/*--------------------------------------------------------------------*/ /* C o n f i g u r e . c p p */ /* */ /* Configuration routine for FTrack */ /*--------------------------------------------------------------------*/ /* Copyright (c) 2000-2002 by Fyodor Ustinov */ /* FIDONet 2:5020/79 */ /* */ /* All rights reserved. */ /*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/ /* FTrack include files */ /*--------------------------------------------------------------------*/ #include "constant.hpp" #include "vars.hpp" #include "log.hpp" #include "configure.hpp" #include "scandir.hpp" #include "cfg.tab.h" #include "script.hpp" /*--------------------------------------------------------------------*/ /* System include files */ /*--------------------------------------------------------------------*/ #ifndef UNIX #ifdef __EMX__ #include #endif #include #else #define stricmp strcasecmp #endif #include #include #include /*--------------------------------------------------------------------*/ /* Global definitions */ /*--------------------------------------------------------------------*/ int yyparse(void); /*--------------------------------------------------------------------*/ /* Global variables */ /*--------------------------------------------------------------------*/ static FILE *fh; // Configuration file handler int nxtch; // Next character. Used by Lex int LineNumber; // Current Line number int CharNumber; // Position in the current line char *chpool; // Pool for String's & Token's int avail = 0; // Current position in Pool. int DetectError; // Detected error in config file int NoTokensF = FALSE; // Special state of lexx. No tokens! char *CurrentLine; // Current translated line FA cffa; FA cffa1; FA cffa2; /*--------------------------------------------------------------------*/ /* Predefined tokens */ /*--------------------------------------------------------------------*/ static struct { char *kw; int ltp; } kwtable[] = { {"Action:",_ACTION}, {"Mask:",_MASK}, {"*Mask:",_SMASK}, {"+Mask:",_PMASK}, {"Route",_ROUTE}, {"Hold",_HOLD}, {"Direct",_DIRECT}, {"Crash",_CRASH}, {"Normal",_NORMAL}, {"AddNote",_ADDNOTE}, {"Copy",_COPY}, {"Rewrite",_REWRITE}, {"Ignore",_IGNORE}, {"Display",_DISPLAY}, {"DelFile",_DELFILE}, {"NewMsg",_NEWMSG}, {"WriteFile",_WRITEFILE}, {"AppendToFile",_APPENDTOFILE}, {"Call",_CALL}, {"Poll",_POLL}, {"Script",_ASCRIPT}, {"DeleteAttach",_DELETEATTACH}, {"ChangePath",_CHANGEPATH}, {"MoveAttach",_MOVEATTACH}, {"CopyAttach",_COPYATTACH}, {"Split",_SPLIT}, {"Recode",_RECODE}, {"LogFile:",_LOGFILE}, {"TimeStampFile:",_TIMESTAMPFILE}, {"LogLevel:",_LOGLEVEL}, {"Nodelist:",_NODELIST}, {"IndexFile:",_INDEXFILE}, {"NodelistPath:",_NODELISTPATH}, {"Address:",_ADDRESS}, {"SysopName:",_SYSOPNAME}, {"UseOwnZone",_USEOWNZONE}, {"ForceINTL",_FORCEINTL}, {"LoopStr:",_LOOPSTR}, {"ScanDir:",_SCANDIR}, {"BodyMask:",_BODYMASK}, {"*BodyMask:",_SBODYMASK}, {"+BodyMask:",_PBODYMASK}, {"KludgeMask:",_KLUDGEMASK}, {"*KludgeMask:",_SKLUDGEMASK}, {"+KludgeMask:",_PKLUDGEMASK}, {"ScriptMask:",_SCRIPTMASK}, {"*ScriptMask:",_SSCRIPTMASK}, {"+ScriptMask:",_PSCRIPTMASK}, {"MaxAge:",_MAXAGE}, {"BadMessages:",_BADMESSAGES}, {"NoLogIgnore",_NOLOGIGNORE}, {"Aka:",_AKA}, {"SkipHiddenFiles",_SKIPHIDDENFILES}, {"FileInbound:",_FILEINBOUND}, {"Outbound:",_OUTBOUND}, {"AddToNullPkt",_ADDTONULLPKT}, {"TempMail:",_TEMPMAIL}, {"TrafficLog:",_TRAFFICLOG}, {"Password:",_PASSWORD}, {"UTC:",_UTC}, {"Origin:",_ORIGIN}, {"Tearline:",_TEARLINE}, {"Include:",_INCLUDE}, {"APktDir:",_APKTDIR}, {"CreateMissingBase",_CREATEMISSINGBASE}, {"MaxAttachSize:",_MAXATTACHSIZE}, {"KillRoutedMessage:",_KILLROUTEDMESSAGE}, {"MaxNodelistAge:",_MAXNODELISTAGE}, {"UseNewVia",_USENEWVIA}, {"SetViaAlways",_SETVIAALWAYS}, {"SoftCheckInNodelists",_SOFTCHECKINNODELIST}, {"CheckPoints:",_CHECKPOINTS}, {"TrafficLogTemplate:",_TRAFFICLOGTEMPLATE}, {"Skip",_SKIP}, {"Delete",_DELETE}, {"Exit",_EXIT}, {"Move",_MOVE}, {"@BeforeRoute",_BEFOREROUTE}, {"@AfterRoute",_AFTERROUTE}, {"Renumber",_RENUMBER}, {"Unpack",_UNPACK}, {"Daily",_DAILY}, {"Weekly",_WEEKLY}, {"Flag",_FLAG}, {"Never",_NEVER}, {"Hard",_HARD}, {"Soft",_SOFT}, {"Always",_ALWAYS}, {"Semaphore:",_SEMAPHORE}, {"UseASO",_USEASO}, {"ScriptFile:",_SCRIPTFILE}, {"IgnoreBSY",_IGNOREBSY}, {"Fresh",_FRESH}, {"ScriptBefore",_BEFORESCRIPT}, {"ScriptAfter",_AFTERSCRIPT}, {NULL, LEXERR}, }; // -------------------------------------------------------------------- int SetMyAddr(FA &f) { if ((MyAddr.Zone() & FA_NOTDEF) == 0) { yyerror("Address already defined."); return (-1); } MyAddr = f; if (!MyAddr.Valid()) { yyerror("Invalid FTN Address."); return (-1); } if (MyAddr.Masked()) { yyerror("You can't use mask in our address."); return (-1); } return (0); } // -------------------------------------------------------------------- int SetSemaphoreName(char *File, unsigned int SemTime) { if (Semaphore != NULL) { yyerror("Semaphore is already set"); return(-1); } if (strlen(File) == 0) { yyerror("Missed parameter: Semaphore file name."); return (-1); } Semaphore = strdup(File); SemaphoreTime = SemTime; return (0); } // -------------------------------------------------------------------- int SetTimeStampFile(char *tmt) { FILE *fh; if (TimeStampFile != NULL) { yyerror("Timestamp file already defined."); return (-1); } if (strlen(tmt) == 0) { yyerror("Missed parameter: Timestamp file name."); return (-1); } if (access(tmt,W_OK) != 0) { /* attempt to create file */ fh = fopen(tmt,"a"); if (fh == NULL) { yyerror("Unable to create Timestamp file"); return (-1); } else { fclose(fh); } } TimeStampFile = strdup(tmt); if (!GetLastTime(TimeStampFile)) { return (-1); } return 0; } // -------------------------------------------------------------------- int SetLogFile(char *tmt) { if (LogFileName != NULL) { yyerror("Log file already defined."); return (-1); } if (strlen(tmt) == 0) { yyerror("Missed parameter: Log file name."); return (-1); } LogFileName = strdup(tmt); if (Log.Open(LogFileName) != 0) { return (-1); } if (LogLevel != 0) { Log.Level(LOGE) << "--- FTrack " << FVersion << " started." << EOL; } return 0; } // -------------------------------------------------------------------- int SetTrafficLogTemplate(char *tmt) { if (TrafficLogTpl != NULL) { yyerror("Template for Traffic log already defined."); return (-1); } if (strlen(tmt) == 0) { yyerror("Missed parameter: File name of Template for traffic Log."); return (-1); } TrafficLogTpl = strdup(tmt); return 0; } // -------------------------------------------------------------------- int SetLogLevel(int tmt) { if (LogLevel != -1) { yyerror("LogLevel already set."); return (-1); } if (tmt < 0 || tmt > 65535) { yyerror("Parameter must be a number between 0 and 65535."); return (-1); } Log.LogLevel(tmt); LogLevel = tmt; return 0; } // --------------------------------------------------------------------- int LoadScriptFile(char *fname) { if (strlen(fname) == 0) { yyerror("Missed parameter: Script file name."); return (-1); } if (access(fname,R_OK) != 0) { yyerror("Script file not found."); return (-1); } if (_LoadScriptFile(fname) != 0) return (-1); return 0; } // --------------------------------------------------------------------- int SetCreateMissingBase(void) { if (CreateMissingBase) { yyerror("CreateMissingBase already set."); return (-1); } CreateMissingBase = TRUE; return (0); } // -------------------------------------------------------------------- int SetForceINTL(void) { if (ForceINTL) { yyerror("ForceINTL already set."); return (-1); } ForceINTL = TRUE; return (0); } // -------------------------------------------------------------------- int SetNoLogIgnore(void) { if (!LogIgnore) { yyerror("NoLogIgnore already set."); return (-1); } LogIgnore = FALSE; return (0); } // -------------------------------------------------------------------- int SetSetViaAlways(void) { if (SetViaAlways) { yyerror("SetViaAlways already set."); return (-1); } SetViaAlways = TRUE; return (0); } // -------------------------------------------------------------------- int SetIgnoreBSY(void) { if (IgnoreBSY) { yyerror("IgnoreBSY already set."); return (-1); } IgnoreBSY = TRUE; return (0); } // -------------------------------------------------------------------- int SetStripPathInPkt(void) { if (StripPathInPKT) { yyerror("StripPathInPKT already set."); return (-1); } StripPathInPKT = TRUE; return (0); } // -------------------------------------------------------------------- int SetMaxAttach(int tmt) { IndBiList::ElemPtr sd; sd = ScanDirs.GetLast(); if (sd == NULL) { if (MaxAttachSize != 0) { yyerror("Global MaxAttachSize already defined."); return (-1); } } else { if (sd->_MaxAttachSize != 0) { yyerror("MaxAttachSize for this ScanDir already defined."); return (-1); } } if (tmt < 1) { yyerror("Parameter must be a number great than 0."); return (-1); } if (sd != NULL) { sd->_MaxAttachSize = tmt; } else { MaxAttachSize = tmt; } return 0; } // -------------------------------------------------------------------- int SetLoopStr(char *tmt) { IndBiList::ElemPtr sd; sd = ScanDirs.GetLast(); if (sd == NULL) { if (LoopStr != NULL) { yyerror("Loop string already defined."); return (-1); } } else { if (sd->_LoopStr != 0) { yyerror("Loop string for this ScanDir already defined."); return (-1); } } if (strlen(tmt) == 0) { yyerror("Missed parameter: Loop string."); return (-1); } if (sd != NULL) { sd->_LoopStr = strdup(tmt); } else { LoopStr = strdup(tmt); } return (0); } // -------------------------------------------------------------------- int SetOrigin(char *tmt) { if (Origin != NULL) { yyerror("Origin already defined."); return (-1); } if (strlen(tmt) == 0) { yyerror("Missed parameter: Origin string."); return (-1); } if (strlen(tmt) > 70) { yyerror("Origin string too long. Max Origin length is a 70 characters."); return (-1); } Origin = strdup(tmt); return (0); } // -------------------------------------------------------------------- int SetSysopName(char *tmt) { if (strlen(tmt) == 0) { yyerror("Missed parameter: Sysop name."); return (-1); } if (SysopName != NULL) { yyerror("Sysop name already defined."); return (-1); } SysopName = strdup(tmt); return 0; } // -------------------------------------------------------------------- int SetTearline(char *tmt) { if (Tearline != NULL) { yyerror("Tearline already defined."); return (-1); } if (strlen(tmt) == 0) { yyerror("Missed parameter: Tearline string."); return (-1); } if (strlen(tmt) > 70) { yyerror("Tearline string too long. Max Tearline length is a 70 characters."); return (-1); } Tearline = strdup(tmt); return (0); } // -------------------------------------------------------------------- int SetNewVia(void) { if (NewVIAType) { yyerror("NewVIA mode already set."); return (-1); } NewVIAType = TRUE; return (0); } // -------------------------------------------------------------------- int SetUseOwnZone(void) { if (UseOwnZone) { yyerror("UseOwnZone already set."); return (-1); } UseOwnZone = TRUE; return (0); } // -------------------------------------------------------------------- int SetUseASO(void) { if (UseASO) { yyerror("UseASO already set."); return (-1); } UseASO = TRUE; return (0); } // -------------------------------------------------------------------- int SetSoftCheckInNodelists(void) { if (SoftCheckInNodelists) { yyerror("SoftCheckInNodelists already set."); return (-1); } SoftCheckInNodelists = TRUE; return (0); } // -------------------------------------------------------------------- int SetAPktDir(char *tmt) { char Buff[1024]; char Buff2[1024]; if (APktDir != NULL) { yyerror("APktDir already defined."); return (-1); } if (strlen(tmt) == 0) { yyerror("Missed parameter: directory name."); return (-1); } if (!DirExists(tmt)) { yyerror("Directory not exists."); return (-1); } if (Outbound != NULL) { strcpy(Buff,Outbound); if (Buff[strlen(Buff)-1] == PATHDELIMC) Buff[strlen(Buff)-1] = '\0'; strcpy(Buff2,tmt); if (Buff2[strlen(Buff2)-1] == PATHDELIMC) Buff2[strlen(Buff2)-1] = '\0'; if (stricmp(Buff,Buff2) == 0) { yyerror("APKT directory and Outbound directory should be in different place."); return (-1); } } APktDir = strdup(tmt); return (0); } int SetCheckPoints(CheckPointsT pmode) { CheckPoints = pmode; return (0); } // -------------------------------------------------------------------- int SetNodelistPath(char *tmt) { char Buf[1024]; if (strlen(tmt) == 0) { yyerror("Missed parameter: Nodelists path."); return (-1); } if (!DirExists(tmt)) { yyerror("Directory not found."); return (-1); } strcpy(Buf,tmt); if (Buf[strlen(Buf)-1] != PATHDELIMC) { strcat(Buf,PATHDELIMS); } NodelistPath = strdup(Buf); return 0; } // -------------------------------------------------------------------- int SetIndexFile(char *tmt) { if (strlen(tmt) == 0) { yyerror("Missed parameter: Index file name."); return (-1); } Ndl.IndexFile(tmt); return 0; } // -------------------------------------------------------------------- int SetUTC(int i) { if (UTC != 99) { yyerror("UTC offset already defined."); return (-1); } if (i < -12 || i > 12) { yyerror("UTC offset must be a number between -12 and +12."); return (-1); } UTC = i; return 0; } /*--------------------------------------------------------------------*/ /* P a r s e C o n f i g */ /* */ /* Read and parse configuration file */ /*--------------------------------------------------------------------*/ // extern int yydebug; int ParseConfig(char *CfgFile) { int rc; // Open configuration File // yydebug = 1; CHP = 1003; if (access(CfgFile,R_OK) != 0) { Log.Level(LOGE) << "Configuration file '" << CfgFile << "' not found." << EOL; return (-1); } CHP = 1004; fh = fopen(CfgFile,"rt"); if (fh == 0) { Log.Level(LOGE) << "Unable to open configuration file '" << CfgFile << "'." << EOL; return (-1); } // Initialise variables LineNumber = 0; CharNumber = 0; avail = 0; CHP = 1005; chpool = (char *)malloc(MAXCFGLINE); CurrentLine = (char *)malloc(MAXCFGLINE); CHP = 1006; CheckMem(chpool); CheckMem(CurrentLine); CHP = 1007; // Parse rc = yyparse(); // Done? // if (!feof(fh)) { // Log.Level(LOGE) << "Error(s) in configuration file '" << CfgFile << "'." << EOL; // rc = -1; // } free(CurrentLine); CurrentLine = NULL; free(chpool); chpool = NULL; fclose(fh); return (rc); } /*--------------------------------------------------------------------*/ /* y y e r r o r */ /* */ /* Show error message from lexical analiser */ /*--------------------------------------------------------------------*/ static int Pos = 0; int yyerror(char *s) { int i; Log.Level(LOGE) << "\nError in '" << ConfigFile << "' Line: " << LineNumber << EOL; Log.Level(LOGE) << CurrentLine << EOL; for (i = 0; i < Pos; i++) { Log.Level(LOGE) << " "; } Log.Level(LOGE) << "^ "; if (stricmp(s,"parse error") == 0) { Log.Level(LOGE) << "Syntax error. Please, refer to documentation." << EOL; } else { Log.Level(LOGE) << s << EOL; } return(0); } /*--------------------------------------------------------------------*/ /* S e a r c h T o k e n */ /* */ /* Search token in table and return his number */ /*--------------------------------------------------------------------*/ int SearchToken(char *s) { int i; int l; char *Buff; l = strlen(s); if (l == 0) { return(LEXERR); } Buff = (char *)malloc(l+1); CheckMem(Buff); strcpy(Buff,s); for (i = 0; i < l; i++) { if (Buff[i] != '\0' && strchr(DELIMETERS,Buff[i]) != NULL) { Buff[i] = '\0'; break; } } if (strlen(Buff) == 0) { free(Buff); return (LEXERR); } for (i = 0; kwtable[i].kw != NULL; i++) { if (!stricmp(Buff, kwtable[i].kw)) break; } // if (LogLevel >= 5) { if (kwtable[i].kw != NULL) { Pos += strlen(Buff); // Log.Level(LOGD) << "Found token: '" << kwtable[i].kw << "'." << EOL; } else { // Log.Level(LOGD) << "token: '" << Buff << "' not found." << EOL; } // } free(Buff); return(kwtable[i].ltp); } /*--------------------------------------------------------------------*/ /* T o k e n N a m e */ /* */ /* Search token in table by number and return his name */ /*--------------------------------------------------------------------*/ char *TokenName(int s) { int i; for (i = 0; kwtable[i].kw != NULL; i++) { if (kwtable[i].ltp == s) break; } return(kwtable[i].kw); } /*--------------------------------------------------------------------*/ /* T a k e C h a r */ /* */ /* Get one char from stream with buffering */ /* Look forward, and if get token then return token. */ /* */ /* NoTokenF: TRUE Disable tokenise stream. */ /* FALSE Enable tokenise stream. */ /*--------------------------------------------------------------------*/ static tLexState LexStat = LEX_START; static int NeedLoad = TRUE; int TakeChar(void) { int rctk; char *tmt; if (NeedLoad) { if (fgets(CurrentLine,MAXCFGLINE,fh) == NULL) { NeedLoad = TRUE; return (__EOF); } LineNumber++; NeedLoad = FALSE; Pos = 0; CharNumber = 0; avail = 0; tmt = strrchr(CurrentLine,'\n'); if (tmt != NULL) *tmt = '\0'; tmt = strrchr(CurrentLine,'\r'); if (tmt != NULL) *tmt = '\0'; } if (CurrentLine[Pos] == '\0') { NeedLoad = TRUE; return (_CRLF); } if (LexStat == LEX_START && NoTokensF != TRUE) { rctk = SearchToken(&CurrentLine[Pos]); } else { rctk = LEXERR; } if (rctk == LEXERR) { return (CurrentLine[Pos++]); } else { return (rctk); } } // -------------------------------------------------------------------- void AddEnv(char *Buf, char *env) { char *tmt; tmt = getenv(env); if (tmt != NULL) { strcat(Buf,tmt); } else if (StrIsXNum(env)) { tmt = Buf+ strlen(Buf); *tmt++ = strtol(env,NULL,16); *tmt = '\0'; } else { // strcat(Buf,env); } } /*--------------------------------------------------------------------*/ /* P r e p a r e S t r i n g */ /* */ /* Translate in string all '%blabla%' as environment variabless */ /* and'%01%' as hexadecimal characters. */ /*--------------------------------------------------------------------*/ char *PrepareString(char *tmt){ char *tmt2, *c; static char Buff[MAXCFGLINE]; Buff[0] = '\0'; tmt2 = Buff; while(*tmt != '\0') { if (*tmt == '%') { tmt++; if (*tmt == '%') { *tmt2++ = *tmt++; *tmt2 = '\0'; continue; } if ((c = strchr(tmt,'%')) != NULL) { *c = '\0'; AddEnv(tmt2,tmt); *c = '%'; tmt = c + 1; tmt2 += strlen(tmt2); } else { *tmt2++ = '%'; *tmt2++ = *tmt++; *tmt2 = '\0'; continue; } } else { *tmt2++ = *tmt++; *tmt2 = '\0'; } } return Buff; } /*--------------------------------------------------------------------*/ /* y y l e x */ /* */ /* Lexical analiser */ /*--------------------------------------------------------------------*/ int yylex(void) { char *p; p = NULL; if (DetectError) { LexStat = LEX_ERROR; } while (1) { switch (LexStat) { case LEX_START : nxtch = TakeChar(); LexStat = LEX_PARSE; break; case LEX_PARSE : if (nxtch > 256) { if (nxtch == __EOF) { LexStat = LEX_END; break; } else if (nxtch == _CRLF) { LexStat = LEX_CRLF; break; } else { LexStat = LEX_START; return(nxtch); } // printf("NxtCh == '%s'(%d)\n",TokenName(nxtch),nxtch); // } else { // printf("NxtCh == '%c'(%d)\n",nxtch,nxtch); } if (strchr(DELIMETERS,nxtch) != NULL) { LexStat = LEX_START; break; } else if (isdigit(nxtch)) { yylval.ln = 0; LexStat = LEX_DIGIT; break; } else if (nxtch == '(') { LexStat = LEX_COMMENT; break; } else if (nxtch == '\\') { LexStat = LEX_COMMLINE; break; } else if (nxtch == '"') { p = &chpool[avail]; LexStat = LEX_STRING; break; } else { LexStat = LEX_START; return(nxtch); } case LEX_DIGIT : if (isdigit(nxtch) && nxtch < 256) { yylval.ln = (yylval.ln * 10) + nxtch - '0'; nxtch = TakeChar(); break; } else { LexStat = LEX_PARSE; return (_DIGIT_); } case LEX_COMMENT : nxtch = TakeChar(); if (nxtch == __EOF) { LexStat = LEX_PARSE; } if (nxtch == ')') { LexStat = LEX_START; } break; case LEX_COMMLINE : nxtch = TakeChar(); if (nxtch == __EOF || nxtch == _CRLF) { LexStat = LEX_PARSE; } break; case LEX_ERROR : if (nxtch == _CRLF || nxtch == __EOF) { NoTokensF = FALSE; LexStat = LEX_PARSE; } else { nxtch = TakeChar(); } break; case LEX_STRING : if (avail + 3 > MAXCFGLINE) { Log.Level(LOGE) << "Internal error #1. Please, contact with author!" << EOL; exit(-1); } nxtch = TakeChar(); if (nxtch == _CRLF || nxtch == __EOF) { LexStat = LEX_PARSE; return (LEXERR); } else if (nxtch == '"') { chpool[avail] = '\0'; avail -= strlen(p); strcpy(p,PrepareString(p)); avail += (strlen(p) + 1); yylval.ch = p; LexStat = LEX_START; return (_STRING); } else { chpool[avail++] = nxtch; break; } case LEX_CRLF : DetectError = FALSE; LexStat = LEX_START; return (_CRLF); case LEX_END : return (0); default: Log.Level(LOGE) << "Wrong state of LexStateMachine!" << EOL; exit(-1); } } Log.Level(LOGE) << "Exit from LEXX!" << EOL; exit(-1); return (0); } /*--------------------------------------------------------------------*/ /* Nested include file */ /*--------------------------------------------------------------------*/ extern int yychar; int SetInclude(char *tmt) { int sLineNumber; int sCharNumber; int sAvail; int snxtch; char *schpool; char *sCurrentLine; FILE *sFh; char *sConfigFile; if (strlen(tmt) == 0) { yyerror("Missed parameter: Include file name."); return (-1); } if (access(tmt,R_OK) != 0) { yyerror("File is not exists."); return (-1); } sLineNumber = LineNumber; sCharNumber = CharNumber; sFh = fh; sAvail = avail; snxtch = nxtch; sConfigFile = ConfigFile; ConfigFile = strdup(tmt); CheckMem(ConfigFile); schpool = chpool; sCurrentLine = CurrentLine; if (ParseConfig(tmt) != 0) { return(-1); } LexStat = LEX_START; chpool = schpool; CurrentLine = sCurrentLine; LineNumber = sLineNumber; nxtch = _CRLF; yychar = _CRLF; fh = sFh; free(ConfigFile); ConfigFile = sConfigFile; NeedLoad = TRUE; return (0); }