/* * param.c -- parameter processing routine * * Copyright (c) 1995-1997 by nir@mxa.meshnet.or.jp * * This file is part of npc.cgi source tree. * npc.cgi is free software; you can redistribute it and/or modify it * for any purpose. * * @(#)$Id: param.c,v 2.5 1997/11/10 16:19:05 nir Rel $ */ /* * $Log: param.c,v $ * Revision 2.5 1997/11/10 16:19:05 nir * Modify error_out() message. * * Revision 2.4 1997/11/09 23:05:27 nir * Fix MODE option. MODE was not evaluated before config file. * * Revision 2.3 1997/11/08 18:57:17 nir * Modify set_control() function. Delete useless tag name, append GCONTROL * for generalization, as set_control() be able to use not only for assignment * but for comparison. Append RESTRICTION assignment in set_control(). * Append T_BAD condition to get_param(). * * Revision 2.2 1997/11/06 19:54:55 nir * Add MODE processing routine to debug_out() and set_control(). * * Revision 2.1 1997/11/05 12:19:48 nir * Add Copyright, Id and Log. * Change TAG search method from linear search to binary search. * TAG table is modified due to TAG search method change. * Add TAG search self test routine in the help_out(). * Extend OPTION processing routine due to addition of OPTIONs. * */ #include "npc.h" INTERN void set_addr(char *addr); INTERN void make_qstr(char *query); INTERN void help_out(void); INTERN void decode_qstr(char *str); INTERN BOOLEAN yes_or_no(char *str); INTERN int xtoi(int c); INTERN long next_color(char **pstr); INTERN struct _TAG_TABLE { enum tag_id id; char *name; } tag_table[] = { {T_ANIMATION, "A"}, {T_ADDRESS, "ADDRess"}, {T_ANIMATION, "ANimation"}, {T_BROWSER, "BROWSER"}, {T_COLOR, "Color"}, {T_COUNTER, "COUNTer"}, {T_DELAY, "De"}, {T_DEBUG, "DEBUG"}, {T_DELAY, "DELay"}, {T_DIGITS, "DIgits"}, {T_ELSE, "ELSE"}, {T_ELSIF, "ELSIF"}, {T_ENDIF, "ENDIF"}, {T_ENVIRONMENT, "ENVironment"}, {T_FALSE, "FALSE"}, {T_HELP, "Help"}, {T_HOST, "HOST"}, {T_INDEX, "I"}, {T_IF, "IF"}, {T_INDEX, "IN"}, {T_INCREMENT, "INCrement"}, {T_INDEX, "INDex"}, {T_INITIAL, "INITial"}, {T_LOCATION, "Location"}, {T_MODE, "Mode"}, {T_NUMBER, "Number"}, {T_OFFSET, "Offset"}, {T_OPTION, "OPTion"}, {T_PROGRESS, "Progress"}, {T_RANDOM, "RANdom"}, {T_REFERER, "REFerer"}, {T_RESTRICTION, "RESTRICTion"}, {T_TRANSPARENT, "Transparent"}, {T_TRUE, "TRUE"}, {T_UNIT, "Unit"}, {T_WIDTH, "Width"}, }; INTERN char *qname = "Query String"; void get_environ(int argc, char **argv) { char buf[LINE_SIZE]; char *query, *str; int len; if ((str = strrchr(*argv, SEP)) == NULL) str = *argv; else str++; env.nph = (strncmp(str, "nph-", 4) == 0); env.referer = new_str(getenv("HTTP_REFERER")); env.host = new_str(getenv("REMOTE_HOST")); env.browser = new_str(getenv("HTTP_USER_AGENT")); set_addr(getenv("REMOTE_ADDR")); if (((str = getenv("PATH_INFO")) != NULL) && (*str != EOS) && ((str = getenv("PATH_TRANSLATED")) != NULL) && (*str != EOS)) { env.index = new_str(str); } query = NULL; if ((str = getenv("REQUEST_METHOD")) == NULL) { if (argc > 1) query = argv[1]; } else if (strcmp(str, "GET") == 0) { query = getenv("QUERY_STRING"); } else if (strcmp(str, "POST") != 0) { error_out("Unknown Request Method \"%s\"", str); } else if (fgets(buf, LINE_SIZE, stdin) != NULL) { query = buf; } if (query == NULL) query = ""; for (len = strlen(query); len > 0; len--) { if (! isspace(query[len - 1])) break; } if ((str = (char *)malloc(len + 1)) == NULL) error_out("get_environ: Cannot Allocate Memory"); strncpy(str, query, len); str[len] = EOS; make_qstr(str); } INTERN void set_addr(char *str) { int addr[4]; int n; env.addr[0] = env.addr[1] = env.addr[2] = env.addr[3] = 0; if ((str == NULL) || (sscanf(str, "%d.%d.%d.%d", &addr[0], &addr[1], &addr[2], &addr[3]) != 4)) return; for (n = 0; n < 4; n++) { if ((addr[n] < 0) || (addr[n] >= 256)) return; } for (n = 0; n < 4; n++) { env.addr[n] = addr[n]; } } INTERN void make_qstr(char *query) { QSTR *qstr, *next; enum tag_id id; char *p; p = query; env.query = NULL; while (*p != EOS) { if ((qstr = (QSTR *)malloc(sizeof(QSTR))) == NULL) error_out("make_qstr: Cannot Allocate Memory"); qstr->tag = p; qstr->next = env.query; env.query = qstr; while (*p != EOS) { if (*p == '&') { *(p++) = EOS; break; } p++; } } qstr = env.query; env.query = NULL; while (qstr != NULL) { for (p = qstr->tag; *p != EOS; p++) { if (*p == '=') { *(p++) = EOS; break; } } qstr->body = p; next = qstr->next; qstr->next = env.query; env.query = qstr; qstr = next; } for (qstr = env.query; qstr != NULL; qstr = qstr->next) { decode_qstr(qstr->tag); decode_qstr(qstr->body); if ((id = tag_search(qstr->tag)) == T_HELP) { help_out(); } else if (id == T_INDEX) { if (*(env.index = qstr->body) == EOS) error_out("%s: \"%s\" TAG Has No VALUE", qname, qstr->tag); } else if (id == T_MODE) { set_control(&gcontrol, qname, id, qstr->body); } } } INTERN void help_out(void) { char *help_table[T_BAD]; char buf[MAX_CHAR]; enum tag_id id; char *p; int i, n; for (n = 0; n < T_BAD; n++) { help_table[n] = NULL; } for (n = 0; n < sizeof(tag_table) / sizeof(struct _TAG_TABLE); n++) { if ((id = tag_table[n].id) >= T_BAD) error_out("INTERNAL ERROR: help_out: Tag Table Is Corrupted"); if (help_table[id] == NULL) { help_table[id] = tag_table[n].name; } else { for (i = 0; help_table[id][i] != EOS; i++) { if (toupper(help_table[id][i]) != tag_table[n].name[i]) error_out("INTERNAL ERROR: help_out: Tag Table \"%s\" Is Corrupted", tag_table[n].name); } p = new_str(tag_table[n].name); strncpy(p, help_table[id], i); while (tag_table[n].name[i] != EOS) { p[i] = tolower(tag_table[n].name[i]); i++; } help_table[id] = p; } } p = buf; sprintf(p, "%s:", version); for (n = 0; n < T_BAD; n++) { if (help_table[n] == NULL) error_out("INTERNAL ERROR: help_out: No Table For Tag Number %d", n); p += strlen(p); sprintf(p, " %s", help_table[n]); } error_out(buf); } INTERN void decode_qstr(char *str) { char *new; new = str; while (*str != EOS) { if (*str == '+') { *(new++) = ' '; str++; } else if ((*str == '%') && isxdigit(*(str + 1)) && isxdigit(*(str + 2))) { *(new++) = 0x10 * xtoi(*(str + 1)) + xtoi(*(str + 2)); str += 3; } else { *(new++) = *(str++); } } *new = EOS; } void get_param(void) { QSTR *qstr; enum tag_id id; if ((gcontrol.restriction < 0) || (gcontrol.restriction > 1)) error_out("%s: No Permission To Use This Counter", qname); for (qstr = env.query; qstr != NULL; qstr = qstr->next) { switch (id = tag_search(qstr->tag)) { case T_BAD: error_out("%s: \"%s\" Is Unknown TAG Name", qname, qstr->tag); case T_COUNTER: case T_REFERER: case T_ADDRESS: case T_HOST: case T_BROWSER: case T_RESTRICTION: case T_IF: case T_ELSIF: case T_ELSE: case T_ENDIF: case T_OPTION: case T_TRUE: case T_FALSE: error_out("%s: \"%s\" TAG Cannot Be Used", qname, qstr->tag); case T_DEBUG: debug_out(qstr->body); case T_ENVIRONMENT: env_out(qstr->body); case T_INDEX: case T_MODE: break; case T_LOCATION: case T_NUMBER: case T_RANDOM: if ((gcontrol.restriction == 0) || ((gcontrol.restriction > 0) && (gcontrol.location == NULL) && (gcontrol.number == BAD) && (gcontrol.random == NO))) set_control(&gcontrol, qname, id, qstr->body); break; default: if (gcontrol.restriction == 0) set_control(&gcontrol, qname, id, qstr->body); break; } } } void debug_out(char *debug) { switch (tag_search(debug)) { case T_INDEX: error_out("INDEX: \"%s\"", env.index); case T_REFERER: error_out("REFERER: \"%s\"", env.referer); case T_ADDRESS: error_out("ADDRESS: %d.%d.%d.%d", env.addr[0], env.addr[1], env.addr[2], env.addr[3]); case T_HOST: error_out("HOST: \"%s\"", env.host); case T_BROWSER: error_out("BROWSER: \"%s\"", env.browser); case T_RESTRICTION: error_out("RESTRICTION: %d", gcontrol.restriction); case T_ANIMATION: error_out("ANIMATION: %s", (gcontrol.gif_animation) ? "GIF89a animation" : "Server Push"); case T_COLOR: if (gcontrol.color[0] < 0L) error_out("COLOR: (Not Present)"); else error_out("COLOR: Foreground=%06lX, Background=06lX", gcontrol.color[0], gcontrol.color[1]); case T_DELAY: error_out("DELAY: First=%dms, Rest=%dms", gcontrol.delay[0], gcontrol.delay[1]); case T_DIGITS: error_out("DIGITS: %d", gcontrol.digits); case T_INCREMENT: error_out("INCREMENT: %d", gcontrol.increment); case T_INITIAL: error_out("INITIAL: %d", gcontrol.initial); case T_LOCATION: error_out("LOCATION: \"%s\"", gcontrol.location); case T_MODE: error_out("MODE: %d", gcontrol.mode); case T_NUMBER: error_out("NUMBER: %d", gcontrol.number); case T_OFFSET: error_out("OFFSET: %d", gcontrol.offset); case T_PROGRESS: error_out("PROGRESS: \"%s\"", (gcontrol.progress) ? "YES" : "NO"); case T_RANDOM: error_out("RANDOM: \"%s\"", (gcontrol.random) ? "YES" : "NO"); case T_TRANSPARENT: error_out("TRANSPARENT: %d", gcontrol.transparent); case T_UNIT: error_out("UNIT: %d", gcontrol.unit); case T_WIDTH: error_out("WIDTH: %d", gcontrol.width); default: error_out("%s", debug); } } void set_control(GCONTROL *pg, char *name, enum tag_id id, char *param) { char *p; int c; switch (id) { case T_ANIMATION: if (((c = toupper(*param)) != 'G') && (c != 'S')) error_out("%s: \"%s\" Is Invalid Animation Mode", name, param); pg->gif_animation = (c == 'G'); break; case T_COLOR: p = param; pg->color[0] = next_color(&p); if (*p == ',') { p++; pg->color[1] = next_color(&p); } else { pg->color[1] = 0xFFFFFFL; } if ((pg->color[0] < 0L) || (pg->color[1] < 0L)) error_out("%s: \"%s\" Invalid Color Format", name, param); break; case T_DELAY: p = param; pg->delay[0] = pg->delay[1] = next_num(&p); if (*p == ',') { p++; pg->delay[1] = next_num(&p); } if ((pg->delay[0] < 0) || (pg->delay[1] < 0)) error_out("%s: \"%s\" Invalid Delay Format", name, param); break; case T_DIGITS: p = param; pg->digits = next_num(&p); if ((pg->digits < 0) || (*p != EOS)) error_out("%s: \"%s\" Invalid Digits Number", name, param); if ((p > param + 1) || (pg->digits >= 4)) error_out("%s: Digits Number %d Is Out Of Range", name, pg->digits); break; case T_INCREMENT: if (((pg->increment = atol(param)) < -1) || (pg->increment > 1)) error_out("%s: Increment Number %d Is Out Of Range", name, pg->increment); break; case T_INITIAL: if ((pg->initial = atol(param)) <= 0) error_out("%s: Minus Or Zero Initial Number %d Is Used", name, pg->initial); break; case T_LOCATION: if (*(pg->location = param) == EOS) error_out("%s: Location TAG Has No Value", name); break; case T_MODE: if ((pg->mode = atol(param)) < 0) error_out("%s: Minus Mode %d Is Used", name, pg->mode); break; case T_NUMBER: if ((pg->number = atol(param)) < 0) error_out("%s: Minus Number %d Is Used", name, pg->number); break; case T_OFFSET: pg->offset = atol(param); break; case T_PROGRESS: pg->progress = yes_or_no(param); break; case T_RANDOM: pg->random = yes_or_no(param); break; case T_RESTRICTION: if (((pg->restriction = atol(param)) < 0) || (pg->restriction > 2)) error_out("%s: Restriction Level %d Out Of Range", name, pg->restriction); break; case T_TRANSPARENT: if (((pg->transparent = atol(param)) < 0) || (pg->transparent >= 256)) error_out("%s: Transparent Palette Number %d Is Out Of Range", name, pg->transparent); break; case T_UNIT: if ((pg->unit = atol(param)) <= 0) error_out("%s: %d Is Invalid Unit", name, pg->unit); break; case T_WIDTH: if (((pg->width = atol(param)) <= 0) || (pg->width > MAX_WIDTH)) error_out("%s: %d Is Invalid Width", name, pg->width); break; default: error_out("set_control: INTERNAL ERROR: %s: Invalid TAG ID %d", name, id); } } enum tag_id tag_search(char *tag) { char *name; int i, l, n, u; l = 0; u = sizeof(tag_table) / sizeof(struct _TAG_TABLE) - 1; n = 0; while (l <= u) { n = (l + u) / 2; name = tag_table[n].name; i = 0; while (toupper(tag[i]) == name[i]) { if (tag[i] == EOS) return(tag_table[n].id); i++; } while (tolower(tag[i]) == name[i]) { if (tag[i] == EOS) return(tag_table[n].id); i++; } if ((tag[i] == EOS) && islower(name[i])) return(tag_table[n].id); if (toupper(tag[i]) < toupper(name[i])) { u = n - 1; } else { l = n + 1; } } return(T_BAD); } INTERN BOOLEAN yes_or_no(char *str) { LOCAL char *ans[10] = { "YES", "NO", "TRUE", "FALSE", "SET", "UNSET", "ON", "OFF", "1", "0" }; int i, n; if (*str == EOS) return(NO); for (n = 0; n < 10; n++) { for (i = 0; toupper(str[i]) == (ans[n])[i]; i++) { if(str[i] == EOS) return((n % 2) == 0); } } error_out("\"%s\" Is Not Boolean Value", str); } INTERN int xtoi(int c) { if (c < '0') { return(c); } else if (c <= '9') { return(c - '0'); } else if (c < 'A') { return(c); } else if (c <= 'F') { return(c - 'A' + 10); } else if (c < 'a') { return(c); } else if (c <= 'f') { return(c - 'a' + 10); } else { return(c); } } INTERN long next_color(char **pstr) { char *p; long color; p = *pstr; if (! isxdigit(*p)) return((long)BAD); color = 0L; do { color = color * 0x10 + xtoi(*(p++)); } while (isxdigit(*p)); if (p != *pstr + 6) return((long)BAD); *pstr = p; return(color); } char *new_str(char *str) { char *p; if (str == NULL) str = ""; if ((p = (char *)malloc(strlen(str) + 1)) == NULL) error_out("new_str: Cannot Allocate Memory"); return(strcpy(p, str)); }