/* * Copyright (C) 2001-2003 R. David Quattlebaum * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ /* $Id: parse.c,v 1.27 2003/06/14 14:35:02 drq Exp $ */ /* * parse the config file for scud */ #include #include #include #include #ifdef WIN32 #include #include #include "regex.h" #else #include #include #include #include #include #include #include #include #endif #include "scud.h" #include "lists.h" #include "util.h" /* * prototypes */ int file_to_argv(char *, char ***); void parse_args(int, char **); /* * option variables */ int allow = 0; int console= 0; int *logfile = 0; char *logfilename=LOGFILE; char *device = DEFAULT_MODEM; int private = 0; int unavailable = 0; int verbose; char *modeminit = NULL; int sync_duration = 10; int hangup_duration = 1; int heartbeat = 10*60; /* ten minutes between resets */ char call_action = 'A'; int action_delay = 0; char *input_file = NULL; int double_byte=0; int action_start = -1; int action_stop = 9999; /* * lists of names and number that we also want to hangup on */ QUEUEID names = NULL; QUEUEID phones = NULL; /* * external global variables */ extern int debug; static char __usage_buffer[65536]; void usage(char *format, ...) { va_list ap; char *buffer = __usage_buffer; int rc; va_start(ap, format); rc = vsprintf(buffer, format, ap); va_end(ap); log_printf("%s\n" " scud - Selected Caller and Unavailable Deterrent\n\n" " SYNTAX: scud [-ACTion [-ALLOW] [-CONsole]\n" " [-DELay ] [-DEVice ] [-DBLBYTE]\n" " [-HANGUPDuration ] [-INItcid ]\n" " [-LOG [-MODEMDuration ]\n" " [-NAMe ] [-PHOne ]\n" " [-TIMErange hhmm-hhmm]\n" " [-PRIVate] [-UNAVailable] [-VERBose]\n" " WHERE :\n\n" " -ACTion - tells scud what action to take\n" " -ALLOW - will reverse the behavior of scud. This will\n" " cause scud to use the config file to determine\n" " what callers to 'allow'. All others will be answered.\n" " -CONFIG - use this config file instead of system config file\n" " -CONsole - print log to stdout also\n" " -DELay - delay nn seconds after an action, to allow all calls\n" " thru. Default is 0\n" " -DEVice - what device to use as the modem\n" " default is /dev/cuaa1\n" " -DBLBYTE - callerid from modem is double byte ascii\n" " -HANGUPDuration - duration between off-hook, on-hook\n" " -HEARTbeat - Reset modem every seconds. Default is 600\n" " -INItcid - special init string for CID\n" " -LOG - data will be logged here.\n" " default is /var/log/scud.log\n" " -MODEMDuration - duration for modem sync signal\n" " -NAME - perform action if callerid name matches \n" " you can supply more than one -name option\n" " -PHOne - perform action if callerid name matches \n" " you can supply more than one -phone option\n" " -TIMERange - only perform action during this time range\n" " -PRIVate - perform action if caller id number is PRIVATE\n" " -UNAVailable - perform action if caller id number is UNAVAILABLE\n" " -VERBose - produce verbose output (level 1-2 so far)\n" , buffer); exit(1); } /*----------------------------------------------------------------------------+ | file_to_argv(file, argv) | | | | break up file into tokens and return an argv list. | | | | returns: argc | | | +----------------------------------------------------------------------------*/ int file_to_argv(file, argv_out) char *file; char ***argv_out; { int fd, len, i; char *filedata, *eod; struct stat sb; char *cp, *tp; char delim; int qrc; QNODEID token; QUEUEID tokens = lcreat(NULL, 0); int tcnt = 0; char **argv; /* set up initial values for argc and argv */ argv = NULL; /* open the file and gulp it's entire contents in */ #ifdef WIN32 if ((fd = (int)CreateFile(file, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0)) == BAD_FD) { if (GetLastError() != ERROR_FILE_NOT_FOUND) { log_printf("Can't open config file: %s\n", file); #else if ((fd = open(file, O_RDONLY)) == BAD_FD) { if (errno != ENOENT) { perror(";E: open (file_to_argv)"); #endif } return(-1); } if (stat(file, &sb) == -1) { perror(";E: stat (file_to_argv)"); return(-1); } if (!sb.st_size) { close(fd); return(0); } filedata = malloc(sb.st_size+1); #ifdef WIN32 qrc = ReadFile((HANDLE)fd, filedata, sb.st_size, &len, 0); #else len = read(fd, filedata, sb.st_size); #endif if (len != sb.st_size) { log_printf("ERROR: Didn't read entire file! only read %d of %d bytes\n", len, (int)sb.st_size); } /* let's run thru the file creating a linked list of tokens */ eod=filedata+len-1; for (cp=filedata; cp < eod;) { /* skip over any whitespace (space, tab, newline) */ for (;isspace(*cp); cp++) if (cp > eod) break; /* skip over any # comments (up to end of line) */ if (*cp == '#') { for (;*cp != '\n';cp++); cp += 1; continue; } if (cp > eod) break; tp = cp; /* if we have a quoted string look for closing quote */ if (*tp == '\'' || *tp == '"') { delim = *tp++; for (cp=tp; *cp != delim; cp++) if (cp > eod) break; } /* else look for next space */ else { for (;!isspace(*cp); cp++) if (cp > eod) break; } *cp++ = (char)NULL; tcnt += 1; qrc = ladd(tokens, tp); } close(fd); if (tcnt) { /* let's run thru the tokens creating an argv list */ argv = malloc(tcnt*sizeof(char *)); for (token=lrmv_n(tokens,1), i=0; token; token=lrmv_n(tokens,1), i++ ) { argv[i] = token; } } *argv_out = argv; return(tcnt); } void parse_args(argc, argv) int argc; char *argv[]; { int optm; /* option value, option argument, option prefix */ char *optn = "", *opta; int i, rc; optm = argc-1; for (i=0; ipattern = opta; s->re = malloc(sizeof(regex_t)); rc = regcomp(s->re, opta, REG_FLAGS); ladd(names, s); if (i!=optm && argv[i+1][0] != '-' && argv[i+1][0] != '+') opta = argv[++i]; else opta = NULL; } } /* * -PHOne|-NUMber option */ else if ((!strncasecmp(optn, "-pho", 4)) || (!strncasecmp(optn, "-num", 4))) { Selected *s; while (opta) { if (phones == NULL) phones = lcreat(NULL, 0); s = malloc(sizeof(Selected)); s->pattern = opta; s->re = malloc(sizeof(regex_t)); rc = regcomp(s->re, opta, REG_FLAGS); ladd(phones, s); if (i!=optm && argv[i+1][0] != '-' && argv[i+1][0] != '+') opta = argv[++i]; else opta = NULL; } } /* * -PRIVate option */ else if (!strncasecmp(optn, "-priv", 5)) { private = 1; } /* * -TIMErange option */ else if (!strncasecmp(optn, "-time", 5)) { char *tc; if (opta) { tc = strchr(opta, '-'); if (!tc) tc = strchr(opta, ':'); *tc = 0; action_start = atoi(opta); action_stop = atoi(tc+1); } } /* * -UNAVailable option */ else if (!strncasecmp(optn, "-unav", 5)) { unavailable = 1; } /* * -VERBose option */ else if (!strncasecmp(optn, "-verb", 5)) { if (opta) verbose = atoi(opta); else verbose++; } /* * Invalid option, exit */ else { usage("ERROR: Unrecognized option - %s\n", optn); } } else { usage("ERROR: Unrecognized command line option - %s\n", optn); } } }