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