1 /*****************************************************************************
2  * HPT --- FTN NetMail/EchoMail Tosser
3  *****************************************************************************
4  * Copyright (C) 1997-1999
5  *
6  * Matthias Tichy
7  *
8  * Fido:     2:2433/1245 2:2433/1247 2:2432/605.14
9  * Internet: mtt@tichy.de
10  *
11  * Grimmestr. 12         Buchholzer Weg 4
12  * 33098 Paderborn       40472 Duesseldorf
13  * Germany               Germany
14  *
15  * This file is part of HPT.
16  *
17  * HPT is free software; you can redistribute it and/or modify it
18  * under the terms of the GNU General Public License as published by the
19  * Free Software Foundation; either version 2, or (at your option) any
20  * later version.
21  *
22  * HPT is distributed in the hope that it will be useful, but
23  * WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25  * General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with HPT; see the file COPYING.  If not, write to the Free
29  * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
30  *****************************************************************************
31  * $Id$
32  */
33 #include <time.h>
34 #include <string.h>
35 #include <stdlib.h>
36 #include <ctype.h>
37 #include <stdio.h>
38 #include <fcntl.h>
39 #include <errno.h>
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 
43 #include <huskylib/compiler.h>
44 
45 #ifdef HAS_PROCESS_H
46 #  include <process.h>
47 #endif
48 
49 #ifdef HAS_UNISTD_H
50 #   include <unistd.h>
51 #endif
52 
53 #ifdef HAS_IO_H
54 #   include <io.h>
55 #endif
56 
57 #ifdef HAS_SYS_SYSEXITS_H
58 #include <sys/sysexits.h>
59 #endif
60 #ifdef HAS_SYSEXITS_H
61 #include <sysexits.h>
62 #endif
63 
64 #ifdef HAS_DOS_H
65 #include <dos.h>
66 #endif
67 
68 #if defined(__TURBOC__) || defined(__IBMC__)
69 
70 #if !defined(S_ISDIR)
71 #define S_ISDIR(a) (((a) & S_IFDIR) != 0)
72 #endif
73 
74 #endif
75 
76 #include <huskylib/huskylib.h>
77 #include <huskylib/cvtdate.h>
78 #include <huskylib/xstr.h>
79 #include <huskylib/dirlayer.h>
80 #include <huskylib/recode.h>
81 #include <huskylib/crc.h>
82 
83 #include <fidoconf/fidoconf.h>
84 #include <fidoconf/common.h>
85 
86 #include <areafix/areafix.h>
87 
88 #include <global.h>
89 #include <fcommon.h>
90 #include <dupe.h>
91 
writeDupeFiles(void)92 void writeDupeFiles(void)
93 {
94 	unsigned i;
95 
96 	/*  write dupeFiles */
97 	for (i = 0 ; i < config->echoAreaCount; i++) {
98 		writeToDupeFile(&(config->echoAreas[i]));
99 		freeDupeMemory(&(config->echoAreas[i]));
100 	}
101 	for (i = 0 ; i < config->netMailAreaCount; i++) {
102 		writeToDupeFile(&(config->netMailAreas[i]));
103 		freeDupeMemory(&(config->netMailAreas[i]));
104 	}
105 }
106 
exit_hpt(char * logstr,int print)107 void exit_hpt(char *logstr, int print) {
108 
109     w_log(LL_FUNC,"exit_hpt()");
110     w_log(LL_CRIT, logstr);
111     if (!config->logEchoToScreen && print) fprintf(stderr, "%s\n", logstr);
112 
113     writeDupeFiles();
114     doneCharsets();
115     w_log(LL_STOP, "Exit");
116     closeLog();
117     if (config->lockfile) {
118        FreelockFile(config->lockfile ,lock_fd);
119     }
120     disposeConfig(config);
121 
122     exit(EX_SOFTWARE);
123 }
124 
125 /* this function has no calls
126 int createLockFile(char *lockfile) {
127         int fd;
128         char *pidstr = NULL;
129 
130         w_log(LL_FUNC,"createLockFile()");
131         if ( (fd=open(lockfile, O_CREAT | O_RDWR | O_EXCL, S_IREAD | S_IWRITE)) < 0 )
132            {
133                    fprintf(stderr,"createLockFile: cannot create lock file\"%s\"\n",lockfile);
134                    w_log(LL_ERR, "createLockFile: cannot create lock file \"%s\"m", lockfile);
135                    return 1;
136            }
137 
138         xscatprintf(&pidstr, "%u\n", (unsigned)getpid());
139         write (fd, pidstr, strlen(pidstr));
140 
141         close(fd);
142 	nfree(pidstr);
143         w_log(LL_FUNC,"createLockFile() OK");
144         return 0;
145 }
146 */
147 /*
148 e_prio cvtFlavour2Prio(e_flavour flavour)
149 {
150    switch (flavour) {
151       case hold:      return HOLD;
152       case normal:    return NORMAL;
153       case direct:    return DIRECT;
154       case crash:     return CRASH;
155       case immediate: return IMMEDIATE;
156       default:        return NORMAL;
157    }
158    return NORMAL;
159 }
160 */
161 #if 1
162 /* This old code will be removed once the new one proves to be reliable */
163 
fileNameAlreadyUsed(char * pktName,char * packName)164 int fileNameAlreadyUsed(char *pktName, char *packName) {
165    UINT i;
166 
167    for (i=0; i < config->linkCount; i++) {
168       if ((config->links[i]->pktFile != NULL) && (pktName != NULL))
169          if ((stricmp(pktName, config->links[i]->pktFile)==0)) return 1;
170       if ((config->links[i]->packFile != NULL) && (packName != NULL))
171          if ((stricmp(packName, config->links[i]->packFile)==0)) return 1;
172    }
173 
174    return 0;
175 }
176 
177 
178 static char *wdays[7]={ "su", "mo", "tu", "we", "th", "fr", "sa" };
179 
cleanEmptyBundles(char * pathName,size_t npos,char * wday)180 void cleanEmptyBundles(char *pathName, size_t npos, char *wday)
181 /*  Removing old empty bundles when bundleNameStyle == addDiff */
182 {
183    char           *ptr, *tmpfile, *pattern, savech;
184    husky_DIR      *dir;
185    char           *filename;
186    struct stat stbuf;
187    unsigned pathlen;
188 
189    if( npos >= strlen(pathName) )
190    { w_log( LL_CRIT, "fcommon.c:cleanEmptyBundles(): 'npos' too big! Can't work." );
191      return;
192    }
193    pathlen = strlen(pathName) + 4;
194    tmpfile = safe_malloc(pathlen);
195 
196    strcpy(tmpfile, pathName);
197    savech = tmpfile[npos-1]; /*  there must be path delimiter */
198    tmpfile[npos-1] = '\0';
199 
200    if((dir = husky_opendir(tmpfile)) == NULL) { /*  nothing to clean */
201       nfree(tmpfile);
202       return;
203    }
204 
205    tmpfile[npos-1] = savech;
206 
207    pattern = safe_malloc(strlen(tmpfile+npos) + 4);
208    strcpy(pattern, tmpfile+npos);
209 
210    for (ptr=pattern; *ptr; ptr++);
211    ptr[0]='*';
212    ptr[1]='\0';
213 
214    while ((filename = husky_readdir(dir)) != NULL) {
215 
216 	   if ( patimat(filename, pattern) == 1 &&
217 	        strncasecmp(filename+(ptr-pattern), wday, 2) != 0 ) {
218 
219 		   strcpy(tmpfile+npos, filename);
220 
221 		   if (stat(tmpfile, &stbuf) == 0 && stbuf.st_size == 0) {
222 
223 				   remove (tmpfile); /*  old empty bundle */
224 		   }
225 	   }
226    }
227 
228    husky_closedir(dir);
229    nfree(pattern);
230    nfree(tmpfile);
231 }
232 
233 /* old algorythm, use it if used didn't set SeqDir */
createTempPktFileName_legasy(s_link * link)234 int createTempPktFileName_legasy(s_link *link)
235 {
236     char *fileName=NULL; /*  pkt file in tempOutbound */
237     time_t aTime = time(NULL);  /* get actual time */
238     int counter;
239 
240     counter = pkt_count;
241 
242     aTime %= 0xffffff;   /* only last 24 bit count */
243 
244     /* Making pkt name */
245     for (;;)
246     {
247 		do {
248 			nfree(fileName);
249 			xscatprintf(&fileName, "%s%06lx%02x.pkt",
250 						config->tempOutbound, (long)aTime, counter);
251 			counter++;
252 
253 		} while ((fexist(fileName) || fileNameAlreadyUsed(fileName, NULL)) &&
254 				 (counter<=255));
255 
256 		if (counter<=256) break;
257 		else {
258 			counter=0;
259 			if (pkt_aTime==aTime) {
260 				sleep(1);
261 				aTime = time(NULL);
262 				aTime %= 0xffffff;
263 			}
264 		}
265     }
266     pkt_count = counter;
267     pkt_aTime = aTime;
268 
269     nfree(link->pktFile);
270     link->pktFile = fileName;
271     w_log(LL_CREAT,"pktFile %s created for [%s]",
272           link->pktFile,
273           aka2str(link->hisAka));
274     return 0;
275 }
276 
createTempPktFileName(s_link * link)277 int createTempPktFileName(s_link *link)
278 {
279     char *fileName=NULL; /*  pkt file in tempOutbound */
280 
281     if (config->seqDir == NULL)
282         return createTempPktFileName_legasy(link);
283 
284     /* Making pkt name */
285     do {
286         nfree(fileName);
287         xscatprintf(&fileName, "%s%08x.pkt",
288                     config->tempOutbound,
289                     GenMsgId(config->seqDir, config->seqOutrun)
290                    );
291     } while (fexist(fileName) || fileNameAlreadyUsed(fileName, NULL));
292 
293     nfree(link->pktFile);
294     link->pktFile = fileName;
295     w_log(LL_CREAT,"pktFile %s created for [%s]",
296           link->pktFile,
297           aka2str(link->hisAka));
298     return 0;
299 }
300 
createPackFileName(s_link * link)301 int createPackFileName(s_link *link)
302 {
303     char *pfileName=NULL; /*  name of the arcmail bundle */
304     char *tmp=NULL; /*  temp name of the arcmail bundle */
305     char *tmp2=NULL;    /* temp string */
306     int  minFreeExt;
307     size_t npos;
308     char limiter=PATH_DELIM;
309     time_t tr, aTime;
310     char *wday;
311     struct tm *tp;
312     int i;
313     struct stat stbuf;
314     static char ext3[] = "0123456789abcdefghijklmnopqrstuvwxyz";
315     int numExt = sizeof(ext3)-1;
316     int counter;
317     hs_addr *aka;
318     char *str_hisAka, *str_Aka;
319     e_bundleFileNameStyle bundleNameStyle = eTimeStamp;
320 
321     tr=aTime=time(NULL);
322     aTime %= 0xffffff;
323     tp=localtime(&tr);
324     counter = pkt_count;
325 
326     wday=wdays[tp->tm_wday];
327 
328     aka = SelectPackAka(link);
329 
330     if (link->linkBundleNameStyle!=eUndef) bundleNameStyle=link->linkBundleNameStyle;
331     else if (config->bundleNameStyle!=eUndef) bundleNameStyle=config->bundleNameStyle;
332 
333     /*  fileBoxes support */
334     if (needUseFileBoxForLinkAka(config,link,aka)) {
335 	if (!link->fileBox) link->fileBox = makeFileBoxNameAka (config,link,aka);
336 	xstrcat(&tmp, link->fileBox);
337 	_createDirectoryTree (tmp);
338     } else {
339 	xstrcat(&tmp, config->outbound);
340 
341 	/*  add suffix for other zones */
342 	if (aka->zone != config->addr[0].zone && bundleNameStyle != eAmiga) {
343 		tmp[strlen(tmp)-1]='\0';
344 		xscatprintf(&tmp, ".%03x%c", aka->zone, limiter);
345 	}
346 
347 	/*  path to bundle */
348 	if (bundleNameStyle!=eAmiga) {
349 		if (aka->point)
350 			xscatprintf(&tmp, "%04x%04x.pnt%c",
351 						aka->net, aka->node, limiter);
352 
353 		/*  separate bundles */
354 		if (config->separateBundles) {
355 			if (aka->point) xscatprintf(&tmp, "%08x.sep%c",
356 							aka->point, limiter);
357 			else xscatprintf(&tmp, "%04x%04x.sep%c", aka->net,
358 							aka->node, limiter);
359 		}
360 	}
361 
362     } /*  link->fileBox */
363 
364     npos = strlen(tmp);
365 
366     /* bundle file name */
367     switch ( bundleNameStyle ) {
368 
369     case eAddrsCRC32:
370     case eAddrsCRC32Always:
371     case eAddrDiff:
372     case eAddrDiffAlways:
373                 if( bundleNameStyle == eAddrsCRC32 ||
374                     bundleNameStyle == eAddrsCRC32Always ) {
375                   xscatprintf( &tmp2, "hpt %s ", aka2str(config->addr[0]) );
376   	          xstrcat( &tmp2, aka2str(*aka) );
377                   xscatprintf(&tmp,"%08x.", strcrc32(tmp2,0xFFFFFFFFUL) );
378                   nfree(tmp2);
379                 } else {
380                   if ( aka->point == 0 && config->addr[0].point == 0) {
381                     xscatprintf (&tmp, "%04hx%04hx.",
382                                  config->addr[0].net - aka->net,
383                                  config->addr[0].node - aka->node);
384                   } else {
385                     xscatprintf (&tmp, "%04hx%04hx.",
386                                  config->addr[0].node - aka->node,
387                                  config->addr[0].point- aka->point);
388                   }
389                 }
390                 w_log(LL_FILENAME, "bundle name generating: %s", tmp);
391 
392     case eAmiga:
393 		if (bundleNameStyle==eAmiga) {
394 			xscatprintf (&tmp, "%u.%u.%u.%u.",
395 						 aka->zone, aka->net,
396 						 aka->node, aka->point);
397 		}
398 
399 		if (!needUseFileBoxForLinkAka(config,link,aka)) cleanEmptyBundles(tmp,npos,wday);
400 
401 		counter = 0;
402 		minFreeExt = -1;
403 		for (i=0; i<numExt; i++) {
404 
405 			xstrscat(&pfileName, tmp, wday, NULLP);
406 			xscatprintf(&pfileName, "%c", ext3[i]);
407 
408 			if (stat(pfileName, &stbuf) == 0) {
409 
410 				if (tr - stbuf.st_mtime < 60*60*48) {
411 					/*  today's bundle */
412 					counter = i+1;
413 					if (stbuf.st_size==0 && (counter<numExt ||
414       					    bundleNameStyle==eAddrDiffAlways ||
415       					    bundleNameStyle==eAddrsCRC32Always ||
416       					    bundleNameStyle==eAmiga))
417 					   remove (pfileName);
418 				} else {
419 					/*  old bundle */
420 					if (stbuf.st_size == 0)	remove (pfileName);
421 					else counter = i+1;
422 				}
423 			} else if (errno==ENOENT) {
424 				if (minFreeExt <0) minFreeExt = i;
425 			}
426 
427 			nfree(pfileName);
428 		}
429 
430 		if (counter >= numExt) {
431 			if ((bundleNameStyle==eAddrDiffAlways ||
432 			     bundleNameStyle==eAddrsCRC32Always ||
433 			     bundleNameStyle==eAmiga)
434 				&& minFreeExt>=0) {
435 				counter = minFreeExt;
436 			} else {
437 				w_log(LL_ERR,"Can't use more than %d extensions for bundle names",numExt);
438 				nfree(pfileName);
439 				nfree(tmp);
440 				/*  Switch link to TimeStamp style */
441 				link->linkBundleNameStyle = eTimeStamp;
442 				i = createPackFileName(link);
443 				link->linkBundleNameStyle = bundleNameStyle;
444 				return i;
445 			}
446 		}
447 
448 		xstrscat(&pfileName, tmp, wday, NULLP);
449 		xscatprintf(&pfileName, "%c", ext3[counter]);
450 
451 		break;
452 
453     case eTimeStamp:
454 		counter = 0;
455 		do {
456 			nfree(pfileName);
457 			xscatprintf(&pfileName, "%s%06lx%02x.%s%c", tmp, (long)aTime, counter%256, wday, ext3[counter/256]);
458 			counter++;
459 		} while ((fexist(pfileName) || fileNameAlreadyUsed(NULL, pfileName))
460 				 && (counter < numExt*256));
461 
462 		if (counter >= numExt*256)
463 			w_log(LL_STAT,"created %d bundles/sec!", numExt*256);
464 
465 		break;
466 
467     default:
468 		w_log(LL_ERR, "Unknown bundleNameStyle (non-compatible fidoconfig library?)");
469 		exit(EX_SOFTWARE);
470 		break;
471     }
472     nfree(tmp);
473 
474     if (!fexist(pfileName)) {
475         nfree(link->packFile);
476         link->packFile = pfileName;
477         str_hisAka = aka2str5d(link->hisAka);
478         str_Aka = aka2str5d(*aka);
479         w_log(LL_CREAT,"packFile %s created for [%s via %s]",
480             link->packFile,
481             str_hisAka, str_Aka);
482         nfree(str_hisAka); nfree(str_Aka);
483         return 0;
484     }
485     else {
486         nfree(pfileName);
487 	w_log(LL_ERR,"can't create arcmail bundles any more!");
488         return 1;
489     }
490 }/* createPackFileName() */
491 #endif
492 
493 #if 0
494 /* filenames are not FTSC compliant, some links have problems :-( */
495 int createTempPktFileName(s_link *link)
496 {
497     char  *filename = NULL;     /* pkt file in tempOutbound */
498     char  *pfilename;           /* name of the arcmail bundle */
499     char   limiter = PATH_DELIM;
500     char   ext[4];              /* week-day based extension of the pack file */
501     char   zoneSuffix[6]="\0";
502     char  *zoneOutbound;        /* this contains the correct outbound directory
503                                    including zones */
504     char   uniquestring[9];     /* the unique part of filename */
505 
506     time_t       tr;
507     static char *wdays[7]={ "su", "mo", "tu", "we", "th", "fr", "sa" };
508     struct tm   *tp;
509 
510     tr=time(NULL);
511     tp=localtime(&tr);
512     sprintf(ext,"%s0", wdays[tp->tm_wday]);
513 
514     pfilename = (char *) malloc(strlen(config->outbound)+13+13+12+1);
515 
516     if (link->hisAka.zone != config->addr[0].zone) {
517         sprintf(zoneSuffix, ".%03x%c", link->hisAka.zone, PATH_DELIM);
518         zoneOutbound = safe_malloc(strlen(config->outbound)-1+strlen(zoneSuffix)+1);
519         strcpy(zoneOutbound, config->outbound);
520         strcpy(zoneOutbound+strlen(zoneOutbound)-1, zoneSuffix);
521     } else
522         zoneOutbound = safe_strdup(config->outbound);
523 
524     do
525     {
526         nfree(filename);
527         filename = makeUniqueDosFileName(config->tempOutbound, "pkt", config);
528         memcpy(uniquestring, filename + strlen(config->tempOutbound), 8);
529         uniquestring[8] = '\0';
530 
531         if (link->hisAka.point == 0)
532         {
533             if (config->separateBundles)
534             {
535                 sprintf(pfilename,"%s%04x%04x.sep%c%s.%s",
536                         zoneOutbound, link->hisAka.net, link->hisAka.node,
537                         limiter, uniquestring, ext);
538             } else
539             {
540                 sprintf(pfilename,"%s%s.%s",zoneOutbound,
541                         uniquestring, ext);
542             }
543         } else
544         {
545             if (config->separateBundles)
546             {
547                 sprintf(pfilename,"%s%04x%04x.pnt%c%08x.sep%c%s.%s",
548                         zoneOutbound, link->hisAka.net, link->hisAka.node,
549                         limiter, link->hisAka.point, limiter,
550                         uniquestring, ext);
551             } else
552             {
553                 sprintf(pfilename,"%s%04x%04x.pnt%c%s.%s",
554                         zoneOutbound, link->hisAka.net, link->hisAka.node,
555                         limiter, uniquestring, ext);
556             }
557         }
558     } while (fexist(filename) || fexist(pfilename));
559 
560     nfree(zoneOutbound);
561 
562     nfree(link->packFile);
563     nfree(link->pktFile);
564 
565     link->packFile = pfilename;
566     link->pktFile = filename;
567     return 0;
568 }
569 /*  this function moved to smapi has name _createDirectoryTree */
570 int createDirectoryTree(const char *pathName) {
571    char *start, *slash;
572 
573    char limiter=PATH_DELIM;
574 
575    int i;
576 
577    start = (char *) safe_malloc(strlen(pathName)+2);
578    strcpy(start, pathName);
579    i = strlen(start)-1;
580    if (start[i] != limiter) {
581       start[i+1] = limiter;
582       start[i+2] = '\0';
583    }
584    slash = start;
585 
586 #ifndef __UNIX__
587    /*  if there is a drivename, jump over it */
588    if (slash[1] == ':') slash += 2;
589 #endif
590 
591    /*  jump over first limiter */
592    slash++;
593 
594    while ((slash = strchr(slash, limiter)) != NULL) {
595       *slash = '\0';
596 
597       if (!direxist(start)) {
598          if (!fexist(start)) {
599             /*  this part of the path does not exist, create it */
600             if (mymkdir(start) != 0) {
601                w_log(LL_ERR, "Could not create directory %s", start);
602                nfree(start);
603                return 1;
604             }
605          } else {
606             w_log(LL_ERR, "%s is a file not a directory", start);
607             nfree(start);
608             return 1;
609          }
610       }
611 
612       *slash++ = limiter;
613    }
614 
615    nfree(start);
616 
617    return 0;
618 } /* createDirectoryTree() */
619 #endif
620 
createOutboundFileNameAka(s_link * link,e_flavour prio,e_pollType typ,hs_addr * aka)621 int createOutboundFileNameAka(s_link *link, e_flavour prio, e_pollType typ, hs_addr *aka)
622 {
623    int nRet = NCreateOutboundFileNameAka(config,link,prio,typ,aka);
624    if(nRet == -1)
625       exit_hpt("cannot create *.bsy file!",0);
626    return nRet;
627 }
628 
createOutboundFileName(s_link * link,e_flavour prio,e_pollType typ)629 int createOutboundFileName(s_link *link, e_flavour prio, e_pollType typ)
630 {
631   return createOutboundFileNameAka(link, prio, typ, &(link->hisAka));
632 }
633 
safe_malloc(size_t size)634 void *safe_malloc(size_t size)
635 {
636     void *ptr = malloc (size);
637     if (ptr == NULL) exit_hpt("out of memory (safe_malloc())", 1);
638     return ptr;
639 }
640 
safe_calloc(size_t nmemb,size_t size)641 void *safe_calloc(size_t nmemb, size_t size)
642 {
643     void *ptr = safe_malloc (size*nmemb);
644     memset(ptr,'\0',size*nmemb);
645     return ptr;
646 }
647 
safe_realloc(void * ptr,size_t size)648 void *safe_realloc(void *ptr, size_t size)
649 {
650     void *newptr = realloc (ptr, size);
651     if (newptr == NULL) exit_hpt("out of memory (safe_realloc())", 1);
652     return newptr;
653 }
654 
safe_strdup(const char * src)655 char *safe_strdup(const char *src)
656 {
657     char *ptr=NULL;
658     if(src)
659       if ( ( ptr = strdup (src) ) == NULL ) /* use sstrdup() from fidoconfig library */
660         exit_hpt("out of memory (safe_strdup())", 1);
661     return ptr;
662 }
663 
writeEchoTossLogEntry(char * areaName)664 void writeEchoTossLogEntry(char *areaName)
665 {
666     if (areaName && config->echotosslog)
667     {
668         FILE *f=fopen(config->echotosslog, "a");
669         if (f==NULL)
670             w_log(LL_ERROR, "Could not open or create EchoTossLogFile.");
671         else {
672             fprintf(f, "%s\n", areaName);
673             fclose(f);
674         }
675     }
676 }
677