Tue Aug 18 00:42:33 EDT 1998 Nathan Bryant <bryant@cs.usm.maine.edu>
[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(int argc, char **argv);
101 void serv_read(char *buf, int bytes);
102 void serv_write(char *buf, int nbytes);
103 void get_config(void);
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(int e)
120 {
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(char *buf)
130 {
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(void) {
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(void) {
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(void) {
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(void) {
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(char *sysname)
315 {
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(void) {
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(void) {
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(int e)
381 {
382         remove_lockfile();
383         exit(e);
384         }
385
386 void cleanup(int e)
387 {
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(int e)
402 {
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(void) {
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(char *k_person, char *k_room, char *k_system)
447 {
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(char *name)        /* determine routing from sysinfo file */
462              {
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(FILE *fp, char *string)
484 {
485         int a,b;
486
487         strcpy(string,"");
488         a=0;
489         do {
490                 b=getc(fp);
491                 if (b<1) {
492                         string[a]=0;
493                         return;
494                         }
495                 string[a]=b;
496                 ++a;
497                 } while (b!=0);
498         }
499
500
501
502 /*
503  * Load all of the fields of a message, except the actual text, into a
504  * table in memory (so we know how to process the message).
505  */
506 void msgfind(char *msgfile, struct minfo *buffer)
507 {
508         int b,e,mtype,aflag;
509         char bbb[1024];
510         char userid[1024];
511         FILE *fp;
512                 
513         strcpy(userid,"");
514         fp=fopen(msgfile,"rb");
515         if (fp==NULL) {
516                 fprintf(stderr,"Can't open message file: %s\n",strerror(errno));
517                 return;
518                 }
519         e=getc(fp);
520         if (e!=255) {
521                 fprintf(stdout,"Incorrect message format\n");
522                 goto END;
523                 }
524         mtype=getc(fp); aflag=getc(fp);
525         buffer->I=0L;
526         buffer->R[0]=0;
527         buffer->E[0]=0;
528         buffer->H[0]=0;
529         buffer->S[0]=0;
530         buffer->B[0]=0;
531         buffer->G[0]=0;
532
533 BONFGM: b=getc(fp); if (b<0) goto END;
534         if (b=='M') goto END;
535         fpgetfield(fp,bbb);
536         while ((bbb[0]==' ')&&(strlen(bbb)>1)) strcpy(bbb,&bbb[1]);
537         if (b=='A') {
538                 strcpy(buffer->A,bbb);
539                 if (strlen(userid)==0) {
540                         strcpy(userid,bbb);
541                         for (e=0; e<strlen(userid); ++e)
542                                 if (userid[e]==' ') userid[e]='_';
543                         }
544                 }
545         if (b=='O') strcpy(buffer->O,bbb);
546         if (b=='C') strcpy(buffer->C,bbb);
547         if (b=='N') strcpy(buffer->N,bbb);
548         if (b=='S') strcpy(buffer->S,bbb);
549         if (b=='P') {
550                 /* extract the user id from the path */
551                 for (e=0; e<strlen(bbb); ++e)
552                         if (bbb[e]=='!') strcpy(userid,&bbb[e+1]);
553
554                 /* now find the next hop */
555                 for (e=0; e<strlen(bbb); ++e) if (bbb[e]=='!') bbb[e]=0;
556                 strcpy(buffer->nexthop,bbb);
557                 }
558         if (b=='R') {
559                 for (e=0; e<strlen(bbb); ++e) if (bbb[e]=='_') bbb[e]=' ';
560                 strcpy(buffer->R,bbb);
561                 }
562         if (b=='D') strcpy(buffer->D,bbb);
563         if (b=='T') buffer->T=atol(bbb);
564         if (b=='I') buffer->I=atol(bbb);
565         if (b=='H') strcpy(buffer->H,bbb);
566         if (b=='B') strcpy(buffer->B,bbb);
567         if (b=='G') strcpy(buffer->G,bbb);
568         if (b=='E') strcpy(buffer->E,bbb);
569         goto BONFGM;
570
571 END:    if (buffer->I==0L) buffer->I=buffer->T;
572         fclose(fp);
573         }
574
575 void ship_to(char *filenm, char *sysnm) /* send spool file filenm to system sysnm */
576              
577              {
578         char sysflnm[100];
579         char commbuf1[100];
580         char commbuf2[100];
581         FILE *sysflfd;
582
583 #ifdef DEBUG
584         fprintf(stdout,"netproc: shipping %s to %s\n",filenm,sysnm);
585 #endif
586         sprintf(sysflnm,"./network/systems/%s",sysnm);
587         sysflfd=fopen(sysflnm,"r");
588         if (sysflfd==NULL) fprintf(stdout,"netproc: cannot open %s\n",sysflnm);
589         fgets(commbuf1,99,sysflfd);
590         commbuf1[strlen(commbuf1)-1] = 0;
591         fclose(sysflfd);
592         sprintf(commbuf2,commbuf1,filenm);
593         system(commbuf2);
594         }
595
596 /*
597  * proc_file_transfer()  -  handle a simple file transfer packet
598  */
599 void proc_file_transfer(char *tname)
600 {       /* name of temp file containing the whole message */
601         char buf[128];
602         char dest_dir[32];
603         FILE *tfp,*uud;
604         int a,b;
605
606         printf("netproc: processing network file transfer...\n");
607         strcpy(dest_dir,config.c_bucket_dir);
608
609         tfp=fopen(tname,"rb");
610         if (tfp==NULL) printf("netproc: cannot open %s\n",tname);
611         getc(tfp); getc(tfp); getc(tfp);
612         do {
613                 a=getc(tfp);
614                 if (a!='M') {
615                         fpgetfield(tfp,buf);
616                         if (a=='O') for (b=0; b<MAXROOMS; ++b) {
617                                 if (!strcasecmp(buf,roomnames[b]))
618                                         strcpy(dest_dir,roomdirs[b]);
619                                 }
620                         }
621                 } while ((a!='M')&&(a>=0));
622         if (a!='M') {
623                 fclose(tfp);
624                 printf("netproc: no message text for file transfer\n");
625                 return;
626                 }
627
628         sprintf(buf,"cd %s/files/%s; exec %s",bbs_home_directory,dest_dir,UUDECODE);
629         uud=(FILE *)popen(buf,"w");
630         if (uud==NULL) {
631                 printf("netproc: cannot open uudecode pipe\n");
632                 fclose(tfp);
633                 return;
634                 }
635
636         fgets(buf,128,tfp);
637         buf[strlen(buf)-1] = 0;
638         for (a=0; a<strlen(buf); ++a) if (buf[a]=='/') buf[a]='_';
639         fprintf(uud,"%s\n",buf);
640         printf("netproc: %s\n",buf);
641         while(a=getc(tfp), a>0) putc(a,uud);
642         fclose(tfp);
643         pclose(uud);
644         return;
645         }
646
647
648 /* send a bounce message */
649 void bounce(struct minfo *bminfo)
650 {
651
652         FILE *bounce;
653         char bfilename[64];
654         static int bseq = 1;
655         long now;
656
657         sprintf(bfilename,"./network/spoolin/bounce.%d.%d",getpid(),bseq++);
658         bounce = fopen(bfilename,"wb");
659         time(&now);
660                 
661         fprintf(bounce,"%c%c%c",0xFF,MES_NORMAL,0);
662         fprintf(bounce,"Ppostmaster%c",0);
663         fprintf(bounce,"T%ld%c",now,0);
664         fprintf(bounce,"APostmaster%c",0);
665         fprintf(bounce,"OMail%c",0);
666         fprintf(bounce,"N%s%c",config.c_nodename,0);
667         fprintf(bounce,"H%s%c",config.c_humannode,0);
668
669         if (strlen(bminfo->E) > 0) {
670                 fprintf(bounce,"R%s%c",bminfo->E,0);
671                 }
672         else {
673                 fprintf(bounce,"R%s%c",bminfo->A,0);
674                 }
675
676         fprintf(bounce,"D%s%c",bminfo->N,0);
677         fprintf(bounce,"M%s could not deliver your mail to:\n",
678                 config.c_humannode);
679         fprintf(bounce," \n %s\n \n",bminfo->R);
680         fprintf(bounce," because there is no such user on this system.\n");
681         fprintf(bounce," (Unsent message does *not* follow.  ");
682         fprintf(bounce,"Help to conserve bandwidth.)\n%c",0);
683         fclose(bounce);
684         }
685
686
687
688 /*
689  * process incoming files in ./network/spoolin
690  */
691 void inprocess(void) {
692         FILE *fp,*message,*testfp,*ls;
693         static struct minfo minfo;
694         struct recentmsg recentmsg;
695         char tname[128],aaa[1024],iname[256],sfilename[256],pfilename[256];
696         int a,b;
697         int FieldID;
698         struct syslist *stemp;
699         char *ptr = NULL;
700         char buf[256];
701         long msglen;
702         int bloklen;
703
704
705         sprintf(tname,"/tmp/net.t%d",getpid()); /* temp file name */
706         sprintf(iname,"/tmp/net.i%d",getpid()); /* temp file name */
707
708         load_filterlist();
709
710         chdir(bbs_home_directory);
711         
712         /* Let the shell do the dirty work. Get all data from spoolin */
713     do {
714         sprintf(aaa,"cd %s/network/spoolin; ls",bbs_home_directory);
715         ls=popen(aaa,"r");
716         if (ls==NULL) {
717                 fprintf(stderr,"netproc: could not open dir cmd: %s\n",
718                         strerror(errno));
719                 }
720         if (ls!=NULL) {
721                 do {
722                         ptr=fgets(sfilename,256,ls);
723                         if (ptr!=NULL) sfilename[strlen(sfilename)-1] = 0;
724                         } while( (ptr!=NULL)&&((!strcmp(sfilename,"."))
725                                  ||(!strcmp(sfilename,".."))));
726                 if (ptr!=NULL) printf("netproc: processing %s\n",sfilename);
727                 pclose(ls);
728                 }
729
730       if (ptr!=NULL) {
731         sprintf(pfilename,"%s/network/spoolin/%s",bbs_home_directory,sfilename);
732         fprintf(stderr,"netproc: processing <%s>\n", pfilename);
733         fflush(stderr);
734         
735         fp = fopen(pfilename, "rb");
736         if (fp == NULL) {
737             fprintf(stderr, "netproc: cannot open <%s>: %s\n",
738                         pfilename, strerror(errno));
739             fflush(stderr);
740             fp = fopen("/dev/null" ,"rb");
741             }
742                 
743 NXMSG:  /* Seek to the beginning of the next message */
744         do {
745                 a=getc(fp);
746                 } while((a!=255)&&(a>=0));
747         if (a<0) goto ENDSTR;
748
749         message = fopen(tname,"wb");    /* This crates the temporary file. */
750         if (message == NULL) {
751                 fprintf(stderr, "Error creating %s: %s\n",
752                         tname, strerror(errno));
753                 goto ENDSTR;
754                 }
755         putc(255,message);              /* 0xFF (start-of-message) */
756         a = getc(fp); putc(a, message); /* type */
757         a = getc(fp); putc(a, message); /* mode */
758         do {
759                 FieldID = getc(fp);     /* Header field ID */
760                 putc(FieldID, message);
761                 do {
762                         a = getc(fp);
763                         putc(a, message);
764                         } while (a > 0);
765                 } while ((FieldID != 'M') && (a >= 0)); /* M is always last */
766
767         msglen = ftell(message);
768         fclose(message);
769
770         /* process the individual mesage */
771         minfo.D[0]=0;
772         minfo.C[0]=0;
773         minfo.B[0]=0;
774         minfo.G[0]=0;
775         minfo.R[0]=0;
776         msgfind(tname,&minfo);
777         strncpy(recentmsg.RMnodename,minfo.N,9);
778         recentmsg.RMnodename[9]=0;
779         recentmsg.RMnum=minfo.I;
780         printf("netproc: #%ld fm <%s> in <%s> @ <%s>\n",
781                 minfo.I,minfo.A,minfo.O,minfo.N);
782         if (strlen(minfo.R)>0) {
783                 printf("         to <%s>",minfo.R);
784                 if (strlen(minfo.D)>0) {
785                         printf(" @ <%s>",minfo.D);
786                         }
787                 printf("\n");
788                 }
789         fflush(stdout);
790         if (!strcasecmp(minfo.D,FQDN)) strcpy(minfo.D,NODENAME);
791
792         /* this routine updates our info on the system that sent the message */
793         stemp = get_sys_ptr(minfo.N);
794         if ((stemp == NULL) && (get_sys_ptr(minfo.nexthop) != NULL)) {
795                 /* add non-neighbor system to map */
796                 printf("Adding non-neighbor system <%s> to map\n", slist->s_name);
797                 stemp = (struct syslist *)malloc((long)sizeof(struct syslist));
798                 stemp->next = slist;
799                 slist = stemp;
800                 strcpy(slist->s_name,minfo.N);
801                 strcpy(slist->s_type,"use");
802                 strcpy(slist->s_nexthop,minfo.nexthop);
803                 time(&slist->s_lastcontact);
804                 }
805         else if ((stemp == NULL) && (!strcasecmp(minfo.N,minfo.nexthop))) {
806                 /* add neighbor system to map */
807                 printf("Adding neighbor system <%s> to map\n", slist->s_name);
808                 sprintf(aaa,"%s/network/systems/%s",bbs_home_directory,minfo.N);
809                 testfp=fopen(aaa,"r");
810                 if (testfp!=NULL) {
811                         fclose(testfp);
812                         stemp = (struct syslist *)
813                                 malloc((long)sizeof(struct syslist));
814                         stemp->next = slist;
815                         slist = stemp;
816                         strcpy(slist->s_name,minfo.N);
817                         strcpy(slist->s_type,"bin");
818                         strcpy(slist->s_nexthop,"Mail");
819                         time(&slist->s_lastcontact);
820                         }
821                 }
822         /* now update last contact and long node name if we can */
823         if (stemp!=NULL) {
824                 time(&stemp->s_lastcontact);
825                 if (strlen(minfo.H) > 0) strcpy(stemp->s_humannode,minfo.H);
826                 if (strlen(minfo.B) > 0) strcpy(stemp->s_phonenum,minfo.B);
827                 if (strlen(minfo.G) > 0) strcpy(stemp->s_gdom,minfo.G);
828                 }
829
830         /* route the message if necessary */
831         if ((strcasecmp(minfo.D,NODENAME))&&(minfo.D[0]!=0)) { 
832                 a = get_sysinfo_type(minfo.D);
833                 printf("netproc: routing message to system <%s>\n",minfo.D);
834                 fflush(stdout);
835                 if (a==M_INTERNET) {
836                         if (fork()==0) {
837                                 printf("netproc: netmailer %s\n", tname);
838                                 fflush(stdout);
839                                 execlp("./netmailer","netmailer",
840                                         tname,NULL);
841                                 printf("netproc: error running netmailer: %s\n",
842                                         strerror(errno));
843                                 fflush(stdout);
844                                 exit(errno);
845                                 }
846                         else while (wait(&b)!=(-1));
847                         }
848                 else if (a==M_BINARY) {
849                         ship_to(tname,minfo.D);
850                         }
851                 else {
852                         /* message falls into the bit bucket? */
853                         }
854                 }
855
856         /* check to see if it's a file transfer */
857         else if (!strncasecmp(minfo.S,"FILE",4)) {
858                 proc_file_transfer(tname);
859                 }
860
861         /* otherwise process it as a normal message */
862         else {
863
864                 if (!strcasecmp(minfo.R, "postmaster")) {
865                         strcpy(minfo.R, "");
866                         strcpy(minfo.C, "Aide");
867                         }
868
869                 if (strlen(minfo.R) > 0) {
870                         sprintf(buf,"GOTO _MAIL_");
871                         }
872                 if (is_banned(minfo.A,minfo.C,minfo.N)) {
873                         sprintf(buf,"GOTO %s", FILTERROOM);
874                         }
875                 else {
876                         if (strlen(minfo.C) > 0) {
877                                 sprintf(buf,"GOTO %s", minfo.C);
878                                 }
879                         else {
880                                 sprintf(buf,"GOTO %s", minfo.O);
881                                 }
882                         }
883                 serv_puts(buf);
884                 serv_gets(buf);
885                 if (buf[0] != '2') {
886                         puts(buf); fflush(stdout);
887                         sprintf(buf,"GOTO _BITBUCKET_");
888                         serv_puts(buf);
889                         serv_gets(buf);
890                         }
891
892                 /* Open the temporary file containing the message */
893                 message = fopen(tname, "rb");
894                 if (message == NULL) {
895                         fprintf(stderr, "netproc: cannot open %s: %s\n",
896                                 tname, strerror(errno));
897                         unlink(tname);
898                         goto NXMSG;
899                         }
900
901                 /* Transmit the message to the server */
902                 sprintf(buf, "ENT3 1|%s|%ld", minfo.R, msglen);
903                 printf("< %s\n", buf);
904                 serv_puts(buf);
905                 serv_gets(buf);
906                 printf("> %s\n", buf);
907                 if (!strncmp(buf, "570", 3)) {
908                         /* no such user, do a bounce */
909                         bounce(&minfo);
910                         }
911                 if (buf[0] == '7') {
912                         /* Always use the server's idea of the message length,
913                          * even though they should both be identical */
914                         msglen = atol(&buf[4]);
915                         while (msglen > 0L) {
916                                 bloklen = ((msglen >= 255L) ? 255 : ((int)msglen));
917                                 if (fread(buf, bloklen, 1, message) < 1) {
918                                         fprintf(stderr, "netproc: error trying to read %d bytes: %s\n",
919                                                 bloklen, strerror(errno));
920                                         fflush(stderr);
921                                         }
922                                 serv_write(buf, bloklen);
923                                 msglen = msglen - (long)bloklen;
924                                 }
925                         serv_puts("NOOP");
926                         serv_gets(buf);
927                         }
928                 else {
929                         puts(buf);
930                         fflush(stdout); 
931                         }
932
933                 fclose(message);
934                 }
935
936         unlink(tname);
937         goto NXMSG;
938
939 ENDSTR: fclose(fp);
940         unlink(pfilename);
941         }
942       } while(ptr!=NULL);
943     unlink(iname);
944     }
945
946
947 int checkpath(char *path, char *sys)    /* Checks to see whether its ok to send */
948                         /* Returns 1 for ok, send message       */
949             {           /* Returns 0 if message already there   */
950         int a;
951         char sys2[512];
952         strcpy(sys2,sys);
953         strcat(sys2,"!");
954
955 #ifdef DEBUG
956         printf("netproc: checkpath <%s> <%s> ... ",path,sys);
957 #endif
958         for (a=0; a<strlen(path); ++a) {
959                 if (!strncmp(&path[a],sys2,strlen(sys2))) return(0);
960                 }
961         return(1);
962         }
963
964 /*
965  * implement split horizon algorithm
966  */
967 int ismsgok(long int mpos, FILE *mmfp, char *sysname)
968 {
969         int a;
970         int ok = 0;             /* fail safe - no path, don't send it */
971         char fbuf[256];
972
973         fseek(mmfp,mpos,0);
974         if (getc(mmfp)!=255) return(0);
975         getc(mmfp); getc(mmfp);
976
977         while (a=getc(mmfp),((a!='M')&&(a!=0))) {
978                 fpgetfield(mmfp,fbuf);
979                 if (a=='P') {
980                         ok = checkpath(fbuf,sysname);
981                         }
982                 }
983 #ifdef DEBUG
984         printf("%s\n", ((ok)?"SEND":"(no)") );
985 #endif
986         return(ok);
987         }
988
989 int spool_out(struct msglist *cmlist, FILE *destfp, char *sysname)      /* spool list of messages to a file */
990                                         /* returns # of msgs spooled */
991               
992               
993 {
994         struct msglist *cmptr;
995         FILE *mmfp;
996         char mmtemp[128];
997         char fbuf[128];
998         int a;
999         int msgs_spooled = 0;
1000         long msg_len;
1001         int blok_len;
1002
1003         char buf[256];
1004         char curr_rm[256];
1005
1006         strcpy(curr_rm, "");
1007         sprintf(mmtemp, "/tmp/net.m%d", getpid());
1008
1009         /* for each message in the list... */
1010         for (cmptr=cmlist; cmptr!=NULL; cmptr=cmptr->next) {
1011
1012                 /* make sure we're in the correct room... */
1013                 if (strcasecmp(curr_rm, cmptr->m_rmname)) {
1014                         sprintf(buf, "GOTO %s", cmptr->m_rmname);
1015                         serv_puts(buf);
1016                         serv_gets(buf);
1017                         if (buf[0] == '2') {
1018                                 strcpy(curr_rm, cmptr->m_rmname);
1019                                 }
1020                         else {
1021                                 fprintf(stderr,"%s\n", buf);
1022                                 }
1023                         }
1024
1025                 /* download the message from the server... */
1026                 mmfp = fopen(mmtemp, "wb");
1027                 sprintf(buf, "MSG3 %ld", cmptr->m_num);
1028                 serv_puts(buf);
1029                 serv_gets(buf);
1030                 if (buf[0]=='6') {                      /* read the msg */
1031                         msg_len = atol(&buf[4]);
1032                         while (msg_len > 0L) {
1033                                 blok_len = ((msg_len >= 256L) ? 256 : (int)msg_len);
1034                                 serv_read(buf, blok_len);
1035                                 fwrite(buf, blok_len, 1, mmfp);
1036                                 msg_len = msg_len - (long)blok_len;
1037                                 }
1038                         }
1039                 else {                                  /* or print the err */
1040                         fprintf(stderr, "%s\n", buf);
1041                         }
1042                 fclose(mmfp);
1043         
1044                 mmfp = fopen(mmtemp,"rb");
1045
1046                 if (ismsgok(0L,mmfp,sysname)) {
1047                         ++msgs_spooled;
1048                         fflush(stdout);
1049                         fseek(mmfp,0L,0);
1050                         fread(fbuf,3,1,mmfp);
1051                         fwrite(fbuf,3,1,destfp);
1052                         while (a=getc(mmfp),((a!=0)&&(a!='M'))) {
1053                                 if (a!='C') putc(a,destfp);
1054                                 fpgetfield(mmfp,fbuf);
1055                                 if (a=='P') fprintf(destfp,"%s!",NODENAME);
1056                                 if (a!='C')
1057                                         fwrite(fbuf,strlen(fbuf)+1,1,destfp);
1058                                 }
1059                         if (a=='M') {
1060                                 fprintf(destfp, "C%s%c",
1061                                         cmptr->m_rmname, 0);
1062                                 putc('M',destfp);
1063                                 do {
1064                                         a=getc(mmfp);
1065                                         putc(a,destfp);
1066                                         } while(a>0);
1067                                 }
1068                         }
1069                 fclose(mmfp);
1070                 }
1071
1072         unlink(mmtemp);
1073         return(msgs_spooled);
1074         }
1075
1076 void outprocess(char *sysname) /* send new room messages to sysname */
1077                {
1078         char sysflnm[64];
1079         char srmname[32];
1080         char shiptocmd[128];
1081         char lbuf[64];
1082         char tempflnm[64];
1083         char buf[256];
1084         struct msglist *cmlist = NULL;
1085         struct rmlist *crmlist = NULL;
1086         struct rmlist *rmptr,*rmptr2;
1087         struct msglist *cmptr,*cmptr2;
1088         FILE *sysflfp,*tempflfp;
1089         int outgoing_msgs;
1090         long thismsg;
1091
1092         sprintf(tempflnm,"/tmp/%s.%d",NODENAME,getpid());
1093         tempflfp=fopen(tempflnm,"w");
1094         if (tempflfp==NULL) return;
1095
1096
1097 /*
1098  * Read system file for node in question and put together room list
1099  */
1100         sprintf(sysflnm,"%s/network/systems/%s",bbs_home_directory,sysname);
1101         sysflfp=fopen(sysflnm,"r");
1102         if (sysflfp==NULL) return;
1103         fgets(shiptocmd,128,sysflfp); shiptocmd[strlen(shiptocmd)-1]=0;
1104         while(!feof(sysflfp)) {
1105                 if (fgets(srmname,32,sysflfp)==NULL) break;
1106                 srmname[strlen(srmname)-1]=0;
1107                 fgets(lbuf,32,sysflfp);
1108                 rmptr=(struct rmlist *)malloc(sizeof(struct rmlist));
1109                 rmptr->next = NULL;
1110                 strcpy(rmptr->rm_name,srmname);
1111                 strip_trailing_whitespace(rmptr->rm_name);
1112                 rmptr->rm_lastsent = atol(lbuf);
1113                 if (crmlist==NULL) crmlist=rmptr;
1114                 else if (!strcasecmp(rmptr->rm_name,"control")) {
1115                         /* control has to be first in room list */
1116                         rmptr->next = crmlist;
1117                         crmlist = rmptr;
1118                         }
1119                 else {
1120                         rmptr2=crmlist;
1121                         while (rmptr2->next != NULL) rmptr2=rmptr2->next;
1122                         rmptr2->next=rmptr;
1123                         }
1124                 }
1125         fclose(sysflfp);
1126
1127 /*
1128  * Assemble list of messages to be spooled
1129  */
1130         for (rmptr=crmlist; rmptr!=NULL; rmptr=rmptr->next) {
1131
1132                 sprintf(buf,"GOTO %s",rmptr->rm_name);
1133                 serv_puts(buf);
1134                 serv_gets(buf);
1135                 if (buf[0]!='2') {
1136                         fprintf(stderr, "%s\n", buf);
1137                         }
1138                 else {
1139                         sprintf(buf, "MSGS GT|%ld", rmptr->rm_lastsent);
1140                         serv_puts(buf);
1141                         serv_gets(buf);
1142                         if (buf[0]=='1') while (serv_gets(buf), strcmp(buf,"000")) {
1143                                 thismsg = atol(buf);
1144                                 if ( thismsg > (rmptr->rm_lastsent) ) {
1145                                         rmptr->rm_lastsent = thismsg;
1146                                         
1147                                 cmptr=(struct msglist *)
1148                                       malloc(sizeof(struct msglist));
1149                                         cmptr->next = NULL;
1150                                         cmptr->m_num = thismsg;
1151                                         strcpy(cmptr->m_rmname, rmptr->rm_name);
1152         
1153                                         if (cmlist == NULL) cmlist = cmptr;
1154                                         else {
1155                                                 cmptr2 = cmlist;
1156                                                 while (cmptr2->next != NULL)
1157                                                 cmptr2 = cmptr2->next;
1158                                                 cmptr2->next = cmptr;
1159                                                 }
1160                                         }
1161                                 }
1162                         else {          /* print error from "msgs all" */
1163                                 fprintf(stderr, "%s\n", buf);
1164                                 }
1165                         }
1166                 }
1167
1168         outgoing_msgs=0; cmptr2=cmlist; /* this loop counts the messages */
1169         while (cmptr2!=NULL) {
1170                 ++outgoing_msgs;
1171                 cmptr2 = cmptr2->next;
1172                 }
1173         printf("netproc: %d messages to be spooled to %s\n",
1174                 outgoing_msgs,sysname);
1175         fflush(stdout);
1176
1177 /*
1178  * Spool out the messages, but only if there are any.
1179  */
1180         fflush(stdout);
1181         if (outgoing_msgs!=0) outgoing_msgs=spool_out(cmlist,tempflfp,sysname);
1182         printf("netproc: %d messages actually spooled\n",
1183                 outgoing_msgs);
1184         fflush(stdout);
1185
1186 /*
1187  * Deallocate list of spooled messages.
1188  */
1189         while(cmlist!=NULL) {
1190                 cmptr=cmlist->next;
1191                 free(cmlist);
1192                 cmlist=cmptr;
1193                 }
1194
1195 /*
1196  * Rewrite system file and deallocate room list.
1197  */
1198         printf("Spooling...\n");
1199         fflush(stdout);
1200         sysflfp=fopen(sysflnm,"w");
1201         fprintf(sysflfp,"%s\n",shiptocmd);
1202         for (rmptr=crmlist; rmptr!=NULL; rmptr=rmptr->next)  
1203                 fprintf(sysflfp,"%s\n%ld\n",rmptr->rm_name,rmptr->rm_lastsent);
1204         fclose(sysflfp);
1205         while(crmlist!=NULL) {
1206                 rmptr=crmlist->next;
1207                 free(crmlist);
1208                 crmlist=rmptr;
1209                 }
1210
1211 /* 
1212  * Close temporary file, ship it out, and return
1213  */
1214         fclose(tempflfp);
1215         if (outgoing_msgs!=0) ship_to(tempflnm,sysname);
1216         unlink(tempflnm);
1217         }
1218
1219
1220 /*
1221  * Connect netproc to the Citadel server running on this computer.
1222  */
1223 void np_attach_to_server(void) {
1224         char buf[256];
1225         char portname[8];
1226         char *args[] = { "netproc", "localhost", NULL, NULL } ;
1227
1228         printf("Attaching to server...\n");
1229         sprintf(portname, "%d", config.c_port_number);
1230         args[2] = portname;
1231         attach_to_server(3, args);
1232         serv_gets(buf);
1233         printf("%s\n",&buf[4]);
1234         sprintf(buf,"IPGM %d", config.c_ipgm_secret);
1235         serv_puts(buf);
1236         serv_gets(buf);
1237         printf("%s\n",&buf[4]);
1238         if (buf[0]!='2') {
1239                 cleanup(2);
1240                 }
1241         }
1242
1243
1244
1245 /*
1246  * main
1247  */
1248 void main(int argc, char **argv)
1249 {
1250         char allst[32];
1251         FILE *allfp;
1252         int a;
1253
1254
1255         strcpy(bbs_home_directory, BBSDIR);
1256
1257         /*
1258          * Change directories if specified
1259          */
1260         if (argv > 0) for (a=1; a<argc; ++a) {
1261                 if (!strncmp(argv[a], "-h", 2)) {
1262                         strcpy(bbs_home_directory, argv[a]);
1263                         strcpy(bbs_home_directory, &bbs_home_directory[2]);
1264                         home_specified = 1;
1265                         }
1266                 else {
1267                         fprintf(stderr, "netproc: usage: netproc [-hHomeDir]\n");
1268                         exit(1);
1269                         }
1270                 }
1271
1272         get_config();
1273
1274         /* write all messages to the log from this point onward */
1275         freopen(NPLOGFILE,NPLOGMODE,stdout);
1276         freopen(NPLOGFILE,NPLOGMODE,stderr);
1277
1278         if (set_lockfile()!=0) {
1279                 fprintf(stderr,"netproc: lock file exists: already running\n");
1280                 cleanup(1);
1281                 }
1282
1283         signal(SIGINT,cleanup);
1284         signal(SIGQUIT,cleanup);
1285         signal(SIGHUP,cleanup);
1286         signal(SIGTERM,cleanup);
1287
1288         printf("netproc: started.  pid=%d\n",getpid());
1289         fflush(stdout);
1290         np_attach_to_server();
1291         fflush(stdout);
1292
1293         if (load_roomnames()!=0) fprintf(stdout,"netproc: cannot load rooms\n");
1294         if (load_syslist()!=0) fprintf(stdout,"netproc: cannot load sysinfo\n");
1295         setup_special_nodes();
1296
1297         inprocess();    /* first collect incoming stuff */
1298
1299         allfp=(FILE *)popen("cd ./network/systems; ls","r");
1300         if (allfp!=NULL) {
1301                 while (fgets(allst,32,allfp)!=NULL) {
1302                         allst[strlen(allst)-1] = 0;
1303                         outprocess(allst);
1304                         }
1305                 pclose(allfp);
1306                 }
1307
1308         inprocess();    /* incoming again in case anything new was generated */
1309         rewrite_syslist();
1310         printf("netproc: processing ended.\n");
1311         cleanup(0);
1312         }
1313