2 * This module handles shared rooms, inter-Citadel mail, and outbound
3 * mailing list processing.
5 * Copyright (c) 2000-2018 by the citadel.org team
7 * This program is open source software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License, version 3.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * ** NOTE ** A word on the S_NETCONFIGS semaphore:
16 * This is a fairly high-level type of critical section. It ensures that no
17 * two threads work on the netconfigs files at the same time. Since we do
18 * so many things inside these, here are the rules:
19 * 1. begin_critical_section(S_NETCONFIGS) *before* begin_ any others.
20 * 2. Do *not* perform any I/O with the client during these sections.
24 * Duration of time (in seconds) after which pending list subscribe/unsubscribe
25 * requests that have not been confirmed will be deleted.
27 #define EXP 259200 /* three days */
39 #include <sys/types.h>
41 #if TIME_WITH_SYS_TIME
42 # include <sys/time.h>
46 # include <sys/time.h>
54 # if HAVE_SYS_SYSCALL_H
55 # include <sys/syscall.h>
62 #include <libcitadel.h>
65 #include "citserver.h"
71 #include "internet_addressing.h"
72 #include "serv_network.h"
73 #include "clientsocket.h"
74 #include "citadel_dirs.h"
77 #include "ctdl_module.h"
81 struct CitContext networker_spool_CC;
83 /* comes from lookup3.c from libcitadel... */
84 extern uint32_t hashlittle( const void *key, size_t length, uint32_t initval);
86 typedef struct __roomlists {
92 * When we do network processing, it's accomplished in two passes; one to
93 * gather a list of rooms and one to actually do them. It's ok that rplist
94 * is global; we have a mutex that keeps it safe.
96 struct RoomProcList *rplist = NULL;
98 RoomProcList *CreateRoomProcListEntry(struct ctdlroom *qrbuf, OneRoomNetCfg *OneRNCFG)
101 struct RoomProcList *ptr;
103 ptr = (struct RoomProcList *) malloc(sizeof (struct RoomProcList));
108 ptr->namelen = strlen(qrbuf->QRname);
109 if (ptr->namelen > ROOMNAMELEN) {
110 ptr->namelen = ROOMNAMELEN - 1;
113 memcpy (ptr->name, qrbuf->QRname, ptr->namelen);
114 ptr->name[ptr->namelen] = '\0';
115 ptr->QRNum = qrbuf->QRnumber;
117 for (i = 0; i < ptr->namelen; i++)
119 ptr->lcname[i] = tolower(ptr->name[i]);
122 ptr->lcname[ptr->namelen] = '\0';
123 ptr->key = hashlittle(ptr->lcname, ptr->namelen, 9872345);
128 * Batch up and send all outbound traffic from the current room
130 void network_queue_interesting_rooms(struct ctdlroom *qrbuf, void *data, OneRoomNetCfg *OneRNCfg)
132 struct RoomProcList *ptr;
133 roomlists *RP = (roomlists*) data;
135 if (!HaveSpoolConfig(OneRNCfg)) {
139 ptr = CreateRoomProcListEntry(qrbuf, OneRNCfg);
143 ptr->next = RP->rplist;
149 * Batch up and send all outbound traffic from the current room
151 int network_room_handler(struct ctdlroom *qrbuf)
153 struct RoomProcList *ptr;
154 OneRoomNetCfg *RNCfg;
156 if (qrbuf->QRdefaultview == VIEW_QUEUE) {
160 RNCfg = CtdlGetNetCfgForRoom(qrbuf->QRnumber);
165 if (!HaveSpoolConfig(RNCfg)) {
166 FreeRoomNetworkStruct(&RNCfg);
170 ptr = CreateRoomProcListEntry(qrbuf, RNCfg);
172 FreeRoomNetworkStruct(&RNCfg);
176 begin_critical_section(S_RPLIST);
179 end_critical_section(S_RPLIST);
180 FreeRoomNetworkStruct(&RNCfg);
184 void destroy_network_queue_room(RoomProcList *rplist)
186 struct RoomProcList *cur, *p;
197 void destroy_network_queue_room_locked (void)
199 begin_critical_section(S_RPLIST);
200 destroy_network_queue_room(rplist);
201 end_critical_section(S_RPLIST);
208 * Run through the rooms doing various types of network stuff.
210 void network_do_queue(void)
212 static time_t last_run = 0L;
213 int full_processing = 1;
214 HashList *working_ignetcfg;
215 HashList *the_netmap = NULL;
216 int netmap_changed = 0;
218 SpoolControl *sc = NULL;
222 * Run the full set of processing tasks no more frequently
223 * than once every n seconds
225 if ( (time(NULL) - last_run) < CtdlGetConfigLong("c_net_freq") )
228 syslog(LOG_DEBUG, "network: full processing in %ld seconds.", CtdlGetConfigLong("c_net_freq") - (time(NULL)- last_run));
231 become_session(&networker_spool_CC);
232 begin_critical_section(S_RPLIST);
235 end_critical_section(S_RPLIST);
237 // TODO hm, check whether we have a config at all here?
238 /* Load the IGnet Configuration into memory */
239 working_ignetcfg = CtdlLoadIgNetCfg();
242 * Load the network map and filter list into memory.
244 if (!server_shutting_down) {
245 the_netmap = CtdlReadNetworkMap();
249 * Go ahead and run the queue
251 if (full_processing && !server_shutting_down) {
252 syslog(LOG_DEBUG, "network: loading outbound queue");
253 CtdlForEachNetCfgRoom(network_queue_interesting_rooms, &RL);
256 if ((RL.rplist != NULL) && (!server_shutting_down)) {
257 RoomProcList *ptr, *cmp;
259 syslog(LOG_DEBUG, "network: running outbound queue");
260 while (ptr != NULL && !server_shutting_down) {
263 /* filter duplicates from the list... */
264 while (cmp != NULL) {
265 if ((cmp->namelen > 0) &&
266 (cmp->key == ptr->key) &&
267 (cmp->namelen == ptr->namelen) &&
268 (strcmp(cmp->lcname, ptr->lcname) == 0))
275 if (ptr->namelen > 0) {
276 InspectQueuedRoom(&sc, ptr, working_ignetcfg, the_netmap);
286 network_spoolout_room(pSC);
294 free_spoolcontrol_struct(&pSC);
298 /* Save the network map back to disk */
299 if (netmap_changed) {
300 StrBuf *MapStr = CtdlSerializeNetworkMap(the_netmap);
301 char *pMapStr = SmashStrBuf(&MapStr);
302 CtdlPutSysConfig(IGNETMAP, pMapStr);
308 DeleteHash(&the_netmap);
310 DeleteHash(&working_ignetcfg);
312 syslog(LOG_DEBUG, "network: queue run completed");
314 if (full_processing) {
315 last_run = time(NULL);
317 destroy_network_queue_room(RL.rplist);
326 CTDL_MODULE_INIT(network)
330 CtdlFillSystemContext(&networker_spool_CC, "CitNetSpool");
331 CtdlRegisterRoomHook(network_room_handler);
332 CtdlRegisterCleanupHook(destroy_network_queue_room_locked);
333 CtdlRegisterSessionHook(network_do_queue, EVT_TIMER, PRIO_QUEUE + 10);