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