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