* Cc: and Bcc: support. Not finished yet.
[citadel.git] / citadel / serv_network.c
index 8d90f311c19c4a0a944a15fac8d2b11cf6f9fc13..668ed2964a30958c0af986b066cb4096820e79eb 100644 (file)
@@ -31,6 +31,7 @@
 #include <signal.h>
 #include <pwd.h>
 #include <errno.h>
+#include <sys/stat.h>
 #include <sys/types.h>
 #include <dirent.h>
 #if TIME_WITH_SYS_TIME
@@ -84,6 +85,7 @@ struct RoomProcList *rplist = NULL;
  * We build a map of network nodes during processing.
  */
 struct NetMap *the_netmap = NULL;
+int netmap_changed = 0;
 char *working_ignetcfg = NULL;
 
 /*
@@ -233,6 +235,7 @@ void read_network_map(void) {
        }
 
        free(serialized_map);
+       netmap_changed = 0;
 }
 
 
@@ -243,25 +246,28 @@ void write_network_map(void) {
        char *serialized_map = NULL;
        struct NetMap *nmptr;
 
-       serialized_map = strdup("");
 
-       if (the_netmap != NULL) {
-               for (nmptr = the_netmap; nmptr != NULL; nmptr = nmptr->next) {
-                       serialized_map = realloc(serialized_map,
-                                               (strlen(serialized_map)+SIZ) );
-                       if (strlen(nmptr->nodename) > 0) {
-                               snprintf(&serialized_map[strlen(serialized_map)],
-                                       SIZ,
-                                       "%s|%ld|%s\n",
-                                       nmptr->nodename,
-                                       (long)nmptr->lastcontact,
-                                       nmptr->nexthop);
+       if (netmap_changed) {
+               serialized_map = strdup("");
+       
+               if (the_netmap != NULL) {
+                       for (nmptr = the_netmap; nmptr != NULL; nmptr = nmptr->next) {
+                               serialized_map = realloc(serialized_map,
+                                                       (strlen(serialized_map)+SIZ) );
+                               if (strlen(nmptr->nodename) > 0) {
+                                       snprintf(&serialized_map[strlen(serialized_map)],
+                                               SIZ,
+                                               "%s|%ld|%s\n",
+                                               nmptr->nodename,
+                                               (long)nmptr->lastcontact,
+                                               nmptr->nexthop);
+                               }
                        }
                }
-       }
 
-       CtdlPutSysConfig(IGNETMAP, serialized_map);
-       free(serialized_map);
+               CtdlPutSysConfig(IGNETMAP, serialized_map);
+               free(serialized_map);
+       }
 
        /* Now free the list */
        while (the_netmap != NULL) {
@@ -269,6 +275,7 @@ void write_network_map(void) {
                free(the_netmap);
                the_netmap = nmptr;
        }
+       netmap_changed = 0;
 }
 
 
@@ -417,13 +424,10 @@ void cmd_snet(char *argbuf) {
  */
 void network_spool_msg(long msgnum, void *userdata) {
        struct SpoolControl *sc;
-       int err;
        int i;
        char *newpath = NULL;
-       char *instr = NULL;
        size_t instr_len = SIZ;
        struct CtdlMessage *msg = NULL;
-       struct CtdlMessage *imsg;
        struct namelist *nptr;
        struct maplist *mptr;
        struct ser_ret sermsg;
@@ -433,8 +437,8 @@ void network_spool_msg(long msgnum, void *userdata) {
        int bang = 0;
        int send = 1;
        int delete_after_send = 0;      /* Set to 1 to delete after spooling */
-       long list_msgnum = 0L;
        int ok_to_participate = 0;
+       struct recptypes *valid;
 
        sc = (struct SpoolControl *)userdata;
 
@@ -443,68 +447,79 @@ void network_spool_msg(long msgnum, void *userdata) {
         */
        instr_len = SIZ;
        if (sc->listrecps != NULL) {
-       
-               /* First, copy it to the spoolout room */
-               err = CtdlSaveMsgPointerInRoom(SMTP_SPOOLOUT_ROOM, msgnum, 0);
-               if (err != 0) return;
-
-               /* 
-                * 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);
-               }
-       
-               /*
-                * 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);
-                       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 */
-               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);
+               /* Fetch the message.  We're going to need to modify it
+                * for each recipient in order to satisfy foreign mailers, etc.
+                */
+               msg = CtdlFetchMessage(msgnum, 1);
+               if (msg != NULL) {
+
+                       /* Prepend "[List name]" to the subject */
+                       if (msg->cm_fields['U'] == NULL) {
+                               msg->cm_fields['U'] = strdup("(no subject)");
+                       }
+                       snprintf(buf, sizeof buf, "[%s] %s", CC->room.QRname, msg->cm_fields['U']);
+                       free(msg->cm_fields['U']);
+                       msg->cm_fields['U'] = strdup(buf);
+
+                       /* For each recipient... */
+                       for (nptr = sc->listrecps; nptr != NULL; nptr = nptr->next) {
+
+                               if (msg->cm_fields['R'] == NULL) {
+                                       free(msg->cm_fields['R']);
+                               }
+                               msg->cm_fields['R'] = strdup(nptr->name);
+
+                               valid = validate_recipients(nptr->name);
+                               CtdlSubmitMsg(msg, valid, NULL, NULL, "");
+                               free(valid);
+
+                       }
+                       CtdlFreeMessage(msg);
                }
-       
-               /*
-                * 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);
        }
 
        /*
         * Process digest recipients
         */
        if ((sc->digestrecps != NULL) && (sc->digestfp != NULL)) {
-               fprintf(sc->digestfp,   " -----------------------------------"
-                                       "------------------------------------"
-                                       "-------\n");
-               CtdlRedirectOutput(sc->digestfp);
-               CtdlOutputMsg(msgnum, MT_RFC822, HEADERS_ALL, 0, 0);
-               CtdlRedirectOutput(NULL);
-               sc->num_msgs_spooled += 1;
+               msg = CtdlFetchMessage(msgnum, 1);
+               if (msg != NULL) {
+                       fprintf(sc->digestfp,   " -----------------------------------"
+                                               "------------------------------------"
+                                               "-------\n");
+                       fprintf(sc->digestfp, "From: ");
+                       if (msg->cm_fields['A'] != NULL) {
+                               fprintf(sc->digestfp, "%s ", msg->cm_fields['A']);
+                       }
+                       if (msg->cm_fields['F'] != NULL) {
+                               fprintf(sc->digestfp, "<%s> ", msg->cm_fields['F']);
+                       }
+                       else if (msg->cm_fields['N'] != NULL) {
+                               fprintf(sc->digestfp, "@%s ", msg->cm_fields['N']);
+                       }
+                       fprintf(sc->digestfp, "\n");
+                       if (msg->cm_fields['U'] != NULL) {
+                               fprintf(sc->digestfp, "Subject: %s\n", msg->cm_fields['U']);
+                       }
+
+                       CC->redirect_buffer = malloc(SIZ);
+                       CC->redirect_len = 0;
+                       CC->redirect_alloc = SIZ;
+
+                       safestrncpy(CC->preferred_formats, "text/plain", sizeof CC->preferred_formats);
+                       CtdlOutputPreLoadedMsg(msg, 0L, MT_CITADEL, HEADERS_NONE, 0, 0);
+
+                       striplt(CC->redirect_buffer);
+                       fprintf(sc->digestfp, "\n%s\n", CC->redirect_buffer);
+
+                       free(CC->redirect_buffer);
+                       CC->redirect_buffer = NULL;
+                       CC->redirect_len = 0;
+                       CC->redirect_alloc = 0;
+
+                       sc->num_msgs_spooled += 1;
+                       free(msg);
+               }
        }
 
        /*
@@ -547,52 +562,21 @@ void network_spool_msg(long msgnum, void *userdata) {
                                        }
                                }
 
-                               /* Now save it and generate delivery instructions */
-                               list_msgnum = CtdlSubmitMsg(msg, NULL, SMTP_SPOOLOUT_ROOM);
-
                                /* 
                                 * Figure out how big a buffer we need to allocate
                                 */
                                for (nptr = sc->participates; nptr != NULL; nptr = nptr->next) {
-                                       instr_len = instr_len + strlen(nptr->name);
-                               }
-                       
-                               /*
-                                * allocate...
-                                */
-                               instr = malloc(instr_len);
-                               if (instr == NULL) {
-                                       lprintf(CTDL_EMERG,
-                                               "Cannot allocate %ld bytes for instr...\n",
-                                               (long)instr_len);
-                                       abort();
-                               }
-                               snprintf(instr, instr_len,
-                                       "Content-type: %s\n\nmsgid|%ld\nsubmitted|%ld\n"
-                                       "bounceto|postmaster@%s\n" ,
-                                       SPOOLMIME, list_msgnum, (long)time(NULL), config.c_fqdn );
-                       
-                               /* Generate delivery instructions for each recipient */
-                               for (nptr = sc->participates; nptr != NULL; nptr = nptr->next) {
-                                       size_t tmp = strlen(instr);
-                                       snprintf(&instr[tmp], instr_len - tmp,
-                                                "remote|%s|0||\n", nptr->name);
+
+                                       if (msg->cm_fields['R'] == NULL) {
+                                               free(msg->cm_fields['R']);
+                                       }
+                                       msg->cm_fields['R'] = strdup(nptr->name);
+       
+                                       valid = validate_recipients(nptr->name);
+                                       CtdlSubmitMsg(msg, valid, NULL, NULL, "");
+                                       free(valid);
                                }
                        
-                               /*
-                                * 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);
                        }
                        CtdlFreeMessage(msg);
                }
@@ -678,14 +662,23 @@ void network_spool_msg(long msgnum, void *userdata) {
 
                                        /* write it to the spool file */
                                        snprintf(filename, sizeof filename,
-                                               "./network/spoolout/%s",
-                                               mptr->remote_nodename);
+#ifndef HAVE_SPOOL_DIR
+                                                        "."
+#else
+                                                        SPOOL_DIR
+#endif /* HAVE_SPOOL_DIR */
+                                                        "/network/spoolout/%s",
+                                                        mptr->remote_nodename);
+                                       lprintf(CTDL_DEBUG, "Appending to %s\n", filename);
                                        fp = fopen(filename, "ab");
                                        if (fp != NULL) {
                                                fwrite(sermsg.ser,
                                                        sermsg.len, 1, fp);
                                                fclose(fp);
                                        }
+                                       else {
+                                               lprintf(CTDL_ERR, "%s: %s\n", filename, strerror(errno));
+                                       }
 
                                        /* free the serialized version */
                                        free(sermsg.ser);
@@ -700,7 +693,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, "");
+               CtdlDeleteMessages(CC->room.QRname, msgnum, "", 0);
        }
 
 }
@@ -735,7 +728,8 @@ void network_deliver_digest(struct SpoolControl *sc) {
        sprintf(buf, "%ld", time(NULL));
        msg->cm_fields['T'] = strdup(buf);
        msg->cm_fields['A'] = strdup(CC->room.QRname);
-       msg->cm_fields['U'] = strdup(CC->room.QRname);
+       snprintf(buf, sizeof buf, "[%s]", CC->room.QRname);
+       msg->cm_fields['U'] = strdup(buf);
        sprintf(buf, "room_%s@%s", CC->room.QRname, config.c_fqdn);
        for (i=0; i<strlen(buf); ++i) {
                if (isspace(buf[i])) buf[i]='_';
@@ -754,7 +748,7 @@ void network_deliver_digest(struct SpoolControl *sc) {
        fclose(sc->digestfp);
        sc->digestfp = NULL;
 
-       msgnum = CtdlSubmitMsg(msg, NULL, SMTP_SPOOLOUT_ROOM);
+       msgnum = CtdlSubmitMsg(msg, NULL, NULL, NULL, SMTP_SPOOLOUT_ROOM);
        CtdlFreeMessage(msg);
 
        /* Now generate the delivery instructions */
@@ -800,7 +794,7 @@ void network_deliver_digest(struct SpoolControl *sc) {
        imsg->cm_fields['M'] = instr;
 
        /* Save delivery instructions in spoolout room */
-       CtdlSubmitMsg(imsg, NULL, SMTP_SPOOLOUT_ROOM);
+       CtdlSubmitMsg(imsg, NULL, NULL, NULL, SMTP_SPOOLOUT_ROOM);
        CtdlFreeMessage(imsg);
 }
 
@@ -1124,6 +1118,7 @@ void network_learn_topology(char *node, char *path) {
                if (!strcasecmp(nmptr->nodename, node)) {
                        extract_token(nmptr->nexthop, path, 0, '!', sizeof nmptr->nexthop);
                        nmptr->lastcontact = time(NULL);
+                       ++netmap_changed;
                        return;
                }
        }
@@ -1135,6 +1130,7 @@ void network_learn_topology(char *node, char *path) {
        extract_token(nmptr->nexthop, path, 0, '!', sizeof nmptr->nexthop);
        nmptr->next = the_netmap;
        the_netmap = nmptr;
+       ++netmap_changed;
 }
 
 
@@ -1201,9 +1197,13 @@ void network_bounce(struct CtdlMessage *msg, char *reason) {
                free(msg->cm_fields['N']);
        }
 
+       if (msg->cm_fields['U'] == NULL) {
+               free(msg->cm_fields['U']);
+       }
+
        msg->cm_fields['A'] = strdup(BOUNCESOURCE);
        msg->cm_fields['N'] = strdup(config.c_nodename);
-       
+       msg->cm_fields['U'] = strdup("Delivery Status Notification (Failure)");
 
        /* prepend our node to the path */
        if (msg->cm_fields['P'] != NULL) {
@@ -1233,7 +1233,7 @@ void network_bounce(struct CtdlMessage *msg, char *reason) {
        if ( (valid == NULL) && (strlen(force_room) == 0) ) {
                strcpy(force_room, config.c_aideroom);
        }
-       CtdlSubmitMsg(msg, valid, force_room);
+       CtdlSubmitMsg(msg, valid, NULL, NULL, force_room);
 
        /* Clean up */
        if (valid != NULL) free(valid);
@@ -1276,11 +1276,11 @@ void network_process_buffer(char *buffer, long size) {
        strcpy(target_room, TWITROOM);
 
        /* Load the message into memory */
-        msg = (struct CtdlMessage *) malloc(sizeof(struct CtdlMessage));
-        memset(msg, 0, sizeof(struct CtdlMessage));
-        msg->cm_magic = CTDLMESSAGE_MAGIC;
-        msg->cm_anon_type = buffer[1];
-        msg->cm_format_type = buffer[2];
+       msg = (struct CtdlMessage *) malloc(sizeof(struct CtdlMessage));
+       memset(msg, 0, sizeof(struct CtdlMessage));
+       msg->cm_magic = CTDLMESSAGE_MAGIC;
+       msg->cm_anon_type = buffer[1];
+       msg->cm_format_type = buffer[2];
 
        for (pos = 3; pos < size; ++pos) {
                field = buffer[pos];
@@ -1319,13 +1319,22 @@ void network_process_buffer(char *buffer, long size) {
                                        strcpy(nexthop, msg->cm_fields['D']);
                                }
                                snprintf(filename, sizeof filename,
-                                       "./network/spoolout/%s", nexthop);
+#ifndef HAVE_SPOOL_DIR
+                                                "."
+#else
+                                                SPOOL_DIR
+#endif /* HAVE_SPOOL_DIR */
+                                                "/network/spoolout/%s", nexthop);
+                               lprintf(CTDL_DEBUG, "Appending to %s\n", filename);
                                fp = fopen(filename, "ab");
                                if (fp != NULL) {
                                        fwrite(sermsg.ser,
                                                sermsg.len, 1, fp);
                                        fclose(fp);
                                }
+                               else {
+                                       lprintf(CTDL_ERR, "%s: %s\n", filename, strerror(errno));
+                               }
                                free(sermsg.ser);
                                CtdlFreeMessage(msg);
                                return;
@@ -1378,7 +1387,7 @@ void network_process_buffer(char *buffer, long size) {
                        msg = NULL;
                        free(recp);
                        return;
-                }
+               }
                strcpy(target_room, "");        /* no target room if mail */
        }
 
@@ -1404,7 +1413,7 @@ void network_process_buffer(char *buffer, long size) {
        /* save the message into a room */
        if (PerformNetprocHooks(msg, target_room) == 0) {
                msg->cm_flags = CM_SKIP_HOOKS;
-               CtdlSubmitMsg(msg, recp, target_room);
+               CtdlSubmitMsg(msg, recp, NULL, NULL, target_room);
        }
        CtdlFreeMessage(msg);
        free(recp);
@@ -1483,22 +1492,33 @@ void network_process_file(char *filename) {
 void network_do_spoolin(void) {
        DIR *dp;
        struct dirent *d;
-       char filename[SIZ];
+       char filename[256];
 
-       dp = opendir("./network/spoolin");
+       dp = opendir(
+#ifndef HAVE_SPOOL_DIR
+                                "."
+#else
+                                SPOOL_DIR
+#endif /* HAVE_SPOOL_DIR */
+                                "/network/spoolin");
        if (dp == NULL) return;
 
        while (d = readdir(dp), d != NULL) {
-               snprintf(filename, sizeof filename,
-                       "./network/spoolin/%s", d->d_name);
-               network_process_file(filename);
+               if ((strcmp(d->d_name, ".")) && (strcmp(d->d_name, ".."))) {
+                       snprintf(filename, sizeof filename,
+#ifndef HAVE_SPOOL_DIR
+                                        "."
+#else
+                                        SPOOL_DIR
+#endif /* HAVE_SPOOL_DIR */
+                                        "/network/spoolin/%s", d->d_name);
+                       network_process_file(filename);
+               }
        }
 
-
        closedir(dp);
 }
 
-
 /*
  * Delete any files in the outbound queue that were intended
  * to be sent to nodes which no longer exist.
@@ -1506,18 +1526,29 @@ void network_do_spoolin(void) {
 void network_purge_spoolout(void) {
        DIR *dp;
        struct dirent *d;
-       char filename[SIZ];
-       char nexthop[SIZ];
+       char filename[256];
+       char nexthop[256];
        int i;
 
-       dp = opendir("./network/spoolout");
+       dp = opendir(
+#ifndef HAVE_SPOOL_DIR
+                                "."
+#else
+                                SPOOL_DIR
+#endif /* HAVE_SPOOL_DIR */
+                                "/network/spoolout");
        if (dp == NULL) return;
 
        while (d = readdir(dp), d != NULL) {
                if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, ".."))
                        continue;
                snprintf(filename, sizeof filename,
-                       "./network/spoolout/%s", d->d_name);
+#ifndef HAVE_SPOOL_DIR
+                                "."
+#else
+                                SPOOL_DIR
+#endif /* HAVE_SPOOL_DIR */
+                                "/network/spoolout/%s", d->d_name);
 
                strcpy(nexthop, "");
                i = is_valid_node(nexthop, NULL, d->d_name);
@@ -1532,7 +1563,6 @@ void network_purge_spoolout(void) {
 }
 
 
-
 /*
  * receive network spool from the remote system
  */
@@ -1602,8 +1632,15 @@ void receive_spool(int sock, char *remote_nodename) {
                lprintf(CTDL_NOTICE, "Received %ld octets from <%s>",
                                download_len, remote_nodename);
        lprintf(CTDL_DEBUG, "%s", buf);
-       snprintf(buf, sizeof buf, "mv %s ./network/spoolin/%s.%ld",
-               tempfilename, remote_nodename, (long) getpid());
+       /* TODO: make move inline. forking is verry expensive. */
+       snprintf(buf, sizeof buf, "mv %s "
+#ifndef HAVE_SPOOL_DIR
+                        "."
+#else
+                        SPOOL_DIR
+#endif /* HAVE_SPOOL_DIR */
+                        "/network/spoolin/%s.%ld",
+                        tempfilename, remote_nodename, (long) getpid());
        system(buf);
 }
 
@@ -1628,7 +1665,13 @@ void transmit_spool(int sock, char *remote_nodename)
                return;
        }
 
-       snprintf(sfname, sizeof sfname, "./network/spoolout/%s", remote_nodename);
+       snprintf(sfname, sizeof sfname, 
+#ifndef HAVE_SPOOL_DIR
+                        "."
+#else
+                        SPOOL_DIR
+#endif /* HAVE_SPOOL_DIR */
+                        "/network/spoolout/%s", remote_nodename);
        fd = open(sfname, O_RDONLY);
        if (fd < 0) {
                if (errno != ENOENT) {
@@ -1669,10 +1712,11 @@ ABORTUPL:
        close(fd);
        if (sock_puts(sock, "UCLS 1") < 0) return;
        if (sock_gets(sock, buf) < 0) return;
-       lprintf(CTDL_NOTICE, "Sent %ld octets to <%s>",
+       lprintf(CTDL_NOTICE, "Sent %ld octets to <%s>\n",
                        bytes_written, remote_nodename);
        lprintf(CTDL_DEBUG, "<%s\n", buf);
        if (buf[0] == '2') {
+               lprintf(CTDL_DEBUG, "Removing <%s>\n", sfname);
                unlink(sfname);
        }
 }
@@ -1754,7 +1798,12 @@ void network_poll_other_citadel_nodes(int full_poll) {
                        poll = full_poll;
                        if (poll == 0) {
                                snprintf(spoolfile, sizeof spoolfile,
-                                       "./network/spoolout/%s", node);
+#ifndef HAVE_SPOOL_DIR
+                                                "."
+#else
+                                                SPOOL_DIR
+#endif
+                                                "/network/spoolout/%s", node);
                                if (access(spoolfile, R_OK) == 0) {
                                        poll = 1;
                                }
@@ -1770,6 +1819,24 @@ void network_poll_other_citadel_nodes(int full_poll) {
 
 
 
+/*
+ * It's ok if these directories already exist.  Just fail silently.
+ */
+void create_spool_dirs(void) {
+#ifndef HAVE_SPOOL_DIR
+       mkdir("./network", 0700);
+       mkdir("./network/systems", 0700);
+       mkdir("./network/spoolin", 0700);
+       mkdir("./network/spoolout", 0700);
+#else
+       mkdir(SPOOL_DIR "/network", 0700);
+       mkdir(SPOOL_DIR "/network/systems", 0700);
+       mkdir(SPOOL_DIR "/network/spoolin", 0700);
+       mkdir(SPOOL_DIR "/network/spoolout", 0700);
+#endif /* HAVE_SPOOL_DIR */
+}
+
+
 
 
 
@@ -1791,6 +1858,8 @@ void network_do_queue(void) {
                full_processing = 0;
        }
 
+       create_spool_dirs();
+
        /*
         * 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
@@ -1856,7 +1925,7 @@ void network_do_queue(void) {
 
 /*
  * cmd_netp() - authenticate to the server as another Citadel node polling
- *              for network traffic
+ *           for network traffic
  */
 void cmd_netp(char *cmdbuf)
 {
@@ -1883,7 +1952,7 @@ void cmd_netp(char *cmdbuf)
        v = is_valid_node(nexthop, secret, node);
 
        if (v != 0) {
-               lprintf(CTDL_WARNING, "Unknown node <%s>", node);
+               lprintf(CTDL_WARNING, "Unknown node <%s>\n", node);
                cprintf("%d authentication failed\n",
                        ERROR + PASSWORD_REQUIRED);
                return;
@@ -1908,13 +1977,12 @@ void cmd_netp(char *cmdbuf)
                CC->net_node);
 }
 
-
-
 /*
  * Module entry point
  */
 char *serv_network_init(void)
 {
+       create_spool_dirs();
        CtdlRegisterProtoHook(cmd_gnet, "GNET", "Get network config");
        CtdlRegisterProtoHook(cmd_snet, "SNET", "Set network config");
        CtdlRegisterProtoHook(cmd_netp, "NETP", "Identify as network poller");