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