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