- else if (!strncasecmp(cmdbuf, "RCPT", 4)) {
- smtp_rcpt(&cmdbuf[5]);
- }
-
- else if (!strncasecmp(cmdbuf, "RSET", 4)) {
- smtp_rset(1);
- }
-#ifdef HAVE_OPENSSL
- else if (!strcasecmp(cmdbuf, "STARTTLS")) {
- smtp_starttls();
- }
-#endif
- else {
- cprintf("502 I'm afraid I can't do that.\r\n");
- }
-
-
-}
-
-
-
-
-/*****************************************************************************/
-/* SMTP CLIENT (OUTBOUND PROCESSING) STUFF */
-/*****************************************************************************/
-
-
-
-/*
- * smtp_try()
- *
- * Called by smtp_do_procmsg() to attempt delivery to one SMTP host
- *
- */
-void smtp_try(const char *key, const char *addr, int *status,
- char *dsn, size_t n, long msgnum, char *envelope_from)
-{
- int sock = (-1);
- char mxhosts[1024];
- int num_mxhosts;
- int mx;
- int i;
- char user[1024], node[1024], name[1024];
- char buf[1024];
- char mailfrom[1024];
- char mx_user[256];
- char mx_pass[256];
- char mx_host[256];
- char mx_port[256];
- int lp, rp;
- char *msgtext;
- const char *ptr;
- size_t msg_size;
- int scan_done;
- CitContext *CCC=CC;
-
-
- /* Parse out the host portion of the recipient address */
- process_rfc822_addr(addr, user, node, name);
-
- CtdlLogPrintf(CTDL_DEBUG, "SMTP client: Attempting delivery to <%s> @ <%s> (%s)\n",
- user, node, name);
-
- /* Load the message out of the database */
- CCC->redirect_buffer = malloc(SIZ);
- CCC->redirect_len = 0;
- CCC->redirect_alloc = SIZ;
- CtdlOutputMsg(msgnum, MT_RFC822, HEADERS_ALL, 0, 1, NULL, ESC_DOT);
- msgtext = CC->redirect_buffer;
- msg_size = CC->redirect_len;
- CCC->redirect_buffer = NULL;
- CCC->redirect_len = 0;
- CCC->redirect_alloc = 0;
-
- /* If no envelope_from is supplied, extract one from the message */
- if ( (envelope_from == NULL) || (IsEmptyStr(envelope_from)) ) {
- strcpy(mailfrom, "");
- scan_done = 0;
- ptr = msgtext;
- do {
- if (ptr = memreadline(ptr, buf, sizeof buf), *ptr == 0) {
- scan_done = 1;
- }
- if (!strncasecmp(buf, "From:", 5)) {
- safestrncpy(mailfrom, &buf[5], sizeof mailfrom);
- striplt(mailfrom);
- for (i=0; mailfrom[i]; ++i) {
- if (!isprint(mailfrom[i])) {
- strcpy(&mailfrom[i], &mailfrom[i+1]);
- i=0;
- }
- }
-
- /* Strip out parenthesized names */
- lp = (-1);
- rp = (-1);
- for (i=0; mailfrom[i]; ++i) {
- if (mailfrom[i] == '(') lp = i;
- if (mailfrom[i] == ')') rp = i;
- }
- if ((lp>0)&&(rp>lp)) {
- strcpy(&mailfrom[lp-1], &mailfrom[rp+1]);
- }
-
- /* Prefer brokketized names */
- lp = (-1);
- rp = (-1);
- for (i=0; mailfrom[i]; ++i) {
- if (mailfrom[i] == '<') lp = i;
- if (mailfrom[i] == '>') rp = i;
- }
- if ( (lp>=0) && (rp>lp) ) {
- mailfrom[rp] = 0;
- strcpy(mailfrom, &mailfrom[lp]);
- }
-
- scan_done = 1;
- }
- } while (scan_done == 0);
- if (IsEmptyStr(mailfrom)) strcpy(mailfrom, "someone@somewhere.org");
- stripallbut(mailfrom, '<', '>');
- envelope_from = mailfrom;
- }
-
- /* Figure out what mail exchanger host we have to connect to */
- num_mxhosts = getmx(mxhosts, node);
- CtdlLogPrintf(CTDL_DEBUG, "Number of MX hosts for <%s> is %d [%s]\n", node, num_mxhosts, mxhosts);
- if (num_mxhosts < 1) {
- *status = 5;
- snprintf(dsn, SIZ, "No MX hosts found for <%s>", node);
- return;
- }
-
- sock = (-1);
- for (mx=0; (mx<num_mxhosts && sock < 0); ++mx) {
- char *endpart;
- extract_token(buf, mxhosts, mx, '|', sizeof buf);
- strcpy(mx_user, "");
- strcpy(mx_pass, "");
- if (num_tokens(buf, '@') > 1) {
- strcpy (mx_user, buf);
- endpart = strrchr(mx_user, '@');
- *endpart = '\0';
- strcpy (mx_host, endpart + 1);
- endpart = strrchr(mx_user, ':');
- if (endpart != NULL) {
- strcpy(mx_pass, endpart+1);
- *endpart = '\0';
- }
- }
- else
- strcpy (mx_host, buf);
- endpart = strrchr(mx_host, ':');
- if (endpart != 0){
- *endpart = '\0';
- strcpy(mx_port, endpart + 1);
- }
- else {
- strcpy(mx_port, "25");
- }
- CtdlLogPrintf(CTDL_DEBUG, "SMTP client: connecting to %s : %s ...\n", mx_host, mx_port);
- sock = sock_connect(mx_host, mx_port, "tcp");
- snprintf(dsn, SIZ, "Could not connect: %s", strerror(errno));
- if (sock >= 0) CtdlLogPrintf(CTDL_DEBUG, "SMTP client: connected!\n");
- if (sock < 0) {
- if (errno > 0) {
- snprintf(dsn, SIZ, "%s", strerror(errno));
- }
- else {
- snprintf(dsn, SIZ, "Unable to connect to %s : %s\n", mx_host, mx_port);
- }
- }
- }
-
- if (sock < 0) {
- *status = 4; /* dsn is already filled in */
- return;
- }
-
- CCC->sReadBuf = NewStrBuf();
- CCC->sMigrateBuf = NewStrBuf();
- CCC->sPos = NULL;
-
- /* Process the SMTP greeting from the server */
- if (ml_sock_gets(&sock, buf) < 0) {
- *status = 4;
- strcpy(dsn, "Connection broken during SMTP conversation");
- goto bail;
- }
- CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf);
- if (buf[0] != '2') {
- if (buf[0] == '4') {
- *status = 4;
- safestrncpy(dsn, &buf[4], 1023);
- goto bail;
- }
- else {
- *status = 5;
- safestrncpy(dsn, &buf[4], 1023);
- goto bail;
- }
- }
-
- /* At this point we know we are talking to a real SMTP server */
-
- /* Do a EHLO command. If it fails, try the HELO command. */
- snprintf(buf, sizeof buf, "EHLO %s\r\n", config.c_fqdn);
- CtdlLogPrintf(CTDL_DEBUG, ">%s", buf);
- sock_write(&sock, buf, strlen(buf));
- if (ml_sock_gets(&sock, buf) < 0) {
- *status = 4;
- strcpy(dsn, "Connection broken during SMTP HELO");
- goto bail;
- }
- CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf);
- if (buf[0] != '2') {
- snprintf(buf, sizeof buf, "HELO %s\r\n", config.c_fqdn);
- CtdlLogPrintf(CTDL_DEBUG, ">%s", buf);
- sock_write(&sock, buf, strlen(buf));
- if (ml_sock_gets(&sock, buf) < 0) {
- *status = 4;
- strcpy(dsn, "Connection broken during SMTP HELO");
- goto bail;
- }
- }
- if (buf[0] != '2') {
- if (buf[0] == '4') {
- *status = 4;
- safestrncpy(dsn, &buf[4], 1023);
- goto bail;
- }
- else {
- *status = 5;
- safestrncpy(dsn, &buf[4], 1023);
- goto bail;
- }
- }
-
- /* Do an AUTH command if necessary */
- if (!IsEmptyStr(mx_user)) {
- char encoded[1024];
- sprintf(buf, "%s%c%s%c%s", mx_user, '\0', mx_user, '\0', mx_pass);
- CtdlEncodeBase64(encoded, buf, strlen(mx_user) + strlen(mx_user) + strlen(mx_pass) + 2, 0);
- snprintf(buf, sizeof buf, "AUTH PLAIN %s\r\n", encoded);
- CtdlLogPrintf(CTDL_DEBUG, ">%s", buf);
- sock_write(&sock, buf, strlen(buf));
- if (ml_sock_gets(&sock, buf) < 0) {
- *status = 4;
- strcpy(dsn, "Connection broken during SMTP AUTH");
- goto bail;
- }
- CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf);
- if (buf[0] != '2') {
- if (buf[0] == '4') {
- *status = 4;
- safestrncpy(dsn, &buf[4], 1023);
- goto bail;
- }
- else {
- *status = 5;
- safestrncpy(dsn, &buf[4], 1023);
- goto bail;
- }
- }
- }
-
- /* previous command succeeded, now try the MAIL FROM: command */
- snprintf(buf, sizeof buf, "MAIL FROM:<%s>\r\n", envelope_from);
- CtdlLogPrintf(CTDL_DEBUG, ">%s", buf);
- sock_write(&sock, buf, strlen(buf));
- if (ml_sock_gets(&sock, buf) < 0) {
- *status = 4;
- strcpy(dsn, "Connection broken during SMTP MAIL");
- goto bail;
- }
- CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf);
- if (buf[0] != '2') {
- if (buf[0] == '4') {
- *status = 4;
- safestrncpy(dsn, &buf[4], 1023);
- goto bail;
- }
- else {
- *status = 5;
- safestrncpy(dsn, &buf[4], 1023);
- goto bail;
- }
- }
-
- /* MAIL succeeded, now try the RCPT To: command */
- snprintf(buf, sizeof buf, "RCPT TO:<%s@%s>\r\n", user, node);
- CtdlLogPrintf(CTDL_DEBUG, ">%s", buf);
- sock_write(&sock, buf, strlen(buf));
- if (ml_sock_gets(&sock, buf) < 0) {
- *status = 4;
- strcpy(dsn, "Connection broken during SMTP RCPT");
- goto bail;
- }
- CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf);
- if (buf[0] != '2') {
- if (buf[0] == '4') {
- *status = 4;
- safestrncpy(dsn, &buf[4], 1023);
- goto bail;
- }
- else {
- *status = 5;
- safestrncpy(dsn, &buf[4], 1023);
- goto bail;
- }
- }
-
- /* RCPT succeeded, now try the DATA command */
- CtdlLogPrintf(CTDL_DEBUG, ">DATA\n");
- sock_write(&sock, "DATA\r\n", 6);
- if (ml_sock_gets(&sock, buf) < 0) {
- *status = 4;
- strcpy(dsn, "Connection broken during SMTP DATA");
- goto bail;
- }
- CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf);
- if (buf[0] != '3') {
- if (buf[0] == '4') {
- *status = 3;
- safestrncpy(dsn, &buf[4], 1023);
- goto bail;
- }
- else {
- *status = 5;
- safestrncpy(dsn, &buf[4], 1023);
- goto bail;
- }
- }
-
- /* If we reach this point, the server is expecting data.*/
- sock_write(&sock, msgtext, msg_size);
- if (msgtext[msg_size-1] != 10) {
- CtdlLogPrintf(CTDL_WARNING, "Possible problem: message did not "
- "correctly terminate. (expecting 0x10, got 0x%02x)\n",
- buf[msg_size-1]);
- sock_write(&sock, "\r\n", 2);
- }
-
- sock_write(&sock, ".\r\n", 3);
- if (ml_sock_gets(&sock, buf) < 0) {
- *status = 4;
- strcpy(dsn, "Connection broken during SMTP message transmit");
- goto bail;
- }
- CtdlLogPrintf(CTDL_DEBUG, "%s\n", buf);
- if (buf[0] != '2') {
- if (buf[0] == '4') {
- *status = 4;
- safestrncpy(dsn, &buf[4], 1023);
- goto bail;