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