]> code.citadel.org Git - citadel.git/blobdiff - citadel/serv_network.c
mk_module_init.sh now tests to see if echo supports -e and -E
[citadel.git] / citadel / serv_network.c
index 27704f10321fe5af6d06c033df307f9755cb7717..1c8260b9b47497db60f36846499d87d6b284e541 100644 (file)
 #include <limits.h>
 #include "citadel.h"
 #include "server.h"
-#include "sysdep_decls.h"
 #include "citserver.h"
 #include "support.h"
 #include "config.h"
-#include "serv_extensions.h"
 #include "room_ops.h"
 #include "user_ops.h"
 #include "policy.h"
 #include "snprintf.h"
 #endif
 
+
+#include "ctdl_module.h"
+
+
+
 /* Nonzero while we are doing network processing */
 static int doing_queue = 0;
 
 /*
  * When we do network processing, it's accomplished in two passes; one to
  * gather a list of rooms and one to actually do them.  It's ok that rplist
- * is global; this process *only* runs as part of the housekeeping loop and
- * therefore only one will run at a time.
+ * is global; we have a mutex that keeps it safe.
  */
 struct RoomProcList *rplist = NULL;
 
@@ -426,12 +428,11 @@ void cmd_snet(char *argbuf) {
 void network_deliver_digest(struct SpoolControl *sc) {
        char buf[SIZ];
        int i;
-       struct CtdlMessage *msg;
+       struct CtdlMessage *msg = NULL;
        long msglen;
-       long msgnum;
-       char *instr = NULL;
-       size_t instr_len = SIZ;
-       struct CtdlMessage *imsg;
+       char *recps = NULL;
+       size_t recps_len = SIZ;
+       struct recptypes *valid;
        struct namelist *nptr;
 
        if (sc->num_msgs_spooled < 1) {
@@ -473,54 +474,38 @@ void network_deliver_digest(struct SpoolControl *sc) {
        fclose(sc->digestfp);
        sc->digestfp = NULL;
 
-       msgnum = CtdlSubmitMsg(msg, NULL, SMTP_SPOOLOUT_ROOM);
-       CtdlFreeMessage(msg);
-
        /* Now generate the delivery instructions */
 
        /* 
         * Figure out how big a buffer we need to allocate
         */
        for (nptr = sc->digestrecps; nptr != NULL; nptr = nptr->next) {
-               instr_len = instr_len + strlen(nptr->name) + 2;
+               recps_len = recps_len + strlen(nptr->name) + 2;
        }
        
-       /*
-        * allocate...
-        */
-       lprintf(CTDL_DEBUG, "Generating delivery instructions\n");
-       instr = malloc(instr_len);
-       if (instr == NULL) {
-               lprintf(CTDL_EMERG, "Cannot allocate %ld bytes for instr...\n",
-                       (long)instr_len);
+       recps = malloc(recps_len);
+
+       if (recps == NULL) {
+               lprintf(CTDL_EMERG, "Cannot allocate %ld bytes for recps...\n", (long)recps_len);
                abort();
        }
-       snprintf(instr, instr_len,
-               "Content-type: %s\n\nmsgid|%ld\nsubmitted|%ld\n"
-               "bounceto|postmaster@%s\n" ,
-               SPOOLMIME, msgnum, (long)time(NULL), config.c_fqdn );
 
-       /* Generate delivery instructions for each recipient */
+       strcpy(recps, "");
+
+       /* Each recipient */
        for (nptr = sc->digestrecps; nptr != NULL; nptr = nptr->next) {
-               size_t tmp = strlen(instr);
-               snprintf(&instr[tmp], instr_len - tmp,
-                        "remote|%s|0||\n", nptr->name);
+               if (nptr != sc->digestrecps) {
+                       strcat(recps, ",");
+               }
+               strcat(recps, nptr->name);
        }
 
-       /*
-        * Generate a message from the instructions
-        */
-       imsg = malloc(sizeof(struct CtdlMessage));
-       memset(imsg, 0, sizeof(struct CtdlMessage));
-       imsg->cm_magic = CTDLMESSAGE_MAGIC;
-       imsg->cm_anon_type = MES_NORMAL;
-       imsg->cm_format_type = FMT_RFC822;
-       imsg->cm_fields['A'] = strdup("Citadel");
-       imsg->cm_fields['M'] = instr;
-
-       /* Save delivery instructions in spoolout room */
-       CtdlSubmitMsg(imsg, NULL, SMTP_SPOOLOUT_ROOM);
-       CtdlFreeMessage(imsg);
+       /* Now submit the message */
+       valid = validate_recipients(recps);
+       free(recps);
+       CtdlSubmitMsg(msg, valid, NULL);
+       CtdlFreeMessage(msg);
+       free_recipients(valid);
 }
 
 
@@ -528,63 +513,46 @@ void network_deliver_digest(struct SpoolControl *sc) {
  * Deliver list messages to everyone on the list ... efficiently
  */
 void network_deliver_list(struct CtdlMessage *msg, struct SpoolControl *sc) {
-       long msgnum;
-       char *instr = NULL;
-       size_t instr_len = SIZ;
-       struct CtdlMessage *imsg;
+       char *recps = NULL;
+       size_t recps_len = SIZ;
+       struct recptypes *valid;
        struct namelist *nptr;
 
        /* Don't do this if there were no recipients! */
        if (sc->listrecps == NULL) return;
 
-       /* Save the message to disk... */
-       msgnum = CtdlSubmitMsg(msg, NULL, SMTP_SPOOLOUT_ROOM);
-
        /* Now generate the delivery instructions */
 
        /* 
         * Figure out how big a buffer we need to allocate
         */
        for (nptr = sc->listrecps; nptr != NULL; nptr = nptr->next) {
-               instr_len = instr_len + strlen(nptr->name) + 2;
+               recps_len = recps_len + strlen(nptr->name) + 2;
        }
        
-       /*
-        * allocate...
-        */
-       lprintf(CTDL_DEBUG, "Generating delivery instructions\n");
-       instr = malloc(instr_len);
-       if (instr == NULL) {
-               lprintf(CTDL_EMERG, "Cannot allocate %ld bytes for instr...\n",
-                       (long)instr_len);
+       recps = malloc(recps_len);
+
+       if (recps == NULL) {
+               lprintf(CTDL_EMERG, "Cannot allocate %ld bytes for recps...\n", (long)recps_len);
                abort();
        }
-       snprintf(instr, instr_len,
-               "Content-type: %s\n\nmsgid|%ld\nsubmitted|%ld\n"
-               "bounceto|postmaster@%s\n" ,
-               SPOOLMIME, msgnum, (long)time(NULL), config.c_fqdn );
 
-       /* Generate delivery instructions for each recipient */
+       strcpy(recps, "");
+
+       /* Each recipient */
        for (nptr = sc->listrecps; nptr != NULL; nptr = nptr->next) {
-               size_t tmp = strlen(instr);
-               snprintf(&instr[tmp], instr_len - tmp,
-                        "remote|%s|0||\n", nptr->name);
+               if (nptr != sc->listrecps) {
+                       strcat(recps, ",");
+               }
+               strcat(recps, nptr->name);
        }
 
-       /*
-        * Generate a message from the instructions
-        */
-       imsg = malloc(sizeof(struct CtdlMessage));
-       memset(imsg, 0, sizeof(struct CtdlMessage));
-       imsg->cm_magic = CTDLMESSAGE_MAGIC;
-       imsg->cm_anon_type = MES_NORMAL;
-       imsg->cm_format_type = FMT_RFC822;
-       imsg->cm_fields['A'] = strdup("Citadel");
-       imsg->cm_fields['M'] = instr;
-
-       /* Save delivery instructions in spoolout room */
-       CtdlSubmitMsg(imsg, NULL, SMTP_SPOOLOUT_ROOM);
-       CtdlFreeMessage(imsg);
+       /* Now submit the message */
+       valid = validate_recipients(recps);
+       free(recps);
+       CtdlSubmitMsg(msg, valid, NULL);
+       free_recipients(valid);
+       /* Do not call CtdlFreeMessage(msg) here; the caller will free it. */
 }
 
 
@@ -751,7 +719,7 @@ void network_spool_msg(long msgnum, void *userdata) {
        
                                        valid = validate_recipients(nptr->name);
                                        CtdlSubmitMsg(msg, valid, "");
-                                       free(valid);
+                                       free_recipients(valid);
                                }
                        
                        }
@@ -865,7 +833,7 @@ void network_spool_msg(long msgnum, void *userdata) {
 
        /* Delete this message if delete-after-send is set */
        if (delete_after_send) {
-               CtdlDeleteMessages(CC->room.QRname, &msgnum, 1, "", 0);
+               CtdlDeleteMessages(CC->room.QRname, &msgnum, 1, "");
        }
 
 }
@@ -890,6 +858,11 @@ void network_spoolout_room(char *room_to_spool) {
        int skipthisline = 0;
        int i;
 
+       /*
+        * If the room doesn't exist, don't try to perform its networking tasks.
+        * Normally this should never happen, but once in a while maybe a room gets
+        * queued for networking and then deleted before it can happen.
+        */
        if (getroom(&CC->room, room_to_spool) != 0) {
                lprintf(CTDL_CRIT, "ERROR: cannot load <%s>\n", room_to_spool);
                return;
@@ -900,6 +873,7 @@ void network_spoolout_room(char *room_to_spool) {
 
        begin_critical_section(S_NETCONFIGS);
 
+       /* Only do net processing for rooms that have netconfigs */
        fp = fopen(filename, "r");
        if (fp == NULL) {
                end_critical_section(S_NETCONFIGS);
@@ -992,7 +966,7 @@ void network_spoolout_room(char *room_to_spool) {
        }
 
        /* Do something useful */
-       CtdlForEachMessage(MSGS_GT, sc.lastsent, NULL, NULL,
+       CtdlForEachMessage(MSGS_GT, sc.lastsent, NULL, NULL, NULL,
                network_spool_msg, &sc);
 
        /* If we wrote a digest, deliver it and then close it */
@@ -1127,7 +1101,7 @@ int network_sync_to(char *target_node) {
        if (!found_node) return(-1);
 
        /* Send ALL messages */
-       num_spooled = CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL,
+       num_spooled = CtdlForEachMessage(MSGS_ALL, 0L, NULL, NULL, NULL,
                network_spool_msg, &sc);
 
        /* Concise cleanup because we know there's only one node in the sc */
@@ -1171,8 +1145,39 @@ void network_queue_room(struct ctdlroom *qrbuf, void *data) {
        if (ptr == NULL) return;
 
        safestrncpy(ptr->name, qrbuf->QRname, sizeof ptr->name);
+       begin_critical_section(S_RPLIST);
        ptr->next = rplist;
        rplist = ptr;
+       end_critical_section(S_RPLIST);
+}
+
+void destroy_network_queue_room(void)
+{
+       struct RoomProcList *cur, *p;
+       struct NetMap *nmcur, *nmp;
+
+       cur = rplist;
+       begin_critical_section(S_RPLIST);
+       while (cur != NULL)
+       {
+               p = cur->next;
+               free (cur);
+               cur = p;                
+       }
+       rplist = NULL;
+       end_critical_section(S_RPLIST);
+
+       nmcur = the_netmap;
+       while (nmcur != NULL)
+       {
+               nmp = nmcur->next;
+               free (nmcur);
+               nmcur = nmp;            
+       }
+       the_netmap = NULL;
+       if (working_ignetcfg != NULL)
+               free (working_ignetcfg);
+       working_ignetcfg = NULL;
 }
 
 
@@ -1293,7 +1298,7 @@ void network_bounce(struct CtdlMessage *msg, char *reason) {
        /* Now submit the message */
        valid = validate_recipients(recipient);
        if (valid != NULL) if (valid->num_error != 0) {
-               free(valid);
+               free_recipients(valid);
                valid = NULL;
        }
        if ( (valid == NULL) || (!strcasecmp(recipient, bouncesource)) ) {
@@ -1308,7 +1313,7 @@ void network_bounce(struct CtdlMessage *msg, char *reason) {
        CtdlSubmitMsg(msg, valid, force_room);
 
        /* Clean up */
-       if (valid != NULL) free(valid);
+       if (valid != NULL) free_recipients(valid);
        CtdlFreeMessage(msg);
        lprintf(CTDL_DEBUG, "leaving network_bounce()\n");
 }
@@ -1321,7 +1326,7 @@ void network_bounce(struct CtdlMessage *msg, char *reason) {
  * from the inbound queue 
  */
 void network_process_buffer(char *buffer, long size) {
-       struct CtdlMessage *msg;
+       struct CtdlMessage *msg = NULL;
        long pos;
        int field;
        struct recptypes *recp = NULL;
@@ -1452,10 +1457,10 @@ void network_process_buffer(char *buffer, long size) {
                recp = validate_recipients(msg->cm_fields['R']);
                if (recp != NULL) if (recp->num_error != 0) {
                        network_bounce(msg,
-"A message you sent could not be delivered due to an invalid address.\n"
-"Please check the address and try sending the message again.\n");
+                               "A message you sent could not be delivered due to an invalid address.\n"
+                               "Please check the address and try sending the message again.\n");
                        msg = NULL;
-                       free(recp);
+                       free_recipients(recp);
                        return;
                }
                strcpy(target_room, "");        /* no target room if mail */
@@ -1486,7 +1491,7 @@ void network_process_buffer(char *buffer, long size) {
                CtdlSubmitMsg(msg, recp, target_room);
        }
        CtdlFreeMessage(msg);
-       free(recp);
+       free_recipients(recp);
 }
 
 
@@ -1949,13 +1954,31 @@ void network_do_queue(void) {
        if (full_processing) {
                lprintf(CTDL_DEBUG, "network: loading outbound queue\n");
                ForEachRoom(network_queue_room, NULL);
+       }
 
+       if (rplist != NULL) {
                lprintf(CTDL_DEBUG, "network: running outbound queue\n");
                while (rplist != NULL) {
-                       network_spoolout_room(rplist->name);
+                       char spoolroomname[ROOMNAMELEN];
+                       safestrncpy(spoolroomname, rplist->name, sizeof spoolroomname);
+                       begin_critical_section(S_RPLIST);
+
+                       /* pop this record off the list */
                        ptr = rplist;
                        rplist = rplist->next;
                        free(ptr);
+
+                       /* invalidate any duplicate entries to prevent double processing */
+                       for (ptr=rplist; ptr!=NULL; ptr=ptr->next) {
+                               if (!strcasecmp(ptr->name, spoolroomname)) {
+                                       ptr->name[0] = 0;
+                               }
+                       }
+
+                       end_critical_section(S_RPLIST);
+                       if (spoolroomname[0] != 0) {
+                               network_spoolout_room(spoolroomname);
+                       }
                }
        }
 
@@ -2035,10 +2058,16 @@ void cmd_netp(char *cmdbuf)
                CC->net_node);
 }
 
+int network_room_handler (struct ctdlroom *room)
+{
+       network_queue_room(room, NULL);
+       return 0;
+}
+
 /*
  * Module entry point
  */
-char *serv_network_init(void)
+CTDL_MODULE_INIT(network)
 {
        create_spool_dirs();
        CtdlRegisterProtoHook(cmd_gnet, "GNET", "Get network config");
@@ -2046,5 +2075,8 @@ char *serv_network_init(void)
        CtdlRegisterProtoHook(cmd_netp, "NETP", "Identify as network poller");
        CtdlRegisterProtoHook(cmd_nsyn, "NSYN", "Synchronize room to node");
        CtdlRegisterSessionHook(network_do_queue, EVT_TIMER);
+        CtdlRegisterRoomHook(network_room_handler);
+
+       /* return our Subversion id for the Log */
        return "$Id$";
 }