41aad9274daad0bb6e6d3818cf6795c8f1956215
[citadel.git] / webcit / subst.c
1 /*
2  * $Id$
3  */
4 /**
5  * \defgroup Subst Variable substitution type stuff
6  * \ingroup CitadelConfig
7  */
8
9 /*@{*/
10
11 #include "sysdep.h"
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <unistd.h>
15 #include <dirent.h>
16 #include <errno.h>
17 #include <stdarg.h>
18 #define SHOW_ME_VAPPEND_PRINTF
19
20 #include "webcit.h"
21 #include "webserver.h"
22
23 extern char *static_dirs[PATH_MAX];  /**< Disk representation */
24
25 HashList *WirelessTemplateCache;
26 HashList *WirelessLocalTemplateCache;
27 HashList *TemplateCache;
28 HashList *LocalTemplateCache;
29
30 HashList *GlobalNS;
31 HashList *Iterators;
32 HashList *Conditionals;
33 HashList *SortHash;
34
35 int LoadTemplates = 0;
36
37 #define SV_GETTEXT 1
38 #define SV_CONDITIONAL 2
39 #define SV_NEG_CONDITIONAL 3
40 #define SV_CUST_STR_CONDITIONAL 4
41 #define SV_SUBTEMPL 5
42 #define SV_PREEVALUATED 6
43
44 typedef struct _WCTemplate {
45         StrBuf *Data;
46         StrBuf *FileName;
47         int nTokensUsed;
48         int TokenSpace;
49         WCTemplateToken **Tokens;
50 } WCTemplate;
51
52 typedef struct _HashHandler {
53         int nMinArgs;
54         int nMaxArgs;
55         int ContextRequired;
56         WCHandlerFunc HandlerFunc;
57 }HashHandler;
58
59 void *load_template(StrBuf *filename, StrBuf *Key, HashList *PutThere);
60 int EvaluateConditional(StrBuf *Target, WCTemplateToken *Tokens, WCTemplate *pTmpl, void *Context, int Neg, int state, int ContextType);
61
62 void RegisterNS(const char *NSName, 
63                 long len, 
64                 int nMinArgs, 
65                 int nMaxArgs, 
66                 WCHandlerFunc HandlerFunc, 
67                 int ContextRequired)
68 {
69         HashHandler *NewHandler;
70         
71         NewHandler = (HashHandler*) malloc(sizeof(HashHandler));
72         NewHandler->nMinArgs = nMinArgs;
73         NewHandler->nMaxArgs = nMaxArgs;
74         NewHandler->HandlerFunc = HandlerFunc;  
75         NewHandler->ContextRequired = ContextRequired;
76         Put(GlobalNS, NSName, len, NewHandler, NULL);
77 }
78
79 void FreeToken(WCTemplateToken **Token)
80 {
81         int i; 
82         FreeStrBuf(&(*Token)->FlatToken);
83         if ((*Token)->HaveParameters) 
84                 for (i = 0; i < (*Token)->nParameters; i++)
85                         free((*Token)->Params[i]);
86         free(*Token);
87         *Token = NULL;
88 }
89
90
91
92 void FreeWCTemplate(void *vFreeMe)
93 {
94         int i;
95         WCTemplate *FreeMe = (WCTemplate*)vFreeMe;
96
97         if (FreeMe->TokenSpace > 0) {
98                 for (i = 0; i < FreeMe->nTokensUsed; i ++) {
99                         FreeToken(&FreeMe->Tokens[i]);
100                 }
101                 free(FreeMe->Tokens);
102         }
103         FreeStrBuf(&FreeMe->FileName);
104         FreeStrBuf(&FreeMe->Data);
105         free(FreeMe);
106 }
107
108
109 /**
110  * \brief debugging function to print array to log
111  */
112 void VarPrintTransition(void *vVar1, void *vVar2, int odd){}
113 /**
114  * \brief debugging function to print array to log
115  */
116 void VarPrintEntry(const char *Key, void *vSubst, int odd)
117 {
118         wcsubst *ptr;
119         lprintf(1,"Subst[%s] : ", Key);
120         ptr = (wcsubst*) vSubst;
121
122         switch(ptr->wcs_type) {
123         case WCS_STRING:
124                 lprintf(1, "  -> %s\n", ChrPtr(ptr->wcs_value));
125                 break;
126         case WCS_SERVCMD:
127                 lprintf(1, "  -> Server [%s]\n", ChrPtr(ptr->wcs_value));
128                 break;
129         case WCS_FUNCTION:
130                 lprintf(1, "  -> function at [%0xd]\n", ptr->wcs_function);
131                 break;
132         default:
133                 lprintf(1,"  WARNING: invalid type: [%ld]!\n", ptr->wcs_type);
134         }
135 }
136
137
138
139 /**
140  * \brief Clear out the list of substitution variables local to this session
141  */
142 void clear_substs(struct wcsession *wc) {
143
144         if (wc->vars != NULL) {
145                 DeleteHash(&wc->vars);
146         }
147 }
148
149 /**
150  * \brief Clear out the list of substitution variables local to this session
151  */
152 void clear_local_substs(void) {
153         clear_substs (WC);
154 }
155
156 int NeedNewBuf(type)
157 {
158         switch(type) {
159         case WCS_STRING:
160         case WCS_SERVCMD:
161         case WCS_STRBUF:
162                 return 1;
163         case WCS_FUNCTION:
164         case WCS_STRBUF_REF:
165         case WCS_LONG:
166         default:
167                 return 0;
168         }
169 }
170
171 void FlushPayload(wcsubst *ptr, int reusestrbuf, int type)
172 {
173         int NeedNew = NeedNewBuf(type);
174         switch(ptr->wcs_type) {
175         case WCS_STRING:
176         case WCS_SERVCMD:
177         case WCS_STRBUF:
178                 if (reusestrbuf && NeedNew) {
179                         FlushStrBuf(ptr->wcs_value);
180                 }
181                 else {
182                         
183                         FreeStrBuf(&ptr->wcs_value);
184                         ptr->wcs_value = NULL;
185                 }
186                 break;
187         case WCS_FUNCTION:
188                 ptr->wcs_function = NULL;
189                 if (reusestrbuf && NeedNew)
190                         ptr->wcs_value = NewStrBuf();
191                 break;
192         case WCS_STRBUF_REF:
193                 ptr->wcs_value = NULL;
194                 if (reusestrbuf && NeedNew)
195                         ptr->wcs_value = NewStrBuf();
196                 break;
197         case WCS_LONG:
198                 ptr->lvalue = 0;
199                 if (reusestrbuf && NeedNew)
200                         ptr->wcs_value = NewStrBuf();
201                 break;
202         default:
203                 if (reusestrbuf && NeedNew)
204                         ptr->wcs_value = NewStrBuf();
205                 break;
206         }
207 }
208
209
210 /**
211  * \brief destructor; kill one entry.
212  */
213 void deletevar(void *data)
214 {
215         wcsubst *ptr = (wcsubst*)data;
216         FlushPayload(ptr, 0, ptr->wcs_type);
217         free(ptr);      
218 }
219
220
221 wcsubst *NewSubstVar(const char *keyname, int keylen, int type)
222 {
223         wcsubst* ptr;
224         struct wcsession *WCC = WC;
225
226         ptr = (wcsubst *) malloc(sizeof(wcsubst));
227         memset(ptr, 0, sizeof(wcsubst));
228
229         ptr->wcs_type = type;
230         safestrncpy(ptr->wcs_key, keyname, sizeof ptr->wcs_key);
231         Put(WCC->vars, keyname, keylen, ptr,  deletevar);
232
233         switch(ptr->wcs_type) {
234         case WCS_STRING:
235         case WCS_SERVCMD:
236                 ptr->wcs_value = NewStrBuf();
237                 break;
238         case WCS_STRBUF:
239         case WCS_FUNCTION:
240         case WCS_STRBUF_REF:
241         case WCS_LONG:
242         default:
243                 break;
244         }
245         return ptr;
246 }
247
248
249 /**
250  * \brief Add a substitution variable (local to this session) (strlen version...)
251  * \param keyname the replacementstring to substitute
252  * \param keytype the kind of the key
253  * \param format the format string ala printf
254  * \param ... the arguments to substitute in the formatstring
255  */
256 void SVPRINTF(char *keyname, int keytype, const char *format,...)
257 {
258         va_list arg_ptr;
259         void *vPtr;
260         wcsubst *ptr = NULL;
261         size_t keylen;
262         struct wcsession *WCC = WC;
263         
264         keylen = strlen(keyname);
265         /**
266          * First look if we're doing a replacement of
267          * an existing key
268          */
269         /*PrintHash(WCC->vars, VarPrintTransition, VarPrintEntry);*/
270         if (GetHash(WCC->vars, keyname, keylen, &vPtr)) {
271                 ptr = (wcsubst*)vPtr;
272                 FlushPayload(ptr, keytype, keytype);
273                 ptr->wcs_type = keytype;
274         }
275         else    /** Otherwise allocate a new one */
276         {
277                 ptr = NewSubstVar(keyname, keylen, keytype);
278         }
279
280         /** Format the string */
281         va_start(arg_ptr, format);
282         StrBufVAppendPrintf(ptr->wcs_value, format, arg_ptr);
283         va_end(arg_ptr);
284 }
285
286 /**
287  * \brief Add a substitution variable (local to this session)
288  * \param keyname the replacementstring to substitute
289  * \param keytype the kind of the key
290  * \param format the format string ala printf
291  * \param ... the arguments to substitute in the formatstring
292  */
293 void svprintf(char *keyname, size_t keylen, int keytype, const char *format,...)
294 {
295         va_list arg_ptr;
296         void *vPtr;
297         wcsubst *ptr = NULL;
298         struct wcsession *WCC = WC;
299                 
300         /**
301          * First look if we're doing a replacement of
302          * an existing key
303          */
304         /*PrintHash(WCC->vars, VarPrintTransition, VarPrintEntry);*/
305         if (GetHash(WCC->vars, keyname, keylen, &vPtr)) {
306                 ptr = (wcsubst*)vPtr;
307                 FlushPayload(ptr, 1, keytype);
308                 ptr->wcs_type = keytype;
309         }
310         else    /** Otherwise allocate a new one */
311         {
312                 ptr = NewSubstVar(keyname, keylen, keytype);
313         }
314
315         /** Format the string and save it */
316         va_start(arg_ptr, format);
317         StrBufVAppendPrintf(ptr->wcs_value, format, arg_ptr);
318         va_end(arg_ptr);
319 }
320
321 /**
322  * \brief Add a substitution variable (local to this session)
323  * \param keyname the replacementstring to substitute
324  * \param keytype the kind of the key
325  * \param format the format string ala printf
326  * \param ... the arguments to substitute in the formatstring
327  */
328 void SVPut(char *keyname, size_t keylen, int keytype, char *Data)
329 {
330         void *vPtr;
331         wcsubst *ptr = NULL;
332         struct wcsession *WCC = WC;
333
334         
335         /**
336          * First look if we're doing a replacement of
337          * an existing key
338          */
339         /*PrintHash(WCC->vars, VarPrintTransition, VarPrintEntry);*/
340         if (GetHash(WCC->vars, keyname, keylen, &vPtr)) {
341                 ptr = (wcsubst*)vPtr;
342                 FlushPayload(ptr, 1, keytype);
343                 ptr->wcs_type = keytype;
344         }
345         else    /** Otherwise allocate a new one */
346         {
347                 ptr = NewSubstVar(keyname, keylen, keytype);
348         }
349         StrBufAppendBufPlain(ptr->wcs_value, Data, -1, 0);
350 }
351
352 /**
353  * \brief Add a substitution variable (local to this session)
354  * \param keyname the replacementstring to substitute
355  * \param keytype the kind of the key
356  * \param format the format string ala printf
357  * \param ... the arguments to substitute in the formatstring
358  */
359 void SVPutLong(char *keyname, size_t keylen, long Data)
360 {
361         void *vPtr;
362         wcsubst *ptr = NULL;
363         struct wcsession *WCC = WC;
364
365         
366         /**
367          * First look if we're doing a replacement of
368          * an existing key
369          */
370         /*PrintHash(WCC->vars, VarPrintTransition, VarPrintEntry);*/
371         if (GetHash(WCC->vars, keyname, keylen, &vPtr)) {
372                 ptr = (wcsubst*)vPtr;
373                 FlushPayload(ptr, 1, WCS_LONG);
374                 ptr->wcs_type = WCS_LONG;
375         }
376         else    /** Otherwise allocate a new one */
377         {
378                 ptr = NewSubstVar(keyname, keylen, WCS_LONG);
379         }
380         ptr->lvalue = Data;
381 }
382
383 /**
384  * \brief Add a substitution variable (local to this session) that does a callback
385  * \param keyname the keystring to substitute
386  * \param fcn_ptr the function callback to give the substitution string
387  */
388 void SVCallback(char *keyname, size_t keylen, WCHandlerFunc fcn_ptr)
389 {
390         wcsubst *ptr;
391         void *vPtr;
392         struct wcsession *WCC = WC;
393
394         /**
395          * First look if we're doing a replacement of
396          * an existing key
397          */
398         /*PrintHash(WCC->vars, VarPrintTransition, VarPrintEntry);*/
399         if (GetHash(WCC->vars, keyname, keylen, &vPtr)) {
400                 ptr = (wcsubst*)vPtr;
401                 FlushPayload(ptr, 1, WCS_FUNCTION);
402                 ptr->wcs_type = WCS_FUNCTION;
403         }
404         else    /** Otherwise allocate a new one */
405         {
406                 ptr = NewSubstVar(keyname, keylen, WCS_FUNCTION);
407         }
408
409         ptr->wcs_function = fcn_ptr;
410 }
411 inline void SVCALLBACK(char *keyname, WCHandlerFunc fcn_ptr)
412 {
413         SVCallback(keyname, strlen(keyname), fcn_ptr);
414 }
415
416
417
418 void SVPUTBuf(const char *keyname, int keylen, const StrBuf *Buf, int ref)
419 {
420         wcsubst *ptr;
421         void *vPtr;
422         struct wcsession *WCC = WC;
423
424         /**
425          * First look if we're doing a replacement of
426          * an existing key
427          */
428         /*PrintHash(WCC->vars, VarPrintTransition, VarPrintEntry);*/
429         if (GetHash(WCC->vars, keyname, keylen, &vPtr)) {
430                 ptr = (wcsubst*)vPtr;
431                 FlushPayload(ptr, 0, (ref)?WCS_STRBUF_REF:WCS_STRBUF);
432                 ptr->wcs_type = (ref)?WCS_STRBUF_REF:WCS_STRBUF;
433         }
434         else    /** Otherwise allocate a new one */
435         {
436                 ptr = NewSubstVar(keyname, keylen, (ref)?WCS_STRBUF_REF:WCS_STRBUF);
437         }
438         ptr->wcs_value = (StrBuf*)Buf;
439 }
440
441 /**
442  * \brief back end for print_value_of() ... does a server command
443  * \param servcmd server command to execute on the citadel server
444  */
445 void pvo_do_cmd(StrBuf *Target, StrBuf *servcmd) {
446         char buf[SIZ];
447         int len;
448
449         serv_puts(ChrPtr(servcmd));
450         len = serv_getln(buf, sizeof buf);
451
452         switch(buf[0]) {
453                 case '2':
454                 case '3':
455                 case '5':
456                         StrBufAppendPrintf(Target, "%s\n", &buf[4]);
457                         break;
458                 case '1':
459                         _fmout(Target, "CENTER");
460                         break;
461                 case '4':
462                         StrBufAppendPrintf(Target, "%s\n", &buf[4]);
463                         serv_puts("000");
464                         break;
465         }
466 }
467
468 void GetTemplateTokenString(WCTemplateToken *Tokens,
469                             int N, 
470                             const char **Value, 
471                             long *len)
472 {
473         StrBuf *Buf;
474
475         if (Tokens->nParameters < N) {
476                 *Value = "";
477                 *len = 0;
478                 return;
479         }
480
481         switch (Tokens->Params[N]->Type) {
482
483         case TYPE_STR:
484                 *Value = Tokens->Params[N]->Start;
485                 *len = Tokens->Params[N]->len;
486                 break;
487         case TYPE_BSTR:
488                 Buf = (StrBuf*) SBstr(Tokens->Params[N]->Start, 
489                                       Tokens->Params[N]->len);
490                 *Value = ChrPtr(Buf);
491                 *len = StrLength(Buf);
492                 break;
493         case TYPE_PREFSTR:
494                 get_PREFERENCE(
495                         Tokens->Params[N]->Start, 
496                         Tokens->Params[N]->len, 
497                         &Buf);
498                 *Value = ChrPtr(Buf);
499                 *len = StrLength(Buf);
500                 break;
501         case TYPE_LONG:
502         case TYPE_PREFINT:
503                 break; ///todo: string to text?
504         case TYPE_GETTEXT:
505                 *Value = _(Tokens->Params[N]->Start);
506                 *len = strlen(*Value);
507                 break;
508         default:
509                 break;
510 //todo log error
511         }
512 }
513
514
515
516 /**
517  * \brief Print the value of a variable
518  * \param keyname get a key to print
519  */
520 void print_value_of(StrBuf *Target, WCTemplateToken *Tokens, void *Context, int ContextType) {
521         struct wcsession *WCC = WC;
522         wcsubst *ptr;
523         void *vVar;
524
525         /*if (WCC->vars != NULL) PrintHash(WCC->vars, VarPrintTransition, VarPrintEntry);*/
526         /// TODO: debricated!
527         if (Tokens->pName[0] == '=') {
528                 DoTemplate(Tokens->pName+1, Tokens->NameEnd - 1, NULL, NULL, 0);
529         }
530
531 //////TODO: if param[1] == "U" -> urlescape
532 /// X -> escputs
533         /** Page-local variables */
534         if ((WCC->vars!= NULL) && GetHash(WCC->vars, Tokens->pName, Tokens->NameEnd, &vVar)) {
535                 ptr = (wcsubst*) vVar;
536                 switch(ptr->wcs_type) {
537                 case WCS_STRING:
538                         StrBufAppendBuf(Target, ptr->wcs_value, 0);
539                         break;
540                 case WCS_SERVCMD:
541                         pvo_do_cmd(Target, ptr->wcs_value);
542                         break;
543                 case WCS_FUNCTION:
544                         (*ptr->wcs_function) (Target, Tokens->nParameters, Tokens, Context, ContextType);
545                         break;
546                 case WCS_STRBUF:
547                 case WCS_STRBUF_REF:
548                         StrBufAppendBuf(Target, ptr->wcs_value, 0);
549                         break;
550                 case WCS_LONG:
551                         StrBufAppendPrintf(Target, "%ld", ptr->lvalue);
552                         break;
553                 default:
554                         lprintf(1,"WARNING: invalid value in SV-Hash at %s!\n", Tokens->pName);
555                         StrBufAppendPrintf(Target, "<pre>WARNING: \ninvalid value in SV-Hash at %s!\n</pre>", Tokens->pName);
556                 }
557         }
558         else {
559                 lprintf(1, "didn't find Handler [%s] (in '%s' line %ld); "
560                         " [%s]\n", 
561                         Tokens->pName,
562                         ChrPtr(Tokens->FileName),
563                         Tokens->Line,
564                         ChrPtr(Tokens->FlatToken));
565                 wc_backtrace();
566         }
567 }
568
569 int CompareSubstToToken(TemplateParam *ParamToCompare, TemplateParam *ParamToLookup)
570 {
571         struct wcsession *WCC = WC;
572         wcsubst *ptr;
573         void *vVar;
574
575         if ((WCC->vars!= NULL) && GetHash(WCC->vars, ParamToLookup->Start, 
576                                           ParamToLookup->len, &vVar)) {
577                 ptr = (wcsubst*) vVar;
578                 switch(ptr->wcs_type) {
579                 case WCS_STRING:
580                 case WCS_STRBUF:
581                 case WCS_STRBUF_REF:
582                         if (ParamToCompare->Type == TYPE_STR)
583                                 return ((ParamToCompare->len == StrLength(ptr->wcs_value)) &&
584                                         (strcmp(ParamToCompare->Start, ChrPtr(ptr->wcs_value)) == 0));
585                         else
586                                 return ParamToCompare->lvalue == StrTol(ptr->wcs_value);
587                         break;
588                 case WCS_SERVCMD:
589                         return 1; 
590                         break;
591                 case WCS_FUNCTION:
592                         return 1;
593                 case WCS_LONG:
594                         if (ParamToCompare->Type == TYPE_STR)
595                                 return 0;
596                         else 
597                                 return ParamToCompare->lvalue == ptr->lvalue;
598                         break;
599                 default:
600                         lprintf(1,"WARNING: invalid value in SV-Hash at %s!\n", 
601                                 ParamToLookup->Start);
602                 }
603         }
604         return 0;
605 }
606
607 int CompareSubstToStrBuf(StrBuf *Compare, TemplateParam *ParamToLookup)
608 {
609         struct wcsession *WCC = WC;
610         wcsubst *ptr;
611         void *vVar;
612
613         if ((WCC->vars!= NULL) && GetHash(WCC->vars, ParamToLookup->Start, 
614                                           ParamToLookup->len, &vVar)) {
615                 ptr = (wcsubst*) vVar;
616                 switch(ptr->wcs_type) {
617                 case WCS_STRING:
618                 case WCS_STRBUF:
619                 case WCS_STRBUF_REF:
620                         return ((StrLength(Compare) == StrLength(ptr->wcs_value)) &&
621                                 (strcmp(ChrPtr(Compare), ChrPtr(ptr->wcs_value)) == 0));
622                 case WCS_SERVCMD:
623                         return 1; 
624                         break;
625                 case WCS_FUNCTION:
626                         return 1;
627                 case WCS_LONG:
628                         return StrTol(Compare) == ptr->lvalue;
629                 default:
630                         lprintf(1,"WARNING: invalid value in SV-Hash at %s!\n", 
631                                 ParamToLookup->Start);
632                 }
633         }
634         return 0;
635 }
636
637
638
639 /**
640  * \brief puts string into the template and computes which escape methon we should use
641  * \param Source the string we should put into the template
642  * \param FormatTypeIndex where should we look for escape types if?
643  */
644 void StrBufAppendTemplate(StrBuf *Target, 
645                           int nArgs, 
646                           WCTemplateToken *Tokens,
647                           void *Context, int ContextType,
648                           const StrBuf *Source, int FormatTypeIndex)
649 {
650         struct wcsession *WCC;
651         StrBuf *Buf;
652         char EscapeAs = ' ';
653
654         if ((FormatTypeIndex < Tokens->nParameters) &&
655             (Tokens->Params[FormatTypeIndex]->Type == TYPE_STR) &&
656             (Tokens->Params[FormatTypeIndex]->len == 1)) {
657                 EscapeAs = *Tokens->Params[FormatTypeIndex]->Start;
658         }
659
660         switch(EscapeAs)
661         {
662         case 'H':
663                 WCC = WC;
664                 Buf = NewStrBufPlain(NULL, StrLength(Source));
665                 StrBuf_RFC822_to_Utf8(Buf, 
666                                       Source, 
667                                       (WCC!=NULL)? WCC->DefaultCharset : NULL, 
668                                       NULL);
669                 StrEscAppend(Target, Buf, NULL, 0, 0);
670                 FreeStrBuf(&Buf);
671                 break;
672         case 'X':
673                 StrEscAppend(Target, Source, NULL, 0, 0);
674                 break;
675         default:
676                 StrBufAppendBuf(Target, Source, 0);
677         }
678 }
679
680
681 void PutNewToken(WCTemplate *Template, WCTemplateToken *NewToken)
682 {
683         if (Template->nTokensUsed + 1 >= Template->TokenSpace) {
684                 if (Template->TokenSpace <= 0) {
685                         Template->Tokens = (WCTemplateToken**)malloc(
686                                 sizeof(WCTemplateToken*) * 10);
687                         Template->TokenSpace = 10;
688                 }
689                 else {
690                         WCTemplateToken **NewTokens;
691                         NewTokens= (WCTemplateToken**)malloc(
692                                 sizeof(WCTemplateToken*) * 
693                                 Template->TokenSpace * 2);
694                         memcpy(NewTokens, Template->Tokens, 
695                                sizeof(WCTemplateToken*) * Template->nTokensUsed);
696                         free(Template->Tokens);
697                         Template->TokenSpace *= 2;
698                         Template->Tokens = NewTokens;
699                 }
700         }
701         Template->Tokens[(Template->nTokensUsed)++] = NewToken;
702 }
703
704 TemplateParam *GetNextParameter(StrBuf *Buf, const char **pCh, const char *pe, WCTemplateToken *Tokens, WCTemplate *pTmpl)
705 {
706         const char *pch = *pCh;
707         const char *pchs, *pche;
708         TemplateParam *Parm = (TemplateParam *) malloc(sizeof(TemplateParam));
709         char quote = '\0';
710         
711
712         Parm->Type = TYPE_STR;
713
714         /* Skip leading whitespaces */
715         while ((*pch == ' ' )||
716                (*pch == '\t')||
717                (*pch == '\r')||
718                (*pch == '\n')) pch ++;
719
720         if (*pch == ':') {
721                 Parm->Type = TYPE_PREFSTR;
722                 pch ++;
723         }
724         else if (*pch == ';') {
725                 Parm->Type = TYPE_PREFINT;
726                 pch ++;
727         }
728         else if (*pch == '_') {
729                 Parm->Type = TYPE_GETTEXT;
730                 pch ++;
731         }
732         else if (*pch == 'B') {
733                 Parm->Type = TYPE_BSTR;
734                 pch ++;
735         }
736
737
738         if (*pch == '"')
739                 quote = '"';
740         else if (*pch == '\'')
741                 quote = '\'';
742         if (quote != '\0') {
743                 pch ++;
744                 pchs = pch;
745                 while (pch <= pe &&
746                        ((*pch != quote) ||
747                         ( (pch > pchs) && (*(pch - 1) == '\\'))
748                                )) {
749                         pch ++;
750                 }
751                 pche = pch;
752                 if (*pch != quote) {
753                         lprintf(1, "Error (in '%s' line %ld); "
754                                 "evaluating template param [%s] in Token [%s]\n",
755                                 ChrPtr(pTmpl->FileName),
756                                 Tokens->Line,
757                                 ChrPtr(Tokens->FlatToken),
758                                 *pCh);
759                         pch ++;
760                         free(Parm);
761                         return NULL;
762                 }
763                 else {
764                         StrBufPeek(Buf, pch, -1, '\0');         
765                         if (LoadTemplates > 1) {                        
766                                 lprintf(1, "DBG: got param [%s] %ld %ld\n", 
767                                         pchs, pche - pchs, strlen(pchs));
768                         }
769                         Parm->Start = pchs;
770                         Parm->len = pche - pchs;
771                         pch ++; /* move after trailing quote */
772                 }
773         }
774         else {
775                 Parm->Type = TYPE_LONG;
776                 pchs = pch;
777                 while ((pch <= pe) &&
778                        (isdigit(*pch) ||
779                         (*pch == '+') ||
780                         (*pch == '-')))
781                         pch ++;
782                 pch ++;
783                 if (pch - pchs > 1){
784                         StrBufPeek(Buf, pch, -1, '\0');
785                         Parm->lvalue = atol(pchs);
786                         Parm->Start = pchs;
787                         pch++;
788                 }
789                 else {
790                         Parm->lvalue = 0;
791                         lprintf(1, "Error (in '%s' line %ld); "
792                                 "evaluating long template param [%s] in Token [%s]\n",
793                                 ChrPtr(pTmpl->FileName),
794                                 Tokens->Line,
795                                 ChrPtr(Tokens->FlatToken),
796                                 *pCh);
797                         free(Parm);
798                         return NULL;
799                 }
800         }
801         while ((*pch == ' ' )||
802                (*pch == '\t')||
803                (*pch == '\r')||
804                (*pch == ',' )||
805                (*pch == '\n')) pch ++;
806
807         *pCh = pch;
808         return Parm;
809 }
810
811 WCTemplateToken *NewTemplateSubstitute(StrBuf *Buf, 
812                                        const char *pStart, 
813                                        const char *pTmplStart, 
814                                        const char *pTmplEnd, 
815                                        long Line,
816                                        WCTemplate *pTmpl)
817 {
818         void *vVar;
819         const char *pch;
820         TemplateParam *Param;
821         WCTemplateToken *NewToken = (WCTemplateToken*)malloc(sizeof(WCTemplateToken));
822
823         NewToken->FileName = pTmpl->FileName; /* to print meaningfull log messages... */
824         NewToken->Flags = 0;
825         NewToken->Line = Line + 1;
826         NewToken->pTokenStart = pTmplStart;
827         NewToken->TokenStart = pTmplStart - pStart;
828         NewToken->TokenEnd =  (pTmplEnd - pStart) - NewToken->TokenStart;
829         NewToken->pTokenEnd = pTmplEnd;
830         NewToken->NameEnd = NewToken->TokenEnd - 2;
831         NewToken->PreEval = NULL;
832         NewToken->FlatToken = NewStrBufPlain(pTmplStart + 2, pTmplEnd - pTmplStart - 2);
833         
834         StrBufPeek(Buf, pTmplStart, + 1, '\0');
835         StrBufPeek(Buf, pTmplEnd, -1, '\0');
836         pch = NewToken->pName = pTmplStart + 2;
837
838         NewToken->HaveParameters = 0;;
839         NewToken->nParameters = 0;
840
841         while (pch < pTmplEnd - 1) {
842                 if (*pch == '(') {
843                         StrBufPeek(Buf, pch, -1, '\0');
844                         NewToken->NameEnd = pch - NewToken->pName;
845                         pch ++;
846                         if (*(pTmplEnd - 1) != ')') {
847                                 lprintf(1, "Warning, Non welformed Token; missing right parenthesis (in '%s' line %ld); "
848                                         "[%s]\n", 
849                                         ChrPtr(pTmpl->FileName),
850                                         NewToken->Line,
851                                         ChrPtr(NewToken->FlatToken));
852                         }
853                         while (pch < pTmplEnd - 1) {
854                                 Param = GetNextParameter(Buf, &pch, pTmplEnd - 1, NewToken, pTmpl);
855                                 if (Param != NULL) {
856                                         NewToken->HaveParameters = 1;
857                                         if (NewToken->nParameters > MAXPARAM) {
858                                                 lprintf(1, "Error (in '%s' line %ld); "
859                                                         "only [%ld] Params allowed in Tokens [%s]\n",
860                                                         ChrPtr(pTmpl->FileName),
861                                                         NewToken->Line,
862                                                         MAXPARAM,
863                                                         ChrPtr(NewToken->FlatToken));
864                                                 free(Param);
865                                                 FreeToken(&NewToken);
866                                                 return NULL;
867                                         }
868                                         NewToken->Params[NewToken->nParameters++] = Param;
869                                 }
870                                 else break;
871                         }
872                         if((NewToken->NameEnd == 1) &&
873                            (NewToken->HaveParameters == 1))
874                            
875                         {
876                                 if (*(NewToken->pName) == '_')
877                                         NewToken->Flags = SV_GETTEXT;
878                                 else if (*(NewToken->pName) == '=')
879                                         NewToken->Flags = SV_SUBTEMPL;
880                                 else if (*(NewToken->pName) == '%')
881                                         NewToken->Flags = SV_CUST_STR_CONDITIONAL;
882                                 else if (*(NewToken->pName) == '?')
883                                         NewToken->Flags = SV_CONDITIONAL;
884                                 else if (*(NewToken->pName) == '!')
885                                         NewToken->Flags = SV_NEG_CONDITIONAL;
886                         }
887                 }
888                 else pch ++;            
889         }
890         
891         switch (NewToken->Flags) {
892         case 0:
893                 /* If we're able to find out more about the token, do it now while its fresh. */
894                 if (GetHash(GlobalNS, NewToken->pName, NewToken->NameEnd, &vVar)) {
895                         HashHandler *Handler;
896                         Handler = (HashHandler*) vVar;
897                         if ((NewToken->nParameters < Handler->nMinArgs) || 
898                             (NewToken->nParameters > Handler->nMaxArgs)) {
899                                 lprintf(1, "Handler [%s] (in '%s' line %ld); "
900                                         "doesn't work with %ld params [%s]\n", 
901                                         NewToken->pName,
902                                         ChrPtr(pTmpl->FileName),
903                                         NewToken->Line,
904                                         NewToken->nParameters, 
905                                         ChrPtr(NewToken->FlatToken));
906                         }
907                         else {
908                                 NewToken->PreEval = Handler;
909                                 NewToken->Flags = SV_PREEVALUATED;              
910                         }
911                 }
912                 break;
913         case SV_GETTEXT:
914                 if (NewToken->nParameters !=1) {
915                         lprintf(1, "Gettext (in '%s' line %ld); "
916                                 "requires exactly 1 parameter, you gave %ld params [%s]\n", 
917                                 ChrPtr(pTmpl->FileName),
918                                 NewToken->Line,
919                                 NewToken->nParameters, 
920                                 ChrPtr(NewToken->FlatToken));
921                         NewToken->Flags = 0;
922                         break;
923                 }
924                 break;
925         case SV_SUBTEMPL:
926                 if (NewToken->nParameters != 1) {
927                         lprintf(1, "Subtemplates (in '%s' line %ld); "
928                                 "require exactly 1 parameter, you gave %ld params [%s]\n", 
929                                 ChrPtr(pTmpl->FileName),
930                                 NewToken->Line,
931                                 NewToken->nParameters, 
932                                 ChrPtr(NewToken->FlatToken));
933                         break;
934                 }
935                 break;
936         case SV_CUST_STR_CONDITIONAL:
937         case SV_CONDITIONAL:
938         case SV_NEG_CONDITIONAL:
939                 if (NewToken->nParameters <2) {
940                         lprintf(1, "Conditional (in '%s' line %ld); "
941                                 "require at least 2 parameters, you gave %ld params [%s]\n", 
942                                 ChrPtr(pTmpl->FileName),
943                                 NewToken->Line,
944                                 NewToken->nParameters, 
945                                 ChrPtr(NewToken->FlatToken));
946                         NewToken->Flags = 0;
947                         break;
948                 }
949                 if (NewToken->Params[1]->lvalue == 0) {
950                         lprintf(1, "Conditional (in '%s' line %ld); "
951                                 "Conditional ID mustn't be 0! [%s]\n", 
952                                 ChrPtr(pTmpl->FileName),
953                                 NewToken->Line,
954                                 ChrPtr(NewToken->FlatToken));
955                         NewToken->Flags = 0;
956                         break;
957                 }
958                 if (!GetHash(Conditionals, 
959                              NewToken->Params[0]->Start,
960                              NewToken->Params[0]->len,
961                              &vVar) || 
962                     (vVar == NULL)) {
963                         if ((NewToken->Params[0]->len == 1) &&
964                             (NewToken->Params[0]->Start[0] == 'X'))
965                                 break;
966                         lprintf(1, "Conditional [%s] (in '%s' line %ld); Not found![%s]\n", 
967                                 NewToken->Params[0]->Start,
968                                 ChrPtr(pTmpl->FileName),
969                                 NewToken->Line,
970                                 ChrPtr(NewToken->FlatToken));
971 /*
972                         NewToken->Error = NewStrBuf();
973                         StrBufAppendPrintf(
974                                 NewToken->Error, 
975                                 "<pre>\nConditional [%s] (in '%s' line %ld); Not found!\n[%s]\n</pre>\n", 
976                                 NewToken->Params[0]->Start,
977                                 ChrPtr(pTmpl->FileName),
978                                 NewToken->Line,
979                                 ChrPtr(NewToken->FlatToken));
980 */
981                 }
982                 else {
983                         NewToken->PreEval = vVar;
984                 }
985                 break;
986         }
987         return NewToken;
988 }
989
990
991
992
993
994 /**
995  * \brief Display a variable-substituted template
996  * \param templatename template file to load
997  */
998 void *prepare_template(StrBuf *filename, StrBuf *Key, HashList *PutThere)
999 {
1000         WCTemplate *NewTemplate;
1001         NewTemplate = (WCTemplate *) malloc(sizeof(WCTemplate));
1002         NewTemplate->Data = NULL;
1003         NewTemplate->FileName = NewStrBufDup(filename);
1004         NewTemplate->nTokensUsed = 0;
1005         NewTemplate->TokenSpace = 0;
1006         NewTemplate->Tokens = NULL;
1007
1008         Put(PutThere, ChrPtr(Key), StrLength(Key), NewTemplate, FreeWCTemplate);
1009         return NewTemplate;
1010 }
1011
1012 /**
1013  * \brief Display a variable-substituted template
1014  * \param templatename template file to load
1015  */
1016 void *load_template(StrBuf *filename, StrBuf *Key, HashList *PutThere)
1017 {
1018         int fd;
1019         struct stat statbuf;
1020         const char *pS, *pE, *pch, *Err;
1021         long Line;
1022         int pos;
1023         WCTemplate *NewTemplate;
1024
1025         fd = open(ChrPtr(filename), O_RDONLY);
1026         if (fd <= 0) {
1027                 lprintf(1, "ERROR: could not open template '%s' - %s\n",
1028                         ChrPtr(filename), strerror(errno));
1029                 return NULL;
1030         }
1031
1032         if (fstat(fd, &statbuf) == -1) {
1033                 lprintf(1, "ERROR: could not stat template '%s' - %s\n",
1034                         ChrPtr(filename), strerror(errno));
1035                 return NULL;
1036         }
1037
1038         NewTemplate = (WCTemplate *) malloc(sizeof(WCTemplate));
1039         NewTemplate->Data = NewStrBufPlain(NULL, statbuf.st_size);
1040         NewTemplate->FileName = NewStrBufDup(filename);
1041         NewTemplate->nTokensUsed = 0;
1042         NewTemplate->TokenSpace = 0;
1043         NewTemplate->Tokens = NULL;
1044         if (StrBufReadBLOB(NewTemplate->Data, &fd, 1, statbuf.st_size, &Err) < 0) {
1045                 close(fd);
1046                 FreeWCTemplate(NewTemplate);
1047                 lprintf(1, "ERROR: reading template '%s' - %s<br />\n",
1048                         ChrPtr(filename), strerror(errno));
1049                 return NULL;
1050         }
1051         close(fd);
1052
1053         Line = 0;
1054         pS = pch = ChrPtr(NewTemplate->Data);
1055         pE = pS + StrLength(NewTemplate->Data);
1056         while (pch < pE) {
1057                 const char *pts, *pte;
1058                 int InQuotes = 0;
1059                 int InDoubleQuotes = 0;
1060
1061                 /** Find one <? > */
1062                 pos = (-1);
1063                 for (; pch < pE; pch ++) {
1064                         if ((*pch=='<')&&(*(pch + 1)=='?'))
1065                                 break;
1066                         if (*pch=='\n') Line ++;
1067                 }
1068                 if (pch >= pE)
1069                         continue;
1070                 pts = pch;
1071
1072                 /** Found one? parse it. */
1073                 for (; pch <= pE - 1; pch ++) {
1074                         if (*pch == '"')
1075                                 InDoubleQuotes = ! InDoubleQuotes;
1076                         else if (*pch == '\'')
1077                                 InQuotes = ! InQuotes;
1078                         else if ((!InQuotes  && !InDoubleQuotes) &&
1079                                  ((*pch!='\\')&&(*(pch + 1)=='>'))) {
1080                                 pch ++;
1081                                 break;
1082                         }
1083                 }
1084                 if (pch + 1 > pE)
1085                         continue;
1086                 pte = pch;
1087                 PutNewToken(NewTemplate, 
1088                             NewTemplateSubstitute(NewTemplate->Data, pS, pts, pte, Line, NewTemplate));
1089                 pch ++;
1090         }
1091         if (LoadTemplates == 0)
1092                 Put(PutThere, ChrPtr(Key), StrLength(Key), NewTemplate, FreeWCTemplate);
1093         return NewTemplate;
1094 }
1095
1096
1097 ///void PrintTemplate(const char *Key, void *vSubst, int odd)
1098 const char* PrintTemplate(void *vSubst)
1099 {
1100         WCTemplate *Tmpl = vSubst;
1101
1102         return ChrPtr(Tmpl->FileName);
1103
1104 }
1105
1106 int LoadTemplateDir(const char *DirName, HashList *wireless, HashList *big)
1107 {
1108         StrBuf *FileName;
1109         StrBuf *Tag;
1110         StrBuf *Dir;
1111         DIR *filedir = NULL;
1112         struct dirent *filedir_entry;
1113         int d_namelen;
1114         int d_without_ext;
1115         int IsMobile;
1116         
1117         Dir = NewStrBuf();
1118         StrBufPrintf(Dir, "%s/t", DirName);
1119         filedir = opendir (ChrPtr(Dir));
1120         if (filedir == NULL) {
1121                 FreeStrBuf(&Dir);
1122                 return 0;
1123         }
1124
1125         FileName = NewStrBuf();
1126         Tag = NewStrBuf();
1127         while ((filedir_entry = readdir(filedir)))
1128         {
1129                 char *MinorPtr;
1130                 char *PStart;
1131 #ifdef _DIRENT_HAVE_D_NAMELEN
1132                 d_namelen = filedir_entry->d_namelen;
1133 #else
1134                 d_namelen = strlen(filedir_entry->d_name);
1135 #endif
1136                 d_without_ext = d_namelen;
1137                 while ((d_without_ext > 0) && (filedir_entry->d_name[d_without_ext] != '.'))
1138                         d_without_ext --;
1139                 if ((d_without_ext == 0) || (d_namelen < 3))
1140                         continue;
1141                 if ((d_namelen > 1) && filedir_entry->d_name[d_namelen - 1] == '~')
1142                         continue; /* Ignore backup files... */
1143
1144                 IsMobile = (strstr(filedir_entry->d_name, ".m.html")!= NULL);
1145                 PStart = filedir_entry->d_name;
1146                 StrBufPrintf(FileName, "%s/%s", ChrPtr(Dir),  filedir_entry->d_name);
1147                 MinorPtr = strchr(filedir_entry->d_name, '.');
1148                 if (MinorPtr != NULL)
1149                         *MinorPtr = '\0';
1150                 StrBufPlain(Tag, filedir_entry->d_name, MinorPtr - filedir_entry->d_name);
1151
1152                 if (LoadTemplates > 1)
1153                         lprintf(1, "%s %d %s\n",ChrPtr(FileName), IsMobile, ChrPtr(Tag));
1154                 if (LoadTemplates == 0)
1155                         load_template(FileName, Tag, (IsMobile)?wireless:big);
1156                 else
1157                         prepare_template(FileName, Tag, (IsMobile)?wireless:big);
1158         }
1159         closedir(filedir);
1160         FreeStrBuf(&FileName);
1161         FreeStrBuf(&Tag);
1162         FreeStrBuf(&Dir);
1163         return 1;
1164 }
1165
1166 void InitTemplateCache(void)
1167 {
1168         LoadTemplateDir(static_dirs[0],
1169                         WirelessTemplateCache,
1170                         TemplateCache);
1171         LoadTemplateDir(static_dirs[1],
1172                         WirelessLocalTemplateCache,
1173                         LocalTemplateCache);
1174 }
1175
1176
1177
1178 /*-----------------------------------------------------------------------------
1179  *                      Filling & processing Templates
1180  */
1181 /**
1182  * \brief executes one token
1183  * \param Target buffer to append to
1184  * \param Token da to  process.
1185  * \param Template we're iterating
1186  * \param Context Contextpoointer to pass in
1187  * \param state are we in conditional state?
1188  * \param ContextType what type of information does context giv us?
1189  */
1190 int EvaluateToken(StrBuf *Target, WCTemplateToken *Tokens, WCTemplate *pTmpl, void *Context, int state, int ContextType)
1191 {
1192         const char *AppendMe;
1193         long AppendMeLen;
1194         HashHandler *Handler;
1195         void *vVar;
1196 // much output, since pName is not terminated...
1197 //      lprintf(1,"Doing token: %s\n",Token->pName);
1198
1199         switch (Tokens->Flags) {
1200         case SV_GETTEXT:
1201                 TmplGettext(Target, Tokens->nParameters, Tokens);
1202                 break;
1203         case SV_CONDITIONAL: /** Forward conditional evaluation */
1204                 return EvaluateConditional(Target, Tokens, pTmpl, Context, 1, state, ContextType);
1205                 break;
1206         case SV_NEG_CONDITIONAL: /** Reverse conditional evaluation */
1207                 return EvaluateConditional(Target, Tokens, pTmpl, Context, 0, state, ContextType);
1208                 break;
1209         case SV_CUST_STR_CONDITIONAL: /** Conditional put custom strings from params */
1210                 if (Tokens->nParameters >= 6) {
1211                         if (EvaluateConditional(Target, Tokens, pTmpl, Context, 0, state, ContextType)) {
1212                                 GetTemplateTokenString(Tokens, 5, &AppendMe, &AppendMeLen);
1213                                 StrBufAppendBufPlain(Target, 
1214                                                      AppendMe, 
1215                                                      AppendMeLen,
1216                                                      0);
1217                         }
1218                         else{
1219                                 GetTemplateTokenString(Tokens, 4, &AppendMe, &AppendMeLen);
1220                                 StrBufAppendBufPlain(Target, 
1221                                                      AppendMe, 
1222                                                      AppendMeLen,
1223                                                      0);
1224                         }
1225                 }
1226                 else  {
1227                         lprintf(1, "Conditional [%s] (in '%s' line %ld); needs at least 6 Params![%s]\n", 
1228                                 Tokens->Params[0]->Start,
1229                                 ChrPtr(pTmpl->FileName),
1230                                 Tokens->Line,
1231                                 ChrPtr(Tokens->FlatToken));
1232                         StrBufAppendPrintf(
1233                                 Target, 
1234                                 "<pre>\nConditional [%s] (in '%s' line %ld); needs 6 Params!\n[%s]\n</pre>\n", 
1235                                 Tokens->Params[0]->Start,
1236                                 ChrPtr(pTmpl->FileName),
1237                                 Tokens->Line,
1238                                 ChrPtr(Tokens->FlatToken));
1239                 }
1240                 break;
1241         case SV_SUBTEMPL:
1242                 if (Tokens->nParameters == 1)
1243                         DoTemplate(Tokens->Params[0]->Start, Tokens->Params[0]->len, NULL, NULL, ContextType);
1244                 break;
1245         case SV_PREEVALUATED:
1246                 Handler = (HashHandler*) Tokens->PreEval;
1247                 if ((Handler->ContextRequired != CTX_NONE) &&
1248                     (Handler->ContextRequired != ContextType)) {
1249                         lprintf(1, "Handler [%s] (in '%s' line %ld); "
1250                                 "requires context of type %ld, have %ld [%s]\n", 
1251                                 Tokens->pName,
1252                                 ChrPtr(pTmpl->FileName),
1253                                 Tokens->Line,
1254                                 Handler->ContextRequired, 
1255                                 ContextType,
1256                                 ChrPtr(Tokens->FlatToken));
1257                         StrBufAppendPrintf(
1258                                 Target, 
1259                                 "<pre>\nHandler [%s] (in '%s' line %ld);"
1260                                 " requires context of type %ld, have %ld!\n[%s]\n</pre>\n", 
1261                                 Tokens->pName,
1262                                 ChrPtr(pTmpl->FileName),
1263                                 Tokens->Line,
1264                                 Handler->ContextRequired, 
1265                                 ContextType,
1266                                 ChrPtr(Tokens->FlatToken));
1267                         return -1;
1268
1269                 }
1270                 Handler->HandlerFunc(Target, 
1271                                      Tokens->nParameters,
1272                                      Tokens,
1273                                      Context, 
1274                                      ContextType); 
1275                 break;          
1276         default:
1277                 if (GetHash(GlobalNS, Tokens->pName, Tokens->NameEnd, &vVar)) {
1278                         Handler = (HashHandler*) vVar;
1279                         if ((Handler->ContextRequired != CTX_NONE) &&
1280                             (Handler->ContextRequired != ContextType)) {
1281                                 lprintf(1, "Handler [%s] (in '%s' line %ld); "
1282                                         "requires context of type %ld, have %ld [%s]\n", 
1283                                         Tokens->pName,
1284                                         ChrPtr(pTmpl->FileName),
1285                                         Tokens->Line,
1286                                         Handler->ContextRequired, 
1287                                         ContextType,
1288                                         ChrPtr(Tokens->FlatToken));
1289                                 StrBufAppendPrintf(
1290                                         Target, 
1291                                         "<pre>\nHandler [%s] (in '%s' line %ld);"
1292                                         " requires context of type %ld, have %ld!\n[%s]\n</pre>\n", 
1293                                         Tokens->pName,
1294                                         ChrPtr(pTmpl->FileName),
1295                                         Tokens->Line,
1296                                         Handler->ContextRequired, 
1297                                         ContextType,
1298                                         ChrPtr(Tokens->FlatToken));
1299                                 return -1;
1300                         }
1301                         else if ((Tokens->nParameters < Handler->nMinArgs) || 
1302                                  (Tokens->nParameters > Handler->nMaxArgs)) {
1303                                 lprintf(1, "Handler [%s] (in '%s' line %ld); "
1304                                         "doesn't work with %ld params [%s]\n", 
1305                                         Tokens->pName,
1306                                         ChrPtr(pTmpl->FileName),
1307                                         Tokens->Line,
1308                                         Tokens->nParameters, 
1309                                         ChrPtr(Tokens->FlatToken));
1310                                 StrBufAppendPrintf(
1311                                         Target, 
1312                                         "<pre>\nHandler [%s] (in '%s' line %ld);"
1313                                         " doesn't work with %ld params!\n[%s]\n</pre>\n", 
1314                                         Tokens->pName,
1315                                         ChrPtr(pTmpl->FileName),
1316                                         Tokens->Line,
1317                                         Tokens->nParameters,
1318                                         ChrPtr(Tokens->FlatToken));
1319                         }
1320                         else {
1321                                 Handler->HandlerFunc(Target, 
1322                                                      Tokens->nParameters,
1323                                                      Tokens,
1324                                                      Context, 
1325                                                      ContextType); /*TODO: subset of that */
1326                                 
1327                         }
1328                 }
1329                 else {
1330                         print_value_of(Target, Tokens, Context, ContextType);
1331                 }
1332         }
1333         return 0;
1334 }
1335
1336
1337
1338 void ProcessTemplate(WCTemplate *Tmpl, StrBuf *Target, void *Context, int ContextType)
1339 {
1340         WCTemplate *pTmpl = Tmpl;
1341         int done = 0;
1342         int i, state;
1343         const char *pData, *pS;
1344         long len;
1345
1346         if (LoadTemplates != 0) {                       
1347                 if (LoadTemplates > 1)
1348                         lprintf(1, "DBG: ----- loading:  [%s] ------ \n", 
1349                                 ChrPtr(Tmpl->FileName));
1350
1351                 pTmpl = load_template(Tmpl->FileName, NULL, NULL);
1352                 if(pTmpl == NULL) {
1353                         StrBufAppendPrintf(
1354                                 Target, 
1355                                 "<pre>\nError loading Template [%s]\n See Logfile for details\n</pre>\n", 
1356                                 ChrPtr(Tmpl->FileName));
1357                         return;
1358                 }
1359
1360         }
1361
1362         pS = pData = ChrPtr(pTmpl->Data);
1363         len = StrLength(pTmpl->Data);
1364         i = 0;
1365         state = 0;
1366         while (!done) {
1367                 if (i >= pTmpl->nTokensUsed) {
1368                         StrBufAppendBufPlain(Target, 
1369                                              pData, 
1370                                              len - (pData - pS), 0);
1371                         done = 1;
1372                 }
1373                 else {
1374                         StrBufAppendBufPlain(
1375                                 Target, pData, 
1376                                 pTmpl->Tokens[i]->pTokenStart - pData, 0);
1377                         state = EvaluateToken(Target, pTmpl->Tokens[i], pTmpl, Context, state, ContextType);
1378                         while ((state != 0) && (i+1 < pTmpl->nTokensUsed)) {
1379                         /* condition told us to skip till its end condition */
1380                                 i++;
1381                                 if ((pTmpl->Tokens[i]->Flags == SV_CONDITIONAL) ||
1382                                     (pTmpl->Tokens[i]->Flags == SV_NEG_CONDITIONAL)) {
1383                                         if (state == EvaluateConditional(
1384                                                     Target,
1385                                                     pTmpl->Tokens[i], 
1386                                                     pTmpl,
1387                                                     Context, 
1388                                                     pTmpl->Tokens[i]->Flags,
1389                                                     state, 
1390                                                     ContextType))
1391                                                 state = 0;
1392                                 }
1393                         }
1394                         pData = pTmpl->Tokens[i++]->pTokenEnd + 1;
1395                         if (i > pTmpl->nTokensUsed)
1396                                 done = 1;
1397                 }
1398         }
1399         if (LoadTemplates != 0) {
1400                 FreeWCTemplate(pTmpl);
1401         }
1402 }
1403
1404 /**
1405  * \brief Display a variable-substituted template
1406  * \param templatename template file to load
1407  */
1408 void DoTemplate(const char *templatename, long len, StrBuf *Target, void *Context, int ContextType) 
1409 {
1410         HashList *Static;
1411         HashList *StaticLocal;
1412         void *vTmpl;
1413         
1414         if (Target == NULL)
1415                 Target = WC->WBuf;
1416         if (WC->is_mobile) {
1417                 Static = WirelessTemplateCache;
1418                 StaticLocal = WirelessLocalTemplateCache;
1419         }
1420         else {
1421                 Static = TemplateCache;
1422                 StaticLocal = LocalTemplateCache;
1423         }
1424
1425         if (len == 0)
1426         {
1427                 lprintf (1, "Can't to load a template with empty name!\n");
1428                 StrBufAppendPrintf(Target, "<pre>\nCan't to load a template with empty name!\n</pre>");
1429                 return;
1430         }
1431
1432         if (!GetHash(StaticLocal, templatename, len, &vTmpl) &&
1433             !GetHash(Static, templatename, len, &vTmpl)) {
1434                 lprintf (1, "didn't find Template [%s] %ld %ld\n", templatename, len , (long)strlen(templatename));
1435                 StrBufAppendPrintf(Target, "<pre>\ndidn't find Template [%s] %ld %ld\n</pre>", 
1436                                    templatename, len, 
1437                                    (long)strlen(templatename));
1438 ///             dbg_PrintHash(Static, PrintTemplate, NULL);
1439 //              PrintHash(Static, VarPrintTransition, PrintTemplate);
1440                 return;
1441         }
1442         if (vTmpl == NULL) 
1443                 return;
1444         ProcessTemplate(vTmpl, Target, Context, ContextType);
1445 }
1446
1447 /*-----------------------------------------------------------------------------
1448  *                      Iterators
1449  */
1450 typedef struct _HashIterator {
1451         HashList *StaticList;
1452         int AdditionalParams;
1453         int ContextType;
1454         int XPectContextType;
1455         RetrieveHashlistFunc GetHash;
1456         HashDestructorFunc Destructor;
1457         SubTemplFunc DoSubTemplate;
1458 } HashIterator;
1459
1460 void RegisterITERATOR(const char *Name, long len, 
1461                       int AdditionalParams, 
1462                       HashList *StaticList, 
1463                       RetrieveHashlistFunc GetHash, 
1464                       SubTemplFunc DoSubTempl,
1465                       HashDestructorFunc Destructor,
1466                       int ContextType, 
1467                       int XPectContextType)
1468 {
1469         HashIterator *It = (HashIterator*)malloc(sizeof(HashIterator));
1470         It->StaticList = StaticList;
1471         It->AdditionalParams = AdditionalParams;
1472         It->GetHash = GetHash;
1473         It->DoSubTemplate = DoSubTempl;
1474         It->Destructor = Destructor;
1475         It->ContextType = ContextType;
1476         It->XPectContextType = XPectContextType;
1477         Put(Iterators, Name, len, It, NULL);
1478 }
1479
1480 void tmpl_iterate_subtmpl(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
1481 {
1482         void *vIt;
1483         HashIterator *It;
1484         HashList *List;
1485         HashPos  *it;
1486         int nMembersUsed;
1487         int nMembersCounted = 0;
1488         long len; 
1489         const char *Key;
1490         void *vContext;
1491         StrBuf *SubBuf;
1492         int oddeven = 0;
1493         
1494         if (!GetHash(Iterators, 
1495                      Tokens->Params[0]->Start,
1496                      Tokens->Params[0]->len,
1497                      &vIt)) {
1498                 lprintf(1, "unknown Iterator [%s] (in '%s' line %ld); "
1499                         " [%s]\n", 
1500                         Tokens->Params[0]->Start,
1501                         ChrPtr(Tokens->FileName),
1502                         Tokens->Line,
1503                         ChrPtr(Tokens->FlatToken));
1504                 StrBufAppendPrintf(
1505                         Target,
1506                         "<pre>\nunknown Iterator [%s] (in '%s' line %ld); \n"
1507                         " [%s]\n</pre>", 
1508                         Tokens->Params[0]->Start,
1509                         ChrPtr(Tokens->FileName),
1510                         Tokens->Line,
1511                         ChrPtr(Tokens->FlatToken));
1512                 return;
1513         }
1514
1515         It = (HashIterator*) vIt;
1516
1517         if (Tokens->nParameters < It->AdditionalParams + 2) {
1518                 lprintf(1, "Iterator [%s] (in '%s' line %ld); "
1519                         "doesn't work with %ld params [%s]\n", 
1520                         Tokens->Params[0]->Start,
1521                         ChrPtr(Tokens->FileName),
1522                         Tokens->Line,
1523                         Tokens->nParameters, 
1524                         ChrPtr(Tokens->FlatToken));
1525                 StrBufAppendPrintf(
1526                         Target,
1527                         "<pre>Iterator [%s] \n(in '%s' line %ld);\n"
1528                         "doesn't work with %ld params \n[%s]\n</pre>", 
1529                         Tokens->Params[0]->Start,
1530                         ChrPtr(Tokens->FileName),
1531                         Tokens->Line,
1532                         Tokens->nParameters, 
1533                         ChrPtr(Tokens->FlatToken));
1534                 return;
1535         }
1536
1537         if ((It->XPectContextType != CTX_NONE) &&
1538             (It->XPectContextType != ContextType)) {
1539                 lprintf(1, "Iterator [%s] (in '%s' line %ld); "
1540                         "requires context of type %ld, have %ld [%s]\n", 
1541                         Tokens->pName,
1542                         ChrPtr(Tokens->FileName),
1543                         Tokens->Line,
1544                         It->XPectContextType, 
1545                         ContextType,
1546                         ChrPtr(Tokens->FlatToken));
1547                 StrBufAppendPrintf(
1548                         Target, 
1549                         "<pre>\nIterator [%s] (in '%s' line %ld);"
1550                         " requires context of type %ld, have %ld!\n[%s]\n</pre>\n", 
1551                         Tokens->pName,
1552                         ChrPtr(Tokens->FileName),
1553                         Tokens->Line,
1554                         It->XPectContextType, 
1555                         ContextType,
1556                         ChrPtr(Tokens->FlatToken));
1557                 return ;
1558                 
1559         }
1560
1561         if (It->StaticList == NULL)
1562                 List = It->GetHash(Target, nArgs, Tokens, Context, ContextType);
1563         else
1564                 List = It->StaticList;
1565
1566         nMembersUsed = GetCount(List);
1567         SubBuf = NewStrBuf();
1568         it = GetNewHashPos(List, 0);
1569         while (GetNextHashPos(List, it, &len, &Key, &vContext)) {
1570                 svprintf(HKEY("ITERATE:ODDEVEN"), WCS_STRING, "%s", 
1571                          (oddeven) ? "odd" : "even");
1572                 svprintf(HKEY("ITERATE:KEY"), WCS_STRING, "%s", Key);
1573                 svputlong("ITERATE:N", nMembersCounted);
1574                 svputlong("ITERATE:LASTN", ++nMembersCounted == nMembersUsed);
1575
1576                 if (It->DoSubTemplate != NULL)
1577                         It->DoSubTemplate(SubBuf, vContext, Tokens);
1578                 DoTemplate(Tokens->Params[1]->Start,
1579                            Tokens->Params[1]->len,
1580                            SubBuf, vContext,
1581                            It->ContextType);
1582                         
1583                 StrBufAppendBuf(Target, SubBuf, 0);
1584                 FlushStrBuf(SubBuf);
1585                 oddeven = ~ oddeven;
1586         }
1587         FreeStrBuf(&SubBuf);
1588         DeleteHashPos(&it);
1589         if (It->Destructor != NULL)
1590                 It->Destructor(&List);
1591 }
1592
1593
1594
1595 /*-----------------------------------------------------------------------------
1596  *                      Conditionals
1597  */
1598 int EvaluateConditional(StrBuf *Target, WCTemplateToken *Tokens, WCTemplate *pTmpl, void *Context, int Neg, int state, int ContextType)
1599 {
1600         ConditionalStruct *Cond;
1601
1602         if ((Tokens->Params[0]->len == 1) &&
1603             (Tokens->Params[0]->Start[0] == 'X'))
1604                 return (state != 0)?Tokens->Params[1]->lvalue:0;
1605             
1606         Cond = (ConditionalStruct *) Tokens->PreEval;
1607         if (Cond == NULL) {
1608                 lprintf(1, "Conditional [%s] (in '%s' line %ld); unknown![%s]\n", 
1609                         Tokens->Params[0]->Start,
1610                         ChrPtr(pTmpl->FileName),
1611                         Tokens->Line,
1612                         ChrPtr(Tokens->FlatToken));
1613                 return 1;
1614         }
1615
1616         if (Tokens->nParameters < Cond->nParams) {
1617                 lprintf(1, "Conditional [%s] (in '%s' line %ld); needs %ld Params![%s]\n", 
1618                         Tokens->Params[0]->Start,
1619                         ChrPtr(pTmpl->FileName),
1620                         Tokens->Line,
1621                         Cond->nParams,
1622                         ChrPtr(Tokens->FlatToken));
1623                 StrBufAppendPrintf(
1624                         Target, 
1625                         "<pre>\nConditional [%s] (in '%s' line %ld); needs %ld Params!\n[%s]\n</pre>\n", 
1626                         Tokens->Params[0]->Start,
1627                         ChrPtr(pTmpl->FileName),
1628                         Tokens->Line,
1629                         Cond->nParams,
1630                         ChrPtr(Tokens->FlatToken));
1631                 return 0;
1632         }
1633         if (Cond->CondF(Tokens, Context, ContextType) == Neg)
1634                 return Tokens->Params[1]->lvalue;
1635         return 0;
1636 }
1637
1638 int ConditionalVar(WCTemplateToken *Tokens, void *Context, int ContextType)
1639 {
1640         void *vsubst;
1641         wcsubst *subst;
1642         
1643         if (!GetHash(WC->vars, 
1644                      Tokens->Params[2]->Start,
1645                      Tokens->Params[2]->len,
1646                      &vsubst))
1647                 return 0;
1648         subst = (wcsubst*) vsubst;
1649         if ((subst->ContextRequired != CTX_NONE) &&
1650             (subst->ContextRequired != ContextType)) {
1651                 lprintf(1,"  WARNING: Conditional requires Context: [%ld]!\n", Tokens->Params[2]->Start);
1652                 return -1;
1653         }
1654
1655         switch(subst->wcs_type) {
1656         case WCS_FUNCTION:
1657                 return (subst->wcs_function!=NULL);
1658         case WCS_SERVCMD:
1659                 lprintf(1, "  -> Server [%s]\n", subst->wcs_value);////todo
1660                 return 1;
1661         case WCS_STRING:
1662         case WCS_STRBUF:
1663         case WCS_STRBUF_REF:
1664                 if (Tokens->nParameters < 4)
1665                         return 1;
1666                 return (strcmp(Tokens->Params[3]->Start, ChrPtr(subst->wcs_value)) == 0);
1667         case WCS_LONG:
1668                 if (Tokens->nParameters < 4)
1669                         return (subst->lvalue != 0);
1670                 return (subst->lvalue == Tokens->Params[3]->lvalue);
1671         default:
1672                 lprintf(1,"  WARNING: invalid type: [%ld]!\n", subst->wcs_type);
1673                 return -1;
1674         }
1675         return 0;
1676 }
1677
1678
1679 void RegisterConditional(const char *Name, long len, 
1680                          int nParams,
1681                          WCConditionalFunc CondF, 
1682                          int ContextRequired)
1683 {
1684         ConditionalStruct *Cond = (ConditionalStruct*)malloc(sizeof(ConditionalStruct));
1685         Cond->PlainName = Name;
1686         Cond->nParams = nParams;
1687         Cond->CondF = CondF;
1688         Cond->ContextRequired = ContextRequired;
1689         Put(Conditionals, Name, len, Cond, NULL);
1690 }
1691
1692 /*-----------------------------------------------------------------------------
1693  *                      Context Strings
1694  */
1695 void tmplput_ContextString(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
1696 {
1697         StrBufAppendTemplate(Target, nArgs, Tokens, Context, ContextType, (StrBuf*)Context, 0);
1698 }
1699 int ConditionalContextStr(WCTemplateToken *Tokens, void *Context, int ContextType)
1700 {
1701         StrBuf *TokenText = (StrBuf*) Context;
1702         const char *CompareToken;
1703         long len;
1704
1705         GetTemplateTokenString(Tokens, 2, &CompareToken, &len);
1706         return strcmp(ChrPtr(TokenText), CompareToken) == 0;
1707 }
1708
1709 /*-----------------------------------------------------------------------------
1710  *                      Boxed-API
1711  */
1712
1713 void tmpl_do_boxed(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
1714 {
1715         StrBuf *Headline;
1716         if (nArgs == 2) {
1717                 if (Tokens->Params[1]->Type == TYPE_STR) {
1718                         Headline = NewStrBuf();
1719                         DoTemplate(Tokens->Params[1]->Start, 
1720                                    Tokens->Params[1]->len,
1721                                    Headline, 
1722                                    Context, 
1723                                    ContextType);
1724                 }
1725                 else {
1726                         const char *Ch;
1727                         long len;
1728                         GetTemplateTokenString(Tokens, 
1729                                                1,
1730                                                &Ch,
1731                                                &len);
1732                         Headline = NewStrBufPlain(Ch, len);
1733                 }
1734         }
1735         
1736         DoTemplate(HKEY("beginbox"), Target, Headline, CTX_STRBUF);
1737         DoTemplate(Tokens->Params[0]->Start, 
1738                    Tokens->Params[0]->len,
1739                    Target, 
1740                    Context, 
1741                    ContextType);
1742         DoTemplate(HKEY("endbox"), Target, Context, ContextType);
1743         FreeStrBuf(&Headline);
1744 }
1745
1746 /*-----------------------------------------------------------------------------
1747  *                      Tabbed-API
1748  */
1749
1750 void tmpl_do_tabbed(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
1751 {
1752         StrBuf **TabNames;
1753         int i, ntabs, nTabs;
1754
1755         nTabs = ntabs = Tokens->nParameters / 2;
1756         TabNames = (StrBuf **) malloc(ntabs * sizeof(StrBuf*));
1757
1758         for (i = 0; i < ntabs; i++) {
1759                 TabNames[i] = NewStrBuf();
1760                 if (Tokens->Params[i * 2]->len > 0) {
1761                         DoTemplate(Tokens->Params[i * 2]->Start, 
1762                                    Tokens->Params[i * 2]->len,
1763                                    TabNames[i],
1764                                    Context,
1765                                    ContextType);
1766                 }
1767                 else { 
1768                         /** A Tab without subject? we can't count that, add it as silent */
1769                         nTabs --;
1770                 }
1771         }
1772
1773         StrTabbedDialog(Target, nTabs, TabNames);
1774         for (i = 0; i < ntabs; i++) {
1775                 StrBeginTab(Target, i, nTabs);
1776
1777                 DoTemplate(Tokens->Params[i * 2 + 1]->Start, 
1778                            Tokens->Params[i * 2 + 1]->len,
1779                            Target,
1780                            Context, 
1781                            ContextType);
1782                 StrEndTab(Target, i, nTabs);
1783         }
1784 }
1785
1786
1787 /*-----------------------------------------------------------------------------
1788  *                      Sorting-API
1789  */
1790
1791 typedef struct _SortStruct {
1792         StrBuf *Name;
1793         StrBuf *PrefPrepend;
1794         CompareFunc Forward;
1795         CompareFunc Reverse;
1796
1797         long ContextType;
1798 }SortStruct;
1799
1800 void DestroySortStruct(void *vSort)
1801 {
1802         SortStruct *Sort = (SortStruct*) vSort;
1803         FreeStrBuf(&Sort->Name);
1804         FreeStrBuf(&Sort->PrefPrepend);
1805         free (Sort);
1806 }
1807
1808 void RegisterSortFunc(const char *name, long len, 
1809                       const char *prepend, long preplen,
1810                       CompareFunc Forward, 
1811                       CompareFunc Reverse, 
1812                       long ContextType)
1813 {
1814         SortStruct *NewSort = (SortStruct*) malloc(sizeof(SortStruct));
1815         NewSort->Name = NewStrBufPlain(name, len);
1816         if (prepend != NULL)
1817                 NewSort->PrefPrepend = NewStrBufPlain(prepend, preplen);
1818         else
1819                 NewSort->PrefPrepend = NULL;
1820         NewSort->Forward = Forward;
1821         NewSort->Reverse = Reverse;
1822         NewSort->ContextType = ContextType;
1823         Put(SortHash, name, len, NewSort, DestroySortStruct);
1824 }
1825
1826 CompareFunc RetrieveSort(long ContextType, const char *OtherPrefix, 
1827                          const char *Default, long ldefault, long DefaultDirection)
1828 {
1829         int isdefault = 0;
1830         const StrBuf *BSort;
1831         SortStruct *SortBy;
1832         void *vSortBy;
1833         long SortOrder;
1834         
1835         if (havebstr("SortBy")) {
1836                 BSort = sbstr("SortBy");
1837         }
1838         else { /** Try to fallback to our remembered values... */
1839                 if (OtherPrefix == NULL) {
1840                         BSort = get_room_pref("sort");
1841                 }
1842                 else {
1843                         ////todo: nail prefprepend to sort, and lookup this!
1844                 }
1845         }
1846
1847         if (!GetHash(SortHash, SKEY(BSort), &vSortBy) || 
1848             (vSortBy == NULL)) {
1849                 isdefault = 1;
1850                 if (!GetHash(SortHash, Default, ldefault, &vSortBy) || 
1851                     (vSortBy == NULL)) {
1852                         lprintf(1, "Illegal default sort: [%s]\n", Default);
1853                         wc_backtrace();
1854                 }
1855         }
1856         SortBy = (SortStruct*)vSortBy;
1857
1858         /** Ok, its us, lets see in which direction we should sort... */
1859         if (havebstr("SortOrder")) {
1860                 SortOrder = LBSTR("SortOrder");
1861         }
1862         else { /** Try to fallback to our remembered values... */
1863                 if (SortBy->PrefPrepend == NULL) {
1864                         SortOrder = StrTol(get_room_pref("SortOrder"));
1865                 }
1866                 else {
1867                         ////todo: nail prefprepend to sort, and lookup this!
1868                 }
1869         }
1870         switch (SortOrder) {
1871         default:
1872         case 0:
1873                 return NULL;
1874         case 1:
1875                 return SortBy->Forward;
1876         case 2:
1877                 return SortBy->Reverse;
1878         }
1879 }
1880
1881
1882 enum {
1883         eNO_SUCH_SORT, 
1884         eNOT_SPECIFIED,
1885         eINVALID_PARAM,
1886         eFOUND
1887 };
1888
1889 ConstStr SortIcons[] = {
1890         {HKEY("static/sort_none.gif")},
1891         {HKEY("static/up_pointer.gif")},
1892         {HKEY("static/down_pointer.gif")},
1893 };
1894
1895 ConstStr SortNextOrder[] = {
1896         {HKEY("1")},
1897         {HKEY("2")},
1898         {HKEY("0")},
1899 };
1900
1901
1902 int GetSortMetric(WCTemplateToken *Tokens, SortStruct **Next, SortStruct **Param, long *SortOrder)
1903 {
1904         int bSortError = eNOT_SPECIFIED;
1905         const StrBuf *BSort;
1906         void *vSort;
1907         
1908         *SortOrder = 0;
1909         *Next = NULL;
1910         if (!GetHash(SortHash, Tokens->Params[0]->Start, Tokens->Params[0]->len, &vSort) || 
1911             (vSort == NULL))
1912                 return eNO_SUCH_SORT;
1913         *Param = (SortStruct*) vSort;
1914         
1915
1916         if (havebstr("SortBy")) {
1917                 BSort = sbstr("SortBy");
1918                 bSortError = eINVALID_PARAM;
1919         }
1920         else { /** Try to fallback to our remembered values... */
1921                 if ((*Param)->PrefPrepend == NULL) {
1922                         BSort = get_room_pref("sort");
1923                 }
1924                 else {
1925                         ////todo: nail prefprepend to sort, and lookup this!
1926                 }
1927         }
1928
1929         if (!GetHash(SortHash, SKEY(BSort), &vSort) || 
1930             (vSort == NULL))
1931                 return bSortError;
1932
1933         *Next = (SortStruct*) vSort;
1934
1935         /** Ok, its us, lets see in which direction we should sort... */
1936         if (havebstr("SortOrder")) {
1937                 *SortOrder = LBSTR("SortOrder");
1938         }
1939         else { /** Try to fallback to our remembered values... */
1940                 if ((*Param)->PrefPrepend == NULL) {
1941                         *SortOrder = StrTol(get_room_pref("SortOrder"));
1942                 }
1943                 else {
1944                         ////todo: nail prefprepend to sort, and lookup this!
1945                 }
1946         }
1947         if (*SortOrder > 2)
1948                 *SortOrder = 0;
1949
1950         return eFOUND;
1951 }
1952
1953
1954 void tmplput_SORT_ICON(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
1955 {
1956         long SortOrder;
1957         SortStruct *Next;
1958         SortStruct *Param;
1959         const ConstStr *SortIcon;
1960
1961         switch (GetSortMetric(Tokens, &Next, &Param, &SortOrder)){
1962         case eNO_SUCH_SORT:
1963                 lprintf(1, "[%s] (in '%s' line %ld); "
1964                         " Sorter [%s] unknown! [%s]\n", 
1965                         Tokens->pName,
1966                         ChrPtr(Tokens->FileName),
1967                         Tokens->Line,
1968                         Tokens->Params[0]->Start,
1969                         ChrPtr(Tokens->FlatToken));
1970                 StrBufAppendPrintf(
1971                         Target, 
1972                         "<pre>\n [%s] (in '%s' line %ld);"
1973                         " Sorter [%s] unknown!\n[%s]\n</pre>\n", 
1974                         Tokens->pName,
1975                         ChrPtr(Tokens->FileName),
1976                         Tokens->Line,
1977                         Tokens->Params[0]->Start,
1978                         ChrPtr(Tokens->FlatToken));
1979                 break;          
1980         case eINVALID_PARAM:
1981                 lprintf(1, "[%s] (in '%s' line %ld); "
1982                         " Sorter specified by BSTR 'SortBy' [%s] unknown! [%s]\n", 
1983                         Tokens->pName,
1984                         ChrPtr(Tokens->FileName),
1985                         Tokens->Line,
1986                         bstr("SortBy"),
1987                         ChrPtr(Tokens->FlatToken));
1988         case eNOT_SPECIFIED:
1989         case eFOUND:
1990                 if (Next == Param) {
1991                         SortIcon = &SortIcons[SortOrder];
1992                 }
1993                 else { /** Not Us... */
1994                         SortIcon = &SortIcons[0];
1995                 }
1996                 StrBufAppendBufPlain(Target, SortIcon->Key, SortIcon->len, 0);
1997         }
1998 }
1999
2000 void tmplput_SORT_NEXT(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
2001 {
2002         long SortOrder;
2003         SortStruct *Next;
2004         SortStruct *Param;
2005
2006         switch (GetSortMetric(Tokens, &Next, &Param, &SortOrder)){
2007         case eNO_SUCH_SORT:
2008                 lprintf(1, "[%s] (in '%s' line %ld); "
2009                         " Sorter [%s] unknown! [%s]\n", 
2010                         Tokens->pName,
2011                         ChrPtr(Tokens->FileName),
2012                         Tokens->Line,
2013                         Tokens->Params[0]->Start,
2014                         ChrPtr(Tokens->FlatToken));
2015                 StrBufAppendPrintf(
2016                         Target, 
2017                         "<pre>\n [%s] (in '%s' line %ld);"
2018                         " Sorter [%s] unknown!\n[%s]\n</pre>\n", 
2019                         Tokens->pName,
2020                         ChrPtr(Tokens->FileName),
2021                         Tokens->Line,
2022                         Tokens->Params[0]->Start,
2023                         ChrPtr(Tokens->FlatToken));
2024                 break;          
2025         case eINVALID_PARAM:
2026                 lprintf(1, "[%s] (in '%s' line %ld); "
2027                         " Sorter specified by BSTR 'SortBy' [%s] unknown! [%s]\n", 
2028                         Tokens->pName,
2029                         ChrPtr(Tokens->FileName),
2030                         Tokens->Line,
2031                         bstr("SortBy"),
2032                         ChrPtr(Tokens->FlatToken));
2033
2034         case eNOT_SPECIFIED:
2035         case eFOUND:
2036                 StrBufAppendBuf(Target, Param->Name, 0);
2037                 
2038         }
2039 }
2040
2041 void tmplput_SORT_ORDER(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
2042 {
2043         long SortOrder;
2044         const ConstStr *SortOrderStr;
2045         SortStruct *Next;
2046         SortStruct *Param;
2047
2048         switch (GetSortMetric(Tokens, &Next, &Param, &SortOrder)){
2049         case eNO_SUCH_SORT:
2050                 lprintf(1, "[%s] (in '%s' line %ld); "
2051                         " Sorter [%s] unknown! [%s]\n", 
2052                         Tokens->pName,
2053                         ChrPtr(Tokens->FileName),
2054                         Tokens->Line,
2055                         Tokens->Params[0]->Start,
2056                         ChrPtr(Tokens->FlatToken));
2057                 StrBufAppendPrintf(
2058                         Target, 
2059                         "<pre>\n [%s] (in '%s' line %ld);"
2060                         " Sorter [%s] unknown!\n[%s]\n</pre>\n", 
2061                         Tokens->pName,
2062                         ChrPtr(Tokens->FileName),
2063                         Tokens->Line,
2064                         Tokens->Params[0]->Start,
2065                         ChrPtr(Tokens->FlatToken));
2066                 break;          
2067         case eINVALID_PARAM:
2068                 lprintf(1, "[%s] (in '%s' line %ld); "
2069                         " Sorter specified by BSTR 'SortBy' [%s] unknown! [%s]\n", 
2070                         Tokens->pName,
2071                         ChrPtr(Tokens->FileName),
2072                         Tokens->Line,
2073                         bstr("SortBy"),
2074                         ChrPtr(Tokens->FlatToken));
2075
2076         case eNOT_SPECIFIED:
2077         case eFOUND:
2078                 if (Next == Param) {
2079                         SortOrderStr = &SortNextOrder[SortOrder];
2080                 }
2081                 else { /** Not Us... */
2082                         SortOrderStr = &SortNextOrder[0];
2083                 }
2084                 StrBufAppendBufPlain(Target, SortOrderStr->Key, SortOrderStr->len, 0);
2085         }
2086 }
2087
2088
2089 void tmplput_long_vector(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
2090 {
2091         long *LongVector = (long*) Context;
2092
2093         if ((Tokens->Params[0]->Type == TYPE_LONG) && 
2094             (Tokens->Params[0]->lvalue <= LongVector[0]))
2095         {
2096                 StrBufAppendPrintf(Target, "%ld", LongVector[Tokens->Params[0]->lvalue]);
2097         }
2098         else
2099         {
2100                 if (Tokens->Params[0]->Type == TYPE_LONG) {
2101                         lprintf(1, "longvector [%s] (in '%s' line %ld); needs a long Parameter![%s]\n", 
2102                                 Tokens->Params[0]->Start,
2103                                 ChrPtr(Tokens->FileName),
2104                                 Tokens->Line,
2105                                 ChrPtr(Tokens->FlatToken));
2106                         StrBufAppendPrintf(
2107                                 Target, 
2108                                 "<pre>\nlongvector [%s] (in '%s' line %ld); needs a numerical Parameter!\n[%s]\n</pre>\n", 
2109                                 Tokens->Params[0]->Start,
2110                                 ChrPtr(Tokens->FileName),
2111                                 Tokens->Line,
2112                                 ChrPtr(Tokens->FlatToken));
2113                 }
2114                 else {
2115                         lprintf(1, "longvector [%s] (in '%s' line %ld); doesn't have %ld Parameters,"
2116                                 " its just the size of %ld![%s]\n", 
2117                                 Tokens->Params[0]->Start,
2118                                 ChrPtr(Tokens->FileName),
2119                                 Tokens->Line,
2120                                 Tokens->Params[0]->lvalue,
2121                                 LongVector[0],
2122                                 ChrPtr(Tokens->FlatToken));
2123                         StrBufAppendPrintf(
2124                                 Target, 
2125                                 "<pre>\nlongvector [%s] (in '%s' line %ld); doesn't have %ld Parameters,"
2126                                 " its just the size of %ld!\n[%s]\n</pre>\n", 
2127                                 Tokens->Params[0]->Start,
2128                                 ChrPtr(Tokens->FileName),
2129                                 Tokens->Line,
2130                                 Tokens->Params[0]->lvalue,
2131                                 LongVector[0],
2132                                 ChrPtr(Tokens->FlatToken));             
2133                 }
2134         }
2135 }
2136
2137
2138
2139 int ConditionalLongVector(WCTemplateToken *Tokens, void *Context, int ContextType)
2140 {
2141         long *LongVector = (long*) Context;
2142
2143         if ((Tokens->Params[2]->Type == TYPE_LONG) && 
2144             (Tokens->Params[2]->lvalue <= LongVector[0])&&
2145             (Tokens->Params[3]->Type == TYPE_LONG) && 
2146             (Tokens->Params[3]->lvalue <= LongVector[0]))
2147         {
2148                 return LongVector[Tokens->Params[2]->lvalue] == LongVector[Tokens->Params[3]->lvalue];
2149         }
2150         else
2151         {
2152                 if ((Tokens->Params[2]->Type == TYPE_LONG) ||
2153                     (Tokens->Params[2]->Type == TYPE_LONG)) {
2154                         lprintf(1, "ConditionalLongVector [%s] (in '%s' line %ld); needs two long Parameter![%s]\n", 
2155                                 Tokens->Params[0]->Start,
2156                                 ChrPtr(Tokens->FileName),
2157                                 Tokens->Line,
2158                                 ChrPtr(Tokens->FlatToken));
2159                 }
2160                 else {
2161                         lprintf(1, "longvector [%s] (in '%s' line %ld); doesn't have %ld / %ld Parameters,"
2162                                 " its just the size of %ld![%s]\n", 
2163                                 Tokens->Params[0]->Start,
2164                                 ChrPtr(Tokens->FileName),
2165                                 Tokens->Line,
2166                                 Tokens->Params[2]->lvalue,
2167                                 Tokens->Params[3]->lvalue,
2168                                 LongVector[0],
2169                                 ChrPtr(Tokens->FlatToken));
2170                 }
2171         }
2172         return 0;
2173 }
2174
2175 void 
2176 InitModule_SUBST
2177 (void)
2178 {
2179         RegisterNamespace("SORT:ICON", 1, 1, tmplput_SORT_ICON, CTX_NONE);
2180         RegisterNamespace("SORT:ORDER", 1, 1, tmplput_SORT_ORDER, CTX_NONE);
2181         RegisterNamespace("SORT:NEXT", 1, 1, tmplput_SORT_NEXT, CTX_NONE);
2182         RegisterNamespace("CONTEXTSTR", 0, 1, tmplput_ContextString, CTX_STRBUF);
2183         RegisterNamespace("ITERATE", 2, 100, tmpl_iterate_subtmpl, CTX_NONE);
2184         RegisterNamespace("DOBOXED", 1, 2, tmpl_do_boxed, CTX_NONE);
2185         RegisterNamespace("DOTABBED", 2, 100, tmpl_do_tabbed, CTX_NONE);
2186         RegisterNamespace("LONGVECTOR", 1, 1, tmplput_long_vector, CTX_LONGVECTOR);
2187         RegisterConditional(HKEY("COND:SUBST"), 3, ConditionalVar, CTX_NONE);
2188         RegisterConditional(HKEY("COND:CONTEXTSTR"), 3, ConditionalContextStr, CTX_STRBUF);
2189         RegisterConditional(HKEY("COND:LONGVECTOR"), 4, ConditionalLongVector, CTX_LONGVECTOR);
2190 }
2191
2192 /*@}*/