50 |
#include <mailer0.h> |
#include <mailer0.h> |
51 |
#include <registrar0.h> |
#include <registrar0.h> |
52 |
|
|
53 |
static struct _record _smtp_record = |
static struct _record _smtp_record = { |
|
{ |
|
54 |
MU_SMTP_SCHEME, |
MU_SMTP_SCHEME, |
55 |
_url_smtp_init, /* url init. */ |
_url_smtp_init, /* url init. */ |
56 |
NULL, /* Mailbox init. */ |
NULL, /* Mailbox init. */ |
57 |
&_mailer_smtp_init, /* Mailer init. */ |
&_mailer_smtp_init, /* Mailer init. */ |
58 |
NULL, /* Folder init. */ |
NULL, /* Folder init. */ |
59 |
NULL, /* No need for a back pointer. */ |
NULL, /* No need for a back pointer. */ |
60 |
NULL, /* _is_scheme method. */ |
NULL, /* _is_scheme method. */ |
61 |
NULL, /* _get_url method. */ |
NULL, /* _get_url method. */ |
62 |
NULL, /* _get_mailbox method. */ |
NULL, /* _get_mailbox method. */ |
63 |
NULL, /* _get_mailer method. */ |
NULL, /* _get_mailer method. */ |
64 |
NULL /* _get_folder method. */ |
NULL /* _get_folder method. */ |
65 |
}; |
}; |
66 |
/* We export : url parsing and the initialisation of |
/* We export : url parsing and the initialisation of |
67 |
the mailbox, via the register entry/record. */ |
the mailbox, via the register entry/record. */ |
74 |
char *localhost; |
char *localhost; |
75 |
|
|
76 |
/* IO buffering. */ |
/* IO buffering. */ |
77 |
char *buffer; /* Must be freed. */ |
char *buffer; /* Must be freed. */ |
78 |
size_t buflen; |
size_t buflen; |
79 |
|
|
80 |
char *ptr; |
char *ptr; |
88 |
SMTP_ENV_RCPT, SMTP_MAIL_FROM, SMTP_MAIL_FROM_ACK, SMTP_RCPT_TO, |
SMTP_ENV_RCPT, SMTP_MAIL_FROM, SMTP_MAIL_FROM_ACK, SMTP_RCPT_TO, |
89 |
SMTP_RCPT_TO_ACK, SMTP_DATA, SMTP_DATA_ACK, SMTP_SEND, SMTP_SEND_ACK, |
SMTP_RCPT_TO_ACK, SMTP_DATA, SMTP_DATA_ACK, SMTP_SEND, SMTP_SEND_ACK, |
90 |
SMTP_SEND_DOT |
SMTP_SEND_DOT |
91 |
} state; |
} |
92 |
|
state; |
93 |
|
|
94 |
int extended; |
int extended; |
95 |
|
|
96 |
char* mail_from; |
char *mail_from; |
97 |
address_t rcpt_to; /* Destroy this if not the same as argto below. */ |
address_t rcpt_to; /* Destroy this if not the same as argto below. */ |
98 |
address_t rcpt_bcc; |
address_t rcpt_bcc; |
99 |
size_t rcpt_to_count; |
size_t rcpt_to_count; |
100 |
size_t rcpt_bcc_count; |
size_t rcpt_bcc_count; |
101 |
size_t rcpt_index; |
size_t rcpt_index; |
102 |
size_t rcpt_count; |
size_t rcpt_count; |
103 |
int bccing; |
int bccing; |
104 |
message_t msg; /* Destroy this if not same argmsg. */ |
message_t msg; /* Destroy this if not same argmsg. */ |
105 |
|
|
106 |
off_t offset; |
off_t offset; |
107 |
|
|
111 |
address_t argto; |
address_t argto; |
112 |
}; |
}; |
113 |
|
|
114 |
typedef struct _smtp * smtp_t; |
typedef struct _smtp *smtp_t; |
115 |
|
|
116 |
static void smtp_destroy (mailer_t); |
static void smtp_destroy (mailer_t); |
117 |
static int smtp_open (mailer_t, int); |
static int smtp_open (mailer_t, int); |
122 |
static int smtp_read_ack (smtp_t); |
static int smtp_read_ack (smtp_t); |
123 |
static int smtp_write (smtp_t); |
static int smtp_write (smtp_t); |
124 |
|
|
125 |
static int _smtp_set_from (smtp_t, message_t , address_t); |
static int _smtp_set_from (smtp_t, message_t, address_t); |
126 |
static int _smtp_set_rcpt (smtp_t, message_t , address_t); |
static int _smtp_set_rcpt (smtp_t, message_t, address_t); |
127 |
|
|
128 |
/* Useful little macros, since these are very repetitive. */ |
/* Useful little macros, since these are very repetitive. */ |
129 |
|
|
173 |
as that which is ongoing. Check this. */ |
as that which is ongoing. Check this. */ |
174 |
static int |
static int |
175 |
smtp_check_send_resumption (smtp_t smtp, |
smtp_check_send_resumption (smtp_t smtp, |
176 |
message_t msg, address_t from, address_t to) |
message_t msg, address_t from, address_t to) |
177 |
{ |
{ |
178 |
if(smtp->state == SMTP_NO_STATE) |
if (smtp->state == SMTP_NO_STATE) |
179 |
return 0; |
return 0; |
180 |
|
|
181 |
/* FIXME: state should be one of the "send" states if its not |
/* FIXME: state should be one of the "send" states if its not |
248 |
if (mailer->data == NULL) |
if (mailer->data == NULL) |
249 |
return ENOMEM; |
return ENOMEM; |
250 |
|
|
251 |
smtp->mailer = mailer; /* Back pointer. */ |
smtp->mailer = mailer; /* Back pointer. */ |
252 |
smtp->state = SMTP_NO_STATE; |
smtp->state = SMTP_NO_STATE; |
253 |
|
|
254 |
mailer->_destroy = smtp_destroy; |
mailer->_destroy = smtp_destroy; |
267 |
} |
} |
268 |
|
|
269 |
static void |
static void |
270 |
smtp_destroy(mailer_t mailer) |
smtp_destroy (mailer_t mailer) |
271 |
{ |
{ |
272 |
smtp_t smtp = mailer->data; |
smtp_t smtp = mailer->data; |
273 |
|
|
274 |
CLEAR_STATE(smtp); |
CLEAR_STATE (smtp); |
275 |
|
|
276 |
/* Not our responsability to close. */ |
/* Not our responsability to close. */ |
277 |
|
|
334 |
} |
} |
335 |
/* Fetch our local host name. */ |
/* Fetch our local host name. */ |
336 |
|
|
337 |
status = mu_get_host_name(&smtp->localhost); |
status = mu_get_host_name (&smtp->localhost); |
338 |
|
|
339 |
if (status != 0) |
if (status != 0) |
340 |
{ |
{ |
346 |
|
|
347 |
/* allocate a working io buffer. */ |
/* allocate a working io buffer. */ |
348 |
if (smtp->buffer == NULL) |
if (smtp->buffer == NULL) |
349 |
{ |
{ |
350 |
smtp->buflen = 512; /* Initial guess. */ |
smtp->buflen = 512; /* Initial guess. */ |
351 |
smtp->buffer = malloc (smtp->buflen + 1); |
smtp->buffer = malloc (smtp->buflen + 1); |
352 |
if (smtp->buffer == NULL) |
if (smtp->buffer == NULL) |
353 |
{ |
{ |
354 |
CHECK_ERROR (smtp, ENOMEM); |
CHECK_ERROR (smtp, ENOMEM); |
355 |
} |
} |
356 |
smtp->ptr = smtp->buffer; |
smtp->ptr = smtp->buffer; |
357 |
} |
} |
358 |
|
|
359 |
/* Create a TCP stack if one is not given. */ |
/* Create a TCP stack if one is not given. */ |
360 |
if (mailer->stream == NULL) |
if (mailer->stream == NULL) |
361 |
{ |
{ |
362 |
status = tcp_stream_create (&mailer->stream, smtp->mailhost, port, mailer->flags); |
status = |
363 |
|
tcp_stream_create (&mailer->stream, smtp->mailhost, port, |
364 |
|
mailer->flags); |
365 |
CHECK_ERROR (smtp, status); |
CHECK_ERROR (smtp, status); |
366 |
stream_setbufsiz (mailer->stream, BUFSIZ); |
stream_setbufsiz (mailer->stream, BUFSIZ); |
367 |
} |
} |
414 |
} |
} |
415 |
|
|
416 |
case SMTP_HELO: |
case SMTP_HELO: |
417 |
if (!smtp->extended) /* FIXME: this will always be false! */ |
if (!smtp->extended) /* FIXME: this will always be false! */ |
418 |
{ |
{ |
419 |
status = smtp_write (smtp); |
status = smtp_write (smtp); |
420 |
CHECK_EAGAIN (smtp, status); |
CHECK_EAGAIN (smtp, status); |
439 |
break; |
break; |
440 |
} |
} |
441 |
|
|
442 |
CLEAR_STATE(smtp); |
CLEAR_STATE (smtp); |
443 |
|
|
444 |
return 0; |
return 0; |
445 |
} |
} |
488 |
} |
} |
489 |
|
|
490 |
static int |
static int |
491 |
message_has_bcc(message_t msg) |
message_has_bcc (message_t msg) |
492 |
{ |
{ |
493 |
int status; |
int status; |
494 |
header_t header = NULL; |
header_t header = NULL; |
549 |
smtp_t smtp = NULL; |
smtp_t smtp = NULL; |
550 |
int status; |
int status; |
551 |
|
|
552 |
if(mailer == NULL) |
if (mailer == NULL) |
553 |
return EINVAL; |
return EINVAL; |
554 |
|
|
555 |
smtp = mailer->data; |
smtp = mailer->data; |
574 |
CHECK_ERROR (smtp, status); |
CHECK_ERROR (smtp, status); |
575 |
|
|
576 |
/* Clear the Bcc: field if we found one. */ |
/* Clear the Bcc: field if we found one. */ |
577 |
if (message_has_bcc(smtp->argmsg)) |
if (message_has_bcc (smtp->argmsg)) |
578 |
{ |
{ |
579 |
smtp->msg = NULL; |
smtp->msg = NULL; |
580 |
status = message_create_copy (&smtp->msg, smtp->argmsg); |
status = message_create_copy (&smtp->msg, smtp->argmsg); |
632 |
CHECK_ERROR (smtp, status); |
CHECK_ERROR (smtp, status); |
633 |
|
|
634 |
/* Add the Bcc: field back in for recipient. */ |
/* Add the Bcc: field back in for recipient. */ |
635 |
if(smtp->bccing) |
if (smtp->bccing) |
636 |
{ |
{ |
637 |
status = message_set_header_value (smtp->msg, MU_HEADER_BCC, to); |
status = message_set_header_value (smtp->msg, MU_HEADER_BCC, to); |
638 |
CHECK_ERROR (smtp, status); |
CHECK_ERROR (smtp, status); |
639 |
} |
} |
640 |
|
|
641 |
status = smtp_writeline (smtp, "RCPT TO: %s\r\n", to); |
status = smtp_writeline (smtp, "RCPT TO: %s\r\n", to); |
642 |
|
|
688 |
smtp->offset = 0; |
smtp->offset = 0; |
689 |
smtp->state = SMTP_SEND; |
smtp->state = SMTP_SEND; |
690 |
|
|
691 |
if((smtp->mailer->flags & MAILER_FLAG_DEBUG_DATA) == 0) |
if ((smtp->mailer->flags & MAILER_FLAG_DEBUG_DATA) == 0) |
692 |
MAILER_DEBUG0 (smtp->mailer, MU_DEBUG_PROT, "> (data...)\n"); |
MAILER_DEBUG0 (smtp->mailer, MU_DEBUG_PROT, "> (data...)\n"); |
693 |
|
|
694 |
case SMTP_SEND: |
case SMTP_SEND: |
695 |
{ |
{ |
696 |
stream_t stream; |
stream_t stream; |
697 |
size_t n = 0; |
size_t n = 0; |
698 |
char data[256] = ""; |
char data[256] = ""; |
699 |
|
|
700 |
/* We may be here after an EAGAIN so check if we have something |
/* We may be here after an EAGAIN so check if we have something |
701 |
in the buffer and flush it. */ |
in the buffer and flush it. */ |
702 |
status = smtp_write (smtp); |
status = smtp_write (smtp); |
703 |
CHECK_EAGAIN (smtp, status); |
CHECK_EAGAIN (smtp, status); |
704 |
|
|
705 |
message_get_stream (smtp->msg, &stream); |
message_get_stream (smtp->msg, &stream); |
706 |
while ((status = stream_readline (stream, data, sizeof (data) - 1, |
while ((status = stream_readline (stream, data, sizeof (data) - 1, |
707 |
smtp->offset, &n)) == 0 && n > 0) |
smtp->offset, &n)) == 0 && n > 0) |
866 |
return status; |
return status; |
867 |
} |
} |
868 |
|
|
869 |
|
int |
870 |
|
smtp_address_add (address_t *paddr, const char *value) |
871 |
|
{ |
872 |
|
address_t addr = NULL; |
873 |
|
int status; |
874 |
|
|
875 |
|
status = address_create (&addr, value); |
876 |
|
if (status) |
877 |
|
return status; |
878 |
|
status = address_union (paddr, addr); |
879 |
|
address_destroy (&addr); |
880 |
|
return status; |
881 |
|
} |
882 |
|
|
883 |
static int |
static int |
884 |
_smtp_set_rcpt (smtp_t smtp, message_t msg, address_t to) |
_smtp_set_rcpt (smtp_t smtp, message_t msg, address_t to) |
885 |
{ |
{ |
886 |
int status = 0; |
int status = 0; |
887 |
header_t header = NULL; |
header_t header = NULL; |
888 |
char *toaddrv[3] = { NULL, NULL }; |
char *value; |
889 |
char *bccaddr = NULL; |
|
|
address_t rcpt_to = NULL; |
|
|
address_t rcpt_bcc = NULL; |
|
|
|
|
890 |
/* Get RCPT_TO from TO, or the message. */ |
/* Get RCPT_TO from TO, or the message. */ |
891 |
|
|
|
/* FIXME: even if there are TO addresses on the command-line, I have |
|
|
to blank out the Bcc: header in the message! |
|
|
*/ |
|
892 |
if (to) |
if (to) |
893 |
{ |
{ |
894 |
/* Use the specified address_t. */ |
/* Use the specified address_t. */ |
901 |
smtp->rcpt_to = to; |
smtp->rcpt_to = to; |
902 |
address_get_count (smtp->rcpt_to, &smtp->rcpt_to_count); |
address_get_count (smtp->rcpt_to, &smtp->rcpt_to_count); |
903 |
|
|
904 |
return status; |
if (status) |
905 |
|
return status; |
906 |
} |
} |
907 |
|
|
908 |
if ((status = message_get_header (msg, &header))) |
if ((status = message_get_header (msg, &header))) |
909 |
return status; |
return status; |
910 |
|
|
911 |
status = header_aget_value (header, MU_HEADER_TO, toaddrv + 0); |
status = header_aget_value (header, MU_HEADER_TO, &value); |
912 |
|
|
913 |
if (status && status != ENOENT) |
if (status == 0) |
914 |
|
{ |
915 |
|
smtp_address_add (&smtp->rcpt_to, value); |
916 |
|
free (value); |
917 |
|
} |
918 |
|
else if (status && status != ENOENT) |
919 |
goto end; |
goto end; |
920 |
|
|
921 |
status = header_aget_value (header, MU_HEADER_CC, toaddrv + 1); |
status = header_aget_value (header, MU_HEADER_CC, &value); |
922 |
|
|
923 |
if (status && status != ENOENT) |
if (status == 0) |
924 |
|
{ |
925 |
|
smtp_address_add (&smtp->rcpt_to, value); |
926 |
|
free (value); |
927 |
|
} |
928 |
|
else if (status && status != ENOENT) |
929 |
goto end; |
goto end; |
930 |
|
|
931 |
status = header_aget_value (header, MU_HEADER_BCC, &bccaddr); |
status = header_aget_value (header, MU_HEADER_BCC, &value); |
932 |
|
if (status == 0) |
933 |
if (status && status != ENOENT) |
{ |
934 |
|
smtp_address_add (&smtp->rcpt_bcc, value); |
935 |
|
free (value); |
936 |
|
} |
937 |
|
else if (status && status != ENOENT) |
938 |
goto end; |
goto end; |
939 |
|
|
|
status = 0; |
|
|
|
|
|
{ |
|
|
const char **av = (const char **) toaddrv; |
|
|
int tostatus = address_createv (&rcpt_to, av, 2); |
|
|
|
|
|
/* Any error other than EMPTY_ADDRESS is fatal */ |
|
|
if (tostatus) |
|
|
{ |
|
|
if (tostatus == MU_ERR_EMPTY_ADDRESS) |
|
|
tostatus = MU_ERR_MAILER_NO_RCPT_TO; |
|
|
else |
|
|
goto end; |
|
|
} |
|
|
|
|
|
if (!bccaddr) |
|
|
status = MU_ERR_EMPTY_ADDRESS; |
|
|
else |
|
|
{ |
|
|
status = address_create (&rcpt_bcc, bccaddr); |
|
|
|
|
|
if (status) |
|
|
{ |
|
|
if (status == MU_ERR_EMPTY_ADDRESS) |
|
|
status = MU_ERR_MAILER_NO_RCPT_TO; |
|
|
else |
|
|
goto end; |
|
|
} |
|
|
} |
|
|
|
|
|
/* If both to and bcc are empty, it is fatal */ |
|
|
if (status == MU_ERR_EMPTY_ADDRESS && tostatus == status) |
|
|
goto end; |
|
|
|
|
|
/* otherwise, at least rcpt_to or rcpt_bcc is defined */ |
|
|
status = 0; |
|
|
} |
|
|
|
|
940 |
/* If to or bcc is present, the must be OK. */ |
/* If to or bcc is present, the must be OK. */ |
941 |
if (rcpt_to && (status = mailer_check_to (rcpt_to))) |
if (smtp->rcpt_to && (status = mailer_check_to (smtp->rcpt_to))) |
942 |
goto end; |
goto end; |
943 |
|
|
944 |
if (rcpt_bcc && (status = mailer_check_to (rcpt_bcc))) |
if (smtp->rcpt_bcc && (status = mailer_check_to (smtp->rcpt_bcc))) |
945 |
goto end; |
goto end; |
946 |
|
|
947 |
end: |
end: |
948 |
|
|
|
if (toaddrv[0]) |
|
|
free (toaddrv[0]); |
|
|
|
|
|
if (toaddrv[1]) |
|
|
free (toaddrv[1]); |
|
|
|
|
|
if (bccaddr) |
|
|
free (bccaddr); |
|
|
|
|
949 |
if (status) |
if (status) |
950 |
{ |
{ |
951 |
address_destroy (&rcpt_to); |
address_destroy (&smtp->rcpt_to); |
952 |
address_destroy (&rcpt_bcc); |
address_destroy (&smtp->rcpt_bcc); |
953 |
} |
} |
954 |
else |
else |
955 |
{ |
{ |
|
smtp->rcpt_to = rcpt_to; |
|
|
|
|
956 |
if (smtp->rcpt_to) |
if (smtp->rcpt_to) |
957 |
address_get_count (smtp->rcpt_to, &smtp->rcpt_to_count); |
address_get_count (smtp->rcpt_to, &smtp->rcpt_to_count); |
958 |
|
|
|
smtp->rcpt_bcc = rcpt_bcc; |
|
|
|
|
959 |
if (smtp->rcpt_bcc) |
if (smtp->rcpt_bcc) |
960 |
address_get_count (smtp->rcpt_bcc, &smtp->rcpt_bcc_count); |
address_get_count (smtp->rcpt_bcc, &smtp->rcpt_bcc_count); |
961 |
|
|
962 |
|
if (smtp->rcpt_to_count + smtp->rcpt_bcc_count == 0) |
963 |
|
status = MU_ERR_MAILER_NO_RCPT_TO; |
964 |
} |
} |
965 |
|
|
966 |
return status; |
return status; |
967 |
} |
} |
968 |
|
|
969 |
/* C99 says that a conforming implementations of snprintf () |
/* C99 says that a conforming implementations of snprintf () |
970 |
should return the number of char that would have been call |
should return the number of char that would have been call |
971 |
but many GNU/Linux && BSD implementations return -1 on error. |
but many GNU/Linux && BSD implementations return -1 on error. |
1006 |
while (len > 0 && isspace (smtp->buffer[len - 1])) |
while (len > 0 && isspace (smtp->buffer[len - 1])) |
1007 |
len--; |
len--; |
1008 |
|
|
1009 |
if ( |
if ((smtp->state != SMTP_SEND && smtp->state != SMTP_SEND_DOT) |
1010 |
(smtp->state != SMTP_SEND && smtp->state != SMTP_SEND_DOT) |
|| smtp->mailer->flags & MAILER_FLAG_DEBUG_DATA) |
|
|| |
|
|
smtp->mailer->flags & MAILER_FLAG_DEBUG_DATA |
|
|
) |
|
1011 |
{ |
{ |
1012 |
MAILER_DEBUG2 (smtp->mailer, MU_DEBUG_PROT, "> %.*s\n", len, |
MAILER_DEBUG2 (smtp->mailer, MU_DEBUG_PROT, "> %.*s\n", len, |
1013 |
smtp->buffer); |
smtp->buffer); |