#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;
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) {
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);
}
* 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. */
}
valid = validate_recipients(nptr->name);
CtdlSubmitMsg(msg, valid, "");
- free(valid);
+ free_recipients(valid);
}
}
/* 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, "");
}
}
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;
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);
}
/* 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 */
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 */
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;
}
/* 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)) ) {
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");
}
* 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;
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 */
CtdlSubmitMsg(msg, recp, target_room);
}
CtdlFreeMessage(msg);
- free(recp);
+ free_recipients(recp);
}
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);
+ }
}
}
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");
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$";
}