4 * This module will eventually replace netproc and some of its utilities. In
5 * the meantime, it serves as a mailing list manager.
7 * Copyright (C) 2000-2001 by Art Cancro and others.
8 * This code is released under the terms of the GNU General Public License.
20 #include <sys/types.h>
22 #if TIME_WITH_SYS_TIME
23 # include <sys/time.h>
27 # include <sys/time.h>
38 #include "sysdep_decls.h"
39 #include "citserver.h"
42 #include "dynloader.h"
49 #include "internet_addressing.h"
50 #include "serv_network.h"
53 void cmd_gnet(char *argbuf) {
58 if (CtdlAccessCheck(ac_room_aide)) return;
59 assoc_file_name(filename, &CC->quickroom, "netconfigs");
60 cprintf("%d Network settings for room #%ld <%s>\n",
62 CC->quickroom.QRnumber, CC->quickroom.QRname);
64 fp = fopen(filename, "r");
66 while (fgets(buf, sizeof buf, fp) != NULL) {
67 buf[strlen(buf)-1] = 0;
77 void cmd_snet(char *argbuf) {
78 char tempfilename[SIZ];
83 if (CtdlAccessCheck(ac_room_aide)) return;
84 safestrncpy(tempfilename, tmpnam(NULL), sizeof tempfilename);
85 assoc_file_name(filename, &CC->quickroom, "netconfigs");
87 fp = fopen(tempfilename, "w");
89 cprintf("%d Cannot open %s: %s\n",
95 cprintf("%d %s\n", SEND_LISTING, tempfilename);
96 while (client_gets(buf), strcmp(buf, "000")) {
97 fprintf(fp, "%s\n", buf);
101 /* Now copy the temp file to its permanent location
102 * (We use /bin/mv instead of link() because they may be on
103 * different filesystems)
106 snprintf(buf, sizeof buf, "/bin/mv %s %s", tempfilename, filename);
113 * Spools out one message from the list.
115 void network_spool_msg(long msgnum, void *userdata) {
116 struct SpoolControl *sc;
117 struct namelist *nptr;
120 size_t instr_len = SIZ;
121 struct CtdlMessage *imsg;
123 sc = (struct SpoolControl *)userdata;
125 /* If no recipients, bail out now.
126 * (May need to tweak this when we add other types of targets)
128 if (sc->listrecps == NULL) return;
130 /* First, copy it to the spoolout room */
131 err = CtdlSaveMsgPointerInRoom(SMTP_SPOOLOUT_ROOM, msgnum, 0);
132 if (err != 0) return;
135 * Figure out how big a buffer we need to allocate
137 for (nptr = sc->listrecps; nptr != NULL; nptr = nptr->next) {
138 instr_len = instr_len + strlen(nptr->name);
144 lprintf(9, "Generating delivery instructions\n");
145 instr = mallok(instr_len);
147 lprintf(1, "Cannot allocate %d bytes for instr...\n",
152 "Content-type: %s\n\nmsgid|%ld\nsubmitted|%ld\n"
153 "bounceto|postmaster@%s\n" ,
154 SPOOLMIME, msgnum, time(NULL), config.c_fqdn );
156 /* Generate delivery instructions for each recipient */
157 for (nptr = sc->listrecps; nptr != NULL; nptr = nptr->next) {
158 sprintf(&instr[strlen(instr)], "remote|%s|0||\n",
163 * Generate a message from the instructions
165 imsg = mallok(sizeof(struct CtdlMessage));
166 memset(imsg, 0, sizeof(struct CtdlMessage));
167 imsg->cm_magic = CTDLMESSAGE_MAGIC;
168 imsg->cm_anon_type = MES_NORMAL;
169 imsg->cm_format_type = FMT_RFC822;
170 imsg->cm_fields['A'] = strdoop("Citadel");
171 imsg->cm_fields['M'] = instr;
173 /* Save delivery instructions in spoolout room */
174 CtdlSaveMsg(imsg, "", SMTP_SPOOLOUT_ROOM, MES_LOCAL);
175 CtdlFreeMessage(imsg);
177 /* update lastsent */
178 sc->lastsent = msgnum;
185 * Batch up and send all outbound traffic from the current room
187 void network_spoolout_room(struct quickroom *qrbuf, void *data) {
192 struct SpoolControl sc;
193 /* struct namelist *digestrecps = NULL; */
194 struct namelist *nptr;
196 memcpy(&CC->quickroom, qrbuf, sizeof(struct quickroom));
198 memset(&sc, 0, sizeof(struct SpoolControl));
199 assoc_file_name(filename, &CC->quickroom, "netconfigs");
201 fp = fopen(filename, "r");
203 lprintf(7, "Outbound batch processing skipped for <%s>\n",
204 CC->quickroom.QRname);
208 lprintf(5, "Outbound batch processing started for <%s>\n",
209 CC->quickroom.QRname);
211 while (fgets(buf, sizeof buf, fp) != NULL) {
212 buf[strlen(buf)-1] = 0;
214 extract(instr, buf, 0);
215 if (!strcasecmp(instr, "lastsent")) {
216 sc.lastsent = extract_long(buf, 1);
218 else if (!strcasecmp(instr, "listrecp")) {
219 nptr = (struct namelist *)
220 mallok(sizeof(struct namelist));
221 nptr->next = sc.listrecps;
222 extract(nptr->name, buf, 1);
231 /* Do something useful */
232 CtdlForEachMessage(MSGS_GT, sc.lastsent, (-63), NULL, NULL,
233 network_spool_msg, &sc);
236 /* Now rewrite the config file */
237 fp = fopen(filename, "w");
239 lprintf(1, "ERROR: cannot open %s: %s\n",
240 filename, strerror(errno));
243 fprintf(fp, "lastsent|%ld\n", sc.lastsent);
245 /* Write out the listrecps while freeing from memory at the
246 * same time. Am I clever or what? :)
248 while (sc.listrecps != NULL) {
249 fprintf(fp, "listrecp|%s\n", sc.listrecps->name);
250 nptr = sc.listrecps->next;
258 lprintf(5, "Outbound batch processing finished for <%s>\n",
259 CC->quickroom.QRname);
266 * Run through the rooms doing various types of network stuff.
268 void network_do_queue(void) {
269 static int doing_queue = 0;
270 static time_t last_run = 0L;
272 #define NETWORK_QUEUE_FREQUENCY 3600 /* one hour ... FIXME put in config */
274 * Run no more frequently than once every n seconds
276 if ( (time(NULL) - last_run) < NETWORK_QUEUE_FREQUENCY ) return;
279 * This is a simple concurrency check to make sure only one queue run
280 * is done at a time. We could do this with a mutex, but since we
281 * don't really require extremely fine granularity here, we'll do it
282 * with a static variable instead.
284 if (doing_queue) return;
286 last_run = time(NULL);
289 * Go ahead and run the queue
291 lprintf(7, "network: processing outbound queue\n");
292 ForEachRoom(network_spoolout_room, NULL);
293 lprintf(7, "network: queue run completed\n");
298 char *Dynamic_Module_Init(void)
300 CtdlRegisterProtoHook(cmd_gnet, "GNET", "Get network config");
301 CtdlRegisterProtoHook(cmd_snet, "SNET", "Get network config");
302 CtdlRegisterSessionHook(network_do_queue, EVT_TIMER);