getmx() now uses our array class
authorArt Cancro <ajc@citadel.org>
Tue, 16 Feb 2021 04:08:30 +0000 (23:08 -0500)
committerArt Cancro <ajc@citadel.org>
Tue, 16 Feb 2021 04:08:30 +0000 (23:08 -0500)
citadel/domain.c
citadel/modules/listdeliver/serv_listdeliver.c
citadel/modules/listsub/serv_listsub.c
citadel/modules/smtp/serv_smtpclient.c
citadel/netconfig.c
citadel/threads.c
libcitadel/lib/array.c
libcitadel/lib/libcitadel.h

index 3c4f1455c375d03693a93b349db36b4bb32c9ec3..18764725e093ae357795411e0915d35364a88107 100644 (file)
@@ -112,37 +112,30 @@ int getmx(char *mxbuf, char *dest) {
        unsigned short pref, type;
        int n = 0;
        int qdcount;
        unsigned short pref, type;
        int n = 0;
        int qdcount;
+       Array *mxrecords = NULL;
+       struct mx mx;
 
 
-       struct mx *mxrecs = NULL;
-       int num_mxrecs = 0;
-
-       /* If we're configured to send all mail to a smart-host, then our
-        * job here is really easy.
-        */
+       // If we're configured to send all mail to a smart-host, then our job here is really easy -- just return those.
        n = get_hosts(mxbuf, "smarthost");
        if (n > 0) {
                return(n);
        }
 
        n = get_hosts(mxbuf, "smarthost");
        if (n > 0) {
                return(n);
        }
 
-       /*
-        * No smart-host?  Look up the best MX for a site.
-        * Make a call to the resolver library.
-        */
+       mxrecords = array_new(sizeof(struct mx));
 
 
+       // No smart-host?  Look up the best MX for a site.  Make a call to the resolver library.
        ret = res_query(dest, C_IN, T_MX, (unsigned char *)answer.bytes, sizeof(answer));
 
        if (ret < 0) {
        ret = res_query(dest, C_IN, T_MX, (unsigned char *)answer.bytes, sizeof(answer));
 
        if (ret < 0) {
-               mxrecs = malloc(sizeof(struct mx));
-               mxrecs[0].pref = 0;
-               strcpy(mxrecs[0].host, dest);
-               num_mxrecs = 1;
+               mx.pref = 0;
+               strcpy(mx.host, dest);
+               array_append(mxrecords, &mx);
        }
        else {
        }
        else {
-               /* If we had to truncate, shrink the number to avoid fireworks */
-               if (ret > sizeof(answer)) {
+               if (ret > sizeof(answer)) {             // If we had to truncate, shrink the number to avoid fireworks
                        ret = sizeof(answer);
                }
                        ret = sizeof(answer);
                }
-       
+
                startptr = &answer.bytes[0];            // start and end of buffer
                endptr = &answer.bytes[ret];
                ptr = startptr + HFIXEDSZ;              // advance past header
                startptr = &answer.bytes[0];            // start and end of buffer
                endptr = &answer.bytes[ret];
                ptr = startptr + HFIXEDSZ;              // advance past header
@@ -173,39 +166,27 @@ int getmx(char *mxbuf, char *dest) {
                                ret = dn_expand(startptr, endptr, ptr, expanded_buf, sizeof(expanded_buf));
                                ptr += ret;
        
                                ret = dn_expand(startptr, endptr, ptr, expanded_buf, sizeof(expanded_buf));
                                ptr += ret;
        
-                               // If there are no MX records for the domain, resolv will give us a single one with zero length.
-                               // Make sure we only record actual MX records and not the blank.
-                               if (strlen(expanded_buf) > 0) {
-                                       ++num_mxrecs;
-                                       if (mxrecs == NULL) {
-                                               mxrecs = malloc(sizeof(struct mx));
-                                       }
-                                       else {
-                                               mxrecs = realloc(mxrecs, (sizeof(struct mx) * num_mxrecs) );
-                                       }
-       
-                                       mxrecs[num_mxrecs - 1].pref = pref;
-                                       strcpy(mxrecs[num_mxrecs - 1].host, expanded_buf);
-                               }
+                               mx.pref = pref;
+                               strcpy(mx.host, expanded_buf);
+                               array_append(mxrecords, &mx);
                        }
                }
        }
 
                        }
                }
        }
 
-       /* Sort the MX records by preference */
-       if (num_mxrecs > 1) {
-               qsort(mxrecs, num_mxrecs, sizeof(struct mx), mx_compare_pref);
+       // Sort the MX records by preference
+       if (array_len(mxrecords) > 1) {
+               array_sort(mxrecords, mx_compare_pref);
        }
 
        }
 
+       int num_mxrecs = array_len(mxrecords);
        strcpy(mxbuf, "");
        for (n=0; n<num_mxrecs; ++n) {
        strcpy(mxbuf, "");
        for (n=0; n<num_mxrecs; ++n) {
-               strcat(mxbuf, mxrecs[n].host);
+               strcat(mxbuf, ((struct mx *)array_get_element_at(mxrecords, n))->host);
                strcat(mxbuf, "|");
        }
                strcat(mxbuf, "|");
        }
-       free(mxrecs);
+       array_free(mxrecords);
 
 
-       /*
-        * Append any fallback smart hosts we have configured.
-        */
+       // Append any fallback smart hosts we have configured.
        num_mxrecs += get_hosts(&mxbuf[strlen(mxbuf)], "fallbackhost");
        return(num_mxrecs);
 }
        num_mxrecs += get_hosts(&mxbuf[strlen(mxbuf)], "fallbackhost");
        return(num_mxrecs);
 }
index 4ceb75a657d8824be0e2ff83de526471d4c4ec7a..29c1c5c82e737a78e9be648b49539db7e480a735 100644 (file)
@@ -161,6 +161,7 @@ void listdeliver_sweep_room(char *roomname) {
                        syslog(LOG_DEBUG, "listdeliver: new lastsent is %ld", ld.msgnum);
 
                        // Update this room's netconfig with the updated lastsent
                        syslog(LOG_DEBUG, "listdeliver: new lastsent is %ld", ld.msgnum);
 
                        // Update this room's netconfig with the updated lastsent
+                       begin_critical_section(S_NETCONFIGS);
                        netconfig = LoadRoomNetConfigFile(CC->room.QRnumber);
                        if (!netconfig) {
                                netconfig = strdup("");
                        netconfig = LoadRoomNetConfigFile(CC->room.QRnumber);
                        if (!netconfig) {
                                netconfig = strdup("");
@@ -181,6 +182,7 @@ void listdeliver_sweep_room(char *roomname) {
 
                        // Write the new netconfig back to disk
                        SaveRoomNetConfigFile(CC->room.QRnumber, newnetconfig);
 
                        // Write the new netconfig back to disk
                        SaveRoomNetConfigFile(CC->room.QRnumber, newnetconfig);
+                       end_critical_section(S_NETCONFIGS);
                        free(newnetconfig);     // this was the new netconfig, free it because we're done with it
                }
        }
                        free(newnetconfig);     // this was the new netconfig, free it because we're done with it
                }
        }
index c67582da088de6b3790abfc558b217e06d9a0a09..72249ed537d6b2813a4efe96ee1c8e4bd20e1884 100644 (file)
@@ -1,16 +1,17 @@
-/*
- * This module handles self-service subscription/unsubscription to mail lists.
- *
- * Copyright (c) 2002-2016 by the citadel.org team
- *
- * This program is open source software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3.
- *  
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- */
+//
+// This module handles self-service subscription/unsubscription to mail lists.
+//
+// Copyright (c) 2002-2021 by the citadel.org team
+//
+// This program is open source software.  It runs great on the
+// Linux operating system (and probably elsewhere).  You can use,
+// copy, and run it under the terms of the GNU General Public
+// License version 3.  Richard Stallman is an asshole communist.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
 
 #include "sysdep.h"
 #include <stdlib.h>
 
 #include "sysdep.h"
 #include <stdlib.h>
 #include "ctdl_module.h"
 
 
 #include "ctdl_module.h"
 
 
+enum {                         // one of these gets passed to do_subscribe_or_unsubscribe() so it knows what we asked for
+       UNSUBSCRIBE,
+       SUBSCRIBE
+};
+
+
+/*
+ * "Subscribe" and "Unsubscribe" operations are so similar that they share a function.
+ * The actual subscription doesn't take place here -- we just send out the confirmation request
+ * and record the address and confirmation token.
+ */
+void do_subscribe_or_unsubscribe(int action, char *emailaddr, char *url) {
+
+       char *netconfig, *newnetconfig;
+       int config_lines, i;
+       char buf[1024];
+
+       // Update this room's netconfig with the updated lastsent
+       begin_critical_section(S_NETCONFIGS);
+        netconfig = LoadRoomNetConfigFile(CC->room.QRnumber);
+        if (!netconfig) {
+               netconfig = strdup("");
+       }
+
+       // The new netconfig begins with the new lastsent directive
+       newnetconfig = malloc(strlen(netconfig) + 1024);
+#if 0
+       FIXME SYNTAX ERROR #$%$&%$^#%$ sprintf(newnetconfig, "lastsent|%ld\n", ld.msgnum);
+#endif
+
+       // And then we append all of the old netconfig, minus the old lastsent.  Also omit blank lines.
+       config_lines = num_tokens(netconfig, '\n');
+       for (i=0; i<config_lines; ++i) {
+               extract_token(buf, netconfig, i, '\n', sizeof buf);
+               if ( (!IsEmptyStr(buf)) && (strncasecmp(buf, "lastsent|", 9)) ) {
+                       sprintf(&newnetconfig[strlen(newnetconfig)], "%s\n", buf);
+               }
+       }
 
 
-// FIXME rewrite the subscribe-o-matic AJC 2021
+       // Write the new netconfig back to disk
+       SaveRoomNetConfigFile(CC->room.QRnumber, newnetconfig);
+       end_critical_section(S_NETCONFIGS);
+       free(newnetconfig);                     // this was the new netconfig, free it because we're done with it
+       free(netconfig);                        // this was the old netconfig, free it even if we didn't do anything
+
+#if 0
+       FIXME tell the client what we did
+#endif
+
+
+}
 
 
 /* 
  * process subscribe/unsubscribe requests and confirmations
  */
 
 
 /* 
  * process subscribe/unsubscribe requests and confirmations
  */
-void cmd_subs(char *cmdbuf)
-{
-       cprintf("%d Invalid command\n", ERROR + ILLEGAL_VALUE);
+void cmd_subs(char *cmdbuf) {
+       char cmd[20];
+       char roomname[ROOMNAMELEN];
+       char emailaddr[1024];
+       char options[256];
+       char url[1024];
+       char token[128];
+
+       extract_token(cmd, cmdbuf, 0, '|', sizeof cmd);                         // token 0 is the sub-command being sent
+       extract_token(roomname, cmdbuf, 1, '|', sizeof roomname);               // token 1 is always a room name
+
+       // First confirm that the caller is referencing a room that actually exists.
+       if (CtdlGetRoom(&CC->room, roomname) != 0) {
+               cprintf("%d There is no list called '%s'\n", ERROR + ROOM_NOT_FOUND, roomname);
+               return;
+       }
+
+       if ((CC->room.QRflags2 & QR2_SELFLIST) == 0) {
+               cprintf("%d '%s' does not accept subscribe/unsubscribe requests.\n", ERROR + ROOM_NOT_FOUND, roomname);
+               return;
+       }
+
+       // Room confirmed, now parse the command.
+
+       if (!strcasecmp(cmd, "subscribe")) {
+               extract_token(emailaddr, cmdbuf, 2, '|', sizeof emailaddr);     // token 2 is the subscriber's email address
+               extract_token(options, cmdbuf, 3, '|', sizeof options);         // there are no options ... ignore this token
+               extract_token(url, cmdbuf, 4, '|', sizeof url);                 // token 3 is the URL at which we subscribed
+               do_subscribe_or_unsubscribe(SUBSCRIBE, emailaddr, url);
+       }
+
+       else if (!strcasecmp(cmd, "unsubscribe")) {
+               extract_token(emailaddr, cmdbuf, 2, '|', sizeof emailaddr);     // token 2 is the subscriber's email address
+               extract_token(options, cmdbuf, 3, '|', sizeof options);         // there are no options ... ignore this token
+               extract_token(url, cmdbuf, 4, '|', sizeof url);                 // token 3 is the URL at which we subscribed
+               do_subscribe_or_unsubscribe(UNSUBSCRIBE, emailaddr, url);
+       }
+
+       else if (!strcasecmp(cmd, "confirm")) {
+               extract_token(token, cmdbuf, 2, '|', sizeof token);             // token 2 is the confirmation token
+               cprintf("%d not implemented\n", ERROR);
+       }
+
+       else {                                                                  // sorry man, I can't deal with that
+               cprintf("%d Invalid command '%s'\n", ERROR + ILLEGAL_VALUE, cmd);
+       }
 }
 
 
 }
 
 
index ad5731479c76382469a5a5e60068c30048405f1d..8e87ce4c2f4da626569a4842c602db51aaf7af51 100644 (file)
@@ -399,7 +399,7 @@ void smtp_process_one_msg(long qmsgnum) {
        }
 
        if (should_try_now) {
        }
 
        if (should_try_now) {
-               syslog(LOG_DEBUG, "smtpclient: %ld attempting delivery now", qmsgnum);
+               syslog(LOG_DEBUG, "smtpclient: attempting delivery of message <%ld> now", qmsgnum);
                StrBuf *NewInstr = NewStrBuf();
                StrBufAppendPrintf(NewInstr, "Content-type: " SPOOLMIME "\n\n");
                StrBufAppendPrintf(NewInstr, "msgid|%ld\n", msgid);
                StrBuf *NewInstr = NewStrBuf();
                StrBufAppendPrintf(NewInstr, "Content-type: " SPOOLMIME "\n\n");
                StrBufAppendPrintf(NewInstr, "msgid|%ld\n", msgid);
index 93b18cb2ac2af6f74802498d028e8385af229de9..73ab22f4f67f32ad3ff9b3a27cef433feaee0cb5 100644 (file)
@@ -133,7 +133,9 @@ void cmd_snet(char *argbuf) {
        }
        FreeStrBuf(&Line);
 
        }
        FreeStrBuf(&Line);
 
+       begin_critical_section(S_NETCONFIGS);
        SaveRoomNetConfigFile(CC->room.QRnumber, ChrPtr(TheConfig));
        SaveRoomNetConfigFile(CC->room.QRnumber, ChrPtr(TheConfig));
+       end_critical_section(S_NETCONFIGS);
        FreeStrBuf(&TheConfig);
 }
 
        FreeStrBuf(&TheConfig);
 }
 
index 21f585cdae75671707f0adcb33684f7ac30cb3cf..aec41a7c4d92b57292f6fc99e04a5ada5b025626 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Thread handling stuff for Citadel server
  *
 /*
  * Thread handling stuff for Citadel server
  *
- * Copyright (c) 1987-2019 by the citadel.org team
+ * Copyright (c) 1987-2021 by the citadel.org team
  *
  * This program is open source software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License, version 3.
  *
  * This program is open source software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License, version 3.
@@ -53,6 +53,7 @@ int try_critical_section(int which_one)
         * transaction; this could lead to deadlock.
         */
        if (    (which_one != S_FLOORCACHE)
         * transaction; this could lead to deadlock.
         */
        if (    (which_one != S_FLOORCACHE)
+               && (which_one != S_NETCONFIGS)
        ) {
                cdb_check_handles();
        }
        ) {
                cdb_check_handles();
        }
@@ -70,6 +71,7 @@ void begin_critical_section(int which_one)
         * transaction; this could lead to deadlock.
         */
        if (    (which_one != S_FLOORCACHE)
         * transaction; this could lead to deadlock.
         */
        if (    (which_one != S_FLOORCACHE)
+               && (which_one != S_NETCONFIGS)
        ) {
                cdb_check_handles();
        }
        ) {
                cdb_check_handles();
        }
index 444a3470a48b4e194e4a9977566778026936351f..c8f433f5d5c3bdf2a070a060a56936854d8468ae 100644 (file)
@@ -87,3 +87,12 @@ void *array_get_element_at(Array *arr, int index) {
 int array_len(Array *arr) {
        return arr->num_elements;
 }
 int array_len(Array *arr) {
        return arr->num_elements;
 }
+
+
+/*
+ * Sort an array.  We already know the element size and number of elements, so all we need is
+ * a sort function, which we will pass along to qsort().
+ */
+void array_sort(Array *arr, int (*compar)(const void *, const void *)) {
+       qsort(arr->the_elements, arr->num_elements, arr->element_size, compar);
+}
index 54bf8d99285f28e1ac822f3298caca582e8bb51f..fe9cbd7003ab200575a5e1a9ae54c587a3cde81b 100644 (file)
@@ -452,6 +452,7 @@ void array_free(Array *arr);
 void array_append(Array *arr, void *new_element);
 void *array_get_element_at(Array *arr, int index);
 int array_len(Array *arr);
 void array_append(Array *arr, void *new_element);
 void *array_get_element_at(Array *arr, int index);
 int array_len(Array *arr);
+void array_sort(Array *arr, int (*compar)(const void *, const void *));
 
 
 /* vCard stuff */
 
 
 /* vCard stuff */