+Missing <time.h> include
[middleman.git] / src / keywords.c
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 <string.h>
22 #include "proto.h"
23
24 KEYWORD_LIST *keyword_load(KEYWORD_LIST *keyword_list, XML_LIST *xml_list) {
25         KEYWORD_LIST *tmp_list = keyword_list;
26         struct KEYWORD_LIST_LIST *keywords = NULL;
27
28         if (tmp_list == NULL) {
29                 tmp_list = xmalloc(sizeof(KEYWORD_LIST));
30                 tmp_list->keyword_list = NULL;
31                 tmp_list->threshold = 0;
32                 tmp_list->template = NULL;
33                 tmp_list->id = 0;
34                 tmp_list->enabled = TRUE;
35
36                 keyword_list = tmp_list;
37
38                 pthread_rwlock_init(&tmp_list->lock, NULL);
39         } else
40                 keywords = tmp_list->keyword_list;
41
42         while ((xml_list = xml_section(xml_list, "<keywords>"))) {
43                 XML_LIST_LOOP(xml_list, "<keywords>") {
44                         XML_LIST_CMP(xml_list, "<item>") {
45                                 keywords = keyword_list_new(keywords);
46                                 keywords->id = tmp_list->id++;
47
48                                 if (tmp_list->keyword_list == NULL) tmp_list->keyword_list = keywords;
49
50                                 XML_LIST_LOOP(xml_list, "<item>") {
51                                         XML_LIST_CMP(xml_list, "<enabled>") {
52                                                 xml_list = xml_list->next;
53                                                 if (xml_list->type == XML_VALUE) {
54                                                         if (!strcasecmp(xml_list->item, "false"))
55                                                                 keywords->enabled = FALSE;
56                                                         else
57                                                                 keywords->enabled = TRUE;
58                                                 }
59                                         }
60                                         XML_LIST_CMP(xml_list, "<comment>") {
61                                                 xml_list = xml_list->next;
62                                                 if (xml_list->type == XML_VALUE)
63                                                         keyword_list_insert(keywords, xml_list->item, NULL, NULL, NULL, NULL, NULL);
64                                         }
65                                         XML_LIST_CMP(xml_list, "<host>") {
66                                                 xml_list = xml_list->next;
67                                                 if (xml_list->type == XML_VALUE)
68                                                         keyword_list_insert(keywords, NULL, xml_list->item, NULL, NULL, NULL, NULL);
69                                         }
70                                         XML_LIST_CMP(xml_list, "<file>") {
71                                                 xml_list = xml_list->next;
72                                                 if (xml_list->type == XML_VALUE)
73                                                         keyword_list_insert(keywords, NULL, NULL, xml_list->item, NULL, NULL, NULL);
74                                         }
75                                         XML_LIST_CMP(xml_list, "<mime>") {
76                                                 xml_list = xml_list->next;
77                                                 if (xml_list->type == XML_VALUE)
78                                                         keyword_list_insert(keywords, NULL, NULL, NULL, xml_list->item, NULL, NULL);
79                                         }
80                                         XML_LIST_CMP(xml_list, "<keyword>") {
81                                                 xml_list = xml_list->next;
82                                                 if (xml_list->type == XML_VALUE)
83                                                         keyword_list_insert(keywords, NULL, NULL, NULL, NULL, xml_list->item, NULL);
84                                         }
85                                         XML_LIST_CMP(xml_list, "<score>") {
86                                                 xml_list = xml_list->next;
87                                                 if (xml_list->type == XML_VALUE)
88                                                         keyword_list_insert(keywords, NULL, NULL, NULL, NULL, NULL, xml_list->item);
89                                         }
90                                 }
91                         }
92                         XML_LIST_CMP(xml_list, "<enabled>") {
93                                 xml_list = xml_list->next;
94                                 if (xml_list->type == XML_VALUE) {
95                                         if (!strcasecmp(xml_list->item, "false"))
96                                                 tmp_list->enabled = FALSE;
97                                         else
98                                                 tmp_list->enabled = TRUE;
99                                 }
100                         }
101                         XML_LIST_CMP(xml_list, "<threshold>") {
102                                 xml_list = xml_list->next;
103                                 if (xml_list->type == XML_VALUE)
104                                         tmp_list->threshold = atoi(xml_list->item);
105                         }
106                         XML_LIST_CMP(xml_list, "<template>") {
107                                 xml_list = xml_list->next;
108                                 if (xml_list->type == XML_VALUE) {
109                                         FREE_AND_NULL(tmp_list->template);
110                                         tmp_list->template = xstrdup(xml_list->item);
111                                 }
112                         }
113                 }
114         }
115
116         return tmp_list;
117 }
118
119 XML_LIST *keyword_xml(KEYWORD_LIST *keyword_list, XML_LIST *xml_list) {
120         char *ptr, buf[128];
121         struct KEYWORD_LIST_LIST *kl;
122
123         pthread_rwlock_rdlock(&keyword_list->lock);
124
125         xml_list = xml_list_add(xml_list, "<keywords>", XML_TAG);
126
127         xml_list = xml_list_add(xml_list, "<enabled>", XML_TAG);
128         xml_list = xml_list_add(xml_list, (keyword_list->enabled == TRUE) ? "true" : "false", XML_VALUE);
129         xml_list = xml_list_add(xml_list, "</enabled>", XML_TAG);
130
131         xml_list = xml_list_add(xml_list, "<threshold>", XML_TAG);
132         snprintf(buf, sizeof(buf), "%d", keyword_list->threshold);
133         xml_list = xml_list_add(xml_list, buf, XML_VALUE);
134         xml_list = xml_list_add(xml_list, "</threshold>", XML_TAG);
135
136         if (keyword_list->template != NULL) {
137                 xml_list = xml_list_add(xml_list, "<template>", XML_TAG);
138                 ptr = string_to_xml(keyword_list->template);
139                 xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
140                 xfree(ptr);
141                 xml_list = xml_list_add(xml_list, "</template>", XML_TAG);
142         }
143
144         for (kl = keyword_list->keyword_list; kl; kl = kl->next) {
145                 xml_list = xml_list_add(xml_list, "<item>", XML_TAG);
146
147                 xml_list = xml_list_add(xml_list, "<enabled>", XML_TAG);
148                 xml_list = xml_list_add(xml_list, (kl->enabled == TRUE) ? "true" : "false", XML_VALUE);
149                 xml_list = xml_list_add(xml_list, "</enabled>", XML_TAG);
150
151                 if (kl->comment != NULL) {
152                         xml_list = xml_list_add(xml_list, "<comment>", XML_TAG);
153                         ptr = string_to_xml(kl->comment);
154                         xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
155                         xfree(ptr);
156                         xml_list = xml_list_add(xml_list, "</comment>", XML_TAG);
157                 }
158                 if (kl->host != NULL) {
159                         xml_list = xml_list_add(xml_list, "<host>", XML_TAG);
160                         ptr = string_to_xml(kl->host);
161                         xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
162                         xfree(ptr);
163                         xml_list = xml_list_add(xml_list, "</host>", XML_TAG);
164                 }
165                 if (kl->file != NULL) {
166                         xml_list = xml_list_add(xml_list, "<file>", XML_TAG);
167                         ptr = string_to_xml(kl->file);
168                         xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
169                         xfree(ptr);
170                         xml_list = xml_list_add(xml_list, "</file>", XML_TAG);
171                 }
172                 if (kl->mime != NULL) {
173                         xml_list = xml_list_add(xml_list, "<mime>", XML_TAG);
174                         ptr = string_to_xml(kl->mime);
175                         xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
176                         xfree(ptr);
177                         xml_list = xml_list_add(xml_list, "</mime>", XML_TAG);
178                 }
179
180                 if (kl->keyword != NULL) {
181                         xml_list = xml_list_add(xml_list, "<keyword>", XML_TAG);
182                         ptr = string_to_xml(kl->keyword);
183                         xml_list = xml_list_add(xml_list, ptr, XML_VALUE);
184                         xfree(ptr);
185                         xml_list = xml_list_add(xml_list, "</keyword>", XML_TAG);
186                 }
187
188                 xml_list = xml_list_add(xml_list, "<score>", XML_TAG);
189                 snprintf(buf, sizeof(buf), "%d", kl->score);
190                 xml_list = xml_list_add(xml_list, buf, XML_VALUE);
191                 xml_list = xml_list_add(xml_list, "</score>", XML_TAG);
192
193                 xml_list = xml_list_add(xml_list, "</item>", XML_TAG);
194         }
195
196         xml_list = xml_list_add(xml_list, "</keywords>", XML_TAG);
197
198         pthread_rwlock_unlock(&keyword_list->lock);
199
200         return xml_list;
201 }
202
203 struct KEYWORD_LIST_LIST *keyword_list_new(struct KEYWORD_LIST_LIST *x) {
204         if (x == NULL) {
205                 x = xmalloc(sizeof(struct KEYWORD_LIST_LIST));
206                 x->prev = NULL;
207         } else {
208                 while (x->next != NULL) x = x->next;
209                 x->next = xmalloc(sizeof(struct KEYWORD_LIST_LIST));
210                 x->next->prev = x;
211                 x = x->next;
212         }
213
214         x->enabled = TRUE;
215         x->comment = NULL;
216         x->score = 0;
217         x->host = NULL;
218         x->file = NULL;
219         x->mime = NULL;
220         x->keyword = NULL;
221         x->he = NULL;
222         x->fe = NULL;
223         x->me = NULL;
224         x->ke = NULL;
225         x->next = NULL;
226
227         return x;
228 }
229
230 void keyword_list_insert(struct KEYWORD_LIST_LIST *x, char *a, char *b, char *c, char *d, char *e, char *f) {
231         if (a != NULL) {
232                 FREE_AND_NULL(x->comment);
233
234                 if (strcmp(a, ""))
235                         x->comment = xstrdup(a);
236         }
237         if (b != NULL) {
238                 if (x->he != NULL) reg_free(x->he);
239                 FREE_AND_NULL(x->host);
240
241                 if (strcmp(b, "")) {
242                         x->he = reg_compile(b, REGFLAGS);
243                         x->host = xstrdup(b);
244                 } else x->he = NULL;
245         }
246         if (c != NULL) {
247                 if (x->fe != NULL) reg_free(x->fe);
248                 FREE_AND_NULL(x->file);
249
250                 if (strcmp(c, "")) {
251                         x->fe = reg_compile(c, REGFLAGS);
252                         x->file = xstrdup(c);
253                 } else x->fe = NULL;
254         }
255         if (d != NULL) {
256                 if (x->me != NULL) reg_free(x->me);
257                 FREE_AND_NULL(x->mime);
258
259                 if (strcmp(d, "")) {
260                         x->me = reg_compile(d, REGFLAGS);
261                         x->mime = xstrdup(d);
262                 } else x->me = NULL;
263         }
264         if (e != NULL) {
265                 if (x->ke != NULL) reg_free(x->ke);
266                 FREE_AND_NULL(x->keyword);
267
268                 if (strcmp(e, "")) {
269                         x->ke = reg_compile(e, REGFLAGS);
270                         x->keyword = xstrdup(e);
271                 } else x->ke = NULL;
272         }
273         if (f != NULL) {
274                 if (strcmp(f, ""))
275                         x->score = atoi(f);
276         }
277 }
278
279 struct KEYWORD_LIST_LIST *keyword_list_delete(struct KEYWORD_LIST_LIST *x) {
280         struct KEYWORD_LIST_LIST *start = x;
281
282         while (start->prev != NULL)
283                 start = start->prev;
284
285         if (x->next != NULL)
286                 x->next->prev = x->prev;
287         if (x->prev != NULL)
288                 x->prev->next = x->next;
289         else
290                 start = start->next;
291
292         if (x->he != NULL) reg_free(x->he);
293         if (x->fe != NULL) reg_free(x->fe);
294         if (x->me != NULL) reg_free(x->me);
295         if (x->ke != NULL) reg_free(x->ke);
296         FREE_AND_NULL(x->comment);
297         FREE_AND_NULL(x->host);
298         FREE_AND_NULL(x->file);
299         FREE_AND_NULL(x->mime);
300         FREE_AND_NULL(x->keyword);
301
302         xfree(x);
303
304         return start;
305 }
306
307 void keyword_list_free(struct KEYWORD_LIST_LIST *kl) {
308         struct KEYWORD_LIST_LIST *tmp;
309
310         while (kl != NULL) {
311                 tmp = kl->next;
312
313                 if (kl->he != NULL) reg_free(kl->he);
314                 if (kl->fe != NULL) reg_free(kl->fe);
315                 if (kl->me != NULL) reg_free(kl->me);
316                 if (kl->ke != NULL) reg_free(kl->ke);
317                 FREE_AND_NULL(kl->comment);
318                 FREE_AND_NULL(kl->host);
319                 FREE_AND_NULL(kl->file);
320                 FREE_AND_NULL(kl->mime);
321                 FREE_AND_NULL(kl->keyword);
322
323                 xfree(kl);
324
325                 kl = tmp;
326         }
327 }
328
329 void keyword_free(KEYWORD_LIST *keyword_list) {
330         if (keyword_list == NULL)
331                 return;
332
333         keyword_list_free(keyword_list->keyword_list);
334                 
335         FREE_AND_NULL(keyword_list->template);
336
337         pthread_rwlock_destroy(&keyword_list->lock);
338
339         xfree(keyword_list);
340 }
341
342 int keyword_check(KEYWORD_LIST *keyword_list, CONNECTION *connection, FILEBUF *filebuf, int action) {
343         int ret, x = FALSE;
344         struct KEYWORD_LIST_LIST *kl;
345
346         if (!keyword_list || connection->bypass & FEATURE_KEYWORDS)
347                 return FALSE;
348
349         pthread_rwlock_rdlock(&keyword_list->lock);
350
351         if (keyword_list->enabled == FALSE) {
352                 pthread_rwlock_unlock(&keyword_list->lock);
353
354                 return FALSE;
355         }
356
357         if (filebuf != NULL) filebuf_add(filebuf, "", 1);
358
359         for (kl = keyword_list->keyword_list; kl; kl = kl->next) {
360                 if (kl->enabled == FALSE)
361                         continue;
362
363                 if (kl->he != NULL) {
364                         ret = reg_exec(kl->he, connection->header->host);
365                         if (ret) continue;
366                 }
367
368                 if (kl->fe != NULL) {
369                         ret = reg_exec(kl->fe, connection->header->file);
370                         if (ret) continue;
371                 }
372
373                 if (kl->me != NULL && connection->rheader->content_type != NULL) {
374                         ret = reg_exec(kl->me, connection->rheader->content_type);
375                         if (ret) continue;
376                 } else if (kl->me != NULL) {
377                         ret = reg_exec(kl->me, "");
378                         if (ret) continue;
379                 }
380
381                 if (kl->ke != NULL && filebuf != NULL) {
382                         ret = reg_exec(kl->ke, filebuf->data);
383                         if (ret) continue;
384                 }
385
386                 if (action == FALSE) {
387                         /* just check if any entires apply to current page */
388                         x = TRUE;
389
390                         break;
391                 }
392
393                 if (kl->score == 0) {
394                         /* stop checking when we hit an entry with a score of 0 */
395                         break;
396                 }
397
398                 x += kl->score;
399         }
400
401         if (filebuf != NULL) filebuf_resize(filebuf, filebuf->size - 1);
402
403         pthread_rwlock_unlock(&keyword_list->lock);
404
405         return x;
406 }