|
|
1.1 root 1: /* load_cfg.c */
2:
3: /* Synchronet configuration load routines (exported) */
4:
5: /* $Id: load_cfg.c,v 1.56 2006/01/09 23:41:13 rswindell Exp $ */
6:
7: /****************************************************************************
8: * @format.tab-size 4 (Plain Text/Source Code File Header) *
9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
10: * *
11: * Copyright 2004 Rob Swindell - http://www.synchro.net/copyright.html *
12: * *
13: * This program is free software; you can redistribute it and/or *
14: * modify it under the terms of the GNU General Public License *
15: * as published by the Free Software Foundation; either version 2 *
16: * of the License, or (at your option) any later version. *
17: * See the GNU General Public License for more details: gpl.txt or *
18: * http://www.fsf.org/copyleft/gpl.html *
19: * *
20: * Anonymous FTP access to the most recent released source is available at *
21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net *
22: * *
23: * Anonymous CVS access to the development source and modification history *
24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: *
25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login *
26: * (just hit return, no password is necessary) *
27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src *
28: * *
29: * For Synchronet coding style and modification guidelines, see *
30: * http://www.synchro.net/source.html *
31: * *
32: * You are encouraged to submit any modifications (preferably in Unix diff *
33: * format) via e-mail to [email protected] *
34: * *
35: * Note: If this box doesn't appear square, then you need to fix your tabs. *
36: ****************************************************************************/
37:
38: #include "sbbs.h"
39: #include "text.h" /* TOTAL_TEXT */
40:
41: static void prep_cfg(scfg_t* cfg);
42: static void free_attr_cfg(scfg_t* cfg);
43:
44: char * readtext(long *line, FILE *stream);
45: int lprintf(int level, char *fmt, ...); /* log output */
46:
47: /****************************************************************************/
48: /* Initializes system and node configuration information and data variables */
49: /****************************************************************************/
50: BOOL DLLCALL load_cfg(scfg_t* cfg, char* text[], BOOL prep, char* error)
51: {
52: char str[256],fname[13];
53: int i;
54: long line=0L;
55: FILE *instream;
56:
57: if(cfg->size!=sizeof(scfg_t)) {
58: sprintf(error,"cfg->size (%ld) != sizeof(scfg_t) (%d)"
59: ,cfg->size,sizeof(scfg_t));
60: return(FALSE);
61: }
62:
63: free_cfg(cfg); /* free allocated config parameters */
64:
65: cfg->prepped=FALSE; /* reset prepped flag */
66:
67: if(cfg->node_num<1)
68: cfg->node_num=1;
69:
70: backslash(cfg->ctrl_dir);
71: if(read_main_cfg(cfg, error)==FALSE)
72: return(FALSE);
73:
74: if(prep)
75: for(i=0;i<cfg->sys_nodes;i++)
76: prep_dir(cfg->ctrl_dir, cfg->node_path[i], sizeof(cfg->node_path[i]));
77:
78: SAFECOPY(cfg->node_dir,cfg->node_path[cfg->node_num-1]);
79: prep_dir(cfg->ctrl_dir, cfg->node_dir, sizeof(cfg->node_dir));
80: if(read_node_cfg(cfg, error)==FALSE)
81: return(FALSE);
82: if(read_msgs_cfg(cfg, error)==FALSE)
83: return(FALSE);
84: if(read_file_cfg(cfg, error)==FALSE)
85: return(FALSE);
86: if(read_xtrn_cfg(cfg, error)==FALSE)
87: return(FALSE);
88: if(read_chat_cfg(cfg, error)==FALSE)
89: return(FALSE);
90: if(read_attr_cfg(cfg, error)==FALSE)
91: return(FALSE);
92:
93: if(text!=NULL) {
94:
95: /* Free existing text if allocated */
96: free_text(text);
97:
98: strcpy(fname,"text.dat");
99: sprintf(str,"%s%s",cfg->ctrl_dir,fname);
100: if((instream=fnopen(NULL,str,O_RDONLY))==NULL) {
101: sprintf(error,"%d opening %s",errno,str);
102: return(FALSE);
103: }
104: for(i=0;i<TOTAL_TEXT && !feof(instream) && !ferror(instream);i++)
105: if((text[i]=readtext(&line,instream))==NULL) {
106: i--;
107: break;
108: }
109: fclose(instream);
110:
111: if(i<TOTAL_TEXT) {
112: sprintf(error,"line %lu in %s: Less than TOTAL_TEXT (%u) strings defined in %s."
113: ,i,fname
114: ,TOTAL_TEXT,fname);
115: return(FALSE);
116: }
117: }
118:
119: /* Override com-port settings */
120: cfg->com_base=0xf; /* All nodes use FOSSIL */
121: cfg->com_port=1; /* All nodes use "COM1" */
122:
123: if(prep)
124: prep_cfg(cfg);
125:
126: /* Auto-toggle daylight savings time in US time-zones */
127: sys_timezone(cfg);
128:
129: return(TRUE);
130: }
131:
132: /****************************************************************************/
133: /* Prepare configuration for run-time (resolve relative paths, etc) */
134: /****************************************************************************/
135: void prep_cfg(scfg_t* cfg)
136: {
137: int i;
138:
139: #if 0 /* def __unix__ */
140: strlwr(cfg->text_dir); /* temporary Unix-compatibility hack */
141: strlwr(cfg->temp_dir); /* temporary Unix-compatibility hack */
142: strlwr(cfg->data_dir); /* temporary Unix-compatibility hack */
143: strlwr(cfg->exec_dir); /* temporary Unix-compatibility hack */
144: #endif
145:
146: /* Fix-up paths */
147: prep_dir(cfg->ctrl_dir, cfg->data_dir, sizeof(cfg->data_dir));
148: prep_dir(cfg->ctrl_dir, cfg->logs_dir, sizeof(cfg->logs_dir));
149: prep_dir(cfg->ctrl_dir, cfg->exec_dir, sizeof(cfg->exec_dir));
150: prep_dir(cfg->ctrl_dir, cfg->mods_dir, sizeof(cfg->mods_dir));
151: prep_dir(cfg->ctrl_dir, cfg->text_dir, sizeof(cfg->text_dir));
152:
153: prep_dir(cfg->ctrl_dir, cfg->netmail_dir, sizeof(cfg->netmail_dir));
154: prep_dir(cfg->ctrl_dir, cfg->echomail_dir, sizeof(cfg->echomail_dir));
155: prep_dir(cfg->ctrl_dir, cfg->fidofile_dir, sizeof(cfg->fidofile_dir));
156:
157: prep_path(cfg->netmail_sem);
158: prep_path(cfg->echomail_sem);
159: prep_path(cfg->inetmail_sem);
160:
161: #if 0 /* def __unix__ */
162: /* temporary hack for Unix compatibility */
163: strlwr(cfg->logon_mod);
164: strlwr(cfg->logoff_mod);
165: strlwr(cfg->newuser_mod);
166: strlwr(cfg->login_mod);
167: strlwr(cfg->logout_mod);
168: strlwr(cfg->sync_mod);
169: strlwr(cfg->expire_mod);
170: #endif
171:
172: for(i=0;i<cfg->total_subs;i++) {
173:
174: if(!cfg->sub[i]->data_dir[0]) /* no data storage path specified */
175: sprintf(cfg->sub[i]->data_dir,"%ssubs",cfg->data_dir);
176: prep_dir(cfg->ctrl_dir, cfg->sub[i]->data_dir, sizeof(cfg->sub[i]->data_dir));
177:
178: /* default QWKnet tagline */
179: if(!cfg->sub[i]->tagline[0])
180: SAFECOPY(cfg->sub[i]->tagline,cfg->qnet_tagline);
181:
182: /* default origin line */
183: if(!cfg->sub[i]->origline[0])
184: SAFECOPY(cfg->sub[i]->origline,cfg->origline);
185:
186: /* A sub-board's internal code is the combination of the grp's code_prefix & the sub's code_suffix */
187: SAFEPRINTF2(cfg->sub[i]->code,"%s%s"
188: ,cfg->grp[cfg->sub[i]->grp]->code_prefix
189: ,cfg->sub[i]->code_suffix);
190:
191: strlwr(cfg->sub[i]->code); /* data filenames are all lowercase */
192:
193: prep_path(cfg->sub[i]->post_sem);
194: }
195:
196: for(i=0;i<cfg->total_libs;i++) {
197: if(cfg->lib[i]->parent_path[0])
198: prep_dir(cfg->ctrl_dir, cfg->lib[i]->parent_path, sizeof(cfg->lib[i]->parent_path));
199: }
200:
201: for(i=0;i<cfg->total_dirs;i++) {
202:
203: if(!cfg->dir[i]->data_dir[0]) /* no data storage path specified */
204: sprintf(cfg->dir[i]->data_dir,"%sdirs",cfg->data_dir);
205: prep_dir(cfg->ctrl_dir, cfg->dir[i]->data_dir, sizeof(cfg->dir[i]->data_dir));
206:
207: if(!cfg->dir[i]->path[0]) /* no file storage path specified */
208: sprintf(cfg->dir[i]->path,"%sdirs/%s/",cfg->data_dir,cfg->dir[i]->code);
209: else if(cfg->lib[cfg->dir[i]->lib]->parent_path[0])
210: prep_dir(cfg->lib[cfg->dir[i]->lib]->parent_path, cfg->dir[i]->path, sizeof(cfg->dir[i]->path));
211: else
212: prep_dir(cfg->ctrl_dir, cfg->dir[i]->path, sizeof(cfg->dir[i]->path));
213:
214: /* A directory's internal code is the combination of the lib's code_prefix & the dir's code_suffix */
215: sprintf(cfg->dir[i]->code,"%s%s"
216: ,cfg->lib[cfg->dir[i]->lib]->code_prefix
217: ,cfg->dir[i]->code_suffix);
218:
219: strlwr(cfg->dir[i]->code); /* data filenames are all lowercase */
220:
221: prep_path(cfg->dir[i]->upload_sem);
222: }
223:
224:
225: /* make data filenames are all lowercase */
226: for(i=0;i<cfg->total_shells;i++)
227: strlwr(cfg->shell[i]->code);
228:
229: for(i=0;i<cfg->total_gurus;i++)
230: strlwr(cfg->guru[i]->code);
231:
232: for(i=0;i<cfg->total_txtsecs;i++)
233: strlwr(cfg->txtsec[i]->code);
234:
235: for(i=0;i<cfg->total_xtrnsecs;i++)
236: strlwr(cfg->xtrnsec[i]->code);
237:
238: for(i=0;i<cfg->total_xtrns;i++)
239: {
240: strlwr(cfg->xtrn[i]->code);
241: prep_dir(cfg->ctrl_dir, cfg->xtrn[i]->path, sizeof(cfg->xtrn[i]->path));
242: }
243: for(i=0;i<cfg->total_events;i++) {
244: strlwr(cfg->event[i]->code); /* data filenames are all lowercase */
245: prep_dir(cfg->ctrl_dir, cfg->event[i]->dir, sizeof(cfg->event[i]->dir));
246: }
247: for(i=0;i<cfg->total_xedits;i++)
248: strlwr(cfg->xedit[i]->code);
249:
250: cfg->prepped=TRUE; /* data prepared for run-time, DO NOT SAVE TO DISK! */
251: }
252:
253: void DLLCALL free_cfg(scfg_t* cfg)
254: {
255: free_node_cfg(cfg);
256: free_main_cfg(cfg);
257: free_msgs_cfg(cfg);
258: free_file_cfg(cfg);
259: free_chat_cfg(cfg);
260: free_xtrn_cfg(cfg);
261: free_attr_cfg(cfg);
262: }
263:
264: void DLLCALL free_text(char* text[])
265: {
266: int i;
267:
268: if(text==NULL)
269: return;
270:
271: for(i=0;i<TOTAL_TEXT;i++) {
272: FREE_AND_NULL(text[i]);
273: }
274: }
275:
276: /****************************************************************************/
277: /* If the directory 'path' doesn't exist, create it. */
278: /****************************************************************************/
279: BOOL md(char *inpath)
280: {
281: DIR* dir;
282: char path[MAX_PATH+1];
283:
284: if(inpath[0]==0)
285: return(FALSE);
286:
287: SAFECOPY(path,inpath);
288:
289: /* Remove trailing '.' if present */
290: if(path[strlen(path)-1]=='.')
291: path[strlen(path)-1]=0;
292:
293: /* Remove trailing slash if present */
294: if(path[strlen(path)-1]=='\\' || path[strlen(path)-1]=='/')
295: path[strlen(path)-1]=0;
296:
297: dir=opendir(path);
298: if(dir==NULL) {
299: /* lprintf("Creating directory: %s",path); */
300: if(MKDIR(path)) {
301: lprintf(LOG_WARNING,"!ERROR %d creating directory: %s",errno,path);
302: return(FALSE);
303: }
304: }
305: else
306: closedir(dir);
307:
308: return(TRUE);
309: }
310:
311: /****************************************************************************/
312: /* Reads special TEXT.DAT printf style text lines, splicing multiple lines, */
313: /* replacing escaped characters, and allocating the memory */
314: /****************************************************************************/
315: char *readtext(long *line,FILE *stream)
316: {
317: char buf[2048],str[2048],tmp[256],*p,*p2;
318: int i,j,k;
319:
320: if(!fgets(buf,256,stream))
321: return(NULL);
322: if(line)
323: (*line)++;
324: if(buf[0]=='#')
325: return(NULL);
326: p=strrchr(buf,'"');
327: if(!p) {
328: if(line) {
329: lprintf(LOG_ERR,"No quotation marks in line %d of text.dat",*line);
330: return(NULL);
331: }
332: return(NULL);
333: }
334: if(*(p+1)=='\\') /* merge multiple lines */
335: while(strlen(buf)<2000) {
336: if(!fgets(str,255,stream))
337: return(NULL);
338: if(line)
339: (*line)++;
340: p2=strchr(str,'"');
341: if(!p2)
342: continue;
343: strcpy(p,p2+1);
344: p=strrchr(p,'"');
345: if(p && *(p+1)=='\\')
346: continue;
347: break;
348: }
349: *(p)=0;
350: k=strlen(buf);
351: for(i=1,j=0;i<k;j++) {
352: if(buf[i]=='\\') { /* escape */
353: i++;
354: if(isdigit(buf[i])) {
355: str[j]=atoi(buf+i); /* decimal, NOT octal */
356: if(isdigit(buf[++i])) /* skip up to 3 digits */
357: if(isdigit(buf[++i]))
358: i++;
359: continue;
360: }
361: switch(buf[i++]) {
362: case '\\':
363: str[j]='\\';
364: break;
365: case '?':
366: str[j]='?';
367: break;
368: case 'x':
369: tmp[0]=buf[i++]; /* skip next character */
370: tmp[1]=0;
371: if(isxdigit(buf[i])) { /* if another hex digit, skip too */
372: tmp[1]=buf[i++];
373: tmp[2]=0;
374: }
375: str[j]=(char)ahtoul(tmp);
376: break;
377: case '\'':
378: str[j]='\'';
379: break;
380: case '"':
381: str[j]='"';
382: break;
383: case 'r':
384: str[j]=CR;
385: break;
386: case 'n':
387: str[j]=LF;
388: break;
389: case 't':
390: str[j]=TAB;
391: break;
392: case 'b':
393: str[j]=BS;
394: break;
395: case 'a':
396: str[j]=BEL;
397: break;
398: case 'f':
399: str[j]=FF;
400: break;
401: case 'v':
402: str[j]=11; /* VT */
403: break;
404: default:
405: str[j]=buf[i];
406: break;
407: }
408: continue;
409: }
410: str[j]=buf[i++];
411: }
412: str[j]=0;
413: if((p=(char *)calloc(1,j+2))==NULL) { /* +1 for terminator, +1 for YNQX line */
414: lprintf(LOG_CRIT,"Error allocating %u bytes of memory from text.dat",j);
415: return(NULL);
416: }
417: strcpy(p,str);
418: return(p);
419: }
420:
421: /****************************************************************************/
422: /* Reads in ATTR.CFG and initializes the associated variables */
423: /****************************************************************************/
424: BOOL read_attr_cfg(scfg_t* cfg, char* error)
425: {
426: char* p;
427: char str[256],fname[13];
428: long offset=0;
429: FILE *instream;
430:
431: strcpy(fname,"attr.cfg");
432: sprintf(str,"%s%s",cfg->ctrl_dir,fname);
433: if((instream=fnopen(NULL,str,O_RDONLY))==NULL) {
434: sprintf(error,"%d opening %s",errno,str);
435: return(FALSE);
436: }
437: FREE_AND_NULL(cfg->color);
438: if((cfg->color=malloc(MIN_COLORS))==NULL) {
439: sprintf(error,"Error allocating memory (%u bytes) for colors"
440: ,MIN_COLORS);
441: return(FALSE);
442: }
443: memset(cfg->color,LIGHTGRAY|HIGH,MIN_COLORS);
444: for(cfg->total_colors=0;!feof(instream) && !ferror(instream);cfg->total_colors++) {
445: if(readline(&offset,str,4,instream)==NULL)
446: break;
447: if(cfg->total_colors>=MIN_COLORS) {
448: if((p=realloc(cfg->color,cfg->total_colors+1))==NULL)
449: break;
450: cfg->color=p;
451: }
452: cfg->color[cfg->total_colors]=attrstr(str);
453: }
454: fclose(instream);
455: if(cfg->total_colors<MIN_COLORS)
456: cfg->total_colors=MIN_COLORS;
457: return(TRUE);
458: }
459:
460: static void free_attr_cfg(scfg_t* cfg)
461: {
462: if(cfg->color!=NULL)
463: FREE_AND_NULL(cfg->color);
464: cfg->total_colors=0;
465: }
466:
467: char* DLLCALL prep_dir(char* base, char* path, size_t buflen)
468: {
469: #ifdef __unix__
470: char *p;
471: #endif
472: char str[MAX_PATH+1];
473: char abspath[MAX_PATH+1];
474: char ch;
475:
476: if(!path[0])
477: return(path);
478: if(path[0]!='\\' && path[0]!='/' && path[1]!=':') { /* Relative directory */
479: ch=*lastchar(base);
480: if(ch=='\\' || ch=='/')
481: sprintf(str,"%s%s",base,path);
482: else
483: sprintf(str,"%s%c%s",base,PATH_DELIM,path);
484: } else
485: strcpy(str,path);
486:
487: #ifdef __unix__ /* Change backslashes to forward slashes on Unix */
488: for(p=str;*p;p++)
489: if(*p=='\\')
490: *p='/';
491: #endif
492:
493: backslashcolon(str);
494: strcat(str,"."); /* Change C: to C:. and C:\SBBS\ to C:\SBBS\. */
495: FULLPATH(abspath,str,buflen); /* Change C:\SBBS\NODE1\..\EXEC to C:\SBBS\EXEC */
496: backslash(abspath);
497:
498: sprintf(path,"%.*s",(int)(buflen-1),abspath);
499: return(path);
500: }
501:
502: char* prep_path(char* path)
503: {
504: #ifdef __unix__ /* Change backslashes to forward slashes on Unix */
505: char *p;
506:
507: for(p=path;*p;p++)
508: if(*p=='\\')
509: *p='/';
510: #endif
511:
512: return(path);
513: }
514:
515: /****************************************************************************/
516: /* Auto-toggle daylight savings time in US time-zones */
517: /****************************************************************************/
518: ushort DLLCALL sys_timezone(scfg_t* cfg)
519: {
520: time_t now;
521: struct tm tm;
522:
523: if(cfg->sys_misc&SM_AUTO_DST && !OTHER_ZONE(cfg->sys_timezone) && cfg->sys_timezone&US_ZONE) {
524: now=time(NULL);
525: if(localtime_r(&now,&tm)!=NULL) {
526: if(tm.tm_isdst>0)
527: cfg->sys_timezone|=DAYLIGHT;
528: else if(tm.tm_isdst==0)
529: cfg->sys_timezone&=~DAYLIGHT;
530: }
531: }
532:
533: return(cfg->sys_timezone);
534: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.