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