]> code.citadel.org Git - citadel.git/blobdiff - citadel/internet_addressing.c
Saving my place while we try something...
[citadel.git] / citadel / internet_addressing.c
index 132eba9b76bd0227a2c0df539312de4131902aa1..6c46199732e09ffdf555c06064dddc4b1fe9a535 100644 (file)
@@ -44,8 +44,8 @@
 #ifdef HAVE_ICONV
 #include <iconv.h>
 
-#if 0
 /* This is the non-define version in case it is needed for debugging */
+#if 0
 inline void FindNextEnd (char *bptr, char *end)
 {
        /* Find the next ?Q? */
@@ -313,8 +313,7 @@ int CtdlHostAlias(char *fqdn) {
 /*
  * Determine whether a given Internet address belongs to the current user
  */
-int CtdlIsMe(char *addr, int addr_buf_len)
-{
+int CtdlIsMe(char *addr, int addr_buf_len) {
        struct recptypes *recp;
        int i;
 
@@ -392,31 +391,37 @@ enum {
 };
 
 
-/*
- * Aliasing for network mail.
- */
-int expand_aliases(char *name) {                               /* process alias and routing info for mail */
+// Process alias and routing info for email addresses
+int expand_aliases(char *name, char *aliases) {
        int a;
        char aaa[SIZ];
        int at = 0;
-       char node[64];
-
-
-
 
-       // temporary test of expansion
-       if (!strcasecmp(name, "root")) {
-               strcpy(name, "foo,bar,root,baz");
-               return(EA_MULTIPLE);
+       if (aliases) {
+               int num_aliases = num_tokens(aliases, '\n');
+               for (a=0; a<num_aliases; ++a) {
+                       extract_token(aaa, aliases, a, '\n', sizeof aaa);
+                       char *bar = strchr(aaa, '|');
+                       if (bar) {
+                               bar[0] = 0;
+                               ++bar;
+                               striplt(aaa);
+                               striplt(bar);
+                               if ( (!IsEmptyStr(aaa)) && (!strcasecmp(name, aaa)) ) {
+                                       syslog(LOG_DEBUG, "internet_addressing: global alias <%s> to <%s>", name, bar);
+                                       strcpy(name, bar);
+                               }
+                       }
+               }
+               if (strchr(name, ',')) {
+                       return(EA_MULTIPLE);
+               }
        }
 
-
-
-
-
-       char original_name[256];
+       char original_name[256];                                // Now go for the regular aliases
        safestrncpy(original_name, name, sizeof original_name);
 
+       // should these checks still be here, or maybe move them to split_recps() ?
        striplt(name);
        remove_any_whitespace_to_the_left_or_right_of_at_symbol(name);
        stripallbut(name, '<', '>');
@@ -427,7 +432,7 @@ int expand_aliases(char *name) {                            /* process alias and routing info for mail *
        }
 
        if (strcasecmp(original_name, name)) {
-               syslog(LOG_INFO, "internet_addressing: %s is being forwarded to %s", original_name, name);
+               syslog(LOG_INFO, "internet_addressing: directory alias <%s> to <%s>", original_name, name);
        }
 
        /* Change "user @ xxx" to "user" if xxx is an alias for this host */
@@ -435,30 +440,23 @@ int expand_aliases(char *name) {                          /* process alias and routing info for mail *
                if (name[a] == '@') {
                        if (CtdlHostAlias(&name[a+1]) == hostalias_localhost) {
                                name[a] = 0;
-                               syslog(LOG_DEBUG, "internet_addressing: changed to <%s>", name);
+                               syslog(LOG_DEBUG, "internet_addressing: host is local, recipient is <%s>", name);
                                break;
                        }
                }
        }
 
-       /* determine local or remote type, see citadel.h */
+       /* Is this a local or remote recipient? */
        at = haschar(name, '@');
-       if (at == 0) return(EA_LOCAL);          /* no @'s - local address */
-       if (at > 1) return(EA_ERROR);           /* >1 @'s - invalid address */
-       remove_any_whitespace_to_the_left_or_right_of_at_symbol(name);
-
-       /* figure out the delivery mode */
-       extract_token(node, name, 1, '@', sizeof node);
-
-       /* If there are one or more dots in the nodename, we assume that it
-        * is an FQDN and will attempt SMTP delivery to the Internet.
-        */
-       if (haschar(node, '.') > 0) {
-               return(EA_INTERNET);
+       if (at == 0) {
+               return(EA_LOCAL);                       /* no @'s = local address */
+       }
+       else if (at == 1) {
+               return(EA_INTERNET);                    /* one @ = internet address */
+       }
+       else {
+               return(EA_ERROR);                       /* more than one @ = badly formed address */
        }
-
-       /* If we get to this point it's an invalid node name */
-       return (EA_ERROR);
 }
 
 
@@ -467,9 +465,13 @@ Array *split_recps(char *addresses) {
 
        // Copy the supplied address list into our own memory space, because we are going to mangle it.
        char *a = malloc(strlen(addresses));
-       a[0] = 0;
+       if (a == NULL) {
+               syslog(LOG_ERR, "internet_addressing: malloc() failed: %m");
+               return(NULL);
+       }
 
        // Strip out anything in double quotes
+       a[0] = 0;
        int toggle = 0;
        int pos = 0;
        char *t;
@@ -492,12 +494,17 @@ Array *split_recps(char *addresses) {
 
        // Tokenize the recipients into an array
        Array *recipients_array = array_new(256);               // no single recipient should be bigger than 256 bytes
-       char *r = a;
-       while ((t = strtok_r(r, ",", &r))) {
-               striplt(t);                                     // strip leading and trailing whitespace
-               stripout(t, '(', ')');                          // remove any portion in parentheses
-               stripallbut(t, '<', '>');                       // if angle brackets are present, keep only what is inside them
-               array_append(recipients_array, t);
+
+       int num_addresses = num_tokens(a, ',');
+       for (int i=0; i<num_addresses; ++i) {
+               char this_address[256];
+               extract_token(this_address, a, i, ',', sizeof this_address);
+               striplt(this_address);                          // strip leading and trailing whitespace
+               stripout(this_address, '(', ')');               // remove any portion in parentheses
+               stripallbut(this_address, '<', '>');            // if angle brackets are present, keep only what is inside them
+               if (!IsEmptyStr(this_address)) {
+                       array_append(recipients_array, this_address);
+               }
        }
 
        free(a);                                                // We don't need this buffer anymore.
@@ -521,8 +528,7 @@ struct recptypes *validate_recipients(char *supplied_recipients, const char *Rem
        int mailtype;
        int invalid;
        struct ctdluser tempUS;
-       struct ctdlroom tempQR;
-       struct ctdlroom tempQR2;
+       struct ctdlroom original_room;
        int err = 0;
        char errmsg[SIZ];
        char *org_recp;
@@ -530,7 +536,6 @@ struct recptypes *validate_recipients(char *supplied_recipients, const char *Rem
 
        ret = (struct recptypes *) malloc(sizeof(struct recptypes));                    // Initialize
        if (ret == NULL) return(NULL);
-
        memset(ret, 0, sizeof(struct recptypes));                                       // set all values to null/zero
 
        if (supplied_recipients == NULL) {
@@ -554,43 +559,53 @@ struct recptypes *validate_recipients(char *supplied_recipients, const char *Rem
        ret->recp_room[0] = 0;
        ret->recp_orgroom[0] = 0;
        ret->display_recp[0] = 0;
-
        ret->recptypes_magic = RECPTYPES_MAGIC;
 
+       // char *aliases = CtdlGetSysConfig(GLOBAL_ALIASES);                            // First hit the Global Alias Table
+       // char *aliases = strdup("root|admin,ajc@citadel.org,artcancro@gmail.com\n abuse|admin\n ajc|ajc@citadel.org\n");//crashes
+       // char *aliases = strdup("root|admin,eeeeee@example.com\nabuse|admin\neek|blat\nwoiwozerosf|wow\n"); //works
+       // char *aliases = strdup("root|admin,ajc@citadel.org");        // works
+       // char *aliases = strdup("root|admin,eeeeee@example.com");     // works
+       // char *aliases = strdup("root|admin,eeeeeee@example.com");    // crashes
+       char *aliases = strdup("root|admin,ignatius.t.foobar@uncensored.citadel.org");  // crashes on the first try
 
        Array *recp_array = split_recps(supplied_recipients);
-
-
-
+       int original_array_len = array_len(recp_array);
        for (int r=0; r<array_len(recp_array); ++r) {
                org_recp = (char *)array_get_element_at(recp_array, r);
                strncpy(this_recp, org_recp, sizeof this_recp);
+               mailtype = expand_aliases(this_recp, aliases);
 
-
-
-               // To prevent endless aliasing loops, we will only do this five times.
-               for (int alias_loop=0; alias_loop<5; ++alias_loop) {
-                       mailtype = expand_aliases(this_recp);
-                       if (mailtype == EA_MULTIPLE) {
-                               // If an alias expanded to multiple recipients, strip off those recipients and append them
-                               // to the end of the array.  This loop will hit those again when it gets there.
+               // If an alias expanded to multiple recipients, strip off those recipients and append them
+               // to the end of the array.  This loop will hit those again when it gets there.
+               // Note that we don't do this after we get past the *original* array length, to avoid aliasing loops.
+               if (mailtype == EA_MULTIPLE) {
+                       if (r < original_array_len) {
                                char *comma;
-                               while (comma = strrchr(this_recp, ',')) {
+                               while ((comma = strrchr(this_recp, ','))) {
                                        comma[0] = 0;
                                        array_append(recp_array, &comma[1]);
                                        strcpy(org_recp, this_recp);
                                }
                        }
+                       else {
+                               mailtype = EA_ERROR;
+                       }
                }
 
+               syslog(LOG_DEBUG, "\x1b[7m%s\x1b[0m", this_recp);
 
-               syslog(LOG_DEBUG, "this_recp: \033[31m%s\033[0m   org_recp: \033[32m%s\033[0m", this_recp, org_recp);
-
+               mailtype = expand_aliases(this_recp, aliases);  // do it ONCE again to handle alias expansions
+               if (mailtype == EA_MULTIPLE) {
+                       mailtype = EA_ERROR;                    // and fail if it wants to expand a second time
+               }
 
                invalid = 0;
                errmsg[0] = 0;
                switch(mailtype) {
-               case EA_LOCAL:
+               case EA_LOCAL:                                  // There are several types of "local" recipients.
+
+                       // Old BBS conventions require mail to "sysop" to go somewhere.  Send it to the admin room.
                        if (!strcasecmp(this_recp, "sysop")) {
                                ++ret->num_room;
                                strcpy(this_recp, CtdlGetConfigStr("c_aideroom"));
@@ -599,45 +614,55 @@ struct recptypes *validate_recipients(char *supplied_recipients, const char *Rem
                                }
                                strcat(ret->recp_room, this_recp);
                        }
-                       else if ( (!strncasecmp(this_recp, "room_", 5)) && (!CtdlGetRoom(&tempQR, &this_recp[5])) ) {
 
+                       // This handles rooms which can receive posts via email.
+                       else if (!strncasecmp(this_recp, "room_", 5)) {
+                               original_room = CC->room;                               // Remember where we parked
 
-                               // FIXME -- handle the underscores
-
-
-                                                                                       // Save room so we can restore it later
-                               tempQR2 = CC->room;
-                               CC->room = tempQR;
-                                       
-                               err = CtdlDoIHavePermissionToPostInThisRoom(            // check for write permissions to room
-                                       errmsg, 
-                                       sizeof errmsg, 
-                                       RemoteIdentifier,
-                                       Flags,
-                                       0                                               // 0 means "not a reply"
-                               );
-                               if (err) {
+                               char mail_to_room[ROOMNAMELEN];
+                               char *m;
+                               strncpy(mail_to_room, &this_recp[5], sizeof mail_to_room);
+                               for (m = mail_to_room; *m; ++m) {
+                                       if (m[0] == '_') m[0]=' ';
+                               }
+                               if (!CtdlGetRoom(&CC->room, mail_to_room)) {            // Find the room they asked for
+
+                                       err = CtdlDoIHavePermissionToPostInThisRoom(    // check for write permissions to room
+                                               errmsg, 
+                                               sizeof errmsg, 
+                                               RemoteIdentifier,
+                                               Flags,
+                                               0                                       // 0 means "this is not a reply"
+                                       );
+                                       if (err) {
+                                               ++ret->num_error;
+                                               invalid = 1;
+                                       } 
+                                       else {
+                                               ++ret->num_room;
+                                               if (!IsEmptyStr(ret->recp_room)) {
+                                                       strcat(ret->recp_room, "|");
+                                               }
+                                               strcat(ret->recp_room, &this_recp[5]);
+       
+                                               if (!IsEmptyStr(ret->recp_orgroom)) {
+                                                       strcat(ret->recp_orgroom, "|");
+                                               }
+                                               strcat(ret->recp_orgroom, org_recp);
+       
+                                       }
+                               }
+                               else {                                                  // no such room exists
                                        ++ret->num_error;
                                        invalid = 1;
-                               } 
-                               else {
-                                       ++ret->num_room;
-                                       if (!IsEmptyStr(ret->recp_room)) {
-                                               strcat(ret->recp_room, "|");
-                                       }
-                                       strcat(ret->recp_room, &this_recp[5]);
-
-                                       if (!IsEmptyStr(ret->recp_orgroom)) {
-                                               strcat(ret->recp_orgroom, "|");
-                                       }
-                                       strcat(ret->recp_orgroom, org_recp);
-
                                }
-                                       
-                               /* Restore room in case something needs it */
-                               CC->room = tempQR2;
+                                               
+                               // Restore this session's original room location.
+                               CC->room = original_room;
 
                        }
+
+                       // This handles the most common case, which is mail to a user's inbox.
                        else if (CtdlGetUser(&tempUS, this_recp) == 0) {
                                ++ret->num_local;
                                strcpy(this_recp, tempUS.fullname);
@@ -646,18 +671,17 @@ struct recptypes *validate_recipients(char *supplied_recipients, const char *Rem
                                }
                                strcat(ret->recp_local, this_recp);
                        }
+
+                       // No match for this recipient
                        else {
                                ++ret->num_error;
                                invalid = 1;
                        }
                        break;
                case EA_INTERNET:
-                       /* Yes, you're reading this correctly: if the target
-                        * domain points back to the local system,
-                        * the address is invalid.  That's
-                        * because if the address were valid, we would have
-                        * already translated it to a local address by now.
-                        */
+                       // Yes, you're reading this correctly: if the target domain points back to the local system,
+                       // the address is invalid.  That's because if the address were valid, we would have
+                       // already translated it to a local address by now.
                        if (IsDirectory(this_recp, 0)) {
                                ++ret->num_error;
                                invalid = 1;
@@ -702,6 +726,10 @@ struct recptypes *validate_recipients(char *supplied_recipients, const char *Rem
                }
        }
 
+       if (aliases != NULL) {          // ok, we're done with the global alias list now
+               free(aliases);
+       }
+
        if ( (ret->num_local + ret->num_internet + ret->num_room + ret->num_error) == 0) {
                ret->num_error = (-1);
                strcpy(ret->errormsg, "No recipients specified.");