* The size constant "256" which shows up everywhere as a buffer size has now
[citadel.git] / citadel / serv_network.c
1 /*
2  * $Id$ 
3  *
4  * This module will eventually replace netproc and some of its utilities.
5  * Copyright (C) 2000 by Art Cancro and others.
6  * This code is released under the terms of the GNU General Public License.
7  *
8  */
9
10 #include "sysdep.h"
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <stdio.h>
14 #include <fcntl.h>
15 #include <signal.h>
16 #include <pwd.h>
17 #include <errno.h>
18 #include <sys/types.h>
19 #include <sys/time.h>
20 #include <sys/wait.h>
21 #include <string.h>
22 #include <limits.h>
23 #include "citadel.h"
24 #include "server.h"
25 #include <time.h>
26 #include "sysdep_decls.h"
27 #include "citserver.h"
28 #include "support.h"
29 #include "config.h"
30 #include "dynloader.h"
31 #include "room_ops.h"
32 #include "user_ops.h"
33 #include "policy.h"
34 #include "database.h"
35 #include "msgbase.h"
36 #include "tools.h"
37 #include "internet_addressing.h"
38 #include "serv_network.h"
39
40
41 void cmd_gnet(char *argbuf) {
42         char filename[SIZ];
43         char buf[SIZ];
44         FILE *fp;
45
46         if (CtdlAccessCheck(ac_room_aide)) return;
47         assoc_file_name(filename, &CC->quickroom, "netconfigs");
48         cprintf("%d Network settings for room #%ld <%s>\n",
49                 LISTING_FOLLOWS,
50                 CC->quickroom.QRnumber, CC->quickroom.QRname);
51
52         fp = fopen(filename, "r");
53         if (fp != NULL) {
54                 while (fgets(buf, sizeof buf, fp) != NULL) {
55                         buf[strlen(buf)-1] = 0;
56                         cprintf("%s\n", buf);
57                 }
58                 fclose(fp);
59         }
60
61         cprintf("000\n");
62 }
63
64
65 void cmd_snet(char *argbuf) {
66         char tempfilename[SIZ];
67         char filename[SIZ];
68         char buf[SIZ];
69         FILE *fp;
70
71         if (CtdlAccessCheck(ac_room_aide)) return;
72         safestrncpy(tempfilename, tmpnam(NULL), sizeof tempfilename);
73         assoc_file_name(filename, &CC->quickroom, "netconfigs");
74
75         fp = fopen(tempfilename, "w");
76         if (fp == NULL) {
77                 cprintf("%d Cannot open %s: %s\n",
78                         ERROR+INTERNAL_ERROR,
79                         tempfilename,
80                         strerror(errno));
81         }
82
83         cprintf("%d %s\n", SEND_LISTING, tempfilename);
84         while (client_gets(buf), strcmp(buf, "000")) {
85                 fprintf(fp, "%s\n", buf);
86         }
87         fclose(fp);
88
89         /* Now copy the temp file to its permanent location
90          * (We use /bin/mv instead of link() because they may be on
91          * different filesystems)
92          */
93         unlink(filename);
94         snprintf(buf, sizeof buf, "/bin/mv %s %s", tempfilename, filename);
95         system(buf);
96 }
97
98
99
100 /*
101  * Spools out one message from the list.
102  */
103 void network_spool_msg(long msgnum, void *userdata) {
104         struct SpoolControl *sc;
105         struct namelist *nptr;
106         int err;
107         char *instr = NULL;
108         int instr_len = 0;
109         struct CtdlMessage *imsg;
110
111         sc = (struct SpoolControl *)userdata;
112
113         /* If no recipients, bail out now.
114          * (May need to tweak this when we add other types of targets)
115          */
116         if (sc->listrecps == NULL) return;
117         
118         /* First, copy it to the spoolout room */
119         err = CtdlSaveMsgPointerInRoom(SMTP_SPOOLOUT_ROOM, msgnum, 0);
120         if (err != 0) return;
121
122         lprintf(9, "Generating delivery instructions\n");
123         instr_len = 4096;
124         instr = mallok(instr_len);
125         sprintf(instr,
126                 "Content-type: %s\n\nmsgid|%ld\nsubmitted|%ld\n"
127                 "bounceto|postmaster@%s\n" ,
128                 SPOOLMIME, msgnum, time(NULL), config.c_fqdn );
129
130         imsg = mallok(sizeof(struct CtdlMessage));
131         memset(imsg, 0, sizeof(struct CtdlMessage));
132         imsg->cm_magic = CTDLMESSAGE_MAGIC;
133         imsg->cm_anon_type = MES_NORMAL;
134         imsg->cm_format_type = FMT_RFC822;
135         imsg->cm_fields['A'] = strdoop("Citadel");
136         imsg->cm_fields['M'] = instr;
137
138         /* Generate delivery instructions for each recipient */
139         for (nptr = sc->listrecps; nptr != NULL; nptr = nptr->next) {
140                 if (instr_len - strlen(instr) < SIZ) {
141                         instr_len = instr_len * 2;
142                         instr = reallok(instr, instr_len);
143                 }
144                 sprintf(&instr[strlen(instr)], "remote|%s|0||\n",
145                         nptr->name);
146         }
147
148         /* Save delivery instructions in spoolout room */
149         CtdlSaveMsg(imsg, "", SMTP_SPOOLOUT_ROOM, MES_LOCAL);
150         CtdlFreeMessage(imsg);
151
152         /* update lastsent */
153         sc->lastsent = msgnum;
154 }
155
156
157
158
159 /*
160  * Batch up and send all outbound traffic from the current room
161  */
162 void network_spoolout_current_room(void) {
163         char filename[SIZ];
164         char buf[SIZ];
165         char instr[SIZ];
166         FILE *fp;
167         struct SpoolControl sc;
168         /* struct namelist *digestrecps = NULL; */
169         struct namelist *nptr;
170
171         memset(&sc, 0, sizeof(struct SpoolControl));
172         assoc_file_name(filename, &CC->quickroom, "netconfigs");
173
174         fp = fopen(filename, "r");
175         if (fp == NULL) {
176                 lprintf(7, "Outbound batch processing skipped for <%s>\n",
177                         CC->quickroom.QRname);
178                 return;
179         }
180
181         lprintf(5, "Outbound batch processing started for <%s>\n",
182                 CC->quickroom.QRname);
183
184         while (fgets(buf, sizeof buf, fp) != NULL) {
185                 buf[strlen(buf)-1] = 0;
186
187                 extract(instr, buf, 0);
188                 if (!strcasecmp(instr, "lastsent")) {
189                         sc.lastsent = extract_long(buf, 1);
190                 }
191                 else if (!strcasecmp(instr, "listrecp")) {
192                         nptr = (struct namelist *)
193                                 mallok(sizeof(struct namelist));
194                         nptr->next = sc.listrecps;
195                         extract(nptr->name, buf, 1);
196                         sc.listrecps = nptr;
197                 }
198
199
200         }
201         fclose(fp);
202
203
204         /* Do something useful */
205         CtdlForEachMessage(MSGS_GT, sc.lastsent, (-63), NULL, NULL,
206                 network_spool_msg, &sc);
207
208
209         /* Now rewrite the config file */
210         fp = fopen(filename, "w");
211         if (fp == NULL) {
212                 lprintf(1, "ERROR: cannot open %s: %s\n",
213                         filename, strerror(errno));
214         }
215         else {
216                 fprintf(fp, "lastsent|%ld\n", sc.lastsent);
217
218                 /* Write out the listrecps while freeing from memory at the
219                  * same time.  Am I clever or what?  :)
220                  */
221                 while (sc.listrecps != NULL) {
222                         fprintf(fp, "listrecp|%s\n", sc.listrecps->name);
223                         nptr = sc.listrecps->next;
224                         phree(sc.listrecps);
225                         sc.listrecps = nptr;
226                 }
227
228                 fclose(fp);
229         }
230
231         lprintf(5, "Outbound batch processing finished for <%s>\n",
232                 CC->quickroom.QRname);
233 }
234
235
236
237 /* FIXME temporary server command for batch send */
238 void cmd_batc(char *argbuf) {
239         if (CtdlAccessCheck(ac_aide)) return;
240
241         network_spoolout_current_room();
242
243         cprintf("%d FIXME cmd_batc() ok\n", OK);
244 }
245
246
247
248 char *Dynamic_Module_Init(void)
249 {
250         CtdlRegisterProtoHook(cmd_gnet, "GNET", "Get network config");
251         CtdlRegisterProtoHook(cmd_snet, "SNET", "Get network config");
252
253         /* FIXME
254            temporary server command for batch send
255          */
256         CtdlRegisterProtoHook(cmd_batc, "BATC", "send out batch (temp)");
257
258         return "$Id$";
259 }