]> code.citadel.org Git - citadel.git/blob - webcit/subst.c
* add counter and lastn to iterators:
[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->Params[1]->lvalue == 0) {
940                         lprintf(1, "Conditional (in '%s' line %ld); "
941                                 "Conditional ID mustn't be 0! [%s]\n", 
942                                 ChrPtr(pTmpl->FileName),
943                                 NewToken->Line,
944                                 ChrPtr(NewToken->FlatToken));
945                         NewToken->Flags = 0;
946                         break;
947                 }
948                 if (NewToken->nParameters <2) {
949                         lprintf(1, "Conditional (in '%s' line %ld); "
950                                 "require at least 2 parameters, you gave %ld params [%s]\n", 
951                                 ChrPtr(pTmpl->FileName),
952                                 NewToken->Line,
953                                 NewToken->nParameters, 
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         HashHandler *Handler;
1193         void *vVar;
1194 // much output, since pName is not terminated...
1195 //      lprintf(1,"Doing token: %s\n",Token->pName);
1196
1197         switch (Tokens->Flags) {
1198         case SV_GETTEXT:
1199                 TmplGettext(Target, Tokens->nParameters, Tokens);
1200                 break;
1201         case SV_CONDITIONAL: /** Forward conditional evaluation */
1202                 return EvaluateConditional(Target, Tokens, pTmpl, Context, 1, state, ContextType);
1203                 break;
1204         case SV_NEG_CONDITIONAL: /** Reverse conditional evaluation */
1205                 return EvaluateConditional(Target, Tokens, pTmpl, Context, 0, state, ContextType);
1206                 break;
1207         case SV_CUST_STR_CONDITIONAL: /** Conditional put custom strings from params */
1208                 if (Tokens->nParameters >= 6) {
1209                         if (EvaluateConditional(Target, Tokens, pTmpl, Context, 0, state, ContextType))
1210                                 StrBufAppendBufPlain(Target, 
1211                                                      Tokens->Params[5]->Start,
1212                                                      Tokens->Params[5]->len,
1213                                                      0);
1214                         else
1215                                 StrBufAppendBufPlain(Target, 
1216                                                      Tokens->Params[4]->Start,
1217                                                      Tokens->Params[4]->len,
1218                                                      0);
1219                 }
1220                 else  {
1221                         lprintf(1, "Conditional [%s] (in '%s' line %ld); needs at least 6 Params![%s]\n", 
1222                                 Tokens->Params[0]->Start,
1223                                 ChrPtr(pTmpl->FileName),
1224                                 Tokens->Line,
1225                                 ChrPtr(Tokens->FlatToken));
1226                         StrBufAppendPrintf(
1227                                 Target, 
1228                                 "<pre>\nConditional [%s] (in '%s' line %ld); needs 6 Params!\n[%s]\n</pre>\n", 
1229                                 Tokens->Params[0]->Start,
1230                                 ChrPtr(pTmpl->FileName),
1231                                 Tokens->Line,
1232                                 ChrPtr(Tokens->FlatToken));
1233                 }
1234                 break;
1235         case SV_SUBTEMPL:
1236                 if (Tokens->nParameters == 1)
1237                         DoTemplate(Tokens->Params[0]->Start, Tokens->Params[0]->len, NULL, NULL, ContextType);
1238                 break;
1239         case SV_PREEVALUATED:
1240                 Handler = (HashHandler*) Tokens->PreEval;
1241                 if ((Handler->ContextRequired != CTX_NONE) &&
1242                     (Handler->ContextRequired != ContextType)) {
1243                         lprintf(1, "Handler [%s] (in '%s' line %ld); "
1244                                 "requires context of type %ld, have %ld [%s]\n", 
1245                                 Tokens->pName,
1246                                 ChrPtr(pTmpl->FileName),
1247                                 Tokens->Line,
1248                                 Handler->ContextRequired, 
1249                                 ContextType,
1250                                 ChrPtr(Tokens->FlatToken));
1251                         StrBufAppendPrintf(
1252                                 Target, 
1253                                 "<pre>\nHandler [%s] (in '%s' line %ld);"
1254                                 " requires context of type %ld, have %ld!\n[%s]\n</pre>\n", 
1255                                 Tokens->pName,
1256                                 ChrPtr(pTmpl->FileName),
1257                                 Tokens->Line,
1258                                 Handler->ContextRequired, 
1259                                 ContextType,
1260                                 ChrPtr(Tokens->FlatToken));
1261                         return -1;
1262
1263                 }
1264                 Handler->HandlerFunc(Target, 
1265                                      Tokens->nParameters,
1266                                      Tokens,
1267                                      Context, 
1268                                      ContextType); 
1269                 break;          
1270         default:
1271                 if (GetHash(GlobalNS, Tokens->pName, Tokens->NameEnd, &vVar)) {
1272                         Handler = (HashHandler*) vVar;
1273                         if ((Handler->ContextRequired != CTX_NONE) &&
1274                             (Handler->ContextRequired != ContextType)) {
1275                                 lprintf(1, "Handler [%s] (in '%s' line %ld); "
1276                                         "requires context of type %ld, have %ld [%s]\n", 
1277                                         Tokens->pName,
1278                                         ChrPtr(pTmpl->FileName),
1279                                         Tokens->Line,
1280                                         Handler->ContextRequired, 
1281                                         ContextType,
1282                                         ChrPtr(Tokens->FlatToken));
1283                                 StrBufAppendPrintf(
1284                                         Target, 
1285                                         "<pre>\nHandler [%s] (in '%s' line %ld);"
1286                                         " requires context of type %ld, have %ld!\n[%s]\n</pre>\n", 
1287                                         Tokens->pName,
1288                                         ChrPtr(pTmpl->FileName),
1289                                         Tokens->Line,
1290                                         Handler->ContextRequired, 
1291                                         ContextType,
1292                                         ChrPtr(Tokens->FlatToken));
1293                                 return -1;
1294                         }
1295                         else if ((Tokens->nParameters < Handler->nMinArgs) || 
1296                                  (Tokens->nParameters > Handler->nMaxArgs)) {
1297                                 lprintf(1, "Handler [%s] (in '%s' line %ld); "
1298                                         "doesn't work with %ld params [%s]\n", 
1299                                         Tokens->pName,
1300                                         ChrPtr(pTmpl->FileName),
1301                                         Tokens->Line,
1302                                         Tokens->nParameters, 
1303                                         ChrPtr(Tokens->FlatToken));
1304                                 StrBufAppendPrintf(
1305                                         Target, 
1306                                         "<pre>\nHandler [%s] (in '%s' line %ld);"
1307                                         " doesn't work with %ld params!\n[%s]\n</pre>\n", 
1308                                         Tokens->pName,
1309                                         ChrPtr(pTmpl->FileName),
1310                                         Tokens->Line,
1311                                         Tokens->nParameters,
1312                                         ChrPtr(Tokens->FlatToken));
1313                         }
1314                         else {
1315                                 Handler->HandlerFunc(Target, 
1316                                                      Tokens->nParameters,
1317                                                      Tokens,
1318                                                      Context, 
1319                                                      ContextType); /*TODO: subset of that */
1320                                 
1321                         }
1322                 }
1323                 else {
1324                         print_value_of(Target, Tokens, Context, ContextType);
1325                 }
1326         }
1327         return 0;
1328 }
1329
1330
1331
1332 void ProcessTemplate(WCTemplate *Tmpl, StrBuf *Target, void *Context, int ContextType)
1333 {
1334         WCTemplate *pTmpl = Tmpl;
1335         int done = 0;
1336         int i, state;
1337         const char *pData, *pS;
1338         long len;
1339
1340         if (LoadTemplates != 0) {                       
1341                 if (LoadTemplates > 1)
1342                         lprintf(1, "DBG: ----- loading:  [%s] ------ \n", 
1343                                 ChrPtr(Tmpl->FileName));
1344
1345                 pTmpl = load_template(Tmpl->FileName, NULL, NULL);
1346                 if(pTmpl == NULL) {
1347                         StrBufAppendPrintf(
1348                                 Target, 
1349                                 "<pre>\nError loading Template [%s]\n See Logfile for details\n</pre>\n", 
1350                                 ChrPtr(Tmpl->FileName));
1351                         return;
1352                 }
1353
1354         }
1355
1356         pS = pData = ChrPtr(pTmpl->Data);
1357         len = StrLength(pTmpl->Data);
1358         i = 0;
1359         state = 0;
1360         while (!done) {
1361                 if (i >= pTmpl->nTokensUsed) {
1362                         StrBufAppendBufPlain(Target, 
1363                                              pData, 
1364                                              len - (pData - pS), 0);
1365                         done = 1;
1366                 }
1367                 else {
1368                         StrBufAppendBufPlain(
1369                                 Target, pData, 
1370                                 pTmpl->Tokens[i]->pTokenStart - pData, 0);
1371                         state = EvaluateToken(Target, pTmpl->Tokens[i], pTmpl, Context, state, ContextType);
1372                         while ((state != 0) && (i+1 < pTmpl->nTokensUsed)) {
1373                         /* condition told us to skip till its end condition */
1374                                 i++;
1375                                 if ((pTmpl->Tokens[i]->Flags == SV_CONDITIONAL) ||
1376                                     (pTmpl->Tokens[i]->Flags == SV_NEG_CONDITIONAL)) {
1377                                         if (state == EvaluateConditional(
1378                                                     Target,
1379                                                     pTmpl->Tokens[i], 
1380                                                     pTmpl,
1381                                                     Context, 
1382                                                     pTmpl->Tokens[i]->Flags,
1383                                                     state, 
1384                                                     ContextType))
1385                                                 state = 0;
1386                                 }
1387                         }
1388                         pData = pTmpl->Tokens[i++]->pTokenEnd + 1;
1389                         if (i > pTmpl->nTokensUsed)
1390                                 done = 1;
1391                 }
1392         }
1393         if (LoadTemplates != 0) {
1394                 FreeWCTemplate(pTmpl);
1395         }
1396 }
1397
1398 /**
1399  * \brief Display a variable-substituted template
1400  * \param templatename template file to load
1401  */
1402 void DoTemplate(const char *templatename, long len, StrBuf *Target, void *Context, int ContextType) 
1403 {
1404         HashList *Static;
1405         HashList *StaticLocal;
1406         void *vTmpl;
1407         
1408         if (Target == NULL)
1409                 Target = WC->WBuf;
1410         if (WC->is_mobile) {
1411                 Static = WirelessTemplateCache;
1412                 StaticLocal = WirelessLocalTemplateCache;
1413         }
1414         else {
1415                 Static = TemplateCache;
1416                 StaticLocal = LocalTemplateCache;
1417         }
1418
1419         if (len == 0)
1420         {
1421                 lprintf (1, "Can't to load a template with empty name!\n");
1422                 StrBufAppendPrintf(Target, "<pre>\nCan't to load a template with empty name!\n</pre>");
1423                 return;
1424         }
1425
1426         if (!GetHash(StaticLocal, templatename, len, &vTmpl) &&
1427             !GetHash(Static, templatename, len, &vTmpl)) {
1428                 lprintf (1, "didn't find Template [%s] %ld %ld\n", templatename, len , (long)strlen(templatename));
1429                 StrBufAppendPrintf(Target, "<pre>\ndidn't find Template [%s] %ld %ld\n</pre>", 
1430                                    templatename, len, 
1431                                    (long)strlen(templatename));
1432 ///             dbg_PrintHash(Static, PrintTemplate, NULL);
1433 //              PrintHash(Static, VarPrintTransition, PrintTemplate);
1434                 return;
1435         }
1436         if (vTmpl == NULL) 
1437                 return;
1438         ProcessTemplate(vTmpl, Target, Context, ContextType);
1439 }
1440
1441 /*-----------------------------------------------------------------------------
1442  *                      Iterators
1443  */
1444 typedef struct _HashIterator {
1445         HashList *StaticList;
1446         int AdditionalParams;
1447         int ContextType;
1448         int XPectContextType;
1449         RetrieveHashlistFunc GetHash;
1450         HashDestructorFunc Destructor;
1451         SubTemplFunc DoSubTemplate;
1452 } HashIterator;
1453
1454 void RegisterITERATOR(const char *Name, long len, 
1455                       int AdditionalParams, 
1456                       HashList *StaticList, 
1457                       RetrieveHashlistFunc GetHash, 
1458                       SubTemplFunc DoSubTempl,
1459                       HashDestructorFunc Destructor,
1460                       int ContextType, 
1461                       int XPectContextType)
1462 {
1463         HashIterator *It = (HashIterator*)malloc(sizeof(HashIterator));
1464         It->StaticList = StaticList;
1465         It->AdditionalParams = AdditionalParams;
1466         It->GetHash = GetHash;
1467         It->DoSubTemplate = DoSubTempl;
1468         It->Destructor = Destructor;
1469         It->ContextType = ContextType;
1470         It->XPectContextType = XPectContextType;
1471         Put(Iterators, Name, len, It, NULL);
1472 }
1473
1474 void tmpl_iterate_subtmpl(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
1475 {
1476         void *vIt;
1477         HashIterator *It;
1478         HashList *List;
1479         HashPos  *it;
1480         int nMembersUsed;
1481         int nMembersCounted = 0;
1482         long len; 
1483         const char *Key;
1484         void *vContext;
1485         StrBuf *SubBuf;
1486         int oddeven = 0;
1487         
1488         if (!GetHash(Iterators, 
1489                      Tokens->Params[0]->Start,
1490                      Tokens->Params[0]->len,
1491                      &vIt)) {
1492                 lprintf(1, "unknown Iterator [%s] (in '%s' line %ld); "
1493                         " [%s]\n", 
1494                         Tokens->Params[0]->Start,
1495                         ChrPtr(Tokens->FileName),
1496                         Tokens->Line,
1497                         ChrPtr(Tokens->FlatToken));
1498                 StrBufAppendPrintf(
1499                         Target,
1500                         "<pre>\nunknown Iterator [%s] (in '%s' line %ld); \n"
1501                         " [%s]\n</pre>", 
1502                         Tokens->Params[0]->Start,
1503                         ChrPtr(Tokens->FileName),
1504                         Tokens->Line,
1505                         ChrPtr(Tokens->FlatToken));
1506                 return;
1507         }
1508
1509         It = (HashIterator*) vIt;
1510
1511         if (Tokens->nParameters < It->AdditionalParams + 2) {
1512                 lprintf(1, "Iterator [%s] (in '%s' line %ld); "
1513                         "doesn't work with %ld params [%s]\n", 
1514                         Tokens->Params[0]->Start,
1515                         ChrPtr(Tokens->FileName),
1516                         Tokens->Line,
1517                         Tokens->nParameters, 
1518                         ChrPtr(Tokens->FlatToken));
1519                 StrBufAppendPrintf(
1520                         Target,
1521                         "<pre>Iterator [%s] \n(in '%s' line %ld);\n"
1522                         "doesn't work with %ld params \n[%s]\n</pre>", 
1523                         Tokens->Params[0]->Start,
1524                         ChrPtr(Tokens->FileName),
1525                         Tokens->Line,
1526                         Tokens->nParameters, 
1527                         ChrPtr(Tokens->FlatToken));
1528                 return;
1529         }
1530
1531         if ((It->XPectContextType != CTX_NONE) &&
1532             (It->XPectContextType != ContextType)) {
1533                 lprintf(1, "Iterator [%s] (in '%s' line %ld); "
1534                         "requires context of type %ld, have %ld [%s]\n", 
1535                         Tokens->pName,
1536                         ChrPtr(Tokens->FileName),
1537                         Tokens->Line,
1538                         It->XPectContextType, 
1539                         ContextType,
1540                         ChrPtr(Tokens->FlatToken));
1541                 StrBufAppendPrintf(
1542                         Target, 
1543                         "<pre>\nIterator [%s] (in '%s' line %ld);"
1544                         " requires context of type %ld, have %ld!\n[%s]\n</pre>\n", 
1545                         Tokens->pName,
1546                         ChrPtr(Tokens->FileName),
1547                         Tokens->Line,
1548                         It->XPectContextType, 
1549                         ContextType,
1550                         ChrPtr(Tokens->FlatToken));
1551                 return ;
1552                 
1553         }
1554
1555         if (It->StaticList == NULL)
1556                 List = It->GetHash(Target, nArgs, Tokens, Context, ContextType);
1557         else
1558                 List = It->StaticList;
1559
1560         nMembersUsed = GetCount(List);
1561         SubBuf = NewStrBuf();
1562         it = GetNewHashPos(List, 0);
1563         while (GetNextHashPos(List, it, &len, &Key, &vContext)) {
1564                 svprintf(HKEY("ITERATE:ODDEVEN"), WCS_STRING, "%s", 
1565                          (oddeven) ? "odd" : "even");
1566                 svprintf(HKEY("ITERATE:KEY"), WCS_STRING, "%s", Key);
1567                 svputlong("ITERATE:N", nMembersCounted);
1568                 svputlong("ITERATE:LASTN", ++nMembersCounted == nMembersUsed);
1569
1570                 if (It->DoSubTemplate != NULL)
1571                         It->DoSubTemplate(SubBuf, vContext, Tokens);
1572                 DoTemplate(Tokens->Params[1]->Start,
1573                            Tokens->Params[1]->len,
1574                            SubBuf, vContext,
1575                            It->ContextType);
1576                         
1577                 StrBufAppendBuf(Target, SubBuf, 0);
1578                 FlushStrBuf(SubBuf);
1579                 oddeven = ~ oddeven;
1580         }
1581         FreeStrBuf(&SubBuf);
1582         DeleteHashPos(&it);
1583         if (It->Destructor != NULL)
1584                 It->Destructor(&List);
1585 }
1586
1587
1588
1589 /*-----------------------------------------------------------------------------
1590  *                      Conditionals
1591  */
1592 int EvaluateConditional(StrBuf *Target, WCTemplateToken *Tokens, WCTemplate *pTmpl, void *Context, int Neg, int state, int ContextType)
1593 {
1594         ConditionalStruct *Cond;
1595
1596         if ((Tokens->Params[0]->len == 1) &&
1597             (Tokens->Params[0]->Start[0] == 'X'))
1598                 return (state != 0)?Tokens->Params[1]->lvalue:0;
1599             
1600         Cond = (ConditionalStruct *) Tokens->PreEval;
1601         if (Cond == NULL) {
1602                 lprintf(1, "Conditional [%s] (in '%s' line %ld); unknown![%s]\n", 
1603                         Tokens->Params[0]->Start,
1604                         ChrPtr(pTmpl->FileName),
1605                         Tokens->Line,
1606                         ChrPtr(Tokens->FlatToken));
1607                 return 1;
1608         }
1609
1610         if (Tokens->nParameters < Cond->nParams) {
1611                 lprintf(1, "Conditional [%s] (in '%s' line %ld); needs %ld Params![%s]\n", 
1612                         Tokens->Params[0]->Start,
1613                         ChrPtr(pTmpl->FileName),
1614                         Tokens->Line,
1615                         Cond->nParams,
1616                         ChrPtr(Tokens->FlatToken));
1617                 StrBufAppendPrintf(
1618                         Target, 
1619                         "<pre>\nConditional [%s] (in '%s' line %ld); needs %ld Params!\n[%s]\n</pre>\n", 
1620                         Tokens->Params[0]->Start,
1621                         ChrPtr(pTmpl->FileName),
1622                         Tokens->Line,
1623                         Cond->nParams,
1624                         ChrPtr(Tokens->FlatToken));
1625                 return 0;
1626         }
1627         if (Cond->CondF(Tokens, Context, ContextType) == Neg)
1628                 return Tokens->Params[1]->lvalue;
1629         return 0;
1630 }
1631
1632 int ConditionalVar(WCTemplateToken *Tokens, void *Context, int ContextType)
1633 {
1634         void *vsubst;
1635         wcsubst *subst;
1636         
1637         if (!GetHash(WC->vars, 
1638                      Tokens->Params[2]->Start,
1639                      Tokens->Params[2]->len,
1640                      &vsubst))
1641                 return 0;
1642         subst = (wcsubst*) vsubst;
1643         if ((subst->ContextRequired != CTX_NONE) &&
1644             (subst->ContextRequired != ContextType)) {
1645                 lprintf(1,"  WARNING: Conditional requires Context: [%ld]!\n", Tokens->Params[2]->Start);
1646                 return -1;
1647         }
1648
1649         switch(subst->wcs_type) {
1650         case WCS_FUNCTION:
1651                 return (subst->wcs_function!=NULL);
1652         case WCS_SERVCMD:
1653                 lprintf(1, "  -> Server [%s]\n", subst->wcs_value);////todo
1654                 return 1;
1655         case WCS_STRING:
1656         case WCS_STRBUF:
1657         case WCS_STRBUF_REF:
1658                 if (Tokens->nParameters < 4)
1659                         return 1;
1660                 return (strcmp(Tokens->Params[3]->Start, ChrPtr(subst->wcs_value)) == 0);
1661         case WCS_LONG:
1662                 if (Tokens->nParameters < 4)
1663                         return (subst->lvalue != 0);
1664                 return (subst->lvalue == Tokens->Params[3]->lvalue);
1665         default:
1666                 lprintf(1,"  WARNING: invalid type: [%ld]!\n", subst->wcs_type);
1667                 return -1;
1668         }
1669         return 0;
1670 }
1671
1672
1673 void RegisterConditional(const char *Name, long len, 
1674                          int nParams,
1675                          WCConditionalFunc CondF, 
1676                          int ContextRequired)
1677 {
1678         ConditionalStruct *Cond = (ConditionalStruct*)malloc(sizeof(ConditionalStruct));
1679         Cond->PlainName = Name;
1680         Cond->nParams = nParams;
1681         Cond->CondF = CondF;
1682         Cond->ContextRequired = ContextRequired;
1683         Put(Conditionals, Name, len, Cond, NULL);
1684 }
1685
1686 /*-----------------------------------------------------------------------------
1687  *                      Context Strings
1688  */
1689 void tmplput_ContextString(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
1690 {
1691         StrBufAppendTemplate(Target, nArgs, Tokens, Context, ContextType, (StrBuf*)Context, 0);
1692 }
1693 int ConditionalContextStr(WCTemplateToken *Tokens, void *Context, int ContextType)
1694 {
1695         StrBuf *TokenText = (StrBuf*) Context;
1696         const char *CompareToken;
1697         long len;
1698
1699         GetTemplateTokenString(Tokens, 2, &CompareToken, &len);
1700         return strcmp(ChrPtr(TokenText), CompareToken) == 0;
1701 }
1702
1703 /*-----------------------------------------------------------------------------
1704  *                      Boxed-API
1705  */
1706
1707 void tmpl_do_boxed(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
1708 {
1709         StrBuf *Headline;
1710         if (nArgs == 2) {
1711                 if (Tokens->Params[1]->Type == TYPE_STR) {
1712                         Headline = NewStrBuf();
1713                         DoTemplate(Tokens->Params[1]->Start, 
1714                                    Tokens->Params[1]->len,
1715                                    Headline, 
1716                                    Context, 
1717                                    ContextType);
1718                 }
1719                 else {
1720                         const char *Ch;
1721                         long len;
1722                         GetTemplateTokenString(Tokens, 
1723                                                1,
1724                                                &Ch,
1725                                                &len);
1726                         Headline = NewStrBufPlain(Ch, len);
1727                 }
1728         }
1729         
1730         DoTemplate(HKEY("beginbox"), Target, Headline, CTX_STRBUF);
1731         DoTemplate(Tokens->Params[0]->Start, 
1732                    Tokens->Params[0]->len,
1733                    Target, 
1734                    Context, 
1735                    ContextType);
1736         DoTemplate(HKEY("endbox"), Target, Context, ContextType);
1737         FreeStrBuf(&Headline);
1738 }
1739
1740 /*-----------------------------------------------------------------------------
1741  *                      Tabbed-API
1742  */
1743
1744 void tmpl_do_tabbed(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
1745 {
1746         StrBuf **TabNames;
1747         int i, ntabs, nTabs;
1748
1749         nTabs = ntabs = Tokens->nParameters / 2;
1750         TabNames = (StrBuf **) malloc(ntabs * sizeof(StrBuf*));
1751
1752         for (i = 0; i < ntabs; i++) {
1753                 TabNames[i] = NewStrBuf();
1754                 if (Tokens->Params[i * 2]->len > 0) {
1755                         DoTemplate(Tokens->Params[i * 2]->Start, 
1756                                    Tokens->Params[i * 2]->len,
1757                                    TabNames[i],
1758                                    Context,
1759                                    ContextType);
1760                 }
1761                 else { 
1762                         /** A Tab without subject? we can't count that, add it as silent */
1763                         nTabs --;
1764                 }
1765         }
1766
1767         StrTabbedDialog(Target, nTabs, TabNames);
1768         for (i = 0; i < ntabs; i++) {
1769                 StrBeginTab(Target, i, nTabs);
1770
1771                 DoTemplate(Tokens->Params[i * 2 + 1]->Start, 
1772                            Tokens->Params[i * 2 + 1]->len,
1773                            Target,
1774                            Context, 
1775                            ContextType);
1776                 StrEndTab(Target, i, nTabs);
1777         }
1778 }
1779
1780
1781 /*-----------------------------------------------------------------------------
1782  *                      Sorting-API
1783  */
1784
1785 typedef struct _SortStruct {
1786         StrBuf *Name;
1787         StrBuf *PrefPrepend;
1788         CompareFunc Forward;
1789         CompareFunc Reverse;
1790
1791         long ContextType;
1792 }SortStruct;
1793
1794 void DestroySortStruct(void *vSort)
1795 {
1796         SortStruct *Sort = (SortStruct*) vSort;
1797         FreeStrBuf(&Sort->Name);
1798         FreeStrBuf(&Sort->PrefPrepend);
1799         free (Sort);
1800 }
1801
1802 void RegisterSortFunc(const char *name, long len, 
1803                       const char *prepend, long preplen,
1804                       CompareFunc Forward, 
1805                       CompareFunc Reverse, 
1806                       long ContextType)
1807 {
1808         SortStruct *NewSort = (SortStruct*) malloc(sizeof(SortStruct));
1809         NewSort->Name = NewStrBufPlain(name, len);
1810         if (prepend != NULL)
1811                 NewSort->PrefPrepend = NewStrBufPlain(prepend, preplen);
1812         else
1813                 NewSort->PrefPrepend = NULL;
1814         NewSort->Forward = Forward;
1815         NewSort->Reverse = Reverse;
1816         NewSort->ContextType = ContextType;
1817         Put(SortHash, name, len, NewSort, DestroySortStruct);
1818 }
1819
1820 CompareFunc RetrieveSort(long ContextType, const char *OtherPrefix, 
1821                          const char *Default, long ldefault, long DefaultDirection)
1822 {
1823         int isdefault = 0;
1824         const StrBuf *BSort;
1825         SortStruct *SortBy;
1826         void *vSortBy;
1827         long SortOrder;
1828         
1829         if (havebstr("SortBy")) {
1830                 BSort = sbstr("SortBy");
1831         }
1832         else { /** Try to fallback to our remembered values... */
1833                 if (OtherPrefix == NULL) {
1834                         BSort = get_room_pref("sort");
1835                 }
1836                 else {
1837                         ////todo: nail prefprepend to sort, and lookup this!
1838                 }
1839         }
1840
1841         if (!GetHash(SortHash, SKEY(BSort), &vSortBy) || 
1842             (vSortBy == NULL)) {
1843                 isdefault = 1;
1844                 if (!GetHash(SortHash, Default, ldefault, &vSortBy) || 
1845                     (vSortBy == NULL)) {
1846                         lprintf(1, "Illegal default sort: [%s]\n", Default);
1847                         wc_backtrace();
1848                 }
1849         }
1850         SortBy = (SortStruct*)vSortBy;
1851
1852         /** Ok, its us, lets see in which direction we should sort... */
1853         if (havebstr("SortOrder")) {
1854                 SortOrder = LBSTR("SortOrder");
1855         }
1856         else { /** Try to fallback to our remembered values... */
1857                 if (SortBy->PrefPrepend == NULL) {
1858                         SortOrder = StrTol(get_room_pref("SortOrder"));
1859                 }
1860                 else {
1861                         ////todo: nail prefprepend to sort, and lookup this!
1862                 }
1863         }
1864         switch (SortOrder) {
1865         default:
1866         case 0:
1867                 return NULL;
1868         case 1:
1869                 return SortBy->Forward;
1870         case 2:
1871                 return SortBy->Reverse;
1872         }
1873 }
1874
1875
1876 enum {
1877         eNO_SUCH_SORT, 
1878         eNOT_SPECIFIED,
1879         eINVALID_PARAM,
1880         eFOUND
1881 };
1882
1883 ConstStr SortIcons[] = {
1884         {HKEY("static/sort_none.gif")},
1885         {HKEY("static/up_pointer.gif")},
1886         {HKEY("static/down_pointer.gif")},
1887 };
1888
1889 ConstStr SortNextOrder[] = {
1890         {HKEY("1")},
1891         {HKEY("2")},
1892         {HKEY("0")},
1893 };
1894
1895
1896 int GetSortMetric(WCTemplateToken *Tokens, SortStruct **Next, SortStruct **Param, long *SortOrder)
1897 {
1898         int bSortError = eNOT_SPECIFIED;
1899         const StrBuf *BSort;
1900         void *vSort;
1901         
1902         *SortOrder = 0;
1903         *Next = NULL;
1904         if (!GetHash(SortHash, Tokens->Params[0]->Start, Tokens->Params[0]->len, &vSort) || 
1905             (vSort == NULL))
1906                 return eNO_SUCH_SORT;
1907         *Param = (SortStruct*) vSort;
1908         
1909
1910         if (havebstr("SortBy")) {
1911                 BSort = sbstr("SortBy");
1912                 bSortError = eINVALID_PARAM;
1913         }
1914         else { /** Try to fallback to our remembered values... */
1915                 if ((*Param)->PrefPrepend == NULL) {
1916                         BSort = get_room_pref("sort");
1917                 }
1918                 else {
1919                         ////todo: nail prefprepend to sort, and lookup this!
1920                 }
1921         }
1922
1923         if (!GetHash(SortHash, SKEY(BSort), &vSort) || 
1924             (vSort == NULL))
1925                 return bSortError;
1926
1927         *Next = (SortStruct*) vSort;
1928
1929         /** Ok, its us, lets see in which direction we should sort... */
1930         if (havebstr("SortOrder")) {
1931                 *SortOrder = LBSTR("SortOrder");
1932         }
1933         else { /** Try to fallback to our remembered values... */
1934                 if ((*Param)->PrefPrepend == NULL) {
1935                         *SortOrder = StrTol(get_room_pref("SortOrder"));
1936                 }
1937                 else {
1938                         ////todo: nail prefprepend to sort, and lookup this!
1939                 }
1940         }
1941         if (*SortOrder > 2)
1942                 *SortOrder = 0;
1943
1944         return eFOUND;
1945 }
1946
1947
1948 void tmplput_SORT_ICON(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
1949 {
1950         long SortOrder;
1951         SortStruct *Next;
1952         SortStruct *Param;
1953         const ConstStr *SortIcon;
1954
1955         switch (GetSortMetric(Tokens, &Next, &Param, &SortOrder)){
1956         case eNO_SUCH_SORT:
1957                 lprintf(1, "[%s] (in '%s' line %ld); "
1958                         " Sorter [%s] unknown! [%s]\n", 
1959                         Tokens->pName,
1960                         ChrPtr(Tokens->FileName),
1961                         Tokens->Line,
1962                         Tokens->Params[0]->Start,
1963                         ChrPtr(Tokens->FlatToken));
1964                 StrBufAppendPrintf(
1965                         Target, 
1966                         "<pre>\n [%s] (in '%s' line %ld);"
1967                         " Sorter [%s] unknown!\n[%s]\n</pre>\n", 
1968                         Tokens->pName,
1969                         ChrPtr(Tokens->FileName),
1970                         Tokens->Line,
1971                         Tokens->Params[0]->Start,
1972                         ChrPtr(Tokens->FlatToken));
1973                 break;          
1974         case eINVALID_PARAM:
1975                 lprintf(1, "[%s] (in '%s' line %ld); "
1976                         " Sorter specified by BSTR 'SortBy' [%s] unknown! [%s]\n", 
1977                         Tokens->pName,
1978                         ChrPtr(Tokens->FileName),
1979                         Tokens->Line,
1980                         bstr("SortBy"),
1981                         ChrPtr(Tokens->FlatToken));
1982         case eNOT_SPECIFIED:
1983         case eFOUND:
1984                 if (Next == Param) {
1985                         SortIcon = &SortIcons[SortOrder];
1986                 }
1987                 else { /** Not Us... */
1988                         SortIcon = &SortIcons[0];
1989                 }
1990                 StrBufAppendBufPlain(Target, SortIcon->Key, SortIcon->len, 0);
1991         }
1992 }
1993
1994 void tmplput_SORT_NEXT(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
1995 {
1996         long SortOrder;
1997         SortStruct *Next;
1998         SortStruct *Param;
1999
2000         switch (GetSortMetric(Tokens, &Next, &Param, &SortOrder)){
2001         case eNO_SUCH_SORT:
2002                 lprintf(1, "[%s] (in '%s' line %ld); "
2003                         " Sorter [%s] unknown! [%s]\n", 
2004                         Tokens->pName,
2005                         ChrPtr(Tokens->FileName),
2006                         Tokens->Line,
2007                         Tokens->Params[0]->Start,
2008                         ChrPtr(Tokens->FlatToken));
2009                 StrBufAppendPrintf(
2010                         Target, 
2011                         "<pre>\n [%s] (in '%s' line %ld);"
2012                         " Sorter [%s] unknown!\n[%s]\n</pre>\n", 
2013                         Tokens->pName,
2014                         ChrPtr(Tokens->FileName),
2015                         Tokens->Line,
2016                         Tokens->Params[0]->Start,
2017                         ChrPtr(Tokens->FlatToken));
2018                 break;          
2019         case eINVALID_PARAM:
2020                 lprintf(1, "[%s] (in '%s' line %ld); "
2021                         " Sorter specified by BSTR 'SortBy' [%s] unknown! [%s]\n", 
2022                         Tokens->pName,
2023                         ChrPtr(Tokens->FileName),
2024                         Tokens->Line,
2025                         bstr("SortBy"),
2026                         ChrPtr(Tokens->FlatToken));
2027
2028         case eNOT_SPECIFIED:
2029         case eFOUND:
2030                 StrBufAppendBuf(Target, Param->Name, 0);
2031                 
2032         }
2033 }
2034
2035 void tmplput_SORT_ORDER(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
2036 {
2037         long SortOrder;
2038         const ConstStr *SortOrderStr;
2039         SortStruct *Next;
2040         SortStruct *Param;
2041
2042         switch (GetSortMetric(Tokens, &Next, &Param, &SortOrder)){
2043         case eNO_SUCH_SORT:
2044                 lprintf(1, "[%s] (in '%s' line %ld); "
2045                         " Sorter [%s] unknown! [%s]\n", 
2046                         Tokens->pName,
2047                         ChrPtr(Tokens->FileName),
2048                         Tokens->Line,
2049                         Tokens->Params[0]->Start,
2050                         ChrPtr(Tokens->FlatToken));
2051                 StrBufAppendPrintf(
2052                         Target, 
2053                         "<pre>\n [%s] (in '%s' line %ld);"
2054                         " Sorter [%s] unknown!\n[%s]\n</pre>\n", 
2055                         Tokens->pName,
2056                         ChrPtr(Tokens->FileName),
2057                         Tokens->Line,
2058                         Tokens->Params[0]->Start,
2059                         ChrPtr(Tokens->FlatToken));
2060                 break;          
2061         case eINVALID_PARAM:
2062                 lprintf(1, "[%s] (in '%s' line %ld); "
2063                         " Sorter specified by BSTR 'SortBy' [%s] unknown! [%s]\n", 
2064                         Tokens->pName,
2065                         ChrPtr(Tokens->FileName),
2066                         Tokens->Line,
2067                         bstr("SortBy"),
2068                         ChrPtr(Tokens->FlatToken));
2069
2070         case eNOT_SPECIFIED:
2071         case eFOUND:
2072                 if (Next == Param) {
2073                         SortOrderStr = &SortNextOrder[SortOrder];
2074                 }
2075                 else { /** Not Us... */
2076                         SortOrderStr = &SortNextOrder[0];
2077                 }
2078                 StrBufAppendBufPlain(Target, SortOrderStr->Key, SortOrderStr->len, 0);
2079         }
2080 }
2081
2082
2083 void tmplput_long_vector(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
2084 {
2085         long *LongVector = (long*) Context;
2086
2087         if ((Tokens->Params[0]->Type == TYPE_LONG) && 
2088             (Tokens->Params[0]->lvalue <= LongVector[0]))
2089         {
2090                 StrBufAppendPrintf(Target, "%ld", LongVector[Tokens->Params[0]->lvalue]);
2091         }
2092         else
2093         {
2094                 if (Tokens->Params[0]->Type == TYPE_LONG) {
2095                         lprintf(1, "longvector [%s] (in '%s' line %ld); needs a long Parameter![%s]\n", 
2096                                 Tokens->Params[0]->Start,
2097                                 ChrPtr(Tokens->FileName),
2098                                 Tokens->Line,
2099                                 ChrPtr(Tokens->FlatToken));
2100                         StrBufAppendPrintf(
2101                                 Target, 
2102                                 "<pre>\nlongvector [%s] (in '%s' line %ld); needs a numerical Parameter!\n[%s]\n</pre>\n", 
2103                                 Tokens->Params[0]->Start,
2104                                 ChrPtr(Tokens->FileName),
2105                                 Tokens->Line,
2106                                 ChrPtr(Tokens->FlatToken));
2107                 }
2108                 else {
2109                         lprintf(1, "longvector [%s] (in '%s' line %ld); doesn't have %ld Parameters,"
2110                                 " its just the size of %ld![%s]\n", 
2111                                 Tokens->Params[0]->Start,
2112                                 ChrPtr(Tokens->FileName),
2113                                 Tokens->Line,
2114                                 Tokens->Params[0]->lvalue,
2115                                 LongVector[0],
2116                                 ChrPtr(Tokens->FlatToken));
2117                         StrBufAppendPrintf(
2118                                 Target, 
2119                                 "<pre>\nlongvector [%s] (in '%s' line %ld); doesn't have %ld Parameters,"
2120                                 " its just the size of %ld!\n[%s]\n</pre>\n", 
2121                                 Tokens->Params[0]->Start,
2122                                 ChrPtr(Tokens->FileName),
2123                                 Tokens->Line,
2124                                 Tokens->Params[0]->lvalue,
2125                                 LongVector[0],
2126                                 ChrPtr(Tokens->FlatToken));             
2127                 }
2128         }
2129 }
2130
2131
2132
2133 int ConditionalLongVector(WCTemplateToken *Tokens, void *Context, int ContextType)
2134 {
2135         long *LongVector = (long*) Context;
2136
2137         if ((Tokens->Params[2]->Type == TYPE_LONG) && 
2138             (Tokens->Params[2]->lvalue <= LongVector[0])&&
2139             (Tokens->Params[3]->Type == TYPE_LONG) && 
2140             (Tokens->Params[3]->lvalue <= LongVector[0]))
2141         {
2142                 return LongVector[Tokens->Params[2]->lvalue] == LongVector[Tokens->Params[3]->lvalue];
2143         }
2144         else
2145         {
2146                 if ((Tokens->Params[2]->Type == TYPE_LONG) ||
2147                     (Tokens->Params[2]->Type == TYPE_LONG)) {
2148                         lprintf(1, "ConditionalLongVector [%s] (in '%s' line %ld); needs two long Parameter![%s]\n", 
2149                                 Tokens->Params[0]->Start,
2150                                 ChrPtr(Tokens->FileName),
2151                                 Tokens->Line,
2152                                 ChrPtr(Tokens->FlatToken));
2153                 }
2154                 else {
2155                         lprintf(1, "longvector [%s] (in '%s' line %ld); doesn't have %ld / %ld Parameters,"
2156                                 " its just the size of %ld![%s]\n", 
2157                                 Tokens->Params[0]->Start,
2158                                 ChrPtr(Tokens->FileName),
2159                                 Tokens->Line,
2160                                 Tokens->Params[2]->lvalue,
2161                                 Tokens->Params[3]->lvalue,
2162                                 LongVector[0],
2163                                 ChrPtr(Tokens->FlatToken));
2164                 }
2165         }
2166         return 0;
2167 }
2168
2169 void 
2170 InitModule_SUBST
2171 (void)
2172 {
2173         RegisterNamespace("SORT:ICON", 1, 1, tmplput_SORT_ICON, CTX_NONE);
2174         RegisterNamespace("SORT:ORDER", 1, 1, tmplput_SORT_ORDER, CTX_NONE);
2175         RegisterNamespace("SORT:NEXT", 1, 1, tmplput_SORT_NEXT, CTX_NONE);
2176         RegisterNamespace("CONTEXTSTR", 0, 1, tmplput_ContextString, CTX_STRBUF);
2177         RegisterNamespace("ITERATE", 2, 100, tmpl_iterate_subtmpl, CTX_NONE);
2178         RegisterNamespace("DOBOXED", 1, 2, tmpl_do_boxed, CTX_NONE);
2179         RegisterNamespace("DOTABBED", 2, 100, tmpl_do_tabbed, CTX_NONE);
2180         RegisterNamespace("LONGVECTOR", 1, 1, tmplput_long_vector, CTX_LONGVECTOR);
2181         RegisterConditional(HKEY("COND:SUBST"), 3, ConditionalVar, CTX_NONE);
2182         RegisterConditional(HKEY("COND:CONTEXTSTR"), 3, ConditionalContextStr, CTX_STRBUF);
2183         RegisterConditional(HKEY("COND:LONGVECTOR"), 4, ConditionalLongVector, CTX_LONGVECTOR);
2184 }
2185
2186 /*@}*/