/* MiddleMan filtering proxy server Copyright (C) 2002 Jason McLaughlin 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-1307 USA */ #include #include #include #include "flags.h" #include "proto.h" #include "macros.h" /* load an XML-ish file into a linked list note: this is only a partial xml implementation, just enough to suit the needs of this program */ XML_LIST *xml_load(XML_LIST * xml_list, char *filename) { int i, line = 0, inside = FALSE, label = FALSE; char buf[8096], tag[64], value[8096] = "", *bufpos, *vpos = value; FILE *fptr; STACK *stack = NULL; XML_LIST *new_list = xml_list; if ((fptr = fopen(filename, "r")) == NULL) return NULL; while (fgets(buf, sizeof(buf), fptr) != NULL) { line++; bufpos = buf; while (*bufpos) { if (!strncmp(bufpos, "", 3)) label--; if (!label && *bufpos == '<') { s_strncpy(tag, bufpos, sizeof(tag)); for (i = 0; tag[i] != '>' && tag[i]; i++); if (i < 2 || !tag[i]) goto error; else i++; tag[i] = '\0'; bufpos += i; if (tag[1] == '/') { if (stack == NULL || strcasecmp(&tag[2], &stack->data[1])) goto error; if (!strcasecmp(stack->data, "")) { *vpos = '\0'; if (!strcasecmp(value, filename)) goto error; new_list = xml_load(new_list, value); value[0] = '\0'; vpos = value; } inside = FALSE; POP(stack); if (*value) { *vpos = '\0'; new_list = xml_list_add(new_list, value, XML_VALUE); *value = '\0'; } } else { PUSH(stack, tag); vpos = value; inside = TRUE; } if (strcasecmp(tag, "") && strcasecmp(tag, "")) new_list = xml_list_add(new_list, tag, XML_TAG); } else { if (!label && inside) { if (*bufpos == '\\' && (bufpos[1] == '\\' || bufpos[1] == '<' || bufpos[1] == '>')) bufpos++; if (vpos - value < sizeof(value)) *(vpos++) = *bufpos; } bufpos++; } if (xml_list == NULL) xml_list = new_list; } } if (stack != NULL) goto error; fclose(fptr); return xml_list; error: fclose(fptr); putlog(MMLOG_ERROR, "Parse error in %s on line %d", filename, line); while (stack != NULL) { /* close off all open tags */ s_strncpy(tag, stack->data, sizeof(tag) - 1); memmove(&tag[2], &tag[1], strlen(&tag[1]) + 1); tag[1] = '/'; xml_list_add(new_list, tag, XML_TAG); POP(stack); } return xml_list; } /* insert an XML tag or item at the end of a linked list */ XML_LIST *xml_list_add(XML_LIST * list, char *item, int type) { if (list == NULL) { list = xmalloc(sizeof(XML_LIST)); list->prev = NULL; } else { while (list->next != NULL) list = list->next; list->next = xmalloc(sizeof(XML_LIST)); list->next->prev = list; list = list->next; } list->item = xstrdup(item); list->type = type; list->next = NULL; return list; } /* free memory used by an XML linked list */ void xml_list_free(XML_LIST * xml_list) { XML_LIST *xml_list_temp; while (xml_list != NULL) { xml_list_temp = xml_list->next; xfree(xml_list->item); xfree(xml_list); xml_list = xml_list_temp; } } /* return pointer where section begins */ XML_LIST *xml_section(XML_LIST * xml_list, char *section) { int i = 0; while (xml_list != NULL) { if (xml_list->type == XML_TAG) { if (!i && !strcasecmp(xml_list->item, section)) return xml_list; if (xml_list->item[1] == '/') i--; else i++; } xml_list = xml_list->next; } return NULL; } /* save formatted xml-ish file from XML_LIST struct */ int xml_save(XML_LIST * xml_list, char *filename) { FILE *file; int i, ind = 0; char buf[8096]; file = fopen(filename, "w"); if (file == NULL) return FALSE; for (; xml_list; xml_list = xml_list->next) { for (i = 0; i < ind; i++) buf[i] = '\t'; if (ind == 0 && xml_list->prev != NULL) fprintf(file, "\n"); if (xml_list->next != NULL && xml_list->next->type == XML_VALUE) { /* put the value on the same line as the opening and closing tags.. i.e. bar */ snprintf(&buf[ind], sizeof(buf) - ind, "%s%s%s", xml_list->item, xml_list->next->item, xml_list->next->next->item); xml_list = xml_list->next->next; } else { if (xml_list->type == XML_TAG) { if (xml_list->item[1] == '/') { ind--; snprintf(&buf[ind], sizeof(buf) - ind, "%s", xml_list->item); } else { snprintf(&buf[ind], sizeof(buf) - ind, "%s", xml_list->item); ind++; } } else snprintf(&buf[ind], sizeof(buf) - ind, "%s", xml_list->item); } fprintf(file, "%s\n", buf); } fclose(file); return TRUE; }