]> code.citadel.org Git - citadel.git/blobdiff - citadel/serv_smtp.c
* Finished the inbound side of gateway domain service
[citadel.git] / citadel / serv_smtp.c
index 4ff49901a7567f106f292e642287710df46bc686..8a7a3147c54749255e969ca12875d64f43321fc0 100644 (file)
@@ -21,6 +21,7 @@
 #include "citserver.h"
 #include "support.h"
 #include "config.h"
+#include "control.h"
 #include "dynloader.h"
 #include "room_ops.h"
 #include "user_ops.h"
@@ -371,7 +372,7 @@ void smtp_rcpt(char *argbuf) {
 
        cvt = convert_internet_address(user, node, recp);
        sprintf(recp, "%s@%s", user, node);
-
+       lprintf(9, "cvt=%d, citaddr=<%s@%s>\n", cvt, user, node);
 
        switch(cvt) {
                case rfc822_address_locally_validated:
@@ -398,7 +399,19 @@ void smtp_rcpt(char *argbuf) {
                        cprintf("550 %s: no such user\r\n", recp);
                        return;
 
-               case rfc822_address_invalid:
+               case rfc822_address_on_citadel_network:
+                       cprintf("250 %s is on the local network\r\n", recp);
+                       ++SMTP->number_of_recipients;
+                       CtdlReallocUserData(SYM_SMTP_RECP,
+                               strlen(SMTP_RECP) + 1024 );
+                       strcat(SMTP_RECP, "ignet|");
+                       strcat(SMTP_RECP, user);
+                       strcat(SMTP_RECP, "|");
+                       strcat(SMTP_RECP, node);
+                       strcat(SMTP_RECP, "|0|\n");
+                       return;
+
+               case rfc822_address_nonlocal:
                        if (is_spam) {
                                cprintf("551 Away with thee, spammer!\r\n");
                        }
@@ -420,6 +433,44 @@ void smtp_rcpt(char *argbuf) {
 
 
 
+/*
+ * Send a message out through the local network
+ * (This is kind of ugly.  IGnet should be done using clean server-to-server
+ * code instead of the old style spool.)
+ */
+void smtp_deliver_ignet(struct CtdlMessage *msg, char *user, char *dest) {
+       struct ser_ret smr;
+       char *hold_R, *hold_D;
+       FILE *fp;
+       char filename[256];
+       static int seq = 0;
+
+       lprintf(9, "smtp_deliver_ignet(msg, %s, %s)\n", user, dest);
+
+       hold_R = msg->cm_fields['R'];
+       hold_D = msg->cm_fields['D'];
+       msg->cm_fields['R'] = user;
+       msg->cm_fields['D'] = dest;
+
+       serialize_message(&smr, msg);
+
+       msg->cm_fields['R'] = hold_R;
+       msg->cm_fields['D'] = hold_D;
+
+       if (smr.len != 0) {
+               sprintf(filename, "./network/spoolin/%s.%04x.%04x",
+                       dest, getpid(), ++seq);
+               lprintf(9, "spool file name is <%s>\n", filename);
+               fp = fopen(filename, "wb");
+               if (fp != NULL) {
+                       fwrite(smr.ser, smr.len, 1, fp);
+                       fclose(fp);
+               }
+               phree(smr.ser);
+       }
+
+}
+
 
 
 /*
@@ -488,6 +539,13 @@ int smtp_message_delivery(struct CtdlMessage *msg) {
                        ++successful_saves;
                }
 
+               /* Delivery over the local Citadel network (IGnet) */
+               if (!strcasecmp(dtype, "ignet")) {
+                       extract(user, buf, 1);
+                       extract(node, buf, 2);
+                       smtp_deliver_ignet(msg, user, node);
+               }
+
                /* Remote delivery */
                if (!strcasecmp(dtype, "remote")) {
                        extract(user, buf, 1);
@@ -704,6 +762,7 @@ void smtp_try(char *key, char *addr, int *status, char *dsn, long msgnum)
 
        /* Parse out the host portion of the recipient address */
        process_rfc822_addr(addr, user, node, name);
+
        lprintf(9, "Attempting SMTP delivery to <%s> @ <%s> (%s)\n",
                user, node, name);
 
@@ -802,12 +861,12 @@ void smtp_try(char *key, char *addr, int *status, char *dsn, long msgnum)
        if (buf[0] != '2') {
                if (buf[0] == '4') {
                        *status = 4;
-                       strcpy(dsn, &buf[4]);
+                       safestrncpy(dsn, &buf[4], 1023);
                        goto bail;
                }
                else {
                        *status = 5;
-                       strcpy(dsn, &buf[4]);
+                       safestrncpy(dsn, &buf[4], 1023);
                        goto bail;
                }
        }
@@ -827,12 +886,12 @@ void smtp_try(char *key, char *addr, int *status, char *dsn, long msgnum)
        if (buf[0] != '2') {
                if (buf[0] == '4') {
                        *status = 4;
-                       strcpy(dsn, &buf[4]);
+                       safestrncpy(dsn, &buf[4], 1023);
                        goto bail;
                }
                else {
                        *status = 5;
-                       strcpy(dsn, &buf[4]);
+                       safestrncpy(dsn, &buf[4], 1023);
                        goto bail;
                }
        }
@@ -851,12 +910,12 @@ void smtp_try(char *key, char *addr, int *status, char *dsn, long msgnum)
        if (buf[0] != '2') {
                if (buf[0] == '4') {
                        *status = 4;
-                       strcpy(dsn, &buf[4]);
+                       safestrncpy(dsn, &buf[4], 1023);
                        goto bail;
                }
                else {
                        *status = 5;
-                       strcpy(dsn, &buf[4]);
+                       safestrncpy(dsn, &buf[4], 1023);
                        goto bail;
                }
        }
@@ -875,12 +934,12 @@ void smtp_try(char *key, char *addr, int *status, char *dsn, long msgnum)
        if (buf[0] != '2') {
                if (buf[0] == '4') {
                        *status = 4;
-                       strcpy(dsn, &buf[4]);
+                       safestrncpy(dsn, &buf[4], 1023);
                        goto bail;
                }
                else {
                        *status = 5;
-                       strcpy(dsn, &buf[4]);
+                       safestrncpy(dsn, &buf[4], 1023);
                        goto bail;
                }
        }
@@ -898,12 +957,12 @@ void smtp_try(char *key, char *addr, int *status, char *dsn, long msgnum)
        if (buf[0] != '3') {
                if (buf[0] == '4') {
                        *status = 3;
-                       strcpy(dsn, &buf[4]);
+                       safestrncpy(dsn, &buf[4], 1023);
                        goto bail;
                }
                else {
                        *status = 5;
-                       strcpy(dsn, &buf[4]);
+                       safestrncpy(dsn, &buf[4], 1023);
                        goto bail;
                }
        }
@@ -933,18 +992,18 @@ void smtp_try(char *key, char *addr, int *status, char *dsn, long msgnum)
        if (buf[0] != '2') {
                if (buf[0] == '4') {
                        *status = 4;
-                       strcpy(dsn, &buf[4]);
+                       safestrncpy(dsn, &buf[4], 1023);
                        goto bail;
                }
                else {
                        *status = 5;
-                       strcpy(dsn, &buf[4]);
+                       safestrncpy(dsn, &buf[4], 1023);
                        goto bail;
                }
        }
 
        /* We did it! */
-       strcpy(dsn, &buf[4]);
+       safestrncpy(dsn, &buf[4], 1023);
        *status = 2;
 
        lprintf(9, ">QUIT\n");
@@ -976,11 +1035,33 @@ void smtp_do_bounce(char *instr) {
        int num_bounces = 0;
        int bounce_this = 0;
        long bounce_msgid = (-1);
+       time_t submitted = 0L;
        struct CtdlMessage *bmsg = NULL;
+       int give_up = 0;
+       int mes_type = 0;
 
        lprintf(9, "smtp_do_bounce() called\n");
        strcpy(bounceto, "");
 
+       lines = num_tokens(instr, '\n');
+
+
+       /* See if it's time to give up on delivery of this message */
+       for (i=0; i<lines; ++i) {
+               extract_token(buf, instr, i, '\n');
+               extract(key, buf, 0);
+               extract(addr, buf, 1);
+               if (!strcasecmp(key, "submitted")) {
+                       submitted = atol(addr);
+               }
+       }
+
+       if ( (time(NULL) - submitted) > SMTP_GIVE_UP ) {
+               give_up = 1;
+       }
+
+
+
        bmsg = (struct CtdlMessage *) mallok(sizeof(struct CtdlMessage));
        if (bmsg == NULL) return;
        memset(bmsg, 0, sizeof(struct CtdlMessage));
@@ -989,15 +1070,24 @@ void smtp_do_bounce(char *instr) {
         bmsg->cm_anon_type = MES_NORMAL;
         bmsg->cm_format_type = 1;
         bmsg->cm_fields['A'] = strdoop("Citadel");
+        bmsg->cm_fields['O'] = strdoop(MAILROOM);
         bmsg->cm_fields['N'] = strdoop(config.c_nodename);
-        bmsg->cm_fields['M'] = strdoop(
 
-"BOUNCE!  BOUNCE!!  BOUNCE!!!\n\n"
-"FIXME ... this message should be made to look nice and stuff.\n"
-"In the meantime, you should be aware that the following\n"
-"recipient addresses had permanent fatal errors:\n\n");
+       if (give_up) bmsg->cm_fields['M'] = strdoop(
+"A message you sent could not be delivered to some or all of its recipients.\n"
+"The following addresses were undeliverable:\n\n"
+);
+
+        else bmsg->cm_fields['M'] = strdoop(
+"A message you sent could not be delivered to some or all of its recipients\n"
+"due to prolonged unavailability of its destination(s).\n"
+"Giving up on the following addresses:\n\n"
+);
+
+       /*
+        * Now go through the instructions checking for stuff.
+        */
 
-       lines = num_tokens(instr, '\n');
        for (i=0; i<lines; ++i) {
                extract_token(buf, instr, i, '\n');
                extract(key, buf, 0);
@@ -1020,6 +1110,7 @@ void smtp_do_bounce(char *instr) {
                   || (!strcasecmp(key, "room"))
                ) {
                        if (status == 5) bounce_this = 1;
+                       if (give_up) bounce_this = 1;
                }
 
                if (bounce_this) {
@@ -1049,10 +1140,19 @@ void smtp_do_bounce(char *instr) {
 
                /* First try the user who sent the message */
                lprintf(9, "bounce to user? <%s>\n", bounceto);
-               if (strlen(bounceto) == 0) bounce_msgid = (-1L);
-               else bounce_msgid = CtdlSaveMsg(bmsg,
-                       bounceto,
-                       "", MES_LOCAL, 1);
+               if (strlen(bounceto) == 0) {
+                       lprintf(7, "No bounce address specified\n");
+                       bounce_msgid = (-1L);
+               }
+               else if (mes_type = alias(bounceto), mes_type == MES_ERROR) {
+                       lprintf(7, "Invalid bounce address <%s>\n", bounceto);
+                       bounce_msgid = (-1L);
+               }
+               else {
+                       bounce_msgid = CtdlSaveMsg(bmsg,
+                               bounceto,
+                               "", mes_type, 1);
+               }
 
                /* Otherwise, go to the Aide> room */
                lprintf(9, "bounce to room?\n");
@@ -1132,6 +1232,8 @@ void smtp_do_procmsg(long msgnum) {
        char dsn[1024];
        long text_msgid = (-1);
        int incomplete_deliveries_remaining;
+       time_t attempted = 0L;
+       time_t last_attempted = 0L;
 
        msg = CtdlFetchMessage(msgnum);
        if (msg == NULL) {
@@ -1154,7 +1256,7 @@ void smtp_do_procmsg(long msgnum) {
                }
        }
 
-       /* Learn the message ID */
+       /* Learn the message ID and find out about recent delivery attempts */
        lines = num_tokens(instr, '\n');
        for (i=0; i<lines; ++i) {
                extract_token(buf, instr, i, '\n');
@@ -1162,8 +1264,27 @@ void smtp_do_procmsg(long msgnum) {
                if (!strcasecmp(key, "msgid")) {
                        text_msgid = extract_long(buf, 1);
                }
+               if (!strcasecmp(key, "attempted")) {
+                       attempted = extract_long(buf, 1);
+                       if (attempted > last_attempted)
+                               last_attempted = attempted;
+               }
        }
 
+
+       /*
+        * Postpone delivery if we've already tried recently.
+        */
+       if ( (time(NULL) - last_attempted) < SMTP_RETRY_INTERVAL) {
+               lprintf(7, "Retry time not yet reached.\n");
+               phree(instr);
+               return;
+       }
+
+
+       /*
+        * Bail out if there's no actual message associated with this
+        */
        if (text_msgid < 0L) {
                lprintf(3, "SMTP: no 'msgid' directive found!\n");
                phree(instr);
@@ -1259,6 +1380,20 @@ void smtp_do_procmsg(long msgnum) {
  * Run through the queue sending out messages.
  */
 void smtp_do_queue(void) {
+       static int doing_queue = 0;
+
+       /*
+        * This is a simple concurrency check to make sure only one queue run
+        * is done at a time.  We could do this with a mutex, but since we
+        * don't really require extremely fine granularity here, we'll do it
+        * with a static variable instead.
+        */
+       if (doing_queue) return;
+       doing_queue = 1;
+
+       /* 
+        * Go ahead and run the queue
+        */
        lprintf(5, "SMTP: processing outbound queue\n");
 
        if (getroom(&CC->quickroom, SMTP_SPOOLOUT_ROOM) != 0) {
@@ -1268,6 +1403,7 @@ void smtp_do_queue(void) {
        CtdlForEachMessage(MSGS_ALL, 0L, SPOOLMIME, NULL, smtp_do_procmsg);
 
        lprintf(5, "SMTP: queue run completed\n");
+       doing_queue = 0;
 }