Annotation of sbbs/src/sbbs3/load_cfg.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.