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