~ubuntu-branches/ubuntu/precise/ncbi-tools6/precise

« back to all changes in this revision

Viewing changes to connect/ncbi_sendmail.c

  • Committer: Bazaar Package Importer
  • Author(s): Aaron M. Ucko
  • Date: 2005-03-27 12:00:15 UTC
  • mfrom: (2.1.2 hoary)
  • Revision ID: james.westby@ubuntu.com-20050327120015-embhesp32nj73p9r
Tags: 6.1.20041020-3
* Fix FTBFS under GCC 4.0 caused by inconsistent use of "static" on
  functions.  (Closes: #295110.)
* Add a watch file, now that we can.  (Upstream's layout needs version=3.)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*  $Id: ncbi_sendmail.c,v 6.10 2001/07/13 20:15:12 lavr Exp $
 
1
/*  $Id: ncbi_sendmail.c,v 6.22 2004/01/07 19:51:36 lavr Exp $
2
2
 * ===========================================================================
3
3
 *
4
4
 *                            PUBLIC DOMAIN NOTICE
26
26
 * Author:  Anton Lavrentiev
27
27
 *
28
28
 * File Description:
29
 
 *    Send mail
30
 
 *
31
 
 * --------------------------------------------------------------------------
32
 
 * $Log: ncbi_sendmail.c,v $
33
 
 * Revision 6.10  2001/07/13 20:15:12  lavr
34
 
 * Write lock then unlock when using not MT-safe s_ComposeFrom()
35
 
 *
36
 
 * Revision 6.9  2001/05/18 20:41:43  lavr
37
 
 * Beautifying: change log corrected
38
 
 *
39
 
 * Revision 6.8  2001/05/18 19:52:24  lavr
40
 
 * Tricks in macros to keep Sun C compiler silent from warnings (details below)
41
 
 *
42
 
 * Revision 6.7  2001/03/26 18:39:24  lavr
43
 
 * Casting to (unsigned char) instead of (int) for ctype char.class macros
44
 
 *
45
 
 * Revision 6.6  2001/03/06 04:32:00  lavr
46
 
 * Better custom header processing
47
 
 *
48
 
 * Revision 6.5  2001/03/02 20:09:06  lavr
49
 
 * Typo fixed
50
 
 *
51
 
 * Revision 6.4  2001/03/01 00:30:23  lavr
52
 
 * Toolkit configuration moved to ncbi_sendmail_.c
53
 
 *
54
 
 * Revision 6.3  2001/02/28 21:11:47  lavr
55
 
 * Bugfix: buffer overrun
56
 
 *
57
 
 * Revision 6.2  2001/02/28 17:48:53  lavr
58
 
 * Some fixes; larger intermediate buffer for message body
59
 
 *
60
 
 * Revision 6.1  2001/02/28 00:52:26  lavr
61
 
 * Initial revision
62
 
 *
63
 
 * ==========================================================================
 
29
 *   Send mail
 
30
 *
64
31
 */
65
32
 
 
33
#include "ncbi_ansi_ext.h"
66
34
#include "ncbi_priv.h"
67
35
#include <connect/ncbi_sendmail.h>
68
36
#include <connect/ncbi_socket.h>
69
37
#include <ctype.h>
70
38
#include <stdlib.h>
71
 
#include <string.h>
72
39
#ifdef NCBI_OS_UNIX
73
40
#include <pwd.h>
74
41
#include <unistd.h>
75
42
#endif
76
 
 
77
 
 
78
 
#define MX_MAGIC_NUMBER 0xBABADEDA
 
43
#ifdef NCBI_CXX_TOOLKIT
 
44
#define NCBI_SENDMAIL_TOOLKIT "C++"
 
45
#else
 
46
#define NCBI_SENDMAIL_TOOLKIT "C"
 
47
#endif
 
48
 
 
49
#define MX_MAGIC_NUMBER 0xBA8ADEDA
79
50
#define MX_CRLF         "\r\n"
80
51
 
81
52
#define SMTP_READERR    -1      /* Error reading from socket         */
82
53
#define SMTP_REPLYERR   -2      /* Error reading reply prefix        */
 
54
#define SMTP_BADCODE    -3      /* Reply code doesn't match in lines */
83
55
#define SMTP_BADREPLY   -4      /* Malformed reply text              */
84
 
#define SMTP_BADCODE    -3      /* Reply code doesn't match in lines */
85
56
#define SMTP_NOCODE     -5      /* No reply code detected (letters?) */
86
57
#define SMTP_WRITERR    -6      /* Error writing to socket           */
87
58
 
99
70
    size_t n = 0;
100
71
    int code = 0;
101
72
 
102
 
    if (!reply || !reply_len)
 
73
    if (!reply  ||  !reply_len)
103
74
        return 0;
104
75
 
105
76
    do {
106
77
        size_t m = 0;
107
78
        char buf[4];
108
79
 
109
 
        if (SOCK_Read(sock, buf, 4, &m, eIO_Persist) != eIO_Success)
 
80
        if (SOCK_Read(sock, buf, 4, &m, eIO_ReadPersist) != eIO_Success)
110
81
            return SMTP_READERR;
111
82
        if (m != 4)
112
83
            return SMTP_REPLYERR;
113
84
 
114
 
        if (buf[3] == '-' || (done = isspace((unsigned char)buf[3]))) {
 
85
        if (buf[3] == '-'  ||  (done = isspace((unsigned char) buf[3]))) {
115
86
            buf[3] = 0;
116
87
            if (!code) {
117
88
                if (!(code = atoi(buf)))
123
94
 
124
95
        do {
125
96
            m = 0;
126
 
            if (SOCK_Read(sock, buf, 1, &m, eIO_Plain) != eIO_Success || !m)
 
97
            if (SOCK_Read(sock,buf,1,&m,eIO_ReadPlain) != eIO_Success  ||  !m)
127
98
                return SMTP_READERR;
128
99
 
129
 
            if (buf[0] != '\r' && n < reply_len)
 
100
            if (buf[0] != '\r'  &&  n < reply_len)
130
101
                reply[n++] = buf[0];
131
102
        } while (buf[0] != '\n');
132
103
 
145
116
 
146
117
 
147
118
static int/*bool*/ s_SockReadResponse(SOCK sock, int code, int alt_code,
148
 
                                      char* buffer, size_t buffer_len)
 
119
                                      char* buf, size_t buf_size)
149
120
{
150
 
    int c = s_SockRead(sock, buffer, buffer_len);
 
121
    int c = s_SockRead(sock, buf, buf_size);
151
122
    if (c <= 0) {
152
123
        const char* message = 0;
153
124
        switch (c) {
157
128
        case SMTP_REPLYERR:
158
129
            message = "Error reading reply prefix";
159
130
            break;
 
131
        case SMTP_BADCODE:
 
132
            message = "Reply code doesn't match in lines";
 
133
            break;
160
134
        case SMTP_BADREPLY:
161
135
            message = "Malformed reply text";
162
136
            break;
163
 
        case SMTP_BADCODE:
164
 
            message = "Reply code doesn't match in lines";
165
 
            break;
166
137
        case SMTP_NOCODE:
167
138
            message = "No reply code detected";
168
139
            break;
174
145
            break;
175
146
        }
176
147
        assert(message);
177
 
        strncpy(buffer, message, buffer_len - 1);
178
 
        buffer[buffer_len - 1] = '\0';
179
 
    } else if (c == code || (alt_code && c == alt_code))
 
148
        strncpy0(buf, message, buf_size - 1);
 
149
    } else if (c == code  ||  (alt_code  &&  c == alt_code))
180
150
        return 1/*success*/;
181
151
    return 0/*failure*/;
182
152
}
187
157
    size_t len = strlen(buf);
188
158
    size_t n;
189
159
 
190
 
    if (SOCK_Write(sock, buf, len, &n) != eIO_Success || n != len)
191
 
        return 0/*failed*/;
192
 
    return 1/*success*/;
 
160
    if (SOCK_Write(sock, buf, len, &n, eIO_WritePersist) == eIO_Success  &&
 
161
        n == len) {
 
162
        return 1/*success*/;
 
163
    }
 
164
    return 0/*failure*/;
193
165
}
194
166
 
195
167
 
204
176
    if (!login_name) {
205
177
        struct passwd* pwd = getpwuid(getuid());
206
178
        if (!pwd) {
207
 
            if (!(login_name = getenv("USER")) &&
 
179
            if (!(login_name = getenv("USER"))  &&
208
180
                !(login_name = getenv("LOGNAME"))) {
209
181
                CORE_UNLOCK;
210
182
                return 0;
215
187
#else
216
188
    /* Temporary solution for login name */
217
189
    const char* login_name = "anonymous";
 
190
#  ifdef NCBI_OS_MSWIN
 
191
    const char* user_name = getenv("USERNAME");
 
192
    if (user_name)
 
193
        login_name = user_name;
 
194
#  endif
218
195
#endif
219
 
    strncpy(buf, login_name, buf_size - 1);
 
196
    strncpy0(buf, login_name, buf_size - 1);
220
197
#ifdef NCBI_OS_UNIX
221
198
    CORE_UNLOCK;
222
199
#endif
223
 
    buf[buf_size - 1] = '\0';
224
200
    buf_len = strlen(buf);
225
201
    hostname_len = buf_size - buf_len;
226
202
    if (hostname_len-- > 1) {
233
209
 
234
210
SSendMailInfo* SendMailInfo_Init(SSendMailInfo* info)
235
211
{
236
 
    info->magic_number = MX_MAGIC_NUMBER;
237
 
    info->cc = 0;
238
 
    info->bcc = 0;
239
 
    if (!s_ComposeFrom(info->from, sizeof(info->from)))
240
 
        info->from[0] = 0;
241
 
    info->header = 0;
242
 
    info->mx_host = MX_HOST;
243
 
    info->mx_port = MX_PORT;
244
 
    info->mx_timeout.sec = MX_TIMEOUT;
245
 
    info->mx_timeout.usec = 0;
 
212
    if (info) {
 
213
        info->magic_number    = MX_MAGIC_NUMBER;
 
214
        info->cc              = 0;
 
215
        info->bcc             = 0;
 
216
        if (!s_ComposeFrom(info->from, sizeof(info->from)))
 
217
            info->from[0]     = 0;
 
218
        info->header          = 0;
 
219
        info->body_size       = 0;
 
220
        info->mx_host         = MX_HOST;
 
221
        info->mx_port         = MX_PORT;
 
222
        info->mx_timeout.sec  = MX_TIMEOUT;
 
223
        info->mx_timeout.usec = 0;
 
224
        info->mx_no_header    = 0/*false*/;
 
225
    }
246
226
    return info;
247
227
}
248
228
 
257
237
 
258
238
/* In two macros below the smartest (or, weak-minded?) Sun
259
239
 * C compiler warned about unreachable end-of-loop condition
260
 
 * (well, it thinks the "condition" is there, dumb!), if we
 
240
 * (well, it thinks "a condition" is there, dumb!), if we
261
241
 * used 'return' right before the end of 'while' statement.
262
242
 * So we now added "check" and "conditional" exit, which makes
263
243
 * the Sun compiler much happier, and less wordy :-)
265
245
 
266
246
#define SENDMAIL_RETURN(reason)                                            \
267
247
    do {                                                                   \
 
248
        if (sock)                                                          \
 
249
            SOCK_Close(sock);                                              \
268
250
        CORE_LOGF(eLOG_Error, ("[SendMail]  %s", reason));                 \
269
251
        if (reason/*always true, though, to trick "smart" compiler*/)      \
270
252
            return reason;                                                 \
272
254
 
273
255
#define SENDMAIL_RETURN2(reason, explanation)                              \
274
256
    do {                                                                   \
 
257
       if (sock)                                                           \
 
258
           SOCK_Close(sock);                                               \
275
259
       CORE_LOGF(eLOG_Error, ("[SendMail]  %s: %s", reason, explanation)); \
276
260
       if (reason/*always true, though, to trick "smart" compiler*/)       \
277
261
           return reason;                                                  \
278
262
    } while (0)
279
263
 
 
264
 
 
265
static const char* s_SendRcpt(SOCK sock, const char* to,
 
266
                              char buf[], size_t buf_size,
 
267
                              const char what[],
 
268
                              const char write_error[],
 
269
                              const char proto_error[])
 
270
{
 
271
    char c;
 
272
    while ((c = *to++) != 0) {
 
273
        char   quote = 0;
 
274
        size_t k = 0;
 
275
        if (isspace((unsigned char) c))
 
276
            continue;
 
277
        while (k < buf_size) {
 
278
            if (quote) {
 
279
                if (c == quote)
 
280
                    quote = 0;
 
281
            } else if (c == '"'  ||  c == '<'  ||  c == '\'') {
 
282
                quote = c == '<' ? '>' : c;
 
283
            } else if (c == ',')
 
284
                break;
 
285
            buf[k++] = c == '\t' ? ' ' : c;
 
286
            if (!(c = *to++))
 
287
                break;
 
288
            if (isspace((unsigned char) c)) {
 
289
                while (isspace((unsigned char)(*to)))
 
290
                    to++;
 
291
            }
 
292
        }
 
293
        if (k >= buf_size)
 
294
            SENDMAIL_RETURN("Recepient address is too long");
 
295
        buf[k] = 0;
 
296
        if (quote) {
 
297
            CORE_LOGF(eLOG_Warning, ("[SendMail]  Ubalanced delimiters in "
 
298
                                     "recepient %s for %s: \"%c\" expected",
 
299
                                     buf, what, quote));
 
300
        }
 
301
        if (!s_SockWrite(sock, "RCPT TO: <")  ||
 
302
            !s_SockWrite(sock, buf)           ||
 
303
            !s_SockWrite(sock, ">" MX_CRLF)) {
 
304
            SENDMAIL_RETURN(write_error);
 
305
        }
 
306
        if (!s_SockReadResponse(sock, 250, 251, buf, buf_size))
 
307
            SENDMAIL_RETURN2(proto_error, buf);
 
308
        if (!c)
 
309
            break;
 
310
    }
 
311
    return 0;
 
312
}
 
313
 
 
314
 
 
315
#define SENDMAIL_SENDRCPT(what, list, buffer)                              \
 
316
    s_SendRcpt(sock, list, buffer, sizeof(buffer), what,                   \
 
317
               "Write error in RCPT (" what ") command",                   \
 
318
               "Protocol error in RCPT (" what ") command")
 
319
 
280
320
#define SENDMAIL_READ_RESPONSE(code, altcode, buffer)                      \
281
321
    s_SockReadResponse(sock, code, altcode, buffer, sizeof(buffer))
282
322
 
289
329
    const SSendMailInfo* info;
290
330
    SSendMailInfo ainfo;
291
331
    char buffer[1024];
292
 
    SOCK sock;
 
332
    SOCK sock = 0;
293
333
 
294
334
    info = uinfo ? uinfo : SendMailInfo_Init(&ainfo);
295
335
    if (info->magic_number != MX_MAGIC_NUMBER)
296
336
        SENDMAIL_RETURN("Invalid magic number");
297
337
 
298
 
    if ((!to || !*to) &&
299
 
        (!info->cc || !*info->cc) &&
300
 
        (!info->bcc || !*info->bcc))
 
338
    if ((!to         ||  !*to)        &&
 
339
        (!info->cc   ||  !*info->cc)  &&
 
340
        (!info->bcc  ||  !*info->bcc)) {
301
341
        SENDMAIL_RETURN("At least one message recipient must be specified");
302
 
    
 
342
    }
 
343
 
303
344
    /* Open connection to sendmail */
304
345
    if (SOCK_Create(info->mx_host, info->mx_port, &info->mx_timeout, &sock)
305
 
        != eIO_Success)
 
346
        != eIO_Success) {
306
347
        SENDMAIL_RETURN("Cannot connect to sendmail");
 
348
    }
307
349
    SOCK_SetTimeout(sock, eIO_ReadWrite, &info->mx_timeout);
308
 
    
 
350
 
309
351
    /* Follow the protocol conversation, RFC821 */
310
352
    if (!SENDMAIL_READ_RESPONSE(220, 0, buffer))
311
353
        SENDMAIL_RETURN2("Protocol error in connection init", buffer);
312
 
    
 
354
 
313
355
    if (SOCK_gethostname(buffer, sizeof(buffer)) != 0)
314
356
        SENDMAIL_RETURN("Unable to get local host name");
315
 
    if (!s_SockWrite(sock, "HELO ") ||
316
 
        !s_SockWrite(sock, buffer) ||
317
 
        !s_SockWrite(sock, MX_CRLF))
 
357
    if (!s_SockWrite(sock, "HELO ")         ||
 
358
        !s_SockWrite(sock, buffer)          ||
 
359
        !s_SockWrite(sock, MX_CRLF)) {
318
360
        SENDMAIL_RETURN("Write error in HELO command");
 
361
    }
319
362
    if (!SENDMAIL_READ_RESPONSE(250, 0, buffer))
320
363
        SENDMAIL_RETURN2("Protocol error in HELO command", buffer);
321
 
    
322
 
    if (!s_SockWrite(sock, "MAIL FROM: <") ||
323
 
        !s_SockWrite(sock, info->from) ||
324
 
        !s_SockWrite(sock, ">" MX_CRLF))
 
364
 
 
365
    if (!s_SockWrite(sock, "MAIL FROM: <")  ||
 
366
        !s_SockWrite(sock, info->from)      ||
 
367
        !s_SockWrite(sock, ">" MX_CRLF)) {
325
368
        SENDMAIL_RETURN("Write error in MAIL command");
 
369
    }
326
370
    if (!SENDMAIL_READ_RESPONSE(250, 0, buffer))
327
371
        SENDMAIL_RETURN2("Protocol error in MAIL command", buffer);
328
372
 
329
373
    if (to && *to) {
330
 
        if (!s_SockWrite(sock, "RCPT TO: <") ||
331
 
            !s_SockWrite(sock, to) ||
332
 
            !s_SockWrite(sock, ">" MX_CRLF))
333
 
            SENDMAIL_RETURN("Write error in RCPT (To) command");
334
 
        if (!SENDMAIL_READ_RESPONSE(250, 251, buffer))
335
 
            SENDMAIL_RETURN2("Protocol error in RCPT (To) command", buffer);
 
374
        const char* error = SENDMAIL_SENDRCPT("To", to, buffer);
 
375
        if (error)
 
376
            return error;
336
377
    }
337
378
 
338
379
    if (info->cc && *info->cc) {
339
 
        if (!s_SockWrite(sock, "RCPT TO: <") ||
340
 
            !s_SockWrite(sock, info->cc) ||
341
 
            !s_SockWrite(sock, ">" MX_CRLF))
342
 
            SENDMAIL_RETURN("Write error in RCPT (Cc) command");
343
 
        if (!SENDMAIL_READ_RESPONSE(250, 251, buffer))
344
 
            SENDMAIL_RETURN2("Protocol error in RCPT (Cc) command", buffer);
 
380
        const char* error = SENDMAIL_SENDRCPT("Cc", info->cc, buffer);
 
381
        if (error)
 
382
            return error;
345
383
    }
346
384
 
347
385
    if (info->bcc && *info->bcc) {
348
 
        if (!s_SockWrite(sock, "RCPT TO: <") ||
349
 
            !s_SockWrite(sock, info->bcc) ||
350
 
            !s_SockWrite(sock, ">" MX_CRLF))
351
 
            SENDMAIL_RETURN("Write error in RCPT (Bcc) command");
352
 
        if (!SENDMAIL_READ_RESPONSE(250, 251, buffer))
353
 
            SENDMAIL_RETURN2("Protocol error in RCPT (Bcc) command", buffer);
 
386
        const char* error = SENDMAIL_SENDRCPT("Bcc", info->bcc, buffer);
 
387
        if (error)
 
388
            return error;
354
389
    }
355
 
    
 
390
 
356
391
    if (!s_SockWrite(sock, "DATA" MX_CRLF))
357
392
        SENDMAIL_RETURN("Write error in DATA command");
358
393
    if (!SENDMAIL_READ_RESPONSE(354, 0, buffer))
359
394
        SENDMAIL_RETURN2("Protocol error in DATA command", buffer);
360
 
    
361
 
    /* Follow RFC822 to compose message headers. Note that
362
 
     * 'Date:'and 'From:' are both added by sendmail automatically.
363
 
     */ 
364
 
    if (!s_SockWrite(sock, "Subject: ") ||
365
 
        (subject && !s_SockWrite(sock, subject)) ||
366
 
        !s_SockWrite(sock, MX_CRLF))
367
 
        SENDMAIL_RETURN("Write error in sending subject");
368
 
 
369
 
    if (to && *to) {
370
 
        if (!s_SockWrite(sock, "To: ") ||
371
 
            !s_SockWrite(sock, to) ||
372
 
            !s_SockWrite(sock, MX_CRLF))
373
 
            SENDMAIL_RETURN("Write error in sending To");
374
 
    }
375
 
 
376
 
    if (info->cc && *info->cc) {
377
 
        if (!s_SockWrite(sock, "Cc: ") ||
378
 
            !s_SockWrite(sock, info->cc) ||
379
 
            !s_SockWrite(sock, MX_CRLF))
380
 
            SENDMAIL_RETURN("Write error in sending Cc");
381
 
    }
382
 
 
383
 
    if (!s_SockWrite(sock,
384
 
                     "X-Mailer: CORE_SendMail (NCBI "
 
395
 
 
396
    if (!info->mx_no_header) {
 
397
        /* Follow RFC822 to compose message headers. Note that
 
398
         * 'Date:'and 'From:' are both added by sendmail automatically.
 
399
         */ 
 
400
        if (!s_SockWrite(sock, "Subject: ")           ||
 
401
            (subject && !s_SockWrite(sock, subject))  ||
 
402
            !s_SockWrite(sock, MX_CRLF))
 
403
            SENDMAIL_RETURN("Write error in sending subject");
 
404
 
 
405
        if (to && *to) {
 
406
            if (!s_SockWrite(sock, "To: ")            ||
 
407
                !s_SockWrite(sock, to)                ||
 
408
                !s_SockWrite(sock, MX_CRLF))
 
409
                SENDMAIL_RETURN("Write error in sending To");
 
410
        }
 
411
 
 
412
        if (info->cc && *info->cc) {
 
413
            if (!s_SockWrite(sock, "Cc: ")            ||
 
414
                !s_SockWrite(sock, info->cc)          ||
 
415
                !s_SockWrite(sock, MX_CRLF))
 
416
                SENDMAIL_RETURN("Write error in sending Cc");
 
417
        }
 
418
    } else if (subject && *subject)
 
419
        CORE_LOG(eLOG_Warning,"[SendMail]  Subject ignored in as-is messages");
 
420
 
 
421
    if (!s_SockWrite(sock, "X-Mailer: CORE_SendMail (NCBI "
385
422
                     NCBI_SENDMAIL_TOOLKIT " Toolkit)" MX_CRLF))
386
423
        SENDMAIL_RETURN("Write error in sending mailer information");
387
424
 
388
425
    assert(sizeof(buffer) > sizeof(MX_CRLF) && sizeof(MX_CRLF) >= 3);
389
426
 
390
427
    if (info->header && *info->header) {
391
 
        int/*bool*/ newline = 0/*false*/;
392
428
        size_t n = 0, m = strlen(info->header);
 
429
        int/*bool*/ newline = 0/*false*/;
393
430
        while (n < m) {
394
431
            size_t k = 0;
395
432
            while (k < sizeof(buffer) - sizeof(MX_CRLF)) {
398
435
                    k += sizeof(MX_CRLF) - 1;
399
436
                    newline = 1/*true*/;
400
437
                } else {
401
 
                    buffer[k++] = info->header[n];
 
438
                    if (info->header[n] != '\r'  ||  !newline)
 
439
                        buffer[k++] = info->header[n];
402
440
                    newline = 0/*false*/;
403
441
                }
404
442
                if (++n >= m)
406
444
            }
407
445
            buffer[k] = 0;
408
446
            if (!s_SockWrite(sock, buffer))
409
 
                SENDMAIL_RETURN("Write error in sending custom header");
 
447
                SENDMAIL_RETURN("Write error while sending custom header");
410
448
        }
411
449
        if (!newline && !s_SockWrite(sock, MX_CRLF))
412
 
            SENDMAIL_RETURN("Write error in finalizing custom header");
 
450
            SENDMAIL_RETURN("Write error while finalizing custom header");
413
451
    }
414
 
    
415
 
    if (body && *body) {
 
452
 
 
453
    if (body) {
 
454
        size_t n = 0, m = info->body_size ? info->body_size : strlen(body);
416
455
        int/*bool*/ newline = 0/*false*/;
417
 
        size_t n = 0, m = strlen(body);
418
 
        
419
 
        if (!s_SockWrite(sock, MX_CRLF))
420
 
            SENDMAIL_RETURN("Write error in sending text body delimiter");
 
456
        if (!info->mx_no_header  &&  m) {
 
457
            if (!s_SockWrite(sock, MX_CRLF))
 
458
                SENDMAIL_RETURN("Write error in message body delimiter");
 
459
        }
421
460
        while (n < m) {
422
461
            size_t k = 0;
423
 
            
424
462
            while (k < sizeof(buffer) - sizeof(MX_CRLF)) {
425
463
                if (body[n] == '\n') {
426
464
                    memcpy(&buffer[k], MX_CRLF, sizeof(MX_CRLF) - 1);
427
465
                    k += sizeof(MX_CRLF) - 1;
428
466
                    newline = 1/*true*/;
429
467
                } else {
430
 
                    if (body[n] == '.' && (newline || !n)) {
431
 
                        buffer[k++] = '.';
432
 
                        buffer[k++] = '.';
433
 
                    } else
434
 
                        buffer[k++]   = body[n];
 
468
                    if (body[n] != '\r'  ||  !newline) {
 
469
                        if (body[n] == '.'  &&  (newline  ||  !n)) {
 
470
                            buffer[k++] = '.';
 
471
                            buffer[k++] = '.';
 
472
                        } else
 
473
                            buffer[k++] = body[n];
 
474
                    }
435
475
                    newline = 0/*false*/;
436
476
                }
437
477
                if (++n >= m)
439
479
            }
440
480
            buffer[k] = 0;
441
481
            if (!s_SockWrite(sock, buffer))
442
 
                SENDMAIL_RETURN("Write error in sending text body");
443
 
        }
444
 
        if ((!newline && !s_SockWrite(sock, MX_CRLF)) ||
445
 
            !s_SockWrite(sock, "." MX_CRLF))
446
 
            SENDMAIL_RETURN("Write error in finishing text body");
447
 
    } else if (!s_SockWrite(sock, MX_CRLF "." MX_CRLF))
448
 
        SENDMAIL_RETURN("Write error in finishing message");
 
482
                SENDMAIL_RETURN("Write error while sending message body");
 
483
        }
 
484
        if ((!newline  &&  m  &&  !s_SockWrite(sock, MX_CRLF))
 
485
            ||  !s_SockWrite(sock, "." MX_CRLF)) {
 
486
            SENDMAIL_RETURN("Write error while finalizing message body");
 
487
        }
 
488
    } else if (!s_SockWrite(sock, "." MX_CRLF))
 
489
        SENDMAIL_RETURN("Write error while finalizing message");
449
490
    if (!SENDMAIL_READ_RESPONSE(250, 0, buffer))
450
 
        SENDMAIL_RETURN2("Protocol error in sending message body", buffer);
451
 
    
 
491
        SENDMAIL_RETURN2("Protocol error in sending message", buffer);
 
492
 
452
493
    if (!s_SockWrite(sock, "QUIT" MX_CRLF))
453
494
        SENDMAIL_RETURN("Write error in QUIT command");
454
495
    if (!SENDMAIL_READ_RESPONSE(221, 0, buffer))
455
496
        SENDMAIL_RETURN2("Protocol error in QUIT command", buffer);
456
 
    
 
497
 
457
498
    SOCK_Close(sock);
458
499
    return 0;
459
500
}
460
501
 
461
502
#undef SENDMAIL_READ_RESPONSE
 
503
#undef SENDMAIL_SENDRCPT
462
504
#undef SENDMAIL_RETURN2
463
505
#undef SENDMAIL_RETURN
 
506
 
 
507
 
 
508
/*
 
509
 * ---------------------------------------------------------------------------
 
510
 * $Log: ncbi_sendmail.c,v $
 
511
 * Revision 6.22  2004/01/07 19:51:36  lavr
 
512
 * Try to obtain user name from USERNAME env.var. on Windows, else fallback
 
513
 *
 
514
 * Revision 6.21  2003/12/09 15:38:39  lavr
 
515
 * Take advantage of SSendMailInfo::body_size;  few little makeup changes
 
516
 *
 
517
 * Revision 6.20  2003/12/04 14:55:09  lavr
 
518
 * Extend API with no-header and multiple recipient capabilities
 
519
 *
 
520
 * Revision 6.19  2003/04/18 20:59:51  lavr
 
521
 * Mixed up SMTP_BADCODE and SMTP_BADREPLY rearranged in order
 
522
 *
 
523
 * Revision 6.18  2003/03/24 19:46:17  lavr
 
524
 * Few minor changes; do not init SSendMailInfo passed as NULL
 
525
 *
 
526
 * Revision 6.17  2003/02/08 21:05:55  lavr
 
527
 * Unimportant change in comments
 
528
 *
 
529
 * Revision 6.16  2002/10/28 15:43:29  lavr
 
530
 * Use "ncbi_ansi_ext.h" privately and use strncpy0()
 
531
 *
 
532
 * Revision 6.15  2002/09/24 15:05:45  lavr
 
533
 * Log moved to end
 
534
 *
 
535
 * Revision 6.14  2002/08/14 18:55:39  lavr
 
536
 * Close socket on error return (was forgotten)
 
537
 *
 
538
 * Revision 6.13  2002/08/12 15:12:31  lavr
 
539
 * Use persistent SOCK_Write()
 
540
 *
 
541
 * Revision 6.12  2002/08/07 16:33:15  lavr
 
542
 * Changed EIO_ReadMethod enums accordingly; log moved to end
 
543
 *
 
544
 * Revision 6.11  2002/02/11 20:36:44  lavr
 
545
 * Use "ncbi_config.h"
 
546
 *
 
547
 * Revision 6.10  2001/07/13 20:15:12  lavr
 
548
 * Write lock then unlock when using not MT-safe s_ComposeFrom()
 
549
 *
 
550
 * Revision 6.9  2001/05/18 20:41:43  lavr
 
551
 * Beautifying: change log corrected
 
552
 *
 
553
 * Revision 6.8  2001/05/18 19:52:24  lavr
 
554
 * Tricks in macros to keep Sun C compiler silent from warnings (details below)
 
555
 *
 
556
 * Revision 6.7  2001/03/26 18:39:24  lavr
 
557
 * Casting to (unsigned char) instead of (int) for ctype char.class macros
 
558
 *
 
559
 * Revision 6.6  2001/03/06 04:32:00  lavr
 
560
 * Better custom header processing
 
561
 *
 
562
 * Revision 6.5  2001/03/02 20:09:06  lavr
 
563
 * Typo fixed
 
564
 *
 
565
 * Revision 6.4  2001/03/01 00:30:23  lavr
 
566
 * Toolkit configuration moved to ncbi_sendmail_.c
 
567
 *
 
568
 * Revision 6.3  2001/02/28 21:11:47  lavr
 
569
 * Bugfix: buffer overrun
 
570
 *
 
571
 * Revision 6.2  2001/02/28 17:48:53  lavr
 
572
 * Some fixes; larger intermediate buffer for message body
 
573
 *
 
574
 * Revision 6.1  2001/02/28 00:52:26  lavr
 
575
 * Initial revision
 
576
 *
 
577
 * ===========================================================================
 
578
 */