65c213090368faa3dff62902759eedefc3324733
[citadel.git] / citadel / netproc.c
1 /*
2  * Citadel/UX Intelligent Network Processor for IGnet/Open networks
3  * See copyright.txt for copyright information
4  * $Id$
5  */
6
7 /* How long it takes for an old node to drop off the network map */
8 #define EXPIRY_TIME     (2592000L)
9
10 /* How long we keep recently arrived messages in the use table */
11 #define USE_TIME        (604800L)
12
13 /* Where do we keep our lock file? */
14 #define LOCKFILE        "/var/lock/LCK.netproc"
15
16 /* Path to the 'uudecode' utility (needed for network file transfers) */
17 #define UUDECODE        "/usr/bin/uudecode"
18
19 /* Files used by the networker */
20 #define MAILSYSINFO     "./network/mail.sysinfo"
21
22 /* Uncomment the DEBUG def to see noisy traces */
23 #define DEBUG 1
24
25
26 #include "sysdep.h"
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <sys/types.h>
30 #include <sys/wait.h>
31 #include <string.h>
32 #include <fcntl.h>
33 #include <stdio.h>
34 #include <ctype.h>
35 #include <time.h>
36 #include <signal.h>
37 #include <errno.h>
38 #include <syslog.h>
39 #ifdef HAVE_GDBM_H
40 #include <gdbm.h>
41 #endif
42 #include "citadel.h"
43 #include "tools.h"
44
45 /* A list of users you wish to filter out of incoming traffic can be kept
46  * in ./network/filterlist -- messages from these users will be automatically
47  * moved to FILTERROOM.  Normally this will be the same as TWITROOM (the
48  * room problem user messages are moved to) but you can override this by
49  * specifying a different room name here.
50  */
51 #ifndef FILTERROOM
52 #define FILTERROOM TWITROOM
53 #endif
54
55 struct msglist {
56         struct msglist *next;
57         long m_num;
58         char m_rmname[ROOMNAMELEN];
59 };
60
61 struct rmlist {
62         struct rmlist *next;
63         char rm_name[ROOMNAMELEN];
64         long rm_lastsent;
65 };
66
67 struct filterlist {
68         struct filterlist *next;
69         char f_person[64];
70         char f_room[64];
71         char f_system[64];
72 };
73
74 struct syslist {
75         struct syslist *next;
76         char s_name[16];
77         char s_type[4];
78         char s_nexthop[128];
79         time_t s_lastcontact;
80         char s_humannode[64];
81         char s_phonenum[32];
82         char s_gdom[64];
83 };
84
85
86 void attach_to_server(int argc, char **argv);
87 void serv_read(char *buf, int bytes);
88 void serv_write(char *buf, int nbytes);
89 void get_config(void);
90
91 struct filterlist *filter = NULL;
92 struct syslist *slist = NULL;
93
94 struct config config;
95 extern char bbs_home_directory[];
96 extern int home_specified;
97
98 GDBM_FILE use_table;
99
100
101 #ifndef HAVE_STRERROR
102 /*
103  * replacement strerror() for systems that don't have it
104  */
105 char *strerror(int e)
106 {
107         static char buf[32];
108
109         sprintf(buf, "errno = %d", e);
110         return (buf);
111 }
112 #endif
113
114
115 void strip_trailing_whitespace(char *buf)
116 {
117         while (isspace(buf[strlen(buf) - 1]))
118                 buf[strlen(buf) - 1] = 0;
119 }
120
121
122 /*
123  * we also load the mail.sysinfo table into memory, make changes
124  * as we learn more about the network from incoming messages, and write
125  * the table back to disk when we're done.
126  */
127 int load_syslist(void)
128 {
129         FILE *fp;
130         struct syslist *stemp;
131         char insys = 0;
132         char buf[128];
133
134         fp = fopen(MAILSYSINFO, "r");
135         if (fp == NULL)
136                 return (1);
137
138         while (1) {
139                 if (fgets(buf, 128, fp) == NULL) {
140                         fclose(fp);
141                         return (0);
142                 }
143                 buf[strlen(buf) - 1] = 0;
144                 while (isspace(buf[0]))
145                         strcpy(buf, &buf[1]);
146                 if (buf[0] == '#')
147                         buf[0] = 0;
148                 if ((insys == 0) && (strlen(buf) != 0)) {
149                         insys = 1;
150                         stemp = (struct syslist *) malloc(sizeof(struct syslist));
151                         stemp->next = slist;
152                         slist = stemp;
153                         strcpy(slist->s_name, buf);
154                         strcpy(slist->s_type, "bin");
155                         strcpy(slist->s_nexthop, "Mail");
156                         slist->s_lastcontact = 0L;
157                         strcpy(slist->s_humannode, "");
158                         strcpy(slist->s_phonenum, "");
159                         strcpy(slist->s_gdom, "");
160                 } else if ((insys == 1) && (strlen(buf) == 0)) {
161                         insys = 0;
162                 } else if ((insys == 1) && (!strncasecmp(buf, "bin", 3))) {
163                         strcpy(slist->s_type, "bin");
164                         strcpy(slist->s_nexthop, &buf[4]);
165                 } else if ((insys == 1) && (!strncasecmp(buf, "use", 3))) {
166                         strcpy(slist->s_type, "use");
167                         strcpy(slist->s_nexthop, &buf[4]);
168                 } else if ((insys == 1) && (!strncasecmp(buf, "uum", 3))) {
169                         strcpy(slist->s_type, "uum");
170                         strcpy(slist->s_nexthop, &buf[4]);
171                 } else if ((insys == 1) && (!strncasecmp(buf, "lastcontact", 11))) {
172                         long foo;
173                         sscanf(&buf[12], "%ld", &foo);
174                         slist->s_lastcontact = foo;
175                 } else if ((insys == 1) && (!strncasecmp(buf, "humannode", 9))) {
176                         strcpy(slist->s_humannode, &buf[10]);
177                 } else if ((insys == 1) && (!strncasecmp(buf, "phonenum", 8))) {
178                         strcpy(slist->s_phonenum, &buf[9]);
179                 } else if ((insys == 1) && (!strncasecmp(buf, "gdom", 4))) {
180                         strcpy(slist->s_gdom, &buf[5]);
181                 }
182         }
183 }
184
185 /* now we have to set up two "special" nodes on the list: one
186  * for the local node, and one for an Internet gateway
187  */
188 void setup_special_nodes(void)
189 {
190         struct syslist *stemp, *slocal;
191
192         slocal = NULL;
193         for (stemp = slist; stemp != NULL; stemp = stemp->next) {
194                 if (!strcasecmp(stemp->s_name, config.c_nodename))
195                         slocal = stemp;
196         }
197         if (slocal == NULL) {
198                 slocal = (struct syslist *) malloc(sizeof(struct syslist));
199                 slocal->next = slist;
200                 slist = slocal;
201         }
202         strcpy(slocal->s_name, config.c_nodename);
203         strcpy(slocal->s_type, "bin");
204         strcpy(slocal->s_nexthop, "Mail");
205         time(&slocal->s_lastcontact);
206         strcpy(slocal->s_humannode, config.c_humannode);
207         strcpy(slocal->s_phonenum, config.c_phonenum);
208
209         slocal = NULL;
210         for (stemp = slist; stemp != NULL; stemp = stemp->next) {
211                 if (!strcasecmp(stemp->s_name, "internet"))
212                         slocal = stemp;
213         }
214         if (slocal == NULL) {
215                 slocal = (struct syslist *) malloc(sizeof(struct syslist));
216                 slocal->next = slist;
217                 slist = slocal;
218         }
219         strcpy(slocal->s_name, "internet");
220         strcpy(slocal->s_type, "uum");
221         strcpy(slocal->s_nexthop, "%s");
222         time(&slocal->s_lastcontact);
223         strcpy(slocal->s_humannode, "Internet Gateway");
224         strcpy(slocal->s_phonenum, "");
225         strcpy(slocal->s_gdom, "");
226
227 }
228
229 /*
230  * here's the routine to write the table back to disk.
231  */
232 void rewrite_syslist(void)
233 {
234         struct syslist *stemp;
235         FILE *newfp;
236         time_t now;
237
238         time(&now);
239         newfp = fopen(MAILSYSINFO, "w");
240         for (stemp = slist; stemp != NULL; stemp = stemp->next) {
241                 if (!strcasecmp(stemp->s_name, config.c_nodename)) {
242                         time(&stemp->s_lastcontact);
243                         strcpy(stemp->s_type, "bin");
244                         strcpy(stemp->s_humannode, config.c_humannode);
245                         strcpy(stemp->s_phonenum, config.c_phonenum);
246                 }
247                 /* remove systems we haven't heard from in a while */
248                 if ((stemp->s_lastcontact == 0L)
249                     || (now - stemp->s_lastcontact < EXPIRY_TIME)) {
250                         fprintf(newfp, "%s\n%s %s\n",
251                          stemp->s_name, stemp->s_type, stemp->s_nexthop);
252                         if (strlen(stemp->s_phonenum) > 0)
253                                 fprintf(newfp, "phonenum %s\n", stemp->s_phonenum);
254                         if (strlen(stemp->s_gdom) > 0)
255                                 fprintf(newfp, "gdom %s\n", stemp->s_gdom);
256                         if (strlen(stemp->s_humannode) > 0)
257                                 fprintf(newfp, "humannode %s\n", stemp->s_humannode);
258                         if (stemp->s_lastcontact > 0L)
259                                 fprintf(newfp, "lastcontact %ld %s",
260                                         (long) stemp->s_lastcontact,
261                                         asctime(localtime(&stemp->s_lastcontact)));
262                         fprintf(newfp, "\n");
263                 }
264         }
265         fclose(newfp);
266         /* now free the list */
267         while (slist != NULL) {
268                 stemp = slist;
269                 slist = slist->next;
270                 free(stemp);
271         }
272 }
273
274
275 /* call this function with the node name of a system and it returns a pointer
276  * to its syslist structure.
277  */
278 struct syslist *get_sys_ptr(char *sysname)
279 {
280         static char sysnambuf[16];
281         static struct syslist *sysptrbuf = NULL;
282         struct syslist *stemp;
283
284         if ((!strcmp(sysname, sysnambuf))
285             && (sysptrbuf != NULL))
286                 return (sysptrbuf);
287
288         strcpy(sysnambuf, sysname);
289         for (stemp = slist; stemp != NULL; stemp = stemp->next) {
290                 if (!strcmp(sysname, stemp->s_name)) {
291                         sysptrbuf = stemp;
292                         return (stemp);
293                 }
294         }
295         sysptrbuf = NULL;
296         return (NULL);
297 }
298
299
300 /*
301  * make sure only one copy of netproc runs at a time, using lock files
302  */
303 int set_lockfile(void)
304 {
305         FILE *lfp;
306         int onppid;
307
308         if ((lfp = fopen(LOCKFILE, "r")) != NULL) {
309                 fscanf(lfp, "%d", &onppid);
310                 fclose(lfp);
311                 if (!kill(onppid, 0) || errno == EPERM)
312                         return 1;
313         }
314         lfp = fopen(LOCKFILE, "w");
315         if (lfp == NULL) {
316                 syslog(LOG_NOTICE, "Cannot create %s: %s", LOCKFILE,
317                         strerror(errno));
318                 return(1);
319         }
320         fprintf(lfp, "%ld\n", (long) getpid());
321         fclose(lfp);
322         return (0);
323 }
324
325 void remove_lockfile(void)
326 {
327         unlink(LOCKFILE);
328 }
329
330 /*
331  * Why both cleanup() and nq_cleanup() ?  Notice the alarm() call in
332  * cleanup() .  If for some reason netproc hangs waiting for the server
333  * to clean up, the alarm clock goes off and the program exits anyway.
334  * The cleanup() routine makes a check to ensure it's not reentering, in
335  * case the ipc module looped it somehow.
336  */
337 void nq_cleanup(int e)
338 {
339         remove_lockfile();
340         closelog();
341         exit(e);
342 }
343
344 void cleanup(int e)
345 {
346         static int nested = 0;
347
348         alarm(30);
349         signal(SIGALRM, nq_cleanup);
350         if (nested++ < 1)
351                 serv_puts("QUIT");
352         nq_cleanup(e);
353 }
354
355 /*
356  * This is implemented as a function rather than as a macro because the
357  * client-side IPC modules expect logoff() to be defined.  They call logoff()
358  * when a problem connecting or staying connected to the server occurs.
359  */
360 void logoff(int e)
361 {
362         cleanup(e);
363 }
364
365 /*
366  * If there is a kill file in place, this function will process it.
367  */
368 void load_filterlist(void)
369 {
370         FILE *fp;
371         struct filterlist *fbuf;
372         char sbuf[256];
373         int a, p;
374         fp = fopen("./network/filterlist", "r");
375         if (fp == NULL)
376                 return;
377         while (fgets(sbuf, 256, fp) != NULL) {
378                 if (sbuf[0] != '#') {
379                         sbuf[strlen(sbuf) - 1] = 0;
380                         fbuf = (struct filterlist *)
381                             malloc((long) sizeof(struct filterlist));
382                         fbuf->next = filter;
383                         filter = fbuf;
384                         strcpy(fbuf->f_person, "*");
385                         strcpy(fbuf->f_room, "*");
386                         strcpy(fbuf->f_system, "*");
387                         p = (-1);
388                         for (a = strlen(sbuf); a >= 0; --a)
389                                 if (sbuf[a] == ',')
390                                         p = a;
391                         if (p >= 0) {
392                                 sbuf[p] = 0;
393                                 strcpy(fbuf->f_person, sbuf);
394                                 strcpy(sbuf, &sbuf[p + 1]);
395                         }
396                         for (a = strlen(sbuf); a >= 0; --a)
397                                 if (sbuf[a] == ',')
398                                         p = a;
399                         if (p >= 0) {
400                                 sbuf[p] = 0;
401                                 strcpy(fbuf->f_room, sbuf);
402                                 strcpy(sbuf, &sbuf[p + 1]);
403                         }
404                         strcpy(fbuf->f_system, sbuf);
405                 }
406         }
407         fclose(fp);
408 }
409
410 /* returns 1 if user/message/room combination is in the kill file */
411 int is_banned(char *k_person, char *k_room, char *k_system)
412 {
413         struct filterlist *fptr;
414
415         for (fptr = filter; fptr != NULL; fptr = fptr->next)
416                 if (
417                            ((!strcasecmp(fptr->f_person, k_person)) || (!strcmp(fptr->f_person, "*")))
418                            &&
419                            ((!strcasecmp(fptr->f_room, k_room)) || (!strcmp(fptr->f_room, "*")))
420                            &&
421                            ((!strcasecmp(fptr->f_system, k_system)) || (!strcmp(fptr->f_system, "*")))
422                     )
423                         return (1);
424
425         return (0);
426 }
427
428 /*
429  * Determine routing from sysinfo file
430  */
431 int get_sysinfo_type(char *name) {
432         struct syslist *stemp;
433
434 GETSN:  for (stemp = slist; stemp != NULL; stemp = stemp->next) {
435                 if (!strcasecmp(stemp->s_name, name)) {
436                         if (!strcasecmp(stemp->s_type, "use")) {
437                                 strcpy(name, stemp->s_nexthop);
438                                 goto GETSN;
439                         }
440                         if (!strcasecmp(stemp->s_type, "bin")) {
441                                 return (MES_BINARY);
442                         }
443                         if (!strcasecmp(stemp->s_type, "uum")) {
444                                 return (MES_INTERNET);
445                         }
446                 }
447         }
448         syslog(LOG_ERR, "cannot find system '%s' in mail.sysinfo", name);
449         return (-1);
450 }
451
452
453 void fpgetfield(FILE * fp, char *string)
454 {
455         int a, b;
456
457         strcpy(string, "");
458         a = 0;
459         do {
460                 b = getc(fp);
461                 if (b < 1) {
462                         string[a] = 0;
463                         return;
464                 }
465                 string[a] = b;
466                 ++a;
467         } while (b != 0);
468 }
469
470
471
472 /*
473  * Load all of the fields of a message, except the actual text, into a
474  * table in memory (so we know how to process the message).
475  */
476 void fpmsgfind(FILE *fp, struct minfo *buffer)
477 {
478         int b, e, mtype, aflag;
479         char bbb[1024];
480         char userid[1024];
481
482         strcpy(userid, "");
483         e = getc(fp);
484         if (e != 255) {
485                 syslog(LOG_ERR, "Magic number check failed for this message");
486                 goto END;
487         }
488
489         memset(buffer, 0, sizeof(struct minfo));
490         mtype = getc(fp);
491         aflag = getc(fp);
492
493 BONFGM: b = getc(fp);
494         if (b < 0)
495                 goto END;
496         if (b == 'M')
497                 goto END;
498         fpgetfield(fp, bbb);
499         while ((bbb[0] == ' ') && (strlen(bbb) > 1))
500                 strcpy(bbb, &bbb[1]);
501         if (b == 'A') {
502                 strcpy(buffer->A, bbb);
503                 if (strlen(userid) == 0) {
504                         strcpy(userid, bbb);
505                         for (e = 0; e < strlen(userid); ++e)
506                                 if (userid[e] == ' ')
507                                         userid[e] = '_';
508                 }
509         }
510         if (b == 'O')
511                 strcpy(buffer->O, bbb);
512         if (b == 'C')
513                 strcpy(buffer->C, bbb);
514         if (b == 'N')
515                 strcpy(buffer->N, bbb);
516         if (b == 'S')
517                 strcpy(buffer->S, bbb);
518         if (b == 'P') {
519                 /* extract the user id from the path */
520                 for (e = 0; e < strlen(bbb); ++e)
521                         if (bbb[e] == '!')
522                                 strcpy(userid, &bbb[e + 1]);
523
524                 /* now find the next hop */
525                 for (e = 0; e < strlen(bbb); ++e)
526                         if (bbb[e] == '!')
527                                 bbb[e] = 0;
528                 strcpy(buffer->nexthop, bbb);
529         }
530         if (b == 'R') {
531                 for (e = 0; e < strlen(bbb); ++e)
532                         if (bbb[e] == '_')
533                                 bbb[e] = ' ';
534                 strcpy(buffer->R, bbb);
535         }
536         if (b == 'D')
537                 strcpy(buffer->D, bbb);
538         if (b == 'T')
539                 buffer->T = atol(bbb);
540         if (b == 'I')
541                 buffer->I = atol(bbb);
542         if (b == 'H')
543                 strcpy(buffer->H, bbb);
544         if (b == 'B')
545                 strcpy(buffer->B, bbb);
546         if (b == 'G')
547                 strcpy(buffer->G, bbb);
548         if (b == 'E')
549                 strcpy(buffer->E, bbb);
550         if (b == 'Z')
551                 strcpy(buffer->Z, bbb);
552         goto BONFGM;
553
554 END:
555
556         /* NOTE: we used to use the following two lines of code to assign
557          * the timestamp as a message-ID if there was no message-ID already
558          * in the message.  We don't do this anymore because it screws up
559          * the loopzapper.
560          *
561         if (buffer->I == 0L)
562                 buffer->I = buffer->T;
563          */
564 }
565
566
567 /*
568  * msgfind() is the same as fpmsgfind() except it accepts a filename
569  * instead of a file handle.
570  */
571 void msgfind(char *msgfile, struct minfo *buffer) {
572         FILE *fp;
573
574         fp = fopen(msgfile, "rb");
575         if (fp == NULL) {
576                 syslog(LOG_ERR, "can't open %s: %s", msgfile, strerror(errno));
577                 return;
578         }
579
580         fpmsgfind(fp, buffer);
581         fclose(fp);
582 }
583
584
585
586
587
588 void ship_to(char *filenm, char *sysnm)
589 {                               /* send spool file filenm to system sysnm */
590         char sysflnm[100];
591         char commbuf1[100];
592         char commbuf2[100];
593         FILE *sysflfd;
594
595 #ifdef DEBUG
596         syslog(LOG_NOTICE, "shipping %s to %s", filenm, sysnm);
597 #endif
598         sprintf(sysflnm, "./network/systems/%s", sysnm);
599         sysflfd = fopen(sysflnm, "r");
600         if (sysflfd == NULL)
601                 syslog(LOG_ERR, "cannot open %s", sysflnm);
602         fgets(commbuf1, 99, sysflfd);
603         commbuf1[strlen(commbuf1) - 1] = 0;
604         fclose(sysflfd);
605         sprintf(commbuf2, commbuf1, filenm);
606         system(commbuf2);
607 }
608
609 /*
610  * proc_file_transfer()  -  handle a simple file transfer packet
611  *
612  */
613 void proc_file_transfer(char *tname)
614 {                               /* name of temp file containing the whole message */
615         char buf[256];
616         char dest_room[ROOMNAMELEN];
617         char subdir_name[256];
618         FILE *tfp, *uud;
619         int a;
620
621         syslog(LOG_NOTICE, "processing network file transfer...");
622
623         tfp = fopen(tname, "rb");
624         if (tfp == NULL)
625                 syslog(LOG_ERR, "cannot open %s", tname);
626         getc(tfp);
627         getc(tfp);
628         getc(tfp);
629         do {
630                 a = getc(tfp);
631                 if (a != 'M') {
632                         fpgetfield(tfp, buf);
633                         if (a == 'O') {
634                                 strcpy(dest_room, buf);
635                         }
636                 }
637         } while ((a != 'M') && (a >= 0));
638         if (a != 'M') {
639                 fclose(tfp);
640                 syslog(LOG_ERR, "no message text for file transfer");
641                 return;
642         }
643         strcpy(subdir_name, "---xxx---");
644         sprintf(buf, "GOTO %s", dest_room);
645         serv_puts(buf);
646         serv_gets(buf);
647         if (buf[0] == '2') {
648                 extract(subdir_name, &buf[4], 2);
649                 if (strlen(subdir_name) == 0)
650                         strcpy(subdir_name, "--xxx--");
651         }
652         /* Change to the room's directory; if that fails, change to the
653          * bitbucket directory.  Then run uudecode.
654          */
655         sprintf(buf, "(cd %s/files/%s || cd %s/files/%s ) ; exec %s",
656                 bbs_home_directory, subdir_name,
657                 bbs_home_directory, config.c_bucket_dir,
658                 UUDECODE);
659
660         uud = (FILE *) popen(buf, "w");
661         if (uud == NULL) {
662                 syslog(LOG_ERR, "cannot open uudecode pipe");
663                 fclose(tfp);
664                 return;
665         }
666         fgets(buf, 128, tfp);
667         buf[strlen(buf) - 1] = 0;
668         for (a = 0; a < strlen(buf); ++a)
669                 if (buf[a] == '/')
670                         buf[a] = '_';
671         fprintf(uud, "%s\n", buf);
672         printf("netproc: %s\n", buf);
673         while (a = getc(tfp), a > 0)
674                 putc(a, uud);
675         fclose(tfp);
676         pclose(uud);
677         return;
678 }
679
680
681 /* send a bounce message */
682 void bounce(struct minfo *bminfo)
683 {
684
685         FILE *bounce;
686         char bfilename[64];
687         static int bseq = 1;
688         time_t now;
689
690         sprintf(bfilename, "./network/spoolin/bounce.%ld.%d", (long) getpid(),
691                 bseq++);
692         bounce = fopen(bfilename, "wb");
693         time(&now);
694
695         fprintf(bounce, "%c%c%c", 0xFF, MES_NORMAL, 0);
696         fprintf(bounce, "Ppostmaster%c", 0);
697         fprintf(bounce, "T%ld%c", (long) now, 0);
698         fprintf(bounce, "APostmaster%c", 0);
699         fprintf(bounce, "OMail%c", 0);
700         fprintf(bounce, "N%s%c", config.c_nodename, 0);
701         fprintf(bounce, "H%s%c", config.c_humannode, 0);
702
703         if (strlen(bminfo->E) > 0) {
704                 fprintf(bounce, "R%s%c", bminfo->E, 0);
705         } else {
706                 fprintf(bounce, "R%s%c", bminfo->A, 0);
707         }
708
709         fprintf(bounce, "D%s%c", bminfo->N, 0);
710         fprintf(bounce, "M%s could not deliver your mail to:\n",
711                 config.c_humannode);
712         fprintf(bounce, " \n %s\n \n", bminfo->R);
713         fprintf(bounce, " because there is no such user on this system.\n");
714         fprintf(bounce, " (Unsent message does *not* follow.  ");
715         fprintf(bounce, "Help to conserve bandwidth.)\n%c", 0);
716         fclose(bounce);
717 }
718
719
720
721
722 /*
723  * Generate a Message-ID string for the use table
724  */
725 void strmsgid(char *buf, struct minfo *msginfo) {
726         int i;
727
728         sprintf(buf, "%ld@%s", msginfo->I, msginfo->N);
729         for (i=0; i<strlen(buf); ++i) {
730                 if (isspace(buf[i])) {
731                         strcpy(&buf[i], &buf[i+1]);
732                 }
733                 buf[i] = tolower(buf[i]);
734         }
735 }
736
737
738
739 /*
740  * Check the use table to see if a message has been here before.
741  * Returns 1 if the message is a duplicate; otherwise, it returns
742  * 0 and the message ID is added to the use table.
743  */
744 int already_received(GDBM_FILE ut, struct minfo *msginfo) {
745         char buf[256];
746         time_t now;
747         datum mkey, newrec;
748         int retval = 0;
749
750         /* We can't check for dups on a zero msgid, so just pass them through */
751         if ((msginfo->I)==0L) {
752                 return 0;
753         }
754
755         strmsgid(buf, msginfo);
756         now = time(NULL);
757
758         mkey.dptr = buf;
759         mkey.dsize = strlen(buf);
760
761         /* Set return value to 1 if message exists */
762         if (gdbm_exists(ut, mkey)) {
763                 retval = 1;
764         }
765
766         /* Write a record into the use table for this message.
767          * Replace existing records; this keeps the timestamp fresh.
768          */
769         newrec.dptr = (char *)&now;
770         newrec.dsize = sizeof(now);
771         gdbm_store(ut, mkey, newrec, GDBM_REPLACE);
772
773         return(retval);
774 }
775
776
777
778 /*
779  * Purge any old entries out of the use table.
780  * 
781  * Yes, you're reading this correctly: it keeps traversing the table until
782  * it manages to do a complete pass without deleting any records.  Read the
783  * gdbm man page to find out why.
784  *
785  */
786 void purge_use_table(GDBM_FILE ut) {
787         datum mkey, nextkey, therec;
788         int purged_anything = 0;
789         time_t rec_timestamp, now;
790
791         now = time(NULL);
792
793         do {
794                 purged_anything = 0;
795                 mkey = gdbm_firstkey(ut);
796                 while (mkey.dptr != NULL) {
797                         therec = gdbm_fetch(ut, mkey);
798                         if (therec.dptr != NULL) {
799                                 memcpy(&rec_timestamp, therec.dptr,
800                                         sizeof(time_t));
801                                 free(therec.dptr);
802
803                                 if ((now - rec_timestamp) > USE_TIME) {
804                                         gdbm_delete(ut, mkey);
805                                         purged_anything = 1;
806                                 }
807
808                         }
809                         nextkey = gdbm_nextkey(ut, mkey);
810                         free(mkey.dptr);
811                         mkey = nextkey;
812                 }
813         } while (purged_anything != 0);
814 }
815
816
817
818
819
820 /*
821  * process incoming files in ./network/spoolin
822  */
823 void inprocess(void)
824 {
825         FILE *fp, *message, *testfp, *ls, *duplist;
826         static struct minfo minfo;
827         struct recentmsg recentmsg;
828         char tname[128], aaa[1024], iname[256], sfilename[256], pfilename[256];
829         int a, b;
830         int FieldID;
831         struct syslist *stemp;
832         char *ptr = NULL;
833         char buf[256];
834         long msglen;
835         int bloklen;
836         int valid_msg;
837
838         /* temp file names */
839         sprintf(tname, tmpnam(NULL));
840         sprintf(iname, tmpnam(NULL));
841
842         load_filterlist();
843
844         /* Make sure we're in the right directory */
845         chdir(bbs_home_directory);
846
847         /* temporary file to contain a log of rejected dups */
848         duplist = tmpfile();
849
850         /* Let the shell do the dirty work. Get all data from spoolin */
851         do {
852                 sprintf(aaa, "cd %s/network/spoolin; ls", bbs_home_directory);
853                 ls = popen(aaa, "r");
854                 if (ls == NULL) {
855                         syslog(LOG_ERR, "could not open dir cmd: %s", strerror(errno));
856                 }
857                 if (ls != NULL) {
858                         do {
859 SKIP:                           ptr = fgets(sfilename, sizeof sfilename, ls);
860                                 if (ptr != NULL) {
861 #ifdef DEBUG
862                                         syslog(LOG_DEBUG,
863                                                 "Trying %s", sfilename);
864 #endif
865                                         sfilename[strlen(sfilename) - 1] = 0;
866                                         if (!strcmp(sfilename, ".")) goto SKIP;
867                                         if (!strcmp(sfilename, "..")) goto SKIP;
868                                         if (!strcmp(sfilename, "CVS")) goto SKIP;
869                                         goto PROCESS_IT;
870                                 }
871                         } while (ptr != NULL);
872 PROCESS_IT:             pclose(ls);
873                 }
874                 if (ptr != NULL) {
875                         sprintf(pfilename, "%s/network/spoolin/%s", bbs_home_directory, sfilename);
876                         syslog(LOG_NOTICE, "processing <%s>", pfilename);
877
878                         fp = fopen(pfilename, "rb");
879                         if (fp == NULL) {
880                                 syslog(LOG_ERR, "cannot open %s: %s", pfilename, strerror(errno));
881                                 fp = fopen("/dev/null", "rb");
882                         }
883 NXMSG:  /* Seek to the beginning of the next message */
884                         do {
885                                 a = getc(fp);
886                         } while ((a != 255) && (a >= 0));
887                         if (a < 0)
888                                 goto ENDSTR;
889
890                         /* This crates the temporary file. */
891                         valid_msg = 1;
892                         message = fopen(tname, "wb");
893                         if (message == NULL) {
894                                 syslog(LOG_ERR, "error creating %s: %s",
895                                         tname, strerror(errno));
896                                 goto ENDSTR;
897                         }
898                         putc(255, message);     /* 0xFF (start-of-message) */
899                         a = getc(fp);
900                         putc(a, message);       /* type */
901                         a = getc(fp);
902                         putc(a, message);       /* mode */
903                         do {
904                                 FieldID = getc(fp); /* Header field ID */
905                                 if (isalpha(FieldID)) {
906                                         putc(FieldID, message);
907                                         do {
908                                                 a = getc(fp);
909                                                 if (a < 127) putc(a, message);
910                                         } while (a > 0);
911                                         if (a != 0) putc(0, message);
912                                 }
913                                 else {  /* Invalid field ID; flush it */
914                                         do {
915                                                 a = getc(fp);
916                                         } while (a > 0);
917                                         valid_msg = 0;
918                                 }
919                         } while ((FieldID != 'M') && (a >= 0));
920                         /* M is always last */
921                         if (FieldID != 'M') valid_msg = 0;
922
923                         msglen = ftell(message);
924                         fclose(message);
925
926                         if (!valid_msg) {
927                                 unlink(tname);
928                                 goto NXMSG;
929                         }
930
931                         /* process the individual mesage */
932                         msgfind(tname, &minfo);
933                         strncpy(recentmsg.RMnodename, minfo.N, 9);
934                         recentmsg.RMnodename[9] = 0;
935                         recentmsg.RMnum = minfo.I;
936                         syslog(LOG_NOTICE, "#%ld fm <%s> in <%s> @ <%s>",
937                                minfo.I, minfo.A, minfo.O, minfo.N);
938                         if (strlen(minfo.R) > 0) {
939                                 syslog(LOG_NOTICE, "     to <%s>", minfo.R);
940                                 if (strlen(minfo.D) > 0) {
941                                         syslog(LOG_NOTICE, "     @ <%s>",
942                                                 minfo.D);
943                                 }
944                         }
945                         if (!strcasecmp(minfo.D, FQDN))
946                                 strcpy(minfo.D, NODENAME);
947
948 /* this routine updates our info on the system that sent the message */
949                         stemp = get_sys_ptr(minfo.N);
950                         if ((stemp == NULL) && (get_sys_ptr(minfo.nexthop) != NULL)) {
951                                 /* add non-neighbor system to map */
952                                 syslog(LOG_NOTICE, "Adding non-neighbor system <%s> to map",
953                                        slist->s_name);
954                                 stemp = (struct syslist *) malloc((long) sizeof(struct syslist));
955                                 stemp->next = slist;
956                                 slist = stemp;
957                                 strcpy(slist->s_name, minfo.N);
958                                 strcpy(slist->s_type, "use");
959                                 strcpy(slist->s_nexthop, minfo.nexthop);
960                                 time(&slist->s_lastcontact);
961                         } else if ((stemp == NULL) && (!strcasecmp(minfo.N, minfo.nexthop))) {
962                                 /* add neighbor system to map */
963                                 syslog(LOG_NOTICE, "Adding neighbor system <%s> to map",
964                                        slist->s_name);
965                                 sprintf(aaa, "%s/network/systems/%s", bbs_home_directory, minfo.N);
966                                 testfp = fopen(aaa, "r");
967                                 if (testfp != NULL) {
968                                         fclose(testfp);
969                                         stemp = (struct syslist *)
970                                             malloc((long) sizeof(struct syslist));
971                                         stemp->next = slist;
972                                         slist = stemp;
973                                         strcpy(slist->s_name, minfo.N);
974                                         strcpy(slist->s_type, "bin");
975                                         strcpy(slist->s_nexthop, "Mail");
976                                         time(&slist->s_lastcontact);
977                                 }
978                         }
979                         /* now update last contact and long node name if we can */
980                         if (stemp != NULL) {
981                                 time(&stemp->s_lastcontact);
982                                 if (strlen(minfo.H) > 0)
983                                         strcpy(stemp->s_humannode, minfo.H);
984                                 if (strlen(minfo.B) > 0)
985                                         strcpy(stemp->s_phonenum, minfo.B);
986                                 if (strlen(minfo.G) > 0)
987                                         strcpy(stemp->s_gdom, minfo.G);
988                         }
989
990                         /* Check the use table; reject message if it's been here before */
991                         if (already_received(use_table, &minfo)) {
992                                 syslog(LOG_NOTICE, "rejected duplicate message");
993                                 fprintf(duplist, "#%ld fm <%s> in <%s> @ <%s>\n",
994                                         minfo.I, minfo.A, minfo.O, minfo.N);
995                         }
996
997
998                         /* route the message if necessary */
999                         else if ((strcasecmp(minfo.D, NODENAME)) && (minfo.D[0] != 0)) {
1000                                 a = get_sysinfo_type(minfo.D);
1001                                 syslog(LOG_NOTICE, "routing message to system <%s>", minfo.D);
1002                                 fflush(stdout);
1003                                 if (a == MES_INTERNET) {
1004                                         if (fork() == 0) {
1005                                                 syslog(LOG_NOTICE, "netmailer %s", tname);
1006                                                 fflush(stdout);
1007                                                 execlp("./netmailer", "netmailer",
1008                                                        tname, NULL);
1009                                                 syslog(LOG_ERR, "error running netmailer: %s",
1010                                                        strerror(errno));
1011                                                 exit(errno);
1012                                         } else
1013                                                 while (wait(&b) != (-1));
1014                                 } else if (a == MES_BINARY) {
1015                                         ship_to(tname, minfo.D);
1016                                 } else {
1017                                         /* message falls into the bit bucket? */
1018                                 }
1019                         }
1020
1021                         /* check to see if it's a file transfer */
1022                         else if (!strncasecmp(minfo.S, "FILE", 4)) {
1023                                 proc_file_transfer(tname);
1024                         }
1025
1026                         /* otherwise process it as a normal message */
1027                         else {
1028                                 if (!strcasecmp(minfo.R, "postmaster")) {
1029                                         strcpy(minfo.R, "");
1030                                         strcpy(minfo.C, "Aide");
1031                                 }
1032                                 if (strlen(minfo.R) > 0) {
1033                                         sprintf(buf, "GOTO _MAIL_");
1034                                 }
1035                                 if (is_banned(minfo.A, minfo.C, minfo.N)) {
1036                                         sprintf(buf, "GOTO %s", FILTERROOM);
1037                                 } else {
1038                                         if (strlen(minfo.C) > 0) {
1039                                                 sprintf(buf, "GOTO %s", minfo.C);
1040                                         } else {
1041                                                 sprintf(buf, "GOTO %s", minfo.O);
1042                                         }
1043                                 }
1044                                 serv_puts(buf);
1045                                 serv_gets(buf);
1046                                 if (buf[0] != '2') {
1047                                         syslog(LOG_ERR, "%s", buf);
1048                                         sprintf(buf, "GOTO _BITBUCKET_");
1049                                         serv_puts(buf);
1050                                         serv_gets(buf);
1051                                 }
1052                                 /* Open the temporary file containing the message */
1053                                 message = fopen(tname, "rb");
1054                                 if (message == NULL) {
1055                                         syslog(LOG_ERR, "cannot open %s: %s",
1056                                                tname, strerror(errno));
1057                                         unlink(tname);
1058                                         goto NXMSG;
1059                                 }
1060                                 /* Transmit the message to the server */
1061                                 sprintf(buf, "ENT3 1|%s|%ld", minfo.R, msglen);
1062                                 serv_puts(buf);
1063                                 serv_gets(buf);
1064                                 if (!strncmp(buf, "570", 3)) {
1065                                         /* no such user, do a bounce */
1066                                         bounce(&minfo);
1067                                 }
1068                                 if (buf[0] == '7') {
1069                                         /* Always use the server's idea of the message length,
1070                                          * even though they should both be identical */
1071                                         msglen = atol(&buf[4]);
1072                                         while (msglen > 0L) {
1073                                                 bloklen = ((msglen >= 255L) ? 255 : ((int) msglen));
1074                                                 if (fread(buf, bloklen, 1, message) < 1) {
1075                                                         syslog(LOG_ERR,
1076                                                                "error trying to read %d bytes: %s",
1077                                                                bloklen, strerror(errno));
1078                                                 }
1079                                                 serv_write(buf, bloklen);
1080                                                 msglen = msglen - (long) bloklen;
1081                                         }
1082                                         serv_puts("NOOP");
1083                                         serv_gets(buf);
1084                                 } else {
1085                                         syslog(LOG_ERR, "%s", buf);
1086                                 }
1087
1088                                 fclose(message);
1089                                 
1090                         }
1091
1092                         unlink(tname);
1093                         goto NXMSG;
1094
1095 ENDSTR:                 fclose(fp);
1096                         unlink(pfilename);
1097                 }
1098         } while (ptr != NULL);
1099         unlink(iname);
1100
1101
1102         /*
1103          * If dups were rejected, post a message saying so
1104          */
1105         if (ftell(duplist)!=0L) {
1106                 fp = fopen("./network/spoolin/ctdl_rejects", "ab");
1107                 if (fp != NULL) {
1108                         fprintf(fp, "%cA%c", 255, 1);
1109                         fprintf(fp, "T%ld%c", time(NULL), 0);
1110                         fprintf(fp, "ACitadel%c", 0);
1111                         fprintf(fp, "OAide%cM", 0);
1112                         fprintf(fp, "The following duplicate messages"
1113                                 " were rejected:\n \n");
1114                         rewind(duplist);
1115                         while (fgets(buf, sizeof(buf), duplist) != NULL) {
1116                                 buf[strlen(buf)-1] = 0;
1117                                 fprintf(fp, " %s\n", buf);
1118                         }
1119                         fprintf(fp, "%c", 0);
1120                         pclose(fp);
1121                 }
1122         }
1123
1124         fclose(duplist);
1125
1126 }
1127
1128
1129 /* Checks to see whether its ok to send */
1130 /* Returns 1 for ok, send message       */
1131 /* Returns 0 if message already there   */
1132 int checkpath(char *path, char *sys)
1133 {
1134         int a;
1135         char sys2[512];
1136         strcpy(sys2, sys);
1137         strcat(sys2, "!");
1138
1139 #ifdef DEBUG
1140         syslog(LOG_NOTICE, "checkpath <%s> <%s> ... ", path, sys);
1141 #endif
1142         for (a = 0; a < strlen(path); ++a) {
1143                 if (!strncmp(&path[a], sys2, strlen(sys2)))
1144                         return (0);
1145         }
1146         return (1);
1147 }
1148
1149 /*
1150  * Implement split horizon algorithm (prevent infinite spooling loops
1151  * by refusing to send any node a message which already contains its
1152  * nodename in the path).
1153  */
1154 int ismsgok(FILE *mmfp, char *sysname)
1155 {
1156         int a;
1157         int ok = 0;             /* fail safe - no path, don't send it */
1158         char fbuf[256];
1159
1160         fseek(mmfp, 0L, 0);
1161         if (getc(mmfp) != 255)
1162                 return (0);
1163         getc(mmfp);
1164         getc(mmfp);
1165
1166         while (a = getc(mmfp), ((a != 'M') && (a != 0))) {
1167                 fpgetfield(mmfp, fbuf);
1168                 if (a == 'P') {
1169                         ok = checkpath(fbuf, sysname);
1170                 }
1171         }
1172 #ifdef DEBUG
1173         syslog(LOG_NOTICE, "%s", ((ok) ? "SEND" : "(no)"));
1174 #endif
1175         return (ok);
1176 }
1177
1178
1179
1180 /* spool list of messages to a file */
1181 /* returns # of msgs spooled */
1182 int spool_out(struct msglist *cmlist, FILE * destfp, char *sysname)
1183 {
1184         struct msglist *cmptr;
1185         FILE *mmfp;
1186         char fbuf[128];
1187         int a;
1188         int msgs_spooled = 0;
1189         long msg_len;
1190         int blok_len;
1191         static struct minfo minfo;
1192
1193         char buf[256];
1194         char curr_rm[256];
1195
1196         strcpy(curr_rm, "");
1197
1198         /* for each message in the list... */
1199         for (cmptr = cmlist; cmptr != NULL; cmptr = cmptr->next) {
1200
1201                 /* make sure we're in the correct room... */
1202                 if (strcasecmp(curr_rm, cmptr->m_rmname)) {
1203                         sprintf(buf, "GOTO %s", cmptr->m_rmname);
1204                         serv_puts(buf);
1205                         serv_gets(buf);
1206                         if (buf[0] == '2') {
1207                                 strcpy(curr_rm, cmptr->m_rmname);
1208                         } else {
1209                                 syslog(LOG_ERR, "%s", buf);
1210                         }
1211                 }
1212                 /* download the message from the server... */
1213                 mmfp = tmpfile();
1214                 sprintf(buf, "MSG3 %ld", cmptr->m_num);
1215                 serv_puts(buf);
1216                 serv_gets(buf);
1217                 if (buf[0] == '6') {    /* read the msg */
1218                         msg_len = atol(&buf[4]);
1219                         while (msg_len > 0L) {
1220                                 blok_len = ((msg_len >= 256L) ? 256 : (int) msg_len);
1221                                 serv_read(buf, blok_len);
1222                                 fwrite(buf, blok_len, 1, mmfp);
1223                                 msg_len = msg_len - (long) blok_len;
1224                         }
1225                 } else {        /* or print the err */
1226                         syslog(LOG_ERR, "%s", buf);
1227                 }
1228
1229                 rewind(mmfp);
1230
1231                 if (ismsgok(mmfp, sysname)) {
1232                         ++msgs_spooled;
1233                         fflush(stdout);
1234                         fseek(mmfp, 0L, 0);
1235                         fread(fbuf, 3, 1, mmfp);
1236                         fwrite(fbuf, 3, 1, destfp);
1237                         while (a = getc(mmfp), ((a != 0) && (a != 'M'))) {
1238                                 if (a != 'C')
1239                                         putc(a, destfp);
1240                                 fpgetfield(mmfp, fbuf);
1241                                 if (a == 'P')
1242                                         fprintf(destfp, "%s!", NODENAME);
1243                                 if (a != 'C')
1244                                         fwrite(fbuf, strlen(fbuf) + 1, 1, destfp);
1245                         }
1246                         if (a == 'M') {
1247                                 fprintf(destfp, "C%s%c",
1248                                         cmptr->m_rmname, 0);
1249                                 putc('M', destfp);
1250                                 do {
1251                                         a = getc(mmfp);
1252                                         putc(a, destfp);
1253                                 } while (a > 0);
1254                         }
1255
1256                 /* Get this message into the use table, so we can reject it
1257                  * if a misconfigured remote system sends it back to us.
1258                  */
1259                 fseek(mmfp, 0L, 0);
1260                 fpmsgfind(mmfp, &minfo);
1261                 already_received(use_table, &minfo);
1262
1263                 }
1264                 fclose(mmfp);
1265         }
1266
1267         return (msgs_spooled);
1268 }
1269
1270 void outprocess(char *sysname)
1271 {                               /* send new room messages to sysname */
1272         char sysflnm[64];
1273         char srmname[32];
1274         char shiptocmd[128];
1275         char lbuf[64];
1276         char tempflnm[64];
1277         char buf[256];
1278         struct msglist *cmlist = NULL;
1279         struct rmlist *crmlist = NULL;
1280         struct rmlist *rmptr, *rmptr2;
1281         struct msglist *cmptr, *cmptr2;
1282         FILE *sysflfp, *tempflfp;
1283         int outgoing_msgs;
1284         long thismsg;
1285
1286         sprintf(tempflnm, tmpnam(NULL));
1287         tempflfp = fopen(tempflnm, "w");
1288         if (tempflfp == NULL)
1289                 return;
1290
1291
1292 /*
1293  * Read system file for node in question and put together room list
1294  */
1295         sprintf(sysflnm, "%s/network/systems/%s", bbs_home_directory, sysname);
1296         sysflfp = fopen(sysflnm, "r");
1297         if (sysflfp == NULL)
1298                 return;
1299         fgets(shiptocmd, 128, sysflfp);
1300         shiptocmd[strlen(shiptocmd) - 1] = 0;
1301         while (!feof(sysflfp)) {
1302                 if (fgets(srmname, 32, sysflfp) == NULL)
1303                         break;
1304                 srmname[strlen(srmname) - 1] = 0;
1305                 fgets(lbuf, 32, sysflfp);
1306                 rmptr = (struct rmlist *) malloc(sizeof(struct rmlist));
1307                 rmptr->next = NULL;
1308                 strcpy(rmptr->rm_name, srmname);
1309                 strip_trailing_whitespace(rmptr->rm_name);
1310                 rmptr->rm_lastsent = atol(lbuf);
1311                 if (crmlist == NULL)
1312                         crmlist = rmptr;
1313                 else if (!strcasecmp(rmptr->rm_name, "control")) {
1314                         /* control has to be first in room list */
1315                         rmptr->next = crmlist;
1316                         crmlist = rmptr;
1317                 } else {
1318                         rmptr2 = crmlist;
1319                         while (rmptr2->next != NULL)
1320                                 rmptr2 = rmptr2->next;
1321                         rmptr2->next = rmptr;
1322                 }
1323         }
1324         fclose(sysflfp);
1325
1326 /*
1327  * Assemble list of messages to be spooled
1328  */
1329         for (rmptr = crmlist; rmptr != NULL; rmptr = rmptr->next) {
1330
1331                 sprintf(buf, "GOTO %s", rmptr->rm_name);
1332                 serv_puts(buf);
1333                 serv_gets(buf);
1334                 if (buf[0] != '2') {
1335                         syslog(LOG_ERR, "%s", buf);
1336                 } else {
1337                         sprintf(buf, "MSGS GT|%ld", rmptr->rm_lastsent);
1338                         serv_puts(buf);
1339                         serv_gets(buf);
1340                         if (buf[0] == '1')
1341                                 while (serv_gets(buf), strcmp(buf, "000")) {
1342                                         thismsg = atol(buf);
1343                                         if (thismsg > (rmptr->rm_lastsent)) {
1344                                                 rmptr->rm_lastsent = thismsg;
1345
1346                                                 cmptr = (struct msglist *)
1347                                                     malloc(sizeof(struct msglist));
1348                                                 cmptr->next = NULL;
1349                                                 cmptr->m_num = thismsg;
1350                                                 strcpy(cmptr->m_rmname, rmptr->rm_name);
1351
1352                                                 if (cmlist == NULL)
1353                                                         cmlist = cmptr;
1354                                                 else {
1355                                                         cmptr2 = cmlist;
1356                                                         while (cmptr2->next != NULL)
1357                                                                 cmptr2 = cmptr2->next;
1358                                                         cmptr2->next = cmptr;
1359                                                 }
1360                                         }
1361                         } else {        /* print error from "msgs all" */
1362                                 syslog(LOG_ERR, "%s", buf);
1363                         }
1364                 }
1365         }
1366
1367         outgoing_msgs = 0;
1368         cmptr2 = cmlist;        /* this loop counts the messages */
1369         while (cmptr2 != NULL) {
1370                 ++outgoing_msgs;
1371                 cmptr2 = cmptr2->next;
1372         }
1373         syslog(LOG_NOTICE, "%d messages to be spooled to %s",
1374                outgoing_msgs, sysname);
1375
1376 /*
1377  * Spool out the messages, but only if there are any.
1378  */
1379         if (outgoing_msgs != 0)
1380                 outgoing_msgs = spool_out(cmlist, tempflfp, sysname);
1381         syslog(LOG_NOTICE, "%d messages actually spooled",
1382                outgoing_msgs);
1383
1384 /*
1385  * Deallocate list of spooled messages.
1386  */
1387         while (cmlist != NULL) {
1388                 cmptr = cmlist->next;
1389                 free(cmlist);
1390                 cmlist = cmptr;
1391         }
1392
1393 /*
1394  * Rewrite system file and deallocate room list.
1395  */
1396         syslog(LOG_NOTICE, "Spooling...");
1397         sysflfp = fopen(sysflnm, "w");
1398         fprintf(sysflfp, "%s\n", shiptocmd);
1399         for (rmptr = crmlist; rmptr != NULL; rmptr = rmptr->next)
1400                 fprintf(sysflfp, "%s\n%ld\n", rmptr->rm_name, rmptr->rm_lastsent);
1401         fclose(sysflfp);
1402         while (crmlist != NULL) {
1403                 rmptr = crmlist->next;
1404                 free(crmlist);
1405                 crmlist = rmptr;
1406         }
1407
1408 /* 
1409  * Close temporary file, ship it out, and return
1410  */
1411         fclose(tempflfp);
1412         if (outgoing_msgs != 0)
1413                 ship_to(tempflnm, sysname);
1414         unlink(tempflnm);
1415 }
1416
1417
1418 /*
1419  * Connect netproc to the Citadel server running on this computer.
1420  */
1421 void np_attach_to_server(void)
1422 {
1423         char buf[256];
1424         char portname[8];
1425         char *args[] =
1426         {"netproc", "localhost", NULL, NULL};
1427
1428         syslog(LOG_NOTICE, "Attaching to server...");
1429         sprintf(portname, "%d", config.c_port_number);
1430         args[2] = portname;
1431         attach_to_server(3, args);
1432         serv_gets(buf);
1433         syslog(LOG_NOTICE, "%s", &buf[4]);
1434         sprintf(buf, "IPGM %d", config.c_ipgm_secret);
1435         serv_puts(buf);
1436         serv_gets(buf);
1437         syslog(LOG_NOTICE, "%s", &buf[4]);
1438         if (buf[0] != '2') {
1439                 cleanup(2);
1440         }
1441 }
1442
1443
1444
1445 /*
1446  * main
1447  */
1448 int main(int argc, char **argv)
1449 {
1450         char allst[32];
1451         FILE *allfp;
1452         int a;
1453         int import_only = 0;    /* if set to 1, don't export anything */
1454
1455         openlog("netproc", LOG_PID, LOG_USER);
1456         strcpy(bbs_home_directory, BBSDIR);
1457
1458         /*
1459          * Change directories if specified
1460          */
1461         for (a = 1; a < argc; ++a) {
1462                 if (!strncmp(argv[a], "-h", 2)) {
1463                         strcpy(bbs_home_directory, argv[a]);
1464                         strcpy(bbs_home_directory, &bbs_home_directory[2]);
1465                         home_specified = 1;
1466                 } else if (!strcmp(argv[a], "-i")) {
1467                         import_only = 1;
1468                 } else {
1469                         fprintf(stderr, "netproc: usage: ");
1470                         fprintf(stderr, "netproc [-hHomeDir] [-i]\n");
1471                         exit(1);
1472                 }
1473         }
1474
1475 #ifdef DEBUG
1476         syslog(LOG_DEBUG, "Calling get_config()");
1477 #endif
1478         get_config();
1479
1480 #ifdef DEBUG
1481         syslog(LOG_DEBUG, "Creating lock file");
1482 #endif
1483         if (set_lockfile() != 0) {
1484                 syslog(LOG_NOTICE, "lock file exists: already running");
1485                 cleanup(1);
1486         }
1487         signal(SIGINT, cleanup);
1488         signal(SIGQUIT, cleanup);
1489         signal(SIGHUP, cleanup);
1490         signal(SIGTERM, cleanup);
1491
1492         syslog(LOG_NOTICE, "started.  pid=%d", getpid());
1493         fflush(stdout);
1494         np_attach_to_server();
1495         fflush(stdout);
1496
1497         if (load_syslist() != 0)
1498                 syslog(LOG_ERR, "cannot load sysinfo");
1499         setup_special_nodes();
1500
1501         /* Open the use table */
1502         use_table = gdbm_open("./data/usetable.gdbm", 512,
1503                               GDBM_WRCREAT, 0600, 0);
1504         if (use_table == NULL) {
1505                 syslog(LOG_ERR, "could not open use table: %s",
1506                        strerror(errno));
1507         }
1508
1509         /* first collect incoming stuff */
1510         inprocess();
1511
1512         /* Now process outbound messages, but NOT if this is just a
1513          * quick import-only run (i.e. the -i command-line option
1514          * was specified)
1515          */
1516         if (import_only != 1) {
1517                 allfp = (FILE *) popen("cd ./network/systems; ls", "r");
1518                 if (allfp != NULL) {
1519                         while (fgets(allst, 32, allfp) != NULL) {
1520                                 allst[strlen(allst) - 1] = 0;
1521                                 outprocess(allst);
1522                         }
1523                         pclose(allfp);
1524                 }
1525                 /* import again in case anything new was generated */
1526                 inprocess();
1527         }
1528
1529         /* Update mail.sysinfo with new information we learned */
1530         rewrite_syslist();
1531
1532         /* Close the use table */
1533         purge_use_table(use_table);
1534         gdbm_close(use_table);
1535
1536         syslog(LOG_NOTICE, "processing ended.");
1537         cleanup(0);
1538         return 0;
1539 }