1 /*
2  *  fconf.c
3  *
4  *  Written by Tobias Ernst et. al.
5  *  Released to the public domain.
6  *
7  *  Reads a husky project fidoconfig config file.
8  *
9  *  There are two ways of reading the fidoconfig file: If the macro
10  *  USE_FIDOCONFIG is defined, we will use the routines of the fidoconfig
11  *  library. This is very easy, but as soon as a single new keyword is
12  *  introduced to fidoconfig, you must recompile (or at least relink, but
13  *  usually the interface also changes) Msged, because otherwise the
14  *  library routines will complain about unknown keywords.
15  *
16  *  Therefore, this file also contains routines that directly parse the
17  *  fidoconfig file and simply ignore all unknown keywords. This is good for
18  *  doing binary releases, as this code has a high chance of continuing to work
19  *  even if the fidoconfig library is modified and new keywords are introduced.
20  *  It is even resistant against the addition of new flags to area definitions
21  *  - but of course if area definitions would be changed fundamentally, this
22  *  code has to be adapted.
23  *
24  *  Using the USE_FIDOCONFIG code is your choice if you compile Msged on your
25  *  own and have no problem to update and recompile Msged every time you
26  *  upgrade your fidoconfig and other Husky sources.
27  *
28  *  For doing binary releases, or if you don't want to regularly update Msged
29  *  along with the other tools, you should not use the USE_FIDOCONFIG code.
30  *
31  */
32 
33 #ifdef USE_FIDOCONFIG
34 #include <fidoconf/fidoconf.h>
35 #else
36 #include <stdlib.h>
37 #include <stdio.h>
38 #endif
39 
40 #include <time.h>
41 #include <string.h>
42 #include "version.h"
43 #include "addr.h"
44 #include "areas.h"
45 #include "nedit.h"
46 #include "msged.h"
47 #include "strextra.h"
48 #include "memextra.h"
49 #include "config.h"
50 #include "fconf.h"
51 #include "version.h"
52 #include "group.h"
53 #include "environ.h"
54 
55 #ifdef USE_FIDOCONFIG
56 
57 /* ===================================================================== */
58 /* Part 1: Fidoconfig routines that use the Fidoconfig library           */
59 /* ===================================================================== */
60 
fc_copy_address(FIDO_ADDRESS * a,hs_addr * fc_a)61 static void fc_copy_address(FIDO_ADDRESS *a, hs_addr *fc_a)
62 {
63     memset(a, 0, sizeof(FIDO_ADDRESS));
64 
65     a->zone  = fc_a->zone;
66     a->net   = fc_a->net;
67     a->node  = fc_a->node;
68     a->point = fc_a->point;
69 
70     a->fidonet = 1;
71 
72     if (fc_a->domain != NULL && *(fc_a->domain))
73     {
74         a->domain = xstrdup(fc_a->domain);
75     }
76     else
77     {
78         a->domain = NULL;
79     }
80 }
81 
fc_add_area(s_area * fc_area,int netmail,int local)82 static void fc_add_area(s_area *fc_area, int netmail, int local)
83 {
84     static AREA a;
85 
86     memset(&a, 0, sizeof a);
87 
88     if (fc_area->msgbType != MSGTYPE_SDM
89 #ifdef USE_MSGAPI
90         && fc_area->msgbType != MSGTYPE_SQUISH
91         && fc_area->msgbType != MSGTYPE_JAM
92 #endif
93         )
94     {
95         return;
96     }
97 
98     fc_copy_address(&(a.addr), fc_area->useAka);
99 
100     a.tag = xstrdup(fc_area->areaName);
101     a.description=makeareadesc(fc_area->areaName, fc_area->description);
102 
103     a.path = xstrdup(fc_area->fileName);
104 
105     if ((fc_area->group != NULL) && (SW->areafilegroups) &&
106         (strcmp(fc_area->group, "\060") != 0))
107     {
108         a.group = group_gethandle(fc_area->group, 1);
109     }
110     else
111     {
112         a.group = 0;
113     }
114 
115     if (netmail)
116     {
117         a.netmail = 1; a.priv = 1;
118     }
119     else if (local)
120     {
121         a.local = 1;
122     }
123     else
124     {
125         a.echomail = 1;
126     }
127 
128     switch (fc_area->msgbType)
129     {
130     case MSGTYPE_SDM:
131         a.msgtype = FIDO;
132         break;
133 #ifdef USE_MSGAPI
134     case MSGTYPE_SQUISH:
135         a.msgtype = SQUISH;
136         break;
137     case MSGTYPE_JAM:
138         a.msgtype = JAM;
139         break;
140 #endif
141     default:  /* should never get here */
142         abort();
143     }
144 
145     applyflags(&a, areafileflags);
146     AddArea(&a);
147 }
148 
check_fidoconfig(char * option_string)149 void check_fidoconfig(char *option_string)
150 {
151 #ifndef USE_FIDOCONFIG
152     printf("\r\aError! This version of "PROG" has been compiled\n"
153            "without support for the FIDOCONFIG standard.\n");
154     exit(-1);
155 #else
156 
157     s_fidoconfig *fc_config = readConfig(NULL);
158     s_area       *fc_area;
159     int i;
160     int check_type;
161 
162     if (option_string != NULL && !stricmp(option_string, "settings"))
163     {
164         check_type = 1;
165     }
166     else if (option_string != NULL && !stricmp(option_string, "both"))
167     {
168         check_type = 3;
169     }
170     else /* Default: Load areas only */
171     {
172        check_type = 2;
173     }
174 
175     if (fc_config != NULL)
176     {
177         if (check_type & 1)     /* load settings */
178         {
179                                 /* sysop name */
180             for (i = 0; i < MAXUSERS; i++)
181             {
182                 if (user_list[i].name == NULL)
183                 {
184                     break;
185                 }
186             }
187             if (i < MAXUSERS)
188             {
189                 user_list[i].name = xstrdup(fc_config->sysop);
190                 if (i == 0)
191                 {
192                     release(ST->username);
193                     ST->username = xstrdup(user_list[i].name);
194                     SW->useroffset = user_list[i].offset;
195                 }
196             }
197 
198                                 /* addresses */
199             if (fc_config->addrCount)
200             {
201                 alias = xrealloc(alias,
202                                  (SW->aliascount + fc_config->addrCount) *
203                                  sizeof (FIDO_ADDRESS));
204 
205                 for (i = 0; i < fc_config->addrCount; i++)
206                 {
207                     fc_copy_address(alias + SW->aliascount + i,
208                                     fc_config->addr + i);
209                 }
210                 SW->aliascount += fc_config->addrCount;
211             }
212 
213                                 /* echotoss log */
214             if (fc_config->echotosslog !=NULL)
215             {
216                 release(ST->echotoss);
217                 ST->echotoss =
218                     pathcvt(xstrdup(fc_config->echotosslog));
219             }
220 
221                                 /* area to place file requests in */
222 	    if (fc_config->netMailAreaCount > 0)
223 	    {
224 	        release(ST->freqarea);
225 		ST->freqarea = xstrdup(fc_config->netMailAreas[0].areaName);
226 	    }
227 
228                                 /* fido user list */
229             if (fc_config->nodelistDir != NULL &&
230                 fc_config->fidoUserList != NULL)
231             {
232                 release(ST->fidolist);
233                 ST->fidolist = xmalloc(strlen(fc_config->nodelistDir)+
234                                        strlen(fc_config->fidoUserList) + 1);
235                 strcpy(ST->fidolist, fc_config->nodelistDir);
236                 strcat(ST->fidolist, fc_config->fidoUserList);
237             }
238         }
239         if (check_type & 2)     /* load areas */
240         {
241                                 /* netmail, dupe, bad */
242 
243             fc_add_area(&(fc_config->dupeArea), 0, 1);
244             fc_add_area(&(fc_config->badArea), 0, 1);
245 
246                                 /* netmail areas */
247             for (i=0; i<fc_config->netMailAreaCount; i++)
248             {
249                 fc_area = &(fc_config->netMailAreas[i]);
250                 if (fc_area->msgbType != MSGTYPE_PASSTHROUGH)
251                 {
252                     fc_add_area(fc_area, 1, 0);
253                 }
254             }
255 
256                                 /* local areas */
257             for (i=0; i<fc_config->localAreaCount; i++)
258             {
259                 fc_area = &(fc_config->localAreas[i]);
260                 if (fc_area->msgbType != MSGTYPE_PASSTHROUGH)
261                 {
262                     fc_add_area(fc_area, 0, 1);
263                 }
264             }
265 
266                                 /* echomail areas */
267             for (i=0; i<fc_config->echoAreaCount; i++)
268             {
269                 fc_area = &(fc_config->echoAreas[i]);
270                 if (fc_area->msgbType != MSGTYPE_PASSTHROUGH)
271                 {
272                     fc_add_area(fc_area, 0, 0);
273                 }
274             }
275         }
276 
277         disposeConfig(fc_config);
278     }
279     else
280     {
281         printf ("\r\aError! Cannot open fidoconfig!\n");
282         exit(-1);
283     }
284 #endif
285 }
286 #else
287 
288 /* ===================================================================== */
289 /* Part 2: Fidoconfig routines that directly parse the Fidoconfig file   */
290 /* ===================================================================== */
291 
292 static void read_fidoconfig_file (char *filename, int check_type);
293 static FIDO_ADDRESS fc_default_address;
294 static int fc_default_address_set;
295 static char *fc_config_nodelistDir;
296 static char *fc_config_fidoUserList;
297 
check_fidoconfig(char * option_string)298 void check_fidoconfig(char *option_string)
299 {
300     char *filename;
301     int check_type;
302 
303     if (option_string != NULL && !stricmp(option_string, "settings"))
304     {
305         check_type = 1;
306     }
307     else if (option_string != NULL && !stricmp(option_string, "both"))
308     {
309         check_type = 3;
310     }
311     else /* Default: Load areas only */
312     {
313        check_type = 2;
314     }
315 
316     filename = getenv("FIDOCONFIG");
317 
318     if (filename == NULL)
319     {
320         printf ("\r\nError: You must set the FIDOCONFIG environment variable!\n");
321         return;
322     }
323 
324     fc_default_address_set = 0;
325     memset(&fc_default_address, 0, sizeof(FIDO_ADDRESS));
326     release (fc_default_address.domain);
327 
328     fc_config_nodelistDir = NULL;
329     fc_config_fidoUserList = NULL;
330 
331     read_fidoconfig_file(filename, check_type);
332 
333     if (fc_config_nodelistDir != NULL &&
334         fc_config_fidoUserList != NULL)
335     {
336         release(ST->userlist);
337         ST->userlist = xmalloc(strlen(fc_config_nodelistDir) +
338                                strlen(fc_config_fidoUserList) + 1);
339         strcpy(ST->userlist, fc_config_nodelistDir);
340         strcat(ST->userlist, fc_config_fidoUserList);
341     }
342     release(fc_config_nodelistDir);
343     release(fc_config_fidoUserList);
344 }
345 
get_rest_of_line(void)346 static char *get_rest_of_line(void)
347 {
348     static char *rest;
349     char *ptr;
350     int len=0;
351 
352     if ((rest = strtok(NULL, "")) == NULL)
353     {
354         return NULL;
355     }
356 
357     for (ptr = rest; *ptr == ' ' || *ptr == '\t'; ptr ++);
358 
359     if ((len = strlen(ptr)) == 0)
360     {
361         return NULL;
362     }
363 
364     len --;
365 
366     while (len >= 0 && (ptr[len] == ' ' || ptr[len] =='\t'))
367     {
368         len--;
369     }
370     ptr[len + 1] = '\0';
371 
372     return ptr;
373 }
374 
375 
parse_fc_sysop(void)376 static void parse_fc_sysop(void)
377 {
378     int i;
379     char *sysop = get_rest_of_line();
380 
381     if (sysop)
382     {
383         for (i = 0; i < MAXUSERS; i++)
384         {
385             if (user_list[i].name == NULL)
386             {
387                 break;
388             }
389         }
390 
391         if (i < MAXUSERS)
392         {
393             user_list[i].name = xstrdup(sysop);
394             if (i == 0)
395             {
396                 release(ST->username);
397                 ST->username = xstrdup(user_list[i].name);
398                 SW->useroffset = user_list[i].offset;
399             }
400         }
401     }
402 }
403 
404 
parse_fc_address(int check_type)405 static void parse_fc_address(int check_type)
406 {
407     char *token = strtok(NULL, " \t");
408     FIDO_ADDRESS tmp;
409     tmp = parsenode(token);
410 
411     if (token == NULL)
412     {
413         printf ("\r\nFidoconfig address statement missing argument.\n");
414         return;
415     }
416 
417     if (!fc_default_address_set)
418     {
419         fc_default_address_set = 1;
420         copy_addr(&fc_default_address, &tmp);
421     }
422 
423     if (check_type & 1) /* load settings */
424     {
425         alias = xrealloc(alias, (++SW->aliascount) * sizeof(FIDO_ADDRESS));
426         memset(alias + SW->aliascount - 1, 0, sizeof(FIDO_ADDRESS));
427         copy_addr(alias + SW->aliascount - 1, &tmp);
428     }
429     release(tmp.domain);
430 }
431 
parse_fc_tosslog(void)432 static void parse_fc_tosslog(void)
433 {
434     char *tosslog = get_rest_of_line();
435 
436     if (tosslog)
437     {
438         release(ST->echotoss);
439         ST->echotoss = pathcvt(xstrdup(tosslog));
440     }
441 }
442 
parse_fc_fidouserlist()443 static void parse_fc_fidouserlist()
444 {
445     fc_config_fidoUserList = xstrdup(get_rest_of_line());
446 }
447 
parse_fc_nodelistdir()448 static void parse_fc_nodelistdir()
449 {
450     fc_config_nodelistDir = xstrdup(get_rest_of_line());
451 }
452 
parse_fc_include(int check_type)453 static void parse_fc_include(int check_type)
454 {
455     char *token = strtok(NULL, " \t");
456     char *fn;
457     char *duptoken;
458 
459     if (token != NULL)
460     {
461         duptoken = xstrdup(token);
462         fn = pathcvt(duptoken);
463         read_fidoconfig_file(fn, check_type);
464         xfree(fn);
465     }
466     else
467     {
468         printf ("\r\nFidoconfig include statement missing argument.\n");
469     }
470 }
471 
fc_get_description(char * firsttoken)472 static char *fc_get_description(char *firsttoken)
473 {
474 
475     static char desc[257];
476     char *token = firsttoken;
477     int len = 0;
478 
479     *desc = '\0';
480     while(token != NULL)
481     {
482         if (len + 1 >= sizeof(desc))
483         {
484             return NULL;
485         }
486         if (*desc)
487         {
488             desc[len++] = ' '; desc[len] = '\0';
489         }
490         else
491         {
492             if (*token=='"')
493             {
494                 token++;
495             }
496         }
497         if (len + strlen(token) >= sizeof(desc))
498         {
499             return NULL;
500         }
501         strcpy(desc + len, token);
502         len += strlen(token);
503 
504         if (!len || desc[len - 1]!='"')
505         {
506             token=strtok(NULL, " \t");
507         }
508         else
509         {
510             token = NULL;
511             if (len)
512             {
513                 desc[len - 1] = '\0';
514             }
515         }
516     }
517 
518     return desc;
519 }
520 
521 
522 
parse_fc_area(int type)523 static void parse_fc_area(int type)
524 {
525     static AREA a;
526     char *area_description = NULL;
527     char *token;
528     int option;
529 
530     memset(&a, 0, sizeof(AREA));
531 
532     token = strtok(NULL, " \t");
533     if (token == NULL)
534     {
535         printf ("\r\nFidoconfig *area statement missing argument.\n");
536         return;
537     }
538 
539     a.tag = xstrdup(token);
540 
541     token = strtok(NULL, " \t");
542     if (token == NULL)
543     {
544         xfree(a.tag);
545         printf ("\r\nFidoconfig *area statement missing argument.\n");
546         return;
547     }
548     else if (!stricmp(token, "passthrough"))
549     {
550         xfree(a.tag);
551         return;
552     }
553 
554     a.path = pathcvt(xstrdup(token));
555 
556     copy_addr(&(a.addr), &(fc_default_address));
557 
558     switch(type)
559     {
560     case 1:
561         a.netmail = 1;
562 	a.priv    = 1;
563         break;
564     case 2:
565         a.local = 1;
566         break;
567     case 3:
568         a.echomail = 1;
569         break;
570     }
571 
572     a.msgtype = FIDO;
573 
574     token = strtok(NULL, " \t");
575     while (token != NULL)
576     {
577         if (token[0] == '-')
578         {
579             option = 0;
580             if (!stricmp(token + 1, "b"))
581             {
582                 option = 1;
583             }
584             else if (!stricmp(token + 1, "a"))
585             {
586                 option = 2;
587             }
588             else if (!stricmp(token + 1, "g"))
589             {
590                 option = 3;
591             }
592             else if (!stricmp(token + 1, "d"))
593             {
594                 option = 4;
595             }
596 
597             if (option)
598             {
599                 token = strtok(NULL, " \t");
600                 if (token != NULL)
601                 {
602                     switch(option)
603                     {
604                     case 1:
605                         if (!stricmp(token, "msg"))
606                         {
607                             a.msgtype = FIDO;
608                         }
609 #ifdef USE_MSGAPI
610                         else if (!stricmp(token, "squish"))
611                         {
612                             a.msgtype = SQUISH;
613                         }
614                         else if (!stricmp(token, "jam"))
615                         {
616                             a.msgtype = JAM;
617                         }
618 #endif
619                         else
620                         {
621                             release(a.tag);
622                             release(a.path);
623                             release(a.addr.domain);
624                             return;
625                         }
626                         break;
627 
628                     case 2:
629                         release(a.addr.domain);
630                         a.addr = parsenode(token);
631                         break;
632 
633                     case 3:
634                         a.group = group_gethandle(token, 1);
635                         break;
636 
637                     case 4:
638                         area_description = fc_get_description(token);
639                         break;
640                     }
641                 }
642             }
643         }
644         token = strtok(NULL, " \t");
645     }
646 
647     a.description=makeareadesc(a.tag, area_description);
648     applyflags(&a, areafileflags);
649     AddArea(&a);
650 }
651 
parse_fc_line(char * line,int check_type)652 static void parse_fc_line(char *line, int check_type)
653 {
654     char *token;
655 
656     if (!(*line))
657     {
658         return;
659     }
660 
661     token = strtok(line, " \t");
662 
663     if (token == NULL)
664     {
665         return;
666     }
667 
668     if ((check_type & 2) &&
669         ((!stricmp(token, "netmailarea")) ||
670          (!stricmp(token, "netarea"))))
671     {
672         parse_fc_area(1); /* netmail folders */
673     }
674     else if ((check_type && 2) &&
675              ((!stricmp(token, "dupearea")) ||
676               (!stricmp(token, "badarea")) ||
677               (!stricmp(token, "localarea"))))
678     {
679         parse_fc_area(2); /* local folders */
680     }
681     else if ((check_type && 2) &&
682              (!stricmp(token, "echoarea")))
683     {
684         parse_fc_area(3); /* echomail folders */
685     }
686     else if ((!stricmp(token, "include")))
687     {
688         parse_fc_include(check_type);
689     }
690     else if ((!stricmp(token, "address")))
691     {
692         parse_fc_address(check_type);
693     }
694     else if ((check_type && 1) &&
695              (!stricmp(token, "sysop")))
696     {
697         parse_fc_sysop();
698     }
699     else if ((check_type && 1) &&
700              (!stricmp(token, "echotosslog")))
701     {
702         parse_fc_tosslog();
703     }
704     else if ((check_type && 1) &&
705              (!stricmp(token, "fidouserlist")))
706     {
707         parse_fc_fidouserlist();
708     }
709     else if ((check_type && 1) &&
710              (!stricmp(token, "nodelistdir")))
711     {
712         parse_fc_nodelistdir();
713     }
714     else
715     {
716         /* unknown token */
717         ;
718     }
719 
720     return;
721 }
722 
read_fidoconfig_file(char * filename,int check_type)723 static void read_fidoconfig_file (char *filename, int check_type)
724 {
725     FILE *f = fopen(filename, "r");
726     static char *line = NULL; /* uh, oh, care for reentrance! */
727     char *start;
728     char *expanded_line;
729     size_t l;
730     int c;
731 
732     if (line == NULL) line = xmalloc(2048);
733 
734     if (f == NULL)
735     {
736         printf ("\r\nError: Can't open %s while parsing fidoconfig file.\n",
737                 filename);
738         return;
739     }
740 
741     while(fgets(line, 2048, f) != NULL)
742     {
743         l = strlen(line);
744 
745         /* handle trailing \n */
746         if (l)
747         {
748             if (line[l-1] != '\n')
749             {
750                 /* eat up superfluous characters in extra long line */
751                 do
752                 {
753                     c = fgetc(f);
754                 } while (c != '\n' && c != EOF);
755             }
756             else
757             {
758                 line[l-1] = '\0';
759             }
760         }
761 
762         /* trim spaces at beginning */
763         for (start = line;
764              ((*start == ' ') || (*start == '\t') || (*start == (char)0xFE));
765              start++, l--);
766         memmove(line, start, l+1);
767 
768         /* trim trailing spaces */
769         while (l && (line[l - 1] == ' ' || line[l - 1] == '\t'))
770         {
771             line[l - 1] = '\0';
772             l--;
773         }
774 
775         /* strip comments */
776         if (*line == '#')
777         {
778             *line='\0';
779         }
780         else
781         {
782             start = strchr(line,'#');
783             if ((start != NULL) && (*(start - 1)==' ' || *(start - 1) == '\t'))
784             {
785                 *(start - 1) = '\0';
786             }
787         }
788 
789         expanded_line = env_expand(line); /* expand %ENVIRONMENT% variables */
790         parse_fc_line(expanded_line, check_type);
791         xfree(expanded_line);
792     }
793 
794     fclose(f);
795 }
796 #endif
797