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