1 /*
2 MiddleMan filtering proxy server
3 Copyright (C) 2002 Jason McLaughlin
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 #include <stdio.h>
21 #include <ctype.h>
22 #include <string.h>
23 #include "flags.h"
24 #include "proto.h"
25 #include "macros.h"
26
27 /*
28 load an XML-ish file into a linked list
29 note: this is only a partial xml implementation, just enough to suit the needs of this program
30 */
xml_load(XML_LIST * xml_list,char * filename)31 XML_LIST *xml_load(XML_LIST * xml_list, char *filename)
32 {
33 int i, line = 0, inside = FALSE, label = FALSE, special = FALSE;
34 char buf[8192], tag[64], value[8192] = "", *bufpos, *vpos = value;
35 FILE *fptr;
36 STACK *stack = NULL;
37 XML_LIST *new_list = xml_list;
38
39 if ((fptr = fopen(filename, "r")) == NULL)
40 return NULL;
41
42 while (fgets(buf, sizeof(buf), fptr) != NULL) {
43 line++;
44 bufpos = buf;
45
46 while (*bufpos) {
47 if (!strncmp(bufpos, "<!--", 4))
48 label++;
49 else if (!strncmp(bufpos, "-->", 3))
50 label--;
51 else if (*bufpos == '<' && (bufpos[1] == '?' || bufpos[1] == '!')) {
52 label++;
53 special = TRUE;
54 } else if (*bufpos == '>' && special == TRUE) {
55 label--;
56 special = FALSE;
57 bufpos++;
58 continue;
59 }
60
61
62 if (!label && *bufpos == '<') {
63
64 s_strncpy(tag, bufpos, sizeof(tag));
65 for (i = 0; tag[i] != '>' && tag[i]; i++);
66
67 if (i < 2 || !tag[i])
68 goto error;
69 else
70 i++;
71
72 tag[i] = '\0';
73
74 bufpos += i;
75
76 if (tag[1] == '/') {
77 if (stack == NULL || strcasecmp(&tag[2], &stack->data[1]))
78 goto error;
79
80 if (!strcasecmp(stack->data, "<include>")) {
81 *vpos = '\0';
82 if (!strcasecmp(value, filename))
83 goto error;
84
85 new_list = xml_load(new_list, value);
86
87 value[0] = '\0';
88 vpos = value;
89 }
90
91 inside = FALSE;
92
93 POP(stack);
94
95 if (*value) {
96 *vpos = '\0';
97 new_list = xml_list_add(new_list, value, XML_VALUE);
98 *value = '\0';
99 }
100 } else {
101 PUSH(stack, tag);
102
103 vpos = value;
104 inside = TRUE;
105 }
106
107 if (strcasecmp(tag, "<include>") && strcasecmp(tag, "</include>"))
108 new_list = xml_list_add(new_list, tag, XML_TAG);
109 } else {
110 if (!label && inside) {
111 if (*bufpos == '&') {
112 if (!strncasecmp(&bufpos[1], "gt;", 3)) {
113 bufpos += 3;
114 *bufpos = '>';
115 } else if (!strncasecmp(&bufpos[1], "lt;", 3)) {
116 bufpos += 3;
117 *bufpos = '<';
118 } else if (!strncasecmp(&bufpos[1], "amp;", 4)) {
119 bufpos += 4;
120 *bufpos = '&';
121 } else if (!strncasecmp(&bufpos[1], "quot;", 5)) {
122 bufpos += 5;
123 *bufpos = '\"';
124 } else if (!strncasecmp(&bufpos[1], "apos;", 5)) {
125 bufpos += 5;
126 *bufpos = '\'';
127 }
128 }
129
130 if (vpos - value < sizeof(value))
131 *(vpos++) = *bufpos;
132
133 }
134
135 bufpos++;
136 }
137
138 if (xml_list == NULL)
139 xml_list = new_list;
140 }
141 }
142
143 if (stack != NULL)
144 goto error;
145
146 fclose(fptr);
147
148 return xml_list;
149 error:
150
151 fclose(fptr);
152
153 putlog(MMLOG_ERROR, "Parse error in %s on line %d", filename, line);
154
155 while (stack != NULL) {
156 /* close off all open tags */
157 s_strncpy(tag, stack->data, sizeof(tag) - 1);
158 memmove(&tag[2], &tag[1], strlen(&tag[1]) + 1);
159 tag[1] = '/';
160 xml_list_add(new_list, tag, XML_TAG);
161 POP(stack);
162 }
163
164 return xml_list;
165 }
166
167 /*
168 insert an XML tag or item at the end of a linked list
169 */
xml_list_add(XML_LIST * list,char * item,int type)170 XML_LIST *xml_list_add(XML_LIST * list, char *item, int type)
171 {
172 if (list == NULL) {
173 list = xmalloc(sizeof(XML_LIST));
174 list->prev = NULL;
175 } else {
176 while (list->next != NULL)
177 list = list->next;
178 list->next = xmalloc(sizeof(XML_LIST));
179 list->next->prev = list;
180 list = list->next;
181 }
182
183 list->item = xstrdup(item);
184 list->type = type;
185 list->next = NULL;
186
187 return list;
188 }
189
190 /*
191 free memory used by an XML linked list
192 */
xml_list_free(XML_LIST * xml_list)193 void xml_list_free(XML_LIST * xml_list)
194 {
195 XML_LIST *xml_list_temp;
196
197 while (xml_list != NULL) {
198 xml_list_temp = xml_list->next;
199 xfree(xml_list->item);
200 xfree(xml_list);
201 xml_list = xml_list_temp;
202 }
203 }
204
205 /*
206 return pointer where section begins
207 */
xml_section(XML_LIST * xml_list,char * section)208 XML_LIST *xml_section(XML_LIST * xml_list, char *section)
209 {
210 int i = 0;
211
212 while (xml_list != NULL) {
213 if (xml_list->type == XML_TAG) {
214 if (i <= 1 && !strcasecmp(xml_list->item, section))
215 return xml_list;
216 if (xml_list->item[1] == '/')
217 i--;
218 else
219 i++;
220 }
221
222 xml_list = xml_list->next;
223 }
224
225 return NULL;
226 }
227
228 /*
229 save formatted xml-ish file from XML_LIST struct
230 */
xml_save(XML_LIST * xml_list,char * filename)231 int xml_save(XML_LIST * xml_list, char *filename)
232 {
233 FILE *file;
234 int i, ind = 1;
235 char buf[8192];
236
237 file = fopen(filename, "w");
238 if (file == NULL)
239 return FALSE;
240
241 fprintf(file, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
242 fprintf(file, "<mman>\n");
243
244 for (; xml_list; xml_list = xml_list->next) {
245 for (i = 0; i < ind; i++)
246 buf[i] = '\t';
247
248
249 if (ind <= 1 && xml_list->prev != NULL)
250 fprintf(file, "\n");
251
252 if (xml_list->next != NULL && xml_list->next->type == XML_VALUE) {
253 /* put the value on the same line as the opening and closing tags.. i.e. <foo>bar</foo> */
254 snprintf(&buf[ind], sizeof(buf) - ind, "%s%s%s", xml_list->item, xml_list->next->item, xml_list->next->next->item);
255 xml_list = xml_list->next->next;
256 } else {
257
258 if (xml_list->type == XML_TAG) {
259 if (xml_list->item[1] == '/') {
260 ind--;
261 snprintf(&buf[ind], sizeof(buf) - ind, "%s", xml_list->item);
262 } else {
263 snprintf(&buf[ind], sizeof(buf) - ind, "%s", xml_list->item);
264 ind++;
265 }
266 } else
267 snprintf(&buf[ind], sizeof(buf) - ind, "%s", xml_list->item);
268
269 }
270
271 fprintf(file, "%s\n", buf);
272 }
273
274 fprintf(file, "</mman>\n");
275
276 fclose(file);
277
278 return TRUE;
279 }
280