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