Remove $Id$ tags from most of webcit
[citadel.git] / webcit / subst.c
1 #include "sysdep.h"
2
3
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <dirent.h>
7 #include <errno.h>
8
9 #include <unistd.h>
10 #include <stdio.h>
11 #include <stdarg.h>
12 #include <stddef.h>
13
14 #define SHOW_ME_VAPPEND_PRINTF
15
16 #include "webcit.h"
17 #include "webserver.h"
18
19 extern char *static_dirs[PATH_MAX];  /* Disk representation */
20
21 HashList *WirelessTemplateCache;
22 HashList *WirelessLocalTemplateCache;
23 HashList *TemplateCache;
24 HashList *LocalTemplateCache;
25
26 HashList *GlobalNS;
27 HashList *Iterators;
28 HashList *Conditionals;
29 HashList *SortHash;
30 HashList *Defines;
31
32 int DumpTemplateI18NStrings = 0;
33 int LoadTemplates = 0;
34 int dbg_backtrace_template_errors = 0;
35 WCTemplputParams NoCtx;
36 StrBuf *I18nDump = NULL;
37
38 const char EmptyStr[]="";
39
40 #define SV_GETTEXT 1
41 #define SV_CONDITIONAL 2
42 #define SV_NEG_CONDITIONAL 3
43 #define SV_CUST_STR_CONDITIONAL 4
44 #define SV_SUBTEMPL 5
45 #define SV_PREEVALUATED 6
46
47
48 /*
49  * Dynamic content for variable substitution in templates
50  */
51 typedef struct _wcsubst {
52         ContextFilter Filter;
53         int wcs_type;                           /* which type of Substitution are we */
54         char wcs_key[32];                       /* copy of our hashkey for debugging */
55         StrBuf *wcs_value;                      /* if we're a string, keep it here */
56         long lvalue;                            /* type long? keep data here */
57         WCHandlerFunc wcs_function;             /* funcion hook ???*/
58 } wcsubst;
59
60
61 typedef struct _WCTemplate {
62         StrBuf *Data;
63         StrBuf *FileName;
64         int nTokensUsed;
65         int TokenSpace;
66         StrBuf *MimeType;
67         WCTemplateToken **Tokens;
68 } WCTemplate;
69
70 typedef struct _HashHandler {
71         ContextFilter Filter;
72         WCPreevalFunc PreEvalFunc;
73         WCHandlerFunc HandlerFunc;
74 }HashHandler;
75
76 void *load_template(WCTemplate *NewTemplate);
77 int EvaluateConditional(StrBuf *Target, int Neg, int state, WCTemplputParams *TP);
78
79
80
81 typedef struct _SortStruct {
82         StrBuf *Name;
83         StrBuf *PrefPrepend;
84         CompareFunc Forward;
85         CompareFunc Reverse;
86         CompareFunc GroupChange;
87
88         long ContextType;
89 }SortStruct;
90
91 const char *CtxNames[]  = {
92         "Context NONE",
93         "Context SITECFG",
94         "Context SESSION",
95         "Context INETCFG",
96         "Context VNOTE",
97         "Context WHO",
98         "Context PREF",
99         "Context NODECONF",
100         "Context USERLIST",
101         "Context MAILSUM",
102         "Context MIME_ATACH",
103         "Context FILELIST",
104         "Context STRBUF",
105         "Context STRBUFARR",
106         "Context LONGVECTOR",
107         "Context ROOMS",
108         "Context FLOORS",
109         "Context ITERATE",
110         "Context ICAL",
111         "Context DavNamespace",
112         "Context TAB",
113         "Context UNKNOWN"
114 };
115
116
117
118 void DestroySortStruct(void *vSort)
119 {
120         SortStruct *Sort = (SortStruct*) vSort;
121         FreeStrBuf(&Sort->Name);
122         FreeStrBuf(&Sort->PrefPrepend);
123         free (Sort);
124 }
125
126 const char *ContextName(int ContextType)
127 {
128         if (ContextType < CTX_UNKNOWN)
129                 return CtxNames[ContextType];
130         else
131                 return CtxNames[CTX_UNKNOWN];
132 }
133
134 void LogTemplateError (StrBuf *Target, const char *Type, int ErrorPos, WCTemplputParams *TP, const char *Format, ...)
135 {
136         wcsession *WCC;
137         StrBuf *Error;
138         StrBuf *Info;
139         va_list arg_ptr;
140         const char *Err = NULL;
141
142         Info = NewStrBuf();
143         Error = NewStrBuf();
144
145         va_start(arg_ptr, Format);
146         StrBufVAppendPrintf(Error, Format, arg_ptr);
147         va_end(arg_ptr);
148
149         switch (ErrorPos) {
150         case ERR_NAME: /* the main token name... */ 
151                 Err = (TP->Tokens!= NULL)? TP->Tokens->pName:"";
152                 break;
153         default:
154                 Err = ((TP->Tokens!= NULL) && 
155                        (TP->Tokens->nParameters > ErrorPos - 1))? 
156                         TP->Tokens->Params[ErrorPos - 1]->Start : "";
157                 break;
158         }
159         if (TP->Tokens != NULL) 
160         {
161                 lprintf(1, "%s [%s]  (in '%s' line %ld); %s; [%s]\n", 
162                         Type, 
163                         Err, 
164                         ChrPtr(TP->Tokens->FileName),
165                         TP->Tokens->Line, 
166                         ChrPtr(Error), 
167                         ChrPtr(TP->Tokens->FlatToken));
168         }
169         else 
170         {
171                 lprintf(1, "%s: %s;\n", 
172                         Type, 
173                         ChrPtr(Error));
174         }
175 /*
176         if (Target == NULL) 
177                 return;
178 */
179         WCC = WC;
180         if (WCC == NULL) {
181                 FreeStrBuf(&Info);
182                 FreeStrBuf(&Error);
183                 return; 
184         }
185
186         if (WCC->WFBuf == NULL) WCC->WFBuf = NewStrBuf();
187         if (TP->Tokens != NULL) 
188         {
189                 /* deprecated: 
190                 StrBufAppendPrintf(                                                          
191                         Target,                                                              
192                         "<pre>\n%s [%s] (in '%s' line %ld); %s\n[%s]\n</pre>\n",
193                         Type, 
194                         Err, 
195                         ChrPtr(TP->Tokens->FileName),
196                         TP->Tokens->Line,
197                         ChrPtr(Error),
198                         ChrPtr(TP->Tokens->FlatToken));
199                 */
200                 StrBufPrintf(Info, "%s [%s]  %s; [%s]", 
201                              Type, 
202                              Err, 
203                              ChrPtr(Error), 
204                              ChrPtr(TP->Tokens->FlatToken));
205
206
207                 SerializeJson(WCC->WFBuf, WildFireException(SKEY(TP->Tokens->FileName),
208                                                         TP->Tokens->Line,
209                                                         Info,
210                                                         1), 1);
211 /*
212                 SerializeJson(Header, WildFireMessage(SKEY(TP->Tokens->FileName),
213                                                       TP->Tokens->Line,
214                                                       Error,
215                                                       eERROR), 1);
216 */
217                 
218         }
219         else
220         {
221                 /* deprecated.
222                 StrBufAppendPrintf(                                                          
223                         Target,                                                              
224                         "<pre>\n%s: %s\n</pre>\n",
225                         Type, 
226                         ChrPtr(Error));
227                 */
228                 StrBufPrintf(Info, "%s [%s]  %s; [%s]", 
229                              Type, 
230                              Err, 
231                              ChrPtr(Error), 
232                              ChrPtr(TP->Tokens->FlatToken));
233                 SerializeJson(WCC->WFBuf, WildFireException(HKEY(__FILE__), __LINE__, Info, 1), 1);
234         }
235         FreeStrBuf(&Info);
236         FreeStrBuf(&Error);
237 /*
238         if (dbg_backtrace_template_errors)
239                 wc_backtrace(); 
240 */
241 }
242
243
244
245
246 void LogError (StrBuf *Target, const char *Type, const char *Format, ...)
247 {
248         wcsession *WCC;
249         StrBuf *Error;
250         StrBuf *Info;
251         va_list arg_ptr;
252
253         Info = NewStrBuf();
254         Error = NewStrBuf();
255
256         va_start(arg_ptr, Format);
257         StrBufVAppendPrintf(Error, Format, arg_ptr);
258         va_end(arg_ptr);
259
260         lprintf(1, ChrPtr(Error));
261
262         WCC = WC;
263         if (WCC->WFBuf == NULL) WCC->WFBuf = NewStrBuf();
264
265         SerializeJson(WCC->WFBuf, WildFireException(Type, strlen(Type),
266                                                     0,
267                                                     Info,
268                                                     1), 1);
269
270         FreeStrBuf(&Info);
271         FreeStrBuf(&Error);
272 /*
273         if (dbg_backtrace_template_errors)
274                 wc_backtrace(); 
275 */
276 }
277
278
279 void RegisterNS(const char *NSName, 
280                 long len, 
281                 int nMinArgs, 
282                 int nMaxArgs, 
283                 WCHandlerFunc HandlerFunc, 
284                 WCPreevalFunc PreevalFunc,
285                 int ContextRequired)
286 {
287         HashHandler *NewHandler;
288         
289         NewHandler = (HashHandler*) malloc(sizeof(HashHandler));
290         memset(NewHandler, 0, sizeof(HashHandler));
291         NewHandler->Filter.nMinArgs = nMinArgs;
292         NewHandler->Filter.nMaxArgs = nMaxArgs;
293         NewHandler->Filter.ContextType = ContextRequired;
294         NewHandler->Filter.ControlContextType = CTX_NONE;
295
296         NewHandler->PreEvalFunc = PreevalFunc;
297         NewHandler->HandlerFunc = HandlerFunc;  
298         Put(GlobalNS, NSName, len, NewHandler, NULL);
299 }
300
301 void RegisterControlNS(const char *NSName, 
302                        long len, 
303                        int nMinArgs, 
304                        int nMaxArgs, 
305                        WCHandlerFunc HandlerFunc, 
306                        int ControlContextRequired)
307 {
308         HashHandler *NewHandler;
309         
310         NewHandler = (HashHandler*) malloc(sizeof(HashHandler));
311         memset(NewHandler, 0, sizeof(HashHandler));
312         NewHandler->Filter.nMinArgs = nMinArgs;
313         NewHandler->Filter.nMaxArgs = nMaxArgs;
314         NewHandler->Filter.ContextType = CTX_NONE;
315         NewHandler->Filter.ControlContextType = ControlContextRequired;
316         NewHandler->HandlerFunc = HandlerFunc;  
317         Put(GlobalNS, NSName, len, NewHandler, NULL);
318 }
319
320
321
322 int CheckContext(StrBuf *Target, ContextFilter *Need, WCTemplputParams *TP, const char *ErrType)
323 {
324         if ((Need->ContextType != CTX_NONE) && 
325             (Need->ContextType != TP->Filter.ContextType)) {
326                 LogTemplateError(
327                         Target, ErrType, ERR_PARM1, TP,
328                         "  WARNING: requires Context: [%s], have [%s]!", 
329                         ContextName(Need->ContextType), 
330                         ContextName(TP->Filter.ContextType));
331                 return 0;
332         }
333
334         if ((Need->ControlContextType != CTX_NONE) && 
335             (Need->ControlContextType != TP->Filter.ControlContextType)) {
336                 LogTemplateError(
337                         Target, ErrType, ERR_PARM1, TP,
338                         "  WARNING: requires Control Context: [%s], have [%s]!", 
339                         ContextName(Need->ControlContextType), 
340                         ContextName(TP->Filter.ControlContextType));
341                 return 0;
342         }
343 /*                      
344         if (TP->Tokens->nParameters < Need->nMinArgs) {
345                 LogTemplateError(Target, ErrType, ERR_NAME, TP,
346                                  "needs at least %ld params, have %ld", 
347                                  Need->nMinArgs, 
348                                  TP->Tokens->nParameters);
349                 return 0;
350
351         }
352         else if (TP->Tokens->nParameters > Need->nMaxArgs) {
353                 LogTemplateError(Target, ErrType, ERR_NAME, TP,
354                                  "just needs %ld params, you gave %ld",
355                                  Need->nMaxArgs,
356                                  TP->Tokens->nParameters); 
357                 return 0;
358
359         }
360 */
361         return 1;
362 }
363
364 void FreeToken(WCTemplateToken **Token)
365 {
366         int i; 
367         FreeStrBuf(&(*Token)->FlatToken);
368         if ((*Token)->HaveParameters) 
369                 for (i = 0; i < (*Token)->nParameters; i++)
370                         free((*Token)->Params[i]);
371         free(*Token);
372         *Token = NULL;
373 }
374
375
376
377 void FreeWCTemplate(void *vFreeMe)
378 {
379         int i;
380         WCTemplate *FreeMe = (WCTemplate*)vFreeMe;
381
382         if (FreeMe->TokenSpace > 0) {
383                 for (i = 0; i < FreeMe->nTokensUsed; i ++) {
384                         FreeToken(&FreeMe->Tokens[i]);
385                 }
386                 free(FreeMe->Tokens);
387         }
388         FreeStrBuf(&FreeMe->FileName);
389         FreeStrBuf(&FreeMe->Data);
390         FreeStrBuf(&FreeMe->MimeType);
391         free(FreeMe);
392 }
393
394
395
396 /**
397  * \brief back end for print_value_of() ... does a server command
398  * \param servcmd server command to execute on the citadel server
399  */
400 void pvo_do_cmd(StrBuf *Target, StrBuf *servcmd) {
401         char buf[SIZ];
402         int len;
403
404         serv_puts(ChrPtr(servcmd));
405         len = serv_getln(buf, sizeof buf);
406
407         switch(buf[0]) {
408                 case '2':
409                 case '3':
410                 case '5':
411                         StrBufAppendPrintf(Target, "%s\n", &buf[4]);
412                         break;
413                 case '1':
414                         _fmout(Target, "CENTER");
415                         break;
416                 case '4':
417                         StrBufAppendPrintf(Target, "%s\n", &buf[4]);
418                         serv_puts("000");
419                         break;
420         }
421 }
422
423 int HaveTemplateTokenString(StrBuf *Target, 
424                             WCTemplputParams *TP,
425                             int N,
426                             const char **Value, 
427                             long *len)
428 {
429         if (N >= TP->Tokens->nParameters) {
430                 return 0;
431         }
432
433         switch (TP->Tokens->Params[N]->Type) {
434         case TYPE_INTDEFINE:
435         case TYPE_STR:
436         case TYPE_BSTR:
437         case TYPE_PREFSTR:
438         case TYPE_GETTEXT:
439         case TYPE_SUBTEMPLATE:
440                 return 1;
441         case TYPE_LONG:
442         case TYPE_PREFINT:
443         default:
444                 return 0;
445         }
446 }
447
448 void GetTemplateTokenString(StrBuf *Target, 
449                             WCTemplputParams *TP,
450                             int N,
451                             const char **Value, 
452                             long *len)
453 {
454         StrBuf *Buf;
455         WCTemplputParams SubTP;
456
457         if (N >= TP->Tokens->nParameters) {
458                 LogTemplateError(Target, 
459                                  "TokenParameter", N, TP, 
460                                  "invalid token %d. this shouldn't have come till here.\n", N);
461                 *Value = "";
462                 *len = 0;
463                 return;
464         }
465
466         switch (TP->Tokens->Params[N]->Type) {
467
468         case TYPE_INTDEFINE:
469         case TYPE_STR:
470                 *Value = TP->Tokens->Params[N]->Start;
471                 *len = TP->Tokens->Params[N]->len;
472                 break;
473         case TYPE_BSTR:
474                 if (TP->Tokens->Params[N]->len == 0) {
475                         LogTemplateError(Target, 
476                                          "TokenParameter", N, TP, 
477                                          "Requesting parameter %d; of type BSTR, empty lookup string not admitted.", N);
478                         *len = 0;
479                         *Value = EmptyStr;
480                         break;
481                 }
482                 Buf = (StrBuf*) SBstr(TKEY(N));
483                 *Value = ChrPtr(Buf);
484                 *len = StrLength(Buf);
485                 break;
486         case TYPE_PREFSTR:
487                 if (TP->Tokens->Params[N]->len == 0) {
488                         LogTemplateError(Target, 
489                                          "TokenParameter", N, TP, 
490                                          "Requesting parameter %d; of type PREFSTR, empty lookup string not admitted.", N);
491                         *len = 0;
492                         *Value = EmptyStr;
493                         break;
494                 }
495                 get_PREFERENCE(TKEY(N), &Buf);
496                 *Value = ChrPtr(Buf);
497                 *len = StrLength(Buf);
498                 break;
499         case TYPE_LONG:
500                 LogTemplateError(Target, 
501                                  "TokenParameter", N, TP, 
502                                  "Requesting parameter %d; of type LONG, want string.", N);
503                 break;
504         case TYPE_PREFINT:
505                 LogTemplateError(Target, 
506                                  "TokenParameter", N, TP, 
507                                  "Requesting parameter %d; of type PREFINT, want string.", N);
508                 break;
509         case TYPE_GETTEXT:
510                 *Value = _(TP->Tokens->Params[N]->Start);
511                 *len = strlen(*Value);
512                 break;
513         case TYPE_SUBTEMPLATE:
514                 if (TP->Tokens->Params[N]->len == 0) {
515                         LogTemplateError(Target, 
516                                          "TokenParameter", N, TP, 
517                                          "Requesting parameter %d; of type SUBTEMPLATE, empty lookup string not admitted.", N);
518                         *len = 0;
519                         *Value = EmptyStr;
520                         break;
521                 }
522
523                 memset(&SubTP, 0, sizeof(WCTemplputParams *));
524                 SubTP.Context = TP->Context;
525                 SubTP.Filter.ContextType = TP->Filter.ContextType;
526                 Buf = NewStrBuf();
527                 DoTemplate(TKEY(N), Buf, &SubTP);
528                 *Value = ChrPtr(Buf);
529                 *len = StrLength(Buf);
530                 /* we can't free it here, so we put it into the subst so its discarded later on. */
531                 ///SVPUTBuf(TKEY(N), Buf, 0);
532                 break;
533
534         default:
535                 LogTemplateError(Target, 
536                                  "TokenParameter", N, TP, 
537                                  "unknown param type %d; [%d]", N, TP->Tokens->Params[N]->Type);
538                 break;
539         }
540 }
541
542 long GetTemplateTokenNumber(StrBuf *Target, WCTemplputParams *TP, int N, long dflt)
543 {
544         long Ret;
545         if (N >= TP->Tokens->nParameters) {
546                 LogTemplateError(Target, 
547                                  "TokenParameter", N, TP, 
548                                  "invalid token %d. this shouldn't have come till here.\n", N);
549                 wc_backtrace(); 
550                 return 0;
551         }
552
553         switch (TP->Tokens->Params[N]->Type) {
554
555         case TYPE_STR:
556                 return atol(TP->Tokens->Params[N]->Start);
557                 break;
558         case TYPE_BSTR:
559                 if (TP->Tokens->Params[N]->len == 0) {
560                         LogTemplateError(Target, 
561                                          "TokenParameter", N, TP, 
562                                          "Requesting parameter %d; of type BSTR, empty lookup string not admitted.", N);
563                         return 0;
564                 }
565                 return  LBstr(TKEY(N));
566                 break;
567         case TYPE_PREFSTR:
568                 LogTemplateError(Target, 
569                                  "TokenParameter", N, TP, 
570                                  "requesting a prefstring in param %d want a number", N);
571                 if (TP->Tokens->Params[N]->len == 0) {
572                         LogTemplateError(Target, 
573                                          "TokenParameter", N, TP, 
574                                          "Requesting parameter %d; of type PREFSTR, empty lookup string not admitted.", N);
575                         return 0;
576                 }
577                 if (get_PREF_LONG(TKEY(N), &Ret, dflt))
578                         return Ret;
579                 return 0;
580         case TYPE_INTDEFINE:
581         case TYPE_LONG:
582                 return TP->Tokens->Params[N]->lvalue;
583         case TYPE_PREFINT:
584                 if (TP->Tokens->Params[N]->len == 0) {
585                         LogTemplateError(Target, 
586                                          "TokenParameter", N, TP, 
587                                          "Requesting parameter %d; of type PREFINT, empty lookup string not admitted.", N);
588                         return 0;
589                 }
590                 if (get_PREF_LONG(TKEY(N), &Ret, dflt))
591                         return Ret;
592                 return 0;               
593         case TYPE_GETTEXT:
594                 LogTemplateError(Target, 
595                                  "TokenParameter", N, TP, 
596                                  "requesting a I18N string in param %d; want a number", N);
597                 return 0;
598         case TYPE_SUBTEMPLATE:
599                 LogTemplateError(Target, 
600                                  "TokenParameter", N, TP, 
601                                  "requesting a subtemplate in param %d; not supported for numbers", N);
602                 return 0;
603         default:
604                 LogTemplateError(Target, 
605                                  "TokenParameter", N, TP, 
606                                  "unknown param type %d; [%d]", N, TP->Tokens->Params[N]->Type);
607                 return 0;
608         }
609 }
610
611
612 /**
613  * \brief puts string into the template and computes which escape methon we should use
614  * \param Source the string we should put into the template
615  * \param FormatTypeIndex where should we look for escape types if?
616  */
617 void StrBufAppendTemplate(StrBuf *Target, 
618                           WCTemplputParams *TP,
619                           const StrBuf *Source, int FormatTypeIndex)
620 {
621         wcsession *WCC;
622         char EscapeAs = ' ';
623
624         if ((FormatTypeIndex < TP->Tokens->nParameters) &&
625             (TP->Tokens->Params[FormatTypeIndex]->Type == TYPE_STR) &&
626             (TP->Tokens->Params[FormatTypeIndex]->len == 1)) {
627                 EscapeAs = *TP->Tokens->Params[FormatTypeIndex]->Start;
628         }
629
630         switch(EscapeAs)
631         {
632         case 'H':
633                 WCC = WC;
634                 StrEscAppend(Target, Source, NULL, 0, 2);
635                 break;
636         case 'X':
637                 StrEscAppend(Target, Source, NULL, 0, 0);
638                 break;
639         case 'J':
640                 StrECMAEscAppend(Target, Source, NULL);
641           break;
642         case 'K':
643                 StrHtmlEcmaEscAppend(Target, Source, NULL, 0, 0);
644           break;
645         case 'U':
646                 StrBufUrlescAppend(Target, Source, NULL);
647                 break;
648         default:
649                 StrBufAppendBuf(Target, Source, 0);
650         }
651 }
652
653
654 void PutNewToken(WCTemplate *Template, WCTemplateToken *NewToken)
655 {
656         if (Template->nTokensUsed + 1 >= Template->TokenSpace) {
657                 if (Template->TokenSpace <= 0) {
658                         Template->Tokens = (WCTemplateToken**)malloc(
659                                 sizeof(WCTemplateToken*) * 10);
660                         memset(Template->Tokens, 0, sizeof(WCTemplateToken*) * 10);
661                         Template->TokenSpace = 10;
662                 }
663                 else {
664                         WCTemplateToken **NewTokens;
665
666                         NewTokens= (WCTemplateToken**) malloc(
667                                 sizeof(WCTemplateToken*) * Template->TokenSpace * 2);
668
669                         memset(NewTokens, 
670                                0, sizeof(WCTemplateToken*) * Template->TokenSpace * 2);
671
672                         memcpy(NewTokens, 
673                                Template->Tokens, 
674                                sizeof(WCTemplateToken*) * Template->nTokensUsed);
675
676                         free(Template->Tokens);
677                         Template->TokenSpace *= 2;
678                         Template->Tokens = NewTokens;
679                 }
680         }
681         Template->Tokens[(Template->nTokensUsed)++] = NewToken;
682 }
683
684 int GetNextParameter(StrBuf *Buf, 
685                      const char **pCh, 
686                      const char *pe, 
687                      WCTemplateToken *Tokens, 
688                      WCTemplate *pTmpl, 
689                      WCTemplputParams *TP, 
690                      TemplateParam **pParm)
691 {
692         const char *pch = *pCh;
693         const char *pchs, *pche;
694         TemplateParam *Parm;
695         char quote = '\0';
696         int ParamBrace = 0;
697
698         *pParm = Parm = (TemplateParam *) malloc(sizeof(TemplateParam));
699         memset(Parm, 0, sizeof(TemplateParam));
700         Parm->Type = TYPE_STR;
701
702         /* Skip leading whitespaces */
703         while ((*pch == ' ' )||
704                (*pch == '\t')||
705                (*pch == '\r')||
706                (*pch == '\n')) pch ++;
707
708         if (*pch == ':') {
709                 Parm->Type = TYPE_PREFSTR;
710                 pch ++;
711                 if (*pch == '(') {
712                         pch ++;
713                         ParamBrace = 1;
714                 }
715         }
716         else if (*pch == ';') {
717                 Parm->Type = TYPE_PREFINT;
718                 pch ++;
719                 if (*pch == '(') {
720                         pch ++;
721                         ParamBrace = 1;
722                 }
723         }
724         else if (*pch == '#') {
725                 Parm->Type = TYPE_INTDEFINE;
726                 pch ++;
727         }
728         else if (*pch == '_') {
729                 Parm->Type = TYPE_GETTEXT;
730                 pch ++;
731                 if (*pch == '(') {
732                         pch ++;
733                         ParamBrace = 1;
734                 }
735         }
736         else if (*pch == 'B') {
737                 Parm->Type = TYPE_BSTR;
738                 pch ++;
739                 if (*pch == '(') {
740                         pch ++;
741                         ParamBrace = 1;
742                 }
743         }
744         else if (*pch == '=') {
745                 Parm->Type = TYPE_SUBTEMPLATE;
746                 pch ++;
747                 if (*pch == '(') {
748                         pch ++;
749                         ParamBrace = 1;
750                 }
751         }
752
753
754         if (*pch == '"')
755                 quote = '"';
756         else if (*pch == '\'')
757                 quote = '\'';
758         if (quote != '\0') {
759                 pch ++;
760                 pchs = pch;
761                 while (pch <= pe &&
762                        ((*pch != quote) ||
763                         ( (pch > pchs) && (*(pch - 1) == '\\'))
764                                )) {
765                         pch ++;
766                 }
767                 pche = pch;
768                 if (*pch != quote) {
769                         lprintf(1, "Error (in '%s' line %ld); "
770                                 "evaluating template param [%s] in Token [%s]\n",
771                                 ChrPtr(pTmpl->FileName),
772                                 Tokens->Line,
773                                 ChrPtr(Tokens->FlatToken),
774                                 *pCh);
775                         pch ++;
776                         free(Parm);
777                         *pParm = NULL;
778                         return 0;
779                 }
780                 else {
781                         StrBufPeek(Buf, pch, -1, '\0');         
782                         if (LoadTemplates > 1) {                        
783                                 lprintf(1, "DBG: got param [%s] %ld %ld\n", 
784                                         pchs, pche - pchs, strlen(pchs));
785                         }
786                         Parm->Start = pchs;
787                         Parm->len = pche - pchs;
788                         pch ++; /* move after trailing quote */
789                         if (ParamBrace && (*pch == ')')) {
790                                 pch ++;
791                         }
792
793                 }
794         }
795         else {
796                 Parm->Type = TYPE_LONG;
797                 pchs = pch;
798                 while ((pch <= pe) &&
799                        (isdigit(*pch) ||
800                         (*pch == '+') ||
801                         (*pch == '-')))
802                         pch ++;
803                 pch ++;
804                 if (pch - pchs > 1){
805                         StrBufPeek(Buf, pch, -1, '\0');
806                         Parm->lvalue = atol(pchs);
807                         Parm->Start = pchs;
808                         pch++;
809                 }
810                 else {
811                         Parm->lvalue = 0;
812 /* TODO whUT?
813                         lprintf(1, "Error (in '%s' line %ld); "
814                                 "evaluating long template param [%s] in Token [%s]\n",
815                                 ChrPtr(pTmpl->FileName),
816                                 Tokens->Line,
817                                 ChrPtr(Tokens->FlatToken),
818                                 *pCh);
819                                 */
820                         free(Parm);
821                         *pParm = NULL;
822                         return 0;
823                 }
824         }
825         while ((*pch == ' ' )||
826                (*pch == '\t')||
827                (*pch == '\r')||
828                (*pch == ',' )||
829                (*pch == '\n')) pch ++;
830
831         switch (Parm->Type)
832         {
833         case TYPE_GETTEXT:
834                 if (DumpTemplateI18NStrings) {
835                         StrBufAppendPrintf(I18nDump, "_(\"%s\");\n", Parm->Start);
836                 }
837                 break;
838         case TYPE_INTDEFINE: {
839                 void *vPVal;
840                 
841                 if (GetHash(Defines, Parm->Start, Parm->len, &vPVal) &&
842                     (vPVal != NULL))
843                 {
844                         long *PVal;
845                         PVal = (long*) vPVal;
846                 
847                         Parm->lvalue = *PVal;
848                 }
849                 else if (strchr(Parm->Start, '|') != NULL)
850                 {
851                         const char *Pos;
852                         StrBuf *pToken;
853                         StrBuf *Match;
854
855                         Parm->MaskBy = eOR;
856                         pToken = NewStrBufPlain (Parm->Start, Parm->len);
857                         Match = NewStrBufPlain (NULL, Parm->len);
858                         Pos = ChrPtr(pToken);
859                         
860                         while ((Pos != NULL) && (Pos != StrBufNOTNULL))
861                         {
862                                 StrBufExtract_NextToken(Match, pToken, &Pos, '|');
863                                 StrBufTrim(Match);
864                                 if (StrLength (Match) > 0)
865                                 {
866                                         if (GetHash(Defines, SKEY(Match), &vPVal) &&
867                                             (vPVal != NULL))
868                                         {
869                                                 long *PVal;
870                                                 PVal = (long*) vPVal;
871                                                 
872                                                 Parm->lvalue |= *PVal;
873                                         }
874                                         else {
875                                                 LogTemplateError(NULL, "Define", 
876                                                                  Tokens->nParameters,
877                                                                  TP,
878                                                                  "%s isn't known!!",
879                                                                  ChrPtr(Match));
880
881                                         }
882                                 }
883                         }
884                 }
885                 else if (strchr(Parm->Start, '&') != NULL)
886                 {
887                         const char *Pos;
888                         StrBuf *pToken;
889                         StrBuf *Match;
890
891                         Parm->MaskBy = eAND;
892                         pToken = NewStrBufPlain (Parm->Start, Parm->len);
893                         Match = NewStrBufPlain (NULL, Parm->len);
894                         Pos = ChrPtr(pToken);
895                         
896                         while ((Pos != NULL) && (Pos != StrBufNOTNULL))
897                         {
898                                 StrBufExtract_NextToken(Match, pToken, &Pos, '&');
899                                 StrBufTrim(Match);
900                                 if (StrLength (Match) > 0)
901                                 {
902                                         if (GetHash(Defines, SKEY(Match), &vPVal) &&
903                                             (vPVal != NULL))
904                                         {
905                                                 long *PVal;
906                                                 PVal = (long*) vPVal;
907                                                 
908                                                 Parm->lvalue |= *PVal;
909                                         }
910                                         else {
911                                                 LogTemplateError(NULL, "Define", 
912                                                                  Tokens->nParameters,
913                                                                  TP,
914                                                                  "%s isn't known!!",
915                                                                  ChrPtr(Match));
916
917                                         }
918                                 }
919                         }
920                 }
921                 else {
922
923
924                         LogTemplateError(NULL, "Define", 
925                                          Tokens->nParameters,
926                                          TP,
927                                          "%s isn't known!!",
928                                          Parm->Start);
929                 }}
930                 break;
931         case TYPE_SUBTEMPLATE:{
932                 void *vTmpl;
933                 /* well, we don't check the mobile stuff here... */
934                 if (!GetHash(LocalTemplateCache, Parm->Start, Parm->len, &vTmpl) &&
935                     !GetHash(TemplateCache, Parm->Start, Parm->len, &vTmpl)) {
936                         LogTemplateError(NULL, 
937                                          "SubTemplate", 
938                                          Tokens->nParameters,
939                                          TP,
940                                          "referenced here doesn't exist");
941                 }}
942                 break;
943         }
944         *pCh = pch;
945         return 1;
946 }
947
948 WCTemplateToken *NewTemplateSubstitute(StrBuf *Buf, 
949                                        const char *pStart, 
950                                        const char *pTokenStart, 
951                                        const char *pTokenEnd, 
952                                        long Line,
953                                        WCTemplate *pTmpl)
954 {
955         void *vVar;
956         const char *pch;
957         WCTemplateToken *NewToken;
958         WCTemplputParams TP;
959
960         NewToken = (WCTemplateToken*)malloc(sizeof(WCTemplateToken));
961         memset(NewToken, 0, sizeof(WCTemplateToken));
962         TP.Tokens = NewToken;
963         NewToken->FileName = pTmpl->FileName; /* to print meaningfull log messages... */
964         NewToken->Flags = 0;
965         NewToken->Line = Line + 1;
966         NewToken->pTokenStart = pTokenStart;
967         NewToken->TokenStart = pTokenStart - pStart;
968         NewToken->TokenEnd =  (pTokenEnd - pStart) - NewToken->TokenStart;
969         NewToken->pTokenEnd = pTokenEnd;
970         NewToken->NameEnd = NewToken->TokenEnd - 2;
971         NewToken->PreEval = NULL;
972         NewToken->FlatToken = NewStrBufPlain(pTokenStart + 2, pTokenEnd - pTokenStart - 2);
973         StrBufShrinkToFit(NewToken->FlatToken, 1);
974
975         StrBufPeek(Buf, pTokenStart, + 1, '\0');
976         StrBufPeek(Buf, pTokenEnd, -1, '\0');
977         pch = NewToken->pName = pTokenStart + 2;
978
979         NewToken->HaveParameters = 0;;
980         NewToken->nParameters = 0;
981
982         while (pch < pTokenEnd - 1) {
983                 if (*pch == '(') {
984                         StrBufPeek(Buf, pch, -1, '\0');
985                         NewToken->NameEnd = pch - NewToken->pName;
986                         pch ++;
987                         if (*(pTokenEnd - 1) != ')') {
988                                 LogTemplateError(
989                                         NULL, "Parseerror", ERR_NAME, &TP, 
990                                         "Warning, Non welformed Token; missing right parenthesis");
991                         }
992                         while (pch < pTokenEnd - 1) {
993                                 NewToken->nParameters++;
994                                 if (GetNextParameter(Buf, 
995                                                      &pch, 
996                                                      pTokenEnd - 1, 
997                                                      NewToken, 
998                                                      pTmpl, 
999                                                      &TP, 
1000                                                      &NewToken->Params[NewToken->nParameters - 1]))
1001                                 {
1002                                         NewToken->HaveParameters = 1;
1003                                         if (NewToken->nParameters > MAXPARAM) {
1004                                                 LogTemplateError(
1005                                                         NULL, "Parseerror", ERR_NAME, &TP,
1006                                                         "only [%d] Params allowed in Tokens",
1007                                                         MAXPARAM);
1008
1009                                                 FreeToken(&NewToken);
1010                                                 return NULL;
1011                                         }
1012                                 }
1013                                 else break;
1014                         }
1015                         if((NewToken->NameEnd == 1) &&
1016                            (NewToken->HaveParameters == 1))
1017                            
1018                         {
1019                                 if (*(NewToken->pName) == '_')
1020                                         NewToken->Flags = SV_GETTEXT;
1021                                 else if (*(NewToken->pName) == '=')
1022                                         NewToken->Flags = SV_SUBTEMPL;
1023                                 else if (*(NewToken->pName) == '%')
1024                                         NewToken->Flags = SV_CUST_STR_CONDITIONAL;
1025                                 else if (*(NewToken->pName) == '?')
1026                                         NewToken->Flags = SV_CONDITIONAL;
1027                                 else if (*(NewToken->pName) == '!')
1028                                         NewToken->Flags = SV_NEG_CONDITIONAL;
1029                         }
1030                 }
1031                 else pch ++;            
1032         }
1033         
1034         switch (NewToken->Flags) {
1035         case 0:
1036                 /* If we're able to find out more about the token, do it now while its fresh. */
1037                 if (GetHash(GlobalNS, NewToken->pName, NewToken->NameEnd, &vVar)) {
1038                         HashHandler *Handler;
1039                         Handler = (HashHandler*) vVar;
1040                         if ((NewToken->nParameters < Handler->Filter.nMinArgs) || 
1041                             (NewToken->nParameters > Handler->Filter.nMaxArgs)) {
1042                                 LogTemplateError(
1043                                         NULL, "Token", ERR_NAME, &TP,
1044                                         "doesn't work with %d params", 
1045                                         NewToken->nParameters);
1046
1047                         }
1048                         else {
1049                                 NewToken->PreEval = Handler;
1050                                 NewToken->Flags = SV_PREEVALUATED;              
1051                                 if (Handler->PreEvalFunc != NULL)
1052                                         Handler->PreEvalFunc(NewToken);
1053                         }
1054                 }
1055                 break;
1056         case SV_GETTEXT:
1057                 if (NewToken->nParameters !=1) {
1058                         LogTemplateError(                               
1059                                 NULL, "Gettext", ERR_NAME, &TP,
1060                                 "requires exactly 1 parameter, you gave %d params", 
1061                                 NewToken->nParameters);
1062                         NewToken->Flags = 0;
1063                         break;
1064                 }
1065                 if (DumpTemplateI18NStrings) {
1066                         StrBufAppendPrintf(I18nDump, "_(\"%s\");\n", NewToken->Params[0]->Start);
1067                 }
1068                 break;
1069         case SV_SUBTEMPL:
1070                 if (NewToken->nParameters != 1) {
1071                         LogTemplateError(
1072                                 NULL, "Subtemplates", ERR_NAME, &TP,
1073                                 "require exactly 1 parameter, you gave %d params", 
1074                                 NewToken->nParameters);
1075                         break;
1076                 }
1077                 else {
1078                         void *vTmpl;
1079                         /* well, we don't check the mobile stuff here... */
1080                         if (!GetHash(LocalTemplateCache, 
1081                                      NewToken->Params[0]->Start, 
1082                                      NewToken->Params[0]->len, 
1083                                      &vTmpl) &&
1084                             !GetHash(TemplateCache, 
1085                                      NewToken->Params[0]->Start, 
1086                                      NewToken->Params[0]->len, 
1087                                      &vTmpl)) {
1088                                 LogTemplateError(
1089                                         NULL, "SubTemplate", ERR_PARM1, &TP,
1090                                         "doesn't exist");
1091                         }
1092                 }
1093                 break;
1094         case SV_CUST_STR_CONDITIONAL:
1095         case SV_CONDITIONAL:
1096         case SV_NEG_CONDITIONAL:
1097                 if (NewToken->nParameters <2) {
1098                         LogTemplateError(
1099                                 NULL, "Conditional", ERR_PARM1, &TP,
1100                                 "require at least 2 parameters, you gave %d params", 
1101                                 NewToken->nParameters);
1102                         NewToken->Flags = 0;
1103                         break;
1104                 }
1105                 if (NewToken->Params[1]->lvalue == 0) {
1106                         LogTemplateError(
1107                                 NULL, "Conditional", ERR_PARM1, &TP,
1108                                 "Conditional ID (Parameter 1) mustn't be 0!");
1109                         NewToken->Flags = 0;
1110                         break;
1111                 }
1112                 if (!GetHash(Conditionals, 
1113                              NewToken->Params[0]->Start, 
1114                              NewToken->Params[0]->len, 
1115                              &vVar) || 
1116                     (vVar == NULL)) {
1117                         if ((NewToken->Params[0]->len == 1) &&
1118                             (NewToken->Params[0]->Start[0] == 'X'))
1119                                 break;
1120                         LogTemplateError(
1121                                 NULL, "Conditional", ERR_PARM1, &TP,
1122                                 "Not found!");
1123 /*
1124                         NewToken->Error = NewStrBuf();
1125                         StrBufAppendPrintf(
1126                                 NewToken->Error, 
1127                                 "<pre>\nConditional [%s] (in '%s' line %ld); Not found!\n[%s]\n</pre>\n", 
1128                                 NewToken->Params[0]->Start,
1129                                 ChrPtr(pTmpl->FileName),
1130                                 NewToken->Line,
1131                                 ChrPtr(NewToken->FlatToken));
1132 */
1133                 }
1134                 else {
1135                         NewToken->PreEval = vVar;
1136                 }
1137                 break;
1138         }
1139         return NewToken;
1140 }
1141
1142
1143
1144
1145
1146 /**
1147  * \brief Display a variable-substituted template
1148  * \param templatename template file to load
1149  */
1150 void *prepare_template(StrBuf *filename, StrBuf *Key, HashList *PutThere)
1151 {
1152         WCTemplate *NewTemplate;
1153
1154         NewTemplate = (WCTemplate *) malloc(sizeof(WCTemplate));
1155         memset(NewTemplate, 0, sizeof(WCTemplate));
1156         NewTemplate->Data = NULL;
1157         NewTemplate->FileName = NewStrBufDup(filename);
1158         StrBufShrinkToFit(NewTemplate->FileName, 1);
1159         NewTemplate->nTokensUsed = 0;
1160         NewTemplate->TokenSpace = 0;
1161         NewTemplate->Tokens = NULL;
1162         NewTemplate->MimeType = NewStrBufPlain(GuessMimeByFilename (SKEY(NewTemplate->FileName)), -1);
1163         if (strstr(ChrPtr(NewTemplate->MimeType), "text") != NULL) {
1164                 StrBufAppendBufPlain(NewTemplate->MimeType, HKEY("; charset=utf-8"), 0);
1165         }
1166
1167         if (strstr(ChrPtr(NewTemplate->MimeType), "text") != NULL) {
1168                 StrBufAppendBufPlain(NewTemplate->MimeType, HKEY("; charset=utf-8"), 0);
1169         }
1170
1171         Put(PutThere, ChrPtr(Key), StrLength(Key), NewTemplate, FreeWCTemplate);
1172         return NewTemplate;
1173 }
1174
1175 /**
1176  * \brief Display a variable-substituted template
1177  * \param templatename template file to load
1178  */
1179 void *duplicate_template(WCTemplate *OldTemplate)
1180 {
1181         WCTemplate *NewTemplate;
1182
1183         NewTemplate = (WCTemplate *) malloc(sizeof(WCTemplate));
1184         memset(NewTemplate, 0, sizeof(WCTemplate));
1185         NewTemplate->Data = NULL;
1186         NewTemplate->FileName = NewStrBufDup(OldTemplate->FileName);
1187         StrBufShrinkToFit(NewTemplate->FileName, 1);
1188         NewTemplate->nTokensUsed = 0;
1189         NewTemplate->TokenSpace = 0;
1190         NewTemplate->Tokens = NULL;
1191         NewTemplate->MimeType = NewStrBufDup(OldTemplate->MimeType);
1192         return NewTemplate;
1193 }
1194
1195 /**
1196  * \brief Display a variable-substituted template
1197  * \param templatename template file to load
1198  */
1199 void *load_template(WCTemplate *NewTemplate)
1200 {
1201         int fd;
1202         struct stat statbuf;
1203         const char *pS, *pE, *pch, *Err;
1204         long Line;
1205         int pos;
1206
1207         fd = open(ChrPtr(NewTemplate->FileName), O_RDONLY);
1208         if (fd <= 0) {
1209                 lprintf(1, "ERROR: could not open template '%s' - %s\n",
1210                         ChrPtr(NewTemplate->FileName), strerror(errno));
1211                 return NULL;
1212         }
1213
1214         if (fstat(fd, &statbuf) == -1) {
1215                 lprintf(1, "ERROR: could not stat template '%s' - %s\n",
1216                         ChrPtr(NewTemplate->FileName), strerror(errno));
1217                 return NULL;
1218         }
1219
1220         NewTemplate->Data = NewStrBufPlain(NULL, statbuf.st_size + 1);
1221         if (StrBufReadBLOB(NewTemplate->Data, &fd, 1, statbuf.st_size, &Err) < 0) {
1222                 close(fd);
1223                 lprintf(1, "ERROR: reading template '%s' - %s<br />\n",
1224                         ChrPtr(NewTemplate->FileName), strerror(errno));
1225                 //FreeWCTemplate(NewTemplate);/////tODO
1226                 return NULL;
1227         }
1228         close(fd);
1229
1230         Line = 0;
1231         StrBufShrinkToFit(NewTemplate->Data, 1);
1232         StrBufShrinkToFit(NewTemplate->MimeType, 1);
1233         pS = pch = ChrPtr(NewTemplate->Data);
1234         pE = pS + StrLength(NewTemplate->Data);
1235         while (pch < pE) {
1236                 const char *pts, *pte;
1237                 int InQuotes = 0;
1238                 int InDoubleQuotes = 0;
1239
1240                 /** Find one <? > */
1241                 pos = (-1);
1242                 for (; pch < pE; pch ++) {
1243                         if ((*pch=='<')&&(*(pch + 1)=='?') &&
1244                             !((pch == pS) && /* we must ommit a <?xml */
1245                               (*(pch + 2) == 'x') && 
1246                               (*(pch + 3) == 'm') && 
1247                               (*(pch + 4) == 'l')))                          
1248                                 break;
1249                         if (*pch=='\n') Line ++;
1250                 }
1251                 if (pch >= pE)
1252                         continue;
1253                 pts = pch;
1254
1255                 /** Found one? parse it. */
1256                 for (; pch <= pE - 1; pch ++) {
1257                         if (*pch == '"')
1258                                 InDoubleQuotes = ! InDoubleQuotes;
1259                         else if (*pch == '\'')
1260                                 InQuotes = ! InQuotes;
1261                         else if ((!InQuotes  && !InDoubleQuotes) &&
1262                                  ((*pch!='\\')&&(*(pch + 1)=='>'))) {
1263                                 pch ++;
1264                                 break;
1265                         }
1266                 }
1267                 if (pch + 1 > pE)
1268                         continue;
1269                 pte = pch;
1270                 PutNewToken(NewTemplate, 
1271                             NewTemplateSubstitute(NewTemplate->Data, pS, pts, pte, Line, NewTemplate));
1272                 pch ++;
1273         }
1274         return NewTemplate;
1275 }
1276
1277
1278 const char* PrintTemplate(void *vSubst)
1279 {
1280         WCTemplate *Tmpl = vSubst;
1281
1282         return ChrPtr(Tmpl->FileName);
1283
1284 }
1285
1286 int LoadTemplateDir(const StrBuf *DirName, HashList *wireless, HashList *big, const StrBuf *BaseKey)
1287 {
1288         int Toplevel;
1289         StrBuf *FileName;
1290         StrBuf *Key;
1291         StrBuf *SubKey;
1292         StrBuf *SubDirectory;
1293         DIR *filedir = NULL;
1294         struct dirent *filedir_entry;
1295         struct dirent *d;
1296         int d_type = 0;
1297         int d_namelen;
1298         int d_without_ext;
1299         int IsMobile;
1300         
1301         d = (struct dirent *)malloc(offsetof(struct dirent, d_name) + PATH_MAX + 1);
1302         if (d == NULL) {
1303                 return 0;
1304         }
1305
1306         filedir = opendir (ChrPtr(DirName));
1307         if (filedir == NULL) {
1308                 free(d);
1309                 return 0;
1310         }
1311
1312         Toplevel = StrLength(BaseKey) == 0;
1313         SubDirectory = NewStrBuf();
1314         SubKey = NewStrBuf();
1315         FileName = NewStrBufPlain(NULL, PATH_MAX);
1316         Key = NewStrBuf();
1317         while ((readdir_r(filedir, d, &filedir_entry) == 0) &&
1318                (filedir_entry != NULL))
1319         {
1320                 char *MinorPtr;
1321                 char *PStart;
1322 #ifdef _DIRENT_HAVE_D_NAMELEN
1323                 d_namelen = filedir_entry->d_namelen;
1324                 d_type = filedir_entry->d_type;
1325 #else
1326
1327 #ifndef DT_UNKNOWN
1328 #define DT_UNKNOWN     0
1329 #define DT_DIR         4
1330 #define DT_REG         8
1331 #define DT_LNK         10
1332
1333 #define IFTODT(mode)   (((mode) & 0170000) >> 12)
1334 #define DTTOIF(dirtype)        ((dirtype) << 12)
1335 #endif
1336                 d_namelen = strlen(filedir_entry->d_name);
1337                 d_type = DT_UNKNOWN;
1338 #endif
1339                 d_without_ext = d_namelen;
1340
1341                 if ((d_namelen > 1) && filedir_entry->d_name[d_namelen - 1] == '~')
1342                         continue; /* Ignore backup files... */
1343
1344                 if ((d_namelen == 1) && 
1345                     (filedir_entry->d_name[0] == '.'))
1346                         continue;
1347
1348                 if ((d_namelen == 2) && 
1349                     (filedir_entry->d_name[0] == '.') &&
1350                     (filedir_entry->d_name[1] == '.'))
1351                         continue;
1352
1353                 if (d_type == DT_UNKNOWN) {
1354                         struct stat s;
1355                         char path[PATH_MAX];
1356                         snprintf(path, PATH_MAX, "%s/%s", 
1357                                  ChrPtr(DirName), filedir_entry->d_name);
1358                         if (stat(path, &s) == 0) {
1359                                 d_type = IFTODT(s.st_mode);
1360                         }
1361                 }
1362                 switch (d_type)
1363                 {
1364                 case DT_DIR:
1365                         /* Skip directories we are not interested in... */
1366                         if (strcmp(filedir_entry->d_name, ".svn") == 0)
1367                                 continue;
1368
1369                         FlushStrBuf(SubKey);
1370                         if (!Toplevel) {
1371                                 /* If we're not toplevel, the upper dirs count as foo_bar_<local name>*/
1372                                 StrBufAppendBuf(SubKey, BaseKey, 0);
1373                                 StrBufAppendBufPlain(SubKey, HKEY("_"), 0);
1374                         }
1375                         StrBufAppendBufPlain(SubKey, filedir_entry->d_name, d_namelen, 0);
1376
1377                         FlushStrBuf(SubDirectory);
1378                         StrBufAppendBuf(SubDirectory, DirName, 0);
1379                         if (ChrPtr(SubDirectory)[StrLength(SubDirectory) - 1] != '/')
1380                                 StrBufAppendBufPlain(SubDirectory, HKEY("/"), 0);
1381                         StrBufAppendBufPlain(SubDirectory, filedir_entry->d_name, d_namelen, 0);
1382
1383                         LoadTemplateDir(SubDirectory, wireless, big, SubKey);
1384
1385                         break;
1386                 case DT_LNK: /* TODO: check whether its a file or a directory */
1387                 case DT_REG:
1388
1389
1390                         while ((d_without_ext > 0) && (filedir_entry->d_name[d_without_ext] != '.'))
1391                                 d_without_ext --;
1392                         if ((d_without_ext == 0) || (d_namelen < 3))
1393                                 continue;
1394                         if (((d_namelen > 1) && filedir_entry->d_name[d_namelen - 1] == '~') ||
1395                             (strcmp(&filedir_entry->d_name[d_without_ext], ".orig") == 0) ||
1396                             (strcmp(&filedir_entry->d_name[d_without_ext], ".swp") == 0))
1397                                 continue; /* Ignore backup files... */
1398                         /* .m.xxx is for mobile useragents! */
1399                         IsMobile = 0;
1400                         if (d_without_ext > 2)
1401                                 IsMobile = (filedir_entry->d_name[d_without_ext - 1] == 'm') &&
1402                                         (filedir_entry->d_name[d_without_ext - 2] == '.');
1403                         PStart = filedir_entry->d_name;
1404                         StrBufPrintf(FileName, "%s/%s", ChrPtr(DirName),  filedir_entry->d_name);
1405                         MinorPtr = strchr(filedir_entry->d_name, '.');
1406                         if (MinorPtr != NULL)
1407                                 *MinorPtr = '\0';
1408                         FlushStrBuf(Key);
1409                         if (!Toplevel) {
1410                                 /* If we're not toplevel, the upper dirs count as foo_bar_<local name>*/
1411                                 StrBufAppendBuf(Key, BaseKey, 0);
1412                                 StrBufAppendBufPlain(Key, HKEY("_"), 0);
1413                         }
1414                         StrBufAppendBufPlain(Key, filedir_entry->d_name, MinorPtr - filedir_entry->d_name, 0);
1415
1416                         if (LoadTemplates >= 1)
1417                                 lprintf(1, "%s %d %s\n", ChrPtr(FileName), IsMobile, ChrPtr(Key));
1418                         prepare_template(FileName, Key, (IsMobile)?wireless:big);
1419                 default:
1420                         break;
1421                 }
1422         }
1423         free(d);
1424         closedir(filedir);
1425         FreeStrBuf(&FileName);
1426         FreeStrBuf(&Key);
1427         FreeStrBuf(&SubDirectory);
1428         FreeStrBuf(&SubKey);
1429         return 1;
1430 }
1431
1432 void InitTemplateCache(void)
1433 {
1434         int i;
1435         StrBuf *Key;
1436         StrBuf *Dir;
1437         HashList *Templates[4];
1438
1439         Dir = NewStrBuf();
1440         Key = NewStrBuf();
1441
1442         /* Primary Template set... */
1443         StrBufPrintf(Dir, "%s/t", static_dirs[0]);
1444         LoadTemplateDir(Dir,
1445                         WirelessTemplateCache,
1446                         TemplateCache, 
1447                         Key);
1448
1449         /* User local Template set */
1450         StrBufPrintf(Dir, "%s/t", static_dirs[1]);
1451         LoadTemplateDir(Dir,
1452                         WirelessLocalTemplateCache,
1453                         LocalTemplateCache, 
1454                         Key);
1455         
1456         /* Debug Templates, just to be loaded while debugging. */
1457         
1458         StrBufPrintf(Dir, "%s/dbg", static_dirs[0]);
1459         LoadTemplateDir(Dir,
1460                         WirelessTemplateCache,
1461                         TemplateCache, 
1462                         Key);
1463         Templates[0] = WirelessTemplateCache;
1464         Templates[1] = TemplateCache;
1465         Templates[2] = WirelessLocalTemplateCache;
1466         Templates[3] = LocalTemplateCache;
1467
1468
1469         if (LoadTemplates == 0) 
1470                 for (i=0; i < 4; i++) {
1471                         const char *Key;
1472                         long KLen;
1473                         HashPos *At;
1474                         void *vTemplate;
1475
1476                         At = GetNewHashPos(Templates[i], 0);
1477                         while (GetNextHashPos(Templates[i], 
1478                                               At, 
1479                                               &KLen,
1480                                               &Key, 
1481                                               &vTemplate) && 
1482                                (vTemplate != NULL))
1483                         {
1484                                 load_template((WCTemplate *)vTemplate);
1485                         }
1486                         DeleteHashPos(&At);
1487                 }
1488
1489
1490         FreeStrBuf(&Dir);
1491         FreeStrBuf(&Key);
1492 }
1493
1494
1495
1496 /*-----------------------------------------------------------------------------
1497  *                      Filling & processing Templates
1498  */
1499 /**
1500  * \brief executes one token
1501  * \param Target buffer to append to
1502  * \param Token da to  process.
1503  * \param Template we're iterating
1504  * \param Context Contextpoointer to pass in
1505  * \param state are we in conditional state?
1506  * \param ContextType what type of information does context giv us?
1507  */
1508 int EvaluateToken(StrBuf *Target, int state, WCTemplputParams *TP)
1509 {
1510         const char *AppendMe;
1511         long AppendMeLen;
1512         HashHandler *Handler;
1513         void *vVar;
1514         
1515 /* much output, since pName is not terminated...
1516         lprintf(1,"Doing token: %s\n",Token->pName);
1517 */
1518
1519         switch (TP->Tokens->Flags) {
1520         case SV_GETTEXT:
1521                 TmplGettext(Target, TP);
1522                 break;
1523         case SV_CONDITIONAL: /** Forward conditional evaluation */
1524                 return EvaluateConditional(Target, 1, state, TP);
1525                 break;
1526         case SV_NEG_CONDITIONAL: /** Reverse conditional evaluation */
1527                 return EvaluateConditional(Target, 0, state, TP);
1528                 break;
1529         case SV_CUST_STR_CONDITIONAL: /** Conditional put custom strings from params */
1530                 if (TP->Tokens->nParameters >= 6) {
1531                         if (EvaluateConditional(Target, 0, state, TP)) {
1532                                 GetTemplateTokenString(Target, TP, 5, &AppendMe, &AppendMeLen);
1533                                 StrBufAppendBufPlain(Target, 
1534                                                      AppendMe, 
1535                                                      AppendMeLen,
1536                                                      0);
1537                         }
1538                         else{
1539                                 GetTemplateTokenString(Target, TP, 4, &AppendMe, &AppendMeLen);
1540                                 StrBufAppendBufPlain(Target, 
1541                                                      AppendMe, 
1542                                                      AppendMeLen,
1543                                                      0);
1544                         }
1545                 }
1546                 else  {
1547                         LogTemplateError(
1548                                 Target, "Conditional", ERR_NAME, TP,
1549                                 "needs at least 6 Params!"); 
1550                 }
1551                 break;
1552         case SV_SUBTEMPL:
1553                 if (TP->Tokens->nParameters == 1)
1554                         DoTemplate(TKEY(0), Target, TP);
1555                 break;
1556         case SV_PREEVALUATED:
1557                 Handler = (HashHandler*) TP->Tokens->PreEval;
1558                 if (!CheckContext(Target, &Handler->Filter, TP, "Token")) {
1559                         return -1;
1560                 }
1561                 Handler->HandlerFunc(Target, TP);
1562                 break;          
1563         default:
1564                 if (GetHash(GlobalNS, TP->Tokens->pName, TP->Tokens->NameEnd, &vVar)) {
1565                         Handler = (HashHandler*) vVar;
1566                         if (!CheckContext(Target, &Handler->Filter, TP, "Token")) {
1567                                 return -1;
1568                         }
1569                         else {
1570                                 Handler->HandlerFunc(Target, TP);
1571                         }
1572                 }
1573                 else {
1574                         LogTemplateError(
1575                                 Target, "Token UNKNOWN", ERR_NAME, TP,
1576                                 "You've specified a token that isn't known to webcit.!");
1577                 }
1578         }
1579         return 0;
1580 }
1581
1582
1583
1584 const StrBuf *ProcessTemplate(WCTemplate *Tmpl, StrBuf *Target, WCTemplputParams *CallingTP)
1585 {
1586         WCTemplate *pTmpl = Tmpl;
1587         int done = 0;
1588         int i, state;
1589         const char *pData, *pS;
1590         long len;
1591         WCTemplputParams TP;
1592
1593         memcpy(&TP.Filter, &CallingTP->Filter, sizeof(ContextFilter));
1594
1595         TP.Context = CallingTP->Context;
1596         TP.ControlContext = CallingTP->ControlContext;
1597
1598         if (LoadTemplates != 0) {                       
1599                 if (LoadTemplates > 1)
1600                         lprintf(1, "DBG: ----- loading:  [%s] ------ \n", 
1601                                 ChrPtr(Tmpl->FileName));
1602                 pTmpl = duplicate_template(Tmpl);
1603                 if(load_template(pTmpl) == NULL) {
1604                         StrBufAppendPrintf(
1605                                 Target, 
1606                                 "<pre>\nError loading Template [%s]\n See Logfile for details\n</pre>\n", 
1607                                 ChrPtr(Tmpl->FileName));
1608                         FreeWCTemplate(pTmpl);
1609                         return NULL;
1610                 }
1611
1612         }
1613
1614         pS = pData = ChrPtr(pTmpl->Data);
1615         len = StrLength(pTmpl->Data);
1616         i = 0;
1617         state = 0;
1618         while (!done) {
1619                 if (i >= pTmpl->nTokensUsed) {
1620                         StrBufAppendBufPlain(Target, 
1621                                              pData, 
1622                                              len - (pData - pS), 0);
1623                         done = 1;
1624                 }
1625                 else {
1626                         StrBufAppendBufPlain(
1627                                 Target, pData, 
1628                                 pTmpl->Tokens[i]->pTokenStart - pData, 0);
1629                         TP.Tokens = pTmpl->Tokens[i];
1630                         TP.nArgs = pTmpl->Tokens[i]->nParameters;
1631                         state = EvaluateToken(Target, state, &TP);
1632
1633                         while ((state != 0) && (i+1 < pTmpl->nTokensUsed)) {
1634                         /* condition told us to skip till its end condition */
1635                                 i++;
1636                                 TP.Tokens = pTmpl->Tokens[i];
1637                                 TP.nArgs = pTmpl->Tokens[i]->nParameters;
1638                                 if ((pTmpl->Tokens[i]->Flags == SV_CONDITIONAL) ||
1639                                     (pTmpl->Tokens[i]->Flags == SV_NEG_CONDITIONAL)) {
1640                                         if (state == EvaluateConditional(
1641                                                     Target, 
1642                                                     pTmpl->Tokens[i]->Flags, 
1643                                                     state, 
1644                                                     &TP))
1645                                                 state = 0;
1646                                 }
1647                         }
1648                         pData = pTmpl->Tokens[i++]->pTokenEnd + 1;
1649                         if (i > pTmpl->nTokensUsed)
1650                                 done = 1;
1651                 }
1652         }
1653         if (LoadTemplates != 0) {
1654                 FreeWCTemplate(pTmpl);
1655         }
1656         return Tmpl->MimeType;
1657
1658 }
1659
1660 /**
1661  * \brief Display a variable-substituted template
1662  * \param templatename template file to load
1663  * \returns the mimetype of the template its doing
1664  */
1665 const StrBuf *DoTemplate(const char *templatename, long len, StrBuf *Target, WCTemplputParams *TP) 
1666 {
1667         WCTemplputParams LocalTP;
1668         HashList *Static;
1669         HashList *StaticLocal;
1670         void *vTmpl;
1671         
1672         if (Target == NULL)
1673                 Target = WC->WBuf;
1674         if (TP == NULL) {
1675                 memset(&LocalTP, 0, sizeof(WCTemplputParams));
1676                 TP = &LocalTP;
1677         }
1678
1679         if (WC->is_mobile > 0) {
1680                 Static = WirelessTemplateCache;
1681                 StaticLocal = WirelessLocalTemplateCache;
1682         }
1683         else {
1684                 Static = TemplateCache;
1685                 StaticLocal = LocalTemplateCache;
1686         }
1687
1688         if (len == 0)
1689         {
1690                 lprintf (1, "Can't to load a template with empty name!\n");
1691                 StrBufAppendPrintf(Target, "<pre>\nCan't to load a template with empty name!\n</pre>");
1692                 return NULL;
1693         }
1694
1695         if (!GetHash(StaticLocal, templatename, len, &vTmpl) &&
1696             !GetHash(Static, templatename, len, &vTmpl)) {
1697                 lprintf (1, "didn't find Template [%s] %ld %ld\n", templatename, len , (long)strlen(templatename));
1698                 StrBufAppendPrintf(Target, "<pre>\ndidn't find Template [%s] %ld %ld\n</pre>", 
1699                                    templatename, len, 
1700                                    (long)strlen(templatename));
1701 #if 0
1702                 dbg_PrintHash(Static, PrintTemplate, NULL);
1703                 PrintHash(Static, VarPrintTransition, PrintTemplate);
1704 #endif
1705                 return NULL;
1706         }
1707         if (vTmpl == NULL) 
1708                 return NULL;
1709         return ProcessTemplate(vTmpl, Target, TP);
1710
1711 }
1712
1713
1714 void tmplput_Comment(StrBuf *Target, WCTemplputParams *TP)
1715 {
1716         if (LoadTemplates != 0)
1717         {
1718                 StrBuf *Comment;
1719                 const char *pch;
1720                 long len;
1721
1722                 GetTemplateTokenString(Target, TP, 0, &pch, &len);
1723                 Comment = NewStrBufPlain(pch, len);
1724                 StrBufAppendBufPlain(Target, HKEY("<!--"), 0);
1725                 StrBufAppendTemplate(Target, TP, Comment, 1);
1726                 StrBufAppendBufPlain(Target, HKEY("-->"), 0);
1727                 FreeStrBuf(&Comment);
1728         }
1729 }
1730
1731 /*-----------------------------------------------------------------------------
1732  *                      Iterators
1733  */
1734 typedef struct _HashIterator {
1735         HashList *StaticList;
1736         int AdditionalParams;
1737         int ContextType;
1738         int XPectContextType;
1739         int Flags;
1740         RetrieveHashlistFunc GetHash;
1741         HashDestructorFunc Destructor;
1742         SubTemplFunc DoSubTemplate;
1743 } HashIterator;
1744
1745 void RegisterITERATOR(const char *Name, long len, 
1746                       int AdditionalParams, 
1747                       HashList *StaticList, 
1748                       RetrieveHashlistFunc GetHash, 
1749                       SubTemplFunc DoSubTempl,
1750                       HashDestructorFunc Destructor,
1751                       int ContextType, 
1752                       int XPectContextType, 
1753                       int Flags)
1754 {
1755         HashIterator *It;
1756
1757         It = (HashIterator*)malloc(sizeof(HashIterator));
1758         memset(It, 0, sizeof(HashIterator));
1759         It->StaticList = StaticList;
1760         It->AdditionalParams = AdditionalParams;
1761         It->GetHash = GetHash;
1762         It->DoSubTemplate = DoSubTempl;
1763         It->Destructor = Destructor;
1764         It->ContextType = ContextType;
1765         It->XPectContextType = XPectContextType;
1766         It->Flags = Flags;
1767         Put(Iterators, Name, len, It, NULL);
1768 }
1769
1770 typedef struct _iteratestruct {
1771         int GroupChange;
1772         int oddeven;
1773         const char *Key;
1774         long KeyLen;
1775         int n;
1776         int LastN;
1777         }IterateStruct; 
1778
1779 int preeval_iterate(WCTemplateToken *Token)
1780 {
1781         WCTemplputParams TPP;
1782         WCTemplputParams *TP;
1783         void *vTmpl;
1784         void *vIt;
1785         HashIterator *It;
1786
1787         memset(&TPP, 0, sizeof(WCTemplputParams));
1788         TP = &TPP;
1789         TP->Tokens = Token;
1790         if (!GetHash(Iterators, TKEY(0), &vIt)) {
1791                 LogTemplateError(
1792                         NULL, "Iterator", ERR_PARM1, TP,
1793                         "not found");
1794                 return 0;
1795         }
1796         if (TP->Tokens->Params[1]->Type != TYPE_SUBTEMPLATE) {
1797                 LogTemplateError(NULL, "Iterator", ERR_PARM1, TP,
1798                                  "Need token with type Subtemplate as param 1, have %s", 
1799                                  TP->Tokens->Params[1]->Start);
1800         }
1801         
1802         /* well, we don't check the mobile stuff here... */
1803         if (!GetHash(LocalTemplateCache, TKEY(1), &vTmpl) &&
1804             !GetHash(TemplateCache, TKEY(1), &vTmpl)) {
1805                 LogTemplateError(NULL, "SubTemplate", ERR_PARM1, TP,
1806                                  "referenced here doesn't exist");
1807         }
1808         Token->Preeval2 = vIt;
1809         It = (HashIterator *) vIt;
1810
1811         if (TP->Tokens->nParameters < It->AdditionalParams + 2) {
1812                 LogTemplateError(                               
1813                         NULL, "Iterator", ERR_PARM1, TP,
1814                         "doesn't work with %d params", 
1815                         TP->Tokens->nParameters);
1816         }
1817
1818
1819         return 1;
1820 }
1821
1822 void tmpl_iterate_subtmpl(StrBuf *Target, WCTemplputParams *TP)
1823 {
1824         HashIterator *It;
1825         HashList *List;
1826         HashPos  *it;
1827         SortStruct *SortBy = NULL;
1828         void *vSortBy;
1829         int DetectGroupChange = 0;
1830         int nMembersUsed;
1831         void *vContext;
1832         void *vLastContext = NULL;
1833         StrBuf *SubBuf;
1834         WCTemplputParams SubTP;
1835         IterateStruct Status;
1836
1837         long StartAt = 0;
1838         long StepWidth = 0;
1839         long StopAt = -1;
1840
1841         memset(&Status, 0, sizeof(IterateStruct));
1842         memcpy (&SubTP, &TP, sizeof(WCTemplputParams));
1843         
1844         It = (HashIterator*) TP->Tokens->Preeval2;
1845         if (It == NULL) {
1846                 LogTemplateError(
1847                         Target, "Iterator", ERR_PARM1, TP, "Unknown!");
1848                 return;
1849         }
1850
1851         if (TP->Tokens->nParameters < It->AdditionalParams + 2) {
1852                 LogTemplateError(                               
1853                         Target, "Iterator", ERR_PARM1, TP,
1854                         "doesn't work with %d params", 
1855                         TP->Tokens->nParameters - 1);
1856                 return;
1857         }
1858
1859         if ((It->XPectContextType != CTX_NONE) &&
1860             (It->XPectContextType != TP->Filter.ContextType)) {
1861                 LogTemplateError(
1862                         Target, "Iterator", ERR_PARM1, TP,
1863                         "requires context of type %s, have %s", 
1864                         ContextName(It->XPectContextType), 
1865                         ContextName(TP->Filter.ContextType));
1866                 return ;
1867                 
1868         }
1869
1870         if (It->StaticList == NULL)
1871                 List = It->GetHash(Target, TP);
1872         else
1873                 List = It->StaticList;
1874
1875         DetectGroupChange = (It->Flags & IT_FLAG_DETECT_GROUPCHANGE) != 0;
1876         if (DetectGroupChange) {
1877                 const StrBuf *BSort;
1878                 DetectGroupChange = 0;
1879                 if (havebstr("SortBy")) {
1880                         BSort = sbstr("SortBy");
1881                         if (GetHash(SortHash, SKEY(BSort), &vSortBy) &&
1882                             (vSortBy != NULL)) {
1883                                 SortBy = (SortStruct*)vSortBy;
1884                                 /** Ok, its us, lets see in which direction we should sort... */
1885                                 if (havebstr("SortOrder")) {
1886                                         int SortOrder;
1887                                         SortOrder = LBSTR("SortOrder");
1888                                         if (SortOrder != 0)
1889                                                 DetectGroupChange = 1;
1890                                 }
1891                         }
1892                 }
1893         }
1894         nMembersUsed = GetCount(List);
1895         SubBuf = NewStrBuf();
1896         SubTP.Filter.ContextType = It->ContextType;
1897         SubTP.Filter.ControlContextType = CTX_ITERATE;
1898         SubTP.ControlContext = &Status;
1899         
1900         if (HAVE_PARAM(2)) {
1901                 StartAt = GetTemplateTokenNumber(Target, TP, 2, 0);
1902         }
1903         if (HAVE_PARAM(3)) {
1904                 StepWidth = GetTemplateTokenNumber(Target, TP, 3, 0);
1905         }
1906         if (HAVE_PARAM(4)) {
1907                 StopAt = GetTemplateTokenNumber(Target, TP, 4, -1);
1908         }
1909         it = GetNewHashPos(List, StepWidth);
1910         if (StopAt < 0) {
1911                 StopAt = GetCount(List);
1912         }
1913         while (GetNextHashPos(List, it, &Status.KeyLen, &Status.Key, &vContext)) {
1914                 if ((Status.n >= StartAt) && (Status.n <= StopAt)) {
1915                         if (DetectGroupChange && Status.n > 0) {
1916                                 Status.GroupChange = SortBy->GroupChange(vContext, vLastContext);
1917                         }
1918                         Status.LastN = (Status.n + 1) == nMembersUsed;
1919                         SubTP.Context = vContext;
1920                         if (It->DoSubTemplate != NULL)
1921                                 It->DoSubTemplate(SubBuf, &SubTP);
1922                         DoTemplate(TKEY(1), SubBuf, &SubTP);
1923                         
1924                         StrBufAppendBuf(Target, SubBuf, 0);
1925                         FlushStrBuf(SubBuf);
1926                         Status.oddeven = ! Status.oddeven;
1927                         vLastContext = vContext;
1928                 }
1929                 Status.n++;
1930         }
1931         FreeStrBuf(&SubBuf);
1932         DeleteHashPos(&it);
1933         if (It->Destructor != NULL)
1934                 It->Destructor(&List);
1935 }
1936
1937
1938 int conditional_ITERATE_ISGROUPCHANGE(StrBuf *Target, WCTemplputParams *TP)
1939 {
1940         IterateStruct *Ctx = CCTX;
1941         if (TP->Tokens->nParameters < 3)
1942                 return  Ctx->GroupChange;
1943
1944         return TP->Tokens->Params[2]->lvalue == Ctx->GroupChange;
1945 }
1946
1947 void tmplput_ITERATE_ODDEVEN(StrBuf *Target, WCTemplputParams *TP)
1948 {
1949         IterateStruct *Ctx = CCTX;
1950         if (Ctx->oddeven)
1951                 StrBufAppendBufPlain(Target, HKEY("odd"), 0);
1952         else
1953                 StrBufAppendBufPlain(Target, HKEY("even"), 0);
1954 }
1955
1956
1957 void tmplput_ITERATE_KEY(StrBuf *Target, WCTemplputParams *TP)
1958 {
1959         IterateStruct *Ctx = CCTX;
1960
1961         StrBufAppendBufPlain(Target, Ctx->Key, Ctx->KeyLen, 0);
1962 }
1963
1964
1965 void tmplput_ITERATE_LASTN(StrBuf *Target, WCTemplputParams *TP)
1966 {
1967         IterateStruct *Ctx = CCTX;
1968         StrBufAppendPrintf(Target, "%d", Ctx->n);
1969 }
1970
1971 int conditional_ITERATE_FIRSTN(StrBuf *Target, WCTemplputParams *TP)
1972 {
1973         IterateStruct *Ctx = CCTX;
1974         return Ctx->n == 0;
1975 }
1976
1977 int conditional_ITERATE_LASTN(StrBuf *Target, WCTemplputParams *TP)
1978 {
1979         IterateStruct *Ctx = CCTX;
1980         return Ctx->LastN;
1981 }
1982
1983
1984
1985 /*-----------------------------------------------------------------------------
1986  *                      Conditionals
1987  */
1988 int EvaluateConditional(StrBuf *Target, int Neg, int state, WCTemplputParams *TP)
1989 {
1990         ConditionalStruct *Cond;
1991
1992         if ((TP->Tokens->Params[0]->len == 1) &&
1993             (TP->Tokens->Params[0]->Start[0] == 'X'))
1994                 return (state != 0)?TP->Tokens->Params[1]->lvalue:0;
1995             
1996         Cond = (ConditionalStruct *) TP->Tokens->PreEval;
1997         if (Cond == NULL) {
1998                 LogTemplateError(
1999                         Target, "Conditional", ERR_PARM1, TP,
2000                         "unknown!");
2001                 return 1;
2002         }
2003
2004         if (!CheckContext(Target, &Cond->Filter, TP, "Conditional")) {
2005                 return 0;
2006         }
2007
2008         if (Cond->CondF(Target, TP) == Neg)
2009                 return TP->Tokens->Params[1]->lvalue;
2010         return 0;
2011 }
2012
2013 void RegisterConditional(const char *Name, long len, 
2014                          int nParams,
2015                          WCConditionalFunc CondF, 
2016                          int ContextRequired)
2017 {
2018         ConditionalStruct *Cond;
2019
2020         Cond = (ConditionalStruct*)malloc(sizeof(ConditionalStruct));
2021         memset(Cond, 0, sizeof(ConditionalStruct));
2022         Cond->PlainName = Name;
2023         Cond->Filter.nMaxArgs = nParams;
2024         Cond->Filter.nMinArgs = nParams;
2025         Cond->CondF = CondF;
2026         Cond->Filter.ContextType = ContextRequired;
2027         Cond->Filter.ControlContextType = CTX_NONE;
2028         Put(Conditionals, Name, len, Cond, NULL);
2029 }
2030
2031 void RegisterControlConditional(const char *Name, long len, 
2032                                 int nParams,
2033                                 WCConditionalFunc CondF, 
2034                                 int ControlContextRequired)
2035 {
2036         ConditionalStruct *Cond;
2037
2038         Cond = (ConditionalStruct*)malloc(sizeof(ConditionalStruct));
2039         memset(Cond, 0, sizeof(ConditionalStruct));
2040         Cond->PlainName = Name;
2041         Cond->Filter.nMaxArgs = nParams;
2042         Cond->Filter.nMinArgs = nParams;
2043         Cond->CondF = CondF;
2044         Cond->Filter.ContextType = CTX_NONE;
2045         Cond->Filter.ControlContextType = ControlContextRequired;
2046         Put(Conditionals, Name, len, Cond, NULL);
2047 }
2048
2049 void RegisterTokenParamDefine(const char *Name, long len, 
2050                               long Value)
2051 {
2052         long *PVal;
2053
2054         PVal = (long*)malloc(sizeof(long));
2055         *PVal = Value;
2056         Put(Defines, Name, len, PVal, NULL);
2057 }
2058
2059 long GetTokenDefine(const char *Name, long len, 
2060                     long DefValue)
2061 {
2062         void *vPVal;
2063
2064         if (GetHash(Defines, Name, len, &vPVal) &&
2065              (vPVal != NULL))
2066          {
2067                  return *(long*) vPVal;
2068          }
2069          else
2070          {
2071                  return DefValue;
2072          }
2073 }
2074
2075 void tmplput_DefStr(StrBuf *Target, WCTemplputParams *TP)
2076 {
2077         const char *Str;
2078         long len;
2079         GetTemplateTokenString(Target, TP, 2, &Str, &len);
2080         
2081         StrBufAppendBufPlain(Target, Str, len, 0);
2082 }
2083
2084 void tmplput_DefVal(StrBuf *Target, WCTemplputParams *TP)
2085 {
2086         int val;
2087
2088         val = GetTemplateTokenNumber(Target, TP, 0, 0);
2089         StrBufAppendPrintf(Target, "%d", val);
2090 }
2091
2092 HashList *Defines;
2093
2094 /*-----------------------------------------------------------------------------
2095  *                      Context Strings
2096  */
2097 void tmplput_ContextString(StrBuf *Target, WCTemplputParams *TP)
2098 {
2099         StrBufAppendTemplate(Target, TP, (StrBuf*)CTX, 0);
2100 }
2101 int ConditionalContextStr(StrBuf *Target, WCTemplputParams *TP)
2102 {
2103         StrBuf *TokenText = (StrBuf*) CTX;
2104         const char *CompareToken;
2105         long len;
2106
2107         GetTemplateTokenString(Target, TP, 2, &CompareToken, &len);
2108         return strcmp(ChrPtr(TokenText), CompareToken) == 0;
2109 }
2110
2111 void tmplput_ContextStringArray(StrBuf *Target, WCTemplputParams *TP)
2112 {
2113         HashList *Arr = (HashList*) CTX;
2114         void *pV;
2115         int val;
2116
2117         val = GetTemplateTokenNumber(Target, TP, 0, 0);
2118         if (GetHash(Arr, IKEY(val), &pV) && 
2119             (pV != NULL)) {
2120                 StrBufAppendTemplate(Target, TP, (StrBuf*)pV, 1);
2121         }
2122 }
2123 int ConditionalContextStrinArray(StrBuf *Target, WCTemplputParams *TP)
2124 {
2125         HashList *Arr = (HashList*) CTX;
2126         void *pV;
2127         int val;
2128         const char *CompareToken;
2129         long len;
2130
2131         GetTemplateTokenString(Target, TP, 2, &CompareToken, &len);
2132         val = GetTemplateTokenNumber(Target, TP, 0, 0);
2133         if (GetHash(Arr, IKEY(val), &pV) && 
2134             (pV != NULL)) {
2135                 return strcmp(ChrPtr((StrBuf*)pV), CompareToken) == 0;
2136         }
2137         else
2138                 return 0;
2139 }
2140
2141 /*-----------------------------------------------------------------------------
2142  *                      Boxed-API
2143  */
2144
2145 void tmpl_do_boxed(StrBuf *Target, WCTemplputParams *TP)
2146 {
2147         WCTemplputParams SubTP;
2148
2149         StrBuf *Headline = NULL;
2150         if (TP->Tokens->nParameters == 2) {
2151                 if (TP->Tokens->Params[1]->Type == TYPE_STR) {
2152                         Headline = NewStrBuf();
2153                         DoTemplate(TKEY(1), Headline, TP);
2154                 }
2155                 else {
2156                         const char *Ch;
2157                         long len;
2158                         GetTemplateTokenString(Target, 
2159                                                TP, 
2160                                                1,
2161                                                &Ch,
2162                                                &len);
2163                         Headline = NewStrBufPlain(Ch, len);
2164                 }
2165         }
2166         /* else TODO error? logging? */
2167         memcpy (&SubTP, TP, sizeof(WCTemplputParams));
2168         SubTP.Context = Headline;
2169         SubTP.Filter.ContextType = CTX_STRBUF;
2170         DoTemplate(HKEY("beginbox"), Target, &SubTP);
2171         DoTemplate(TKEY(0), Target, TP);
2172         DoTemplate(HKEY("endbox"), Target, TP);
2173         FreeStrBuf(&Headline);
2174 }
2175
2176 /*-----------------------------------------------------------------------------
2177  *                      Tabbed-API
2178  */
2179
2180 typedef struct _tab_struct {
2181         long CurrentTab;
2182         StrBuf *TabTitle;
2183 } tab_struct;
2184
2185 int preeval_do_tabbed(WCTemplateToken *Token)
2186 {
2187         WCTemplputParams TPP;
2188         WCTemplputParams *TP;
2189         const char *Ch;
2190         long len;
2191         int i, nTabs;
2192
2193
2194         memset(&TPP, 0, sizeof(WCTemplputParams));
2195         TP = &TPP;
2196         TP->Tokens = Token;
2197         nTabs = TP->Tokens->nParameters / 2 - 1;
2198         if (TP->Tokens->nParameters % 2 != 0)
2199         {
2200                 LogTemplateError(NULL, "TabbedApi", ERR_PARM1, TP,
2201                                  "need even number of arguments");
2202                 return 0;
2203
2204         }
2205         else for (i = 0; i < nTabs; i++) {
2206                 if (!HaveTemplateTokenString(NULL, 
2207                                              TP, 
2208                                              i * 2,
2209                                              &Ch,
2210                                              &len) || 
2211                     (TP->Tokens->Params[i * 2]->len == 0))
2212                 {
2213                         LogTemplateError(NULL, "TabbedApi", ERR_PARM1, TP,
2214                                          "Tab-Subject %d needs to be able to produce a string, have %s", 
2215                                          i, TP->Tokens->Params[i * 2]->Start);
2216                         return 0;
2217                 }
2218                 if (!HaveTemplateTokenString(NULL, 
2219                                              TP, 
2220                                              i * 2 + 1,
2221                                              &Ch,
2222                                              &len) || 
2223                     (TP->Tokens->Params[i * 2 + 1]->len == 0))
2224                 {
2225                         LogTemplateError(NULL, "TabbedApi", ERR_PARM1, TP,
2226                                          "Tab-Content %d needs to be able to produce a string, have %s", 
2227                                          i, TP->Tokens->Params[i * 2 + 1]->Start);
2228                         return 0;
2229                 }
2230         }
2231
2232         if (!HaveTemplateTokenString(NULL, 
2233                                      TP, 
2234                                      i * 2 + 1,
2235                                      &Ch,
2236                                      &len) || 
2237             (TP->Tokens->Params[i * 2 + 1]->len == 0))
2238         {
2239                 LogTemplateError(NULL, "TabbedApi", ERR_PARM1, TP,
2240                                  "Tab-Content %d needs to be able to produce a string, have %s", 
2241                                  i, TP->Tokens->Params[i * 2 + 1]->Start);
2242                 return 0;
2243         }
2244         return 1;
2245 }
2246
2247
2248 void tmpl_do_tabbed(StrBuf *Target, WCTemplputParams *TP)
2249 {
2250         StrBuf **TabNames;
2251         int i, ntabs, nTabs;
2252         tab_struct TS;
2253         WCTemplputParams SubTP;
2254
2255         memset(&TS, 0, sizeof(tab_struct));
2256         memcpy (&SubTP, &TP, sizeof(WCTemplputParams));
2257
2258         nTabs = ntabs = TP->Tokens->nParameters / 2;
2259         TabNames = (StrBuf **) malloc(ntabs * sizeof(StrBuf*));
2260         memset(TabNames, 0, ntabs * sizeof(StrBuf*));
2261
2262         for (i = 0; i < ntabs; i++) {
2263                 if ((TP->Tokens->Params[i * 2]->Type == TYPE_STR) &&
2264                     (TP->Tokens->Params[i * 2]->len > 0)) {
2265                         TabNames[i] = NewStrBuf();
2266                         DoTemplate(TKEY(i * 2), TabNames[i], TP);
2267                 }
2268                 else if (TP->Tokens->Params[i * 2]->Type == TYPE_GETTEXT) {
2269                         const char *Ch;
2270                         long len;
2271                         GetTemplateTokenString(Target, 
2272                                                TP, 
2273                                                i * 2,
2274                                                &Ch,
2275                                                &len);
2276                         TabNames[i] = NewStrBufPlain(Ch, -1);
2277                 }
2278                 else { 
2279                         /** A Tab without subject? we can't count that, add it as silent */
2280                         nTabs --;
2281                 }
2282         }
2283         memcpy (&SubTP, TP, sizeof(WCTemplputParams));
2284         SubTP.Filter.ControlContextType = CTX_TAB;
2285         SubTP.ControlContext = &TS;
2286
2287         StrTabbedDialog(Target, nTabs, TabNames);
2288         for (i = 0; i < ntabs; i++) {
2289                 memset(&TS, 0, sizeof(tab_struct));
2290                 TS.CurrentTab = i;
2291                 TS.TabTitle = TabNames[i];
2292                 StrBeginTab(Target, i, nTabs, TabNames);
2293                 DoTemplate(TKEY(i * 2 + 1), Target, &SubTP);
2294                 StrEndTab(Target, i, nTabs);
2295         }
2296         for (i = 0; i < ntabs; i++) 
2297                 FreeStrBuf(&TabNames[i]);
2298 }
2299
2300 void tmplput_TAB_N(StrBuf *Target, WCTemplputParams *TP)
2301 {
2302         tab_struct *Ctx = CCTX;
2303
2304         StrBufAppendPrintf(Target, "%d", Ctx->CurrentTab);
2305 }
2306
2307 void tmplput_TAB_TITLE(StrBuf *Target, WCTemplputParams *TP)
2308 {
2309         tab_struct *Ctx = CCTX;
2310         StrBufAppendTemplate(Target, TP, Ctx->TabTitle, 0);
2311 }
2312
2313 /*-----------------------------------------------------------------------------
2314  *                      Sorting-API
2315  */
2316
2317
2318 void RegisterSortFunc(const char *name, long len, 
2319                       const char *prepend, long preplen,
2320                       CompareFunc Forward, 
2321                       CompareFunc Reverse, 
2322                       CompareFunc GroupChange, 
2323                       long ContextType)
2324 {
2325         SortStruct *NewSort;
2326
2327         NewSort = (SortStruct*) malloc(sizeof(SortStruct));
2328         memset(NewSort, 0, sizeof(SortStruct));
2329         NewSort->Name = NewStrBufPlain(name, len);
2330         if (prepend != NULL)
2331                 NewSort->PrefPrepend = NewStrBufPlain(prepend, preplen);
2332         else
2333                 NewSort->PrefPrepend = NULL;
2334         NewSort->Forward = Forward;
2335         NewSort->Reverse = Reverse;
2336         NewSort->GroupChange = GroupChange;
2337         NewSort->ContextType = ContextType;
2338         if (ContextType == CTX_NONE) {
2339                 lprintf(1, "sorting requires a context. CTX_NONE won't make it.\n");
2340                 exit(1);
2341         }
2342                 
2343         Put(SortHash, name, len, NewSort, DestroySortStruct);
2344 }
2345
2346 CompareFunc RetrieveSort(WCTemplputParams *TP, 
2347                          const char *OtherPrefix, long OtherPrefixLen,
2348                          const char *Default, long ldefault, long DefaultDirection)
2349 {
2350         int isdefault = 0;
2351         const StrBuf *BSort = NULL;
2352         SortStruct *SortBy;
2353         void *vSortBy;
2354         long SortOrder = -1;
2355         
2356         if (havebstr("SortBy")) {
2357                 BSort = sbstr("SortBy");
2358                 if (OtherPrefix == NULL) {
2359                         set_room_pref("sort", NewStrBufDup(BSort), 0);
2360                 }
2361                 else {
2362                         set_X_PREFS(HKEY("sort"), OtherPrefix, OtherPrefixLen, NewStrBufDup(BSort), 0);
2363                 }
2364         }
2365         else { /** Try to fallback to our remembered values... */
2366                 if (OtherPrefix == NULL) {
2367                         BSort = get_room_pref("sort");
2368                 }
2369                 else {
2370                         BSort = get_X_PREFS(HKEY("sort"), OtherPrefix, OtherPrefixLen);
2371                 }
2372                 if (BSort != NULL)
2373                         putbstr("SortBy", NewStrBufDup(BSort));
2374                 else {
2375                         StrBuf *Buf;
2376
2377                         BSort = Buf = NewStrBufPlain(Default, ldefault);
2378                         putbstr("SortBy", Buf);
2379                 }
2380         }
2381
2382         if (!GetHash(SortHash, SKEY(BSort), &vSortBy) || 
2383             (vSortBy == NULL)) {
2384                 isdefault = 1;
2385                 if (!GetHash(SortHash, Default, ldefault, &vSortBy) || 
2386                     (vSortBy == NULL)) {
2387                         LogTemplateError(
2388                                 NULL, "Sorting", ERR_PARM1, TP,
2389                                 "Illegal default sort: [%s]", Default);
2390                         wc_backtrace();
2391                 }
2392         }
2393         SortBy = (SortStruct*)vSortBy;
2394
2395         if (SortBy->ContextType != TP->Filter.ContextType)
2396                 return NULL;
2397
2398         /** Ok, its us, lets see in which direction we should sort... */
2399         if (havebstr("SortOrder")) {
2400                 SortOrder = LBSTR("SortOrder");
2401         }
2402         else { /** Try to fallback to our remembered values... */
2403                 StrBuf *Buf = NULL;
2404                 if (SortBy->PrefPrepend == NULL) {
2405                         Buf = get_room_pref("SortOrder");
2406                         SortOrder = StrTol(Buf);
2407                 }
2408                 else {
2409                         BSort = get_X_PREFS(HKEY("SortOrder"), OtherPrefix, OtherPrefixLen);
2410                 }
2411
2412                 if (Buf == NULL)
2413                         SortOrder = DefaultDirection;
2414
2415                 Buf = NewStrBufPlain(NULL, 64);
2416                 StrBufPrintf(Buf, "%ld", SortOrder);
2417                 putbstr("SortOrder", Buf);
2418         }
2419         switch (SortOrder) {
2420         default:
2421         case 0:
2422                 return NULL;
2423         case 1:
2424                 return SortBy->Forward;
2425         case 2:
2426                 return SortBy->Reverse;
2427         }
2428 }
2429
2430
2431 enum {
2432         eNO_SUCH_SORT, 
2433         eNOT_SPECIFIED,
2434         eINVALID_PARAM,
2435         eFOUND
2436 };
2437
2438 ConstStr SortIcons[] = {
2439         {HKEY("static/sort_none.gif")},
2440         {HKEY("static/up_pointer.gif")},
2441         {HKEY("static/down_pointer.gif")},
2442 };
2443
2444 ConstStr SortNextOrder[] = {
2445         {HKEY("1")},
2446         {HKEY("2")},
2447         {HKEY("0")},
2448 };
2449
2450
2451 int GetSortMetric(WCTemplputParams *TP, SortStruct **Next, SortStruct **Param, long *SortOrder, int N)
2452 {
2453         int bSortError = eNOT_SPECIFIED;
2454         const StrBuf *BSort;
2455         void *vSort;
2456         
2457         *SortOrder = 0;
2458         *Next = NULL;
2459         if (!GetHash(SortHash, TKEY(0), &vSort) || 
2460             (vSort == NULL))
2461                 return eNO_SUCH_SORT;
2462         *Param = (SortStruct*) vSort;
2463         
2464
2465         if (havebstr("SortBy")) {
2466                 BSort = sbstr("SortBy");
2467                 bSortError = eINVALID_PARAM;
2468                 if ((*Param)->PrefPrepend == NULL) {
2469                         set_room_pref("sort", NewStrBufDup(BSort), 0);
2470                 }
2471                 else {
2472                         set_X_PREFS(HKEY("sort"), TKEY(N), NewStrBufDup(BSort), 0);
2473                 }
2474         }
2475         else { /** Try to fallback to our remembered values... */
2476                 if ((*Param)->PrefPrepend == NULL) {
2477                         BSort = get_room_pref("sort");
2478                 }
2479                 else {
2480                         BSort = get_X_PREFS(HKEY("sort"), TKEY(N));
2481                 }
2482         }
2483
2484         if (!GetHash(SortHash, SKEY(BSort), &vSort) || 
2485             (vSort == NULL))
2486                 return bSortError;
2487
2488         *Next = (SortStruct*) vSort;
2489
2490         /** Ok, its us, lets see in which direction we should sort... */
2491         if (havebstr("SortOrder")) {
2492                 *SortOrder = LBSTR("SortOrder");
2493         }
2494         else { /** Try to fallback to our remembered values... */
2495                 if ((*Param)->PrefPrepend == NULL) {
2496                         *SortOrder = StrTol(get_room_pref("SortOrder"));
2497                 }
2498                 else {
2499                         *SortOrder = StrTol(get_X_PREFS(HKEY("SortOrder"), TKEY(N)));
2500                 }
2501         }
2502         if (*SortOrder > 2)
2503                 *SortOrder = 0;
2504
2505         return eFOUND;
2506 }
2507
2508
2509 void tmplput_SORT_ICON(StrBuf *Target, WCTemplputParams *TP)
2510 {
2511         long SortOrder;
2512         SortStruct *Next;
2513         SortStruct *Param;
2514         const ConstStr *SortIcon;
2515
2516         switch (GetSortMetric(TP, &Next, &Param, &SortOrder, 2)){
2517         case eNO_SUCH_SORT:
2518                 LogTemplateError(
2519                         Target, "Sorter", ERR_PARM1, TP,
2520                         " Sorter [%s] unknown!", 
2521                         TP->Tokens->Params[0]->Start);
2522                 break;          
2523         case eINVALID_PARAM:
2524                 LogTemplateError(NULL, "Sorter", ERR_PARM1, TP,
2525                                  " Sorter specified by BSTR 'SortBy' [%s] unknown!", 
2526                                  bstr("SortBy"));
2527         case eNOT_SPECIFIED:
2528         case eFOUND:
2529                 if (Next == Param) {
2530                         SortIcon = &SortIcons[SortOrder];
2531                 }
2532                 else { /** Not Us... */
2533                         SortIcon = &SortIcons[0];
2534                 }
2535                 StrBufAppendBufPlain(Target, SortIcon->Key, SortIcon->len, 0);
2536         }
2537 }
2538
2539 void tmplput_SORT_NEXT(StrBuf *Target, WCTemplputParams *TP)
2540 {
2541         long SortOrder;
2542         SortStruct *Next;
2543         SortStruct *Param;
2544
2545         switch (GetSortMetric(TP, &Next, &Param, &SortOrder, 2)){
2546         case eNO_SUCH_SORT:
2547                 LogTemplateError(
2548                         Target, "Sorter", ERR_PARM1, TP,                                  
2549                         " Sorter [%s] unknown!", 
2550                         TP->Tokens->Params[0]->Start);
2551                 break;          
2552         case eINVALID_PARAM:
2553                 LogTemplateError(
2554                         NULL, "Sorter", ERR_PARM1, TP,
2555                         " Sorter specified by BSTR 'SortBy' [%s] unknown!", 
2556                         bstr("SortBy"));
2557         case eNOT_SPECIFIED:
2558         case eFOUND:
2559                 StrBufAppendBuf(Target, Param->Name, 0);
2560                 
2561         }
2562 }
2563
2564 void tmplput_SORT_ORDER(StrBuf *Target, WCTemplputParams *TP)
2565 {
2566         long SortOrder;
2567         const ConstStr *SortOrderStr;
2568         SortStruct *Next;
2569         SortStruct *Param;
2570
2571         switch (GetSortMetric(TP, &Next, &Param, &SortOrder, 2)){
2572         case eNO_SUCH_SORT:
2573                 LogTemplateError(
2574                         Target, "Sorter", ERR_PARM1, TP,
2575                         " Sorter [%s] unknown!",
2576                         TP->Tokens->Params[0]->Start);
2577                 break;          
2578         case eINVALID_PARAM:
2579                 LogTemplateError(
2580                         NULL, "Sorter", ERR_PARM1, TP,
2581                         " Sorter specified by BSTR 'SortBy' [%s] unknown!",
2582                         bstr("SortBy"));
2583         case eNOT_SPECIFIED:
2584         case eFOUND:
2585                 if (Next == Param) {
2586                         SortOrderStr = &SortNextOrder[SortOrder];
2587                 }
2588                 else { /** Not Us... */
2589                         SortOrderStr = &SortNextOrder[0];
2590                 }
2591                 StrBufAppendBufPlain(Target, SortOrderStr->Key, SortOrderStr->len, 0);
2592         }
2593 }
2594
2595
2596 void tmplput_long_vector(StrBuf *Target, WCTemplputParams *TP)
2597 {
2598         long *LongVector = (long*) CTX;
2599
2600         if ((TP->Tokens->Params[0]->Type == TYPE_LONG) && 
2601             (TP->Tokens->Params[0]->lvalue <= LongVector[0]))
2602         {
2603                 StrBufAppendPrintf(Target, "%ld", LongVector[TP->Tokens->Params[0]->lvalue]);
2604         }
2605         else
2606         {
2607                 if (TP->Tokens->Params[0]->Type != TYPE_LONG) {
2608                         LogTemplateError(
2609                                 Target, "Longvector", ERR_NAME, TP,
2610                                 "needs a numerical Parameter!");
2611                 }
2612                 else {
2613                         LogTemplateError(
2614                                 Target, "LongVector", ERR_PARM1, TP,
2615                                 "doesn't have %ld Parameters, its just the size of %ld!", 
2616                                 TP->Tokens->Params[0]->lvalue,
2617                                 LongVector[0]);
2618                 }
2619         }
2620 }
2621
2622 void dbg_print_longvector(long *LongVector)
2623 {
2624         StrBuf *Buf = NewStrBufPlain(HKEY("Longvector: ["));
2625         int nItems = LongVector[0];
2626         int i;
2627
2628         for (i = 0; i < nItems; i++) {
2629                 if (i + 1 < nItems)
2630                         StrBufAppendPrintf(Buf, "%d: %ld | ", i, LongVector[i]);
2631                 else
2632                         StrBufAppendPrintf(Buf, "%d: %ld]\n", i, LongVector[i]);
2633
2634         }
2635         lprintf(1, ChrPtr(Buf));
2636         FreeStrBuf(&Buf);
2637 }
2638
2639 int ConditionalLongVector(StrBuf *Target, WCTemplputParams *TP)
2640 {
2641         long *LongVector = (long*) CTX;
2642
2643         if ((TP->Tokens->Params[2]->Type == TYPE_LONG) && 
2644             (TP->Tokens->Params[2]->lvalue <= LongVector[0])&&
2645             (TP->Tokens->Params[3]->Type == TYPE_LONG) && 
2646             (TP->Tokens->Params[3]->lvalue <= LongVector[0]))
2647         {
2648                 return LongVector[TP->Tokens->Params[2]->lvalue] == 
2649                         LongVector[TP->Tokens->Params[3]->lvalue];
2650         }
2651         else
2652         {
2653                 if ((TP->Tokens->Params[2]->Type == TYPE_LONG) ||
2654                     (TP->Tokens->Params[2]->Type == TYPE_LONG)) {
2655                         LogTemplateError(
2656                                 Target, "ConditionalLongvector", ERR_PARM1, TP,
2657                                 "needs two long Parameter!");
2658                 }
2659                 else {
2660                         LogTemplateError(
2661                                 Target, "Longvector", ERR_PARM1, TP,
2662                                 "doesn't have %ld / %ld Parameters, its just the size of %ld!",
2663                                 TP->Tokens->Params[2]->lvalue,
2664                                 TP->Tokens->Params[3]->lvalue,
2665                                 LongVector[0]);
2666                 }
2667         }
2668         return 0;
2669 }
2670
2671
2672 void tmplput_CURRENT_FILE(StrBuf *Target, WCTemplputParams *TP)
2673 {
2674         StrBufAppendTemplate(Target, TP, TP->Tokens->FileName, 0);
2675 }
2676
2677 void 
2678 InitModule_SUBST
2679 (void)
2680 {
2681         memset(&NoCtx, 0, sizeof(WCTemplputParams));
2682         RegisterNamespace("--", 0, 2, tmplput_Comment, NULL, CTX_NONE);
2683         RegisterNamespace("SORT:ICON", 1, 2, tmplput_SORT_ICON, NULL, CTX_NONE);
2684         RegisterNamespace("SORT:ORDER", 1, 2, tmplput_SORT_ORDER, NULL, CTX_NONE);
2685         RegisterNamespace("SORT:NEXT", 1, 2, tmplput_SORT_NEXT, NULL, CTX_NONE);
2686         RegisterNamespace("CONTEXTSTR", 0, 1, tmplput_ContextString, NULL, CTX_STRBUF);
2687         RegisterNamespace("CONTEXTSTRARR", 1, 2, tmplput_ContextStringArray, NULL, CTX_STRBUFARR);
2688         RegisterNamespace("ITERATE", 2, 100, tmpl_iterate_subtmpl, preeval_iterate, CTX_NONE);
2689         RegisterNamespace("DOBOXED", 1, 2, tmpl_do_boxed, NULL, CTX_NONE);
2690         RegisterNamespace("DOTABBED", 2, 100, tmpl_do_tabbed, preeval_do_tabbed, CTX_NONE);
2691         RegisterControlNS(HKEY("TAB:N"), 0, 0, tmplput_TAB_N, CTX_TAB);
2692         RegisterControlNS(HKEY("TAB:SUBJECT"), 0, 1, tmplput_TAB_TITLE, CTX_TAB);
2693
2694
2695         RegisterNamespace("LONGVECTOR", 1, 1, tmplput_long_vector, NULL, CTX_LONGVECTOR);
2696
2697
2698         RegisterConditional(HKEY("COND:CONTEXTSTR"), 3, ConditionalContextStr, CTX_STRBUF);
2699         RegisterConditional(HKEY("COND:CONTEXTSTRARR"), 4, ConditionalContextStrinArray, CTX_STRBUFARR);
2700         RegisterConditional(HKEY("COND:LONGVECTOR"), 4, ConditionalLongVector, CTX_LONGVECTOR);
2701
2702
2703         RegisterControlConditional(HKEY("COND:ITERATE:ISGROUPCHANGE"), 2, 
2704                                    conditional_ITERATE_ISGROUPCHANGE, 
2705                                    CTX_ITERATE);
2706         RegisterControlConditional(HKEY("COND:ITERATE:LASTN"), 2, 
2707                                    conditional_ITERATE_LASTN, 
2708                                    CTX_ITERATE);
2709         RegisterControlConditional(HKEY("COND:ITERATE:FIRSTN"), 2, 
2710                                    conditional_ITERATE_FIRSTN, 
2711                                    CTX_ITERATE);
2712
2713         RegisterControlNS(HKEY("ITERATE:ODDEVEN"), 0, 0, tmplput_ITERATE_ODDEVEN, CTX_ITERATE);
2714         RegisterControlNS(HKEY("ITERATE:KEY"), 0, 0, tmplput_ITERATE_KEY, CTX_ITERATE);
2715         RegisterControlNS(HKEY("ITERATE:N"), 0, 0, tmplput_ITERATE_LASTN, CTX_ITERATE);
2716         RegisterNamespace("CURRENTFILE", 0, 1, tmplput_CURRENT_FILE, NULL, CTX_NONE);
2717         RegisterNamespace("DEF:STR", 1, 1, tmplput_DefStr, NULL, CTX_NONE);
2718         RegisterNamespace("DEF:VAL", 1, 1, tmplput_DefVal, NULL, CTX_NONE);
2719
2720
2721
2722
2723 }
2724
2725 void
2726 ServerStartModule_SUBST
2727 (void)
2728 {
2729         WirelessTemplateCache = NewHash(1, NULL);
2730         WirelessLocalTemplateCache = NewHash(1, NULL);
2731         LocalTemplateCache = NewHash(1, NULL);
2732         TemplateCache = NewHash(1, NULL);
2733
2734         GlobalNS = NewHash(1, NULL);
2735         Iterators = NewHash(1, NULL);
2736         Conditionals = NewHash(1, NULL);
2737         SortHash = NewHash(1, NULL);
2738         Defines = NewHash(1, NULL);
2739 }
2740
2741 void
2742 FinalizeModule_SUBST
2743 (void)
2744 {
2745
2746 }
2747
2748 void 
2749 ServerShutdownModule_SUBST
2750 (void)
2751 {
2752         DeleteHash(&WirelessTemplateCache);
2753         DeleteHash(&WirelessLocalTemplateCache);
2754         DeleteHash(&TemplateCache);
2755         DeleteHash(&LocalTemplateCache);
2756
2757         DeleteHash(&GlobalNS);
2758         DeleteHash(&Iterators);
2759         DeleteHash(&Conditionals);
2760         DeleteHash(&SortHash);
2761         DeleteHash(&Defines);
2762 }
2763
2764
2765 void
2766 SessionNewModule_SUBST
2767 (wcsession *sess)
2768 {
2769
2770 }
2771
2772 void
2773 SessionAttachModule_SUBST
2774 (wcsession *sess)
2775 {
2776 }
2777
2778 void
2779 SessionDetachModule_SUBST
2780 (wcsession *sess)
2781 {
2782         FreeStrBuf(&sess->WFBuf);
2783 }
2784
2785 void 
2786 SessionDestroyModule_SUBST  
2787 (wcsession *sess)
2788 {
2789
2790 }