312ecd753f50c9abe293d0d8b42d7cdd5630ddb9
[privoxy.git] / cgiedit.c
1 const char cgiedit_rcs[] = "$Id: cgiedit.c,v 1.1 2001/09/16 15:47:37 jongfoster Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/cgiedit.c,v $
5  *
6  * Purpose     :  CGI-based actionsfile editor.
7  *                
8  *                Functions declared include:
9  * 
10  *
11  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
12  *                IJBSWA team.  http://ijbswa.sourceforge.net
13  *
14  *                Based on the Internet Junkbuster originally written
15  *                by and Copyright (C) 1997 Anonymous Coders and 
16  *                Junkbusters Corporation.  http://www.junkbusters.com
17  *
18  *                This program is free software; you can redistribute it 
19  *                and/or modify it under the terms of the GNU General
20  *                Public License as published by the Free Software
21  *                Foundation; either version 2 of the License, or (at
22  *                your option) any later version.
23  *
24  *                This program is distributed in the hope that it will
25  *                be useful, but WITHOUT ANY WARRANTY; without even the
26  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
27  *                PARTICULAR PURPOSE.  See the GNU General Public
28  *                License for more details.
29  *
30  *                The GNU General Public License should be included with
31  *                this file.  If not, you can view it at
32  *                http://www.gnu.org/copyleft/gpl.html
33  *                or write to the Free Software Foundation, Inc., 59
34  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
35  *
36  * Revisions   :
37  *    $Log: cgiedit.c,v $
38  *    Revision 1.1  2001/09/16 15:47:37  jongfoster
39  *    First version of CGI-based edit interface.  This is very much a
40  *    work-in-progress, and you can't actually use it to edit anything
41  *    yet.  You must #define FEATURE_CGI_EDIT_ACTIONS for these changes
42  *    to have any effect.
43  *
44  *
45  **********************************************************************/
46 \f
47
48 #include "config.h"
49
50 /*
51  * FIXME: Following includes copied from cgi.c - which are actually needed?
52  */
53
54 #include <stdio.h>
55 #include <sys/types.h>
56 #include <stdlib.h>
57 #include <ctype.h>
58 #include <string.h>
59 #include <assert.h>
60
61 #ifdef _WIN32
62 #define snprintf _snprintf
63 #endif /* def _WIN32 */
64
65 #include "project.h"
66 #include "cgi.h"
67 #include "cgiedit.h"
68 #include "list.h"
69 #include "encode.h"
70 #include "ssplit.h"
71 #include "jcc.h"
72 #include "filters.h"
73 #include "actions.h"
74 #include "errlog.h"
75 #include "miscutil.h"
76 #include "loadcfg.h"
77
78 const char cgiedit_h_rcs[] = CGIEDIT_H_VERSION;
79
80
81 #ifdef FEATURE_CGI_EDIT_ACTIONS
82
83
84 /*********************************************************************
85  *
86  * Function    :  cgi_edit_actions_list
87  *
88  * Description :  CGI function that edits the actions list.
89  *
90  * Parameters  :
91  *           1 :  csp = Current client state (buffers, headers, etc...)
92  *           2 :  rsp = http_response data structure for output
93  *           3 :  parameters = map of cgi parameters
94  *
95  * CGI Parameters : None
96  *
97  * Returns     :  0
98  *
99  *********************************************************************/
100 int cgi_edit_actions_list(struct client_state *csp, struct http_response *rsp,
101                                  struct map *parameters)
102 {
103    struct file_list *fl;
104    struct url_actions *actions;
105    char * actions_html;
106    char * next_actions_html;
107    char * section_template;
108    char * url_template;
109    char * sections;
110    char * urls;
111    struct map * exports = default_exports(csp, NULL);
112    struct map * section_exports;
113    struct map * url_exports;
114    int urlid;
115    char buf[50];
116    char * s;
117    int url_1_2;
118
119    if (((fl = csp->actions_list) == NULL) || ((actions = fl->f) == NULL))
120    {
121       /* FIXME: Oops, no file to edit */
122       free_map(exports);
123       return cgi_default(csp, rsp, parameters);
124    }
125
126    /* Should do all global exports above this point */
127
128    section_template = template_load(csp, "edit-actions-list-section");
129    url_template = template_load(csp, "edit-actions-list-url");
130
131    template_fill(&section_template, exports);
132    template_fill(&url_template, exports);
133
134    urlid = 0;
135    sections = strdup("");
136
137    ++urlid;
138    actions = actions->next;
139    if (actions != NULL)
140    {
141       actions_html = actions_to_html(actions->action);
142    }
143
144    while (actions != NULL)
145    {
146       section_exports = new_map();
147
148       snprintf(buf, 50, "%d", urlid);
149       map(section_exports, "sectionid", 1, buf, 1);
150
151       map(section_exports, "actions", 1, actions_html, 1);
152
153       /* Should do all section-specific exports above this point */
154
155       urls = strdup("");
156       url_1_2 = 2;
157
158       next_actions_html = NULL;
159       do
160       {
161          freez(next_actions_html);
162
163          url_exports = new_map();
164
165          snprintf(buf, 50, "%d", urlid);
166          map(url_exports, "urlid", 1, buf, 1);
167
168          snprintf(buf, 50, "%d", url_1_2);
169          map(url_exports, "url-1-2", 1, buf, 1);
170
171          s = html_encode(actions->url->spec);
172          map(url_exports, "url", 1, s, 1);
173
174          s = strdup(url_template);
175          template_fill(&s, section_exports);
176          template_fill(&s, url_exports);
177          urls = strsav(urls, s);
178          free_map(url_exports);
179
180          ++urlid;
181          url_1_2 = 3 - url_1_2;
182          actions = actions->next;
183          if (actions)
184          {
185             next_actions_html = actions_to_html(actions->action);
186          }
187       }
188       while (actions && (0 == strcmp(actions_html, next_actions_html)));
189
190       map(section_exports, "urls", 1, urls, 0);
191
192       /* Could also do section-specific exports here, but it wouldn't be as fast */
193
194       s = strdup(section_template);
195       template_fill(&s, section_exports);
196       sections = strsav(sections, s);
197       free_map(section_exports);
198
199       freez(actions_html);
200       actions_html = next_actions_html;
201    }
202
203    map(exports, "sections", 1, sections, 0);
204
205    /* Could also do global exports here, but it wouldn't be as fast */
206
207    rsp->body = template_load(csp, "edit-actions-list");
208    template_fill(&rsp->body, exports);
209    free_map(exports);
210
211    return(0);
212 }
213
214
215 /*********************************************************************
216  *
217  * Function    :  map_radio
218  *
219  * Description :  Map a set of radio button values.  E.g. if you have
220  *                3 radio buttons, declare them as:
221  *                  <option type="radio" name="xyz" @xyz-a@>
222  *                  <option type="radio" name="xyz" @xyz-b@>
223  *                  <option type="radio" name="xyz" @xyz-c@>
224  *                Then map one of the @xyz-?@ variables to "checked"
225  *                and all the others to empty by calling:
226  *                map_radio(exports, "xyz", "abc", sel)
227  *                Where 'sel' is 'a', 'b', or 'c'.
228  *
229  * Parameters  :
230  *           1 :  exports = Exports map to modify.
231  *           2 :  optionname = name for map
232  *           3 :  values = null-terminated list of values;
233  *           4 :  value = Selected value.
234  *
235  * CGI Parameters : None
236  *
237  * Returns     :  0 on success, nonzero on error.
238  *
239  *********************************************************************/
240 static int map_radio(struct map * exports, const char * optionname, 
241                      const char * values, char value)
242 {
243    int len;
244    char * buf;
245    char * p;
246    char c;
247    
248    assert(exports);
249    assert(optionname);
250    assert(values);
251
252    len = strlen(optionname);
253    buf = malloc(len + 3);
254    if (buf == NULL)
255    {
256       return 1;
257    }
258
259    strcpy(buf, optionname);
260    p = buf + len;
261    *p++ = '-';
262    p[1] = '\0';
263
264    while ((c = *values++) != '\0')
265    {
266       if (c != value)
267       {
268          *p = c;
269          if (map(exports, buf, 1, "", 1))
270          {
271             free(buf);
272             return 1;
273          }
274       }
275    }
276
277    *p = value;
278    if (map(exports, buf, 0, "checked", 1))
279    {
280       free(buf);
281       return 1;
282    }
283
284    return 0;
285 }
286
287
288 /*********************************************************************
289  *
290  * Function    :  actions_to_radio
291  *
292  * Description :  Converts a actionsfile entry FIXME
293  *
294  * Parameters  :
295  *          1  :  exports = FIXME
296  *          2  :  action  = FIXME
297  *
298  * Returns     :  0 on success, nonzero on error.
299  *
300  *********************************************************************/
301 static int actions_to_radio(struct map * exports, struct action_spec *action)
302 {
303    unsigned mask = action->mask;
304    unsigned add  = action->add;
305    int mapped_param;
306    int checked;
307
308    /* sanity - prevents "-feature +feature" */
309    mask |= add;
310
311
312 #define DEFINE_ACTION_BOOL(name, bit)       \
313    if (!(mask & bit))                       \
314    {                                        \
315       map_radio(exports, name, "ynx", 'n'); \
316    }                                        \
317    else if (add & bit)                      \
318    {                                        \
319       map_radio(exports, name, "ynx", 'y'); \
320    }                                        \
321    else                                     \
322    {                                        \
323       map_radio(exports, name, "ynx", 'x'); \
324    }
325
326 #define DEFINE_ACTION_STRING(name, bit, index)  \
327    DEFINE_ACTION_BOOL(name, bit);               \
328    mapped_param = 0;
329
330 #define DEFINE_CGI_PARAM_RADIO(name, bit, index, value, is_default) \
331    if (add & bit)                                        \
332    {                                                     \
333       checked = !strcmp(action->string[index], value);   \
334    }                                                     \
335    else                                                  \
336    {                                                     \
337       checked = is_default;                              \
338    }                                                     \
339    mapped_param |= checked;                              \
340    map(exports, name "-param-" value, 1, (checked ? "checked" : ""), 1);
341
342 #define DEFINE_CGI_PARAM_CUSTOM(name, bit, index, default_val)    \
343    map(exports, name "-param-custom", 1,                      \
344       ((!mapped_param) ? "checked" : ""), 1);                     \
345    map(exports, name "-param", 1,                             \
346       (((add & bit) && !mapped_param) ?                           \
347       action->string[index] : default_val), 1);
348
349 #define DEFINE_CGI_PARAM_NO_RADIO(name, bit, index, default_val)  \
350    map(exports, name "-param", 1,                             \
351       ((add & bit) ? action->string[index] : default_val), 1);
352
353 #define DEFINE_ACTION_MULTI(name, index)        \
354    if (action->multi_add[index]->first)         \
355    {                                            \
356       map_radio(exports, name, "ynx", 'y');     \
357    }                                            \
358    else if (action->multi_remove_all[index])    \
359    {                                            \
360       map_radio(exports, name, "ynx", 'n');     \
361    }                                            \
362    else if (action->multi_remove[index]->first) \
363    {                                            \
364       map_radio(exports, name, "ynx", 'y');     \
365    }                                            \
366    else                                         \
367    {                                            \
368       map_radio(exports, name, "ynx", 'x');     \
369    }
370
371 #define DEFINE_ACTION_ALIAS 0 /* No aliases for output */
372
373 #include "actionlist.h"
374
375 #undef DEFINE_ACTION_MULTI
376 #undef DEFINE_ACTION_STRING
377 #undef DEFINE_ACTION_BOOL
378 #undef DEFINE_ACTION_ALIAS
379 #undef DEFINE_CGI_PARAM_CUSTOM
380 #undef DEFINE_CGI_PARAM_RADIO
381 #undef DEFINE_CGI_PARAM_NO_RADIO
382
383    return 0;
384 }
385
386
387 /*********************************************************************
388  *
389  * Function    :  cgi_edit_actions
390  *
391  * Description :  CGI function that edits the Actions list.
392  *
393  * Parameters  :
394  *           1 :  csp = Current client state (buffers, headers, etc...)
395  *           2 :  rsp = http_response data structure for output
396  *           3 :  parameters = map of cgi parameters
397  *
398  * CGI Parameters : None
399  *
400  * Returns     :  0
401  *
402  *********************************************************************/
403 int cgi_edit_actions(struct client_state *csp, struct http_response *rsp,
404                             struct map *parameters)
405 {
406    struct file_list *fl;
407    struct url_actions *actions;
408    struct map * exports = default_exports(csp, NULL);
409    int sectionid;
410    int i;
411    const char * s;
412    char c;
413
414    if (((fl = csp->actions_list) == NULL) || ((actions = fl->f) == NULL))
415    {
416       /* FIXME: Oops, No file to edit */
417       free_map(exports);
418       return cgi_default(csp, rsp, parameters);
419    }
420
421    s = lookup(parameters, "section");
422    if (!*s)
423    {
424       /* FIXME: Oops, No file to edit */
425       free_map(exports);
426       return cgi_default(csp, rsp, parameters);
427    }
428
429    sectionid = 0;
430    while ((c = *s++) != '\0')
431    {
432       /* Note:
433        * (((unsigned)(-1)) >> 1) == MAXINT.
434        * (MAXINT - 9) / 10 is the largest number that 
435        * can be safely multiplied by 10 then have 9 added.
436        */
437       if (c < '0' || c > '9' || sectionid > ((((unsigned)(-1)) >> 1) - 9) / 10)
438       {
439          /* FIXME: Oops, bad paramaters */
440          free_map(exports);
441          return cgi_default(csp, rsp, parameters);
442       }
443
444       sectionid *= 10;
445       sectionid += c - '0';
446    }
447
448    for (i = 0; actions != NULL && i < sectionid; i++)
449    {
450       actions = actions->next;
451    }
452
453    if (actions == NULL || i != sectionid || sectionid < 1)
454    {
455       free_map(exports);
456       return cgi_default(csp, rsp, parameters);
457    }
458
459    /* FIXME: need to fill in exports here */
460    actions_to_radio(exports, actions->action);
461
462    rsp->body = template_load(csp, "edit-actions");
463    template_fill(&rsp->body, exports);
464    free_map(exports);
465
466    return(0);
467 }
468
469
470 /*********************************************************************
471  *
472  * Function    :  cgi_edit_actions_submit
473  *
474  * Description :  CGI function that actually edits the Actions list.
475  *
476  * Parameters  :
477  *           1 :  csp = Current client state (buffers, headers, etc...)
478  *           2 :  rsp = http_response data structure for output
479  *           3 :  parameters = map of cgi parameters
480  *
481  * CGI Parameters : None
482  *
483  * Returns     :  0
484  *
485  *********************************************************************/
486 int cgi_edit_actions_submit(struct client_state *csp, struct http_response *rsp,
487                             struct map *parameters)
488 {
489    struct map * exports = default_exports(csp, NULL);
490
491    map(exports, "cgi-parameters", 1, dump_map(parameters), 0);
492
493    rsp->body = template_load(csp, "edit-actions-submit");
494    template_fill(&rsp->body, exports);
495    free_map(exports);
496
497    return(0);
498 }
499
500
501 #endif /* def FEATURE_CGI_EDIT_ACTIONS */
502
503
504 /*
505   Local Variables:
506   tab-width: 3
507   end:
508 */