CC -> CCC in do_login
[citadel.git] / citadel / modules / smtp / serv_smtpclient.c
index c3f33fecdee3f20f0cf325b1eca4f324dd2ccfcd..cec2f9bd0c1d21a1f1b3e3e65b4fac8e50318b1e 100644 (file)
@@ -20,9 +20,9 @@
  * The VRFY and EXPN commands have been removed from this implementation
  * because nobody uses these commands anymore, except for spammers.
  *
- * Copyright (c) 1998-2009 by the citadel.org team
+ * Copyright (c) 1998-2011 by the citadel.org team
  *
- *  This program is free software; you can redistribute it and/or modify
+ *  This program is open source software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  the Free Software Foundation; either version 3 of the License, or
  *  (at your option) any later version.
@@ -104,8 +104,8 @@ int run_queue_now = 0;      /* Set to 1 to ignore SMTP send retry times */
  *
  */
 void smtp_try(const char *key, const char *addr, int *status,
-             char *dsn, size_t n, long msgnum, char *envelope_from)
-{
+             char *dsn, size_t n, long msgnum, char *envelope_from
+{
        int sock = (-1);
        char mxhosts[1024];
        int num_mxhosts;
@@ -125,18 +125,29 @@ void smtp_try(const char *key, const char *addr, int *status,
        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);
+       syslog(LOG_DEBUG, "SMTP client: Attempting delivery to <%s> @ <%s> (%s)", user, node, name);
 
        /* Load the message out of the database */
        CCC->redirect_buffer = NewStrBufPlain(NULL, SIZ);
        CtdlOutputMsg(msgnum, MT_RFC822, HEADERS_ALL, 0, 1, NULL, (ESC_DOT|SUPPRESS_ENV_TO) );
-       msg_size = StrLength(CC->redirect_buffer);
-       msgtext = SmashStrBuf(&CC->redirect_buffer);
+       msg_size = StrLength(CCC->redirect_buffer);
+       msgtext = SmashStrBuf(&CCC->redirect_buffer);
+
+       /* This check is being added on 2011apr02 as we are experiencing a problem where the msg_size
+        * is being reported as zero for every delivery after about 12h of server runtime; this seems
+        * to indicate a heap corruption of some sort?  Deferring will allow the message to be delivered
+        * after a server restart instead of discarded.  After we fix the real problem, this will still
+        * be a good sanity check to still have in place.  --ajc
+        */
+       if (msg_size <= 0) {
+               syslog(LOG_ALERT, "msg_size is zero -- possible data corruption");
+               *status = 4;
+               strcpy(dsn, "Internal server error prevented successful delivery -- deferring");
+               goto bail;
+       }
 
        /* If no envelope_from is supplied, extract one from the message */
        if ( (envelope_from == NULL) || (IsEmptyStr(envelope_from)) ) {
@@ -177,20 +188,22 @@ void smtp_try(const char *key, const char *addr, int *status,
                                }
                                if ( (lp>=0) && (rp>lp) ) {
                                        mailfrom[rp] = 0;
-                                       strcpy(mailfrom, &mailfrom[lp]);
+                                       strcpy(mailfrom, &mailfrom[lp + 1]);
                                }
        
                                scan_done = 1;
                        }
                } while (scan_done == 0);
-               if (IsEmptyStr(mailfrom)) strcpy(mailfrom, "someone@somewhere.org");
+               if (IsEmptyStr(mailfrom)) {
+                       syslog(LOG_DEBUG, "This message has no From: header.  Hmm...");
+               }
                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);
+       syslog(LOG_DEBUG, "Number of MX hosts for <%s> is %d [%s]", node, num_mxhosts, mxhosts);
        if (num_mxhosts < 1) {
                *status = 5;
                snprintf(dsn, SIZ, "No MX hosts found for <%s>", node);
@@ -224,23 +237,27 @@ void smtp_try(const char *key, const char *addr, int *status,
                else {
                        strcpy(mx_port, "25");
                }
-               CtdlLogPrintf(CTDL_DEBUG, "SMTP client: connecting to %s : %s ...\n", mx_host, mx_port);
+               syslog(LOG_DEBUG, "SMTP client: connecting to %s : %s ...", mx_host, mx_port);
                sock = sock_connect(mx_host, mx_port);
                snprintf(dsn, SIZ, "Could not connect: %s", strerror(errno));
                if (sock >= 0) 
                {
-                       CtdlLogPrintf(CTDL_DEBUG, "SMTP client: connected!\n");
-                               int fdflags; 
-                               fdflags = fcntl(sock, F_GETFL);
-                               if (fdflags < 0)
-                                       CtdlLogPrintf(CTDL_DEBUG,
-                                                     "unable to get SMTP-Client socket flags! %s \n",
-                                                     strerror(errno));
-                               fdflags = fdflags | O_NONBLOCK;
-                               if (fcntl(sock, F_SETFL, fdflags) < 0)
-                                       CtdlLogPrintf(CTDL_DEBUG,
-                                                     "unable to set SMTP-Client socket nonblocking flags! %s \n",
-                                                     strerror(errno));
+                       syslog(LOG_DEBUG, "SMTP client: connected!");
+                       int fdflags; 
+                       fdflags = fcntl(sock, F_GETFL);
+                       if (fdflags < 0) {
+                               syslog(LOG_DEBUG,
+                                     "unable to get SMTP-Client socket flags! %s",
+                                     strerror(errno)
+                               );
+                       }
+                       fdflags = fdflags | O_NONBLOCK;
+                       if (fcntl(sock, F_SETFL, fdflags) < 0) {
+                               syslog(LOG_DEBUG,
+                                     "unable to set SMTP-Client socket nonblocking flags! %s",
+                                     strerror(errno)
+                               );
+                       }
                }
                if (sock < 0) {
                        if (errno > 0) {
@@ -267,7 +284,7 @@ void smtp_try(const char *key, const char *addr, int *status,
                strcpy(dsn, "Connection broken during SMTP conversation");
                goto bail;
        }
-       CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf);
+       syslog(LOG_DEBUG, "<%s", buf);
        if (buf[0] != '2') {
                if (buf[0] == '4') {
                        *status = 4;
@@ -285,17 +302,17 @@ void smtp_try(const char *key, const char *addr, int *status,
 
        /* 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);
+       syslog(LOG_DEBUG, ">%s", buf);
        sock_write(&sock, buf, strlen(buf));
        if (ml_sock_gets(&sock, buf, 30) < 0) {
                *status = 4;
                strcpy(dsn, "Connection broken during SMTP HELO");
                goto bail;
        }
-       CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf);
+       syslog(LOG_DEBUG, "<%s", buf);
        if (buf[0] != '2') {
                snprintf(buf, sizeof buf, "HELO %s\r\n", config.c_fqdn);
-               CtdlLogPrintf(CTDL_DEBUG, ">%s", buf);
+               syslog(LOG_DEBUG, ">%s", buf);
                sock_write(&sock, buf, strlen(buf));
                if (ml_sock_gets(&sock, buf, 30) < 0) {
                        *status = 4;
@@ -322,14 +339,14 @@ void smtp_try(const char *key, const char *addr, int *status,
                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);
+               syslog(LOG_DEBUG, ">%s", buf);
                sock_write(&sock, buf, strlen(buf));
                if (ml_sock_gets(&sock, buf, 30) < 0) {
                        *status = 4;
                        strcpy(dsn, "Connection broken during SMTP AUTH");
                        goto bail;
                }
-               CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf);
+               syslog(LOG_DEBUG, "<%s", buf);
                if (buf[0] != '2') {
                        if (buf[0] == '4') {
                                *status = 4;
@@ -346,14 +363,14 @@ void smtp_try(const char *key, const char *addr, int *status,
 
        /* 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);
+       syslog(LOG_DEBUG, ">%s", buf);
        sock_write(&sock, buf, strlen(buf));
        if (ml_sock_gets(&sock, buf, 30) < 0) {
                *status = 4;
                strcpy(dsn, "Connection broken during SMTP MAIL");
                goto bail;
        }
-       CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf);
+       syslog(LOG_DEBUG, "<%s", buf);
        if (buf[0] != '2') {
                if (buf[0] == '4') {
                        *status = 4;
@@ -369,14 +386,14 @@ void smtp_try(const char *key, const char *addr, int *status,
 
        /* 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);
+       syslog(LOG_DEBUG, ">%s", buf);
        sock_write(&sock, buf, strlen(buf));
        if (ml_sock_gets(&sock, buf, 30) < 0) {
                *status = 4;
                strcpy(dsn, "Connection broken during SMTP RCPT");
                goto bail;
        }
-       CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf);
+       syslog(LOG_DEBUG, "<%s", buf);
        if (buf[0] != '2') {
                if (buf[0] == '4') {
                        *status = 4;
@@ -391,14 +408,14 @@ void smtp_try(const char *key, const char *addr, int *status,
        }
 
        /* RCPT succeeded, now try the DATA command */
-       CtdlLogPrintf(CTDL_DEBUG, ">DATA\n");
+       syslog(LOG_DEBUG, ">DATA");
        sock_write(&sock, "DATA\r\n", 6);
        if (ml_sock_gets(&sock, buf, 30) < 0) {
                *status = 4;
                strcpy(dsn, "Connection broken during SMTP DATA");
                goto bail;
        }
-       CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf);
+       syslog(LOG_DEBUG, "<%s", buf);
        if (buf[0] != '3') {
                if (buf[0] == '4') {
                        *status = 3;
@@ -418,8 +435,8 @@ void smtp_try(const char *key, const char *addr, int *status,
                           msg_size, 
                           (msg_size / 128) + 50);
        if (msgtext[msg_size-1] != 10) {
-               CtdlLogPrintf(CTDL_WARNING, "Possible problem: message did not "
-                       "correctly terminate. (expecting 0x10, got 0x%02x)\n",
+               syslog(LOG_WARNING, "Possible problem: message did not "
+                       "correctly terminate. (expecting 0x10, got 0x%02x)",
                                buf[msg_size-1]);
                sock_write(&sock, "\r\n", 2);
        }
@@ -431,7 +448,7 @@ void smtp_try(const char *key, const char *addr, int *status,
                strcpy(dsn, "Connection broken during SMTP message transmit");
                goto bail;
        }
-       CtdlLogPrintf(CTDL_DEBUG, "%s\n", buf);
+       syslog(LOG_DEBUG, "%s", buf);
        if (buf[0] != '2') {
                if (buf[0] == '4') {
                        *status = 4;
@@ -449,32 +466,23 @@ void smtp_try(const char *key, const char *addr, int *status,
        safestrncpy(dsn, &buf[4], 1023);
        *status = 2;
 
-       CtdlLogPrintf(CTDL_DEBUG, ">QUIT\n");
+       syslog(LOG_DEBUG, ">QUIT");
        sock_write(&sock, "QUIT\r\n", 6);
        ml_sock_gets(&sock, buf, 30);
-       CtdlLogPrintf(CTDL_DEBUG, "<%s\n", buf);
-       CtdlLogPrintf(CTDL_INFO, "SMTP client: delivery to <%s> @ <%s> (%s) succeeded\n",
-               user, node, name);
+       syslog(LOG_DEBUG, "<%s", buf);
+       syslog(LOG_INFO, "SMTP client: delivery to <%s> @ <%s> (%s) succeeded", user, node, name);
 
 bail:  free(msgtext);
        FreeStrBuf(&CCC->sReadBuf);
        FreeStrBuf(&CCC->sMigrateBuf);
-       if (sock != -1)
+       if (sock != -1) {
                sock_close(sock);
-
-       /* Write something to the syslog (which may or may not be where the
-        * rest of the Citadel logs are going; some sysadmins want LOG_MAIL).
-        */
-       if (enable_syslog) {
-               syslog((LOG_MAIL | LOG_INFO),
-                       "%ld: to=<%s>, relay=%s, stat=%s",
-                       msgnum,
-                       addr,
-                       mx_host,
-                       dsn
-               );
        }
 
+       /* Standard practice is to write DSN to LOG_MAIL which may or may not be where the
+        * rest of the Citadel logs are going.
+        */
+       syslog((LOG_MAIL | LOG_INFO), "%ld: to=<%s>, relay=%s, stat=%s", msgnum, addr, mx_host, dsn);
        return;
 }
 
@@ -507,7 +515,7 @@ void smtp_do_bounce(char *instr) {
        StrBuf *BounceMB;
        long omsgid = (-1);
 
-       CtdlLogPrintf(CTDL_DEBUG, "smtp_do_bounce() called\n");
+       syslog(LOG_DEBUG, "smtp_do_bounce() called");
        strcpy(bounceto, "");
        boundary = NewStrBufPlain(HKEY("=_Citadel_Multipart_"));
        StrBufAppendPrintf(boundary, "%s_%04x%04x", config.c_fqdn, getpid(), ++seq);
@@ -576,8 +584,7 @@ void smtp_do_bounce(char *instr) {
                dsnlen = extract_token(dsn, buf, 3, '|', sizeof dsn);
                bounce_this = 0;
 
-               CtdlLogPrintf(CTDL_DEBUG, "key=<%s> addr=<%s> status=%d dsn=<%s>\n",
-                       key, addr, status, dsn);
+               syslog(LOG_DEBUG, "key=<%s> addr=<%s> status=%d dsn=<%s>", key, addr, status, dsn);
 
                if (!strcasecmp(key, "bounceto")) {
                        strcpy(bounceto, addr);
@@ -630,13 +637,13 @@ void smtp_do_bounce(char *instr) {
                free(bmsg->cm_fields['A']);
        bmsg->cm_fields['A'] = SmashStrBuf(&BounceMB);
        /* Deliver the bounce if there's anything worth mentioning */
-       CtdlLogPrintf(CTDL_DEBUG, "num_bounces = %d\n", num_bounces);
+       syslog(LOG_DEBUG, "num_bounces = %d", num_bounces);
        if (num_bounces > 0) {
 
                /* First try the user who sent the message */
-               CtdlLogPrintf(CTDL_DEBUG, "bounce to user? <%s>\n", bounceto);
+               syslog(LOG_DEBUG, "bounce to user? <%s>", bounceto);
                if (IsEmptyStr(bounceto)) {
-                       CtdlLogPrintf(CTDL_ERR, "No bounce address specified\n");
+                       syslog(LOG_ERR, "No bounce address specified");
                        bounce_msgid = (-1L);
                }
 
@@ -661,7 +668,7 @@ void smtp_do_bounce(char *instr) {
        }
        FreeStrBuf(&boundary);
        CtdlFreeMessage(bmsg);
-       CtdlLogPrintf(CTDL_DEBUG, "Done processing bounces\n");
+       syslog(LOG_DEBUG, "Done processing bounces");
 }
 
 
@@ -731,12 +738,12 @@ void smtp_do_procmsg(long msgnum, void *userdata) {
        time_t last_attempted = 0L;
        time_t retry = SMTP_RETRY_INTERVAL;
 
-       CtdlLogPrintf(CTDL_DEBUG, "SMTP client: smtp_do_procmsg(%ld)\n", msgnum);
+       syslog(LOG_DEBUG, "SMTP client: smtp_do_procmsg(%ld)", msgnum);
        strcpy(envelope_from, "");
 
        msg = CtdlFetchMessage(msgnum, 1);
        if (msg == NULL) {
-               CtdlLogPrintf(CTDL_ERR, "SMTP client: tried %ld but no such message!\n", msgnum);
+               syslog(LOG_ERR, "SMTP client: tried %ld but no such message!", msgnum);
                return;
        }
 
@@ -784,7 +791,7 @@ void smtp_do_procmsg(long msgnum, void *userdata) {
         * Postpone delivery if we've already tried recently.
         */
        if (((time(NULL) - last_attempted) < retry) && (run_queue_now == 0)) {
-               CtdlLogPrintf(CTDL_DEBUG, "SMTP client: Retry time not yet reached.\n");
+               syslog(LOG_DEBUG, "SMTP client: Retry time not yet reached.");
                free(instr);
                return;
        }
@@ -794,7 +801,7 @@ void smtp_do_procmsg(long msgnum, void *userdata) {
         * Bail out if there's no actual message associated with this
         */
        if (text_msgid < 0L) {
-               CtdlLogPrintf(CTDL_ERR, "SMTP client: no 'msgid' directive found!\n");
+               syslog(LOG_ERR, "SMTP client: no 'msgid' directive found!");
                free(instr);
                return;
        }
@@ -824,7 +831,7 @@ void smtp_do_procmsg(long msgnum, void *userdata) {
 
                        --i;
                        --lines;
-                       CtdlLogPrintf(CTDL_DEBUG, "SMTP client: Trying <%s>\n", addr);
+                       syslog(LOG_DEBUG, "SMTP client: Trying <%s>", addr);
                        smtp_try(key, addr, &status, dsn, sizeof dsn, text_msgid, envelope_from);
                        if (status != 2) {
                                if (results == NULL) {
@@ -939,30 +946,24 @@ void cmd_smtp(char *argbuf) {
  * 
  * Run through the queue sending out messages.
  */
-void *smtp_queue_thread(void *arg) {
+void smtp_do_queue(void) {
+       static int is_running = 0;
        int num_processed = 0;
-       struct CitContext smtp_queue_CC;
 
-       CtdlFillSystemContext(&smtp_queue_CC, "SMTP Send");
-       citthread_setspecific(MyConKey, (void *)&smtp_queue_CC);
-       CtdlLogPrintf(CTDL_DEBUG, "smtp_queue_thread() initializing\n");
+       if (is_running) return;         /* Concurrency check - only one can run */
+       is_running = 1;
 
-       while (!CtdlThreadCheckStop()) {
-               
-               CtdlLogPrintf(CTDL_INFO, "SMTP client: processing outbound queue\n");
+       syslog(LOG_INFO, "SMTP client: processing outbound queue");
 
-               if (CtdlGetRoom(&CC->room, SMTP_SPOOLOUT_ROOM) != 0) {
-                       CtdlLogPrintf(CTDL_ERR, "Cannot find room <%s>\n", SMTP_SPOOLOUT_ROOM);
-               }
-               else {
-                       num_processed = CtdlForEachMessage(MSGS_ALL, 0L, NULL, SPOOLMIME, NULL, smtp_do_procmsg, NULL);
-               }
-               CtdlLogPrintf(CTDL_INFO, "SMTP client: queue run completed; %d messages processed\n", num_processed);
-               CtdlThreadSleep(60);
+       if (CtdlGetRoom(&CC->room, SMTP_SPOOLOUT_ROOM) != 0) {
+               syslog(LOG_ERR, "Cannot find room <%s>", SMTP_SPOOLOUT_ROOM);
        }
-
-       CtdlClearSystemContext();
-       return(NULL);
+       else {
+               num_processed = CtdlForEachMessage(MSGS_ALL, 0L, NULL, SPOOLMIME, NULL, smtp_do_procmsg, NULL);
+       }
+       syslog(LOG_INFO, "SMTP client: queue run completed; %d messages processed", num_processed);
+       run_queue_now = 0;
+       is_running = 0;
 }
 
 
@@ -997,12 +998,11 @@ CTDL_MODULE_INIT(smtp_client)
        if (!threading)
        {
                smtp_init_spoolout();
-               CtdlThreadCreate("SMTP Send", CTDLTHREAD_BIGSTACK, smtp_queue_thread, NULL);
+               CtdlRegisterSessionHook(smtp_do_queue, EVT_TIMER);
                CtdlRegisterProtoHook(cmd_smtp, "SMTP", "SMTP utility commands");
        }
-       
 #endif
-       /* return our Subversion id for the Log */
-       return "smtpclient";
+       /* return our module name for the log */
+       return "smtp";
 }