1 /******************************************************************************
2  * FIDOCONFIG --- library for fidonet configs
3  ******************************************************************************
4  * Copyright (C) 1998-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 FIDOCONFIG.
16  *
17  * This library is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU Library General Public
19  * License as published by the Free Software Foundation; either
20  * version 2 of the License, or (at your option) any later version.
21  *
22  * This library is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25  * Library General Public License for more details.
26  *
27  * You should have received a copy of the GNU Library General Public
28  * License along with this library; see file COPYING. If not, write to the Free
29  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
30  *****************************************************************************
31  * $Id$
32  */
33 
34 #include <time.h>
35 #include <string.h>
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <ctype.h>
39 #include <signal.h>
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <fcntl.h>
43 #include <errno.h>
44 
45 #include <huskylib/compiler.h>
46 
47 #ifdef HAS_UNISTD_H
48 #  include <unistd.h>
49 #endif
50 
51 #ifdef HAS_IO_H
52 #  include <io.h>
53 #endif
54 
55 #ifdef HAS_DOS_H
56 #include <dos.h>
57 #endif
58 
59 #ifdef HAS_PROCESS_H
60 #include <process.h>
61 #endif
62 
63 #ifdef HAS_STRINGS_H
64 #include <strings.h>
65 #endif
66 
67 #ifdef __BEOS__
68 #include <KernelKit.h>
69 #endif
70 
71 #include <huskylib/huskylib.h>
72 
73 /* export functions from DLL */
74 #define DLLEXPORT
75 #include <huskylib/huskyext.h>
76 
77 /* smapi */
78 #include <smapi/msgapi.h>
79 
80 #include "fidoconf.h"
81 #include "common.h"
82 
83 
84 static char *attrStr[] = { "pvt", "crash", "read", "sent", "att",
85                        "fwd", "orphan", "k/s", "loc", "hld",
86                        "xx2",  "frq", "rrq", "cpt", "arq", "urq" };
87 static char *eattr[] = { "KFS", "TFS", "DIR", "IMM", "CFM", "NPD" };
88 
parseAttrString(char * str,char ** flags,long * bitattr,char ** end)89 int parseAttrString(char *str, char **flags, long *bitattr, char **end)
90 {
91     char *p, *flag, c;
92     long attr;
93     int parsed = 0;
94 
95     if(str == NULL || flags == NULL)
96     {
97         if(end != NULL)
98             *end = str;
99         return -1;
100     }
101 
102     while (1) {
103         while (*str && (isspace(*str) || *str==','))
104             ++str;
105         if (!*str) break;
106         for (p = str; *p && *p!=',' && !isspace(*p); ++p) ;
107         c = *p;
108         *p = '\0';
109         if ((attr = str2attr(str)) != -1L) {
110             *bitattr |= attr;
111             ++parsed;
112         }
113         else if ((flag = extattr(str)) != NULL) {
114             xstrscat(flags, *flags ? " " : "", flag, NULLP);
115             ++parsed;
116         }
117         else {
118             *p = c;
119             if(end != NULL)
120                 *end = str;
121             return parsed;
122         }
123         *p = c;
124         str = p;
125     }
126 
127     if(end != NULL)
128         *end = str;
129     return parsed;
130 }
131 
str2attr(const char * str)132 long  str2attr(const char *str)
133 {
134    size_t i;
135    for (i = 0; i < sizeof(attrStr) / sizeof(char *); i++)
136            if (strncasecmp(str, attrStr[i], strlen(attrStr[i]))==0)
137                    return 1 << i;
138    return -1L;
139 }
140 
attr2str(long attr)141 char *attr2str(long attr)
142 {
143     char *flags = NULL;
144     size_t i;
145     for (i = 0; i < sizeof(attrStr) / sizeof(char *); i++)
146     if (attr & (1 << i))
147         xstrscat(&flags, flags ? " " : "", attrStr[i], NULLP);
148     return flags;
149 }
150 
extattr(const char * line)151 char *extattr(const char *line)
152 {
153     size_t i;
154 
155     for (i=0; i < sizeof(eattr) / sizeof(eattr[0]); i++)
156     if (stricmp(line, eattr[i]) == 0)
157         return eattr[i];
158     return NULL;
159 }
160 
161 /* flag to flavour */
flag2flv(unsigned long attr)162 e_flavour flag2flv(unsigned long attr) {
163   if (attr & 0x100000) return flImmediate;
164   else if ((attr & 0x20000) || (attr & 0x202) == 0x202) return flDirect;
165   else if (attr & 0x200) return flHold;
166   else if (attr & 2) return flCrash;
167   else return flNormal;
168 }
169 
170 /* flavour to flag */
flv2flag(e_flavour flv)171 unsigned long flv2flag(e_flavour flv) {
172   switch (flv) {
173     case flImmediate: return 0x100000;
174     case flDirect:    return 0x20000;
175     case flHold:      return 0x200;
176     case flCrash:     return 2;
177     default:        return 0;
178   }
179 }
180 
181 /* flavour to string */
flv2str(e_flavour flv)182 char* flv2str(e_flavour flv) {
183   switch (flv) {
184     case flImmediate: return "immediate";
185     case flDirect:    return "direct";
186     case flHold:      return "hold";
187     case flCrash:     return "crash";
188     default:        return "normal";
189   }
190 }
191 
192 /* smart string flavour parsing */
str2flv(char * flv)193 e_flavour str2flv(char *flv) {
194   struct flv_data_s { e_flavour f; char c; char *s1; char *s2; };
195   const struct flv_data_s flv_data[] = { { flNormal, 'n', "norm", "normal" },
196                                        { flHold, 'h', "hld", "hold" },
197                                        { flCrash, 'c', "cra", "crash" },
198                                        { flDirect, 'd', "dir", "direct" },
199                                        { flImmediate, 'i', "imm", "immediate" }
200                                      };
201   unsigned char i;
202    for (i = 0; i < sizeof(flv_data)/sizeof(flv_data[0]); i++)
203       if ( ((*flv | 0x20) == flv_data[i].c) && (flv[1] == '\0') ) return flv_data[i].f;
204    for (i = 0; i < sizeof(flv_data)/sizeof(flv_data[0]); i++)
205       if (stricmp(flv, flv_data[i].s1) == 0 ||
206           stricmp(flv, flv_data[i].s2) == 0) return flv_data[i].f;
207    return -1;
208 }
209 
addrComp(const hs_addr a1,const hs_addr a2)210 int  addrComp(const hs_addr a1, const hs_addr a2)
211 {
212    int rc = 0;
213 
214    rc =  a1.zone  != a2.zone;
215    rc += a1.net   != a2.net;
216    rc += a1.node  != a2.node;
217    rc += a1.point != a2.point;
218 
219    return rc;
220 }
221 
aka2str(const hs_addr aka)222 char *aka2str(const hs_addr aka) {
223   static char straka[SIZE_aka2str];
224 
225     if (aka.point) sprintf(straka,"%u:%u/%u.%u",aka.zone,aka.net,aka.node,aka.point);
226     else sprintf(straka,"%u:%u/%u",aka.zone,aka.net,aka.node);
227 
228     return straka;
229 }
230 
231 /* Store 5d-address string into allocalted array (by malloc()).
232  */
aka2str5d(hs_addr aka)233 char *aka2str5d(hs_addr aka) {
234   char *straka=NULL;
235 
236     if (aka.point) {
237       if (aka.domain[0])
238         xscatprintf( &straka, "%u:%u/%u.%u@%s", aka.zone, aka.net, aka.node,
239                                                 aka.point, aka.domain );
240       else
241         xscatprintf( &straka, "%u:%u/%u.%u", aka.zone, aka.net, aka.node,
242                                                 aka.point );
243     }else
244       if (aka.domain[0])
245         xscatprintf( &straka, "%u:%u/%u@%s", aka.zone, aka.net, aka.node,
246                                                 aka.domain );
247       else
248         xscatprintf( &straka, "%u:%u/%u", aka.zone, aka.net, aka.node );
249 
250     return straka;
251 }
252 
freeGroups(char ** grps,int numGroups)253 void freeGroups(char **grps, int numGroups)
254 {
255     unused(numGroups);
256 	nfree (grps);
257 }
258 
copyGroups(char ** grps,int numGroups)259 char **copyGroups(char **grps, int numGroups)
260 {
261 	char **dst;
262 	int  i, len = 0;
263 
264 	if (grps == NULL || numGroups == 0) return NULL;
265 	for (i=0; i<numGroups; i++)
266 		len += sstrlen(grps[i]) + 1;
267 	dst = smalloc(sizeof(char *)*numGroups + len);
268 	dst[0] = (char *)(dst + numGroups);
269 	for (i=0; i<numGroups; i++) {
270 		if (i>0) dst[i] = dst[i-1] + strlen(dst[i-1]) + 1;
271 		sstrcpy(dst[i], grps[i]);
272 	}
273 	return dst;
274 }
275 
276 /*
277  * Sic! All resources are freed including the link structure itself!
278  * Never free it for the second time.
279  * Never use this function on static/automatic structures.
280  */
freeLink(s_link * link)281 void freeLink (s_link *link)
282 {
283 
284   if (link == NULL) return;
285 
286   if (link->handle != link->name) nfree(link->handle);
287   nfree (link->name);
288   if (link->pktPwd != link->defaultPwd)nfree(link->pktPwd);
289   if (link->ticPwd != link->defaultPwd)nfree(link->ticPwd);
290   if (link->areafix.pwd != link->defaultPwd) nfree(link->areafix.pwd);
291   if (link->filefix.pwd != link->defaultPwd) nfree(link->filefix.pwd);
292   if (link->bbsPwd != link->defaultPwd) nfree(link->bbsPwd);
293   if (link->sessionPwd != link->sessionPwd) nfree(link->sessionPwd);
294   nfree(link->email);
295   nfree(link->emailFrom);
296   nfree(link->emailSubj);
297   nfree(link->defaultPwd);
298   nfree(link->pktFile);
299   nfree(link->packFile);
300   nfree(link->floFile);
301   nfree(link->bsyFile);
302   nfree(link->LinkGrp);
303   freeGroups(link->AccessGrp, link->numAccessGrp);
304   freeGroups(link->optGrp, link->numOptGrp);
305   freeGroups(link->areafix.frMask, link->areafix.numFrMask);
306   freeGroups(link->filefix.frMask, link->filefix.numFrMask);
307   freeGroups(link->areafix.dfMask, link->areafix.numDfMask);
308   freeGroups(link->filefix.dfMask, link->filefix.numDfMask);
309   nfree(link->areafix.reportsFlags);
310   nfree(link->filefix.reportsFlags);
311   nfree(link->areafix.fwdFile);
312   nfree(link->filefix.fwdFile);
313   nfree(link->areafix.denyFwdFile);
314   nfree(link->filefix.denyFwdFile);
315   nfree(link->areafix.autoCreateDefaults);
316   nfree(link->filefix.autoCreateDefaults);
317   nfree(link->areafix.autoCreateFile);
318   nfree(link->filefix.autoCreateFile);
319   nfree(link->areafix.name);
320   nfree(link->filefix.name);
321   nfree(link->areafix.baseDir);
322   nfree(link->filefix.baseDir);
323   nfree(link);
324   return;
325 }
326 
makeMsgbFileName(ps_fidoconfig config,char * s)327 char *makeMsgbFileName(ps_fidoconfig config, char *s) {
328     /* allowed symbols: 0..9, a..z, A..Z, ".,!@#$^()~-_{}[]" */
329     static char defstr[]="\"*/:;<=>?\\|%`'&+"; /*  not allowed */
330     char *name=NULL, *str;
331 
332     if (config->notValidFNChars) str = config->notValidFNChars;
333     else str = defstr;
334 
335     while (*s) {
336 	if (strchr(str,*s)) xscatprintf(&name,"%%%x", *s);
337 	else xscatprintf(&name, "%c", *s);
338 	s++;
339     }
340 
341     return name;
342 }
343 
NCreateOutboundFileNameAka(ps_fidoconfig config,s_link * link,e_flavour prio,e_pollType typ,hs_addr * aka)344 int NCreateOutboundFileNameAka(ps_fidoconfig config, s_link *link, e_flavour prio, e_pollType typ, hs_addr *aka)
345 {
346    int fd; /*  bsy file for current link */
347    int nRet = 0;
348    char *name=NULL, *sepDir=NULL, limiter=PATH_DELIM, *tmpPtr;
349    e_bundleFileNameStyle bundleNameStyle = eUndef;
350 
351    if (link->linkBundleNameStyle!=eUndef) bundleNameStyle=link->linkBundleNameStyle;
352    else if (config->bundleNameStyle!=eUndef) bundleNameStyle=config->bundleNameStyle;
353 
354    if (bundleNameStyle != eAmiga) {
355 	   if (aka->point) xscatprintf(&name, "%08x.", aka->point);
356 	   else xscatprintf(&name, "%04x%04x.", aka->net, aka->node);
357    } else {
358 	   xscatprintf(&name, "%u.%u.%u.%u.", aka->zone,
359 				   aka->net, aka->node, aka->point);
360    }
361 
362    if (typ != REQUEST) {
363 	   switch (prio) {
364 	   case flCrash :     xstrcat(&name, "c");
365 		   break;
366 	   case flHold :      xstrcat(&name, "h");
367 		   break;
368 	   case flDirect :    xstrcat(&name, "d");
369 		   break;
370 	   case flImmediate : xstrcat(&name, "i");
371 		   break;
372 	   case flNormal :    xstrcat(&name, (typ==PKT) ? "o" : "f");
373 		   break;
374 	   default :    xstrcat(&name, (typ==PKT) ? "o" : "f");
375 		   break;
376 	   }
377    } else xstrcat(&name, "req");
378 
379    switch (typ) {
380    case PKT :     xstrcat(&name, "ut");
381 	   break;
382    case FLOFILE : xstrcat(&name, "lo");
383 	   break;
384    case REQUEST :
385 	   break;
386    default :
387 	   break;
388    }
389 
390    /*  create floFile */
391    xstrcat(&link->floFile, config->outbound);
392 
393    /*  add suffix for other zones */
394    if (aka->zone != config->addr[0].zone && bundleNameStyle != eAmiga) {
395 	   link->floFile[strlen(link->floFile)-1]='\0';
396 	   xscatprintf(&link->floFile, ".%03x%c", aka->zone, limiter);
397    }
398 
399    if (aka->point && bundleNameStyle != eAmiga)
400 	   xscatprintf(&link->floFile, "%04x%04x.pnt%c",
401 				   aka->net, aka->node, limiter);
402 
403    _createDirectoryTree(link->floFile); /*  create directoryTree if necessary */
404    xstrcat(&link->bsyFile, link->floFile);
405    xstrcat(&link->floFile, name);
406 
407    /*  separate bundles */
408 
409    if (config->separateBundles && (bundleNameStyle!=eAmiga || (bundleNameStyle==eAmiga && link->packerDef==NULL))) {
410 
411        xstrcat(&sepDir, link->bsyFile);
412        if (bundleNameStyle==eAmiga)
413 	   xscatprintf(&sepDir, "%u.%u.%u.%u.sep%c",
414 		       aka->zone, aka->net,
415 		       aka->node ,aka->point, limiter);
416        else if (aka->point) xscatprintf(&sepDir, "%08x.sep%c",
417 						aka->point, limiter);
418        else xscatprintf(&sepDir, "%04x%04x.sep%c", aka->net,
419 			aka->node, limiter);
420 
421        _createDirectoryTree(sepDir);
422        nfree(sepDir);
423    }
424 
425    /*  create bsyFile */
426    if ((tmpPtr=strrchr(name, '.')) != NULL) *tmpPtr = '\0';
427    xstrscat(&link->bsyFile, name, ".bsy", NULLP);
428    nfree(name);
429 
430    /*  maybe we have session with this link? */
431    if ( (fd=open(link->bsyFile, O_CREAT | O_RDWR | O_EXCL, S_IREAD | S_IWRITE)) < 0 ) {
432 #if !defined(__WATCOMC__)
433      int save_errno = errno;
434      if (save_errno != EEXIST) {
435        w_log('7', "cannot create *.bsy file \"%s\" for %s (errno %d)\n", link->bsyFile, aka2str(*aka), (int)save_errno);
436        nRet = -1;
437        errno = save_errno;
438      } else
439 #endif
440      {
441        w_log('7', "link %s is busy.", aka2str(*aka));
442        nfree(link->floFile);
443        nfree(link->bsyFile);
444        nRet = 1;
445      }
446    } else  {
447 #ifdef HAS_getpid
448       FILE *fdd;
449       if((fdd = fdopen(fd,"w+"))) {
450         fprintf(fd,"%u",getpid());
451         fclose(fdd);
452       }
453 #else
454       close(fd);
455 #endif
456       nRet = 0;
457    }
458    return nRet;
459 }
460 
NCreateOutboundFileName(ps_fidoconfig config,s_link * link,e_flavour prio,e_pollType typ)461 int NCreateOutboundFileName(ps_fidoconfig config, s_link *link, e_flavour prio, e_pollType typ)
462 {
463   return NCreateOutboundFileNameAka(config, link, prio, typ, &(link->hisAka));
464 }
465 
needUseFileBoxForLinkAka(ps_fidoconfig config,s_link * link,hs_addr * aka)466 int needUseFileBoxForLinkAka(ps_fidoconfig config, s_link *link, hs_addr *aka)
467 {
468     char limiter=PATH_DELIM;
469     char *bsyFile = NULL;
470     e_bundleFileNameStyle bundleNameStyle = eUndef;
471 
472     /* link->useFileBox means:
473      * 0 - unknown, need to check
474      * 1 - don't use
475      * 2 - use box
476      */
477 
478     if (link->useFileBox == 1) return 0; /*  Don't use */
479     if (link->useFileBox == 2) return 1; /*  Use */
480 
481     /*  link->useFileBox == 0 -> still don't know */
482 
483     if ( (link->fileBox==NULL && config->fileBoxesDir==NULL) ||
484          (theApp.module == M_HTICK  && !link->tickerPackToBox)
485        )
486     {
487         link->useFileBox = 1;
488         return 0;
489     }
490 
491     if (link->fileBoxAlways) {
492 	link->useFileBox = 2;
493 	return 1;
494     }
495 
496     /*  check if can we use outbound */
497     xstrcat(&bsyFile, config->outbound);
498 
499     /*  add suffix for other zones */
500     if (aka->zone != config->addr[0].zone && bundleNameStyle != eAmiga) {
501 	bsyFile[strlen(bsyFile)-1]='\0';
502 	xscatprintf(&bsyFile, ".%03x%c", aka->zone, limiter);
503     }
504 
505     if (aka->point && bundleNameStyle != eAmiga)
506 	xscatprintf(&bsyFile, "%04x%04x.pnt%c",
507 		    aka->net, aka->node, limiter);
508 
509     _createDirectoryTree(bsyFile); /*  create directoryTree if necessary */
510 
511     if (link->linkBundleNameStyle!=eUndef) bundleNameStyle=link->linkBundleNameStyle;
512     else if (config->bundleNameStyle!=eUndef) bundleNameStyle=config->bundleNameStyle;
513 
514     if (bundleNameStyle != eAmiga) {
515 	if (aka->point) xscatprintf(&bsyFile, "%08x", aka->point);
516 	else xscatprintf(&bsyFile, "%04x%04x", aka->net, aka->node);
517     } else {
518 	xscatprintf(&bsyFile, "%u.%u.%u.%u", aka->zone,
519 		    aka->net, aka->node, aka->point);
520     }
521 
522     xstrscat(&bsyFile, ".bsy", NULLP);
523 
524     if (fexist(bsyFile)) {
525 	link->useFileBox = 2;
526     } else {
527 	/*  link is not busy, use outbound */
528 	link->useFileBox = 1;
529     }
530 
531     nfree (bsyFile);
532 
533     return link->useFileBox - 1;
534 }
535 
needUseFileBoxForLink(ps_fidoconfig config,s_link * link)536 int needUseFileBoxForLink(ps_fidoconfig config, s_link *link)
537 {
538   return needUseFileBoxForLinkAka(config, link, &(link->hisAka));
539 }
540 
makeFileBoxNameAka(ps_fidoconfig config,s_link * link,hs_addr * aka)541 char *makeFileBoxNameAka (ps_fidoconfig config, s_link *link, hs_addr *aka)
542 {
543     char *name=NULL;
544 
545     xscatprintf (&name, "%s%d.%d.%d.%d%s%c",
546 		 config->fileBoxesDir,
547 		 aka->zone,
548 		 aka->net,
549 		 aka->node,
550 		 aka->point,
551 		 (link->echoMailFlavour==flHold) ? ".h" : "",
552 		 PATH_DELIM);
553     return name;
554 }
555 
makeFileBoxName(ps_fidoconfig config,s_link * link)556 char *makeFileBoxName (ps_fidoconfig config, s_link *link)
557 {
558   return makeFileBoxNameAka(config, link, &(link->hisAka));
559 }
560 
561 
562 /*  Change file suffix (add if not present).
563     inc = 1 - increment file suffix if new file exists;
564           rename file; return new file name or NULL; set errno
565     inc = 0 - do not increment suffix, do not rename file, return new suffix only
566     if 1st or 2nd parameter is NULL return NULL and set errno to EINVAL
567 */
changeFileSuffix(char * fileName,char * newSuffix,int inc)568 char *changeFileSuffix(char *fileName, char *newSuffix, int inc) {
569 
570     int  i;
571     char buff[3];
572     char *beginOfSuffix;
573     char *newFileName=NULL;
574     size_t  length;
575 
576     if(!(fileName && newSuffix)){
577       w_log( LL_ERR, "changeFileSuffix() illegal call: %s parameter is NULL",
578              fileName? "2nd" : "1st" );
579       errno = EINVAL;
580       return NULL;
581     }
582 
583     beginOfSuffix = strrchr(fileName, '.');
584     if(beginOfSuffix==NULL || beginOfSuffix<strrchr(fileName, '\\') || beginOfSuffix<strrchr(fileName, '/'))
585       beginOfSuffix = fileName+strlen(fileName)+1; /* point char not found in filename, pointed to end of string */
586     else beginOfSuffix++; /* pointed after point in 'name.suf' */
587 
588     length = beginOfSuffix-fileName;      /* length "name." */
589     i=strlen(newSuffix);
590     newFileName = (char *) scalloc( 1, (size_t)(length+i+(i>3?1:4-i)) );
591 
592     strncpy(newFileName, fileName, length);
593     if( length > strlen(newFileName) )
594       strcat(newFileName, ".");
595     strcat(newFileName, newSuffix);
596 
597     if(inc == 0){
598         w_log(LL_DEBUGF, __FILE__ ":%u: old: '%s' new: '%s'",__LINE__, fileName, newFileName);
599         return newFileName;
600     }
601 
602     beginOfSuffix = newFileName+length+1; /*last 2 chars*/
603     for (i=1; fexist(newFileName) && (i<255); i++) {
604 #ifdef HAS_snprintf
605         snprintf(buff, sizeof(buff), "%02x", i);
606 #else
607         sprintf(buff, "%02x", i);
608 #endif
609         strnzcpy(beginOfSuffix, buff, 2);
610     }
611 
612     w_log(LL_DEBUGF, __FILE__ ":%u: old: '%s' new: '%s'",__LINE__, fileName, newFileName);
613     if (!fexist(newFileName)) {
614         if(rename(fileName, newFileName)){ /* -1 = error */
615           w_log(LL_ERR, "Could not rename '%s' to '%s': %s", fileName, newFileName, strerror (errno));
616           nfree(newFileName);
617           return NULL;
618         }
619         return newFileName;
620     } else {
621         w_log(LL_ERR, "Could not change suffix for %s. File is already there and the 255 files after it", fileName);
622         nfree(newFileName);
623         errno = EEXIST;
624         return NULL;
625     }
626 }
627 
628 /* ================================================================
629 
630 Function: makeUniqueDosFileName
631 
632 OVERVIEW:
633 
634 The following function is used to create "unique" 8.3 filenames.  This is
635 a major concern when creating fidonet PKT files.  If you use this
636 function to create PKT filenames, and your node only runs programs that use
637 the same revision of the fidoconfig library, it will be guaranteed that your
638 program will emit unique PKT filenames throughout the whole epoch (!), and
639 in almost all cases you can also be sure that your packets will not have
640 name clashes with packets from other nodes that run fidoconfig programs
641 during a period of about two days.  (Normally, the tosser of your uplink
642 should not have a problem with clashes of pkt filenames from different links
643 anyway, but just in case he uses a brain-dead tosser ...).
644 
645 CALLING:
646 
647 The function takes a directory name as argument (which is prepended to the
648 generated file name, but has no further meaning), an extension (which again
649 is appended to the generated file name, but has no furhter meaning), and a
650 fidoconfig structure.  The fidoconfig structure is used to create a basic
651 offset number that distinguishes your node/point from another node/point.
652 
653 DETAILS:
654 
655 The function guarantees to create
656   - 36 filenames per second (if the average number of filenames created
657     per second over the whole lifetime of the program is greater, the
658     program will be delayed for the appropriate time via an atexit
659     handler). That is, you can poll as many filenames out of the function
660     as you wish, and you will get them quickly when you poll them, the
661     worst case is that if your program ran a very short time it will be
662     delayed before finally exiting.
663   - If the fidoconfig file always has the same primary AKA, and no two
664     programs that use that use the function run at the same time on your
665     system, it will emit unique filenames during the whole epoch (!).
666     That is, a Fidonet editor should NOT use this function (because a
667     editor usually runs parallel to the tosser task), while the tosser,
668     router, ticker, ... may safely use it as those programs usually run
669     serialized.
670   - If the primary AKA in the fidoconfig changes, the file names will
671     change substantially, so that different nodes who both run hpt
672     or other fidoconfig programs will generate substantially different file
673     names.
674   - ATTENTION: This function presently does not check if the file
675     names that it calculates do already exist. If you are afraid of
676     this (because you also use non-fidoconfig programs), you must
677     check it yourself in the application.
678 
679 IMPLEMENTATION NOTES:
680 
681 The alogrithm for creating pkt file names works as follows:
682 
683  - Step 1:  Based on OUR AKA, a static offset number is computed.  This is
684    done so that two systems which both run hpt create somewhat different
685    PKT file name. The offset number is computed as follows:
686 
687       We imagine the node number decomposed in its digits:
688          node  = node1000 * 1000 + node100 * 100 + node10 *10 + node1
689       analoguous for the net number:
690          net   = net1000 * 1000 + net100 * 100 + net10 * 10 + net1
691       and the point number:
692          point = point1000 * 1000 + point100 * 100 + point10 * 10 + point1
693 
694       Then the decimal digits of "offset" are composed as follows:
695 
696       8         7         6        5        4        3        2        1
697   (I) node10    node1     net10    net1     node100  node1000 net100   net1000
698  (II) node10    node1     point10  point1   node100  node1000 net100   net1000
699 
700       where line (I) is used if point!=0, and line (II) is used if point==0.
701 
702       Then the offset number is multiplied by 21 * 36. (This will overflow
703       a 32 bit unsigned integer, so in the code we only multiply by 21 and
704       then do other tricks).
705 
706  - Step 2: If this is the first start, the value of time() is obtained and
707       increased by one. That value is the "base packet number" for the file
708       name about to be created.
709 
710  - Step 3: The base packet number is added to the offset number and printed
711       as a seven digit number in a 36-based number system using the digits
712       0..9 and a..z. (We need all alphanumeric characters to assure all
713       uniquenesses that we guranteed ... hexadezimal characters are not
714       enough for this).
715 
716  - Step 4: The last (eigth') character in the generated file name is
717       a counter to allow for creating more than one filename per second.
718       The initial value of the counter is:
719 
720             (net10 * 10 + net1 + point100) modulo 36
721 
722  - Step 5: The counter is printed as the eight character using characters
723       0..9, and a..z (for counter values from 10 to 35).
724 
725  - Step 6: On subsequent calls of this routine, the counter value is
726       increased by one. If it becomes greater than 35 it is wrapped to zero.
727       If all counter values have been used up (i.e. after incrementing
728       and possibly wrapping the counter value is again the initial value),
729       the base packet number is increased by one.
730 
731   - Step 7: At program exit, the program sleeps until the value of time()
732       is greater or at least equal to the highest base packet number that
733       has been used.
734       (This is done via atexit. If the registering of the atexit program
735       fails, the algorithm above is modified so that every time that
736       the base packet number is increased, the program immediately waits
737       until time() is equal the base packet number. This is slower, but
738       it is a secure fallback in case atexit fails).
739 
740 The result is:
741 
742   - The routine is able to create 36 filenames per second. If more filenames
743     are requested within a single second, calling the routine might delay
744     program execution, but the routine will still produce as many file names
745     as you request.
746 
747   - As long as the AKA that is based for calculating the offset does not
748     change, and of course as long as the system clock is running continously
749     without being turned backwards, the routine will create unique filenames
750     during the whole epoch!
751 
752   - For different nodes that have different AKAs, there will usually be a
753     considerable distance between the filenames created by the one node and
754     those created by another node. Especially, different points of the same
755     node will usually have different file names, and different nodes of the
756     same hubs will usually have very different file names over a period
757     of at least one day, and usually much more. There is no exact guarantee
758     that two different nodes always create different file names within this
759     period, but the chances are high. (Note that any decent tosser should
760     not have any problem with receving arcmail bundles from two different
761     nodes that contain pkt files with the same name; however, Fastecho
762     and probably others do have this problem unless the sysop installs
763     special scripts to circumvent it, and this is why we do the whole shit
764     of sender specific offset numbers ...)
765 
766   - Remark: This code requires sizeof(unsinged long) >= 4. This is true
767     for all known 16, 32 and 64 bit architectures.
768 
769    ================================================================ */
770 
771 static time_t last_reftime_used;
772 static int may_run_ahead;
773 
atexit_wait_handler_function(void)774 static void atexit_wait_handler_function(void)
775 {
776     time_t t;
777 
778     time(&t);
779     while (t < last_reftime_used)
780     {
781 #ifdef HAS_sleep
782         sleep(1);
783 #else
784         mysleep(1);
785 #endif
786         time (&t);
787     }
788 }
789 
makeUniqueDosFileName(const char * dir,const char * ext,s_fidoconfig * config)790 char *makeUniqueDosFileName(const char *dir, const char *ext,
791 			    s_fidoconfig *config)
792 {
793    char                *fileName;
794 
795    static unsigned      counter  = 0x100, refcounter = 0x100;
796    static time_t        refTime  = 0x0;
797    static short         reftime36[7];
798    static volatile int  flag = 0;
799 
800    unsigned             icounter;
801    time_t               tmpt;
802    static char          digits[37]="0123456789abcdefghijklmnopqrstuvwxyz";
803    int                  i, digit;
804    short                offset36[7];
805    unsigned long        node10, node1, digit6, digit5, node100, node1000,
806                         net100, net1000, tempoffset, net10, net1, point100;
807    size_t               pathLen  = strlen(dir);
808 
809    /* make it reentrant */
810    while (flag)
811    {
812 #ifdef HAS_sleep
813         sleep(1);
814 #else
815         mysleep(1);
816 #endif
817    }
818 
819    flag = 1;
820 
821    if ((fileName = malloc(pathLen + 1 + 8 + 1 + strlen(ext) + 1)) == NULL)
822    {                            /* delim file . ext null */
823        flag = 0;
824        return NULL;
825    }
826 
827    memcpy(fileName, dir, pathLen + 1);
828 
829    if (pathLen && fileName[pathLen - 1] != '\\' &&
830                   fileName[pathLen - 1] != '/' &&
831                   fileName[pathLen - 1] != PATH_DELIM)
832    {
833        fileName[pathLen + 1] = '\0';
834        fileName[pathLen] = PATH_DELIM;
835        pathLen++;
836    }
837 
838    if (refTime == 0x0)
839    {
840        time(&refTime);
841        may_run_ahead = !atexit(atexit_wait_handler_function);
842        last_reftime_used = refTime;
843    }
844 
845    /* we make a node specific offset, so that two nodes that both run hpt
846       each generate more or less distinct pkt file names */
847 
848    node10 = (config->addr[0].node % 100) / 10;
849    node1  = (config->addr[0].node % 10);
850    if (config->addr[0].point != 0)
851    {
852        digit6 = (config->addr[0].point % 100) / 10;
853        digit5 = config->addr[0].point % 10;
854    }
855    else
856    {
857        digit6 = (config->addr[0].net % 100) / 10;
858        digit5 = (config->addr[0].net % 10);
859    }
860    node100  = (config->addr[0].node % 1000) / 100;
861    node1000 = (config->addr[0].node % 10000) / 1000;
862    net100   = (config->addr[0].net % 1000) / 100;
863    net1000  = (config->addr[0].net % 10000) / 1000;
864    net10    = (config->addr[0].net % 100) / 10;
865    net1     = config->addr[0].net % 10;
866    point100 = (config->addr[0].point % 1000) / 100;
867 
868 
869    tempoffset = (node10   * 10000000UL +
870                  node1    * 1000000UL  +
871                  digit6   * 100000UL   +
872                  digit5   * 10000UL    +
873                  node100  * 1000UL     +
874                  node1000 * 100UL      +
875                  net100   * 10UL       +
876                  net1000  * 1UL          ) * 21UL;
877 
878    icounter = (unsigned)((net10 * 10U + net1 + point100) % 36U);
879 
880    offset36[0] = 0;  /* this is the multiplication by 36! */
881    for (i = 1; i <= 6; i++)
882    {
883        offset36[i] = (short)(tempoffset % 36);
884        tempoffset = tempoffset / 36;
885    }
886 
887    {
888        if (counter == icounter || icounter != refcounter)
889        {
890 	   counter = refcounter = icounter;
891            last_reftime_used = ++refTime;
892 
893            if (!may_run_ahead)
894            {
895                time (&tmpt);
896 
897                while (tmpt < refTime)
898                {
899 #ifdef HAS_sleep
900                    sleep(1);
901 #else
902                    mysleep(1);
903 #endif
904                    time(&tmpt);
905                }
906            }
907 
908            tmpt = refTime;
909            for (i = 0; i <= 6; i++)
910            {
911                reftime36[i] = (short)(tmpt % 36);
912                tmpt         = tmpt / 36;
913            }
914        }
915 
916        for (i = 0, digit = 0; i < 7; i++)
917        {
918            digit = digit + reftime36[i] + offset36[i];
919            fileName[pathLen + (6 - i)] = digits[digit % 36];
920            digit = digit / 36;
921        }
922 
923        sprintf(fileName + pathLen + 7, "%c.%s", digits[counter], ext);
924        counter = ((counter + 1) % 36);
925 
926    }    /* too slow because of readdir: fexist(fileName) == TRUE */;
927 
928    flag = 0;
929 
930    return fileName;
931 }
932 
SelectPackAka(s_link * link)933 hs_addr *SelectPackAka(s_link *link)
934 {
935  if (link->hisPackAka.zone != 0)
936    return &(link->hisPackAka);
937  else
938    return &(link->hisAka);
939 }
940 
getRobot(ps_fidoconfig config,char * name,int create)941 s_robot *getRobot(ps_fidoconfig config, char *name, int create)
942 {
943   s_robot *r, *def = NULL;
944   unsigned int i;
945 
946   if (sstricmp(name, "default") == 0) name = "*";
947   for (i = 0; i < config->robotCount; i++) {
948     if (sstricmp(config->robot[i]->name, "*") == 0) def = config->robot[i];
949     if (sstricmp(config->robot[i]->name, name) == 0) return config->robot[i];
950   }
951   if (create > 0) {
952     r = (s_robot*)smalloc(sizeof(s_robot));
953     if (!def) {
954       memset(r, 0, sizeof(*r));
955       r->forwardRequestTimeout = 7;
956       r->idlePassthruTimeout   = 4;
957       r->killedRequestTimeout  = 3;
958 	  r->reportsAttr = MSGPRIVATE | MSGKILL | MSGLOCAL;
959 	  r->reportsFlags = sstrdup("NPD");
960     }
961     else {
962       memcpy(r, def, sizeof(*r)); /* this will copy all numeric fields */
963       if (def->names) r->names = copyStrArray(def->names);
964       if (def->fromName) r->fromName = sstrdup(def->fromName);
965       if (def->origin) r->origin = sstrdup(def->origin);
966       if (def->helpFile) r->helpFile = sstrdup(def->helpFile);
967       if (def->rulesDir) r->rulesDir = sstrdup(def->rulesDir);
968       if (def->newAreaRefuseFile) r->newAreaRefuseFile = sstrdup(def->newAreaRefuseFile);
969       if (def->autoCreateFlag) r->autoCreateFlag = sstrdup(def->autoCreateFlag);
970       if (def->queueFile) r->queueFile = sstrdup(def->queueFile);
971       if (def->reportsFlags) r->reportsFlags = sstrdup(def->reportsFlags);
972       if (def->splitStr) r->splitStr = sstrdup(def->splitStr);
973     }
974     r->name = sstrdup(name);
975     config->robot = srealloc(config->robot, sizeof(ps_robot)*(config->robotCount+1));
976     return (config->robot[ config->robotCount++ ] = r);
977   }
978   else if (create < 0) return def;
979   else return NULL;
980 }
981 
remove_kludges(s_message * msg)982 s_message *remove_kludges(s_message *msg)
983 {
984     /*  remove kludges from message text
985         msg->text to reallocated
986     */
987     char *token=NULL, *textBuff = NULL;
988     char *tmp = msg->text;
989 
990     token = strseparate (&tmp,"\n\r");
991 
992     while(token != NULL) {
993         if( !strcmp(token,"---") || !strncmp(token,"--- ",4) )
994             /*  stop on tearline ("---" or "--- text") */
995             break;
996         if( token[0] != '\001' )
997             xstrscat(&textBuff,token,"\r",NULLP);
998         token = strseparate (&tmp,"\n\r");
999     }
1000     nfree(msg->text);
1001     msg->text = textBuff;
1002     return msg;
1003 }
1004