1 /* $Id$ */
2 /******************************************************************************
3  * FIDOCONFIG --- library for fidonet configs
4  ******************************************************************************
5  * Copyright (C) 1998-1999
6  *
7  * Matthias Tichy
8  *
9  * Fido:     2:2433/1245 2:2433/1247 2:2432/605.14
10  * Internet: mtt@tichy.de
11  *
12  * Grimmestr. 12         Buchholzer Weg 4
13  * 33098 Paderborn       40472 Duesseldorf
14  * Germany               Germany
15  *
16  * This file is part of FIDOCONFIG.
17  *
18  * This library is free software; you can redistribute it and/or
19  * modify it under the terms of the GNU Library General Public
20  * License as published by the Free Software Foundation; either
21  * version 2 of the License, or (at your option) any later version.
22  *
23  * This library is distributed in the hope that it will be useful,
24  * but WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
26  * Library General Public License for more details.
27  *
28  * You should have received a copy of the GNU Library General Public
29  * License along with this library; see file COPYING. If not, write to the Free
30  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
31  *****************************************************************************/
32 
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <ctype.h>
37 #include <time.h>
38 #include <errno.h>
39 #include <assert.h>
40 #include <stdarg.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <limits.h>
44 #include <huskylib/compiler.h>
45 
46 #ifdef HAS_UNISTD_H
47 #   include <unistd.h>
48 #endif
49 
50 #ifdef HAS_IO_H
51 #   include <io.h>
52 #endif
53 
54 #ifdef HAS_PWD_H
55 #   include <pwd.h>
56 #endif
57 
58 #ifdef HAS_GRP_H
59 #   include <grp.h>
60 #endif
61 
62 #ifdef HAS_SYSEXITS_H
63 #include <sysexits.h>
64 #endif
65 #ifdef HAS_SYS_SYSEXITS_H
66 #include <sys/sysexits.h>
67 #endif
68 
69 #ifdef HAS_SYS_WAIT_H
70 #include <sys/wait.h>
71 #endif
72 
73 #ifdef HAS_PROCESS_H
74 #  include <process.h>
75 #endif
76 
77 #ifdef HAS_STRINGS_H
78 #  include <strings.h>
79 #endif
80 
81 #include <huskylib/huskylib.h>
82 
83 /* export functions from DLL */
84 #define DLLEXPORT
85 #include <huskylib/huskyext.h>
86 
87 /* smapi */
88 #include <smapi/msgapi.h>
89 
90 /* fidoconfig */
91 #include "fidoconf.h"
92 #include "common.h"
93 #include "findtok.h"
94 #include "tokens.h"
95 #include "grptree.h"
96 
97 int fc_trycreate=0; /* Try to create nonexistant directories (defined in line.c) */
98 char *actualKeyword, *actualLine;
99 int  actualLineNr;
100 char wasError = 0;
101 char CommentChar = '#';
102 int _carbonrule = CC_AND;
103 
104 static s_link linkDefined;
105 static ps_robot curRobot = NULL; /* current robot */
106 
fc_copyString(char * str,char ** pmem)107 int fc_copyString(char *str, char **pmem)
108 {
109    if (str==NULL) {
110       printf("Line %d: There is a parameter missing after %s!\n", actualLineNr, actualKeyword);
111       return 1;
112    }
113 
114    return copyString(stripRoundingChars(str, "\""), pmem);
115 }
116 
fc_copyStringWOstrip(char * str,char ** pmem)117 int fc_copyStringWOstrip(char *str, char **pmem)
118 {
119    if (str==NULL) {
120       printf("Line %d: There is a parameter missing after %s!\n", actualLineNr, actualKeyword);
121       return 1;
122    }
123    return copyString(str, pmem);
124 }
125 
126 
127 /*
128    create new address array by copying the old one
129 */
130 
fc_copyAddressArray(unsigned int count,ps_addr sourceAddr,ps_addr * destAddr)131 int fc_copyAddressArray(unsigned int count, ps_addr sourceAddr, ps_addr *destAddr)
132 {
133     int rc = 0;
134 
135     if (count > 0)            /* we have addresses to copy */
136     {
137         *destAddr = malloc(sizeof(hs_addr) * count);
138         if (*destAddr != NULL)
139             memcpy(*destAddr, sourceAddr, sizeof(hs_addr) * count);
140         else
141             rc = 1;               /* error */
142     }
143     else                      /* nothing to do */
144     {
145         *destAddr = NULL;         /* reset pointer */
146     }
147 
148     return rc;
149 }
150 
151 
152 #if 0
153 #define getRestOfLine() stripLeadingChars(strtok(NULL, "\0"), " \t")
154 #else
getRestOfLine(void)155 char *getRestOfLine(void) {
156    return stripLeadingChars(strtok(NULL, "\0"), " \t");
157 }
158 #endif
159 
prErr(char * string,...)160 void prErr ( char *string, ...)
161 {
162     va_list ap;
163 
164     printf("\"%s\", line %d: ", getCurConfName(), actualLineNr);
165     va_start(ap, string);
166     vprintf(string, ap);
167     va_end(ap);
168     putchar('\n');
169 
170 }
171 
getDescription(void)172 char *getDescription(void)
173 {
174   char *descBuf = NULL, *token;
175   int quoted=0, length;
176 
177   while ((token=strtok(NULL," \t"))!=NULL)
178   {
179     xstrscat (&descBuf, token, " ", NULLP);
180     if (*token=='\"' && !quoted)
181     {
182       quoted=1;
183       if (token[1] == '\0') continue;
184     }
185     if (quoted && token[strlen(token)-1]=='\"') break;
186     if (!quoted) break;
187   }
188 
189   if (descBuf == NULL)
190   {
191     prErr( "Error in area description!");
192     return NULL;
193   }
194 
195   descBuf[length=(strlen(descBuf)-1)] = '\0'; /*  remove trailing space */
196   if (quoted)
197   {
198     /*  out. cut '"' */
199     descBuf[--length] = '\0';
200     memmove(descBuf, descBuf+1, length);
201   }
202 
203   return descBuf;
204 }
205 
parseVersion(char * token,s_fidoconfig * config)206 int parseVersion(char *token, s_fidoconfig *config)
207 {
208    char buffer[10], *temp = token;
209    int i = 0;
210 
211    /*  if there is no token return error... */
212    if (token==NULL) {
213       prErr( "There is a version number missing after %s!", actualKeyword);
214       return 1;
215    }
216 
217    while (isdigit(*temp) && i<9) {
218       buffer[i] = *temp;
219       i++; temp++;
220    }
221    buffer[i] = 0;
222 
223    config->cfgVersionMajor = atoi(buffer);
224 
225    temp++; /*  eat . */
226    i = 0;
227 
228    while (isdigit(*temp) && i<9) {
229       buffer[i] = *temp;
230       i++; temp++;
231    }
232    buffer[i] = 0;
233 
234    config->cfgVersionMinor = atoi(buffer);
235 
236    return 0;
237 }
238 
239 #define checkRobot() if (!curRobot) printRobotError();
printRobotError(void)240 void printRobotError(void)
241 {
242   prErr( "Keyword %s must appear inside robot section!", actualKeyword);
243   exit(EX_CONFIG);
244 }
245 
printLinkError(void)246 void printLinkError(void)
247 {
248   prErr( "You must define a link first before you use %s!", actualKeyword);
249   exit(EX_CONFIG);
250 }
251 
printAddrError(void)252 void printAddrError(void)
253 {
254   prErr("The main address must be defined before any areas!");
255   exit(EX_CONFIG);
256 }
257 
getDescrLink(s_fidoconfig * config)258 s_link *getDescrLink(s_fidoconfig *config)
259 {
260    if (config->describeLinkDefaults) { /*  describing defaults for links */
261       return config->linkDefaults;
262    } else {
263       if (config->linkCount) {
264          return config->links[config->linkCount-1];
265       } else {
266          printLinkError();
267          return NULL;
268       }
269    }
270 }
271 
getDescrAnnDef(s_fidoconfig * config)272 ps_anndef getDescrAnnDef(s_fidoconfig *config)
273 {
274     if (config->ADCount) {
275         return &config->AnnDefs[config->ADCount-1];
276     } else {
277         prErr( "You must define a AnnAreaTag first before you use %s!", actualKeyword);
278         exit(EX_CONFIG);
279     }
280     return NULL;
281 }
282 
283 
parseAddress(char * token,s_fidoconfig * config)284 int parseAddress(char *token, s_fidoconfig *config)
285 {
286    char *aka;
287    hs_addr parsedaddr = {0};
288 
289    if (token==NULL) {
290       prErr( "An address after %s is missing!", actualKeyword);
291       return 1;
292    }
293 
294    aka = strtok(token, " \t"); /*  only look at aka */
295    if (aka == NULL) {
296       prErr( "An address after %s is missing!", actualKeyword);
297       return 1;
298    }
299 
300    if (parseFtnAddrZS(aka, &(parsedaddr)) & FTNADDR_ERROR) {
301       prErr( "The address after %s is invalid!", actualKeyword);
302       return 1;
303    }
304 
305    config->addr = srealloc(config->addr, sizeof(hs_addr)*(config->addrCount+1));
306    memcpy(&(config->addr[config->addrCount]), &parsedaddr, sizeof(hs_addr));
307    config->addrCount++;
308 
309    return 0;
310 }
311 
parseRemap(char * token,s_fidoconfig * config)312 int parseRemap(char *token, s_fidoconfig *config)
313 {
314    char *param1, *param2, *param3;
315    int r=0, r2, r3;
316    s_remap remap;
317 
318    if (token==NULL) {
319       prErr( "All parameters after %s are missing!", actualKeyword);
320       return 1;
321    }
322 
323    memset(&remap, 0, sizeof(remap));
324 
325    param1 = strtok(token, ",\t");
326    if (param1 == NULL) {
327       prErr( "Missing Name or * (1st field) after %s!", actualKeyword);
328       return 1;
329    }
330    if (strcmp(param1,"*")==0) {
331       param1=NULL;
332    }
333 
334    param2 = strtok(NULL, ",\t");
335    if (param2 == NULL) {
336       prErr( "Address or * (2nd field) after %s is missing!",actualKeyword);
337       return 1;
338    }
339 
340    param3 = strtok(NULL, " \t");
341    if (param3 == NULL) {
342       prErr( "Address (3rd field) after %s is missing!", actualKeyword);
343       return 1;
344    }
345 
346    if (strcmp(param2,"*")!=0)
347        r2 = parseFtnAddrZS(param2, &(remap.oldaddr));
348    r3 = parseFtnAddrZS(param3, &(remap.newaddr));
349 
350    if ( param1==NULL && remap.oldaddr.zone==0) {
351       prErr( "One of the two first Parameters must not be \"*\"");
352       r = 1;
353    }
354    if (r3 & FTNADDR_ERROR) {
355       prErr( "Invalid address in the 3rd Parameter (\"param3\")");
356       r = 1;
357    }
358    if (r == 0) { /* All OK, allocate memory and store data */
359       if (param1) { /*  Name for rerouting if not "*" */
360          remap.toname=sstrdup(param1);
361       }
362       config->remaps = srealloc(config->remaps,
363                           (config->remapCount+1)*sizeof(s_remap));
364       memcpy(&config->remaps[config->remapCount], &remap, sizeof(remap));
365       config->remapCount++;
366    }
367 
368    return r;
369 }
370 
371 /* Parse and check/create directory
372  *
373  */
parsePath(char * token,char ** var,char ** alreadyDefined)374 int parsePath(char *token, char **var, char **alreadyDefined)
375 {
376 
377    if (*var != NULL) {
378       if (alreadyDefined==NULL || *alreadyDefined) {
379          prErr("Duplicate path!");
380          return 1;
381       }
382       nfree(*var);
383    }
384    if (token == NULL) {
385       prErr("A path after %s is missing!", actualKeyword);
386       return 1;
387    }
388    if (*token && token[strlen(token)-1] == PATH_DELIM)
389 	   Strip_Trailing(token, PATH_DELIM);
390    xscatprintf(var, "%s%c", token, (char) PATH_DELIM);
391    if (alreadyDefined) *alreadyDefined=*var;
392 
393    if (!direxist(*var)) {
394      if (fc_trycreate)
395          if (_createDirectoryTree(*var)) {
396            prErr( "Path %s not found, can't create: %s", *var, strerror(errno));
397            return 1;
398          }else
399          { prErr( "Path %s created succesfully.", *var); }
400      else{
401          prErr( "Path %s not found!", *var);
402          return 1;
403      }
404    }
405    return 0;
406 }
407 
parseAreaPath(char * token,char ** var,char ** alreadyDefined)408 int parseAreaPath(char *token, char **var, char **alreadyDefined)
409 {
410 /*    char *p, *q, *osvar; */
411 
412    if (*var != NULL) {
413       if (alreadyDefined==NULL || *alreadyDefined) {
414          prErr("Duplicate path!");
415          return 1;
416       }
417       nfree(*var);
418    }
419    if (token == NULL) {
420       prErr("A path after %s is missing!", actualKeyword);
421       return 1;
422    }
423    if (stricmp(token, "passthrough")==0) {
424       fc_copyString(token, &(*var));
425       if (alreadyDefined) *alreadyDefined=*var;
426       return 0;
427    }
428    if (*token && token[strlen(token)-1] == PATH_DELIM)
429 	   Strip_Trailing(token, PATH_DELIM);
430    xscatprintf(var, "%s%c", token, (char) PATH_DELIM);
431    if (alreadyDefined) *alreadyDefined=*var;
432 
433    if (!direxist(*var)) {
434      if (fc_trycreate)
435          if (_createDirectoryTree(*var)) {
436            prErr( "Path %s not found, can't create: %s", *var, strerror(errno));
437            return 1;
438          }else
439          { prErr( "Path %s created succesfully.", *var); }
440      else{
441 	   prErr( "Path %s not found!", *var);
442 	   return 1;
443      }
444    }
445    return 0;
446 }
447 
parseAreaPathExpand(char * token,char ** var,char ** alreadyDefined)448 int parseAreaPathExpand(char *token, char **var, char **alreadyDefined)
449 {
450    char *p;
451 
452    if (*var != NULL) {
453       if (alreadyDefined==NULL || *alreadyDefined) {
454          prErr("Duplicate path!");
455          return 1;
456       }
457       nfree(*var);
458    }
459    if (token == NULL) {
460       prErr("A path after %s is missing!", actualKeyword);
461       return 1;
462    }
463    if (stricmp(token, "passthrough")==0) {
464       fc_copyString(token, &(*var));
465       if (alreadyDefined) *alreadyDefined=*var;
466       return 0;
467    }
468    p = vars_expand(sstrdup(token));
469    if (*p == '\0' || p[strlen(p)-1] != PATH_DELIM) {
470        xscatprintf(var, "%s%c", token, (char) PATH_DELIM);
471        xscatprintf(&p, "%c", (char) PATH_DELIM);
472    } else {
473        *var = sstrdup(token);
474    }
475    if (alreadyDefined) *alreadyDefined=*var;
476 
477    if (!direxist(p)) {
478      if (fc_trycreate)
479          if (_createDirectoryTree(p)) {
480            prErr( "Path %s not found, can't create: %s", p, strerror(errno));
481 	   nfree(p);
482            return 1;
483          }else
484          { prErr( "Path %s created succesfully.", p); }
485      else{
486 	   prErr( "Path %s not found!", p);
487 	   nfree(p);
488 	   return 1;
489      }
490    }
491    nfree(p);
492    return 0;
493 }
494 
parsePathNoCheck(char * token,char ** var,char ** alreadyDefined)495 int parsePathNoCheck(char *token, char **var, char **alreadyDefined)
496 {
497    if (*var != NULL) {
498       if (alreadyDefined==NULL || *alreadyDefined) {
499          prErr("Duplicate path!");
500          return 1;
501       }
502       nfree(*var);
503    }
504 
505    if (token == NULL) {
506       prErr("A path after %s is missing!", actualKeyword);
507       return 1;
508    }
509 
510    if (*token && token[strlen(token)-1] == PATH_DELIM)
511 	   Strip_Trailing(token, PATH_DELIM);
512    xscatprintf(var, "%s%c", token, (char) PATH_DELIM);
513    if (alreadyDefined) *alreadyDefined=*var;
514 
515    return 0;
516 }
517 
parsePublic(char * token,s_fidoconfig * config)518 int parsePublic(char *token, s_fidoconfig *config)
519 {
520    if (token == NULL) {
521       prErr( "A path after %s is missing!", actualKeyword);
522       return 1;
523    }
524    config->publicDir = srealloc(config->publicDir, sizeof(char *)*(config->publicCount+1));
525    config->publicDir[config->publicCount] = NULL;
526 
527    if (*token && token[strlen(token)-1] == PATH_DELIM)
528        Strip_Trailing(token, PATH_DELIM);
529    xscatprintf(&(config->publicDir[config->publicCount]), "%s%c", token, (char) PATH_DELIM);
530 
531    if (!direxist(config->publicDir[config->publicCount])) {
532      if (fc_trycreate)
533          if (_createDirectoryTree(token)) {
534            prErr( "Path %s not found, can't create: %s", token, strerror(errno));
535            return 1;
536          }else
537          { prErr( "Path %s created succesfully.", token); }
538      else{
539          prErr( "Path %s not found!", token);
540          return 1;
541      }
542    }
543 
544    config->publicCount++;
545    return 0;
546 }
547 
parseOwner(char * token,unsigned int * uid,unsigned int * gid)548 int parseOwner(char *token, unsigned int *uid, unsigned int *gid)
549 {
550 #ifdef __UNIX__
551    struct passwd *pw;
552    struct group *grp;
553    char *name, *group, *p;
554 
555    if (token == NULL) {
556       prErr( "There are parameters missing after %s!", actualKeyword);
557       return 1;
558    }
559 
560    p = strchr(token, '.');
561    if (p) {
562      *p = '\0';
563      name = token; group = p + 1;
564    } else {
565      name = token; group = NULL;
566    };
567 
568    if (name != NULL) {
569 	pw  = getpwnam(name);
570 
571   	if (*name && pw == NULL) {
572 		prErr( "User name %s is unknown to OS !", name);
573 		return 1;
574 	}
575 	*uid = pw ? pw->pw_uid : (unsigned int)-1;
576 
577    };
578 
579    if (group != NULL) {
580 	grp = getgrnam(group);
581 
582 	if ((*group) && grp == NULL) {
583 		prErr( "Group name %s is unknown to OS !", group);
584 		return 1;
585 	}
586 	*gid = grp ? grp->gr_gid : (unsigned int)-1;
587    }
588 #else
589    unused(token); unused(uid); unused(gid);
590 #endif
591    return 0;
592 }
593 
parseNumber(char * token,int radix,unsigned * level)594 int parseNumber(char *token, int radix, unsigned *level) {
595     char *end = NULL;
596     unsigned long result;
597 
598     if (token == NULL) {
599     prErr("Parameter after %s is missing!", actualKeyword);
600 	return 1;
601     }
602 
603     result = strtoul(token, &end, radix);
604 
605     if (!(*end == '\0' && *token != '\0') || result == unsigned_long_max) {
606 	prErr("Error in number representation : %s . %s!", token, end);
607 	return 1;
608     }
609 
610     *level = (unsigned) result;
611     return 0;
612 }
613 
parseSeenBy2D(char * token,hs_addr ** addr,unsigned int * count)614 int parseSeenBy2D(char *token, hs_addr **addr, unsigned int *count)
615 {
616 	const char *next;
617 	unsigned int maxcount = *count;
618 
619 	if (token==NULL) {
620 		prErr("An address after %s is missing!", actualKeyword);
621 		return 1;
622 	}
623 
624 	while (*token) {
625 		while(!isdigit(*token)) token++;
626 
627 		if(*count >= maxcount) /* realloc once per 10 iteration */
628 		{
629 			maxcount = *count+10;
630 			(*addr) = srealloc(*addr, sizeof(hs_addr)*maxcount);
631 			memset(*addr+*count, 0, sizeof(hs_addr)*10);
632 		}
633 
634 		if(parseFtnAddrZ(token, &(*addr)[*count], FTNADDR_2D, &next) & FTNADDR_ERROR)
635 			return 1;
636 
637 		token = (char*)next;
638 
639 		(*count)++;
640 
641 		if (*token == ')') break;
642 	}
643 	if(maxcount > *count)
644 		(*addr) = srealloc(*addr, sizeof(hs_addr)*(*count));
645 	return 0;
646 }
647 
getLinkRescanAccess(s_area * area,s_link * link)648 int getLinkRescanAccess(s_area *area, s_link *link)
649 {
650     int rescan = 0;
651 
652     if (area->msgbType != MSGTYPE_PASSTHROUGH) {
653         if (link->numRescanGrp > 0) {
654             rescan = link->denyRescan;
655             if (grpInArray(area->group,link->RescanGrp,link->numRescanGrp))
656                 rescan = (!link->denyRescan);
657         } else
658             rescan = (!link->denyRescan);
659     }
660 
661     return rescan;
662 }
663 
setLinkAccess(s_fidoconfig * config,s_area * area,s_arealink * arealink)664 void setLinkAccess(s_fidoconfig *config, s_area *area, s_arealink *arealink)
665 {
666     s_link *link=arealink->link;
667 
668     if (link->numOptGrp > 0) {
669         /*  default set export on, import on, mandatory off, manual off */
670         arealink->aexport = 1;
671         arealink->import = 1;
672         arealink->mandatory = 0;
673         arealink->manual = 0;
674 
675         if (grpInArray(area->group,link->optGrp,link->numOptGrp)) {
676             arealink->aexport = link->aexport;
677             arealink->import = link->import;
678             arealink->mandatory = link->mandatory;
679             arealink->manual = link->manual;
680         }
681 
682     } else {
683         arealink->aexport = link->aexport;
684         arealink->import = link->import;
685         arealink->mandatory = link->mandatory;
686         arealink->manual = link->manual;
687     }
688 
689     arealink->rescan = getLinkRescanAccess(area, link);
690 
691     if (area->mandatory) arealink->mandatory = 1;
692     if (area->manual) arealink->manual = 1;
693     if ((area->levelread > link->level) || ((link->Pause & area->areaType) && (!area->noPause))) arealink->aexport = 0;
694     if (area->levelwrite > link->level) arealink->import = 0;
695 
696     if (area->group) {
697         if (link->numAccessGrp) {
698             if (config->numPublicGroup) {
699                 if (!grpInArray(area->group,link->AccessGrp,link->numAccessGrp) &&
700                     !grpInArray(area->group,config->PublicGroup,config->numPublicGroup)) {
701                     arealink->aexport = 0;
702                     arealink->import = 0;
703                 }
704             } else if (!grpInArray(area->group,link->AccessGrp,link->numAccessGrp)) {
705                 arealink->aexport = 0;
706                 arealink->import = 0;
707             }
708         } else if (config->numPublicGroup) {
709             if (!grpInArray(area->group,config->PublicGroup,config->numPublicGroup)) {
710                 arealink->aexport = 0;
711                 arealink->import = 0;
712             }
713         }
714     }
715 
716 }
717 
718 
parseAreaOption(s_fidoconfig * config,char * option,s_area * area)719 int parseAreaOption( s_fidoconfig *config, char *option, s_area *area)
720 {
721     char *error;
722     char *token;
723     char *iOption;
724     char *iToken;
725     size_t i;
726     long il;
727 
728     if (option == NULL) {
729         prErr("There are parameters missing after %s!", actualKeyword);
730         return 1;
731     }
732 
733     iOption = strLower(sstrdup(option));
734     if (strcmp(iOption, "b")==0) {
735         if( area->areaType == ECHOAREA ) {
736             token = strtok(NULL, " \t");
737             if (token == NULL) {
738                 prErr("An msgbase type is missing after -b in areaOptions!");
739                 nfree(iOption);
740                 return 1;
741             }
742             if ( area->msgbType == MSGTYPE_PASSTHROUGH ) {
743                 /*  MsgBase type is already defined */
744                 nfree(iOption);
745                 return 0;
746             }
747 
748 			iToken = strLower(sstrdup(token));
749             if (strcasecmp(iToken, "squish")==0) {
750                 area->msgbType = MSGTYPE_SQUISH;
751             }
752             else if (strcasecmp(iToken, "jam")==0) {
753                 area->msgbType = MSGTYPE_JAM;
754             }
755             else if (strcasecmp(iToken, "msg")==0) {
756                 area->msgbType = MSGTYPE_SDM;
757             }
758             else
759             {
760                 prErr("MsgBase type %s not valid after -b in areaOptions!", token);
761                 nfree(iOption);
762                 nfree(iToken);
763                 return 1;
764             }
765 			nfree(iToken);
766 			iToken = NULL;
767         } else {
768             prErr("Option '-b' is allowed for echoareas and localareas only!");
769             nfree(iOption);
770             return 1;     /*  error */
771         }
772     }
773     else if (strcasecmp(iOption, "pass")==0) {
774         area->msgbType = MSGTYPE_PASSTHROUGH;
775     }
776     else if (strcmp(iOption, "p")==0) {
777         token = strtok(NULL, " \t");
778         if (token == NULL) {
779             prErr("A number after -p in areaOptions is missing!");
780             nfree(iOption);
781             return 1;
782         }
783         area->nopack = 0;
784         il = strtol(token, &error, 0);
785         if ((error != NULL) && (*error != '\0')) {
786             prErr("The number after -p in areaOptions is wrong!");
787             nfree(iOption);
788             return 1;     /*  error occured; */
789         }
790         if(area->areaType == ECHOAREA) {
791             area->purge = il<0? config->EchoAreaDefault.purge : (unsigned) il ;
792         }
793         else if(area->areaType == FILEAREA) {
794             area->purge = il<0? config->FileAreaDefault.purge : (unsigned) il ;
795         }
796     }
797     else if (strcmp(iOption, "$m")==0) {
798         if( area->areaType == ECHOAREA ) {
799             token = strtok(NULL, " \t");
800             if (token == NULL) {
801                 prErr("A number after -$m in areaOptions is missing!");
802                 nfree(iOption);
803                 return 1;
804             }
805             area->nopack = 0;
806             il = strtol(token, &error, 0);
807             if ((error != NULL) && (*error != '\0')) {
808                 prErr("The number after -$m in areaOptions is wrong!");
809                 nfree(iOption);
810                 return 1;     /*  error */
811             }
812             area->max = il<0? config->EchoAreaDefault.max : (unsigned) il ;
813         }else{
814             prErr("Option '-$m' is allowed for echoareas and localareas only!");
815             nfree(iOption);
816             return 1;     /*  error */
817         }
818     }
819     else if (strcmp(iOption, "a")==0) {
820         token = strtok(NULL, " \t");
821         if (token == NULL)
822         {
823             prErr("Address after -a in areaOptions is missing!");
824             nfree(iOption);
825             return 1;
826         }
827         area->useAka = getAddr(config, token);
828         if (area->useAka == NULL) {
829             prErr("%s not found as address.", token);
830             nfree(iOption);
831             return 1;
832         }
833     }
834     else if (strcmp(iOption, "lr")==0) {
835         token = strtok(NULL, " \t");
836         if (token == NULL) {
837             prErr("A number after -lr in areaOptions is missing!");
838             nfree(iOption);
839             return 1;
840         }
841         for (i=0; i<strlen(token); i++) {
842             if (isdigit(token[i]) == 0) break;
843         }
844         if (i != strlen(token)) {
845             prErr("The number after -lr in areaOptions is wrong!");
846             nfree(iOption);
847             return 1;
848         }
849         il = strtol(token, &error, 0);
850         if ((error != NULL) && (*error != '\0')) {
851             prErr("The number after -lr in areaOptions is wrong!");
852             nfree(iOption);
853             return 1;     /*  error occured; */
854         }
855         if (il<0) {
856             prErr("The number after -lr in areaOptions is wrong (negative values not alloved)!");
857             nfree(iOption);
858             return 1;     /*  error occured; */
859         }
860         area->levelread = (unsigned) il ;
861 
862         /* if link was added before -lr setting it must be updated */
863         for(i=0;i<area->downlinkCount;++i)
864             setLinkAccess( config, area, area->downlinks[i]);
865 
866     }
867     else if (strcmp(iOption, "lw")==0) {
868         token = strtok(NULL, " \t");
869         if (token == NULL) {
870             prErr("A number after -lw in areaOptions is missing!");
871             nfree(iOption);
872             return 1;
873         }
874         for (i=0; i<strlen(token); i++) {
875             if (isdigit(token[i]) == 0) break;
876         }
877         if (i != strlen(token)) {
878             prErr("The number after -lw in areaOptions is wrong!");
879             nfree(iOption);
880             return 1;
881         }
882         il = strtol(token, &error, 0);
883         if ((error != NULL) && (*error != '\0')) {
884             prErr("The number after -lw in areaOptions is wrong!");
885             nfree(iOption);
886             return 1;     /*  error occured; */
887         }
888         if (il<0) {
889             prErr("The number after -lw in areaOptions is wrong (negative values not alloved)!");
890             nfree(iOption);
891             return 1;     /*  error occured; */
892         }
893         area->levelwrite = (unsigned) il ;
894         /* if link was added before -lw setting it must be updated */
895         for(i=0;i<area->downlinkCount;++i)
896             setLinkAccess( config, area, area->downlinks[i]);
897 
898     }
899     else if (strcmp(iOption, "tooold")==0) {
900         if( area->areaType == ECHOAREA ) {
901             token = strtok(NULL, " \t");
902             if (token == NULL) {
903                 prErr("A number after %s in areaOptions is missing!",iOption);
904                 nfree(iOption);
905                 return 1;
906             }
907             for (i=0; i<strlen(token); i++) {
908                 if (isdigit(token[i]) == 0) break;
909             }
910             if (i != strlen(token)) {
911                 prErr("The number after %s in areaOptions is wrong!",iOption);
912                 nfree(iOption);
913                 return 1;
914             }
915             il = strtol(token, &error, 0);
916             if ((error != NULL) && (*error != '\0')) {
917                 prErr("The number after %s in areaOptions is wrong!",iOption);
918                 nfree(iOption);
919                 return 1;     /*  error occured; */
920             }
921             if (il<0) {
922                 prErr("The number after %s in areaOptions is wrong (negative values not allowed)!",iOption);
923                 nfree(iOption);
924                 return 1;     /*  error occured; */
925             }
926             area->tooOld = (unsigned) il ;
927         }else{
928             prErr("Option '%s' is allowed for echoareas only!",iOption);
929             nfree(iOption);
930             return 1;     /*  error */
931         }
932     }
933     else if (strcmp(iOption, "toonew")==0) {
934         if( area->areaType == ECHOAREA ) {
935             token = strtok(NULL, " \t");
936             if (token == NULL) {
937                 prErr("A number after %s in areaOptions is missing!",iOption);
938                 nfree(iOption);
939                 return 1;
940             }
941             for (i=0; i<strlen(token); i++) {
942                 if (isdigit(token[i]) == 0) break;
943             }
944             if (i != strlen(token)) {
945                 prErr("The number after %s in areaOptions is wrong!",iOption);
946                 nfree(iOption);
947                 return 1;
948             }
949             il = strtol(token, &error, 0);
950             if ((error != NULL) && (*error != '\0')) {
951                 prErr("The number after %s in areaOptions is wrong!",iOption);
952                 nfree(iOption);
953                 return 1;     /*  error occured; */
954             }
955             if (il<0) {
956                 prErr("The number after %s in areaOptions is wrong (negative values not allowed)!",iOption);
957                 nfree(iOption);
958                 return 1;     /*  error occured; */
959             }
960             area->tooNew = (unsigned) il ;
961         }else{
962             prErr("Option '%s' is allowed for echoareas only!",iOption);
963             nfree(iOption);
964             return 1;     /*  error */
965         }
966     }
967     else if (strcmp(iOption, "tinysb")==0) {
968 
969         if( area->areaType == ECHOAREA )  {
970             area->tinySB = 1;
971         } else {
972             prErr("Option '-tinysb' is allowed for echoareas only!");
973             nfree(iOption);
974             return 1;     /*  error */
975         }
976     }
977     else if (strcmp(iOption, "notinysb")==0) {
978         if( area->areaType == ECHOAREA ) {
979             area->tinySB = 0;
980         }else{
981             prErr("Option '-notinysb' is allowed for echoareas only!");
982             nfree(iOption);
983             return 1;     /*  error */
984         }
985     }
986     else if (strcmp(iOption, "killsb")==0) {
987         if( area->areaType == ECHOAREA ) {
988             area->killSB = 1;
989         }else{
990             prErr("Option '-killsb' is allowed for echoareas only!");
991             nfree(iOption);
992             return 1;     /*  error */
993         }
994     }
995     else if (strcmp(iOption, "nokillsb")==0) {
996         if( area->areaType == ECHOAREA ) {
997             area->killSB = 0;
998         }else{
999             prErr("Option '-nokillsb' is allowed for echoareas only!");
1000             nfree(iOption);
1001             return 1;     /*  error */
1002         }
1003     }
1004     else if (strcmp(iOption, "keepunread")==0) {
1005         if( area->areaType == ECHOAREA ) {
1006             area->keepUnread = 1;
1007         }else{
1008             prErr("Option '-keepunread' is allowed for echoareas and localareas only!");
1009             nfree(iOption);
1010             return 1;     /*  error */
1011         }
1012     }
1013     else if (strcmp(iOption, "nokeepunread")==0) {
1014         if( area->areaType == ECHOAREA ) {
1015             area->keepUnread = 0;
1016         }else{
1017             prErr("Option '-nokeepunread' is allowed for echoareas and localareas only!");
1018             nfree(iOption);
1019             return 1;     /*  error */
1020         }
1021     }
1022     else if (strcmp(iOption, "killread")==0) {
1023         if( area->areaType == ECHOAREA ) {
1024             area->killRead = 1;
1025         }else{
1026             prErr("Option '%s' is allowed for echoareas and localareas only!",iOption);
1027             nfree(iOption);
1028             return 1;     /*  error */
1029         }
1030     }
1031     else if (strcmp(iOption, "nokillread")==0) {
1032         if( area->areaType == ECHOAREA ) {
1033             area->killRead = 0;
1034         }else{
1035             prErr("Option '%s' is allowed for echoareas and localareas only!",iOption);
1036             nfree(iOption);
1037             return 1;     /*  error */
1038         }
1039     }
1040 
1041     else if (strcmp(iOption, "h")==0) area->hide = 1;
1042     else if (strcmp(iOption, "hide")==0) area->hide = 1;
1043     else if (strcmp(iOption, "nohide")==0) area->hide = 0;
1044     else if (strcmp(iOption, "k")==0) area->killMsgBase = 1;
1045     else if (strcmp(iOption, "kill")==0) area->killMsgBase = 1;
1046     else if (strcmp(iOption, "nokill")==0) area->killMsgBase = 0;
1047     else if (strcmp(iOption, "manual")==0) area->manual = 1;
1048     else if (strcmp(iOption, "nomanual")==0) area->manual = 0;
1049     else if (strcmp(iOption, "nopause")==0) area->noPause = 1;
1050     else if (strcmp(iOption, "pause")==0) area->noPause = 0;
1051     else if (strcmp(iOption, "nolink")==0) area->nolink = 1;
1052     else if (strcmp(iOption, "link")==0) area->nolink = 0;
1053     else if (strcmp(iOption, "mandatory")==0) area->mandatory = 1;
1054     else if (strcmp(iOption, "nomandatory")==0) area->mandatory = 0;
1055     else if (strcmp(iOption, "debug")==0) area->debug = 1;
1056     else if (strcmp(iOption, "nodebug")==0) area->debug = 0;
1057     else if (strcmp(iOption, "dosfile")==0) {
1058         if( area->areaType == ECHOAREA ) {
1059             area->DOSFile = 1;
1060         }else{
1061             prErr("Option '%s' is allowed for echoareas and localareas only!",iOption);
1062             nfree(iOption);
1063             return 1;     /*  error */
1064         }
1065     }
1066     else if (strcmp(iOption, "nodosfile")==0) {
1067         if( area->areaType == ECHOAREA ) {
1068             area->DOSFile = 0;
1069         }else{
1070             prErr("Option '%s' is allowed for echoareas and localareas only!",iOption);
1071             nfree(iOption);
1072             return 1;     /*  error */
1073         }
1074     }
1075     else if (strcmp(iOption, "paused")==0) area->paused = 1;
1076     else if (strcmp(iOption, "noautoareapause")==0) area->noautoareapause = 1;
1077     else if (strcmp(iOption, "autoareapause")==0) area->noautoareapause = 0;
1078     else if (strcmp(iOption, "nopack")==0) area->nopack = 1;
1079     else if (strcmp(iOption, "pack")==0) area->nopack = 0;
1080     else if (strcmp(iOption, "ccoff")==0) {
1081         if( area->areaType == ECHOAREA ) {
1082             area->ccoff=1;
1083         }else{
1084             prErr("Option '%s' is allowed for echoareas and localareas only!",iOption);
1085             nfree(iOption);
1086             return 1;     /*  error */
1087         }
1088     }
1089     else if (strcmp(iOption, "noccoff")==0) {
1090         if( area->areaType == ECHOAREA ) {
1091             area->ccoff=0;
1092         }else{
1093             prErr("Option '%s' is allowed for echoareas and localareas only!",iOption);
1094             nfree(iOption);
1095             return 1;     /*  error */
1096         }
1097     }
1098     else if (strcmp(iOption, "ccon")==0) {
1099         if( area->areaType == ECHOAREA ) {
1100             area->ccoff=0;
1101         }else{
1102             prErr("Option '%s' is allowed for echoareas and localareas only!",iOption);
1103             nfree(iOption);
1104             return 1;     /*  error */
1105         }
1106     }
1107     else if (strcmp(iOption, "keepsb")==0) {
1108         if( area->areaType == ECHOAREA ) {
1109             area->keepsb=1;
1110         }else{
1111             prErr("Option '%s' is allowed for echoareas and localareas only!",iOption);
1112             nfree(iOption);
1113             return 1;     /*  error */
1114         }
1115     }
1116     else if (strcmp(iOption, "nokeepsb")==0) {
1117         if( area->areaType == ECHOAREA ) {
1118             area->keepsb=0;
1119         }else{
1120             prErr("Option '%s' is allowed for echoareas and localareas only!",iOption);
1121             nfree(iOption);
1122             return 1;     /*  error */
1123         }
1124     }
1125     else if (strcmp(iOption, "sendorig")==0) {
1126         if( area->areaType == FILEAREA ) {
1127             area->sendorig = 1;
1128         }else{
1129             prErr("Option '%s' is allowed for fileareas only!",iOption);
1130             nfree(iOption);
1131                         return 1;     /*  error */
1132                     }
1133     }
1134     else if (strcmp(iOption, "nosendorig")==0) {
1135                         if( area->areaType == FILEAREA ) {
1136                             area->sendorig = 0;
1137                         }else{
1138                             prErr("Option '%s' is allowed for fileareas only!",iOption);
1139                             nfree(iOption);
1140                             return 1;     /*  error */
1141                         }
1142     }
1143     else if (strcmp(iOption, "crc")==0) {
1144                             if( area->areaType == FILEAREA ) {
1145                                 area->noCRC = 0;
1146                             }else{
1147                                 prErr("Option '%s' is allowed for fileareas only!",iOption);
1148                                 nfree(iOption);
1149                                 return 1;     /*  error */
1150                             }
1151     }
1152     else if (strcmp(iOption, "nocrc")==0) {
1153         if( area->areaType == FILEAREA ) {
1154             area->noCRC = 1;
1155         }else{
1156             prErr("Option '%s' is allowed for fileareas only!",iOption);
1157             nfree(iOption);
1158             return 1;     /*  error */
1159         }
1160     }
1161     else if (strcmp(iOption, "replace")==0) {
1162         if( area->areaType == FILEAREA ) {
1163             area->noreplace = 0;
1164         }else{
1165             prErr("Option '%s' is allowed for fileareas only!",iOption);
1166             nfree(iOption);
1167             return 1;     /*  error */
1168         }
1169     }
1170     else if (strcmp(iOption, "noreplace")==0) {
1171         if( area->areaType == FILEAREA ) {
1172             area->noreplace = 1;
1173         }else{
1174             prErr("Option '%s' is allowed for fileareas only!",iOption);
1175             nfree(iOption);
1176             return 1;     /*  error */
1177         }
1178     }
1179     else if (strcmp(iOption, "rename")==0) {
1180         if( area->areaType == FILEAREA ) {
1181             area->rename = 1;
1182         }else{
1183             prErr("Option '%s' is allowed for fileareas only!",iOption);
1184             nfree(iOption);
1185             return 1;     /*  error */
1186         }
1187     }
1188     else if (strcmp(iOption, "norename")==0) {
1189         if( area->areaType == FILEAREA ) {
1190             area->rename = 0;
1191         }else{
1192             prErr("Option '%s' is allowed for fileareas only!",iOption);
1193             nfree(iOption);
1194             return 1;     /*  error */
1195         }
1196     }
1197     else if (strcmp(iOption, "sbkeepall")==0) {
1198         if( area->areaType == ECHOAREA ) {
1199             area->sbkeep_all = 1;
1200         }else{
1201             prErr("Option '%s' is allowed for echoareas only!",iOption);
1202             nfree(iOption);
1203             return 1;     /*  error */
1204         }
1205     }
1206     else if (strcmp(iOption, "nosbkeepall")==0) {
1207         if( area->areaType == ECHOAREA ) {
1208             area->sbkeep_all = 0;
1209         }else{
1210             prErr("Option '%s' is allowed for echoareas only!",iOption);
1211             nfree(iOption);
1212             return 1;     /*  error */
1213         }
1214     }
1215     else if (strcmp(iOption, "diz")==0) {
1216         if( area->areaType == FILEAREA ) {
1217             area->nodiz = 0;
1218         }else{
1219             prErr("Option '%s' is allowed for fileareas only!",iOption);
1220             nfree(iOption);
1221             return 1;     /*  error */
1222         }
1223     }
1224     else if (strcmp(iOption, "nodiz")==0) {
1225         if( area->areaType == FILEAREA ) {
1226             area->nodiz = 1;
1227         }else{
1228             prErr("Option '%s' is allowed for fileareas only!",iOption);
1229             nfree(iOption);
1230             return 1;     /*  error */
1231         }
1232     }
1233     else if (strcmp(iOption, "dupecheck")==0) {
1234         token = strtok(NULL, " \t");
1235         if (token == NULL) {
1236             prErr("Missing dupeCheck parameter!");
1237             nfree(iOption);
1238             return 1;
1239         }
1240         if (stricmp(token, "off")==0) area->dupeCheck = dcOff;
1241         else if (stricmp(token, "move")==0) area->dupeCheck = dcMove;
1242         else if (stricmp(token, "del")==0) area->dupeCheck = dcDel;
1243         else {
1244             prErr("Wrong dupeCheck parameter!");
1245             nfree(iOption);
1246             return 1; /*  error */
1247         }
1248     }
1249     else if (strcmp(iOption, "dupehistory")==0) {
1250         token = strtok(NULL, " \t");
1251         if (token == NULL) {
1252             prErr("Number is missing after -dupehistory in areaOptions!");
1253             nfree(iOption);
1254             return 1;
1255         }
1256         area->dupeHistory = (unsigned) strtol(token, &error, 0);
1257         if ((error != NULL) && (*error != '\0')) {
1258             prErr("Number is wrong after -dupeHistory in areaOptions!");
1259             nfree(iOption);
1260             return 1;     /*  error occured; */
1261         }
1262     }
1263     /* val: -scan listed|manual|never */
1264     else if (strcmp(iOption, "scan")==0) {
1265         if (area->areaType != ECHOAREA) {
1266             prErr("Option '%s' is allowed for echoareas and localareas only!", iOption);
1267             nfree(iOption);
1268             return 1;     /*  error */
1269         }
1270         token = strtok(NULL, " \t");
1271         if (token == NULL) {
1272             prErr("Scan parameter is missing!");
1273             nfree(iOption);
1274             return 1;
1275         }
1276         if (stricmp(token, "never")==0) area->scanMode = smNever;
1277         else if (stricmp(token, "manual")==0) area->scanMode = smManual;
1278         else if (stricmp(token, "listed")==0) area->scanMode = smListed;
1279         else {
1280             prErr("Wrong scan parameter!");
1281             nfree(iOption);
1282             return 1; /* error */
1283         }
1284     }
1285     /* /val */
1286     else if (strcmp(iOption, "g")==0) {
1287         token = strtok(NULL, " \t");
1288         if (token == NULL) {
1289             nfree(iOption);
1290             return 1;
1291         }
1292         /* dmitry: this overrides group in EchoAreaDefaults */
1293         nfree(area->group);
1294         area->group = sstrdup(token);
1295     }
1296     else if (strcmp(iOption, "$")==0) ;
1297     else if (strcmp(iOption, "0")==0) ;
1298     else if (strcmp(iOption, "d")==0) {
1299         if ((area->description=getDescription())==NULL) {
1300             nfree(iOption);
1301             return 1;
1302         }
1303     }
1304     else if (strncmp(iOption, "sbadd(", 6)==0) {
1305         if( area->areaType == ECHOAREA ) {
1306             parseSeenBy2D(iOption,&(area->sbadd),&(area->sbaddCount));
1307         } else {
1308             prErr("Option '%s' is allowed for echoareas only!",iOption);
1309             nfree(iOption);
1310             return 1;     /*  error */
1311         }
1312     }
1313     else if (strncmp(iOption, "sbign(", 6)==0) {
1314         if( area->areaType == ECHOAREA ) {
1315             parseSeenBy2D(iOption,&(area->sbign),&(area->sbignCount));
1316         } else {
1317             prErr("Option '%s' is allowed for echoareas only!",iOption);
1318             nfree(iOption);
1319             return 1;     /*  error */
1320         }
1321     }
1322     else if (strncmp(iOption, "sbstrip(", 8)==0) {
1323         if( area->areaType == ECHOAREA ) {
1324             parseSeenBy2D(iOption,&(area->sbstrip),&(area->sbstripCount));
1325         } else {
1326             prErr("Option '%s' is allowed for echoareas only!",iOption);
1327             nfree(iOption);
1328             return 1;     /*  error */
1329         }
1330     }
1331     else if (strncmp(iOption, "sbkeep(", 7)==0) {
1332         if( area->areaType == ECHOAREA ) {
1333             parseSeenBy2D(iOption,&(area->sbkeep),&(area->sbkeepCount));
1334         }else{
1335             prErr("Option '%s' is allowed for echoareas only!",iOption);
1336             nfree(iOption);
1337             return 1;     /*  error */
1338         }
1339     }
1340     else if (strcmp(iOption, "r")==0) {
1341         if (area->def_subscribing!=RW) {
1342             prErr("Can't mix area options \"-r\" and \"-w\"!");
1343             nfree(iOption);
1344             return 1;
1345         }
1346         area->def_subscribing = RO;
1347     }
1348     else if (strcmp(iOption, "w")==0) {
1349         if (area->def_subscribing!=RW) {
1350             prErr("Can't mix area options \"-r\" and \"-w\"!");
1351             nfree(iOption);
1352             return 1;
1353         }
1354         area->def_subscribing = WO;
1355     }
1356     else {
1357         prErr("unknown area option \"-%s\"!", option);
1358         nfree(iOption);
1359         return 1;
1360     }
1361 
1362     nfree(iOption);
1363     return 0;
1364 }
1365 
parseLinkOption(s_arealink * alink,char * token)1366 int parseLinkOption(s_arealink *alink, char *token)
1367 {
1368     char *iToken;
1369 
1370     if (token == NULL) {
1371         prErr("Parameters after %s are missing!", actualKeyword);
1372         return 1;
1373     }
1374     iToken = strLower(sstrdup(token));
1375     if (strcmp(iToken, "r")==0) alink->import = 0;
1376     else if (strcmp(iToken, "w")==0) alink->aexport = 0;
1377     else if (strcmp(iToken, "mn")==0) alink->mandatory = 1;
1378     else if (strcmp(iToken, "def")==0) alink->defLink = 1;
1379     else {
1380         nfree(iToken);
1381         return 1;
1382     }
1383 
1384     nfree(iToken);
1385     return 0;
1386 }
1387 
parseAreaLink(s_fidoconfig * config,s_area * area,char * tok)1388 int parseAreaLink(s_fidoconfig *config, s_area *area, char *tok)
1389 {
1390     s_arealink *arealink;
1391     s_link *link;
1392 
1393     if (tok == NULL) {
1394         prErr("Parameters after %s are missing!", actualKeyword);
1395         return 1;
1396     }
1397 
1398     if ((link = getLinkForArea(config, tok, area)) == NULL) {
1399         prErr("no links like \"%s\" in config!", tok);
1400         return 1;
1401     }
1402     if (isLinkOfArea(link, area)) {
1403         prErr("link %s is subscribed twice!", tok);
1404         return 0;
1405     }
1406 
1407     area->downlinks = srealloc(area->downlinks, sizeof(s_arealink*)*(area->downlinkCount+1));
1408     area->downlinks[area->downlinkCount] = (s_arealink*)scalloc(1, sizeof(s_arealink));
1409     area->downlinks[area->downlinkCount]->link = link;
1410 
1411     arealink = area->downlinks[area->downlinkCount];
1412     area->downlinkCount++;
1413 
1414     setLinkAccess(config, area, arealink);
1415 
1416     return 0;
1417 }
1418 
1419 /*
1420 useDefs
1421 uses enum pauses { NOPAUSE, ECHOAREA, FILEAREA } for choosing  defaults
1422 */
parseArea(s_fidoconfig * config,char * token,s_area * area,int useDefs)1423 int parseArea(s_fidoconfig *config, char *token, s_area *area, int useDefs)
1424 {
1425    char *tok, addr[24], *ptr;
1426    unsigned int rc = 0, i,j;
1427    int toklen;
1428    grp_t *group;
1429    e_pauses aType = area->areaType;
1430 
1431    if (token == NULL) {
1432       prErr("Parameters after %s are missing!", actualKeyword);
1433       return 1;
1434    }
1435 
1436     /*   memset(area, '\0', sizeof(s_area)); */
1437    area->scanMode = smNone;		/* val: just to be sure it's set */
1438 
1439     /* need add checking for area->areaType == 0 aka NOPAUSE ) */
1440 
1441    if (useDefs) { /* copy defaults */
1442        /* echo|file diffs */
1443        if(area->areaType == ECHOAREA) {
1444            memcpy(area,&(config->EchoAreaDefault),sizeof(s_area));
1445        }
1446        else if(area->areaType == FILEAREA) {
1447            memcpy(area,&(config->FileAreaDefault),sizeof(s_area));
1448        }
1449        /* default has perhaps groups        */
1450        /*             perhaps a description */
1451        /*             perhaps downlinks     */
1452        /*             areaName==NULL        */
1453        /*             fileName==NULL        */
1454        /*             perhaps other settings*/
1455        /*             allways an useAka     */
1456    } else { /* netmail - don't copy defaults */
1457        memset(area, 0, sizeof(s_area));
1458    }
1459    area->areaType = aType;
1460 
1461    tok = strtok(token, " \t");
1462    if (tok == NULL) {
1463       prErr("An areaname after %s is missing!", actualKeyword);
1464       return 1;         /*  if there is no areaname */
1465    }
1466 
1467    if (useDefs && (group = findGroupForArea(tok)) != NULL )
1468        memcpy(area, group->area,sizeof(s_area));
1469 
1470    area->areaName= (char *) smalloc(strlen(tok)+1);
1471    if (*tok=='\"' && tok[strlen(tok)-1]=='\"' && tok[1]) {
1472       strcpy(area->areaName, tok+1);
1473       area->areaName[strlen(area->areaName)-1] = '\0';
1474    } else
1475       strcpy(area->areaName, tok);
1476 
1477    if (token[strlen(tok)] == '\0')
1478        token[strlen(tok)] = ' ';
1479 
1480 
1481     /* copy default group
1482      * fc_freeEchoArea() and parseAreaOption() will free this memory */
1483     if(area->group!=NULL)
1484         area->group=sstrdup(area->group);
1485     area->description=NULL;
1486 
1487     /* not poiting to the links of the default --> .. */
1488     if(area->downlinkCount){
1489         j=area->downlinkCount;
1490         area->downlinkCount=0; /* was copied from default but there were no downlinks added really */
1491         area->downlinks=NULL;
1492         /* so now add default downlinks */
1493 
1494         /* echo|file diffs */
1495         if(area->areaType == ECHOAREA) {
1496             for(i=0;i<j;++i)
1497                 rc += parseAreaLink(config, area, aka2str(( (config->EchoAreaDefault).downlinks[i]->link->hisAka )));
1498         } else if(area->areaType == FILEAREA) {
1499             for(i=0;i<j;++i)
1500                 rc += parseAreaLink(config, area, aka2str(( (config->FileAreaDefault).downlinks[i]->link->hisAka )));
1501         }
1502     }
1503 
1504     /* copy SEEN-BY arrays from default */
1505     if(area->areaType == ECHOAREA)      /* just for echoareas */
1506     {
1507         rc += fc_copyAddressArray(area->sbaddCount, (config->EchoAreaDefault).sbadd, &(area->sbadd));
1508         rc += fc_copyAddressArray(area->sbignCount, (config->EchoAreaDefault).sbign, &(area->sbign));
1509         rc += fc_copyAddressArray(area->sbkeepCount, (config->EchoAreaDefault).sbkeep, &(area->sbkeep));
1510         rc += fc_copyAddressArray(area->sbstripCount, (config->EchoAreaDefault).sbstrip, &(area->sbstrip));
1511     }
1512 
1513     /*   area->fperm = area->uid = area->gid = -1;*/
1514     if(!area->fperm && !area->uid && !area->gid)
1515         area->fperm = area->uid = area->gid = (UINT)-1;
1516 
1517     /*   area->msgbType = MSGTYPE_SDM;*/
1518     if(!area->msgbType)
1519         area->msgbType= MSGTYPE_SQUISH;
1520 
1521     /*   area->useAka = config->addr;*/
1522 
1523     if(area->useAka==NULL)
1524         area->useAka = config->addr;
1525 
1526    /*  set default parameters of dupebase */
1527     if(!area->dupeHistory)
1528         area->dupeHistory = 7;
1529 
1530    /*  set defaults for MS-DOS */
1531 #ifdef __DOS__
1532    area->DOSFile = 1;
1533 #endif
1534 
1535    tok = strtok(token, " \t");
1536    tok = strtok(NULL, " \t");
1537 
1538    if (tok==NULL) {
1539 	   /*  was default settings.. */
1540 	   if (area->msgbType==MSGTYPE_PASSTHROUGH) return 0;
1541 	   else {
1542                prErr("A pathname is missing %s!", actualLine);
1543                return 2; /*  if there is no filename */
1544 	   }
1545    }
1546 
1547    toklen=strlen(tok); /* points to '\0' */
1548    if (stricmp(tok, "passthrough") != 0) {
1549        /* perhaps passthrough in default, so this does not have to be */
1550        /* a filename */
1551 
1552        /* is it a filename? */
1553        ptr=tok;
1554        while(*ptr && *ptr != PATH_DELIM && !isspace(*ptr))
1555            ++ptr;
1556        if(*ptr==PATH_DELIM){
1557            /* yes it is a filename :=) */
1558            /*  msgbase on disk */
1559            area->fileName = (char *) scalloc(1,toklen + 2);
1560            strcpy(area->fileName, tok);
1561            if((area->areaType == FILEAREA) && (tok[toklen-1]!=PATH_DELIM))
1562            area->fileName[toklen] = PATH_DELIM;
1563 
1564            tok = strtok(NULL, " \t");
1565        }else if(area->msgbType!=MSGTYPE_PASSTHROUGH){
1566            /* was not a filename, and default not passthrough */
1567            prErr("A pathname is missing %s!", actualLine);
1568            return 2;         /*  if there is no filename */
1569        }
1570 
1571    }else{
1572         /*  passthrough area */
1573         /*   area->fileName = NULL;  was copied from default */
1574         area->msgbType = MSGTYPE_PASSTHROUGH;
1575         tok = strtok(NULL, " \t");
1576     }
1577 
1578 
1579     while (tok != NULL) {
1580 
1581 
1582         if(tok[0]=='-') {
1583             rc += parseAreaOption(config, tok+1, area);
1584             if (rc) return rc;
1585         }
1586         else if ((isdigit(*tok) || (*tok=='*')) && (patmat(tok, "*:*/*") || patmat(tok, "*:*/*.*"))) {
1587 
1588             if (strchr(tok, '*')) {
1589 	        /* link mask present: set mandatory for all links matched. */
1590                 j = area->downlinkCount;
1591                 for (i=0; i<config->linkCount; i++) {
1592                     strcpy(addr, aka2str(config->links[i]->hisAka));
1593                     if (patmat(addr, tok)) {
1594                         parseAreaLink(config,area,addr);
1595                         area->downlinks[area->downlinkCount-1]->mandatory = 1;
1596                     } else if (config->links[i]->hisAka.point==0) {
1597                         strcat(addr, ".0");
1598                         if (patmat(addr, tok)) {
1599                             parseAreaLink(config,area,addr);
1600                             area->downlinks[area->downlinkCount-1]->mandatory = 1;
1601                         }
1602                     }
1603                 }
1604                 tok = strtok(NULL, " \t");
1605                 while (tok) {
1606                     if (tok[0]!='-') break;
1607                     for (i=j; i<area->downlinkCount; i++) {
1608                         if (parseLinkOption(area->downlinks[i], tok+1))
1609                             break;
1610                     }
1611                     if (i<area->downlinkCount) break;
1612                     tok = strtok(NULL, " \t");
1613                 }
1614                 continue;
1615             }
1616 
1617             rc += parseAreaLink(config, area, tok);
1618             if (rc) return rc;
1619 
1620             tok = strtok(NULL, " \t");
1621             while (tok) {
1622                 if (tok[0]=='-') {
1623                     if (parseLinkOption(area->downlinks[area->downlinkCount-1], tok+1))
1624                         break;
1625                     tok = strtok(NULL, " \t");
1626                 } else break;
1627             }
1628             continue;
1629         }
1630         else {
1631             prErr("Error in areaOptions token=%s!", tok);
1632             rc +=1;
1633         }
1634         tok = strtok(NULL, " \t");
1635     }
1636 
1637     if(area->description==NULL && config->EchoAreaDefault.description!=NULL)
1638         area->description=sstrdup(config->EchoAreaDefault.description);
1639 
1640     return rc;
1641 }
1642 
parseAreaDefault(s_fidoconfig * config,char * token,s_area * adef,int cleanup)1643 int parseAreaDefault(s_fidoconfig *config, char *token, s_area *adef, int cleanup)
1644 {
1645    char *tok, addr[24];
1646    unsigned int rc = 0, i;
1647 
1648 
1649    /* default has perhaps groups        */
1650    /*             perhaps a description */
1651    /*             perhaps downlinks     */
1652    /*             areaName==NULL        */
1653    /*             fileName==NULL        */
1654    /*             perhaps other settings*/
1655    /*             allways an useAka     */
1656 
1657 
1658    /* cleanup */
1659    if (cleanup) {
1660        e_pauses aType = adef->areaType;
1661        fc_freeEchoArea(adef);
1662        memset(adef, '\0', sizeof(s_area));
1663        adef->useAka = config->addr;
1664        adef->areaType = aType;
1665        adef->fperm = adef->uid = adef->gid = (UINT)-1;
1666        adef->msgbType = MSGTYPE_SDM;
1667        /*  set default parameters of dupebase */
1668        adef->dupeHistory = 7; /* 7 days */
1669        /* val: set defaul scan mode */
1670        adef->scanMode = smNone;
1671        /*  set defaults for MS-DOS */
1672 #ifdef __DOS__
1673        adef->DOSFile = 1;
1674 #endif
1675    }
1676 
1677    if (token == NULL) /* all defaults off */
1678        return 0;
1679    if(!strncasecmp(token,"off",3))
1680        return 0; /* default off */
1681 
1682    tok = strtok(token, " \t");
1683    if (tok == NULL) { /* does this ever happen?? */
1684       prErr("Parameters after %s are missing!", actualKeyword);
1685       return 2;
1686    }
1687 
1688    while (tok != NULL) {
1689        if (stricmp(tok, "passthrough") == 0) {
1690            /*  passthrough area */
1691 /*           adef->fileName = NULL;*/
1692            adef->msgbType = MSGTYPE_PASSTHROUGH;
1693        }else if(tok[0]=='-') {
1694            rc += parseAreaOption(config, tok+1, adef);
1695            if (rc) return rc;
1696        }else if ((isdigit(*tok) || (*tok=='*')) && (patmat(tok, "*:*/*") || patmat(tok, "*:*/*.*"))) {
1697            if (strchr(tok, '*')) {
1698                for (i=0; i<config->linkCount; i++) {
1699                    sprintf(addr, "%s", aka2str(config->links[i]->hisAka));
1700                    if (patmat(addr, tok)) {
1701                        parseAreaLink(config,adef,addr);
1702                        adef->downlinks[adef->downlinkCount-1]->mandatory = 1;
1703                    }
1704                }
1705                tok = strtok(NULL, " \t");
1706                continue;
1707            }
1708            rc += parseAreaLink(config, adef, tok);
1709            if (rc) return rc;
1710            tok = strtok(NULL, " \t");
1711            while (tok) {
1712                if (tok[0]=='-') {
1713                    if (parseLinkOption(adef->downlinks[adef->downlinkCount-1], tok+1))
1714                        break;
1715                    tok = strtok(NULL, " \t");
1716                } else break;
1717            }
1718            continue;
1719        }
1720        else {
1721            prErr("Error in areaOptions token=%s!", tok);
1722            rc +=1;
1723        }
1724        tok = strtok(NULL, " \t");
1725    }
1726 
1727    return rc;
1728 }
1729 
parseAreaGroup(char * values)1730 int parseAreaGroup(char *values)
1731 {
1732     char *ptr = NULL;
1733     char *name;
1734     char *patternList;
1735 
1736     if (!values || !strlen(values)) {
1737         prErr("Error in areaGroup definition - no name specified!");
1738         return 1;
1739     }
1740 
1741     ptr = strchr(values, ' ');
1742     if (!ptr)
1743         ptr = strchr(values, '\t');
1744     if (!ptr) {
1745         prErr("Error in areaGroup definition - no patterns specified!");
1746         return 2;
1747     }
1748 
1749     name = scalloc(ptr - values + 1, 1);
1750     sstrncpy(name, values, ptr - values);
1751     while((*ptr == ' ') || (*ptr == '\t')) ptr++;
1752 
1753     if (!strlen(ptr)) {
1754         prErr("Error in areaGroup definition - no patterns specified!");
1755         return 2;
1756     }
1757 
1758     patternList = sstrdup(ptr);
1759     addPatternToGrpTree(name, patternList);
1760 
1761     return 0;
1762 }
1763 
parseAreaGroupDefaults(s_fidoconfig * config,char * values)1764 int parseAreaGroupDefaults(s_fidoconfig *config, char *values)
1765 {
1766     char *ptr = NULL;
1767     char *name;
1768     char *params;
1769     grp_t *g;
1770 
1771     if (!values || !strlen(values)) {
1772         prErr("Error in areaGroup definition - no name specified!");
1773         return 1;
1774     }
1775 
1776     ptr = strchr(values, ' ');
1777     if (!ptr)
1778         ptr = strchr(values, '\t');
1779     if (!ptr) {
1780         prErr("Error in areaGroupDefaults definition - no patterns specified!");
1781         return 2;
1782     }
1783 
1784     name = scalloc(ptr - values + 1, 1);
1785     sstrncpy(name, values, ptr - values);
1786     while((*ptr == ' ') || (*ptr == '\t')) ptr++;
1787 
1788     if (!strlen(ptr)) {
1789         prErr("Error in areaGroupDefaults definition - no parameters specified!");
1790         return 2;
1791     }
1792 
1793     g = findGroupByName(name);
1794     if (!g) {
1795         prErr("Group %s is undefined, please define it first using 'areaGroup' token!");
1796         return 3;
1797     }
1798 
1799     params = sstrdup(ptr);
1800     memcpy(g->area, &(config->EchoAreaDefault), sizeof(s_area));
1801     parseAreaDefault(config, params, g->area, 0);
1802 
1803     nfree(params);
1804     nfree(name);
1805     return 0;
1806 }
1807 
parseEchoArea(char * token,s_fidoconfig * config)1808 int parseEchoArea(char *token, s_fidoconfig *config)
1809 {
1810     int rc;
1811     s_area *area;
1812 
1813     if (config->addr == NULL)
1814     {
1815         printAddrError();
1816     }
1817     if (token == NULL) {
1818         prErr("Parameters after %s are missing!", actualKeyword);
1819         return 1;
1820     }
1821 
1822     config->echoAreas = srealloc(config->echoAreas, sizeof(s_area)*(config->echoAreaCount+1));
1823     area = &(config->echoAreas[config->echoAreaCount]);
1824     area->areaType = ECHOAREA;
1825     rc = parseArea(config, token, area, 1);
1826     config->echoAreaCount++;
1827     return rc;
1828 }
1829 
parseNetMailArea(char * token,s_fidoconfig * config)1830 int parseNetMailArea(char *token, s_fidoconfig *config)
1831 {
1832     int rc;
1833     s_area *area;
1834 
1835     if (config->addr == NULL)
1836     {
1837         printAddrError();
1838     }
1839     if (token == NULL) {
1840         prErr("Parameters after %s are missing!", actualKeyword);
1841         return 1;
1842     }
1843 
1844     config->netMailAreas = srealloc(config->netMailAreas, sizeof(s_area)*(config->netMailAreaCount+1));
1845     area = &(config->netMailAreas[config->netMailAreaCount]);
1846     area->areaType = ECHOAREA;
1847     rc = parseArea(config, token, area, 0);
1848     config->netMailAreaCount++;
1849     return rc;
1850 }
1851 
parseFileArea(char * token,s_fidoconfig * config)1852 int parseFileArea(char *token, s_fidoconfig *config)
1853 {
1854     int rc;
1855     s_area *area;
1856 
1857     if (config->addr == NULL)
1858     {
1859         printAddrError();
1860     }
1861     if (token == NULL) {
1862         prErr("Parameters after %s are missing!", actualKeyword);
1863         return 1;
1864     }
1865 
1866     config->fileAreas = srealloc(config->fileAreas,
1867         sizeof(s_area)*(config->fileAreaCount+1));
1868 
1869     area = &(config->fileAreas[config->fileAreaCount]);
1870     area->areaType = FILEAREA;
1871     rc = parseArea(config, token, area, 1);
1872     config->fileAreaCount++;
1873     return rc;
1874 }
1875 
parseBbsArea(const s_fidoconfig * config,char * token,s_bbsarea * area)1876 int parseBbsArea(const s_fidoconfig *config, char *token, s_bbsarea *area)
1877 {
1878    char *tok;
1879    int rc = 0;
1880 
1881    unused(config);
1882 
1883    if (token == NULL) {
1884       prErr("Parameters after %s are missing!", actualKeyword);
1885       return 1;
1886    }
1887 
1888    memset(area, 0, sizeof(s_bbsarea));
1889 
1890    tok = strtok(token, " \t");
1891    if (tok == NULL) {
1892       prErr("An areaname after %s is missing!", actualKeyword);
1893       return 1;         /*  if there is no areaname */
1894    }
1895 
1896    area->areaName= (char *) smalloc(strlen(tok)+1);
1897    strcpy(area->areaName, tok);
1898 
1899    tok = strtok(NULL, " \t");
1900    if (tok == NULL) {
1901       prErr("A pathname is missing %s!", actualLine);
1902       return 2;         /*  if there is no filename */
1903    }
1904 
1905    if (tok[strlen(tok)-1] == PATH_DELIM) {
1906       area->pathName = (char *) smalloc(strlen(tok)+1);
1907       strcpy(area->pathName, tok);
1908    } else {
1909       area->pathName = (char *) smalloc(strlen(tok)+2);
1910       strcpy(area->pathName, tok);
1911       area->pathName[strlen(tok)] = PATH_DELIM;
1912       area->pathName[strlen(tok)+1] = '\0';
1913    }
1914 
1915    tok = strtok(NULL, " \t");
1916 
1917    while (tok != NULL) {
1918       if (stricmp(tok, "-d")==0) {
1919           if ((area->description=getDescription())==NULL)
1920             rc += 1;
1921       }
1922       else {
1923          prErr("Error in areaOptions token=%s!", tok);
1924          rc +=1;
1925          return rc;
1926       }
1927       tok = strtok(NULL, " \t");
1928    }
1929 
1930    return rc;
1931 }
1932 
parseBbsAreaStatement(char * token,s_fidoconfig * config)1933 int parseBbsAreaStatement(char *token, s_fidoconfig *config)
1934 {
1935    int rc;
1936 
1937    if (token == NULL) {
1938       prErr("Parameters after %s are missing!", actualKeyword);
1939       return 1;
1940    }
1941 
1942    config->bbsAreas = srealloc(config->bbsAreas,
1943 	sizeof(s_bbsarea)*(config->bbsAreaCount+1));
1944    rc = parseBbsArea(config, token,
1945 	&(config->bbsAreas[config->bbsAreaCount]));
1946    config->bbsAreaCount++;
1947    return rc;
1948 }
1949 
parseLink(char * token,s_fidoconfig * config)1950 int parseLink(char *token, s_fidoconfig *config)
1951 {
1952 
1953    s_link   *clink;
1954    s_link   *deflink;
1955 
1956    if (token == NULL) {
1957       prErr("A name after %s is missing!", actualKeyword);
1958       return 1;
1959    }
1960 
1961    config->describeLinkDefaults=0; /*  Stop describing of link defaults if it was */
1962 
1963    config->links = srealloc(config->links, sizeof(ps_link)*(config->linkCount+1));
1964 
1965    config->links[config->linkCount] = scalloc(1,sizeof(s_link));
1966 
1967    clink = config->links[config->linkCount];
1968 
1969    if (config->linkDefaults) {
1970 
1971       memcpy(clink, deflink = config->linkDefaults, sizeof(s_link));
1972 
1973 	  clink->name = sstrdup(deflink->name);
1974 
1975 	  clink->defaultPwd = sstrdup(deflink->defaultPwd);
1976 
1977       if (deflink->pktPwd != deflink->defaultPwd ) {
1978 		  clink->pktPwd = sstrdup (deflink->pktPwd);
1979       } else {
1980 		  clink->pktPwd = clink->defaultPwd;
1981       }
1982       if (deflink->ticPwd != deflink->defaultPwd ) {
1983 		  clink->ticPwd = sstrdup (deflink->ticPwd);
1984       } else {
1985 		  clink->ticPwd = clink->defaultPwd;
1986       }
1987   	  if (deflink->areafix.pwd != deflink->defaultPwd ) {
1988 		  clink->areafix.pwd = sstrdup (deflink->areafix.pwd);
1989       } else {
1990 		  clink->areafix.pwd = clink->defaultPwd;
1991       }
1992   	  if (deflink->filefix.pwd != deflink->defaultPwd ) {
1993 		  clink->filefix.pwd = sstrdup (deflink->filefix.pwd);
1994       } else {
1995 		  clink->filefix.pwd = clink->defaultPwd;
1996       }
1997   	  if (deflink->bbsPwd != deflink->defaultPwd ) {
1998 		  clink->bbsPwd = sstrdup(deflink->bbsPwd);
1999       } else {
2000 		  clink->bbsPwd = clink->defaultPwd;
2001       }
2002   	  if (deflink->sessionPwd != deflink->defaultPwd ) {
2003 		  clink->sessionPwd = sstrdup (deflink->sessionPwd);
2004       } else {
2005 		  clink->sessionPwd = clink->defaultPwd;
2006       }
2007 	  clink->handle = sstrdup (deflink->handle);
2008 	  clink->email = sstrdup (deflink->email);
2009 	  clink->emailFrom = sstrdup (deflink->emailFrom);
2010 	  clink->emailSubj = sstrdup (deflink->emailSubj);
2011 	  clink->LinkGrp = sstrdup (deflink->LinkGrp);
2012 	  clink->AccessGrp = copyGroups(deflink->AccessGrp, deflink->numAccessGrp);
2013 	  clink->areafix.autoCreateFile = sstrdup (deflink->areafix.autoCreateFile);
2014 	  clink->filefix.autoCreateFile = sstrdup (deflink->filefix.autoCreateFile);
2015 	  clink->areafix.autoCreateDefaults = sstrdup (deflink->areafix.autoCreateDefaults);
2016 	  clink->filefix.autoCreateDefaults = sstrdup (deflink->filefix.autoCreateDefaults);
2017 	  clink->areafix.fwdFile = sstrdup (deflink->areafix.fwdFile);
2018 	  clink->filefix.fwdFile = sstrdup (deflink->filefix.fwdFile);
2019 	  clink->areafix.denyFwdFile = sstrdup (deflink->areafix.denyFwdFile);
2020 	  clink->filefix.denyFwdFile = sstrdup (deflink->filefix.denyFwdFile);
2021 	  clink->areafix.name = sstrdup (deflink->areafix.name);
2022 	  clink->filefix.name = sstrdup (deflink->filefix.name);
2023 	  clink->areafix.baseDir = sstrdup (deflink->areafix.baseDir);
2024 	  clink->filefix.baseDir = sstrdup (deflink->filefix.baseDir);
2025 	  clink->areafix.reportsFlags = sstrdup (deflink->areafix.reportsFlags);
2026 	  clink->filefix.reportsFlags = sstrdup (deflink->filefix.reportsFlags);
2027 	  clink->filefix.baseDir = sstrdup (deflink->filefix.baseDir);
2028 	  clink->optGrp = copyGroups(deflink->optGrp, deflink->numOptGrp);
2029 	  clink->areafix.frMask = copyGroups(deflink->areafix.frMask, deflink->areafix.numFrMask);
2030 	  clink->filefix.frMask = copyGroups(deflink->filefix.frMask, deflink->filefix.numFrMask);
2031 	  clink->areafix.dfMask = copyGroups(deflink->areafix.dfMask, deflink->areafix.numDfMask);
2032 	  clink->filefix.dfMask = copyGroups(deflink->filefix.dfMask, deflink->filefix.numDfMask);
2033 
2034    } else {
2035 
2036       memset(clink, 0, sizeof(s_link));
2037 
2038 	  /*  Set defaults like in parseLinkDefaults() */
2039 
2040       /*  set areafix default to on */
2041       clink->areafix.on = 1;
2042       clink->filefix.on = 1;
2043 
2044       /*  set defaults to export, import, mandatory (0), manual (0) */
2045       clink->aexport = 1;
2046       clink->import = 1;
2047       clink->ourAka = &(config->addr[0]);
2048 
2049       /*  set default maxUnpackedNetmail */
2050       clink->maxUnpackedNetmail = 100;
2051 
2052       /*  set FileFixFSC87Subset default to on */
2053       clink->FileFixFSC87Subset = 1;
2054    }
2055 
2056    clink->name = (char *) smalloc (strlen(token)+1);
2057    strcpy(clink->name, token);
2058    clink->handle = clink->name;
2059 
2060    config->linkCount++;
2061    memset(&linkDefined, 0, sizeof(linkDefined));
2062    return 0;
2063 }
2064 
parseAnnDef(char * token,s_fidoconfig * config)2065 int parseAnnDef(char *token, s_fidoconfig *config)
2066 {
2067    ps_anndef   cAnnDef;
2068 
2069    if (token == NULL) {
2070       prErr("A name after %s is missing!", actualKeyword);
2071       return 1;
2072    }
2073    config->AnnDefs = srealloc(config->AnnDefs, sizeof(s_anndef)*(config->ADCount+1));
2074    cAnnDef = &(config->AnnDefs[config->ADCount]);
2075    memset(cAnnDef, 0, sizeof(s_anndef));
2076 
2077    cAnnDef->annAreaTag = sstrdup(token);
2078    config->ADCount++;
2079    return 0;
2080 }
2081 
parseAnnDefAddres(char * token,s_fidoconfig * config,int i)2082 int parseAnnDefAddres(char *token, s_fidoconfig *config, int i)
2083 {
2084    ps_anndef  cAnnDef = NULL;
2085    hs_addr* addr;
2086    if (token == NULL) {
2087       prErr("A name after %s is missing!", actualKeyword);
2088       return 1;
2089    }
2090    cAnnDef = getDescrAnnDef(config);
2091    addr = scalloc(1,sizeof(hs_addr));
2092    parseFtnAddrZS(token, addr);
2093 
2094    if( i == 1)
2095        cAnnDef->annaddrto = addr;
2096    if( i == 2)
2097        cAnnDef->annaddrfrom = addr;
2098 
2099    return 0;
2100 }
2101 
2102 
parseNodelist(char * token,s_fidoconfig * config)2103 int parseNodelist(char *token, s_fidoconfig *config)
2104 {
2105    if (token == NULL) {
2106       prErr("A name after %s is missing!", actualKeyword);
2107       return 1;
2108    }
2109 
2110    config->nodelists = srealloc(config->nodelists, sizeof(s_nodelist)*(config->nodelistCount+1));
2111    memset(&(config->nodelists[config->nodelistCount]), 0, sizeof(s_nodelist));
2112    config->nodelists[config->nodelistCount].nodelistName =
2113      (char *) smalloc (strlen(token)+1);
2114    strcpy(config->nodelists[config->nodelistCount].nodelistName, token);
2115 
2116    config->nodelists[config->nodelistCount].format = fts5000;
2117 
2118    config->nodelists[config->nodelistCount].delAppliedDiff = 0;
2119 
2120    config->nodelistCount++;
2121    return 0;
2122 }
2123 
parseBool(char * token,unsigned int * value)2124 int parseBool (char *token, unsigned int *value)
2125 {
2126   char *iToken;
2127 
2128   if (token == NULL) {
2129     *value = 1;
2130     return 0;
2131   }
2132 
2133   iToken = strLower(sstrdup(token));
2134   if ((strcmp(iToken, "on")==0) || (strcmp(iToken, "yes")==0) || (strcmp(iToken, "1")==0)) *value = 1;
2135   else if ((strcmp(iToken, "off")==0) || (strcmp(iToken, "no")==0) || (strcmp(iToken, "0")==0)) *value = 0;
2136   else {
2137     nfree(iToken);
2138     return 2;
2139   }
2140   nfree(iToken);
2141   return 0;
2142 }
2143 
parseAutoPause(char * token,unsigned * autoPause)2144 int parseAutoPause(char *token, unsigned *autoPause)
2145 {
2146    char *ptr;
2147 
2148    if (token == NULL) {
2149       prErr("A parameter after %s is missing!", actualKeyword);
2150       return 1;
2151    } /* endif */
2152 
2153    for (ptr = token; *ptr; ptr++) {
2154       if (!isdigit(*ptr)) {
2155          prErr("A parameter after %s is missing!", actualKeyword);
2156          return 1;
2157       } /* endif */
2158    } /* endfor */
2159 
2160    *autoPause = (unsigned)atoi(token);
2161 
2162    return 0;
2163 }
2164 
parsePause(char * token,unsigned * Pause)2165 int parsePause(char *token, unsigned *Pause)
2166 {
2167    if ((token == NULL) || (stricmp(token,"on") == 0) ) {
2168       *Pause = ECHOAREA|FILEAREA;
2169    }
2170    else if(stricmp(token,"earea") == 0)
2171       *Pause |= ECHOAREA;
2172    else if(stricmp(token,"farea") == 0)
2173       *Pause |= FILEAREA;
2174    else if (stricmp(token,"off") == 0)
2175       *Pause = NOPAUSE;
2176    else {
2177       prErr("Wrong Pause parameter!");
2178       return 1; /*  error */
2179    }
2180    return 0;
2181 }
2182 
parseUInt(char * token,unsigned int * uint)2183 int parseUInt(char *token, unsigned int *uint) {
2184     long var=0;
2185 
2186     if (token == NULL) {
2187 	prErr("A parameter after %s is missing!", actualKeyword);
2188 	return 1;
2189     }
2190     sscanf(token, "%ld", &var);
2191     if( var<0 ) {
2192         prErr("The negative value of %s is invalid!", actualKeyword);
2193 	return 1;
2194     }
2195     *uint = (unsigned int)var;
2196 
2197     return 0;
2198 }
2199 
parseOctal(char * token,unsigned int * octal)2200 int parseOctal(char *token, unsigned int *octal) {
2201 
2202     if (token == NULL) {
2203        prErr("A parameter after %s is missing!", actualKeyword);
2204        return 1;
2205     }
2206     sscanf(token, "%o", octal);
2207     return 0;
2208 }
2209 
parsePWD(char * token,char ** pwd)2210 int parsePWD(char *token, char **pwd) {
2211 
2212    if (token == NULL) {            /*  return empty password */
2213       *pwd = (char *) smalloc(1);
2214       (*pwd)[0] = '\0';
2215       return 0;
2216    }
2217 
2218    *pwd = sstrdup(token);
2219    if (*pwd == NULL) return 1;
2220    else return 0;
2221 }
2222 
parseHandle(char * token,s_fidoconfig * config)2223 int parseHandle(char *token, s_fidoconfig *config) {
2224    s_link   *clink;
2225 
2226    if (token == NULL) {
2227       prErr("A parameter after %s is missing!", actualKeyword);
2228       return 1;
2229    }
2230 
2231    clink = getDescrLink(config);
2232 
2233    clink->handle = (char *) smalloc (strlen(token)+1);
2234    strcpy(clink->handle, token);
2235    return 0;
2236 }
2237 
2238 /* Return 0 if OK, 1 if invalid parameter, 2 if another error */
parseRoute(char * token,s_fidoconfig * config,s_route ** route,unsigned * count,e_id id)2239 int parseRoute(char *token, s_fidoconfig *config, s_route **route,
2240 			   unsigned *count, e_id id) {
2241   char *option;
2242   char *iOption;
2243   int  rc = 0;
2244   s_route *actualRoute;
2245 
2246   if (token == NULL) {
2247     prErr("A parameter after %s is missing!", actualKeyword);
2248     return 1;
2249   }
2250 
2251   option = strtok(token, " \t");
2252   if (option == NULL) {
2253     prErr("A parameter after %s is missing!", actualKeyword);
2254     return 1;
2255   }
2256 
2257   *route = srealloc(*route, sizeof(s_route)*(*count+1));
2258   actualRoute = &(*route)[*count];
2259   memset(actualRoute, '\0', sizeof(s_route));
2260 
2261   actualRoute->id = id; actualRoute->flavour = flUndef;
2262 
2263   while (option != NULL) {
2264     iOption = strLower(sstrdup(option));
2265 	if (strcmp(iOption, "hold")==0) actualRoute->flavour = flHold;
2266     else if (strcmp(iOption, "normal")==0) actualRoute->flavour = flNormal;
2267     else if (strcmp(iOption, "crash")==0) actualRoute->flavour = flCrash;
2268     else if (strcmp(iOption, "direct")==0) actualRoute->flavour = flDirect;
2269     else if (strcmp(iOption, "immediate")==0) actualRoute->flavour = flImmediate;
2270     else if (strcmp(iOption, "hub")==0) actualRoute->routeVia = hub;
2271     else if (strcmp(iOption, "host")==0) actualRoute->routeVia = host;
2272     else if (strcmp(iOption, "boss")==0) actualRoute->routeVia = boss;
2273     else if (strcmp(iOption, "noroute")==0) actualRoute->routeVia = noroute;
2274     else if (strcmp(iOption, "no-route")==0) actualRoute->routeVia = noroute;
2275     else if (strcmp(iOption, "nopack")==0) actualRoute->routeVia = nopack;
2276     else if (strcmp(iOption, "no-pack")==0) actualRoute->routeVia = nopack;
2277     else if (isdigit(option[0]) || (option[0] == '*') || (option[0] == '?')) {
2278       if ((actualRoute->routeVia == 0) && (actualRoute->target == NULL)) {
2279 	actualRoute->target = getLink(config, option);
2280 	actualRoute->viaStr = (char *) smalloc(strlen(option)+1);
2281 	strcpy(actualRoute->viaStr, option);
2282       }
2283       else {
2284 	if (actualRoute->pattern == NULL) {
2285 	  /* 2 for additional .0 if needed */
2286 	  actualRoute->pattern = (char *) smalloc(strlen(option)+2+1);
2287 	  strcpy(actualRoute->pattern, option);
2288 	  if ((strchr(option, '.')==NULL) && (strchr(option, '*')==NULL)) {
2289 	    strcat(actualRoute->pattern, ".0");
2290 	  }
2291 	  (*count)++;
2292 	} else {
2293 	  /*  add new Route for additional patterns */
2294 	  *route = srealloc(*route, sizeof(s_route)*(*count+1));
2295 	  actualRoute = &(*route)[*count];
2296 	  memcpy(actualRoute,&(*route)[(*count)-1],sizeof(s_route));
2297 	  if ((*route)[(*count)-1].viaStr != NULL)
2298 	    actualRoute->viaStr = sstrdup((*route)[(*count)-1].viaStr);
2299 
2300 	  /* 2 for additional .0 if needed */
2301 	  actualRoute->pattern = (char *) smalloc(strlen(option)+2+1);
2302 	  strcpy(actualRoute->pattern, option);
2303 	  if ((strchr(option, '.')==NULL) && (strchr(option, '*')==NULL)) {
2304 	    strcat(actualRoute->pattern, ".0");
2305 	  }
2306 	  (*count)++;
2307 	}
2308 
2309       }
2310       if ((actualRoute->target == NULL) && (actualRoute->routeVia == 0)) {
2311          prErr("Link %s not found in Route statement!", actualRoute->viaStr);
2312          rc = 2;
2313       }
2314     }
2315     nfree(iOption);
2316     option = strtok(NULL, " \t");
2317   }
2318   /* set flavour if it isn't specified in the statement */
2319   /* and routeVia is not 'nopack' */
2320   if (actualRoute->flavour == flUndef && actualRoute->routeVia != nopack)
2321   {
2322     if (actualRoute->target == NULL)
2323     {
2324       prErr("You must either specify flavour or use defined link as target");
2325       rc = 2;
2326     }
2327     else
2328       actualRoute->flavour = actualRoute->target->netMailFlavour;
2329   }
2330 
2331   return rc;
2332 }
2333 
parsePack(char * line,s_fidoconfig * config)2334 int parsePack(char *line, s_fidoconfig *config) {
2335 
2336    char   *p, *c;
2337    s_pack *pack;
2338 
2339    if (line == NULL) {
2340       prErr("A parameter after %s is missing!", actualKeyword);
2341       return 1;
2342    }
2343 
2344    /* check for no link definition was before */
2345    if(config->linkCount > 0)
2346    {
2347        prErr("Unable to add commandline for packer after link definition!");
2348        return 2;
2349    }
2350 
2351    p = strtok(line, " \t");
2352    c = getRestOfLine();
2353    if ((p != NULL) && (c != NULL)) {
2354 
2355        /*  add new pack statement */
2356        config->packCount++;
2357        config->pack = srealloc(config->pack, config->packCount * sizeof(s_pack));
2358 
2359        /*  fill new pack statement */
2360        pack = &(config->pack[config->packCount-1]);
2361        pack->packer = (char *) smalloc(strlen(p)+1);
2362        strcpy(pack->packer, p);
2363        pack->call   = (char *) smalloc(strlen(c)+1);
2364        strcpy(pack->call, c);
2365        if( strncasecmp(pack->call,ZIPINTERNAL,strlen(ZIPINTERNAL)) )
2366        {
2367            if (strstr(pack->call, "$a")==NULL) {
2368                prErr("$a missing in pack statement %s!", actualLine);
2369                return 2;
2370            }
2371            if (strstr(pack->call, "$f")==NULL) {
2372                prErr("$f missing in pack statement %s!", actualLine);
2373                return 2;
2374            }
2375        }
2376        return 0;
2377    } else {
2378        prErr("A parameter after %s is missing!", actualKeyword);
2379        return 1;
2380    }
2381 }
2382 
parseUnpack(char * line,s_fidoconfig * config)2383 int parseUnpack(char *line, s_fidoconfig *config)
2384 {
2385     char   *p, *c;
2386     char   *error;
2387     s_unpack *unpack;
2388     unsigned char  code;
2389     int    i;
2390 
2391     if (line == NULL)
2392     {
2393         prErr("A parameter after %s is missing!", actualKeyword);
2394         return 1;
2395     }
2396 
2397     /*  ToDo: Create replacement for strtok which handles "str" */
2398 
2399     /* Skip white spaces */
2400     for (p = line; (*p == ' ') || (*p == '\t'); p++);
2401 
2402     if (*p != '\0')
2403     {
2404         if (*p == '\"')
2405         {
2406             /* skip till next double qoute */
2407             for (c = ++p; (*c != '\"') && (*c != '\0'); c++);
2408         }
2409         else
2410         {
2411             /* skip till next white space */
2412             for (c = p; (*c != ' ') && (*c != '\t') && (*c != '\0'); c++);
2413         }
2414 
2415         if (*c != '\0')
2416         {
2417             *c++ = '\0';
2418             stripLeadingChars(c, " \t");
2419         }
2420     }
2421     else
2422         c = NULL;
2423 
2424     if ((p != NULL) && (c != NULL))
2425     {
2426         /*  add new unpack statement */
2427         config->unpackCount++;
2428         config->unpack = srealloc(config->unpack, config->unpackCount * sizeof(s_unpack));
2429 
2430         /*  fill new unpack statement */
2431         unpack = &(config->unpack[config->unpackCount-1]);
2432         unpack->call   = (char *) smalloc(strlen(p)+1);
2433         strcpy(unpack->call, p);
2434 
2435         if( strncasecmp(unpack->call,ZIPINTERNAL,strlen(ZIPINTERNAL)) )
2436         {
2437             /* zipInternal is not used */
2438             if (strstr(unpack->call, "$a")==NULL)
2439             {
2440                 prErr("$a missing in unpack statement %s!", actualLine);
2441                 return 2;
2442             }
2443         }
2444 
2445         p = strtok(c, " \t");    /* p contains offset now */
2446         c = strtok(NULL, " \t"); /* c contains match code now */
2447 
2448         if ((p == NULL) || (c == NULL))
2449         {
2450             prErr("offset or match code missing in unpack statement %s!", actualLine);
2451             return 1;
2452         }
2453 
2454         unpack->offset = (unsigned) strtol(p, &error, 0);
2455 
2456         if ((error != NULL) && (*error != '\0'))
2457         {
2458             prErr("The number is wrong for offset in unpack!");
2459             return 1;     /*  error occured; */
2460         }
2461 
2462         unpack->matchCode = (unsigned char *) smalloc(strlen(c) / 2 + 1);
2463         unpack->mask      = (unsigned char *) smalloc(strlen(c) / 2 + 1);
2464 
2465         /*  parse matchcode statement */
2466         /*  this looks a little curvy, I know. Remember, I programmed this at 23:52 :) */
2467         for (i = 0, error = NULL; c[i] != '\0' && error == NULL; i++)
2468         {
2469             code = (unsigned char) toupper(c[i]);
2470             /*  if code equals to '?' set the corresponding bits  of  mask[] to 0 */
2471             unpack->mask[i / 2] = i % 2  == 0 ? (code != '?' ? 0xF0 : 0) :
2472                                                 unpack->mask[i / 2] | (code != '?' ? 0xF : 0);
2473 
2474             /*  find the numeric representation of hex code */
2475             /*  if this is a '?' code equals to 0 */
2476             code = (isdigit(code) ? code - '0' :
2477                     (isxdigit(code) ? code - 'A' + 10 :
2478                      (code == '?' ? 0 : (error = c + i, 0xFF))));
2479             unpack->matchCode[i / 2] = i % 2 == 0 ? code << 4 : unpack->matchCode[i / 2] | code;
2480         }
2481 
2482         if (error)
2483         {
2484             prErr("matchCode can\'t contain %c in unpack statement %s!", *error, actualLine);
2485             return 1;
2486         }
2487 
2488         if (i % 2 != 0)
2489         {
2490             prErr("matchCode must be byte-aligned in unpack statement %s!", actualLine);
2491             return 1;
2492         }
2493 
2494         unpack->codeSize = i / 2;
2495 
2496         return 0;
2497     }
2498     else
2499     {
2500         prErr("A parameter after %s is missing!", actualKeyword);
2501         return 1;
2502     }
2503 }
2504 
2505 #if 0
2506 static int f_accessable(char *token)
2507 {
2508 /*  We don't need a real fexist function here, and we don't want to */
2509 /*        be dependent on SMAPI just because of this. For us, it is enough */
2510 /*        to see if the file is accessible */
2511 /*  BUT WE DON'T KNOW ABOUT DIRS! */
2512 
2513 #ifdef __UNIX__
2514     struct stat sb;
2515 
2516     if (stat(token, &sb))
2517 	return 0;  /*  cannot stat the file */
2518     if (access(token, R_OK))
2519 	return 0;  /*  cannot access the file */
2520     return 1;
2521 #else
2522     FILE *f = fopen(token, "rb");
2523     if (f == NULL)
2524         return 0;
2525     fclose(f);
2526     return 1;
2527 #endif
2528 }
2529 #endif
2530 
parseFileName(char * line,char ** name,char ** alreadyDefined)2531 int parseFileName(char *line, char **name, char **alreadyDefined) {
2532    char *token;
2533 
2534    if (*name != NULL) {
2535       if (alreadyDefined == NULL || *alreadyDefined) {
2536          prErr("Duplicate file name!");
2537          return 1;
2538       }
2539       nfree(*name);
2540    }
2541 
2542    if (line == NULL) {
2543       prErr("A parameter after %s is missing!", actualKeyword);
2544       return 1;
2545    }
2546 
2547    if (line[0]=='\"') {
2548      token=(char *) smalloc (strlen(line)+1);
2549      sscanf(line,"\"%[^\"]s",token);
2550    }
2551    else
2552      token = strtok(line, " \t");
2553 
2554    if (token == NULL) {
2555       prErr("A parameter after %s is missing!", actualKeyword);
2556       return 1;
2557    }
2558 /*    if (f_accessable(token)) { */
2559    if (fexist(token)) { /*  fexist knows about dirs */
2560 /*       (*name) = smalloc(strlen(token)+1); */
2561 /*       strcpy((*name), token); */
2562 	xstrcat(name, token);
2563 	if (alreadyDefined) *alreadyDefined=*name;
2564    } else {
2565       prErr("File not found or no permission: %s!", token);
2566       if (line[0]=='\"')
2567         nfree(token);
2568       return 2;
2569    }
2570    if (line[0]=='\"')
2571      nfree(token);
2572    return 0;
2573 }
2574 
2575 /* Parse loglevels string
2576    Expand ranges like x-y;
2577    Ignore spaces & etc (recognizes digits & letters only).
2578  */
parseLoglevels(char * line,char ** loglevels)2579 int parseLoglevels(char *line, char **loglevels) {
2580   char *ll, *temp; /* Array for store */
2581   char *p=line;
2582   int i,k;
2583 
2584   if(!line) {
2585     prErr("A parameter after %s is missing!", actualKeyword);
2586     return 1;
2587   }
2588 
2589   ll = calloc(256,sizeof(char));
2590   if( !ll ) {
2591     prErr( "Low memory!" );
2592     return 1;
2593   }
2594 
2595   while( *p ){  /* scan string */
2596     if( isdigit(*p) || isalpha(*p) )
2597       ll[(int)*p] = 1;
2598     else if( *p=='-' && p!=*loglevels )
2599            for( i=*(p-1), k=*(p+1) ; i && i<k ; i++ )
2600               ll[i]=1;
2601     p++;
2602   }
2603 
2604   p = temp = smalloc('z'-'a'+'Z'-'A'+'9'-'0'+4);
2605   for( i='0'; i<='9'; i++ )
2606      if( ll[i] ) *(p++)=i;
2607   for( i='A'; i<='Z'; i++ )
2608      if( ll[i] ) *(p++)=i;
2609   for( i='a'; i<='z'; i++ )
2610      if( ll[i] ) *(p++)=i;
2611   *p='\0';
2612 
2613   *loglevels = sstrdup(temp);
2614 
2615   nfree(temp);
2616   nfree(ll);
2617   return 0;
2618 }
2619 
parsePackerDef(char * line,s_fidoconfig * config,s_pack ** packerDef)2620 int parsePackerDef(char *line, s_fidoconfig *config, s_pack **packerDef) {
2621 
2622    unsigned int i;
2623 
2624    if (line == NULL) {
2625       prErr("A parameter after %s is missing!", actualKeyword);
2626       return 1;
2627    }
2628 
2629    if (stricmp(line,"none")==0) {
2630 	   (*packerDef) = NULL;
2631 	   return 0;
2632    }
2633 
2634    for(i = 0; i < config->packCount; i++)
2635       if (stricmp(line, config->pack[i].packer)==0) {
2636          (*packerDef) = &(config->pack[i]);
2637          return 0;
2638       }
2639 
2640    prErr("Packer %s not found for packer statement!", line);
2641    return 2;
2642 }
2643 
parseFlavour(char * line,e_flavour * flavour)2644 int parseFlavour(char *line, e_flavour *flavour)
2645 {
2646   char *iLine;
2647 
2648   if (line == NULL) {
2649     prErr("A parameter after %s is missing!", actualKeyword);
2650     return 1;
2651   }
2652 
2653   iLine = strLower(sstrdup(line));
2654   if (strcmp(iLine, "hold")==0) *flavour = flHold;
2655   else if (strcmp(iLine, "normal")==0) *flavour = flNormal;
2656   else if (strcmp(iLine, "direct")==0) *flavour = flDirect;
2657   else if (strcmp(iLine, "crash")==0) *flavour = flCrash;
2658   else if (strcmp(iLine, "immediate")==0) *flavour = flImmediate;
2659   else {
2660     prErr("Unknown %s value %s!", actualKeyword, line);
2661     nfree(iLine);
2662     return 2;
2663   }
2664   nfree(iLine);
2665   return 0;
2666 }
2667 
parseAttr(char * token,char ** attrs,long * bitattr)2668 int parseAttr(char *token, char **attrs, long *bitattr) {
2669   char *p;
2670   int parsed;
2671 
2672   nfree(*attrs);
2673   *bitattr = 0;
2674 
2675   parsed = parseAttrString(token, attrs, bitattr, &p);
2676   assert(parsed >= 0); /* Should be */
2677   if(*p != '\0') {
2678     prErr("Unknown flag %s!", p);
2679     nfree(*attrs);
2680     return 2;
2681   }
2682   return 0;
2683 }
2684 
parseUUEechoAreas(char * token,char ** grp[],unsigned int * count)2685 int parseUUEechoAreas(char *token, char **grp[], unsigned int *count) {
2686 
2687   if (token == NULL) {
2688      prErr("Parameters after %s are missing!", actualKeyword);
2689      return 1;
2690   }
2691   *grp = srealloc(*grp, sizeof(char*)*(*count+1));
2692   (*grp)[*count] = sstrdup(token);
2693   (*count)++;
2694   return 0;
2695 }
2696 
2697 /* Parse strings like "token1, token2,token3 token4" into s_str_array */
parseStringList(char * token,s_str_array ** ss)2698 int parseStringList(char *token, s_str_array **ss)
2699 {
2700 
2701 	assert(token != NULL && ss != NULL);
2702 	nfree(*ss);
2703 	*ss = makeStrArray(token);
2704 	return 0;
2705 }
2706 
parseGrp(char * token,char ** grp[],unsigned int * count)2707 int parseGrp(char *token, char **grp[], unsigned int *count) {
2708 	char *p;
2709 
2710 	p = token;
2711 	while (*p && strchr(" \t,", *p)) p++;
2712 	if (!*p) return 0;
2713 	for (*count=1; ;(*count)++) {
2714 		while (*p && !strrchr(" \t,", *p)) p++;
2715 		while (*p && strchr(" \t,", *p)) p++;
2716 		if (!*p) break;
2717 	}
2718 	p = token;
2719 	while (*p && strchr(" \t,", *p)) p++;
2720 	*grp = smalloc(sizeof(char *)*(*count) + strlen(p) + 1);
2721 	(*grp)[0]=(char *)(*grp+(*count));
2722 	strcpy((*grp)[0], p);
2723 	p = (*grp)[0];
2724 	(*count)=1;
2725     for (;;)
2726     {
2727 		while (*p && !strrchr(" \t,", *p)) p++;
2728 		if (!*p) break;
2729 		*p++ = '\0';
2730 		while (*p && strchr(" \t,", *p)) p++;
2731 		if (!*p) break;
2732 		(*grp)[(*count)++] = p;
2733  	}
2734 
2735 	return 0;
2736 }
2737 
2738 /* and the parseGroup: */
2739 /*  i make some checking... maybe it is better check if the pointer exist from */
2740 /*  copyString function? */
2741 /*  i removed some checking... ;-) */
2742 /*  groups may be copied from linkDefaults */
2743 
parseGroup(char * token,s_fidoconfig * config,int i)2744 int parseGroup(char *token, s_fidoconfig *config, int i)
2745 {
2746     s_link *link = NULL;
2747     ps_anndef cAnnDef = NULL;
2748 
2749     if (token == NULL)
2750 		{
2751 			prErr("A parameter after %s is missing!", actualKeyword);
2752 			return 1;
2753 		}
2754 
2755 	if (i != 2)
2756         link    = getDescrLink(config);
2757     if (i == 6 || i == 7)
2758         cAnnDef = getDescrAnnDef(config);
2759 
2760 	switch (i) {
2761 	case 0:
2762 		if (link->AccessGrp) freeGroups(link->AccessGrp, link->numAccessGrp);
2763 		link->AccessGrp = NULL;
2764 		link->numAccessGrp = 0;
2765 		parseGrp(token, &(link->AccessGrp), &(link->numAccessGrp));
2766 		break;
2767 
2768 	case 1:
2769 		nfree(link->LinkGrp);
2770 		fc_copyString(token, &link->LinkGrp);
2771 		break;
2772 
2773 	case 2:
2774 		if (config->numPublicGroup != 0) {
2775 			prErr("Duplicate parameter after %s!", actualKeyword);
2776 			return 1;
2777 		}
2778 		parseGrp(token, &(config->PublicGroup), &(config->numPublicGroup));
2779 		break;
2780 
2781 	case 3:
2782 		if (link->optGrp) freeGroups(link->optGrp, link->numOptGrp);
2783 		link->optGrp = NULL;
2784 		link->numOptGrp = 0;
2785 		parseGrp(token, &(link->optGrp), &(link->numOptGrp));
2786 		break;
2787 
2788 	case 4:
2789 		if (link->areafix.frMask) freeGroups(link->areafix.frMask, link->areafix.numFrMask);
2790 		link->areafix.frMask = NULL;
2791 		link->areafix.numFrMask = 0;
2792 		parseGrp(token, &(link->areafix.frMask), &(link->areafix.numFrMask));
2793 		break;
2794 	case 14:
2795 		if (link->filefix.frMask) freeGroups(link->filefix.frMask, link->filefix.numFrMask);
2796 		link->filefix.frMask = NULL;
2797 		link->filefix.numFrMask = 0;
2798 		parseGrp(token, &(link->filefix.frMask), &(link->filefix.numFrMask));
2799 		break;
2800 
2801 	case 5:
2802 		if (link->areafix.dfMask) freeGroups(link->areafix.dfMask, link->areafix.numDfMask);
2803 		link->areafix.dfMask = NULL;
2804 		link->areafix.numDfMask = 0;
2805 		parseGrp(token, &(link->areafix.dfMask), &(link->areafix.numDfMask));
2806 		break;
2807 	case 15:
2808 		if (link->filefix.dfMask) freeGroups(link->filefix.dfMask, link->filefix.numDfMask);
2809 		link->filefix.dfMask = NULL;
2810 		link->filefix.numDfMask = 0;
2811 		parseGrp(token, &(link->filefix.dfMask), &(link->filefix.numDfMask));
2812 		break;
2813 
2814     case 6:
2815 		if (cAnnDef->annInclude) freeGroups(cAnnDef->annInclude, cAnnDef->numbI);
2816 		cAnnDef->annInclude = NULL;
2817 		cAnnDef->numbI       = 0;
2818 		parseGrp(token, &(cAnnDef->annInclude), &(cAnnDef->numbI));
2819 		break;
2820 
2821     case 7:
2822 		if (cAnnDef->annExclude) freeGroups(cAnnDef->annExclude, cAnnDef->numbE);
2823 		cAnnDef->annExclude = NULL;
2824 		cAnnDef->numbE       = 0;
2825 		parseGrp(token, &(cAnnDef->annExclude), &(cAnnDef->numbE));
2826 		break;
2827 
2828     case 8:
2829 		if (link->RescanGrp) freeGroups(link->RescanGrp, link->numRescanGrp);
2830 		link->RescanGrp = NULL;
2831 		link->numRescanGrp = 0;
2832 		parseGrp(token, &(link->RescanGrp), &(link->numRescanGrp));
2833 		break;
2834     default:
2835 		break;
2836 	}
2837 
2838 
2839 
2840    return 0;
2841 }
2842 
parseLocalArea(char * token,s_fidoconfig * config)2843 int parseLocalArea(char *token, s_fidoconfig *config)
2844 {
2845     int rc;
2846     s_area *area;
2847 
2848     if (token == NULL) {
2849         prErr("Parameters after %s are missing!", actualKeyword);
2850         return 1;
2851     }
2852 
2853     config->localAreas = srealloc(config->localAreas, sizeof(s_area)*(config->localAreaCount+1));
2854     area = &(config->localAreas[config->localAreaCount]);
2855     area->areaType = ECHOAREA;
2856 
2857     area->areaType = ECHOAREA;
2858     rc = parseArea(config, token, area, 0);
2859     config->localAreaCount++;
2860     return rc;
2861 }
2862 
parseCarbonRule(char * token,s_fidoconfig * config)2863 int parseCarbonRule(char *token, s_fidoconfig *config)
2864 {
2865     s_carbon *cb=&(config->carbons[config->carbonCount-1]);
2866 
2867    if (token == NULL) {
2868       prErr("OR|AND|NOT after %s is missing!", actualKeyword);
2869       return 1;
2870    }
2871 
2872    /* rules are valid for the expressions that follow */
2873    /* but carbonRule AND also involves cb */
2874    /* expressions can start with NOT, but not with AND */
2875    if (stricmp(token,"NOT")==0) {
2876        _carbonrule = CC_NOT|CC_AND;
2877        if(config->carbonCount>0 && (cb->areaName==NULL && cb->move!=2)) /* no action */
2878            cb->rule |= CC_AND; /* AND NOT .. with next expr */
2879    }
2880 
2881    else if (stricmp(token,"OR")==0) {
2882        _carbonrule = CC_OR; /* =0 */
2883        if (config->carbonCount)
2884 	   cb->rule &= CC_NOT;
2885    }
2886 
2887    else if (stricmp(token,"AND")==0) {
2888        _carbonrule = CC_AND;
2889        if(config->carbonCount>0 && (cb->areaName==NULL && cb->move!=2)) /* no action */
2890            cb->rule |= CC_AND;
2891    }
2892 
2893    else {
2894        prErr("OR|AND|NOT after %s is missing!", actualKeyword);
2895        return 1;
2896    }
2897    return 0;
2898 }
2899 
parseCarbon(char * token,s_fidoconfig * config,e_carbonType ctype)2900 int parseCarbon(char *token, s_fidoconfig *config, e_carbonType ctype)
2901 {
2902     int c=config->carbonCount;
2903     s_carbon *cb;
2904 
2905 
2906     if (token == NULL) {
2907         prErr("Parameters after %s are missing!", actualKeyword);
2908         return 1;
2909     }
2910 
2911 
2912     config->carbonCount++;
2913     config->carbons = srealloc(config->carbons,sizeof(s_carbon)*(config->carbonCount));
2914 
2915     cb=&(config->carbons[c]);
2916     memset(cb, 0, sizeof(s_carbon));
2917 
2918     cb->ctype = ctype;
2919     cb->rule=_carbonrule;
2920 
2921     if(ctype==ct_addr)
2922 	{
2923         parseFtnAddrZS(token, &(cb->addr));
2924 	}
2925     else {
2926 	/*  strip trailing "" */
2927 	if (token[0]=='"' && token[strlen(token)-1]=='"') {
2928 	    token++;
2929 	    token[strlen(token)-1]='\0';
2930 	}
2931         /* fc_copyString(token, &(cb->str)); */
2932 	xstrcat(&(cb->str),token);
2933     }
2934 
2935     return 0;
2936 }
2937 
parseCarbonArea(char * token,s_fidoconfig * config,int move)2938 int parseCarbonArea(char *token, s_fidoconfig *config, int move) {
2939 
2940     char *areaName,*reason;
2941     int c=config->carbonCount-1;
2942     s_carbon *cb=&(config->carbons[c]);
2943 
2944     if (token == NULL) {
2945         prErr("Parameters after %s are missing!", actualKeyword);
2946         return 1;
2947     }
2948 
2949     if(!config->carbonCount || (cb->str==NULL && cb->addr.zone==0)){
2950           prErr("No carbon codition specified before %s", actualKeyword);
2951           return 1;
2952    }
2953 
2954     if(cb->move==CC_delete){
2955           prErr("CarbonDelete was specified before %s", actualKeyword);
2956           return 1;
2957    }
2958 
2959     if(cb->extspawn){
2960         prErr("Extspawn was specified before %s", actualKeyword);
2961         return 1;
2962     }
2963 
2964     if(cb->areaName!=NULL){
2965         prErr("CarbonArea already defined before %s", actualKeyword);
2966         return 1;
2967     }
2968 
2969 
2970     fc_copyString(token, &(cb->areaName));
2971     cb->move = move;
2972     _carbonrule=CC_AND;  /* default */
2973     cb->rule&=CC_NOT; /* switch AND off */
2974 
2975     /* checking area*/
2976     /* it is possible to have several groups of expressions and each of them */
2977     /* should have a carbonArea in the last expression */
2978     /* so now the area is known, the previous expressions must be checked */
2979     areaName = cb->areaName;
2980     reason   = cb->reason;
2981 
2982     while(c--){
2983         cb--;
2984         /* this was the end of a previous set expressions */
2985         if(cb->areaName!=NULL)  /* carboncopy, -move or extspawn */
2986             break;
2987         /* this was the end of a previous set expressions */
2988         if(cb->move==CC_delete)         /* carbondelete */
2989             break;
2990         fc_copyString(areaName, &(cb->areaName));
2991         if(reason)
2992         fc_copyString(reason, &(cb->reason));
2993         cb->move = move;
2994     }
2995 
2996     return 0;
2997 }
2998 
parseCarbonDelete(char * token,s_fidoconfig * config)2999 int parseCarbonDelete(char *token, s_fidoconfig *config) {
3000 
3001    unsigned int c=config->carbonCount-1;
3002    s_carbon *cb=&(config->carbons[c]);
3003 
3004    if (token != NULL) {
3005 	   prErr("There are extra parameters after %s!", actualKeyword);
3006 	   return 1;
3007    }
3008 
3009    /*   if (config->carbonCount == 0) {*/
3010    if(config->carbonCount == 0 || (cb->str==NULL && cb->addr.zone==0)){
3011           prErr("No carbon condition specified before %s", actualKeyword);
3012           return 1;
3013    }
3014 
3015    if(cb->extspawn){
3016           prErr("CarbonExtern was specified before %s", actualKeyword);
3017           return 1;
3018    }
3019 
3020    if(cb->areaName!=NULL){
3021           prErr("CarbonArea was specified before %s", actualKeyword);
3022           return 1;
3023    }
3024 
3025    cb->move = CC_delete;
3026    _carbonrule=CC_AND;
3027    cb->rule&=CC_NOT;
3028 
3029    /* checking area*/
3030    /* it is possible to have several groups of expressions and each of them */
3031    /* should have a carbonArea in the last expression */
3032    /* so now the area is known, the previous expressions must be checked */
3033    while(c--){
3034        cb--;
3035        if(cb->areaName!=NULL) /* carboncopy, -move, extern */
3036            break; /* this was the end of a previous set expressions */
3037        if(cb->move==CC_delete) /* delete */
3038            break;
3039        if(!(cb->rule&CC_AND)) /* OR */
3040            cb->move=CC_delete;
3041    }
3042    return 0;
3043 }
3044 
parseCarbonExtern(char * token,s_fidoconfig * config)3045 int parseCarbonExtern(char *token, s_fidoconfig *config) {
3046 
3047     unsigned int c=config->carbonCount-1;
3048     s_carbon *cb=&(config->carbons[c]);
3049 
3050    if (token == NULL) {
3051 	   prErr("Parameters after %s are missing!", actualKeyword);
3052 	   return 1;
3053    }
3054    if(config->carbonCount == 0 || (cb->str==NULL && cb->addr.zone==0)){
3055           prErr("No carbon condition specified before %s", actualKeyword);
3056           return 1;
3057    }
3058 
3059    if(cb->extspawn){
3060           prErr("CarbonExtern was already specified before %s", actualKeyword);
3061           return 1;
3062    }
3063 
3064    if (cb->areaName!= NULL) {
3065        prErr("CarbonArea defined before %s!", actualKeyword);
3066        return 1;
3067    }
3068    if (cb->move==CC_delete) {
3069        prErr("CarbonDelete defined before %s!", actualKeyword);
3070        return 1;
3071    }
3072 
3073    fc_copyString(token, &(cb->areaName));
3074    cb->extspawn = 1;
3075    cb->move = CC_copy;
3076    _carbonrule=CC_AND;
3077    cb->rule&=CC_NOT;
3078 
3079    /* checking area*/
3080    /* it is possible to have several groups of expressions and each of them */
3081    /* should have a carbonArea in the last expression */
3082    /* so now the area is known, the previous expressions must be checked */
3083    while(c--){
3084        cb--;
3085        if(cb->areaName!=NULL) /* carboncopy, -move, extern */
3086            break; /* this was the end of a previous set expressions */
3087        if(cb->move==CC_delete) /* delete */
3088            break;
3089        if(!(cb->rule&CC_AND)){ /* OR */
3090            fc_copyString(token, &(cb->areaName));
3091            cb->extspawn=1;
3092            cb->move=CC_copy;
3093        }
3094    }
3095 
3096    /* +AS+ */
3097    if (tolower(*actualKeyword) == 'n')
3098      cb->netMail = 1;
3099    else
3100      cb->netMail = 0;
3101    /* -AS- */
3102    return 0;
3103 }
3104 
parseCarbonReason(char * token,s_fidoconfig * config)3105 int parseCarbonReason(char *token, s_fidoconfig *config) {
3106 
3107    s_carbon *cb=&(config->carbons[config->carbonCount-1]);
3108    /* I know, when count==0 this will give strange results, but */
3109    /* in that case, cb will not be used */
3110 
3111    if (token == NULL) {
3112 	   prErr("Parameters after %s are missing!", actualKeyword);
3113 	   return 1;
3114    }
3115 
3116    /*   if (config->carbonCount == 0) {*/
3117    if(config->carbonCount == 0 || (cb->str==NULL && cb->addr.zone==0)){
3118           prErr("No carbon condition specified before %s", actualKeyword);
3119           return 1;
3120    }
3121 
3122    fc_copyString(token, &(cb->reason));
3123    return 0;
3124 }
3125 
parseForwardPkts(char * token,s_link * link)3126 int parseForwardPkts(char *token, s_link *link)
3127 {
3128    if (token && stricmp(token, "secure") == 0)
3129      link->forwardPkts = fSecure;
3130    else {
3131      unsigned int bval = link->forwardPkts;
3132      return parseBool(token, &bval);
3133    }
3134 
3135    return 0;
3136 }
3137 
parseAllowEmptyPktPwd(char * token,s_fidoconfig * config,s_link * link)3138 int parseAllowEmptyPktPwd(char *token, s_fidoconfig *config, s_link *link)
3139 {  unsigned t;
3140 
3141    unused(config);
3142 
3143    if (token == NULL) {
3144            prErr("Parameters after %s are missing!", actualKeyword);
3145            return 1;
3146    }
3147 
3148    if (stricmp(token, "secure")==0) link->allowEmptyPktPwd = eSecure;
3149 /*   else if (stricmp(token, "on")==0) link->allowEmptyPktPwd = eOn;*/
3150 /*   else if (stricmp(token, "off")==0) link->allowEmptyPktPwd = eOff;*/
3151    else if( !parseBool (token, &t) ){
3152      if(t) link->allowEmptyPktPwd = eOn;
3153      else  link->allowEmptyPktPwd = eOff;
3154    }else return 2;
3155 
3156    return 0;
3157 }
3158 
parseAllowPktAddrDiffer(char * token,s_fidoconfig * config,s_link * link)3159 int parseAllowPktAddrDiffer(char *token, s_fidoconfig *config, s_link *link)
3160 {
3161 
3162    unused(config);
3163 
3164    if (token == NULL) {
3165 	   prErr("Parameters after %s are missing!", actualKeyword);
3166 	   return 1;
3167    }
3168 
3169    if (stricmp(token, "on")==0) link->allowPktAddrDiffer = pdOn;
3170    else if (stricmp(token, "off")==0) link->allowPktAddrDiffer = pdOff;
3171    else return 2;
3172 
3173    return 0;
3174 }
3175 
parseNodelistFormat(char * token,s_fidoconfig * config,s_nodelist * nodelist)3176 int parseNodelistFormat(char *token, s_fidoconfig *config, s_nodelist *nodelist)
3177 {
3178   char *iToken;
3179 
3180   unused(config);
3181 
3182   if (token  == NULL) {
3183     prErr("Parameters after %s are missing!", actualKeyword);
3184     return 1;
3185   }
3186 
3187   iToken = strLower(sstrdup(token));
3188   if ((strcmp(iToken, "fts5000") == 0) || (strcmp(iToken, "standard") == 0))
3189     nodelist->format = fts5000;
3190   else if (strcmp(iToken, "points24") == 0)
3191     nodelist->format = points24;
3192   else if (strcmp(iToken, "points4d") == 0)
3193     nodelist->format = points4d;
3194   else {
3195     nfree(iToken);
3196     return 2;
3197   }
3198 
3199   nfree(iToken);
3200   return 0;
3201 }
3202 
parseTypeDupes(char * line,e_typeDupeCheck * typeDupeBase,unsigned * DayAge)3203 int parseTypeDupes(char *line, e_typeDupeCheck *typeDupeBase, unsigned *DayAge)
3204 {
3205   char *iLine;
3206 
3207   if (line == NULL) {
3208     prErr("A parameter after %s is missing!", actualKeyword);
3209     return 1;
3210   }
3211 
3212   iLine = strLower(sstrdup(line));
3213   if (strcmp(iLine, "textdupes")==0) *typeDupeBase = textDupes;
3214   else if (strcmp(iLine, "hashdupes")==0) *typeDupeBase = hashDupes;
3215   else if (strcmp(iLine, "hashdupeswmsgid")==0) *typeDupeBase = hashDupesWmsgid;
3216   else if (strcmp(iLine, "commondupebase")==0) {
3217     *typeDupeBase = commonDupeBase;
3218     if (*DayAge==0) *DayAge=(unsigned) 5;
3219   }
3220   else {
3221     prErr("Unknown type base of dupes %s!", line);
3222     nfree(iLine);
3223     return 2;
3224   }
3225   nfree(iLine);
3226   return 0;
3227 }
3228 
3229 
parseSaveTic(const s_fidoconfig * config,char * token,s_savetic * savetic)3230 int parseSaveTic(const s_fidoconfig *config, char *token, s_savetic *savetic)
3231 {
3232     char *tok;
3233     int rc;
3234 
3235     unused(config);
3236 
3237     if (token == NULL) {
3238         prErr("Parameters after %s are missing!", actualKeyword);
3239         return 1;
3240     }
3241 
3242     memset(savetic, 0, sizeof(s_savetic));
3243 
3244     tok = strtok(token, " \t");
3245     if (tok == NULL) {
3246         prErr("An areaname mask after %s is missing!", actualKeyword);
3247         return 1;         /* if there is no areaname mask */
3248     }
3249 
3250     savetic->fileAreaNameMask = sstrdup(tok);
3251 
3252     tok = strtok(NULL, " \t");
3253 
3254     if (tok == NULL) {
3255         prErr("Parameters after %s are missing!", token);
3256         return 1;
3257     }
3258 
3259 
3260     if(*tok == '-')
3261     {
3262         if       (tok[1] == 'l')
3263             savetic->fileAction = 2;
3264         else if  (tok[1] == 'c')
3265             savetic->fileAction = 1;
3266         tok = strtok(NULL, " \t");
3267     }
3268 
3269 
3270     rc = parsePath(tok, &savetic->pathName, NULL);
3271     if(rc==0) {
3272         tok = strtok(NULL, " \t");
3273         if (tok) {
3274             parseNumber(tok, 10, &(savetic->days2save));
3275         }
3276     }
3277     return rc;
3278 }
3279 
parseSaveTicStatement(char * token,s_fidoconfig * config)3280 int parseSaveTicStatement(char *token, s_fidoconfig *config)
3281 {
3282    int rc;
3283 
3284    if (token == NULL) {
3285       prErr("Parameters after %s are missing!", actualKeyword);
3286       return 1;
3287    }
3288 
3289    config->saveTic = srealloc(config->saveTic,sizeof(s_savetic)*(config->saveTicCount+1));
3290    rc = parseSaveTic(config, token,&(config->saveTic[config->saveTicCount]));
3291    config->saveTicCount++;
3292    return rc;
3293 }
3294 
parseExecOnFile(char * line,s_fidoconfig * config)3295 int parseExecOnFile(char *line, s_fidoconfig *config) {
3296    char   *a, *f, *c;
3297    s_execonfile *execonfile;
3298 
3299    if (line == NULL) {
3300       prErr("A parameter after %s is missing!", actualKeyword);
3301       return 1;
3302    }
3303 
3304    a = strtok(line, " \t");
3305    f = strtok(NULL, " \t");
3306    c = getRestOfLine();
3307    if ((a != NULL) && (f != NULL) && (c != NULL)) {
3308 
3309       /*  add new execonfile statement */
3310       config->execonfileCount++;
3311       config->execonfile = srealloc(config->execonfile, config->execonfileCount * sizeof(s_execonfile));
3312 
3313       /*  fill new execonfile statement */
3314       execonfile = &(config->execonfile[config->execonfileCount-1]);
3315       execonfile->filearea = (char *) smalloc(strlen(a)+1);
3316       strcpy(execonfile->filearea, a);
3317       execonfile->filename = (char *) smalloc(strlen(f)+1);
3318       strcpy(execonfile->filename, f);
3319       execonfile->command = (char *) smalloc(strlen(c)+1);
3320       strcpy(execonfile->command, c);
3321       return 0;
3322 
3323    } else {
3324       prErr("A parameter after %s is missing!", actualKeyword);
3325       return 1;
3326    }
3327 }
3328 
printNodelistError(void)3329 void printNodelistError(void)
3330 {
3331   prErr("You must define a nodelist first before you use %s!", actualKeyword);
3332 }
3333 
parseLinkDefaults(char * token,s_fidoconfig * config)3334 int parseLinkDefaults(char *token, s_fidoconfig *config)
3335 {
3336 
3337    if (token==NULL) {
3338       config->describeLinkDefaults = 1;
3339    } else {
3340 
3341 	   if (stricmp(token, "begin")==0) config->describeLinkDefaults = 1;
3342        else if (stricmp(token, "end")==0) config->describeLinkDefaults = 0;
3343        else if (stricmp(token, "destroy")==0) {
3344 		   config->describeLinkDefaults = 0;
3345 		   freeLink(config->linkDefaults);
3346 		   config->linkDefaults = NULL;
3347        }
3348        else return 2;
3349    }
3350 
3351    if (config->describeLinkDefaults && config->linkDefaults==NULL) {
3352 
3353       config->linkDefaults = scalloc(1, sizeof(s_link));
3354 
3355       /*  Set defaults like in parseLink() */
3356 
3357       /*  set areafix default to on */
3358       config->linkDefaults->areafix.on = 1;
3359       config->linkDefaults->filefix.on = 1;
3360 
3361       /*  set defaults to export, import, mandatory (0), manual (0) */
3362       config->linkDefaults->aexport = 1;
3363       config->linkDefaults->import = 1;
3364       config->linkDefaults->ourAka = &(config->addr[0]);
3365 
3366       /*  set defaults maxUnpackedNetmail */
3367       config->linkDefaults->maxUnpackedNetmail = 100;
3368       config->linkDefaults->dailyBundles = config->dailyBundles;
3369 
3370       /*  set FileFixFSC87Subset default to on */
3371       config->linkDefaults->FileFixFSC87Subset = 1;
3372    }
3373 
3374    memset(&linkDefined, 0, sizeof(linkDefined));
3375    return 0;
3376 }
3377 
parseNamesCase(char * line,e_nameCase * value)3378 int parseNamesCase(char *line, e_nameCase *value)
3379 {
3380    if (line == NULL) {
3381       prErr("A parameter after %s is missing!", actualKeyword);
3382       return 1;
3383    }
3384 
3385    if (stricmp(line, "lower") == 0) *value = eLower;
3386    else if (stricmp(line, "upper") == 0) *value = eUpper;
3387    else {
3388       prErr("Unknown case parameter %s!", line);
3389       return 2;
3390    }
3391    return 0;
3392 }
3393 
parseNamesCaseConversion(char * line,e_nameCaseConvertion * value)3394 int parseNamesCaseConversion(char *line, e_nameCaseConvertion *value)
3395 {
3396   char *iLine;
3397 
3398   if (line == NULL) {
3399     prErr("A parameter after %s is missing!", actualKeyword);
3400     return 1;
3401   }
3402 
3403   iLine = strLower(sstrdup(line));
3404   if (strcmp(iLine, "lower") == 0) *value = cLower;
3405   else if (strcmp(iLine, "upper") == 0) *value = cUpper;
3406   else if (strcmp(iLine, "dont") == 0) *value = cDontTouch;
3407   else if (strcmp(iLine, "donttouch") == 0) *value = cDontTouch;
3408   else if (strcmp(iLine, "same") == 0) *value = cDontTouch;
3409   else {
3410     prErr("Unknown case convertion parameter %s!", line);
3411     nfree(iLine);
3412     return 2;
3413   }
3414   nfree(iLine);
3415   return 0;
3416 }
3417 
parseBundleNameStyle(char * line,e_bundleFileNameStyle * value)3418 int parseBundleNameStyle(char *line, e_bundleFileNameStyle *value)
3419 {
3420   char *iLine;
3421 
3422   if (line == NULL) {
3423     prErr("A parameter after %s is missing!", actualKeyword);
3424     return 1;
3425   }
3426 
3427   iLine = strLower(sstrdup(line));
3428   if (strcmp(iLine, "addrdiff") == 0) *value = eAddrDiff;
3429   else if (strcmp(iLine, "addrdiffalways") == 0) *value = eAddrDiffAlways;
3430   else if (strcmp(iLine, "timestamp") == 0) *value = eTimeStamp;
3431   else if (strcmp(iLine, "amiga") == 0) *value = eAmiga;
3432   else if (strcmp(iLine, "addrscrc32") == 0) *value = eAddrsCRC32;
3433   else if (strcmp(iLine, "addrscrc32always") == 0) *value = eAddrsCRC32Always;
3434   else {
3435     prErr("Unknown bundle name style %s!", line);
3436     nfree(iLine);
3437     return 2;
3438   }
3439   nfree(iLine);
3440   return 0;
3441 }
3442 
parseLinkWithILogType(char * line,e_linkWithImportLog * value)3443 int parseLinkWithILogType(char *line, e_linkWithImportLog *value)
3444 {
3445   char *iLine;
3446 
3447   if (line == NULL) {
3448     prErr("A parameter after %s is missing!", actualKeyword);
3449     return 1;
3450   }
3451 
3452   if (*value) {
3453     prErr("LinkWithImportLog redefinition");
3454     return 2;
3455   }
3456 
3457   iLine = strLower(sstrdup(line));
3458   striptwhite(iLine);
3459   if (strcmp(iLine, "yes") == 0) *value = lwiYes;
3460   else if (strcmp(iLine, "no") == 0) *value = lwiNo;
3461   else if (strcmp(iLine, "kill") == 0) *value = lwiKill;
3462   else {
3463     prErr("Unknown LinkWithImportLog value %s!", line);
3464     nfree(iLine);
3465     return 2;
3466    }
3467   nfree(iLine);
3468   return 0;
3469 }
3470 
parseKludgeAreaNetmailType(char * line,e_kludgeAreaNetmail * value)3471 int parseKludgeAreaNetmailType(char *line, e_kludgeAreaNetmail *value)
3472 {
3473   char *iLine;
3474 
3475   if (line == NULL) {
3476 	  prErr("A parameter after %s is missing!", actualKeyword);
3477 	  return 1;
3478   }
3479 
3480   if (*value) {
3481 	  prErr("kludgeAreaNetmail redefinition");
3482 	  return 2;
3483   }
3484 
3485   iLine = strLower(sstrdup(line));
3486   if (strcmp(iLine, "kill") == 0) *value = kanKill;
3487   else if (strcmp(iLine, "ignore") == 0) *value = kanIgnore;
3488   else if (strcmp(iLine, "echomail") == 0) *value = kanEcho;
3489   else {
3490 	  prErr("Unknown klugdeAreaNetmail value %s!", line);
3491 	  nfree(iLine);
3492 	  return 2;
3493   }
3494   nfree(iLine);
3495   return 0;
3496 }
3497 
parseSendMailCmd(char * line,char ** sendMailCmd)3498 int parseSendMailCmd( char *line, char **sendMailCmd )
3499 {
3500   if (!line)
3501   {
3502     prErr("A parameter after %s is missing!", actualKeyword);
3503     return 1;
3504   }
3505 
3506   if (*sendMailCmd) {
3507     prErr("sendMailCmd redefinition!");
3508     return 2;
3509   }
3510 
3511   *sendMailCmd = sstrdup(line);
3512   return 0;
3513 }
3514 
parseEmailEncoding(char * line,e_emailEncoding * value)3515 int parseEmailEncoding(char *line, e_emailEncoding *value)
3516 {
3517   char *iLine;
3518 
3519   if (line == NULL)
3520   {
3521     prErr("A parameter after %s is missing!", actualKeyword);
3522     return 1;
3523   }
3524 
3525   iLine = strLower(sstrdup(line));
3526   if (strcmp(iLine, "uue") == 0) *value = eeUUE;
3527   else if (strcmp(iLine, "mime") == 0) *value = eeMIME;
3528   else if (strcmp(iLine, "seat") == 0) *value = eeSEAT;
3529   else
3530   {
3531     prErr("Unknown email encoding parameter %s!", line);
3532     nfree(iLine);
3533     return 2;
3534   }
3535   nfree(iLine);
3536   return 0;
3537 }
3538 
3539 /*  options: <flType> <destFile> <dirHdrTpl> <dirEntryTpl> <dirFtrTpl> [<globHdrTpl> <globFtrTpl>] */
parseFilelist(char * line,s_fidoconfig * config)3540 int parseFilelist(char *line, s_fidoconfig *config)
3541 {
3542   char *lineTmp;
3543   s_filelist *curFl;
3544   char *flType = NULL;
3545   unsigned int numCopied;
3546 
3547   if (line == NULL) {
3548      prErr("Parameters after %s are missing!", actualKeyword);
3549      return 1;
3550   }
3551 
3552   /*  add new template */
3553   config->filelistCount++;
3554   config->filelists = realloc(config->filelists, config->filelistCount * sizeof(s_filelist));
3555   curFl = &config->filelists[config->filelistCount - 1];
3556   memset(curFl, 0, sizeof(s_filelist));
3557 
3558   /*  parse type */
3559   numCopied = copyStringUntilSep(line, " ", &flType);
3560   if (!numCopied) return 1;
3561   strLower(flType);
3562 
3563   if (!strcmp(flType, "dir")) curFl->flType = flDir;
3564   else if (!strcmp(flType, "global")) curFl->flType = flGlobal;
3565   else if (!strcmp(flType, "dirlist")) curFl->flType = flDirList;
3566   else
3567   {
3568     prErr("Unknown filelist type %s!", flType);
3569     nfree(flType);
3570     return 2;
3571   }
3572   nfree(flType);
3573 
3574   /*  parse destFile */
3575   lineTmp = line + numCopied;
3576   if (*lineTmp) lineTmp++;
3577   numCopied = copyStringUntilSep(lineTmp, " ", &(curFl->destFile));
3578   if (!numCopied) return 1;
3579 
3580   if ((curFl->flType == flDir) || (curFl->flType == flGlobal))
3581   {
3582     /*  parse dirHdrTpl */
3583     lineTmp += numCopied;
3584     if (*lineTmp) lineTmp++;
3585     numCopied = copyStringUntilSep(lineTmp, " ", &(curFl->dirHdrTpl));
3586     if (!numCopied) return 1;
3587 
3588     /*  parse dirEntryTpl */
3589     lineTmp += numCopied;
3590     if (*lineTmp) lineTmp++;
3591     numCopied = copyStringUntilSep(lineTmp, " ", &(curFl->dirEntryTpl));
3592     if (!numCopied) return 1;
3593 
3594     /*  parse dirFtrTpl */
3595     lineTmp += numCopied;
3596     if (*lineTmp) lineTmp++;
3597     numCopied = copyStringUntilSep(lineTmp, " ", &(curFl->dirFtrTpl));
3598     if (!numCopied) return 1;
3599   }
3600 
3601   switch (curFl->flType)
3602   {
3603   case flGlobal:
3604     /*  parse globHdrTpl */
3605     lineTmp += numCopied;
3606     if (*lineTmp) lineTmp++;
3607     numCopied = copyStringUntilSep(lineTmp, " ", &(curFl->globHdrTpl));
3608     if (!numCopied) return 1;
3609 
3610     /*  parse globFtrTpl */
3611     lineTmp += numCopied;
3612     if (*lineTmp) lineTmp++;
3613     numCopied = copyStringUntilSep(lineTmp, " ", &(curFl->globFtrTpl));
3614     if (!numCopied) return 1;
3615     break;
3616 
3617   case flDirList:
3618     /*  parse dirListHdrTpl */
3619     lineTmp += numCopied;
3620     if (*lineTmp) lineTmp++;
3621     numCopied = copyStringUntilSep(lineTmp, " ", &(curFl->dirListHdrTpl));
3622     if (!numCopied) return 1;
3623 
3624     /*  parse dirListEntryTpl */
3625     lineTmp += numCopied;
3626     if (*lineTmp) lineTmp++;
3627     numCopied = copyStringUntilSep(lineTmp, " ", &(curFl->dirListEntryTpl));
3628     if (!numCopied) return 1;
3629 
3630     /*  parse dirListFtrTpl */
3631     lineTmp += numCopied;
3632     if (*lineTmp) lineTmp++;
3633     numCopied = copyStringUntilSep(lineTmp, " ", &(curFl->dirListFtrTpl));
3634     if (!numCopied) return 1;
3635     break;
3636 
3637   case flDir:
3638   default:
3639     /*  just avoid a warning */
3640     break;
3641   }
3642 
3643   return 0;
3644 }
3645 
parseSyslog(char * line,int * value)3646 int parseSyslog(char *line, int *value)
3647 {
3648     int rv=0;
3649 
3650 #ifndef HAVE_SYSLOG
3651     prErr("%s: Syslogging is not supported on your platform!", actualKeyword);
3652     rv=1;
3653     unused(line);
3654     unused(value);
3655 
3656 #else
3657 #   include <huskylib/syslogp.h>
3658     int i;
3659 
3660     if (line == NULL || line[0] == '\0') {
3661         prErr("A parameter after %s is missing!", actualKeyword);
3662         return 1;
3663     }
3664 
3665     if (isdigit(line[0]))
3666     {
3667         *value = atoi(line);
3668     }
3669     else
3670     {
3671 
3672                /* | if you get an error about undefined symbol "facilitynames"
3673                   | add your operating system after "sun" to the ifdef line
3674                   | in syslogp.h which comes below the
3675                   | "unix systems that have syslog, but not facilitynames"
3676                   | comment
3677                   V          */
3678         for (i = 0; facilitynames[i].c_name != NULL; i++)
3679         {
3680             if (!strcmp(line, facilitynames[i].c_name))
3681             {
3682                 *value = facilitynames[i].c_val;
3683                 break;
3684             }
3685         }
3686 
3687         if (facilitynames[i].c_name == NULL)
3688         {
3689             prErr("%s: %s is an unknown syslog facility on this system.",
3690                   actualKeyword, line);
3691             rv=1;
3692         }
3693     }
3694 #endif
3695   return rv;
3696 }
3697 
3698 
3699 /* Parse additional option tokens like ReadOnly/WriteOnly */
3700 
parsePermissions(char * line,s_permissions ** perm,unsigned int * permCount)3701 int parsePermissions (char *line,  s_permissions **perm, unsigned int *permCount)
3702 {
3703     char *ptr;
3704 
3705     if (line == NULL) {
3706 	prErr("A parameter after %s is missing!", actualKeyword);
3707 	return 1;
3708     }
3709 
3710     *perm = srealloc (*perm, (*permCount + 1) * sizeof(s_permissions));
3711 
3712     if ((ptr = strtok(line, " \t")) == NULL) {
3713 	prErr("An AddressMask in %s is missing!", actualKeyword);
3714 	return 1;
3715     }
3716 
3717     (*perm)[*permCount].addrMask = strdup (ptr);
3718 
3719     if ((ptr = strtok(NULL, " \t")) == NULL) {
3720 	prErr("An AreaMask in %s is missing!", actualKeyword);
3721 	return 1;
3722     }
3723 
3724     (*perm)[*permCount].areaMask = strdup (ptr);
3725 
3726     (*permCount)++;
3727 
3728     if (strtok(NULL, " \t") != NULL) {
3729         prErr("Extra parameters in %s", actualLine);
3730         return 1;
3731     }
3732 
3733     return 0;
3734 }
3735 
parseSeqOutrun(char * line,unsigned long * seqoutrun)3736 int parseSeqOutrun(char *line, unsigned long *seqoutrun)
3737 {
3738     char *p;
3739 
3740     if (line == NULL) {
3741        prErr("Parameters after %s are missing!", actualKeyword);
3742        return 1;
3743     }
3744 
3745     while (isspace(*line)) line++;
3746     if (!isdigit(*line)) {
3747 	prErr("Bad SeqOutrun value %s", line);
3748 	return 1;
3749     }
3750     *seqoutrun = (unsigned long)atol(line);
3751     p = line;
3752     while (isdigit(*p)) p++;
3753     if (*p == '\0') return 0;
3754     if (p[1]) {
3755 	prErr("Bad SeqOutrun value %s", line);
3756 	return 1;
3757     }
3758     switch (tolower(*p)) {
3759 	case 'y':	*seqoutrun *= 365;
3760 	case 'd':	*seqoutrun *= 24;
3761 	case 'h':	*seqoutrun *= 60*60;
3762 			break;
3763 	case 'w':	*seqoutrun *= 7l*24*60*60;
3764 			break;
3765 	case 'm':	*seqoutrun *= 31l*24*60*60;
3766 			break;
3767 	default:	prErr("Bad SeqOutrun value %s", line);
3768 			return 1;
3769     }
3770     return 0;
3771 }
3772 
3773 
3774 /* Parse the 'AvailList' token value
3775  */
parseAvailList(char * line,eAvailList * availlist)3776 int parseAvailList(char *line, eAvailList *availlist)
3777 {
3778   char *iLine;
3779 
3780   if (line == NULL)
3781   {
3782     prErr("A parameter after %s is missing!", actualKeyword);
3783     return 1;
3784   }
3785 
3786   iLine = strLower(sstrdup(line));
3787   if (stricmp(iLine, "full") == 0)           *availlist = AVAILLIST_FULL;
3788   else if (stricmp(iLine, "unique") == 0)    *availlist = AVAILLIST_UNIQUE;
3789   else if (stricmp(iLine, "uniqueone") == 0) *availlist = AVAILLIST_UNIQUEONE;
3790   else
3791   {
3792     prErr("Unknown AvailList value %s!", line);
3793     nfree(iLine);
3794     return 1;
3795   }
3796   nfree(iLine);
3797   return 0;
3798 }
3799 
3800 /* parse group description */
parseGroupDesc(s_fidoconfig * config,char * line)3801 int parseGroupDesc(s_fidoconfig *config, char *line) {
3802   char *n, *d;
3803   register char *s = line;
3804   register short l;
3805   register unsigned short i;
3806   /* parse line */
3807   while (*s && (*s == ' ' || *s == '\t')) s++;
3808   if (*s == '\0') { prErr("Missing group name, line %d!", actualLineNr); return 1; }
3809   n = s;
3810   while (*s && (*s != ' ' && *s != '\t')) s++;
3811   if (*n == '"' && *(s-1) == '"') { n++; *(s-1) = '\0'; }
3812   if (*s) { *s = '\0'; s++; }
3813   while (*s && (*s == ' ' || *s == '\t')) s++;
3814   if (*s == '\0') { prErr("Missing group description, line %d!", actualLineNr); return 1; }
3815   l = strlen(s) - 1;
3816   while (l > 0 && (s[l] == ' ' || s[l] == '\t')) l--;
3817   if (l <= 0) { prErr("Missing group description, line %d!", actualLineNr); return 1; }
3818   s[l+1] = '\0';
3819   /* create a new group record */
3820   for (i = 0; i <= config->groupCount; i++) {
3821     if (i == config->groupCount) {
3822       config->groupCount++;
3823       config->group = srealloc(config->group, sizeof(s_group)*config->groupCount);
3824       config->group[i].name = sstrdup(n);
3825       break;
3826     }
3827     else if ( strcmp(config->group[i].name, n) == 0 )  {
3828       nfree(config->group[i].desc);
3829       break;
3830     }
3831   }
3832   /* make group desc */
3833   if (*s != '"') { config->group[i].desc = sstrdup(s); return 0; }
3834   else {
3835     d = smalloc(l); s++; l = 0;
3836     for (;;)
3837     {
3838       if (*s == '"') { d[l++] = '\0'; break; }
3839       if (*s != '\\' || (*s == '\\' && *(s+1) == '\0')) d[l++] = *s;
3840       else switch (*(++s)) {
3841         case '"': d[l++] = '"'; break;
3842         case 'n': d[l++] = '\n'; break;
3843         case 'r': d[l++] = '\r'; break;
3844         case 't': d[l++] = '\t'; break;
3845         default : d[l++] = *s;
3846       }
3847       if (*s == '\0') break; else s++;
3848     };
3849     config->group[i].desc = d;
3850   }
3851   return 0;
3852 }
3853 
3854 /* parse SoftEchoList <none|name|group|group,name> */
parseListEcho(char * line,e_listEchoMode * value)3855 int parseListEcho(char *line, e_listEchoMode *value) {
3856   char *iLine;
3857 
3858   if (line == NULL) {
3859 	  prErr("A parameter after %s is missing!", actualKeyword);
3860 	  return 1;
3861   }
3862 
3863   if (*value) {
3864 	  prErr("%s redefinition", actualKeyword);
3865 	  return 2;
3866   }
3867 
3868   iLine = strLower(sstrdup(line));
3869   if (strcmp(iLine, "none") == 0) *value = lemUnsorted;
3870   else if (strcmp(iLine, "name") == 0) *value = lemName;
3871   else if (strcmp(iLine, "group") == 0) *value = lemGroup;
3872   else if (strcmp(iLine, "group,name") == 0) *value = lemGroupName;
3873   else {
3874 	  prErr("Unknown %s value %s!", actualKeyword, line);
3875 	  nfree(iLine);
3876 	  return 2;
3877   }
3878   nfree(iLine);
3879   return 0;
3880 }
3881 
3882 
3883 /* Parse fidoconfig line
3884  * Return 0 if success.
3885  */
parseLine(char * line,s_fidoconfig * config)3886 int parseLine(char *line, s_fidoconfig *config)
3887 {
3888     char *token, *temp, *s;
3889     char *iToken;
3890     int rc = 0, id;
3891     s_link   *clink = NULL;
3892     int link_robot = -1;
3893     static token_list_t tl;
3894     static token_list_t *ptl = NULL;
3895 
3896     temp = (char *) smalloc(strlen(line)+1);
3897     strcpy(temp, line);
3898     actualLine = temp = vars_expand(temp);
3899 
3900     if (ptl == NULL)
3901     {
3902         ptl = &tl;
3903         make_token_list(ptl, parseline_tokens);
3904     }
3905 
3906     actualKeyword = token = strtok(temp, " \t");
3907 
3908     /* printf("Parsing: %s\n", line);
3909        printf("token: %s - %s\n", line, strtok(NULL, "\0")); */
3910 
3911     if (token)
3912     {
3913         iToken = strLower(sstrdup(token));
3914 
3915         id = find_token(ptl, iToken);
3916         /* val: handle ^(area|file)fix.* */
3917         if (id == -1) {
3918           link_robot =   (!strnicmp(iToken, "areafix", 7) << 0)
3919                        | (!strnicmp(iToken, "filefix", 7) << 1);
3920           if (link_robot) id = find_token(ptl, iToken + 7);
3921         }
3922 
3923         switch (id)
3924         {
3925         case ID_VERSION:
3926             rc = parseVersion(getRestOfLine(), config);
3927             break;
3928         case ID_NAME:
3929             if (link_robot == 1 || link_robot == 2) {
3930               clink = getDescrLink(config);
3931               if (clink) {
3932                 if (link_robot == 1)
3933                     fc_copyString(getRestOfLine(), &(clink->areafix.name));
3934                 else
3935                     fc_copyString(getRestOfLine(), &(clink->filefix.name));
3936               }
3937             }
3938             else
3939               rc = fc_copyString(getRestOfLine(), &(config->name));
3940             break;
3941         case ID_LOCATION:
3942             rc = fc_copyString(getRestOfLine(), &(config->location));
3943             break;
3944         case ID_SYSOP:
3945             rc = fc_copyString(getRestOfLine(), &(config->sysop));
3946             break;
3947         case ID_ADDRESS:
3948             rc = parseAddress(getRestOfLine(), config);
3949             break;
3950         case ID_INBOUND:
3951             rc = parsePath(getRestOfLine(), &(config->inbound), NULL);
3952             break;
3953         case ID_PROTINBOUND:
3954             rc = parsePath(getRestOfLine(), &(config->protInbound), NULL);
3955             break;
3956         case ID_LISTINBOUND:
3957             rc = parsePath(getRestOfLine(), &(config->listInbound), NULL);
3958             break;
3959         case ID_LOCALINBOUND:
3960             rc= parsePath(getRestOfLine(), &(config->localInbound), NULL);
3961             break;
3962         case ID_TEMPINBOUND:
3963             rc= parsePath(getRestOfLine(), &(config->tempInbound), NULL);
3964             break;
3965         case ID_OUTBOUND:
3966             rc = parsePath(getRestOfLine(), &(config->outbound), NULL);
3967             break;
3968         case ID_TICOUTBOUND:
3969             rc = parsePath(getRestOfLine(), &(config->ticOutbound), NULL);
3970             break;
3971         case ID_PUBLIC:
3972             rc = parsePublic(getRestOfLine(), config);
3973             break;
3974         case ID_LOGFILEDIR:
3975             rc = parsePath(getRestOfLine(), &(config->logFileDir), NULL);
3976             break;
3977         case ID_DUPEHISTORYDIR:
3978             rc = parsePath(getRestOfLine(), &(config->dupeHistoryDir), NULL);
3979             break;
3980         case ID_NODELISTDIR:
3981             rc = parsePath(getRestOfLine(), &(config->nodelistDir), NULL);
3982             break;
3983         case ID_FILEAREABASEDIR:
3984             rc = parseAreaPath(getRestOfLine(), &(config->fileAreaBaseDir), NULL);
3985             break;
3986         case ID_PASSFILEAREADIR:
3987             rc = parseAreaPath(getRestOfLine(), &(config->passFileAreaDir), NULL);
3988             break;
3989         case ID_BUSYFILEDIR:
3990             rc = parsePath(getRestOfLine(), &(config->busyFileDir), NULL);
3991             break;
3992         case ID_MSGBASEDIR:
3993             rc = parseAreaPathExpand(getRestOfLine(), &(config->msgBaseDir), NULL);
3994             break;
3995         case ID_LINKMSGBASEDIR:
3996             rc = parseAreaPathExpand(getRestOfLine(),
3997                            &(getDescrLink(config)->areafix.baseDir),
3998 			   &(linkDefined.areafix.baseDir));
3999             break;
4000         case ID_LINKFILEBASEDIR:
4001             rc = parseAreaPath(getRestOfLine(),
4002                            &(getDescrLink(config)->filefix.baseDir),
4003 			   &(linkDefined.filefix.baseDir));
4004             break;
4005 
4006         case ID_MAGIC:
4007             rc = parsePath(getRestOfLine(), &(config->magic), NULL);
4008             break;
4009         case ID_SEMADIR:
4010             rc = parsePath(getRestOfLine(), &(config->semaDir), NULL);
4011             break;
4012         case ID_BADFILESDIR:
4013             rc = parsePath(getRestOfLine(), &(config->badFilesDir), NULL);
4014             break;
4015         case ID_NETMAILAREA:
4016         case ID_NETAREA:
4017             rc = parseNetMailArea(getRestOfLine(), config);
4018             break;
4019         case ID_DUPEAREA:
4020             rc = parseArea(config, getRestOfLine(), &(config->dupeArea), 1);
4021             break;
4022         case ID_BADAREA:
4023             rc = parseArea(config, getRestOfLine(), &(config->badArea), 1);
4024             break;
4025         case ID_ECHOAREADEFAULT:
4026             rc = parseAreaDefault(config, getRestOfLine(), &(config->EchoAreaDefault), 1);
4027             break;
4028         case ID_FILEAREADEFAULT:
4029             rc = parseAreaDefault(config, getRestOfLine(), &(config->FileAreaDefault),1);
4030             break;
4031         case ID_ECHOAREA:
4032             rc = parseEchoArea(getRestOfLine(), config);
4033             break;
4034         case ID_FILEAREA:
4035             rc = parseFileArea(getRestOfLine(), config);
4036             break;
4037         case ID_BBSAREA:
4038             rc = parseBbsAreaStatement(getRestOfLine(), config);
4039             break;
4040         case ID_LOCALAREA:
4041             rc = parseLocalArea(getRestOfLine(), config);
4042             break;
4043         case ID_REMAP:
4044             rc = parseRemap(getRestOfLine(),config);
4045             break;
4046         case ID_LINK:
4047             rc = parseLink(getRestOfLine(), config);
4048             if (rc)
4049             {
4050                 exit(EX_CONFIG); /* 'cause of parsing aka and overriding prev. aka */
4051             }
4052             break;
4053         case ID_PASSWORD:
4054             if( (clink = getDescrLink(config)) != NULL ) {
4055                 rc = parsePWD(getRestOfLine(), &clink->defaultPwd);
4056                 /* this way used because of redefinition   */
4057                 /* defaultPwd from linkdefaults (if exist) */
4058                 clink->pktPwd = clink->defaultPwd;
4059                 clink->ticPwd = clink->defaultPwd;
4060                 clink->areafix.pwd = clink->defaultPwd;
4061                 clink->filefix.pwd = clink->defaultPwd;
4062                 clink->bbsPwd = clink->defaultPwd;
4063                 clink->sessionPwd = clink->defaultPwd;
4064             } else {
4065                 rc = 1;
4066             }
4067             break;
4068         case ID_AKA:
4069             if ((clink = getDescrLink(config)) != NULL ) {
4070                 parseFtnAddrZS(getRestOfLine(), &clink->hisAka);
4071             }
4072             else {
4073                 rc = 1;
4074             }
4075             break;
4076         case ID_OURAKA:
4077             rc = 0;
4078             if( (clink = getDescrLink(config)) != NULL ) {
4079                 char *l = getRestOfLine();
4080                 clink->ourAka = getAddr(config, l);
4081                 if (clink->ourAka == NULL) {
4082                   prErr( "Address %s is not our aka!", l );
4083                   rc = 2;
4084                 }
4085             } else {
4086                 rc = 1;
4087             }
4088             break;
4089         case ID_PACKAKA:
4090             rc = 0;
4091             if((clink = getDescrLink(config)) != NULL)
4092             {
4093                 parseFtnAddrZS(getRestOfLine(), &clink->hisPackAka);
4094             }
4095             else
4096               rc = 1;
4097             break;
4098         case ID_AUTOCREATE:
4099             if( (clink = getDescrLink(config)) != NULL ) {
4100                 s = getRestOfLine();
4101                 if (link_robot & 1)
4102                   rc |= parseBool (s, &clink->areafix.autoCreate);
4103                 if (link_robot & 2)
4104                   rc |= parseBool (s, &clink->filefix.autoCreate);
4105             } else {
4106                 rc = 1;
4107             }
4108             break;
4109 	    case ID_FILEFIXFSC87SUBSET:
4110 	        if( (clink = getDescrLink(config)) != NULL ) {
4111                 rc = parseBool (getRestOfLine(), &clink->FileFixFSC87Subset);
4112 	        } else {
4113                 rc = 1;
4114 	        }
4115             break;
4116         case ID_FORWARDREQUESTS:
4117             if( (clink = getDescrLink(config)) != NULL ) {
4118                 s = getRestOfLine();
4119                 if (link_robot & 1)
4120                     rc = parseBool (s, &clink->areafix.forwardRequests);
4121                 if (link_robot & 2)
4122                     rc = parseBool (s, &clink->filefix.forwardRequests);
4123             } else {
4124                 rc = 1;
4125             }
4126             break;
4127         case ID_AUTOSUBSCRIBE:
4128             if( (clink = getDescrLink(config)) != NULL ) {
4129                 s = getRestOfLine();
4130                 if (link_robot & 1)
4131                     rc = parseBool (s, &clink->areafix.autoSubscribe);
4132                 if (link_robot & 2)
4133                     rc = parseBool (s, &clink->filefix.autoSubscribe);
4134             } else {
4135                 rc = 1;
4136             }
4137             break;
4138 		case ID_DENYFWDREQACCESS:
4139             if( (clink = getDescrLink(config)) != NULL ) {
4140               s = getRestOfLine();
4141               if (link_robot & 1)
4142                 rc = parseBool (s, &clink->areafix.denyFRA);
4143               if (link_robot & 2)
4144                 rc = parseBool (s, &clink->filefix.denyFRA);
4145             } else rc = 1;
4146             break;
4147         case ID_FORWARDPKTS:
4148             if( (clink = getDescrLink(config)) != NULL ) {
4149                 rc = parseForwardPkts(getRestOfLine(), clink);
4150             }
4151             else {
4152                 rc = 1;
4153             }
4154             break;
4155         case ID_ALLOWEMPTYPKTPWD:
4156             if( (clink = getDescrLink(config)) != NULL ) {
4157                 rc = parseAllowEmptyPktPwd(getRestOfLine(), config, clink);
4158             }
4159             else {
4160                 rc = 1;
4161             }
4162             break;
4163         case ID_PACKNETMAIL:
4164             if( (clink = getDescrLink(config)) != NULL ) {
4165                 rc = parseBool(getRestOfLine(), &clink->packNetmail);
4166             }
4167             else rc = 1;
4168             break;
4169         case ID_SENDNOTIFYMESSAGES:
4170             if( (clink = getDescrLink(config)) != NULL ) {
4171                 rc = parseBool(getRestOfLine(), &clink->sendNotifyMessages);
4172             }
4173             else rc = 1;
4174             break;
4175         case ID_ALLOWREMOTECONTROL:
4176             if( (clink = getDescrLink(config)) != NULL ) {
4177                 rc = parseBool(getRestOfLine(), &clink->allowRemoteControl);
4178             }
4179             else rc = 1;
4180             break;
4181         case ID_UNSUBSCRIBEONAREADELETE:
4182             if( (clink = getDescrLink(config)) != NULL ) {
4183                 rc = parseBool(getRestOfLine(), &clink->unsubscribeOnAreaDelete);
4184             }
4185             else rc = 1;
4186             break;
4187         case ID_ALLOWPKTADDRDIFFER:
4188             if( (clink = getDescrLink(config)) != NULL ) {
4189                 rc = parseAllowPktAddrDiffer(getRestOfLine(), config, clink);
4190             }
4191             else {
4192                 rc = 1;
4193             }
4194             break;
4195         case ID_AUTOCREATEDEFAULTS:
4196             s = getRestOfLine();
4197             if( (clink = getDescrLink(config)) != NULL ) {
4198                 if (link_robot & 1)
4199                     rc = fc_copyStringWOstrip(s, &clink->areafix.autoCreateDefaults);
4200                 if (link_robot & 2)
4201                     rc = fc_copyStringWOstrip(s, &clink->filefix.autoCreateDefaults);
4202             }
4203             else {
4204                 rc = 1;
4205             }
4206             break;
4207         case ID_AREAFIX:
4208             if( (clink = getDescrLink(config)) != NULL ) {
4209                 rc = parseBool (getRestOfLine(), &clink->areafix.on);
4210             } else {
4211                 rc = 1;
4212             }
4213             break;
4214         case ID_FILEFIX:
4215             if( (clink = getDescrLink(config)) != NULL ) {
4216                 rc = parseBool (getRestOfLine(), &clink->filefix.on);
4217             } else {
4218                 rc = 1;
4219             }
4220             break;
4221         case ID_PAUSE:
4222             if( (clink = getDescrLink(config)) != NULL ) {
4223                 rc = parsePause (getRestOfLine(), &clink->Pause);
4224             } else {
4225                 rc = 1;
4226             }
4227             break;
4228         case ID_NOTIC:
4229             if( (clink = getDescrLink(config)) != NULL ) {
4230                 rc = parseBool (getRestOfLine(), &clink->noTIC);
4231             } else {
4232                 rc = 1;
4233             }
4234             break;
4235         case ID_DELNOTRECEIVEDTIC:
4236             if( (clink = getDescrLink(config)) != NULL ) {
4237                 rc = parseBool (getRestOfLine(), &clink->delNotReceivedTIC);
4238             } else {
4239                 rc = 1;
4240             }
4241             break;
4242         case ID_ADVANCEDAREAFIX:
4243             if( (clink = getDescrLink(config)) != NULL ) {
4244                 rc = parseBool (getRestOfLine(), &clink->advancedAreafix);
4245             } else {
4246                 rc = 1;
4247             }
4248             break;
4249         case ID_AUTOPAUSE:
4250             rc = parseAutoPause(getRestOfLine(),
4251                                 &(getDescrLink(config)->autoPause));
4252             break;
4253         case ID_FWDPRIORITY:
4254             s = getRestOfLine();
4255             if (link_robot & 1)
4256                 rc = parseUInt(s,
4257                                &(getDescrLink(config)->areafix.forwardPriority));
4258             if (link_robot & 2)
4259                 rc = parseUInt(s,
4260                                &(getDescrLink(config)->filefix.forwardPriority));
4261             break;
4262         case ID_FORWARDREQUESTTIMEOUT:
4263             checkRobot();
4264             rc = parseUInt(getRestOfLine(), &(curRobot->forwardRequestTimeout));
4265             break;
4266         case ID_IDLEPASSTHRUTIMEOUT:
4267             checkRobot();
4268             rc = parseUInt(getRestOfLine(), &(curRobot->idlePassthruTimeout));
4269             break;
4270         case ID_KILLEDREQUESTTIMEOUT:
4271             checkRobot();
4272             rc = parseUInt(getRestOfLine(), &(curRobot->killedRequestTimeout));
4273             break;
4274 
4275         case ID_DENYUNCONDFWDREQACCESS:
4276             if( (clink = getDescrLink(config)) != NULL ) {
4277               s = getRestOfLine();
4278               if (link_robot & 1)
4279                 rc |= parseBool(s, &(clink->areafix.denyUFRA));
4280               if (link_robot & 2)
4281                 rc |= parseBool(s, &(clink->filefix.denyUFRA));
4282             } else {
4283                 rc = 1;
4284             }
4285             break;
4286         case ID_REDUCEDSEENBY:
4287             rc = parseBool(getRestOfLine(), &(getDescrLink(config)->reducedSeenBy));
4288             break;
4289         case ID_EXPORT:
4290             if( (clink = getDescrLink(config)) != NULL ) {
4291                 rc = parseBool (getRestOfLine(), &clink->aexport);
4292             } else {
4293                 rc = 1;
4294             }
4295             break;
4296         case ID_IMPORT:
4297             if( (clink = getDescrLink(config)) != NULL ) {
4298                 rc = parseBool (getRestOfLine(), &clink->import);
4299             } else {
4300                 rc = 1;
4301             }
4302             break;
4303         case ID_MANDATORY:
4304             if( (clink = getDescrLink(config)) != NULL ) {
4305                 rc = parseBool (getRestOfLine(), &clink->mandatory);
4306             } else {
4307                 rc = 1;
4308             }
4309             break;
4310         case ID_MANUAL:
4311             if( (clink = getDescrLink(config)) != NULL ) {
4312                 rc = parseBool (getRestOfLine(), &clink->manual);
4313             } else {
4314                 rc = 1;
4315             }
4316             break;
4317         case ID_OPTGRP:
4318             rc = parseGroup(getRestOfLine(), config, 3);
4319             break;
4320         case ID_FWDMASK:
4321             s = getRestOfLine();
4322             if (link_robot & 1) rc = parseGroup(s, config, 4);
4323             if (link_robot & 2) rc = parseGroup(s, config, 14);
4324             break;
4325         case ID_FWDDENYMASK:
4326             s = getRestOfLine();
4327             if (link_robot & 1) rc = parseGroup(s, config, 5);
4328             if (link_robot & 2) rc = parseGroup(s, config, 15);
4329             break;
4330         case ID_LEVEL:
4331             rc = parseNumber(getRestOfLine(), 10,
4332                              &(getDescrLink(config)->level));
4333             break;
4334         case ID_ECHOLIMIT:
4335             {
4336             s_link *link = getDescrLink(config);
4337             s = getRestOfLine();
4338             if (link_robot & 1) rc |= parseNumber(s, 10, &(link->areafix.echoLimit));
4339             if (link_robot & 2) rc |= parseNumber(s, 10, &(link->filefix.echoLimit));
4340             break;
4341             }
4342         case ID_ARCMAILSIZE:
4343             rc = parseNumber(getRestOfLine(), 10,
4344                              &(getDescrLink(config)->arcmailSize));
4345             break;
4346         case ID_DAILYBUNDLES:
4347             if( (clink = getDescrLink(config)) != NULL ) {
4348                 rc = parseBool (getRestOfLine(), &clink->dailyBundles);
4349             } else {
4350                 rc = parseBool (getRestOfLine(), &config->dailyBundles);
4351             }
4352             break;
4353         case ID_PKTSIZE:
4354             rc = parseNumber(getRestOfLine(), 10,
4355                              &(getDescrLink(config)->pktSize));
4356             break;
4357         case ID_MAXUNPACKEDNETMAIL:
4358             rc = parseNumber(getRestOfLine(), 10,
4359                              &(getDescrLink(config)->maxUnpackedNetmail));
4360             break;
4361         case ID_PKTPWD:
4362             rc = parsePWD(getRestOfLine(), &(getDescrLink(config)->pktPwd));
4363             break;
4364         case ID_TICPWD:
4365             rc = parsePWD(getRestOfLine(), &(getDescrLink(config)->ticPwd));
4366             break;
4367         case ID_AREAFIXPWD:
4368             rc = parsePWD(getRestOfLine(),
4369                           &(getDescrLink(config)->areafix.pwd));
4370             break;
4371         case ID_FILEFIXPWD:
4372             rc = parsePWD(getRestOfLine(),
4373                           &(getDescrLink(config)->filefix.pwd));
4374             break;
4375         case ID_BBSPWD:
4376             rc = parsePWD(getRestOfLine(), &(getDescrLink(config)->bbsPwd));
4377             break;
4378         case ID_SESSIONPWD:
4379             rc = parsePWD(getRestOfLine(),
4380                           &(getDescrLink(config)->sessionPwd));
4381             break;
4382         case ID_HANDLE:
4383             rc = parseHandle(getRestOfLine(), config);
4384             break;
4385         case ID_EMAIL:
4386             if (config->linkCount) { /* email of link */
4387               rc = fc_copyString(getRestOfLine(), &(getDescrLink(config)->email));
4388             }else{ /* email of self */
4389               rc = fc_copyString(getRestOfLine(), &config->email );
4390             }
4391             break;
4392         case ID_EMAILFROM:
4393             rc = fc_copyString(getRestOfLine(),
4394                             &(getDescrLink(config)->emailFrom));
4395             break;
4396         case ID_EMAILSUBJ:
4397             rc = fc_copyString(getRestOfLine(),
4398                             &(getDescrLink(config)->emailSubj));
4399             break;
4400         case ID_EMAILENCODING:
4401             rc = parseEmailEncoding(getRestOfLine(),
4402                                     &(getDescrLink(config)->emailEncoding));
4403             break;
4404         case ID_FLAVOUR:
4405             rc = parseFlavour(getRestOfLine(),
4406                               &(getDescrLink(config)->netMailFlavour));
4407             if (rc == 0) getDescrLink(config)->echoMailFlavour =
4408                          getDescrLink(config)->fileEchoFlavour =
4409                          getDescrLink(config)->netMailFlavour;
4410             break;
4411         case ID_NETMAILFLAVOUR:
4412             rc = parseFlavour(getRestOfLine(),
4413                               &(getDescrLink(config)->netMailFlavour));
4414             break;
4415         case ID_ECHOMAILFLAVOUR:
4416             rc = parseFlavour(getRestOfLine(),
4417                               &(getDescrLink(config)->echoMailFlavour));
4418             break;
4419         case ID_FILEECHOFLAVOUR:
4420             rc = parseFlavour(getRestOfLine(),
4421                               &(getDescrLink(config)->fileEchoFlavour));
4422             break;
4423         case ID_ROBOT:
4424             if (config->describeLinkDefaults || config->linkCount) {
4425               prErr( "Any robots should be described before any link or linkdefaults!");
4426               rc = 1;
4427             }
4428             curRobot = getRobot(config, getRestOfLine(), 1);
4429             break;
4430         case ID_ROUTE:
4431             rc = parseRoute(getRestOfLine(), config, &(config->route),
4432                             &(config->routeCount), id_route);
4433             break;
4434         case ID_ROUTEFILE:
4435             rc = parseRoute(getRestOfLine(), config, &(config->route),
4436                             &(config->routeCount), id_routeFile);
4437             break;
4438         case ID_ROUTEMAIL:
4439             rc = parseRoute(getRestOfLine(), config, &(config->route),
4440                             &(config->routeCount), id_routeMail);
4441             break;
4442         case ID_PACK:
4443             rc = parsePack(getRestOfLine(), config);
4444             break;
4445         case ID_UNPACK:
4446             rc = parseUnpack(getRestOfLine(), config);
4447             break;
4448         case ID_PACKER:
4449             rc = parsePackerDef(getRestOfLine(), config,
4450                                 &(getDescrLink(config)->packerDef));
4451             break;
4452         case ID_INTAB:
4453             rc = parseFileName(getRestOfLine(), &(config->intab), NULL);
4454             break;
4455         case ID_OUTTAB:
4456             rc = parseFileName(getRestOfLine(), &(config->outtab), NULL);
4457             break;
4458         case ID_RECODEMSGBASE:
4459             rc = parseBool (getRestOfLine(), &config->recodeMsgBase);
4460             break;
4461         case ID_HELPFILE:
4462             checkRobot();
4463             rc = parseFileName(getRestOfLine(), &(curRobot->helpFile), NULL);
4464             break;
4465         case ID_FWDFILE:
4466             s = getRestOfLine();
4467             if (link_robot & 1)
4468                 rc = parseFileName(s,
4469                                    &(getDescrLink(config)->areafix.fwdFile),
4470                                    &(linkDefined.areafix.fwdFile));
4471             if (link_robot & 2)
4472                 rc = parseFileName(s,
4473                                    &(getDescrLink(config)->filefix.fwdFile),
4474                                    &(linkDefined.filefix.fwdFile));
4475             break;
4476         case ID_FWDDENYFILE:
4477             s = getRestOfLine();
4478             if (link_robot & 1)
4479                 rc = parseFileName(s,
4480                                    &(getDescrLink(config)->areafix.denyFwdFile),
4481                                    &(linkDefined.areafix.denyFwdFile));
4482             if (link_robot & 2)
4483                 rc = parseFileName(s,
4484                                    &(getDescrLink(config)->filefix.denyFwdFile),
4485                                    &(linkDefined.filefix.denyFwdFile));
4486             break;
4487         case ID_AUTOCREATEFILE:
4488             s = getRestOfLine();
4489             if (link_robot & 1)
4490               rc = parseFileName(s,
4491                                  &(getDescrLink(config)->areafix.autoCreateFile),
4492                                  &(linkDefined.areafix.autoCreateFile));
4493             if (link_robot & 2)
4494               rc = parseFileName(s,
4495                                  &(getDescrLink(config)->filefix.autoCreateFile),
4496                                  &(linkDefined.filefix.autoCreateFile));
4497             break;
4498         case ID_LINKBUNDLENAMESTYLE:
4499             rc = parseBundleNameStyle(getRestOfLine(),
4500                                &(getDescrLink(config)->linkBundleNameStyle));
4501             break;
4502         case ID_ECHOTOSSLOG:
4503             rc = fc_copyString(getRestOfLine(), &(config->echotosslog));
4504             break;
4505         case ID_STATLOG:
4506             rc = fc_copyString(getRestOfLine(), &(config->statlog));
4507             break;
4508         case ID_IMPORTLOG:
4509             rc = fc_copyString(getRestOfLine(), &(config->importlog));
4510             break;
4511         case ID_LINKWITHIMPORTLOG:
4512             rc = parseLinkWithILogType(getRestOfLine(),
4513                                        &(config->LinkWithImportlog));
4514             break;
4515         case ID_KLUDGEAREANETMAIL:
4516             rc = parseKludgeAreaNetmailType(getRestOfLine(),
4517                                             &(config->kludgeAreaNetmail));
4518             break;
4519         /* not used
4520         case ID_FILEAREASLOG:
4521             rc = parseFileName(getRestOfLine(), &(config->fileAreasLog), NULL);
4522             break;
4523         case ID_FILENEWAREASLOG:
4524             rc = parseFileName(getRestOfLine(), &(config->fileNewAreasLog), NULL);
4525             break;
4526         case ID_LONGNAMELIST:
4527             rc = parseFileName(getRestOfLine(), &(config->longNameList), NULL);
4528             break;
4529         case ID_FILEARCLIST:
4530             rc = parseFileName(getRestOfLine(), &(config->fileArcList), NULL);
4531             break;
4532         case ID_FILEPASSLIST:
4533             rc = parseFileName(getRestOfLine(), &(config->filePassList), NULL);
4534             break;
4535         case ID_FILEDUPELIST:
4536             rc = parseFileName(getRestOfLine(), &(config->fileDupeList), NULL);
4537             break;
4538         */
4539         case ID_LOGLEVELS:
4540             rc = parseLoglevels(getRestOfLine(), &(config->loglevels));
4541             break;
4542         case ID_SCREENLOGLEVELS:
4543             rc = parseLoglevels(getRestOfLine(), &(config->screenloglevels));
4544             break;
4545         case ID_LOGDATEFORMAT:
4546             rc = fc_copyString(getRestOfLine(), &(config->logDateFormat));
4547             break;
4548         case ID_ACCESSGRP:
4549             rc = parseGroup(getRestOfLine(), config, 0);
4550             break;
4551         case ID_LINKGRP:
4552             rc = parseGroup(getRestOfLine(), config, 1);
4553             break;
4554         case ID_CARBONTO:
4555             rc = parseCarbon(getRestOfLine(),config, ct_to);
4556             break;
4557         case ID_CARBONFROM:
4558             rc = parseCarbon(getRestOfLine(), config, ct_from);
4559             break;
4560         case ID_CARBONADDR:
4561             rc = parseCarbon(getRestOfLine(), config, ct_addr);
4562             break;
4563         case ID_CARBONKLUDGE:
4564             rc = parseCarbon(getRestOfLine(), config, ct_kludge);
4565             break;
4566         case ID_CARBONSUBJ:
4567             rc = parseCarbon(getRestOfLine(), config, ct_subject);
4568             break;
4569         case ID_CARBONTEXT:
4570             rc = parseCarbon(getRestOfLine(), config, ct_msgtext);
4571             break;
4572         case ID_CARBONFROMAREA:
4573             rc = parseCarbon(getRestOfLine(), config, ct_fromarea);
4574             break;
4575         case ID_CARBONGROUPS:
4576             rc = parseCarbon(getRestOfLine(), config, ct_group);
4577             break;
4578         case ID_CARBONCOPY:
4579             rc = parseCarbonArea(getRestOfLine(), config, 0);
4580             break;
4581         case ID_CARBONMOVE:
4582             rc = parseCarbonArea(getRestOfLine(), config, 1);
4583             break;
4584         case ID_CARBONEXTERN:
4585             rc = parseCarbonExtern(getRestOfLine(), config);
4586             break;
4587         case ID_NETMAILEXTERN:
4588             rc = parseCarbonExtern(getRestOfLine(), config);
4589             break;
4590         case ID_CARBONDELETE:
4591             rc = parseCarbonDelete(getRestOfLine(), config);
4592             break;
4593         case ID_CARBONREASON:
4594             rc = parseCarbonReason(getRestOfLine(), config);
4595             break;
4596         case ID_CARBONRULE:
4597             rc = parseCarbonRule(getRestOfLine(), config);
4598             break;
4599         case ID_EXCLUDEPASSTHROUGHCARBON:
4600             rc = parseBool(getRestOfLine(), &(config->exclPassCC));
4601             break;
4602         case ID_LOCKFILE:
4603             rc = fc_copyString(getRestOfLine(), &(config->lockfile));
4604             break;
4605         case ID_TEMPOUTBOUND:
4606             rc = parsePath(getRestOfLine(), &(config->tempOutbound), NULL);
4607             break;
4608         case ID_AUTOAREAPAUSE:
4609             checkRobot();
4610             rc = parseBool(getRestOfLine(), &(curRobot->autoAreaPause));
4611             break;
4612         case ID_AREAFIXFROMPKT:
4613             rc = parseBool(getRestOfLine(), &(config->areafixFromPkt));
4614             break;
4615         case ID_QUEUEFILE:
4616             checkRobot();
4617             rc = parseFileName(getRestOfLine(), &(curRobot->queueFile), NULL);
4618             break;
4619         case ID_REPORTSATTR:
4620             if (config->describeLinkDefaults || config->linkCount) {
4621                  s_link *link = getDescrLink(config);
4622                  s = getRestOfLine();
4623                  if (link_robot & 1) rc |= parseAttr(s, &(link->areafix.reportsFlags), &(link->areafix.reportsAttr));
4624                  if (link_robot & 2) rc |= parseAttr(s, &(link->filefix.reportsFlags), &(link->filefix.reportsAttr));
4625             }
4626             else {
4627               checkRobot();
4628               rc = parseAttr(getRestOfLine(), &(curRobot->reportsFlags), &(curRobot->reportsAttr));
4629             }
4630             break;
4631         case ID_KILLREQUESTS:
4632             checkRobot();
4633             rc = parseBool(getRestOfLine(), &(curRobot->killRequests));
4634             break;
4635         case ID_QUERYREPORTS:
4636             checkRobot();
4637             rc = parseBool(getRestOfLine(), &(curRobot->queryReports));
4638             break;
4639         case ID_CREATEDIRS:
4640             rc = parseBool(getRestOfLine(), &(config->createDirs));
4641             break;
4642         case ID_LONGDIRNAMES:
4643             rc = parseBool(getRestOfLine(), &(config->longDirNames));
4644             break;
4645         case ID_SPLITDIRS:
4646             rc = parseBool(getRestOfLine(), &(config->splitDirs));
4647             break;
4648         case ID_ADDDLC:
4649             rc = parseBool(getRestOfLine(), &(config->addDLC));
4650             break;
4651         case ID_FILESINGLEDESCLINE:
4652             rc = parseBool(getRestOfLine(), &(config->fileSingleDescLine));
4653             break;
4654         case ID_FILECHECKDEST:
4655             rc = parseBool(getRestOfLine(), &(config->fileCheckDest));
4656             break;
4657         case ID_PUBLICGROUP:
4658             rc = parseGroup(getRestOfLine(), config, 2);
4659             break;
4660         case ID_LOGECHOTOSCREEN:
4661             rc = parseBool(getRestOfLine(), &(config->logEchoToScreen));
4662             break;
4663         case ID_SEPARATEBUNDLES:
4664             rc = parseBool(getRestOfLine(), &(config->separateBundles));
4665             break;
4666         case ID_CARBONANDQUIT:
4667             rc = parseBool(getRestOfLine(), &(config->carbonAndQuit));
4668             break;
4669         case ID_CARBONKEEPSB:
4670             rc = parseBool(getRestOfLine(), &(config->carbonKeepSb));
4671             break;
4672         case ID_CARBONOUT:
4673             rc = parseBool(getRestOfLine(), &(config->carbonOut));
4674             break;
4675         case ID_IGNORECAPWORD:
4676             rc = parseBool(getRestOfLine(), &(config->ignoreCapWord));
4677             break;
4678         case ID_NOPROCESSBUNDLES:
4679             rc = parseBool(getRestOfLine(), &(config->noProcessBundles));
4680             break;
4681         case ID_NOTVALIDFILENAMECHARS:
4682             rc = fc_copyString(getRestOfLine(), &(config->notValidFNChars));
4683             break;
4684         case ID_REPORTTO:
4685             rc = fc_copyString(getRestOfLine(), &(config->ReportTo));
4686             break;
4687         case ID_REPORTREQUESTER:
4688             rc = parseBool(getRestOfLine(), (unsigned int*)&(config->reportRequester));
4689             break;
4690         case ID_EXECONFILE:
4691             rc = parseExecOnFile(getRestOfLine(), config);
4692             break;
4693         case ID_DEFARCMAILSIZE:
4694             rc = parseNumber(getRestOfLine(), 10, &(config->defarcmailSize));
4695             break;
4696         case ID_MSGSIZE:
4697             checkRobot();
4698             rc = parseNumber(getRestOfLine(), 10, &(curRobot->msgSize));
4699             break;
4700         case ID_AFTERUNPACK:
4701             rc = fc_copyString(getRestOfLine(), &(config->afterUnpack));
4702             break;
4703         case ID_BEFOREPACK:
4704             rc = fc_copyString(getRestOfLine(), &(config->beforePack));
4705             break;
4706         case ID_PROCESSPKT:
4707             rc = fc_copyString(getRestOfLine(), &(config->processPkt));
4708             break;
4709         case ID_SPLITSTR:
4710             checkRobot();
4711             rc = fc_copyString(getRestOfLine(), &(curRobot->splitStr));
4712             break;
4713         case ID_ROBOTORIGIN:
4714             checkRobot();
4715             temp = getRestOfLine();
4716             if( temp[0] == '"' && temp[strlen(temp)-1] =='"' ) {
4717               temp++; temp[strlen(temp)-1]='\0';
4718             }
4719             rc = fc_copyString(temp, &(curRobot->origin));
4720             break;
4721         case ID_ROBOTSAREA:
4722             rc = fc_copyString(getRestOfLine(), &(config->robotsArea));
4723             break;
4724         case ID_FILEDESCNAME:
4725             rc = parseUUEechoAreas(getRestOfLine(),&(config->fileDescNames),&(config->fDescNameCount));
4726             break;
4727         case ID_FILEDESCRIPTION:
4728             rc = fc_copyString(getRestOfLine(), &(config->fileDescription));
4729             break;
4730         case ID_FILEDESCPOS:
4731             rc = parseUInt(getRestOfLine(), &(config->fileDescPos));
4732             break;
4733         case ID_DLCDIGITS:
4734             rc = parseUInt(getRestOfLine(), &(config->DLCDigits));
4735             break;
4736         /* not used
4737         case ID_FILEMAXDUPEAGE:
4738             rc = parseUInt(getRestOfLine(), &(config->fileMaxDupeAge));
4739             break;
4740         case ID_FILEFILEUMASK:
4741             rc = parseOctal(getRestOfLine(), &(config->fileFileUMask));
4742             break;
4743         case ID_FILEDIRUMASK:
4744             rc = parseOctal(getRestOfLine(), &(config->fileDirUMask));
4745             break;
4746         case ID_FILELOCALPWD:
4747             rc = fc_copyString(getRestOfLine(), &(config->fileLocalPwd));
4748             break;
4749 
4750         */
4751         case ID_ORIGININANNOUNCE:
4752             rc = parseBool(getRestOfLine(), &(config->originInAnnounce));
4753             break;
4754         case ID_MAXTICLINELENGTH:
4755             rc = parseUInt(getRestOfLine(), &(config->MaxTicLineLength));
4756             break;
4757         case ID_FILELDESCSTRING:
4758             rc = fc_copyString(getRestOfLine(), &(config->fileLDescString));
4759             break;
4760         case ID_SAVETIC:
4761             rc = parseSaveTicStatement(getRestOfLine(), config);
4762             break;
4763         case ID_AREASMAXDUPEAGE:
4764             rc = parseNumber(getRestOfLine(), 10, &(config->areasMaxDupeAge));
4765             break;
4766         case ID_DUPEBASETYPE:
4767             rc = parseTypeDupes(getRestOfLine(), &(config->typeDupeBase),
4768                                 &(config->areasMaxDupeAge));
4769             break;
4770         case ID_FIDOUSERLIST:
4771             rc = fc_copyString(getRestOfLine(), &(config->fidoUserList));
4772             break;
4773         case ID_NODELIST:
4774             rc = parseNodelist(getRestOfLine(), config);
4775             break;
4776         case ID_DIFFUPDATE:
4777             rc = 0;
4778             if (config->nodelistCount > 0) {
4779                 rc = fc_copyString(getRestOfLine(),
4780                  &(config->nodelists[config->nodelistCount-1].diffUpdateStem));
4781             }
4782             else {
4783                 printNodelistError();
4784                 rc = 1;
4785             }
4786             break;
4787         case ID_DELAPPLIEDDIFF:
4788             rc = parseBool(getRestOfLine(),
4789                 (unsigned int*)&(config->nodelists[config->nodelistCount-1].delAppliedDiff));
4790             break;
4791         case ID_FULLUPDATE:
4792             rc = 0;
4793             if (config->nodelistCount > 0) {
4794                 rc = fc_copyString(getRestOfLine(),
4795                  &(config->nodelists[config->nodelistCount-1].fullUpdateStem));
4796             }
4797             else {
4798                 printNodelistError();
4799                 rc = 1;
4800             }
4801             break;
4802         case ID_DEFAULTZONE:
4803             rc = 0;
4804             if (config->nodelistCount > 0) {
4805                 rc = parseUInt(getRestOfLine(),
4806                  &(config->nodelists[config->nodelistCount-1].defaultZone));
4807             }
4808             else {
4809                 printNodelistError();
4810                 rc = 1;
4811             }
4812             break;
4813         case ID_NODELISTFORMAT:
4814             if (config->nodelistCount > 0) {
4815                 rc = parseNodelistFormat(getRestOfLine(), config,
4816                                &(config->nodelists[config->nodelistCount-1]));
4817             }
4818             else {
4819                 printNodelistError();
4820                 rc = 1;
4821             }
4822             break;
4823         case ID_LOGOWNER:
4824             rc = parseOwner(getRestOfLine(), &(config->loguid),
4825                             &(config->loggid));
4826             break;
4827         case ID_LOGPERM:
4828             rc = parseNumber(getRestOfLine(), 8, &(config->logperm));
4829             break;
4830         case ID_LINKDEFAULTS:
4831             rc = parseLinkDefaults(getRestOfLine(), config);
4832             break;
4833         case ID_CREATEAREASCASE:
4834             rc = parseNamesCase(getRestOfLine(), &(config->createAreasCase));
4835             break;
4836         case ID_AREASFILENAMECASE:
4837             rc = parseNamesCase(getRestOfLine(), &(config->areasFileNameCase));
4838             break;
4839         case ID_CONVERTLONGNAMES:
4840             rc = parseNamesCaseConversion(getRestOfLine(),
4841                                           &(config->convertLongNames));
4842             break;
4843         case ID_CONVERTSHORTNAMES:
4844             rc = parseNamesCaseConversion(getRestOfLine(),
4845                                           &(config->convertShortNames));
4846             break;
4847         case ID_DISABLEKLUDGERESCANNED:
4848             rc = parseBool(getRestOfLine(), &(config->disableKludgeRescanned));
4849             break;
4850         case ID_DISABLETID:
4851             rc = parseBool(getRestOfLine(), &(config->disableTID));
4852             break;
4853         case ID_DISABLEPID:
4854             rc = parseBool(getRestOfLine(), &(config->disablePID));
4855             break;
4856         case ID_TOSSINGEXT:
4857             if ((temp=getRestOfLine()) != NULL)
4858                 rc = fc_copyString(temp, &(config->tossingExt));
4859             else
4860                 config->tossingExt = NULL;
4861             break;
4862 #if defined ( __NT__ )
4863         case ID_SETCONSOLETITLE:
4864             rc = parseBool(getRestOfLine(), &(config->setConsoleTitle));
4865             break;
4866 #endif
4867         case ID_ADDTOSEEN:
4868             rc = parseSeenBy2D(getRestOfLine(),&(config->addToSeen),
4869                                &(config->addToSeenCount));
4870             break;
4871         case ID_IGNORESEEN:
4872             rc = parseSeenBy2D(getRestOfLine(),&(config->ignoreSeen),
4873                                &(config->ignoreSeenCount));
4874             break;
4875         case ID_TEARLINE:
4876             rc = fc_copyString(getRestOfLine(), &(config->tearline));
4877             break;
4878         case ID_ORIGIN:
4879             temp = getRestOfLine();
4880             if (temp) {
4881                 if( temp[0] == '"' && temp[strlen(temp)-1] =='"' ) {
4882                     temp++; temp[strlen(temp)-1]='\0';
4883                 }
4884             }
4885             rc = fc_copyString(temp, &(config->origin));
4886             break;
4887         case ID_BUNDLENAMESTYLE:
4888             rc = parseBundleNameStyle(getRestOfLine(),
4889                                       &(config->bundleNameStyle));
4890             break;
4891         case ID_KEEPTRSMAIL:
4892             rc = parseBool(getRestOfLine(), &(config->keepTrsMail));
4893             break;
4894         case ID_KEEPTRSFILES:
4895             rc = parseBool(getRestOfLine(), &(config->keepTrsFiles));
4896             break;
4897         case ID_FILELIST:
4898             rc = parseFilelist(getRestOfLine(), config);
4899             break;
4900         case ID_CREATEFWDNONPASS:
4901             rc = parseBool(getRestOfLine(), &(config->createFwdNonPass));
4902             break;
4903         case ID_AUTOPASSIVE:
4904             rc = parseBool(getRestOfLine(), &(config->autoPassive));
4905             break;
4906         case ID_NETMAILFLAG:
4907             rc = fc_copyString(getRestOfLine(), &(config->netmailFlag));
4908             break;
4909         case ID_AUTOCREATEFLAG:
4910             checkRobot();
4911             rc = fc_copyString(getRestOfLine(), &(curRobot->autoCreateFlag));
4912             break;
4913         case ID_MINDISKFREESPACE:
4914             rc = parseNumber(getRestOfLine(), 10, &(config->minDiskFreeSpace));
4915             break;
4916         case ID_AUTOAREACREATESUBDIRS:
4917             rc = parseBool(getRestOfLine(), &(getDescrLink(config)->autoAreaCreateSubdirs));
4918             break;
4919         case ID_AUTOFILECREATESUBDIRS:
4920             rc = parseBool(getRestOfLine(), &(getDescrLink(config)->autoFileCreateSubdirs));
4921             break;
4922         case ID_TICKERPACKTOBOX:
4923             rc = parseBool(getRestOfLine(), &(getDescrLink(config)->tickerPackToBox));
4924             break;
4925         case ID_ADVISORYLOCK:
4926             rc = parseUInt(getRestOfLine(), &(config->advisoryLock));
4927             break;
4928         case ID_NAMES:
4929             checkRobot();
4930             rc = parseStringList(getRestOfLine(), &(curRobot->names));
4931             break;
4932         case ID_REQIDXDIR:
4933             rc = parsePath(getRestOfLine(), &(config->reqidxDir), NULL);
4934             break;
4935         case ID_SYSLOG_FACILITY:
4936             rc = parseSyslog(getRestOfLine(), &(config->syslogFacility));
4937             break;
4938         case ID_FILEBOX:
4939             rc = parsePathNoCheck(getRestOfLine(),
4940 				  &(getDescrLink(config)->fileBox),
4941 				  &(linkDefined.fileBox));
4942             break;
4943         case ID_FILEBOXESDIR:
4944             rc = parsePath(getRestOfLine(), &(config->fileBoxesDir), NULL);
4945             break;
4946         case ID_FILEBOXALWAYS:
4947             rc = parseBool(getRestOfLine(), &(getDescrLink(config)->fileBoxAlways));
4948             break;
4949         case ID_CARBONEXCLUDEFWDFROM:
4950             rc = parseBool(getRestOfLine(), &(config->carbonExcludeFwdFrom));
4951             break;
4952         case ID_HPTPERLFILE:
4953             rc = parseFileName(getRestOfLine(), &(config->hptPerlFile), NULL);
4954             break;
4955         case ID_ADVSTATISTICSFILE:
4956             rc = fc_copyString(getRestOfLine(), &(config->advStatisticsFile));
4957             break;
4958         case ID_READONLY:
4959             rc = parsePermissions (getRestOfLine(),  &(config->readOnly), &(config->readOnlyCount));
4960             break;
4961         case ID_WRITEONLY:
4962             rc = parsePermissions (getRestOfLine(),  &(config->writeOnly), &(config->writeOnlyCount));
4963             break;
4964         case ID_ARCNETMAIL:
4965             if( (clink = getDescrLink(config)) != NULL ) {
4966                 rc = parseBool (getRestOfLine(), &clink->arcNetmail);
4967             } else {
4968                 rc = 1;
4969             }
4970             break;
4971         case ID_RULESDIR:
4972             checkRobot();
4973             rc = parsePath(getRestOfLine(), &(curRobot->rulesDir), NULL);
4974             break;
4975         case ID_NORULES:
4976             s = getRestOfLine();
4977             if (link_robot & 1)
4978                 rc = parseBool(s, &(getDescrLink(config)->areafix.noRules));
4979             if (link_robot & 2)
4980                 rc = parseBool(s, &(getDescrLink(config)->filefix.noRules));
4981             break;
4982         case ID_PACKNETMAILONSCAN:
4983             rc = parseBool(getRestOfLine(), &(config->packNetMailOnScan));
4984             break;
4985         case ID_UUEECHOGROUP:
4986             rc = parseUUEechoAreas(getRestOfLine(), &(config->uuEGrp), &(config->numuuEGrp));
4987             break;
4988         case ID_SENDMAILCMD:
4989             rc = parseSendMailCmd( getRestOfLine(), &(config->sendmailcmd) );
4990             break;
4991 
4992         case ID_TEMPDIR:
4993             rc = parsePath(getRestOfLine(), &(config->tempDir), NULL);
4994             break;
4995 
4996         /*  htick announcer */
4997         case ID_ANNOUNCESPOOL:
4998             rc = parsePath(getRestOfLine(), &(config->announceSpool), NULL);
4999             break;
5000        case ID_ANNAREATAG:
5001             rc = parseAnnDef(getRestOfLine(), config);
5002             break;
5003         case ID_ANNINCLUDE:
5004             rc = parseGroup(getRestOfLine(), config, 6);
5005             break;
5006         case ID_ANNEXCLUDE:
5007             rc = parseGroup(getRestOfLine(), config, 7);
5008             break;
5009         case ID_ANNTO:
5010             rc = fc_copyString(getRestOfLine(), &(getDescrAnnDef(config)->annto));
5011             break;
5012         case ID_ANNFROM:
5013             rc = fc_copyString(getRestOfLine(), &(getDescrAnnDef(config)->annfrom));
5014             break;
5015         case ID_ANNSUBJ:
5016             rc = fc_copyString(getRestOfLine(), &(getDescrAnnDef(config)->annsubj));
5017             break;
5018         case ID_ANNORIGIN:
5019             rc = fc_copyString(getRestOfLine(), &(getDescrAnnDef(config)->annorigin));
5020             break;
5021         case ID_ANNMESSFLAGS:
5022             rc = fc_copyString(getRestOfLine(), &(getDescrAnnDef(config)->annmessflags));
5023             break;
5024         case ID_ANNFILEORIGIN:
5025             rc = parseBool(getRestOfLine(), &(getDescrAnnDef(config)->annforigin));
5026             break;
5027         case ID_ANNFILERFROM:
5028             rc = parseBool(getRestOfLine(), &(getDescrAnnDef(config)->annfrfrom));
5029             break;
5030         case ID_ANNADDRTO:
5031             rc = parseAnnDefAddres(getRestOfLine(), config, 1);
5032             break;
5033         case ID_ANNADDRFROM:
5034             rc = parseAnnDefAddres(getRestOfLine(), config, 2);
5035             break;
5036         case ID_FILEAREACREATEPERMS:
5037             rc = parseNumber(getRestOfLine(), 10, &(config->fileAreaCreatePerms));
5038             config->fileAreaCreatePerms = dec2oct(config->fileAreaCreatePerms);
5039             break;
5040         case ID_NEWAREAREFUSEFILE:
5041             checkRobot();
5042             rc = fc_copyString(getRestOfLine(), &(curRobot->newAreaRefuseFile));
5043             break;
5044         case ID_FROMNAME:
5045             checkRobot();
5046             rc = fc_copyString(getRestOfLine(), &(curRobot->fromName));
5047             break;
5048         case ID_SEQDIR:
5049             rc = parsePath(getRestOfLine(), &(config->seqDir), NULL);
5050             break;
5051         case ID_SEQOUTRUN:
5052             rc = parseSeqOutrun(getRestOfLine(), &(config->seqOutrun));
5053             break;
5054         case ID_AVAILLIST:
5055             if( (clink = getDescrLink(config)) != NULL ) {
5056                 rc = parseAvailList(getRestOfLine(), &(clink->availlist));
5057             } else {
5058                 rc = 1;
5059             }
5060             break;
5061         case ID_AREAGROUP:
5062             rc = parseAreaGroup(getRestOfLine());
5063             break;
5064         case ID_AREAGROUPDEFAULTS:
5065             rc = parseAreaGroupDefaults(config, getRestOfLine());
5066             break;
5067         case ID_GRPDESC:
5068             rc = parseGroupDesc(config, getRestOfLine());
5069             break;
5070         case ID_LISTECHO:
5071             rc = parseListEcho( getRestOfLine(), &(config->listEcho) );
5072             break;
5073         case ID_CREATEADDUPLINK:
5074             rc = parseBool(getRestOfLine(), &(config->createAddUplink));
5075             break;
5076         case ID_DENYRESCAN:
5077             rc = parseBool(getRestOfLine(), &(getDescrLink(config)->denyRescan));
5078             break;
5079         case ID_RESCANGRP:
5080             rc = parseGroup(getRestOfLine(), config, 8);
5081             break;
5082         case ID_RESCANLIMIT:
5083             rc = parseNumber(getRestOfLine(), 10, (unsigned int*)&(getDescrLink(config)->rescanLimit));
5084             break;
5085 
5086         default:
5087             prErr( "unrecognized: %s", line);
5088             wasError = 1;
5089             nfree(iToken);
5090             nfree(actualLine);
5091             return 1;
5092         }
5093 
5094         nfree(iToken);
5095     }
5096     if (rc != 0) {
5097         prErr( "error %d in: %s", rc, line);
5098         wasError = 1;
5099     }
5100 
5101     nfree(actualLine);
5102     return rc;
5103 }
5104