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