26
26
* Author: Anton Lavrentiev
28
28
* File Description:
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()
36
* Revision 6.9 2001/05/18 20:41:43 lavr
37
* Beautifying: change log corrected
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)
42
* Revision 6.7 2001/03/26 18:39:24 lavr
43
* Casting to (unsigned char) instead of (int) for ctype char.class macros
45
* Revision 6.6 2001/03/06 04:32:00 lavr
46
* Better custom header processing
48
* Revision 6.5 2001/03/02 20:09:06 lavr
51
* Revision 6.4 2001/03/01 00:30:23 lavr
52
* Toolkit configuration moved to ncbi_sendmail_.c
54
* Revision 6.3 2001/02/28 21:11:47 lavr
55
* Bugfix: buffer overrun
57
* Revision 6.2 2001/02/28 17:48:53 lavr
58
* Some fixes; larger intermediate buffer for message body
60
* Revision 6.1 2001/02/28 00:52:26 lavr
63
* ==========================================================================
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>
70
38
#include <stdlib.h>
72
39
#ifdef NCBI_OS_UNIX
74
41
#include <unistd.h>
78
#define MX_MAGIC_NUMBER 0xBABADEDA
43
#ifdef NCBI_CXX_TOOLKIT
44
#define NCBI_SENDMAIL_TOOLKIT "C++"
46
#define NCBI_SENDMAIL_TOOLKIT "C"
49
#define MX_MAGIC_NUMBER 0xBA8ADEDA
79
50
#define MX_CRLF "\r\n"
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 */
273
255
#define SENDMAIL_RETURN2(reason, explanation) \
275
259
CORE_LOGF(eLOG_Error, ("[SendMail] %s: %s", reason, explanation)); \
276
260
if (reason/*always true, though, to trick "smart" compiler*/) \
265
static const char* s_SendRcpt(SOCK sock, const char* to,
266
char buf[], size_t buf_size,
268
const char write_error[],
269
const char proto_error[])
272
while ((c = *to++) != 0) {
275
if (isspace((unsigned char) c))
277
while (k < buf_size) {
281
} else if (c == '"' || c == '<' || c == '\'') {
282
quote = c == '<' ? '>' : c;
285
buf[k++] = c == '\t' ? ' ' : c;
288
if (isspace((unsigned char) c)) {
289
while (isspace((unsigned char)(*to)))
294
SENDMAIL_RETURN("Recepient address is too long");
297
CORE_LOGF(eLOG_Warning, ("[SendMail] Ubalanced delimiters in "
298
"recepient %s for %s: \"%c\" expected",
301
if (!s_SockWrite(sock, "RCPT TO: <") ||
302
!s_SockWrite(sock, buf) ||
303
!s_SockWrite(sock, ">" MX_CRLF)) {
304
SENDMAIL_RETURN(write_error);
306
if (!s_SockReadResponse(sock, 250, 251, buf, buf_size))
307
SENDMAIL_RETURN2(proto_error, buf);
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")
280
320
#define SENDMAIL_READ_RESPONSE(code, altcode, buffer) \
281
321
s_SockReadResponse(sock, code, altcode, buffer, sizeof(buffer))
289
329
const SSendMailInfo* info;
290
330
SSendMailInfo ainfo;
291
331
char buffer[1024];
294
334
info = uinfo ? uinfo : SendMailInfo_Init(&ainfo);
295
335
if (info->magic_number != MX_MAGIC_NUMBER)
296
336
SENDMAIL_RETURN("Invalid magic number");
299
(!info->cc || !*info->cc) &&
300
(!info->bcc || !*info->bcc))
339
(!info->cc || !*info->cc) &&
340
(!info->bcc || !*info->bcc)) {
301
341
SENDMAIL_RETURN("At least one message recipient must be specified");
303
344
/* Open connection to sendmail */
304
345
if (SOCK_Create(info->mx_host, info->mx_port, &info->mx_timeout, &sock)
306
347
SENDMAIL_RETURN("Cannot connect to sendmail");
307
349
SOCK_SetTimeout(sock, eIO_ReadWrite, &info->mx_timeout);
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);
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");
319
362
if (!SENDMAIL_READ_RESPONSE(250, 0, buffer))
320
363
SENDMAIL_RETURN2("Protocol error in HELO command", buffer);
322
if (!s_SockWrite(sock, "MAIL FROM: <") ||
323
!s_SockWrite(sock, info->from) ||
324
!s_SockWrite(sock, ">" MX_CRLF))
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");
326
370
if (!SENDMAIL_READ_RESPONSE(250, 0, buffer))
327
371
SENDMAIL_RETURN2("Protocol error in MAIL command", buffer);
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);
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);
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);
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);
361
/* Follow RFC822 to compose message headers. Note that
362
* 'Date:'and 'From:' are both added by sendmail automatically.
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");
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");
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");
383
if (!s_SockWrite(sock,
384
"X-Mailer: CORE_SendMail (NCBI "
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.
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");
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");
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");
418
} else if (subject && *subject)
419
CORE_LOG(eLOG_Warning,"[SendMail] Subject ignored in as-is messages");
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");
388
425
assert(sizeof(buffer) > sizeof(MX_CRLF) && sizeof(MX_CRLF) >= 3);
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*/;
395
432
while (k < sizeof(buffer) - sizeof(MX_CRLF)) {
441
481
if (!s_SockWrite(sock, buffer))
442
SENDMAIL_RETURN("Write error in sending text body");
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");
484
if ((!newline && m && !s_SockWrite(sock, MX_CRLF))
485
|| !s_SockWrite(sock, "." MX_CRLF)) {
486
SENDMAIL_RETURN("Write error while finalizing message body");
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);
491
SENDMAIL_RETURN2("Protocol error in sending message", buffer);
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);
457
498
SOCK_Close(sock);
461
502
#undef SENDMAIL_READ_RESPONSE
503
#undef SENDMAIL_SENDRCPT
462
504
#undef SENDMAIL_RETURN2
463
505
#undef SENDMAIL_RETURN
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
514
* Revision 6.21 2003/12/09 15:38:39 lavr
515
* Take advantage of SSendMailInfo::body_size; few little makeup changes
517
* Revision 6.20 2003/12/04 14:55:09 lavr
518
* Extend API with no-header and multiple recipient capabilities
520
* Revision 6.19 2003/04/18 20:59:51 lavr
521
* Mixed up SMTP_BADCODE and SMTP_BADREPLY rearranged in order
523
* Revision 6.18 2003/03/24 19:46:17 lavr
524
* Few minor changes; do not init SSendMailInfo passed as NULL
526
* Revision 6.17 2003/02/08 21:05:55 lavr
527
* Unimportant change in comments
529
* Revision 6.16 2002/10/28 15:43:29 lavr
530
* Use "ncbi_ansi_ext.h" privately and use strncpy0()
532
* Revision 6.15 2002/09/24 15:05:45 lavr
535
* Revision 6.14 2002/08/14 18:55:39 lavr
536
* Close socket on error return (was forgotten)
538
* Revision 6.13 2002/08/12 15:12:31 lavr
539
* Use persistent SOCK_Write()
541
* Revision 6.12 2002/08/07 16:33:15 lavr
542
* Changed EIO_ReadMethod enums accordingly; log moved to end
544
* Revision 6.11 2002/02/11 20:36:44 lavr
545
* Use "ncbi_config.h"
547
* Revision 6.10 2001/07/13 20:15:12 lavr
548
* Write lock then unlock when using not MT-safe s_ComposeFrom()
550
* Revision 6.9 2001/05/18 20:41:43 lavr
551
* Beautifying: change log corrected
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)
556
* Revision 6.7 2001/03/26 18:39:24 lavr
557
* Casting to (unsigned char) instead of (int) for ctype char.class macros
559
* Revision 6.6 2001/03/06 04:32:00 lavr
560
* Better custom header processing
562
* Revision 6.5 2001/03/02 20:09:06 lavr
565
* Revision 6.4 2001/03/01 00:30:23 lavr
566
* Toolkit configuration moved to ncbi_sendmail_.c
568
* Revision 6.3 2001/02/28 21:11:47 lavr
569
* Bugfix: buffer overrun
571
* Revision 6.2 2001/02/28 17:48:53 lavr
572
* Some fixes; larger intermediate buffer for message body
574
* Revision 6.1 2001/02/28 00:52:26 lavr
577
* ===========================================================================