46ac87280e970bb90976bd4dbd4932511c929194
[citadel.git] / webcit / paramhandling.c
1 /*
2  * parse urlparts and post data
3  *
4  * Copyright (c) 1996-2012 by the citadel.org team
5  *
6  * This program is open source software.  You can redistribute it and/or
7  * modify it under the terms of the GNU General Public License, version 3.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  */
14
15 #include "webcit.h"
16 #include "webserver.h"
17
18 void free_url(void *U)
19 {
20         urlcontent *u = (urlcontent*) U;
21         FreeStrBuf(&u->url_data);
22         free(u);
23 }
24
25 /*
26  * Extract variables from the URL.
27  */
28 void ParseURLParams(StrBuf *url)
29 {
30         const char *aptr, *bptr, *eptr, *up;
31         int len, keylen;
32         urlcontent *u;
33         wcsession *WCC = WC;
34
35         if (WCC->Hdr->urlstrings == NULL)
36                 WCC->Hdr->urlstrings = NewHash(1, NULL);
37         eptr = ChrPtr(url) + StrLength(url);
38         up = ChrPtr(url);
39         while ((up < eptr) && (!IsEmptyStr(up))) {
40                 aptr = up;
41                 while ((aptr < eptr) && (*aptr != '\0') && (*aptr != '='))
42                         aptr++;
43                 if (*aptr != '=') {
44                         return;
45                 }
46                 aptr++;
47                 bptr = aptr;
48                 while ((bptr < eptr) && (*bptr != '\0')
49                       && (*bptr != '&') && (*bptr != '?') && (*bptr != ' ')) {
50                         bptr++;
51                 }
52                 keylen = aptr - up - 1; /* -1 -> '=' */
53                 if(keylen > sizeof(u->url_key)) {
54                         syslog(1, "invalid url_key from %s", ChrPtr(WCC->Hdr->HR.browser_host));
55                         return;
56                 }
57
58                 u = (urlcontent *) malloc(sizeof(urlcontent));
59                 memcpy(u->url_key, up, keylen);
60                 u->url_key[keylen] = '\0';
61                 if (keylen < 0) {
62                         syslog(1, "invalid url_key from %s", ChrPtr(WCC->Hdr->HR.browser_host));
63                         free(u);
64                         return;
65                 }
66                 
67                 if (strncmp(u->url_key, "__", 2) != 0)
68                 {
69                         Put(WCC->Hdr->urlstrings, u->url_key, keylen, u, free_url);
70                         len = bptr - aptr;
71                         u->url_data = NewStrBufPlain(aptr, len);
72                         StrBufUnescape(u->url_data, 1);
73 #ifdef DEBUG_URLSTRINGS
74                         syslog(9, "%s = [%d]  %s\n", 
75                                 u->url_key, 
76                                 StrLength(u->url_data), 
77                                 ChrPtr(u->url_data)); 
78 #endif
79                 }
80                 else {
81                         len = bptr - aptr;
82                         u->url_data = NewStrBufPlain(aptr, len);
83                         StrBufUnescape(u->url_data, 1);
84                         syslog(1, "REJECTED because of __ is internal only: %s = [%d]  %s\n", 
85                                 u->url_key, 
86                                 StrLength(u->url_data), 
87                                 ChrPtr(u->url_data)); 
88                         
89                         free_url(u);
90                 }
91                 up = bptr;
92                 ++up;
93         }
94 }
95
96 /*
97  * free urlstring memory
98  */
99 void free_urls(void)
100 {
101         DeleteHash(&WC->Hdr->urlstrings);
102 }
103
104 /*
105  * Diagnostic function to display the contents of all variables
106  */
107
108 void dump_vars(void)
109 {
110         wcsession *WCC = WC;
111         urlcontent *u;
112         void *U;
113         long HKLen;
114         const char *HKey;
115         HashPos *Cursor;
116         
117         Cursor = GetNewHashPos (WCC->Hdr->urlstrings, 0);
118         while (GetNextHashPos(WCC->Hdr->urlstrings, Cursor, &HKLen, &HKey, &U)) {
119                 u = (urlcontent*) U;
120                 wc_printf("%38s = %s\n", u->url_key, ChrPtr(u->url_data));
121         }
122 }
123
124 /*
125  * Return the value of a variable supplied to the current web page (from the url or a form)
126  */
127
128 const char *XBstr(const char *key, size_t keylen, size_t *len)
129 {
130         void *U;
131
132         if ((WC->Hdr->urlstrings != NULL) && 
133             GetHash(WC->Hdr->urlstrings, key, keylen, &U)) {
134                 *len = StrLength(((urlcontent *)U)->url_data);
135                 return ChrPtr(((urlcontent *)U)->url_data);
136         }
137         else {
138                 *len = 0;
139                 return ("");
140         }
141 }
142
143 const char *XBSTR(const char *key, size_t *len)
144 {
145         void *U;
146
147         if ((WC->Hdr->urlstrings != NULL) &&
148             GetHash(WC->Hdr->urlstrings, key, strlen (key), &U)){
149                 *len = StrLength(((urlcontent *)U)->url_data);
150                 return ChrPtr(((urlcontent *)U)->url_data);
151         }
152         else {
153                 *len = 0;
154                 return ("");
155         }
156 }
157
158
159 const char *BSTR(const char *key)
160 {
161         void *U;
162
163         if ((WC->Hdr->urlstrings != NULL) &&
164             GetHash(WC->Hdr->urlstrings, key, strlen (key), &U))
165                 return ChrPtr(((urlcontent *)U)->url_data);
166         else    
167                 return ("");
168 }
169
170 const char *Bstr(const char *key, size_t keylen)
171 {
172         void *U;
173
174         if ((WC->Hdr->urlstrings != NULL) && 
175             GetHash(WC->Hdr->urlstrings, key, keylen, &U))
176                 return ChrPtr(((urlcontent *)U)->url_data);
177         else    
178                 return ("");
179 }
180
181 const StrBuf *SBSTR(const char *key)
182 {
183         void *U;
184
185         if ((WC->Hdr->urlstrings != NULL) &&
186             GetHash(WC->Hdr->urlstrings, key, strlen (key), &U))
187                 return ((urlcontent *)U)->url_data;
188         else    
189                 return NULL;
190 }
191
192 const StrBuf *SBstr(const char *key, size_t keylen)
193 {
194         void *U;
195
196         if ((WC->Hdr->urlstrings != NULL) && 
197             GetHash(WC->Hdr->urlstrings, key, keylen, &U))
198                 return ((urlcontent *)U)->url_data;
199         else    
200                 return NULL;
201 }
202
203 long LBstr(const char *key, size_t keylen)
204 {
205         void *U;
206
207         if ((WC->Hdr->urlstrings != NULL) && 
208             GetHash(WC->Hdr->urlstrings, key, keylen, &U))
209                 return StrTol(((urlcontent *)U)->url_data);
210         else    
211                 return (0);
212 }
213
214 long LBSTR(const char *key)
215 {
216         void *U;
217
218         if ((WC->Hdr->urlstrings != NULL) && 
219             GetHash(WC->Hdr->urlstrings, key, strlen(key), &U))
220                 return StrTol(((urlcontent *)U)->url_data);
221         else    
222                 return (0);
223 }
224
225 int IBstr(const char *key, size_t keylen)
226 {
227         void *U;
228
229         if ((WC->Hdr->urlstrings != NULL) && 
230             GetHash(WC->Hdr->urlstrings, key, keylen, &U))
231                 return StrTol(((urlcontent *)U)->url_data);
232         else    
233                 return (0);
234 }
235
236 int IBSTR(const char *key)
237 {
238         void *U;
239
240         if ((WC->Hdr->urlstrings != NULL) && 
241             GetHash(WC->Hdr->urlstrings, key, strlen(key), &U))
242                 return StrToi(((urlcontent *)U)->url_data);
243         else    
244                 return (0);
245 }
246
247 int HaveBstr(const char *key, size_t keylen)
248 {
249         void *U;
250
251         if ((WC->Hdr->urlstrings != NULL) && 
252             GetHash(WC->Hdr->urlstrings, key, keylen, &U))
253                 return (StrLength(((urlcontent *)U)->url_data) != 0);
254         else    
255                 return (0);
256 }
257
258 int HAVEBSTR(const char *key)
259 {
260         void *U;
261
262         if ((WC->Hdr->urlstrings != NULL) && 
263             GetHash(WC->Hdr->urlstrings, key, strlen(key), &U))
264                 return (StrLength(((urlcontent *)U)->url_data) != 0);
265         else    
266                 return (0);
267 }
268
269
270 int YesBstr(const char *key, size_t keylen)
271 {
272         void *U;
273
274         if ((WC->Hdr->urlstrings != NULL) && 
275             GetHash(WC->Hdr->urlstrings, key, keylen, &U))
276                 return strcmp( ChrPtr(((urlcontent *)U)->url_data), "yes") == 0;
277         else    
278                 return (0);
279 }
280
281 int YESBSTR(const char *key)
282 {
283         void *U;
284
285         if ((WC->Hdr->urlstrings != NULL) && 
286             GetHash(WC->Hdr->urlstrings, key, strlen(key), &U))
287                 return strcmp( ChrPtr(((urlcontent *)U)->url_data), "yes") == 0;
288         else    
289                 return (0);
290 }
291
292
293
294
295 /*
296  * This function is called by the MIME parser to handle data uploaded by
297  * the browser.  Form data, uploaded files, and the data from HTTP PUT
298  * operations (such as those found in GroupDAV) all arrive this way.
299  *
300  * name         Name of the item being uploaded
301  * filename     Filename of the item being uploaded
302  * partnum      MIME part identifier (not needed)
303  * disp         MIME content disposition (not needed)
304  * content      The actual data
305  * cbtype       MIME content-type
306  * cbcharset    Character set
307  * length       Content length
308  * encoding     MIME encoding type (not needed)
309  * cbid         Content ID (not needed)
310  * userdata     Not used here
311  */
312 void upload_handler(char *name, char *filename, char *partnum, char *disp,
313                         void *content, char *cbtype, char *cbcharset,
314                         size_t length, char *encoding, char *cbid, void *userdata)
315 {
316         wcsession *WCC = WC;
317         urlcontent *u;
318         long keylen;
319
320 #ifdef DEBUG_URLSTRINGS
321         syslog(9, "upload_handler() name=%s, type=%s, len=%d", name, cbtype, length);
322 #endif
323         if (WCC->Hdr->urlstrings == NULL)
324                 WCC->Hdr->urlstrings = NewHash(1, NULL);
325
326         /* Form fields */
327         if ( (length > 0) && (IsEmptyStr(cbtype)) ) {
328                 u = (urlcontent *) malloc(sizeof(urlcontent));
329                 
330                 keylen = safestrncpy(u->url_key, name, sizeof(u->url_key));
331                 u->url_data = NewStrBufPlain(content, length);
332                 
333                 if (strncmp(u->url_key, "__", 2) != 0)
334                 {
335                         Put(WCC->Hdr->urlstrings, u->url_key, keylen, u, free_url);
336                 }
337                 else {
338                         syslog(1, "REJECTED because of __ is internal only: %s = [%d]  %s\n", 
339                                 u->url_key, 
340                                 StrLength(u->url_data), 
341                                 ChrPtr(u->url_data)); 
342                         
343                         free_url(u);
344                 }
345 #ifdef DEBUG_URLSTRINGS
346                 syslog(9, "Key: <%s> len: [%d] Data: <%s>", 
347                         u->url_key, 
348                         StrLength(u->url_data), 
349                         ChrPtr(u->url_data));
350 #endif
351         }
352
353         /* Uploaded files */
354         if ( (length > 0) && (!IsEmptyStr(cbtype)) ) {
355                 WCC->upload = NewStrBufPlain(content, length);
356                 WCC->upload_length = length;
357                 WCC->upload_filename = NewStrBufPlain(filename, -1);
358                 safestrncpy(WCC->upload_content_type, cbtype, sizeof(WC->upload_content_type));
359 #ifdef DEBUG_URLSTRINGS
360                 syslog(9, "File: <%s> len: [%ld]", filename, length);
361 #endif
362                 
363         }
364
365 }
366
367
368
369 void PutBstr(const char *key, long keylen, StrBuf *Value)
370 {
371         urlcontent *u;
372         wcsession *WCC = WC;
373
374         if(keylen > sizeof(u->url_key)) {
375                 syslog(1, "invalid url_key from %s", ChrPtr(WCC->Hdr->HR.browser_host));
376                 FreeStrBuf(&Value);
377                 return;
378         }
379         u = (urlcontent*)malloc(sizeof(urlcontent));
380         memcpy(u->url_key, key, keylen + 1);
381         u->url_data = Value;
382         Put(WC->Hdr->urlstrings, u->url_key, keylen, u, free_url);
383 }
384
385
386
387 int ConditionalBstr(StrBuf *Target, WCTemplputParams *TP)
388 {
389         if(TP->Tokens->nParameters == 3)
390                 return HaveBstr(TKEY(2));
391         else {
392                 if (IS_NUMBER(TP->Tokens->Params[3]->Type))
393                 {
394                         return LBstr(TKEY(2)) == 
395                                 GetTemplateTokenNumber(Target, 
396                                                        TP, 
397                                                        3, 
398                                                        0);
399                 }
400                 else {
401                         const char *pch;
402                         long len;
403
404                         GetTemplateTokenString (Target, TP, 3, &pch, &len);
405                         return strcmp(Bstr(TKEY(2)), pch) == 0;
406                 }
407         }
408 }
409
410 void tmplput_bstr(StrBuf *Target, WCTemplputParams *TP)
411 {
412         const StrBuf *Buf = SBstr(TKEY(0));
413         if (Buf != NULL)
414                 StrBufAppendTemplate(Target, TP, Buf, 1);
415 }
416
417
418 void tmplput_bstrforward(StrBuf *Target, WCTemplputParams *TP)
419 {
420         const StrBuf *Buf = SBstr(TKEY(0));
421         if (Buf != NULL) {
422                 StrBufAppendBufPlain(Target, HKEY("?"), 0);             
423                 StrBufAppendBufPlain(Target, TKEY(0), 0);
424                 StrBufAppendBufPlain(Target, HKEY("="), 0);             
425                 StrBufAppendTemplate(Target, TP, Buf, 1);
426         }
427 }
428
429 void diagnostics(void)
430 {
431         output_headers(1, 1, 1, 0, 0, 0);
432         wc_printf("Session: %d<hr />\n", WC->wc_session);
433         wc_printf("Command: <br><PRE>\n");
434 /*      
435 StrEscAppend(WC->WBuf, NULL, WC->UrlFragment1, 0, 0);
436         wc_printf("<br>\n");
437 StrEscAppend(WC->WBuf, NULL, WC->UrlFragment12 0, 0);
438         wc_printf("<br>\n");
439 StrEscAppend(WC->WBuf, NULL, WC->UrlFragment3, 0, 0);
440 */
441         wc_printf("</PRE><hr />\n");
442         wc_printf("Variables: <br><PRE>\n");
443         dump_vars();
444         wc_printf("</PRE><hr />\n");
445         wDumpContent(1);
446 }
447
448
449 void tmplput_url_part(StrBuf *Target, WCTemplputParams *TP)
450 {
451         StrBuf *Name = NULL;
452         StrBuf *UrlBuf = NULL;
453         wcsession *WCC = WC;
454         
455         if (WCC != NULL) {
456                 long n;
457
458                 n = GetTemplateTokenNumber(Target, TP, 0, 0);
459                 if (n == 0) {
460                         if (WCC->Hdr->HR.Handler != NULL)
461                                 UrlBuf = Name = WCC->Hdr->HR.Handler->Name;
462                 }
463                 else if (n == 1) {
464                         UrlBuf = NewStrBuf();
465                         StrBufExtract_token(UrlBuf, WCC->Hdr->HR.ReqLine, 0, '/');
466                 }
467                 else {
468                         UrlBuf = NewStrBuf();
469                         StrBufExtract_token(UrlBuf, WCC->Hdr->HR.ReqLine, 1, '/');
470                 }
471
472                 if (UrlBuf == NULL)  {
473                         LogTemplateError(Target, "urlbuf", ERR_PARM1, TP, "not set.");
474                 }
475                 StrBufAppendTemplate(Target, TP, UrlBuf, 2);
476                 if (Name == NULL) FreeStrBuf(&UrlBuf);
477         }
478 }
479
480 typedef struct __BstrPair {
481         StrBuf *x;
482         StrBuf *y;
483 }BstrPair;
484 CtxType CTX_BSTRPAIRS = CTX_NONE;
485 void HFreeBstrPair(void *pv)
486 {
487         BstrPair *p = (BstrPair*) pv;
488         FreeStrBuf(&p->x);
489         FreeStrBuf(&p->y);
490         free(pv);
491 }
492
493 HashList *iterate_GetBstrPairs(StrBuf *Target, WCTemplputParams *TP)
494 {
495         StrBuf *X, *Y;
496         const char *ch = NULL;
497         long len;
498         const StrBuf *TheBStr;
499         BstrPair *OnePair;
500         HashList *List;
501         const char *Pos = NULL;
502         int i = 0;
503
504         if (HaveTemplateTokenString(NULL, TP, 2, &ch, &len))
505         {
506                 GetTemplateTokenString(Target, TP, 2, &ch, &len);
507         }
508         else 
509         {
510                 return NULL;
511         }
512
513         TheBStr = SBstr(ch, len);
514         if ((TheBStr == NULL) || (StrLength(TheBStr) == 0))
515                 return NULL;
516         List = NewHash(1, NULL);
517         while (Pos != StrBufNOTNULL)
518         {
519                 X = NewStrBufPlain(NULL, StrLength(TheBStr));
520                 StrBufExtract_NextToken(X, TheBStr, &Pos, '|');
521                 if (Pos == StrBufNOTNULL) {
522                         FreeStrBuf(&X);
523                         DeleteHash(&List);
524                         return NULL;
525                 }
526                 Y = NewStrBufPlain(NULL, StrLength(TheBStr));
527                 StrBufExtract_NextToken(Y, TheBStr, &Pos, '|');
528                 OnePair = (BstrPair*)malloc(sizeof(BstrPair));
529                 OnePair->x = X;
530                 OnePair->y = Y;
531                 Put(List, IKEY(i), OnePair, HFreeBstrPair);
532                 i++;
533         }
534         return List;
535 }
536
537
538 void tmplput_bstr_pair(StrBuf *Target, WCTemplputParams *TP, int XY)
539 {
540         BstrPair *Pair = (BstrPair*) CTX(CTX_BSTRPAIRS);
541
542         StrBufAppendTemplate(Target, TP, (XY)?Pair->y:Pair->x, 0);
543 }
544
545 void tmplput_bstr_pair_x(StrBuf *Target, WCTemplputParams *TP)
546 {       tmplput_bstr_pair(Target, TP, 0); }
547 void tmplput_bstr_pair_y(StrBuf *Target, WCTemplputParams *TP)
548 {       tmplput_bstr_pair(Target, TP, 1); }
549
550 void 
551 InitModule_PARAMHANDLING
552 (void)
553 {
554         RegisterCTX(CTX_BSTRPAIRS);
555         WebcitAddUrlHandler(HKEY("diagnostics"), "", 0, diagnostics, NEED_URL);
556
557         RegisterIterator("ITERATE:BSTR:PAIR", 1, NULL, iterate_GetBstrPairs, NULL, DeleteHash, CTX_BSTRPAIRS, CTX_NONE, IT_NOFLAG);
558         RegisterNamespace("BSTR:PAIR:X", 1, 2, tmplput_bstr_pair_x, NULL, CTX_BSTRPAIRS);
559         RegisterNamespace("BSTR:PAIR:Y", 1, 2, tmplput_bstr_pair_y, NULL, CTX_BSTRPAIRS);
560
561         RegisterConditional("COND:BSTR", 1, ConditionalBstr, CTX_NONE);
562         RegisterNamespace("BSTR", 1, 2, tmplput_bstr, NULL, CTX_NONE);
563         RegisterNamespace("BSTR:FORWARD", 1, 2, tmplput_bstrforward, NULL, CTX_NONE);
564         RegisterNamespace("URLPART", 1, 2, tmplput_url_part, NULL, CTX_NONE);
565 }
566
567
568 void
569 SessionAttachModule_PARAMHANDLING
570 (wcsession *sess)
571 {
572         sess->Hdr->urlstrings = NewHash(1,NULL);
573 }
574
575 void
576 SessionDetachModule_PARAMHANDLING
577 (wcsession *sess)
578 {
579         DeleteHash(&sess->Hdr->urlstrings);
580         FreeStrBuf(&sess->upload_filename);
581 }