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