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