]> code.citadel.org Git - citadel.git/blobdiff - citadel/serv_network.c
* Any "delete message" operation which is synchronous to a client is now
[citadel.git] / citadel / serv_network.c
index 8d90f311c19c4a0a944a15fac8d2b11cf6f9fc13..05c86f74507c6e824fd63e50fe70d511bc969e90 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;
 }
 
 
@@ -435,6 +442,7 @@ void network_spool_msg(long msgnum, void *userdata) {
        int delete_after_send = 0;      /* Set to 1 to delete after spooling */
        long list_msgnum = 0L;
        int ok_to_participate = 0;
+       char *end_of_headers = NULL;
 
        sc = (struct SpoolControl *)userdata;
 
@@ -498,13 +506,51 @@ void network_spool_msg(long msgnum, void *userdata) {
         * 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_MIME, HEADERS_NONE, 0, 0);
+
+                       end_of_headers = bmstrstr(CC->redirect_buffer, "\n\r\n", strncmp);
+                       if (end_of_headers == NULL) {
+                               end_of_headers = bmstrstr(CC->redirect_buffer, "\n\n", strncmp);
+                       }
+                       if (end_of_headers == NULL) {
+                               end_of_headers = CC->redirect_buffer;
+                       }
+                       striplt(end_of_headers);
+                       fprintf(sc->digestfp, "\n%s\n", end_of_headers);
+
+                       free(CC->redirect_buffer);
+                       CC->redirect_buffer = NULL;
+                       CC->redirect_len = 0;
+                       CC->redirect_alloc = 0;
+
+                       sc->num_msgs_spooled += 1;
+                       free(msg);
+               }
        }
 
        /*
@@ -678,14 +724,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 +755,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 +790,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]='_';
@@ -1124,6 +1180,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 +1192,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 +1259,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) {
@@ -1276,11 +1338,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 +1381,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 +1449,7 @@ void network_process_buffer(char *buffer, long size) {
                        msg = NULL;
                        free(recp);
                        return;
-                }
+               }
                strcpy(target_room, "");        /* no target room if mail */
        }
 
@@ -1404,7 +1475,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, target_room);
        }
        CtdlFreeMessage(msg);
        free(recp);
@@ -1483,22 +1554,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 +1588,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 +1625,6 @@ void network_purge_spoolout(void) {
 }
 
 
-
 /*
  * receive network spool from the remote system
  */
@@ -1602,8 +1694,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 +1727,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 +1774,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 +1860,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 +1881,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 +1920,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 +1987,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 +2014,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 +2039,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");