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