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