Back to index

webcit  8.12-dfsg
subst.c
Go to the documentation of this file.
00001 #include "sysdep.h"
00002 
00003 
00004 #include <sys/types.h>
00005 #include <sys/stat.h>
00006 #include <dirent.h>
00007 #include <errno.h>
00008 
00009 #include <unistd.h>
00010 #include <stdio.h>
00011 #include <stdarg.h>
00012 #include <stddef.h>
00013 
00014 #define SHOW_ME_VAPPEND_PRINTF
00015 
00016 #include "webcit.h"
00017 #include "webserver.h"
00018 
00019 extern char *static_dirs[PATH_MAX];  /* Disk representation */
00020 
00021 HashList *TemplateCache;
00022 HashList *LocalTemplateCache;
00023 
00024 HashList *GlobalNS;
00025 HashList *Iterators;
00026 HashList *Conditionals;
00027 HashList *SortHash;
00028 HashList *Defines;
00029 
00030 int DumpTemplateI18NStrings = 0;
00031 int LoadTemplates = 0;
00032 int dbg_backtrace_template_errors = 0;
00033 WCTemplputParams NoCtx;
00034 StrBuf *I18nDump = NULL;
00035 
00036 const char EmptyStr[]="";
00037 
00038 #define SV_GETTEXT 1
00039 #define SV_CONDITIONAL 2
00040 #define SV_NEG_CONDITIONAL 3
00041 #define SV_CUST_STR_CONDITIONAL 4
00042 #define SV_SUBTEMPL 5
00043 #define SV_PREEVALUATED 6
00044 
00045 
00046 /*
00047  * Dynamic content for variable substitution in templates
00048  */
00049 typedef struct _wcsubst {
00050        ContextFilter Filter;
00051        int wcs_type;                      /* which type of Substitution are we */
00052        char wcs_key[32];                  /* copy of our hashkey for debugging */
00053        StrBuf *wcs_value;                 /* if we're a string, keep it here */
00054        long lvalue;                       /* type long? keep data here */
00055        WCHandlerFunc wcs_function;        /* funcion hook ???*/
00056 } wcsubst;
00057 
00058 
00059 typedef struct _WCTemplate {
00060        StrBuf *Data;
00061        StrBuf *FileName;
00062        int nTokensUsed;
00063        int TokenSpace;
00064        StrBuf *MimeType;
00065        WCTemplateToken **Tokens;
00066 } WCTemplate;
00067 
00068 typedef struct _HashHandler {
00069        ContextFilter Filter;
00070        WCPreevalFunc PreEvalFunc;
00071        WCHandlerFunc HandlerFunc;
00072 }HashHandler;
00073 
00074 void *load_template(StrBuf *Target, WCTemplate *NewTemplate);
00075 int EvaluateConditional(StrBuf *Target, int Neg, int state, WCTemplputParams *TP);
00076 
00077 
00078 
00079 typedef struct _SortStruct {
00080        StrBuf *Name;
00081        StrBuf *PrefPrepend;
00082        CompareFunc Forward;
00083        CompareFunc Reverse;
00084        CompareFunc GroupChange;
00085 
00086        long ContextType;
00087 }SortStruct;
00088 
00089 const char *CtxNames[]  = {
00090        "Context NONE",
00091        "Context SITECFG",
00092        "Context SESSION",
00093        "Context INETCFG",
00094        "Context VNOTE",
00095        "Context WHO",
00096        "Context PREF",
00097        "Context NODECONF",
00098        "Context USERLIST",
00099        "Context MAILSUM",
00100        "Context MIME_ATACH",
00101        "Context FILELIST",
00102        "Context STRBUF",
00103        "Context STRBUFARR",
00104        "Context LONGVECTOR",
00105        "Context ROOMS",
00106        "Context FLOORS",
00107        "Context ITERATE",
00108        "Context ICAL",
00109        "Context DavNamespace",
00110        "Context TAB",
00111        "Context VCARD",
00112        "Context SIEVE List",
00113        "Context SIEVE Script",
00114        "Context MailQ-Item",
00115        "Context MailQ-Recipient",
00116        "Context ServLogStatus",
00117        "Context UNKNOWN"
00118 };
00119 
00120 
00121 
00122 void DestroySortStruct(void *vSort)
00123 {
00124        SortStruct *Sort = (SortStruct*) vSort;
00125        FreeStrBuf(&Sort->Name);
00126        FreeStrBuf(&Sort->PrefPrepend);
00127        free (Sort);
00128 }
00129 
00130 const char *ContextName(int ContextType)
00131 {
00132        if (ContextType < CTX_UNKNOWN)
00133               return CtxNames[ContextType];
00134        else
00135               return CtxNames[CTX_UNKNOWN];
00136 }
00137 
00138 void LogTemplateError (StrBuf *Target, const char *Type, int ErrorPos, WCTemplputParams *TP, const char *Format, ...)
00139 {
00140        wcsession *WCC;
00141        StrBuf *Error;
00142        StrBuf *Info;
00143         va_list arg_ptr;
00144        const char *Err = NULL;
00145 
00146        Info = NewStrBuf();
00147        Error = NewStrBuf();
00148 
00149         va_start(arg_ptr, Format);
00150        StrBufVAppendPrintf(Error, Format, arg_ptr);
00151        va_end(arg_ptr);
00152 
00153        switch (ErrorPos) {
00154        case ERR_NAME: /* the main token name... */ 
00155               Err = (TP->Tokens!= NULL)? TP->Tokens->pName:"";
00156               break;
00157        default:
00158               Err = ((TP->Tokens!= NULL) && 
00159                      (TP->Tokens->nParameters > ErrorPos - 1))? 
00160                      TP->Tokens->Params[ErrorPos - 1]->Start : "";
00161               break;
00162        }
00163        if (TP->Tokens != NULL) 
00164        {
00165               syslog(1, "%s [%s]  (in '%s' line %ld); %s; [%s]\n", 
00166                      Type, 
00167                      Err, 
00168                      ChrPtr(TP->Tokens->FileName),
00169                      TP->Tokens->Line, 
00170                      ChrPtr(Error), 
00171                      ChrPtr(TP->Tokens->FlatToken));
00172        }
00173        else 
00174        {
00175               syslog(1, "%s: %s;\n", 
00176                      Type, 
00177                      ChrPtr(Error));
00178        }
00179 /*
00180        if (Target == NULL) 
00181               return;
00182 */
00183        WCC = WC;
00184        if (WCC == NULL) {
00185               FreeStrBuf(&Info);
00186               FreeStrBuf(&Error);
00187               return; 
00188        }
00189 
00190        if (WCC->WFBuf == NULL) WCC->WFBuf = NewStrBuf();
00191        if (TP->Tokens != NULL) 
00192        {
00193               /* deprecated: 
00194               StrBufAppendPrintf(                                                          
00195                      Target,                                                              
00196                      "<pre>\n%s [%s] (in '%s' line %ld); %s\n[%s]\n</pre>\n",
00197                      Type, 
00198                      Err, 
00199                      ChrPtr(TP->Tokens->FileName),
00200                      TP->Tokens->Line,
00201                      ChrPtr(Error),
00202                      ChrPtr(TP->Tokens->FlatToken));
00203               */
00204               StrBufPrintf(Info, "%s [%s]  %s; [%s]", 
00205                           Type, 
00206                           Err, 
00207                           ChrPtr(Error), 
00208                           ChrPtr(TP->Tokens->FlatToken));
00209 
00210 
00211               SerializeJson(WCC->WFBuf, WildFireException(SKEY(TP->Tokens->FileName),
00212                                                  TP->Tokens->Line,
00213                                                  Info,
00214                                                  1), 1);
00215 /*
00216               SerializeJson(Header, WildFireMessage(SKEY(TP->Tokens->FileName),
00217                                                 TP->Tokens->Line,
00218                                                 Error,
00219                                                 eERROR), 1);
00220 */
00221               
00222        }
00223        else
00224        {
00225               /* deprecated.
00226               StrBufAppendPrintf(                                                          
00227                      Target,                                                              
00228                      "<pre>\n%s: %s\n</pre>\n",
00229                      Type, 
00230                      ChrPtr(Error));
00231               */
00232               StrBufPrintf(Info, "%s [%s]  %s; [%s]", 
00233                           Type, 
00234                           Err, 
00235                           ChrPtr(Error), 
00236                           ChrPtr(TP->Tokens->FlatToken));
00237               SerializeJson(WCC->WFBuf, WildFireException(HKEY(__FILE__), __LINE__, Info, 1), 1);
00238        }
00239        FreeStrBuf(&Info);
00240        FreeStrBuf(&Error);
00241 /*
00242        if (dbg_backtrace_template_errors)
00243               wc_backtrace(); 
00244 */
00245 }
00246 
00247 
00248 
00249 
00250 void LogError (StrBuf *Target, const char *Type, const char *Format, ...)
00251 {
00252        wcsession *WCC;
00253        StrBuf *Error;
00254        StrBuf *Info;
00255         va_list arg_ptr;
00256 
00257        Info = NewStrBuf();
00258        Error = NewStrBuf();
00259 
00260         va_start(arg_ptr, Format);
00261        StrBufVAppendPrintf(Error, Format, arg_ptr);
00262        va_end(arg_ptr);
00263 
00264        syslog(1, "%s", ChrPtr(Error));
00265 
00266        WCC = WC;
00267        if (WCC->WFBuf == NULL) WCC->WFBuf = NewStrBuf();
00268 
00269        SerializeJson(WCC->WFBuf, WildFireException(Type, strlen(Type),
00270                                               0,
00271                                               Info,
00272                                               1), 1);
00273 
00274        FreeStrBuf(&Info);
00275        FreeStrBuf(&Error);
00276 /*
00277        if (dbg_backtrace_template_errors)
00278               wc_backtrace(); 
00279 */
00280 }
00281 
00282 
00283 void RegisterNS(const char *NSName, 
00284               long len, 
00285               int nMinArgs, 
00286               int nMaxArgs, 
00287               WCHandlerFunc HandlerFunc, 
00288               WCPreevalFunc PreevalFunc,
00289               int ContextRequired)
00290 {
00291        HashHandler *NewHandler;
00292        
00293        NewHandler = (HashHandler*) malloc(sizeof(HashHandler));
00294        memset(NewHandler, 0, sizeof(HashHandler));
00295        NewHandler->Filter.nMinArgs = nMinArgs;
00296        NewHandler->Filter.nMaxArgs = nMaxArgs;
00297        NewHandler->Filter.ContextType = ContextRequired;
00298        NewHandler->Filter.ControlContextType = CTX_NONE;
00299 
00300        NewHandler->PreEvalFunc = PreevalFunc;
00301        NewHandler->HandlerFunc = HandlerFunc;    
00302        Put(GlobalNS, NSName, len, NewHandler, NULL);
00303 }
00304 
00305 void RegisterControlNS(const char *NSName, 
00306                      long len, 
00307                      int nMinArgs, 
00308                      int nMaxArgs, 
00309                      WCHandlerFunc HandlerFunc, 
00310                      int ControlContextRequired)
00311 {
00312        HashHandler *NewHandler;
00313        
00314        NewHandler = (HashHandler*) malloc(sizeof(HashHandler));
00315        memset(NewHandler, 0, sizeof(HashHandler));
00316        NewHandler->Filter.nMinArgs = nMinArgs;
00317        NewHandler->Filter.nMaxArgs = nMaxArgs;
00318        NewHandler->Filter.ContextType = CTX_NONE;
00319        NewHandler->Filter.ControlContextType = ControlContextRequired;
00320        NewHandler->HandlerFunc = HandlerFunc;    
00321        Put(GlobalNS, NSName, len, NewHandler, NULL);
00322 }
00323 
00324 
00325 
00326 int CheckContext(StrBuf *Target, ContextFilter *Need, WCTemplputParams *TP, const char *ErrType)
00327 {
00328        if ((Need->ContextType != CTX_NONE) && 
00329            (Need->ContextType != TP->Filter.ContextType)) {
00330                 LogTemplateError(
00331                         Target, ErrType, ERR_PARM1, TP,
00332                      "  WARNING: requires Context: [%s], have [%s]!", 
00333                      ContextName(Need->ContextType), 
00334                      ContextName(TP->Filter.ContextType));
00335               return 0;
00336        }
00337 
00338        if ((Need->ControlContextType != CTX_NONE) && 
00339            (Need->ControlContextType != TP->Filter.ControlContextType)) {
00340                 LogTemplateError(
00341                         Target, ErrType, ERR_PARM1, TP,
00342                      "  WARNING: requires Control Context: [%s], have [%s]!", 
00343                      ContextName(Need->ControlContextType), 
00344                      ContextName(TP->Filter.ControlContextType));
00345               return 0;
00346        }
00347 /*                   
00348        if (TP->Tokens->nParameters < Need->nMinArgs) {
00349               LogTemplateError(Target, ErrType, ERR_NAME, TP,
00350                              "needs at least %ld params, have %ld", 
00351                              Need->nMinArgs, 
00352                              TP->Tokens->nParameters);
00353               return 0;
00354 
00355        }
00356        else if (TP->Tokens->nParameters > Need->nMaxArgs) {
00357               LogTemplateError(Target, ErrType, ERR_NAME, TP,
00358                              "just needs %ld params, you gave %ld",
00359                              Need->nMaxArgs,
00360                              TP->Tokens->nParameters); 
00361               return 0;
00362 
00363        }
00364 */
00365        return 1;
00366 }
00367 
00368 void FreeToken(WCTemplateToken **Token)
00369 {
00370        int i; 
00371        FreeStrBuf(&(*Token)->FlatToken);
00372        if ((*Token)->HaveParameters) 
00373               for (i = 0; i < (*Token)->nParameters; i++)
00374                      free((*Token)->Params[i]);
00375        free(*Token);
00376        *Token = NULL;
00377 }
00378 
00379 
00380 
00381 void FreeWCTemplate(void *vFreeMe)
00382 {
00383        int i;
00384        WCTemplate *FreeMe = (WCTemplate*)vFreeMe;
00385 
00386        if (FreeMe->TokenSpace > 0) {
00387               for (i = 0; i < FreeMe->nTokensUsed; i ++) {
00388                      FreeToken(&FreeMe->Tokens[i]);
00389               }
00390               free(FreeMe->Tokens);
00391        }
00392        FreeStrBuf(&FreeMe->FileName);
00393        FreeStrBuf(&FreeMe->Data);
00394        FreeStrBuf(&FreeMe->MimeType);
00395        free(FreeMe);
00396 }
00397 
00398 int HaveTemplateTokenString(StrBuf *Target, 
00399                          WCTemplputParams *TP,
00400                          int N,
00401                          const char **Value, 
00402                          long *len)
00403 {
00404        if (N >= TP->Tokens->nParameters) {
00405               return 0;
00406        }
00407 
00408        switch (TP->Tokens->Params[N]->Type) {
00409        case TYPE_INTDEFINE:
00410        case TYPE_STR:
00411        case TYPE_BSTR:
00412        case TYPE_PREFSTR:
00413        case TYPE_GETTEXT:
00414        case TYPE_SUBTEMPLATE:
00415               return 1;
00416        case TYPE_LONG:
00417        case TYPE_PREFINT:
00418        default:
00419               return 0;
00420        }
00421 }
00422 
00423 void GetTemplateTokenString(StrBuf *Target, 
00424                          WCTemplputParams *TP,
00425                          int N,
00426                          const char **Value, 
00427                          long *len)
00428 {
00429        StrBuf *Buf;
00430        WCTemplputParams SubTP;
00431 
00432        if (N >= TP->Tokens->nParameters) {
00433               LogTemplateError(Target, 
00434                              "TokenParameter", N, TP, 
00435                              "invalid token %d. this shouldn't have come till here.\n", N);
00436               *Value = "";
00437               *len = 0;
00438               return;
00439        }
00440 
00441        switch (TP->Tokens->Params[N]->Type) {
00442 
00443        case TYPE_INTDEFINE:
00444        case TYPE_STR:
00445               *Value = TP->Tokens->Params[N]->Start;
00446               *len = TP->Tokens->Params[N]->len;
00447               break;
00448        case TYPE_BSTR:
00449               if (TP->Tokens->Params[N]->len == 0) {
00450                      LogTemplateError(Target, 
00451                                     "TokenParameter", N, TP, 
00452                                     "Requesting parameter %d; of type BSTR, empty lookup string not admitted.", N);
00453                      *len = 0;
00454                      *Value = EmptyStr;
00455                      break;
00456               }
00457               Buf = (StrBuf*) SBstr(TKEY(N));
00458               *Value = ChrPtr(Buf);
00459               *len = StrLength(Buf);
00460               break;
00461        case TYPE_PREFSTR:
00462               if (TP->Tokens->Params[N]->len == 0) {
00463                      LogTemplateError(Target, 
00464                                     "TokenParameter", N, TP, 
00465                                     "Requesting parameter %d; of type PREFSTR, empty lookup string not admitted.", N);
00466                      *len = 0;
00467                      *Value = EmptyStr;
00468                      break;
00469               }
00470               get_PREFERENCE(TKEY(N), &Buf);
00471               *Value = ChrPtr(Buf);
00472               *len = StrLength(Buf);
00473               break;
00474        case TYPE_LONG:
00475               LogTemplateError(Target, 
00476                              "TokenParameter", N, TP, 
00477                              "Requesting parameter %d; of type LONG, want string.", N);
00478               break;
00479        case TYPE_PREFINT:
00480               LogTemplateError(Target, 
00481                              "TokenParameter", N, TP, 
00482                              "Requesting parameter %d; of type PREFINT, want string.", N);
00483               break;
00484        case TYPE_GETTEXT:
00485               *Value = _(TP->Tokens->Params[N]->Start);
00486               *len = strlen(*Value);
00487               break;
00488        case TYPE_SUBTEMPLATE:
00489               if (TP->Tokens->Params[N]->len == 0) {
00490                      LogTemplateError(Target, 
00491                                     "TokenParameter", N, TP, 
00492                                     "Requesting parameter %d; of type SUBTEMPLATE, empty lookup string not admitted.", N);
00493                      *len = 0;
00494                      *Value = EmptyStr;
00495                      break;
00496               }
00497 
00498               memset(&SubTP, 0, sizeof(WCTemplputParams *));
00499               SubTP.Context = TP->Context;
00500               SubTP.Filter.ContextType = TP->Filter.ContextType;
00501               Buf = NewStrBuf();
00502               DoTemplate(TKEY(N), Buf, &SubTP);
00503               *Value = ChrPtr(Buf);
00504               *len = StrLength(Buf);
00505               /* we can't free it here, so we put it into the subst so its discarded later on. */
00506               PutRequestLocalMem(Buf, HFreeStrBuf);
00507               break;
00508 
00509        default:
00510               LogTemplateError(Target, 
00511                              "TokenParameter", N, TP, 
00512                              "unknown param type %d; [%d]", N, TP->Tokens->Params[N]->Type);
00513               break;
00514        }
00515 }
00516 
00517 long GetTemplateTokenNumber(StrBuf *Target, WCTemplputParams *TP, int N, long dflt)
00518 {
00519        long Ret;
00520        if (N >= TP->Tokens->nParameters) {
00521               LogTemplateError(Target, 
00522                              "TokenParameter", N, TP, 
00523                              "invalid token %d. this shouldn't have come till here.\n", N);
00524               wc_backtrace(); 
00525               return 0;
00526        }
00527 
00528        switch (TP->Tokens->Params[N]->Type) {
00529 
00530        case TYPE_STR:
00531               return atol(TP->Tokens->Params[N]->Start);
00532               break;
00533        case TYPE_BSTR:
00534               if (TP->Tokens->Params[N]->len == 0) {
00535                      LogTemplateError(Target, 
00536                                     "TokenParameter", N, TP, 
00537                                     "Requesting parameter %d; of type BSTR, empty lookup string not admitted.", N);
00538                      return 0;
00539               }
00540               return  LBstr(TKEY(N));
00541               break;
00542        case TYPE_PREFSTR:
00543               LogTemplateError(Target, 
00544                              "TokenParameter", N, TP, 
00545                              "requesting a prefstring in param %d want a number", N);
00546               if (TP->Tokens->Params[N]->len == 0) {
00547                      LogTemplateError(Target, 
00548                                     "TokenParameter", N, TP, 
00549                                     "Requesting parameter %d; of type PREFSTR, empty lookup string not admitted.", N);
00550                      return 0;
00551               }
00552               if (get_PREF_LONG(TKEY(N), &Ret, dflt))
00553                      return Ret;
00554               return 0;
00555        case TYPE_INTDEFINE:
00556        case TYPE_LONG:
00557               return TP->Tokens->Params[N]->lvalue;
00558        case TYPE_PREFINT:
00559               if (TP->Tokens->Params[N]->len == 0) {
00560                      LogTemplateError(Target, 
00561                                     "TokenParameter", N, TP, 
00562                                     "Requesting parameter %d; of type PREFINT, empty lookup string not admitted.", N);
00563                      return 0;
00564               }
00565               if (get_PREF_LONG(TKEY(N), &Ret, dflt))
00566                      return Ret;
00567               return 0;            
00568        case TYPE_GETTEXT:
00569               LogTemplateError(Target, 
00570                              "TokenParameter", N, TP, 
00571                              "requesting a I18N string in param %d; want a number", N);
00572               return 0;
00573        case TYPE_SUBTEMPLATE:
00574               LogTemplateError(Target, 
00575                              "TokenParameter", N, TP, 
00576                              "requesting a subtemplate in param %d; not supported for numbers", N);
00577               return 0;
00578        default:
00579               LogTemplateError(Target, 
00580                              "TokenParameter", N, TP, 
00581                              "unknown param type %d; [%d]", N, TP->Tokens->Params[N]->Type);
00582               return 0;
00583        }
00584 }
00585 
00586 
00587 /*
00588  * puts string into the template and computes which escape methon we should use
00589  * Source = the string we should put into the template
00590  * FormatTypeIndex = where should we look for escape types if?
00591  */
00592 void StrBufAppendTemplate(StrBuf *Target, 
00593                        WCTemplputParams *TP,
00594                        const StrBuf *Source, int FormatTypeIndex)
00595 {
00596        const char *pFmt = NULL;
00597        char EscapeAs = ' ';
00598 
00599        if ((FormatTypeIndex < TP->Tokens->nParameters) &&
00600            (TP->Tokens->Params[FormatTypeIndex]->Type == TYPE_STR) &&
00601            (TP->Tokens->Params[FormatTypeIndex]->len >= 1)) {
00602               pFmt = TP->Tokens->Params[FormatTypeIndex]->Start;
00603               EscapeAs = *pFmt;
00604        }
00605 
00606        switch(EscapeAs)
00607        {
00608        case 'H':
00609               StrEscAppend(Target, Source, NULL, 0, 2);
00610               break;
00611        case 'X':
00612               StrEscAppend(Target, Source, NULL, 0, 0);
00613               break;
00614        case 'J':
00615               StrECMAEscAppend(Target, Source, NULL);
00616          break;
00617        case 'K':
00618               StrHtmlEcmaEscAppend(Target, Source, NULL, 0, 0);
00619          break;
00620        case 'U':
00621               StrBufUrlescAppend(Target, Source, NULL);
00622               break;
00623        case 'F':
00624               if (pFmt != NULL)    pFmt++;
00625               else                 pFmt = "JUSTIFY";
00626               if (*pFmt == '\0')   pFmt = "JUSTIFY";
00627               FmOut(Target, pFmt, Source);
00628               break;
00629        default:
00630               StrBufAppendBuf(Target, Source, 0);
00631        }
00632 }
00633 
00634 
00635 void PutNewToken(WCTemplate *Template, WCTemplateToken *NewToken)
00636 {
00637        if (Template->nTokensUsed + 1 >= Template->TokenSpace) {
00638               if (Template->TokenSpace <= 0) {
00639                      Template->Tokens = (WCTemplateToken**)malloc(
00640                             sizeof(WCTemplateToken*) * 10);
00641                      memset(Template->Tokens, 0, sizeof(WCTemplateToken*) * 10);
00642                      Template->TokenSpace = 10;
00643               }
00644               else {
00645                      WCTemplateToken **NewTokens;
00646 
00647                      NewTokens= (WCTemplateToken**) malloc(
00648                             sizeof(WCTemplateToken*) * Template->TokenSpace * 2);
00649 
00650                      memset(NewTokens, 
00651                             0, sizeof(WCTemplateToken*) * Template->TokenSpace * 2);
00652 
00653                      memcpy(NewTokens, 
00654                             Template->Tokens, 
00655                             sizeof(WCTemplateToken*) * Template->nTokensUsed);
00656 
00657                      free(Template->Tokens);
00658                      Template->TokenSpace *= 2;
00659                      Template->Tokens = NewTokens;
00660               }
00661        }
00662        Template->Tokens[(Template->nTokensUsed)++] = NewToken;
00663 }
00664 
00665 int GetNextParameter(StrBuf *Buf, 
00666                    const char **pCh, 
00667                    const char *pe, 
00668                    WCTemplateToken *Tokens, 
00669                    WCTemplate *pTmpl, 
00670                    WCTemplputParams *TP, 
00671                    TemplateParam **pParm)
00672 {
00673        const char *pch = *pCh;
00674        const char *pchs, *pche;
00675        TemplateParam *Parm;
00676        char quote = '\0';
00677        int ParamBrace = 0;
00678 
00679        *pParm = Parm = (TemplateParam *) malloc(sizeof(TemplateParam));
00680        memset(Parm, 0, sizeof(TemplateParam));
00681        Parm->Type = TYPE_STR;
00682 
00683        /* Skip leading whitespaces */
00684        while ((*pch == ' ' )||
00685               (*pch == '\t')||
00686               (*pch == '\r')||
00687               (*pch == '\n')) pch ++;
00688 
00689        if (*pch == ':') {
00690               Parm->Type = TYPE_PREFSTR;
00691               pch ++;
00692               if (*pch == '(') {
00693                      pch ++;
00694                      ParamBrace = 1;
00695               }
00696        }
00697        else if (*pch == ';') {
00698               Parm->Type = TYPE_PREFINT;
00699               pch ++;
00700               if (*pch == '(') {
00701                      pch ++;
00702                      ParamBrace = 1;
00703               }
00704        }
00705        else if (*pch == '#') {
00706               Parm->Type = TYPE_INTDEFINE;
00707               pch ++;
00708        }
00709        else if (*pch == '_') {
00710               Parm->Type = TYPE_GETTEXT;
00711               pch ++;
00712               if (*pch == '(') {
00713                      pch ++;
00714                      ParamBrace = 1;
00715               }
00716        }
00717        else if (*pch == 'B') {
00718               Parm->Type = TYPE_BSTR;
00719               pch ++;
00720               if (*pch == '(') {
00721                      pch ++;
00722                      ParamBrace = 1;
00723               }
00724        }
00725        else if (*pch == '=') {
00726               Parm->Type = TYPE_SUBTEMPLATE;
00727               pch ++;
00728               if (*pch == '(') {
00729                      pch ++;
00730                      ParamBrace = 1;
00731               }
00732        }
00733 
00734 
00735        if (*pch == '"')
00736               quote = '"';
00737        else if (*pch == '\'')
00738               quote = '\'';
00739        if (quote != '\0') {
00740               pch ++;
00741               pchs = pch;
00742               while (pch <= pe &&
00743                      ((*pch != quote) ||
00744                      ( (pch > pchs) && (*(pch - 1) == '\\'))
00745                             )) {
00746                      pch ++;
00747               }
00748               pche = pch;
00749               if (*pch != quote) {
00750                      syslog(1, "Error (in '%s' line %ld); "
00751                             "evaluating template param [%s] in Token [%s]\n",
00752                             ChrPtr(pTmpl->FileName),
00753                             Tokens->Line,
00754                             ChrPtr(Tokens->FlatToken),
00755                             *pCh);
00756                      pch ++;
00757                      free(Parm);
00758                      *pParm = NULL;
00759                      return 0;
00760               }
00761               else {
00762                      StrBufPeek(Buf, pch, -1, '\0');           
00763                      if (LoadTemplates > 1) {                  
00764                             syslog(1,
00765                                    "DBG: got param [%s] %d %d\n", 
00766                                    pchs, pche - pchs, strlen(pchs)
00767                             );
00768                      }
00769                      Parm->Start = pchs;
00770                      Parm->len = pche - pchs;
00771                      pch ++; /* move after trailing quote */
00772                      if (ParamBrace && (*pch == ')')) {
00773                             pch ++;
00774                      }
00775 
00776               }
00777        }
00778        else {
00779               Parm->Type = TYPE_LONG;
00780               pchs = pch;
00781               while ((pch <= pe) &&
00782                      (isdigit(*pch) ||
00783                      (*pch == '+') ||
00784                      (*pch == '-')))
00785                      pch ++;
00786               pch ++;
00787               if (pch - pchs > 1){
00788                      StrBufPeek(Buf, pch, -1, '\0');
00789                      Parm->lvalue = atol(pchs);
00790                      Parm->Start = pchs;
00791                      pch++;
00792               }
00793               else {
00794                      Parm->lvalue = 0;
00795 /* TODO whUT?
00796                      syslog(1, "Error (in '%s' line %ld); "
00797                             "evaluating long template param [%s] in Token [%s]\n",
00798                             ChrPtr(pTmpl->FileName),
00799                             Tokens->Line,
00800                             ChrPtr(Tokens->FlatToken),
00801                             *pCh);
00802                             */
00803                      free(Parm);
00804                      *pParm = NULL;
00805                      return 0;
00806               }
00807        }
00808        while ((*pch == ' ' )||
00809               (*pch == '\t')||
00810               (*pch == '\r')||
00811               (*pch == ',' )||
00812               (*pch == '\n')) pch ++;
00813 
00814        switch (Parm->Type)
00815        {
00816        case TYPE_GETTEXT:
00817               if (DumpTemplateI18NStrings) {
00818                      StrBufAppendPrintf(I18nDump, "_(\"%s\");\n", Parm->Start);
00819               }
00820               break;
00821        case TYPE_INTDEFINE: {
00822               void *vPVal;
00823               
00824               if (GetHash(Defines, Parm->Start, Parm->len, &vPVal) &&
00825                   (vPVal != NULL))
00826               {
00827                      long *PVal;
00828                      PVal = (long*) vPVal;
00829               
00830                      Parm->lvalue = *PVal;
00831               }
00832               else if (strchr(Parm->Start, '|') != NULL)
00833               {
00834                      const char *Pos;
00835                      StrBuf *pToken;
00836                      StrBuf *Match;
00837 
00838                      Parm->MaskBy = eOR;
00839                      pToken = NewStrBufPlain (Parm->Start, Parm->len);
00840                      Match = NewStrBufPlain (NULL, Parm->len);
00841                      Pos = ChrPtr(pToken);
00842                      
00843                      while ((Pos != NULL) && (Pos != StrBufNOTNULL))
00844                      {
00845                             StrBufExtract_NextToken(Match, pToken, &Pos, '|');
00846                             StrBufTrim(Match);
00847                             if (StrLength (Match) > 0)
00848                             {
00849                                    if (GetHash(Defines, SKEY(Match), &vPVal) &&
00850                                        (vPVal != NULL))
00851                                    {
00852                                           long *PVal;
00853                                           PVal = (long*) vPVal;
00854                                           
00855                                           Parm->lvalue |= *PVal;
00856                                    }
00857                                    else {
00858                                           LogTemplateError(NULL, "Define", 
00859                                                          Tokens->nParameters,
00860                                                          TP,
00861                                                          "%s isn't known!!",
00862                                                          ChrPtr(Match));
00863 
00864                                    }
00865                             }
00866                      }
00867                      FreeStrBuf(&pToken);
00868                      FreeStrBuf(&Match);
00869               }
00870               else if (strchr(Parm->Start, '&') != NULL)
00871               {
00872                      const char *Pos;
00873                      StrBuf *pToken;
00874                      StrBuf *Match;
00875 
00876                      Parm->MaskBy = eAND;
00877                      pToken = NewStrBufPlain (Parm->Start, Parm->len);
00878                      Match = NewStrBufPlain (NULL, Parm->len);
00879                      Pos = ChrPtr(pToken);
00880                      
00881                      while ((Pos != NULL) && (Pos != StrBufNOTNULL))
00882                      {
00883                             StrBufExtract_NextToken(Match, pToken, &Pos, '&');
00884                             StrBufTrim(Match);
00885                             if (StrLength (Match) > 0)
00886                             {
00887                                    if (GetHash(Defines, SKEY(Match), &vPVal) &&
00888                                        (vPVal != NULL))
00889                                    {
00890                                           long *PVal;
00891                                           PVal = (long*) vPVal;
00892                                           
00893                                           Parm->lvalue |= *PVal;
00894                                    }
00895                                    else {
00896                                           LogTemplateError(NULL, "Define", 
00897                                                          Tokens->nParameters,
00898                                                          TP,
00899                                                          "%s isn't known!!",
00900                                                          ChrPtr(Match));
00901 
00902                                    }
00903                             }
00904                      }
00905                      FreeStrBuf(&Match);
00906                      FreeStrBuf(&pToken);
00907               }
00908               else {
00909 
00910 
00911                      LogTemplateError(NULL, "Define", 
00912                                     Tokens->nParameters,
00913                                     TP,
00914                                     "%s isn't known!!",
00915                                     Parm->Start);
00916               }}
00917               break;
00918        case TYPE_SUBTEMPLATE:{
00919               void *vTmpl;
00920               /* well, we don't check the mobile stuff here... */
00921               if (!GetHash(LocalTemplateCache, Parm->Start, Parm->len, &vTmpl) &&
00922                   !GetHash(TemplateCache, Parm->Start, Parm->len, &vTmpl)) {
00923                      LogTemplateError(NULL, 
00924                                     "SubTemplate", 
00925                                     Tokens->nParameters,
00926                                     TP,
00927                                     "referenced here doesn't exist");
00928               }}
00929               break;
00930        }
00931        *pCh = pch;
00932        return 1;
00933 }
00934 
00935 WCTemplateToken *NewTemplateSubstitute(StrBuf *Buf, 
00936                                    const char *pStart, 
00937                                    const char *pTokenStart, 
00938                                    const char *pTokenEnd, 
00939                                    long Line,
00940                                    WCTemplate *pTmpl)
00941 {
00942        void *vVar;
00943        const char *pch;
00944        WCTemplateToken *NewToken;
00945        WCTemplputParams TP;
00946 
00947        NewToken = (WCTemplateToken*)malloc(sizeof(WCTemplateToken));
00948        memset(NewToken, 0, sizeof(WCTemplateToken));
00949        TP.Tokens = NewToken;
00950        NewToken->FileName = pTmpl->FileName; /* to print meaningfull log messages... */
00951        NewToken->Flags = 0;
00952        NewToken->Line = Line + 1;
00953        NewToken->pTokenStart = pTokenStart;
00954        NewToken->TokenStart = pTokenStart - pStart;
00955        NewToken->TokenEnd =  (pTokenEnd - pStart) - NewToken->TokenStart;
00956        NewToken->pTokenEnd = pTokenEnd;
00957        NewToken->NameEnd = NewToken->TokenEnd - 2;
00958        NewToken->PreEval = NULL;
00959        NewToken->FlatToken = NewStrBufPlain(pTokenStart + 2, pTokenEnd - pTokenStart - 2);
00960        StrBufShrinkToFit(NewToken->FlatToken, 1);
00961 
00962        StrBufPeek(Buf, pTokenStart, + 1, '\0');
00963        StrBufPeek(Buf, pTokenEnd, -1, '\0');
00964        pch = NewToken->pName = pTokenStart + 2;
00965 
00966        NewToken->HaveParameters = 0;;
00967        NewToken->nParameters = 0;
00968 
00969        while (pch < pTokenEnd - 1) {
00970               if (*pch == '(') {
00971                      StrBufPeek(Buf, pch, -1, '\0');
00972                      NewToken->NameEnd = pch - NewToken->pName;
00973                      pch ++;
00974                      if (*(pTokenEnd - 1) != ')') {
00975                             LogTemplateError(
00976                                    NULL, "Parseerror", ERR_NAME, &TP, 
00977                                    "Warning, Non welformed Token; missing right parenthesis");
00978                      }
00979                      while (pch < pTokenEnd - 1) {
00980                             NewToken->nParameters++;
00981                             if (GetNextParameter(Buf, 
00982                                                &pch, 
00983                                                pTokenEnd - 1, 
00984                                                NewToken, 
00985                                                pTmpl, 
00986                                                &TP, 
00987                                                &NewToken->Params[NewToken->nParameters - 1]))
00988                             {
00989                                    NewToken->HaveParameters = 1;
00990                                    if (NewToken->nParameters >= MAXPARAM) {
00991                                           LogTemplateError(
00992                                                  NULL, "Parseerror", ERR_NAME, &TP,
00993                                                  "only [%d] Params allowed in Tokens",
00994                                                  MAXPARAM);
00995 
00996                                           FreeToken(&NewToken);
00997                                           return NULL;
00998                                    }
00999                             }
01000                             else break;
01001                      }
01002                      if((NewToken->NameEnd == 1) &&
01003                         (NewToken->HaveParameters == 1))
01004                         
01005                      {
01006                             if (*(NewToken->pName) == '_')
01007                                    NewToken->Flags = SV_GETTEXT;
01008                             else if (*(NewToken->pName) == '=')
01009                                    NewToken->Flags = SV_SUBTEMPL;
01010                             else if (*(NewToken->pName) == '%')
01011                                    NewToken->Flags = SV_CUST_STR_CONDITIONAL;
01012                             else if (*(NewToken->pName) == '?')
01013                                    NewToken->Flags = SV_CONDITIONAL;
01014                             else if (*(NewToken->pName) == '!')
01015                                    NewToken->Flags = SV_NEG_CONDITIONAL;
01016                      }
01017               }
01018               else pch ++;         
01019        }
01020        
01021        switch (NewToken->Flags) {
01022        case 0:
01023               /* If we're able to find out more about the token, do it now while its fresh. */
01024               pch = NewToken->pName;
01025               while (pch <  NewToken->pName + NewToken->NameEnd)
01026               {
01027                      if (((*pch >= 'A') && (*pch <= 'Z')) || 
01028                          ((*pch >= '0') && (*pch <= '9')) ||
01029                          (*pch == ':') || 
01030                          (*pch == '-') ||
01031                          (*pch == '_')) 
01032                             pch ++;
01033                      else
01034                      {
01035                             LogTemplateError(
01036                                    NULL, "Token Name", ERR_NAME, &TP,
01037                                    "contains illegal char: '%c'", 
01038                                    *pch);
01039                             pch++;
01040                      }
01041 
01042               }
01043               if (GetHash(GlobalNS, NewToken->pName, NewToken->NameEnd, &vVar)) {
01044                      HashHandler *Handler;
01045                      Handler = (HashHandler*) vVar;
01046                      if ((NewToken->nParameters < Handler->Filter.nMinArgs) || 
01047                          (NewToken->nParameters > Handler->Filter.nMaxArgs)) {
01048                             LogTemplateError(
01049                                    NULL, "Token", ERR_NAME, &TP,
01050                                    "doesn't work with %d params", 
01051                                    NewToken->nParameters);
01052 
01053                      }
01054                      else {
01055                             NewToken->PreEval = Handler;
01056                             NewToken->Flags = SV_PREEVALUATED;        
01057                             if (Handler->PreEvalFunc != NULL)
01058                                    Handler->PreEvalFunc(NewToken);
01059                      }
01060               }
01061               break;
01062        case SV_GETTEXT:
01063               if (NewToken->nParameters !=1) {
01064                      LogTemplateError(                               
01065                             NULL, "Gettext", ERR_NAME, &TP,
01066                             "requires exactly 1 parameter, you gave %d params", 
01067                             NewToken->nParameters);
01068                      NewToken->Flags = 0;
01069                      break;
01070               }
01071               if (DumpTemplateI18NStrings) {
01072                      StrBufAppendPrintf(I18nDump, "_(\"%s\");\n", NewToken->Params[0]->Start);
01073               }
01074               break;
01075        case SV_SUBTEMPL:
01076               if (NewToken->nParameters != 1) {
01077                      LogTemplateError(
01078                             NULL, "Subtemplates", ERR_NAME, &TP,
01079                             "require exactly 1 parameter, you gave %d params", 
01080                             NewToken->nParameters);
01081                      break;
01082               }
01083               else {
01084                      void *vTmpl;
01085                      /* well, we don't check the mobile stuff here... */
01086                      if (!GetHash(LocalTemplateCache, 
01087                                  NewToken->Params[0]->Start, 
01088                                  NewToken->Params[0]->len, 
01089                                  &vTmpl) &&
01090                          !GetHash(TemplateCache, 
01091                                  NewToken->Params[0]->Start, 
01092                                  NewToken->Params[0]->len, 
01093                                  &vTmpl)) {
01094                             LogTemplateError(
01095                                    NULL, "SubTemplate", ERR_PARM1, &TP,
01096                                    "doesn't exist");
01097                      }
01098               }
01099               break;
01100        case SV_CUST_STR_CONDITIONAL:
01101        case SV_CONDITIONAL:
01102        case SV_NEG_CONDITIONAL:
01103               if (NewToken->nParameters <2) {
01104                      LogTemplateError(
01105                             NULL, "Conditional", ERR_PARM1, &TP,
01106                             "require at least 2 parameters, you gave %d params", 
01107                             NewToken->nParameters);
01108                      NewToken->Flags = 0;
01109                      break;
01110               }
01111               if (NewToken->Params[1]->lvalue == 0) {
01112                      LogTemplateError(
01113                             NULL, "Conditional", ERR_PARM1, &TP,
01114                             "Conditional ID (Parameter 1) mustn't be 0!");
01115                      NewToken->Flags = 0;
01116                      break;
01117               }
01118               if (!GetHash(Conditionals, 
01119                           NewToken->Params[0]->Start, 
01120                           NewToken->Params[0]->len, 
01121                           &vVar) || 
01122                   (vVar == NULL)) {
01123                      if ((NewToken->Params[0]->len == 1) &&
01124                          (NewToken->Params[0]->Start[0] == 'X'))
01125                             break;
01126                      LogTemplateError(
01127                             NULL, "Conditional", ERR_PARM1, &TP,
01128                             "Not found!");
01129 /*
01130                      NewToken->Error = NewStrBuf();
01131                      StrBufAppendPrintf(
01132                             NewToken->Error, 
01133                             "<pre>\nConditional [%s] (in '%s' line %ld); Not found!\n[%s]\n</pre>\n", 
01134                             NewToken->Params[0]->Start,
01135                             ChrPtr(pTmpl->FileName),
01136                             NewToken->Line,
01137                             ChrPtr(NewToken->FlatToken));
01138 */
01139               }
01140               else {
01141                      NewToken->PreEval = vVar;
01142               }
01143               break;
01144        }
01145        return NewToken;
01146 }
01147 
01148 
01149 
01150 
01151 
01156 void *prepare_template(StrBuf *filename, StrBuf *Key, HashList *PutThere)
01157 {
01158        WCTemplate *NewTemplate;
01159 
01160        NewTemplate = (WCTemplate *) malloc(sizeof(WCTemplate));
01161        memset(NewTemplate, 0, sizeof(WCTemplate));
01162        NewTemplate->Data = NULL;
01163        NewTemplate->FileName = NewStrBufDup(filename);
01164        StrBufShrinkToFit(NewTemplate->FileName, 1);
01165        NewTemplate->nTokensUsed = 0;
01166        NewTemplate->TokenSpace = 0;
01167        NewTemplate->Tokens = NULL;
01168        NewTemplate->MimeType = NewStrBufPlain(GuessMimeByFilename (SKEY(NewTemplate->FileName)), -1);
01169        if (strstr(ChrPtr(NewTemplate->MimeType), "text") != NULL) {
01170               StrBufAppendBufPlain(NewTemplate->MimeType, HKEY("; charset=utf-8"), 0);
01171        }
01172 
01173        if (strstr(ChrPtr(NewTemplate->MimeType), "text") != NULL) {
01174               StrBufAppendBufPlain(NewTemplate->MimeType, HKEY("; charset=utf-8"), 0);
01175        }
01176 
01177        Put(PutThere, ChrPtr(Key), StrLength(Key), NewTemplate, FreeWCTemplate);
01178        return NewTemplate;
01179 }
01180 
01185 void *duplicate_template(WCTemplate *OldTemplate)
01186 {
01187        WCTemplate *NewTemplate;
01188 
01189        NewTemplate = (WCTemplate *) malloc(sizeof(WCTemplate));
01190        memset(NewTemplate, 0, sizeof(WCTemplate));
01191        NewTemplate->Data = NULL;
01192        NewTemplate->FileName = NewStrBufDup(OldTemplate->FileName);
01193        StrBufShrinkToFit(NewTemplate->FileName, 1);
01194        NewTemplate->nTokensUsed = 0;
01195        NewTemplate->TokenSpace = 0;
01196        NewTemplate->Tokens = NULL;
01197        NewTemplate->MimeType = NewStrBufDup(OldTemplate->MimeType);
01198        return NewTemplate;
01199 }
01200 
01201 
01202 void SanityCheckTemplate(StrBuf *Target, WCTemplate *CheckMe)
01203 {
01204        int i = 0;
01205        int j;
01206        int FoundConditionalEnd;
01207 
01208        for (i = 0; i < CheckMe->nTokensUsed; i++)
01209        {
01210               switch(CheckMe->Tokens[i]->Flags)
01211               {
01212               case SV_CONDITIONAL:
01213               case SV_NEG_CONDITIONAL:
01214                      FoundConditionalEnd = 0;
01215                      if ((CheckMe->Tokens[i]->Params[0]->len == 1) && 
01216                          (CheckMe->Tokens[i]->Params[0]->Start[0] == 'X'))
01217                             break;
01218                      for (j = i + 1; j < CheckMe->nTokensUsed; j++)
01219                      {
01220                             if (((CheckMe->Tokens[j]->Flags == SV_CONDITIONAL) ||
01221                                  (CheckMe->Tokens[j]->Flags == SV_NEG_CONDITIONAL)) && 
01222                                 (CheckMe->Tokens[i]->Params[1]->lvalue == 
01223                                  CheckMe->Tokens[j]->Params[1]->lvalue))
01224                             {
01225                                    FoundConditionalEnd = 1;
01226                                    break;
01227                             }
01228 
01229                      }
01230                      if (!FoundConditionalEnd)
01231                      {
01232                             WCTemplputParams TP;
01233                             memset(&TP, 0, sizeof(WCTemplputParams));
01234                             TP.Tokens = CheckMe->Tokens[i];
01235                             LogTemplateError(
01236                                    Target, "Token", ERR_PARM1, &TP,
01237                                    "Conditional without Endconditional"
01238                                    );
01239                      }
01240                      break;
01241               default:
01242                      break;
01243               }
01244        }
01245 }
01246 
01251 void *load_template(StrBuf *Target, WCTemplate *NewTemplate)
01252 {
01253        int fd;
01254        struct stat statbuf;
01255        const char *pS, *pE, *pch, *Err;
01256        long Line;
01257 
01258        fd = open(ChrPtr(NewTemplate->FileName), O_RDONLY);
01259        if (fd <= 0) {
01260               syslog(1, "ERROR: could not open template '%s' - %s\n",
01261                      ChrPtr(NewTemplate->FileName), strerror(errno));
01262               return NULL;
01263        }
01264 
01265        if (fstat(fd, &statbuf) == -1) {
01266               syslog(1, "ERROR: could not stat template '%s' - %s\n",
01267                      ChrPtr(NewTemplate->FileName), strerror(errno));
01268               return NULL;
01269        }
01270 
01271        NewTemplate->Data = NewStrBufPlain(NULL, statbuf.st_size + 1);
01272        if (StrBufReadBLOB(NewTemplate->Data, &fd, 1, statbuf.st_size, &Err) < 0) {
01273               close(fd);
01274               syslog(1, "ERROR: reading template '%s' - %s<br>\n",
01275                      ChrPtr(NewTemplate->FileName), strerror(errno));
01276               return NULL;
01277        }
01278        close(fd);
01279 
01280        Line = 0;
01281        StrBufShrinkToFit(NewTemplate->Data, 1);
01282        StrBufShrinkToFit(NewTemplate->MimeType, 1);
01283        pS = pch = ChrPtr(NewTemplate->Data);
01284        pE = pS + StrLength(NewTemplate->Data);
01285        while (pch < pE) {
01286               const char *pts, *pte;
01287               char InQuotes = '\0';
01288               void *pv;
01289 
01291               for (; pch < pE; pch ++) {
01292                      if ((*pch=='<')&&(*(pch + 1)=='?') &&
01293                          !((pch == pS) && /* we must ommit a <?xml */
01294                            (*(pch + 2) == 'x') && 
01295                            (*(pch + 3) == 'm') && 
01296                            (*(pch + 4) == 'l')))                    
01297                             break;
01298                      if (*pch=='\n') Line ++;
01299               }
01300               if (pch >= pE)
01301                      continue;
01302               pts = pch;
01303 
01305               for (; pch <= pE - 1; pch ++) {
01306                      if ((!InQuotes) &&
01307                          ((*pch == '\'') || (*pch == '"')))
01308                      {
01309                             InQuotes = *pch;
01310                      }
01311                      else if (InQuotes && (InQuotes == *pch))
01312                      {
01313                             InQuotes = '\0';
01314                      }
01315                      else if ((InQuotes) &&
01316                              (*pch == '\\') &&
01317                              (*(pch + 1) == InQuotes))
01318                      {
01319                             pch++;
01320                      }
01321                      else if ((!InQuotes) && 
01322                              (*pch == '>'))
01323                      {
01324                             break;
01325                      }
01326               }
01327               if (pch + 1 > pE)
01328                      continue;
01329               pte = pch;
01330               pv = NewTemplateSubstitute(NewTemplate->Data, pS, pts, pte, Line, NewTemplate);
01331               if (pv != NULL) {
01332                      PutNewToken(NewTemplate, pv);
01333                      pch ++;
01334               }
01335        }
01336 
01337        SanityCheckTemplate(NULL, NewTemplate);
01338        return NewTemplate;
01339 }
01340 
01341 
01342 const char* PrintTemplate(void *vSubst)
01343 {
01344        WCTemplate *Tmpl = vSubst;
01345 
01346        return ChrPtr(Tmpl->FileName);
01347 
01348 }
01349 
01350 int LoadTemplateDir(const StrBuf *DirName, HashList *big, const StrBuf *BaseKey)
01351 {
01352        int Toplevel;
01353        StrBuf *FileName;
01354        StrBuf *Key;
01355        StrBuf *SubKey;
01356        StrBuf *SubDirectory;
01357        DIR *filedir = NULL;
01358        struct dirent *filedir_entry;
01359        struct dirent *d;
01360        int d_type = 0;
01361        int d_namelen;
01362        int d_without_ext;
01363        
01364        d = (struct dirent *)malloc(offsetof(struct dirent, d_name) + PATH_MAX + 1);
01365        if (d == NULL) {
01366               return 0;
01367        }
01368 
01369        filedir = opendir (ChrPtr(DirName));
01370        if (filedir == NULL) {
01371               free(d);
01372               return 0;
01373        }
01374 
01375        Toplevel = StrLength(BaseKey) == 0;
01376        SubDirectory = NewStrBuf();
01377        SubKey = NewStrBuf();
01378        FileName = NewStrBufPlain(NULL, PATH_MAX);
01379        Key = NewStrBuf();
01380        while ((readdir_r(filedir, d, &filedir_entry) == 0) &&
01381               (filedir_entry != NULL))
01382        {
01383               char *MinorPtr;
01384 
01385 #ifdef _DIRENT_HAVE_D_NAMELEN
01386               d_namelen = filedir_entry->d_namelen;
01387               d_type = filedir_entry->d_type;
01388 #else
01389 
01390 #ifndef DT_UNKNOWN
01391 #define DT_UNKNOWN     0
01392 #define DT_DIR         4
01393 #define DT_REG         8
01394 #define DT_LNK         10
01395 
01396 #define IFTODT(mode)   (((mode) & 0170000) >> 12)
01397 #define DTTOIF(dirtype)        ((dirtype) << 12)
01398 #endif
01399               d_namelen = strlen(filedir_entry->d_name);
01400               d_type = DT_UNKNOWN;
01401 #endif
01402               d_without_ext = d_namelen;
01403 
01404               if ((d_namelen > 1) && filedir_entry->d_name[d_namelen - 1] == '~')
01405                      continue; /* Ignore backup files... */
01406 
01407               if ((d_namelen == 1) && 
01408                   (filedir_entry->d_name[0] == '.'))
01409                      continue;
01410 
01411               if ((d_namelen == 2) && 
01412                   (filedir_entry->d_name[0] == '.') &&
01413                   (filedir_entry->d_name[1] == '.'))
01414                      continue;
01415 
01416               if (d_type == DT_UNKNOWN) {
01417                      struct stat s;
01418                      char path[PATH_MAX];
01419                      snprintf(path, PATH_MAX, "%s/%s", 
01420                              ChrPtr(DirName), filedir_entry->d_name);
01421                      if (stat(path, &s) == 0) {
01422                             d_type = IFTODT(s.st_mode);
01423                      }
01424               }
01425               switch (d_type)
01426               {
01427               case DT_DIR:
01428                      /* Skip directories we are not interested in... */
01429                      if (strcmp(filedir_entry->d_name, ".svn") == 0)
01430                             continue;
01431 
01432                      FlushStrBuf(SubKey);
01433                      if (!Toplevel) {
01434                             /* If we're not toplevel, the upper dirs count as foo_bar_<local name>*/
01435                             StrBufAppendBuf(SubKey, BaseKey, 0);
01436                             StrBufAppendBufPlain(SubKey, HKEY("_"), 0);
01437                      }
01438                      StrBufAppendBufPlain(SubKey, filedir_entry->d_name, d_namelen, 0);
01439 
01440                      FlushStrBuf(SubDirectory);
01441                      StrBufAppendBuf(SubDirectory, DirName, 0);
01442                      if (ChrPtr(SubDirectory)[StrLength(SubDirectory) - 1] != '/')
01443                             StrBufAppendBufPlain(SubDirectory, HKEY("/"), 0);
01444                      StrBufAppendBufPlain(SubDirectory, filedir_entry->d_name, d_namelen, 0);
01445 
01446                      LoadTemplateDir(SubDirectory, big, SubKey);
01447 
01448                      break;
01449               case DT_LNK: /* TODO: check whether its a file or a directory */
01450               case DT_REG:
01451 
01452 
01453                      while ((d_without_ext > 0) && (filedir_entry->d_name[d_without_ext] != '.'))
01454                             d_without_ext --;
01455                      if ((d_without_ext == 0) || (d_namelen < 3))
01456                             continue;
01457                      if (((d_namelen > 1) && filedir_entry->d_name[d_namelen - 1] == '~') ||
01458                          (strcmp(&filedir_entry->d_name[d_without_ext], ".orig") == 0) ||
01459                          (strcmp(&filedir_entry->d_name[d_without_ext], ".swp") == 0))
01460                             continue; /* Ignore backup files... */
01461                      StrBufPrintf(FileName, "%s/%s", ChrPtr(DirName),  filedir_entry->d_name);
01462                      MinorPtr = strchr(filedir_entry->d_name, '.');
01463                      if (MinorPtr != NULL)
01464                             *MinorPtr = '\0';
01465                      FlushStrBuf(Key);
01466                      if (!Toplevel) {
01467                             /* If we're not toplevel, the upper dirs count as foo_bar_<local name>*/
01468                             StrBufAppendBuf(Key, BaseKey, 0);
01469                             StrBufAppendBufPlain(Key, HKEY("_"), 0);
01470                      }
01471                      StrBufAppendBufPlain(Key, filedir_entry->d_name, MinorPtr - filedir_entry->d_name, 0);
01472 
01473                      if (LoadTemplates >= 1)
01474                             syslog(1, "%s %s\n", ChrPtr(FileName), ChrPtr(Key));
01475                      prepare_template(FileName, Key, big);
01476               default:
01477                      break;
01478               }
01479        }
01480        free(d);
01481        closedir(filedir);
01482        FreeStrBuf(&FileName);
01483        FreeStrBuf(&Key);
01484        FreeStrBuf(&SubDirectory);
01485        FreeStrBuf(&SubKey);
01486        return 1;
01487 }
01488 
01489 void InitTemplateCache(void)
01490 {
01491        int i;
01492        StrBuf *Key;
01493        StrBuf *Dir;
01494        HashList *Templates[2];
01495 
01496        Dir = NewStrBuf();
01497        Key = NewStrBuf();
01498 
01499        /* Primary Template set... */
01500        StrBufPrintf(Dir, "%s/t", static_dirs[0]);
01501        LoadTemplateDir(Dir,
01502                      TemplateCache, 
01503                      Key);
01504 
01505        /* User local Template set */
01506        StrBufPrintf(Dir, "%s/t", static_dirs[1]);
01507        LoadTemplateDir(Dir,
01508                      LocalTemplateCache, 
01509                      Key);
01510        
01511        /* Debug Templates, just to be loaded while debugging. */
01512        
01513        StrBufPrintf(Dir, "%s/dbg", static_dirs[0]);
01514        LoadTemplateDir(Dir,
01515                      TemplateCache, 
01516                      Key);
01517        Templates[0] = TemplateCache;
01518        Templates[1] = LocalTemplateCache;
01519 
01520 
01521        if (LoadTemplates == 0) 
01522               for (i=0; i < 2; i++) {
01523                      const char *Key;
01524                      long KLen;
01525                      HashPos *At;
01526                      void *vTemplate;
01527 
01528                      At = GetNewHashPos(Templates[i], 0);
01529                      while (GetNextHashPos(Templates[i], 
01530                                          At, 
01531                                          &KLen,
01532                                          &Key, 
01533                                          &vTemplate) && 
01534                             (vTemplate != NULL))
01535                      {
01536                             load_template(NULL, (WCTemplate *)vTemplate);
01537                      }
01538                      DeleteHashPos(&At);
01539               }
01540 
01541 
01542        FreeStrBuf(&Dir);
01543        FreeStrBuf(&Key);
01544 }
01545 
01546 
01547 
01548 /*-----------------------------------------------------------------------------
01549  *                      Filling & processing Templates
01550  */
01560 int EvaluateToken(StrBuf *Target, int state, WCTemplputParams *TP)
01561 {
01562        const char *AppendMe;
01563        long AppendMeLen;
01564        HashHandler *Handler;
01565        void *vVar;
01566        
01567 /* much output, since pName is not terminated...
01568        syslog(1,"Doing token: %s\n",Token->pName);
01569 */
01570 
01571        switch (TP->Tokens->Flags) {
01572        case SV_GETTEXT:
01573               TmplGettext(Target, TP);
01574               break;
01575        case SV_CONDITIONAL: 
01576               return EvaluateConditional(Target, 1, state, TP);
01577               break;
01578        case SV_NEG_CONDITIONAL: 
01579               return EvaluateConditional(Target, 0, state, TP);
01580               break;
01581        case SV_CUST_STR_CONDITIONAL: 
01582               if (TP->Tokens->nParameters >= 6) {
01583                      if (EvaluateConditional(Target, 0, state, TP)) {
01584                             GetTemplateTokenString(Target, TP, 5, &AppendMe, &AppendMeLen);
01585                             StrBufAppendBufPlain(Target, 
01586                                                AppendMe, 
01587                                                AppendMeLen,
01588                                                0);
01589                      }
01590                      else{
01591                             GetTemplateTokenString(Target, TP, 4, &AppendMe, &AppendMeLen);
01592                             StrBufAppendBufPlain(Target, 
01593                                                AppendMe, 
01594                                                AppendMeLen,
01595                                                0);
01596                      }
01597               }
01598               else  {
01599                      LogTemplateError(
01600                             Target, "Conditional", ERR_NAME, TP,
01601                             "needs at least 6 Params!"); 
01602               }
01603               break;
01604        case SV_SUBTEMPL:
01605               if (TP->Tokens->nParameters == 1)
01606                      DoTemplate(TKEY(0), Target, TP);
01607               break;
01608        case SV_PREEVALUATED:
01609               Handler = (HashHandler*) TP->Tokens->PreEval;
01610               if (!CheckContext(Target, &Handler->Filter, TP, "Token")) {
01611                      return -1;
01612               }
01613               Handler->HandlerFunc(Target, TP);
01614               break;        
01615        default:
01616               if (GetHash(GlobalNS, TP->Tokens->pName, TP->Tokens->NameEnd, &vVar)) {
01617                      Handler = (HashHandler*) vVar;
01618                      if (!CheckContext(Target, &Handler->Filter, TP, "Token")) {
01619                             return -1;
01620                      }
01621                      else {
01622                             Handler->HandlerFunc(Target, TP);
01623                      }
01624               }
01625               else {
01626                      LogTemplateError(
01627                             Target, "Token UNKNOWN", ERR_NAME, TP,
01628                             "You've specified a token that isn't known to webcit.!");
01629               }
01630        }
01631        return 0;
01632 }
01633 
01634 
01635 
01636 const StrBuf *ProcessTemplate(WCTemplate *Tmpl, StrBuf *Target, WCTemplputParams *CallingTP)
01637 {
01638        WCTemplate *pTmpl = Tmpl;
01639        int done = 0;
01640        int i, state;
01641        const char *pData, *pS;
01642        long len;
01643        WCTemplputParams TP;
01644 
01645        memcpy(&TP.Filter, &CallingTP->Filter, sizeof(ContextFilter));
01646 
01647        TP.Context = CallingTP->Context;
01648        TP.ControlContext = CallingTP->ControlContext;
01649 
01650        if (LoadTemplates != 0) {                 
01651               if (LoadTemplates > 1)
01652                      syslog(1, "DBG: ----- loading:  [%s] ------ \n", 
01653                             ChrPtr(Tmpl->FileName));
01654               pTmpl = duplicate_template(Tmpl);
01655               if(load_template(Target, pTmpl) == NULL) {
01656                      StrBufAppendPrintf(
01657                             Target, 
01658                             "<pre>\nError loading Template [%s]\n See Logfile for details\n</pre>\n", 
01659                             ChrPtr(Tmpl->FileName));
01660                      FreeWCTemplate(pTmpl);
01661                      return NULL;
01662               }
01663 
01664        }
01665 
01666        pS = pData = ChrPtr(pTmpl->Data);
01667        len = StrLength(pTmpl->Data);
01668        i = 0;
01669        state = 0;
01670        while (!done) {
01671               if (i >= pTmpl->nTokensUsed) {
01672                      StrBufAppendBufPlain(Target, 
01673                                         pData, 
01674                                         len - (pData - pS), 0);
01675                      done = 1;
01676               }
01677               else {
01678                      StrBufAppendBufPlain(
01679                             Target, pData, 
01680                             pTmpl->Tokens[i]->pTokenStart - pData, 0);
01681                      TP.Tokens = pTmpl->Tokens[i];
01682                      TP.nArgs = pTmpl->Tokens[i]->nParameters;
01683                      state = EvaluateToken(Target, state, &TP);
01684 
01685                      while ((state != 0) && (i+1 < pTmpl->nTokensUsed)) {
01686                      /* condition told us to skip till its end condition */
01687                             i++;
01688                             TP.Tokens = pTmpl->Tokens[i];
01689                             TP.nArgs = pTmpl->Tokens[i]->nParameters;
01690                             if ((pTmpl->Tokens[i]->Flags == SV_CONDITIONAL) ||
01691                                 (pTmpl->Tokens[i]->Flags == SV_NEG_CONDITIONAL)) {
01692                                    if (state == EvaluateConditional(
01693                                               Target, 
01694                                               pTmpl->Tokens[i]->Flags, 
01695                                               state, 
01696                                               &TP))
01697                                           state = 0;
01698                             }
01699                      }
01700                      pData = pTmpl->Tokens[i++]->pTokenEnd + 1;
01701                      if (i > pTmpl->nTokensUsed)
01702                             done = 1;
01703               }
01704        }
01705        if (LoadTemplates != 0) {
01706               FreeWCTemplate(pTmpl);
01707        }
01708        return Tmpl->MimeType;
01709 
01710 }
01711 
01717 const StrBuf *DoTemplate(const char *templatename, long len, StrBuf *Target, WCTemplputParams *TP) 
01718 {
01719        WCTemplputParams LocalTP;
01720        HashList *Static;
01721        HashList *StaticLocal;
01722        void *vTmpl;
01723        
01724        if (Target == NULL)
01725               Target = WC->WBuf;
01726        if (TP == NULL) {
01727               memset(&LocalTP, 0, sizeof(WCTemplputParams));
01728               TP = &LocalTP;
01729        }
01730 
01731        Static = TemplateCache;
01732        StaticLocal = LocalTemplateCache;
01733 
01734        if (len == 0)
01735        {
01736               syslog(1, "Can't to load a template with empty name!\n");
01737               StrBufAppendPrintf(Target, "<pre>\nCan't to load a template with empty name!\n</pre>");
01738               return NULL;
01739        }
01740 
01741        if (!GetHash(StaticLocal, templatename, len, &vTmpl) &&
01742            !GetHash(Static, templatename, len, &vTmpl)) {
01743               syslog(1, "didn't find Template [%s] %ld %ld\n", templatename, len , (long)strlen(templatename));
01744               StrBufAppendPrintf(Target, "<pre>\ndidn't find Template [%s] %ld %ld\n</pre>", 
01745                                templatename, len, 
01746                                (long)strlen(templatename));
01747 #if 0
01748               dbg_PrintHash(Static, PrintTemplate, NULL);
01749               PrintHash(Static, VarPrintTransition, PrintTemplate);
01750 #endif
01751               return NULL;
01752        }
01753        if (vTmpl == NULL) 
01754               return NULL;
01755        return ProcessTemplate(vTmpl, Target, TP);
01756 
01757 }
01758 
01759 
01760 void tmplput_Comment(StrBuf *Target, WCTemplputParams *TP)
01761 {
01762        if (LoadTemplates != 0)
01763        {
01764               StrBuf *Comment;
01765               const char *pch;
01766               long len;
01767 
01768               GetTemplateTokenString(Target, TP, 0, &pch, &len);
01769               Comment = NewStrBufPlain(pch, len);
01770               StrBufAppendBufPlain(Target, HKEY("<!--"), 0);
01771               StrBufAppendTemplate(Target, TP, Comment, 1);
01772               StrBufAppendBufPlain(Target, HKEY("-->"), 0);
01773               FreeStrBuf(&Comment);
01774        }
01775 }
01776 
01777 /*-----------------------------------------------------------------------------
01778  *                      Iterators
01779  */
01780 typedef struct _HashIterator {
01781        HashList *StaticList;
01782        int AdditionalParams;
01783        int ContextType;
01784        int XPectContextType;
01785        int Flags;
01786        RetrieveHashlistFunc GetHash;
01787        HashDestructorFunc Destructor;
01788        SubTemplFunc DoSubTemplate;
01789 } HashIterator;
01790 
01791 void RegisterITERATOR(const char *Name, long len, 
01792                     int AdditionalParams, 
01793                     HashList *StaticList, 
01794                     RetrieveHashlistFunc GetHash, 
01795                     SubTemplFunc DoSubTempl,
01796                     HashDestructorFunc Destructor,
01797                     int ContextType, 
01798                     int XPectContextType, 
01799                     int Flags)
01800 {
01801        HashIterator *It;
01802 
01803        It = (HashIterator*)malloc(sizeof(HashIterator));
01804        memset(It, 0, sizeof(HashIterator));
01805        It->StaticList = StaticList;
01806        It->AdditionalParams = AdditionalParams;
01807        It->GetHash = GetHash;
01808        It->DoSubTemplate = DoSubTempl;
01809        It->Destructor = Destructor;
01810        It->ContextType = ContextType;
01811        It->XPectContextType = XPectContextType;
01812        It->Flags = Flags;
01813        Put(Iterators, Name, len, It, NULL);
01814 }
01815 
01816 typedef struct _iteratestruct {
01817        int GroupChange;
01818        int oddeven;
01819        const char *Key;
01820        long KeyLen;
01821        int n;
01822        int LastN;
01823        }IterateStruct; 
01824 
01825 int preeval_iterate(WCTemplateToken *Token)
01826 {
01827        WCTemplputParams TPP;
01828        WCTemplputParams *TP;
01829        void *vTmpl;
01830        void *vIt;
01831        HashIterator *It;
01832 
01833        memset(&TPP, 0, sizeof(WCTemplputParams));
01834        TP = &TPP;
01835        TP->Tokens = Token;
01836        if (!GetHash(Iterators, TKEY(0), &vIt)) {
01837               LogTemplateError(
01838                      NULL, "Iterator", ERR_PARM1, TP,
01839                      "not found");
01840               return 0;
01841        }
01842        if (TP->Tokens->Params[1]->Type != TYPE_SUBTEMPLATE) {
01843               LogTemplateError(NULL, "Iterator", ERR_PARM1, TP,
01844                              "Need token with type Subtemplate as param 1, have %s", 
01845                              TP->Tokens->Params[1]->Start);
01846        }
01847        
01848        /* well, we don't check the mobile stuff here... */
01849        if (!GetHash(LocalTemplateCache, TKEY(1), &vTmpl) &&
01850            !GetHash(TemplateCache, TKEY(1), &vTmpl)) {
01851               LogTemplateError(NULL, "SubTemplate", ERR_PARM1, TP,
01852                              "referenced here doesn't exist");
01853        }
01854        Token->Preeval2 = vIt;
01855        It = (HashIterator *) vIt;
01856 
01857        if (TP->Tokens->nParameters < It->AdditionalParams + 2) {
01858               LogTemplateError(                               
01859                      NULL, "Iterator", ERR_PARM1, TP,
01860                      "doesn't work with %d params", 
01861                      TP->Tokens->nParameters);
01862        }
01863 
01864 
01865        return 1;
01866 }
01867 
01868 void tmpl_iterate_subtmpl(StrBuf *Target, WCTemplputParams *TP)
01869 {
01870        HashIterator *It;
01871        HashList *List;
01872        HashPos  *it;
01873        SortStruct *SortBy = NULL;
01874        void *vSortBy;
01875        int DetectGroupChange = 0;
01876        int nMembersUsed;
01877        void *vContext;
01878        void *vLastContext = NULL;
01879        StrBuf *SubBuf;
01880        WCTemplputParams SubTP;
01881        IterateStruct Status;
01882 
01883        long StartAt = 0;
01884        long StepWidth = 0;
01885        long StopAt = -1;
01886 
01887        memset(&Status, 0, sizeof(IterateStruct));
01888        memcpy (&SubTP, &TP, sizeof(WCTemplputParams));
01889        
01890        It = (HashIterator*) TP->Tokens->Preeval2;
01891        if (It == NULL) {
01892               LogTemplateError(
01893                      Target, "Iterator", ERR_PARM1, TP, "Unknown!");
01894               return;
01895        }
01896 
01897        if (TP->Tokens->nParameters < It->AdditionalParams + 2) {
01898               LogTemplateError(                               
01899                      Target, "Iterator", ERR_PARM1, TP,
01900                      "doesn't work with %d params", 
01901                      TP->Tokens->nParameters - 1);
01902               return;
01903        }
01904 
01905        if ((It->XPectContextType != CTX_NONE) &&
01906            (It->XPectContextType != TP->Filter.ContextType)) {
01907               LogTemplateError(
01908                      Target, "Iterator", ERR_PARM1, TP,
01909                      "requires context of type %s, have %s", 
01910                      ContextName(It->XPectContextType), 
01911                      ContextName(TP->Filter.ContextType));
01912               return ;
01913               
01914        }
01915 
01916        if (It->StaticList == NULL)
01917               List = It->GetHash(Target, TP);
01918        else
01919               List = It->StaticList;
01920 
01921        DetectGroupChange = (It->Flags & IT_FLAG_DETECT_GROUPCHANGE) != 0;
01922        if (DetectGroupChange) {
01923               const StrBuf *BSort;
01924               DetectGroupChange = 0;
01925               if (havebstr("SortBy")) {
01926                      BSort = sbstr("SortBy");
01927                      if (GetHash(SortHash, SKEY(BSort), &vSortBy) &&
01928                          (vSortBy != NULL)) {
01929                             SortBy = (SortStruct*)vSortBy;
01930                             /* first check whether its intended for us... */
01931                             if ((SortBy->ContextType == It->ContextType)&&
01933                                 (havebstr("SortOrder"))) {
01934                                    int SortOrder;
01935                                    SortOrder = LBSTR("SortOrder");
01936                                    if (SortOrder != 0)
01937                                           DetectGroupChange = 1;
01938                             }
01939                      }
01940               }
01941        }
01942        nMembersUsed = GetCount(List);
01943        SubBuf = NewStrBuf();
01944        SubTP.Filter.ContextType = It->ContextType;
01945        SubTP.Filter.ControlContextType = CTX_ITERATE;
01946        SubTP.ControlContext = &Status;
01947        
01948        if (HAVE_PARAM(2)) {
01949               StartAt = GetTemplateTokenNumber(Target, TP, 2, 0);
01950        }
01951        if (HAVE_PARAM(3)) {
01952               StepWidth = GetTemplateTokenNumber(Target, TP, 3, 0);
01953        }
01954        if (HAVE_PARAM(4)) {
01955               StopAt = GetTemplateTokenNumber(Target, TP, 4, -1);
01956        }
01957        it = GetNewHashPos(List, StepWidth);
01958        if (StopAt < 0) {
01959               StopAt = GetCount(List);
01960        }
01961        while (GetNextHashPos(List, it, &Status.KeyLen, &Status.Key, &vContext)) {
01962               if ((Status.n >= StartAt) && (Status.n <= StopAt)) {
01963                      if (DetectGroupChange && Status.n > 0) {
01964                             Status.GroupChange = SortBy->GroupChange(vContext, vLastContext);
01965                      }
01966                      Status.LastN = (Status.n + 1) == nMembersUsed;
01967                      SubTP.Context = vContext;
01968                      if (It->DoSubTemplate != NULL)
01969                             It->DoSubTemplate(SubBuf, &SubTP);
01970                      DoTemplate(TKEY(1), SubBuf, &SubTP);
01971                      
01972                      StrBufAppendBuf(Target, SubBuf, 0);
01973                      FlushStrBuf(SubBuf);
01974                      Status.oddeven = ! Status.oddeven;
01975                      vLastContext = vContext;
01976               }
01977               Status.n++;
01978        }
01979        FreeStrBuf(&SubBuf);
01980        DeleteHashPos(&it);
01981        if (It->Destructor != NULL)
01982               It->Destructor(&List);
01983 }
01984 
01985 
01986 int conditional_ITERATE_ISGROUPCHANGE(StrBuf *Target, WCTemplputParams *TP)
01987 {
01988        IterateStruct *Ctx = CCTX;
01989        if (TP->Tokens->nParameters < 3)
01990               return        Ctx->GroupChange;
01991 
01992        return TP->Tokens->Params[2]->lvalue == Ctx->GroupChange;
01993 }
01994 
01995 void tmplput_ITERATE_ODDEVEN(StrBuf *Target, WCTemplputParams *TP)
01996 {
01997        IterateStruct *Ctx = CCTX;
01998        if (Ctx->oddeven)
01999               StrBufAppendBufPlain(Target, HKEY("odd"), 0);
02000        else
02001               StrBufAppendBufPlain(Target, HKEY("even"), 0);
02002 }
02003 
02004 
02005 void tmplput_ITERATE_KEY(StrBuf *Target, WCTemplputParams *TP)
02006 {
02007        IterateStruct *Ctx = CCTX;
02008 
02009        StrBufAppendBufPlain(Target, Ctx->Key, Ctx->KeyLen, 0);
02010 }
02011 
02012 
02013 void tmplput_ITERATE_LASTN(StrBuf *Target, WCTemplputParams *TP)
02014 {
02015        IterateStruct *Ctx = CCTX;
02016        StrBufAppendPrintf(Target, "%d", Ctx->n);
02017 }
02018 
02019 int conditional_ITERATE_FIRSTN(StrBuf *Target, WCTemplputParams *TP)
02020 {
02021        IterateStruct *Ctx = CCTX;
02022        return Ctx->n == 0;
02023 }
02024 
02025 int conditional_ITERATE_LASTN(StrBuf *Target, WCTemplputParams *TP)
02026 {
02027        IterateStruct *Ctx = CCTX;
02028        return Ctx->LastN;
02029 }
02030 
02031 
02032 
02033 /*-----------------------------------------------------------------------------
02034  *                      Conditionals
02035  */
02036 int EvaluateConditional(StrBuf *Target, int Neg, int state, WCTemplputParams *TP)
02037 {
02038        ConditionalStruct *Cond;
02039        int rc = 0;
02040        int res;
02041 
02042        if ((TP->Tokens->Params[0]->len == 1) &&
02043            (TP->Tokens->Params[0]->Start[0] == 'X'))
02044               return (state != 0)?TP->Tokens->Params[1]->lvalue:0;
02045            
02046        Cond = (ConditionalStruct *) TP->Tokens->PreEval;
02047        if (Cond == NULL) {
02048               LogTemplateError(
02049                      Target, "Conditional", ERR_PARM1, TP,
02050                      "unknown!");
02051               return 1;
02052        }
02053 
02054        if (!CheckContext(Target, &Cond->Filter, TP, "Conditional")) {
02055               return 0;
02056        }
02057        res = Cond->CondF(Target, TP);
02058        if (res == Neg)
02059               rc = TP->Tokens->Params[1]->lvalue;
02060        if (LoadTemplates > 5) 
02061               syslog(1, "<%s> : %d %d==%d\n", 
02062                      ChrPtr(TP->Tokens->FlatToken), 
02063                      rc, res, Neg);
02064        return rc;
02065 }
02066 
02067 void RegisterConditional(const char *Name, long len, 
02068                       int nParams,
02069                       WCConditionalFunc CondF, 
02070                       int ContextRequired)
02071 {
02072        ConditionalStruct *Cond;
02073 
02074        Cond = (ConditionalStruct*)malloc(sizeof(ConditionalStruct));
02075        memset(Cond, 0, sizeof(ConditionalStruct));
02076        Cond->PlainName = Name;
02077        Cond->Filter.nMaxArgs = nParams;
02078        Cond->Filter.nMinArgs = nParams;
02079        Cond->CondF = CondF;
02080        Cond->Filter.ContextType = ContextRequired;
02081        Cond->Filter.ControlContextType = CTX_NONE;
02082        Put(Conditionals, Name, len, Cond, NULL);
02083 }
02084 
02085 void RegisterControlConditional(const char *Name, long len, 
02086                             int nParams,
02087                             WCConditionalFunc CondF, 
02088                             int ControlContextRequired)
02089 {
02090        ConditionalStruct *Cond;
02091 
02092        Cond = (ConditionalStruct*)malloc(sizeof(ConditionalStruct));
02093        memset(Cond, 0, sizeof(ConditionalStruct));
02094        Cond->PlainName = Name;
02095        Cond->Filter.nMaxArgs = nParams;
02096        Cond->Filter.nMinArgs = nParams;
02097        Cond->CondF = CondF;
02098        Cond->Filter.ContextType = CTX_NONE;
02099        Cond->Filter.ControlContextType = ControlContextRequired;
02100        Put(Conditionals, Name, len, Cond, NULL);
02101 }
02102 
02103 void RegisterTokenParamDefine(const char *Name, long len, 
02104                            long Value)
02105 {
02106        long *PVal;
02107 
02108        PVal = (long*)malloc(sizeof(long));
02109        *PVal = Value;
02110        Put(Defines, Name, len, PVal, NULL);
02111 }
02112 
02113 long GetTokenDefine(const char *Name, long len, 
02114                   long DefValue)
02115 {
02116        void *vPVal;
02117 
02118        if (GetHash(Defines, Name, len, &vPVal) &&
02119             (vPVal != NULL))
02120         {
02121                return *(long*) vPVal;
02122         }
02123         else
02124         {
02125                return DefValue;
02126         }
02127 }
02128 
02129 void tmplput_DefStr(StrBuf *Target, WCTemplputParams *TP)
02130 {
02131        const char *Str;
02132        long len;
02133        GetTemplateTokenString(Target, TP, 2, &Str, &len);
02134        
02135        StrBufAppendBufPlain(Target, Str, len, 0);
02136 }
02137 
02138 void tmplput_DefVal(StrBuf *Target, WCTemplputParams *TP)
02139 {
02140        int val;
02141 
02142        val = GetTemplateTokenNumber(Target, TP, 0, 0);
02143        StrBufAppendPrintf(Target, "%d", val);
02144 }
02145 
02146 HashList *Defines;
02147 
02148 /*-----------------------------------------------------------------------------
02149  *                      Context Strings
02150  */
02151 void tmplput_ContextString(StrBuf *Target, WCTemplputParams *TP)
02152 {
02153        StrBufAppendTemplate(Target, TP, (StrBuf*)CTX, 0);
02154 }
02155 int ConditionalContextStr(StrBuf *Target, WCTemplputParams *TP)
02156 {
02157        StrBuf *TokenText = (StrBuf*) CTX;
02158        const char *CompareToken;
02159        long len;
02160 
02161        GetTemplateTokenString(Target, TP, 2, &CompareToken, &len);
02162        return strcmp(ChrPtr(TokenText), CompareToken) == 0;
02163 }
02164 
02165 void tmplput_ContextStringArray(StrBuf *Target, WCTemplputParams *TP)
02166 {
02167        HashList *Arr = (HashList*) CTX;
02168        void *pV;
02169        int val;
02170 
02171        val = GetTemplateTokenNumber(Target, TP, 0, 0);
02172        if (GetHash(Arr, IKEY(val), &pV) && 
02173            (pV != NULL)) {
02174               StrBufAppendTemplate(Target, TP, (StrBuf*)pV, 1);
02175        }
02176 }
02177 int ConditionalContextStrinArray(StrBuf *Target, WCTemplputParams *TP)
02178 {
02179        HashList *Arr = (HashList*) CTX;
02180        void *pV;
02181        int val;
02182        const char *CompareToken;
02183        long len;
02184 
02185        GetTemplateTokenString(Target, TP, 2, &CompareToken, &len);
02186        val = GetTemplateTokenNumber(Target, TP, 0, 0);
02187        if (GetHash(Arr, IKEY(val), &pV) && 
02188            (pV != NULL)) {
02189               return strcmp(ChrPtr((StrBuf*)pV), CompareToken) == 0;
02190        }
02191        else
02192               return 0;
02193 }
02194 
02195 /*-----------------------------------------------------------------------------
02196  *                      Boxed-API
02197  */
02198 
02199 void tmpl_do_boxed(StrBuf *Target, WCTemplputParams *TP)
02200 {
02201        WCTemplputParams SubTP;
02202 
02203        StrBuf *Headline = NULL;
02204        if (TP->Tokens->nParameters == 2) {
02205               if (TP->Tokens->Params[1]->Type == TYPE_STR) {
02206                      Headline = NewStrBuf();
02207                      DoTemplate(TKEY(1), Headline, TP);
02208               }
02209               else {
02210                      const char *Ch;
02211                      long len;
02212                      GetTemplateTokenString(Target, 
02213                                           TP, 
02214                                           1,
02215                                           &Ch,
02216                                           &len);
02217                      Headline = NewStrBufPlain(Ch, len);
02218               }
02219        }
02220        /* else TODO error? logging? */
02221        memcpy (&SubTP, TP, sizeof(WCTemplputParams));
02222        SubTP.Context = Headline;
02223        SubTP.Filter.ContextType = CTX_STRBUF;
02224        DoTemplate(HKEY("box_begin"), Target, &SubTP);
02225        DoTemplate(TKEY(0), Target, TP);
02226        DoTemplate(HKEY("box_end"), Target, TP);
02227        FreeStrBuf(&Headline);
02228 }
02229 
02230 /*-----------------------------------------------------------------------------
02231  *                      Tabbed-API
02232  */
02233 
02234 typedef struct _tab_struct {
02235        long CurrentTab;
02236        StrBuf *TabTitle;
02237 } tab_struct;
02238 
02239 int preeval_do_tabbed(WCTemplateToken *Token)
02240 {
02241        WCTemplputParams TPP;
02242        WCTemplputParams *TP;
02243        const char *Ch;
02244        long len;
02245        int i, nTabs;
02246 
02247 
02248        memset(&TPP, 0, sizeof(WCTemplputParams));
02249        TP = &TPP;
02250        TP->Tokens = Token;
02251        nTabs = TP->Tokens->nParameters / 2 - 1;
02252        if (TP->Tokens->nParameters % 2 != 0)
02253        {
02254               LogTemplateError(NULL, "TabbedApi", ERR_PARM1, TP,
02255                              "need even number of arguments");
02256               return 0;
02257 
02258        }
02259        else for (i = 0; i < nTabs; i++) {
02260               if (!HaveTemplateTokenString(NULL, 
02261                                         TP, 
02262                                         i * 2,
02263                                         &Ch,
02264                                         &len) || 
02265                   (TP->Tokens->Params[i * 2]->len == 0))
02266               {
02267                      LogTemplateError(NULL, "TabbedApi", ERR_PARM1, TP,
02268                                     "Tab-Subject %d needs to be able to produce a string, have %s", 
02269                                     i, TP->Tokens->Params[i * 2]->Start);
02270                      return 0;
02271               }
02272               if (!HaveTemplateTokenString(NULL, 
02273                                         TP, 
02274                                         i * 2 + 1,
02275                                         &Ch,
02276                                         &len) || 
02277                   (TP->Tokens->Params[i * 2 + 1]->len == 0))
02278               {
02279                      LogTemplateError(NULL, "TabbedApi", ERR_PARM1, TP,
02280                                     "Tab-Content %d needs to be able to produce a string, have %s", 
02281                                     i, TP->Tokens->Params[i * 2 + 1]->Start);
02282                      return 0;
02283               }
02284        }
02285 
02286        if (!HaveTemplateTokenString(NULL, 
02287                                  TP, 
02288                                  i * 2 + 1,
02289                                  &Ch,
02290                                  &len) || 
02291            (TP->Tokens->Params[i * 2 + 1]->len == 0))
02292        {
02293               LogTemplateError(NULL, "TabbedApi", ERR_PARM1, TP,
02294                              "Tab-Content %d needs to be able to produce a string, have %s", 
02295                              i, TP->Tokens->Params[i * 2 + 1]->Start);
02296               return 0;
02297        }
02298        return 1;
02299 }
02300 
02301 
02302 void tmpl_do_tabbed(StrBuf *Target, WCTemplputParams *TP)
02303 {
02304        StrBuf **TabNames;
02305        int i, ntabs, nTabs;
02306        tab_struct TS;
02307        WCTemplputParams SubTP;
02308 
02309        memset(&TS, 0, sizeof(tab_struct));
02310        memcpy (&SubTP, &TP, sizeof(WCTemplputParams));
02311 
02312        nTabs = ntabs = TP->Tokens->nParameters / 2;
02313        TabNames = (StrBuf **) malloc(ntabs * sizeof(StrBuf*));
02314        memset(TabNames, 0, ntabs * sizeof(StrBuf*));
02315 
02316        for (i = 0; i < ntabs; i++) {
02317               if ((TP->Tokens->Params[i * 2]->Type == TYPE_STR) &&
02318                   (TP->Tokens->Params[i * 2]->len > 0)) {
02319                      TabNames[i] = NewStrBuf();
02320                      DoTemplate(TKEY(i * 2), TabNames[i], TP);
02321               }
02322               else if (TP->Tokens->Params[i * 2]->Type == TYPE_GETTEXT) {
02323                      const char *Ch;
02324                      long len;
02325                      GetTemplateTokenString(Target, 
02326                                           TP, 
02327                                           i * 2,
02328                                           &Ch,
02329                                           &len);
02330                      TabNames[i] = NewStrBufPlain(Ch, -1);
02331               }
02332               else { 
02334                      nTabs --;
02335               }
02336        }
02337        memcpy (&SubTP, TP, sizeof(WCTemplputParams));
02338        SubTP.Filter.ControlContextType = CTX_TAB;
02339        SubTP.ControlContext = &TS;
02340 
02341        StrTabbedDialog(Target, nTabs, TabNames);
02342        for (i = 0; i < ntabs; i++) {
02343               memset(&TS, 0, sizeof(tab_struct));
02344               TS.CurrentTab = i;
02345               TS.TabTitle = TabNames[i];
02346               StrBeginTab(Target, i, nTabs, TabNames);
02347               DoTemplate(TKEY(i * 2 + 1), Target, &SubTP);
02348               StrEndTab(Target, i, nTabs);
02349        }
02350        for (i = 0; i < ntabs; i++) 
02351               FreeStrBuf(&TabNames[i]);
02352 }
02353 
02354 void tmplput_TAB_N(StrBuf *Target, WCTemplputParams *TP)
02355 {
02356        tab_struct *Ctx = CCTX;
02357 
02358        StrBufAppendPrintf(Target, "%d", Ctx->CurrentTab);
02359 }
02360 
02361 void tmplput_TAB_TITLE(StrBuf *Target, WCTemplputParams *TP)
02362 {
02363        tab_struct *Ctx = CCTX;
02364        StrBufAppendTemplate(Target, TP, Ctx->TabTitle, 0);
02365 }
02366 
02367 /*-----------------------------------------------------------------------------
02368  *                      Sorting-API
02369  */
02370 
02371 
02372 void RegisterSortFunc(const char *name, long len, 
02373                     const char *prepend, long preplen,
02374                     CompareFunc Forward, 
02375                     CompareFunc Reverse, 
02376                     CompareFunc GroupChange, 
02377                     long ContextType)
02378 {
02379        SortStruct *NewSort;
02380 
02381        NewSort = (SortStruct*) malloc(sizeof(SortStruct));
02382        memset(NewSort, 0, sizeof(SortStruct));
02383        NewSort->Name = NewStrBufPlain(name, len);
02384        if (prepend != NULL)
02385               NewSort->PrefPrepend = NewStrBufPlain(prepend, preplen);
02386        else
02387               NewSort->PrefPrepend = NULL;
02388        NewSort->Forward = Forward;
02389        NewSort->Reverse = Reverse;
02390        NewSort->GroupChange = GroupChange;
02391        NewSort->ContextType = ContextType;
02392        if (ContextType == CTX_NONE) {
02393               syslog(1, "sorting requires a context. CTX_NONE won't make it.\n");
02394               exit(1);
02395        }
02396               
02397        Put(SortHash, name, len, NewSort, DestroySortStruct);
02398 }
02399 
02400 CompareFunc RetrieveSort(WCTemplputParams *TP, 
02401                       const char *OtherPrefix, long OtherPrefixLen,
02402                       const char *Default, long ldefault, long DefaultDirection)
02403 {
02404        const StrBuf *BSort = NULL;
02405        SortStruct *SortBy;
02406        void *vSortBy;
02407        long SortOrder = -1;
02408        
02409        if (havebstr("SortBy")) {
02410               BSort = sbstr("SortBy");
02411               if (OtherPrefix == NULL) {
02412                      set_room_pref("sort", NewStrBufDup(BSort), 0);
02413               }
02414               else {
02415                      set_X_PREFS(HKEY("sort"), OtherPrefix, OtherPrefixLen, NewStrBufDup(BSort), 0);
02416               }
02417        }
02418        else { 
02419               if (OtherPrefix == NULL) {
02420                      BSort = get_room_pref("sort");
02421               }
02422               else {
02423                      BSort = get_X_PREFS(HKEY("sort"), OtherPrefix, OtherPrefixLen);
02424               }
02425               if (BSort != NULL)
02426                      putbstr("SortBy", NewStrBufDup(BSort));
02427               else {
02428                      StrBuf *Buf;
02429 
02430                      BSort = Buf = NewStrBufPlain(Default, ldefault);
02431                      putbstr("SortBy", Buf);
02432               }
02433        }
02434 
02435        if (!GetHash(SortHash, SKEY(BSort), &vSortBy) || 
02436            (vSortBy == NULL)) {
02437               if (!GetHash(SortHash, Default, ldefault, &vSortBy) || 
02438                   (vSortBy == NULL)) {
02439                      LogTemplateError(
02440                             NULL, "Sorting", ERR_PARM1, TP,
02441                             "Illegal default sort: [%s]", Default);
02442                      wc_backtrace();
02443               }
02444        }
02445        SortBy = (SortStruct*)vSortBy;
02446 
02447        if (SortBy->ContextType != TP->Filter.ContextType)
02448               return NULL;
02449 
02451        if (havebstr("SortOrder")) {
02452               SortOrder = LBSTR("SortOrder");
02453        }
02454        else { 
02455               StrBuf *Buf = NULL;
02456               if (SortBy->PrefPrepend == NULL) {
02457                      Buf = get_room_pref("SortOrder");
02458                      SortOrder = StrTol(Buf);
02459               }
02460               else {
02461                      BSort = get_X_PREFS(HKEY("SortOrder"), OtherPrefix, OtherPrefixLen);
02462               }
02463 
02464               if (Buf == NULL)
02465                      SortOrder = DefaultDirection;
02466 
02467               Buf = NewStrBufPlain(NULL, 64);
02468               StrBufPrintf(Buf, "%ld", SortOrder);
02469               putbstr("SortOrder", Buf);
02470        }
02471        switch (SortOrder) {
02472        default:
02473        case 0:
02474               return NULL;
02475        case 1:
02476               return SortBy->Forward;
02477        case 2:
02478               return SortBy->Reverse;
02479        }
02480 }
02481 
02482 
02483 enum {
02484        eNO_SUCH_SORT, 
02485        eNOT_SPECIFIED,
02486        eINVALID_PARAM,
02487        eFOUND
02488 };
02489 
02490 ConstStr SortIcons[] = {
02491        {HKEY("static/webcit_icons/sort_none.gif")},
02492        {HKEY("static/webcit_icons/up_pointer.gif")},
02493        {HKEY("static/webcit_icons/down_pointer.gif")},
02494 };
02495 
02496 ConstStr SortNextOrder[] = {
02497        {HKEY("1")},
02498        {HKEY("2")},
02499        {HKEY("0")},
02500 };
02501 
02502 
02503 int GetSortMetric(WCTemplputParams *TP, SortStruct **Next, SortStruct **Param, long *SortOrder, int N)
02504 {
02505        int bSortError = eNOT_SPECIFIED;
02506        const StrBuf *BSort;
02507        void *vSort;
02508        
02509        *SortOrder = 0;
02510        *Next = NULL;
02511        if (!GetHash(SortHash, TKEY(0), &vSort) || 
02512            (vSort == NULL))
02513               return eNO_SUCH_SORT;
02514        *Param = (SortStruct*) vSort;
02515        
02516 
02517        if (havebstr("SortBy")) {
02518               BSort = sbstr("SortBy");
02519               bSortError = eINVALID_PARAM;
02520               if ((*Param)->PrefPrepend == NULL) {
02521                      set_room_pref("sort", NewStrBufDup(BSort), 0);
02522               }
02523               else {
02524                      set_X_PREFS(HKEY("sort"), TKEY(N), NewStrBufDup(BSort), 0);
02525               }
02526        }
02527        else { 
02528               if ((*Param)->PrefPrepend == NULL) {
02529                      BSort = get_room_pref("sort");
02530               }
02531               else {
02532                      BSort = get_X_PREFS(HKEY("sort"), TKEY(N));
02533               }
02534        }
02535 
02536        if (!GetHash(SortHash, SKEY(BSort), &vSort) || 
02537            (vSort == NULL))
02538               return bSortError;
02539 
02540        *Next = (SortStruct*) vSort;
02541 
02543        if (havebstr("SortOrder")) {
02544               *SortOrder = LBSTR("SortOrder");
02545        }
02546        else { 
02547               if ((*Param)->PrefPrepend == NULL) {
02548                      *SortOrder = StrTol(get_room_pref("SortOrder"));
02549               }
02550               else {
02551                      *SortOrder = StrTol(get_X_PREFS(HKEY("SortOrder"), TKEY(N)));
02552               }
02553        }
02554        if (*SortOrder > 2)
02555               *SortOrder = 0;
02556 
02557        return eFOUND;
02558 }
02559 
02560 
02561 void tmplput_SORT_ICON(StrBuf *Target, WCTemplputParams *TP)
02562 {
02563        long SortOrder;
02564        SortStruct *Next;
02565        SortStruct *Param;
02566        const ConstStr *SortIcon;
02567 
02568        switch (GetSortMetric(TP, &Next, &Param, &SortOrder, 2)){
02569        case eNO_SUCH_SORT:
02570                 LogTemplateError(
02571                         Target, "Sorter", ERR_PARM1, TP,
02572                      " Sorter [%s] unknown!", 
02573                      TP->Tokens->Params[0]->Start);
02574               break;        
02575        case eINVALID_PARAM:
02576                 LogTemplateError(NULL, "Sorter", ERR_PARM1, TP,
02577                              " Sorter specified by BSTR 'SortBy' [%s] unknown!", 
02578                              bstr("SortBy"));
02579        case eNOT_SPECIFIED:
02580        case eFOUND:
02581               if (Next == Param) {
02582                      SortIcon = &SortIcons[SortOrder];
02583               }
02584               else { 
02585                      SortIcon = &SortIcons[0];
02586               }
02587               StrBufAppendBufPlain(Target, SortIcon->Key, SortIcon->len, 0);
02588        }
02589 }
02590 
02591 void tmplput_SORT_NEXT(StrBuf *Target, WCTemplputParams *TP)
02592 {
02593        long SortOrder;
02594        SortStruct *Next;
02595        SortStruct *Param;
02596 
02597        switch (GetSortMetric(TP, &Next, &Param, &SortOrder, 2)){
02598        case eNO_SUCH_SORT:
02599                 LogTemplateError(
02600                         Target, "Sorter", ERR_PARM1, TP,                                  
02601                      " Sorter [%s] unknown!", 
02602                      TP->Tokens->Params[0]->Start);
02603               break;        
02604        case eINVALID_PARAM:
02605                 LogTemplateError(
02606                         NULL, "Sorter", ERR_PARM1, TP,
02607                      " Sorter specified by BSTR 'SortBy' [%s] unknown!", 
02608                      bstr("SortBy"));
02609        case eNOT_SPECIFIED:
02610        case eFOUND:
02611               StrBufAppendBuf(Target, Param->Name, 0);
02612               
02613        }
02614 }
02615 
02616 void tmplput_SORT_ORDER(StrBuf *Target, WCTemplputParams *TP)
02617 {
02618        long SortOrder;
02619        const ConstStr *SortOrderStr;
02620        SortStruct *Next;
02621        SortStruct *Param;
02622 
02623        switch (GetSortMetric(TP, &Next, &Param, &SortOrder, 2)){
02624        case eNO_SUCH_SORT:
02625                 LogTemplateError(
02626                         Target, "Sorter", ERR_PARM1, TP,
02627                         " Sorter [%s] unknown!",
02628                         TP->Tokens->Params[0]->Start);
02629               break;        
02630        case eINVALID_PARAM:
02631                 LogTemplateError(
02632                         NULL, "Sorter", ERR_PARM1, TP,
02633                         " Sorter specified by BSTR 'SortBy' [%s] unknown!",
02634                         bstr("SortBy"));
02635        case eNOT_SPECIFIED:
02636        case eFOUND:
02637               if (Next == Param) {
02638                      SortOrderStr = &SortNextOrder[SortOrder];
02639               }
02640               else { 
02641                      SortOrderStr = &SortNextOrder[0];
02642               }
02643               StrBufAppendBufPlain(Target, SortOrderStr->Key, SortOrderStr->len, 0);
02644        }
02645 }
02646 
02647 
02648 void tmplput_long_vector(StrBuf *Target, WCTemplputParams *TP)
02649 {
02650        long *LongVector = (long*) CTX;
02651 
02652        if ((TP->Tokens->Params[0]->Type == TYPE_LONG) && 
02653            (TP->Tokens->Params[0]->lvalue <= LongVector[0]))
02654        {
02655               StrBufAppendPrintf(Target, "%ld", LongVector[TP->Tokens->Params[0]->lvalue]);
02656        }
02657        else
02658        {
02659               if (TP->Tokens->Params[0]->Type != TYPE_LONG) {
02660                      LogTemplateError(
02661                             Target, "Longvector", ERR_NAME, TP,
02662                             "needs a numerical Parameter!");
02663               }
02664               else {
02665                      LogTemplateError(
02666                             Target, "LongVector", ERR_PARM1, TP,
02667                             "doesn't have %ld Parameters, its just the size of %ld!", 
02668                             TP->Tokens->Params[0]->lvalue,
02669                             LongVector[0]);
02670               }
02671        }
02672 }
02673 
02674 void dbg_print_longvector(long *LongVector)
02675 {
02676        StrBuf *Buf = NewStrBufPlain(HKEY("Longvector: ["));
02677        int nItems = LongVector[0];
02678        int i;
02679 
02680        for (i = 0; i < nItems; i++) {
02681               if (i + 1 < nItems)
02682                      StrBufAppendPrintf(Buf, "%d: %ld | ", i, LongVector[i]);
02683               else
02684                      StrBufAppendPrintf(Buf, "%d: %ld]\n", i, LongVector[i]);
02685 
02686        }
02687        syslog(1, "%s", ChrPtr(Buf));
02688        FreeStrBuf(&Buf);
02689 }
02690 
02691 int ConditionalLongVector(StrBuf *Target, WCTemplputParams *TP)
02692 {
02693        long *LongVector = (long*) CTX;
02694 
02695        if ((TP->Tokens->Params[2]->Type == TYPE_LONG) && 
02696            (TP->Tokens->Params[2]->lvalue <= LongVector[0])&&
02697            (TP->Tokens->Params[3]->Type == TYPE_LONG) && 
02698            (TP->Tokens->Params[3]->lvalue <= LongVector[0]))
02699        {
02700               return LongVector[TP->Tokens->Params[2]->lvalue] == 
02701                      LongVector[TP->Tokens->Params[3]->lvalue];
02702        }
02703        else
02704        {
02705               if ((TP->Tokens->Params[2]->Type == TYPE_LONG) ||
02706                   (TP->Tokens->Params[2]->Type == TYPE_LONG)) {
02707                      LogTemplateError(
02708                             Target, "ConditionalLongvector", ERR_PARM1, TP,
02709                             "needs two long Parameter!");
02710               }
02711               else {
02712                      LogTemplateError(
02713                             Target, "Longvector", ERR_PARM1, TP,
02714                             "doesn't have %ld / %ld Parameters, its just the size of %ld!",
02715                             TP->Tokens->Params[2]->lvalue,
02716                             TP->Tokens->Params[3]->lvalue,
02717                             LongVector[0]);
02718               }
02719        }
02720        return 0;
02721 }
02722 
02723 
02724 void tmplput_CURRENT_FILE(StrBuf *Target, WCTemplputParams *TP)
02725 {
02726        StrBufAppendTemplate(Target, TP, TP->Tokens->FileName, 0);
02727 }
02728 
02729 void 
02730 InitModule_SUBST
02731 (void)
02732 {
02733        memset(&NoCtx, 0, sizeof(WCTemplputParams));
02734        RegisterNamespace("--", 0, 2, tmplput_Comment, NULL, CTX_NONE);
02735        RegisterNamespace("SORT:ICON", 1, 2, tmplput_SORT_ICON, NULL, CTX_NONE);
02736        RegisterNamespace("SORT:ORDER", 1, 2, tmplput_SORT_ORDER, NULL, CTX_NONE);
02737        RegisterNamespace("SORT:NEXT", 1, 2, tmplput_SORT_NEXT, NULL, CTX_NONE);
02738        RegisterNamespace("CONTEXTSTR", 0, 1, tmplput_ContextString, NULL, CTX_STRBUF);
02739        RegisterNamespace("CONTEXTSTRARR", 1, 2, tmplput_ContextStringArray, NULL, CTX_STRBUFARR);
02740        RegisterNamespace("ITERATE", 2, 100, tmpl_iterate_subtmpl, preeval_iterate, CTX_NONE);
02741        RegisterNamespace("DOBOXED", 1, 2, tmpl_do_boxed, NULL, CTX_NONE);
02742        RegisterNamespace("DOTABBED", 2, 100, tmpl_do_tabbed, preeval_do_tabbed, CTX_NONE);
02743        RegisterControlNS(HKEY("TAB:N"), 0, 0, tmplput_TAB_N, CTX_TAB);
02744        RegisterControlNS(HKEY("TAB:SUBJECT"), 0, 1, tmplput_TAB_TITLE, CTX_TAB);
02745 
02746 
02747        RegisterNamespace("LONGVECTOR", 1, 1, tmplput_long_vector, NULL, CTX_LONGVECTOR);
02748 
02749 
02750        RegisterConditional(HKEY("COND:CONTEXTSTR"), 3, ConditionalContextStr, CTX_STRBUF);
02751        RegisterConditional(HKEY("COND:CONTEXTSTRARR"), 4, ConditionalContextStrinArray, CTX_STRBUFARR);
02752        RegisterConditional(HKEY("COND:LONGVECTOR"), 4, ConditionalLongVector, CTX_LONGVECTOR);
02753 
02754 
02755        RegisterControlConditional(HKEY("COND:ITERATE:ISGROUPCHANGE"), 2, 
02756                                conditional_ITERATE_ISGROUPCHANGE, 
02757                                CTX_ITERATE);
02758        RegisterControlConditional(HKEY("COND:ITERATE:LASTN"), 2, 
02759                                conditional_ITERATE_LASTN, 
02760                                CTX_ITERATE);
02761        RegisterControlConditional(HKEY("COND:ITERATE:FIRSTN"), 2, 
02762                                conditional_ITERATE_FIRSTN, 
02763                                CTX_ITERATE);
02764 
02765        RegisterControlNS(HKEY("ITERATE:ODDEVEN"), 0, 0, tmplput_ITERATE_ODDEVEN, CTX_ITERATE);
02766        RegisterControlNS(HKEY("ITERATE:KEY"), 0, 0, tmplput_ITERATE_KEY, CTX_ITERATE);
02767        RegisterControlNS(HKEY("ITERATE:N"), 0, 0, tmplput_ITERATE_LASTN, CTX_ITERATE);
02768        RegisterNamespace("CURRENTFILE", 0, 1, tmplput_CURRENT_FILE, NULL, CTX_NONE);
02769        RegisterNamespace("DEF:STR", 1, 1, tmplput_DefStr, NULL, CTX_NONE);
02770        RegisterNamespace("DEF:VAL", 1, 1, tmplput_DefVal, NULL, CTX_NONE);
02771 
02772 
02773 
02774 
02775 }
02776 
02777 void
02778 ServerStartModule_SUBST
02779 (void)
02780 {
02781        LocalTemplateCache = NewHash(1, NULL);
02782        TemplateCache = NewHash(1, NULL);
02783 
02784        GlobalNS = NewHash(1, NULL);
02785        Iterators = NewHash(1, NULL);
02786        Conditionals = NewHash(1, NULL);
02787        SortHash = NewHash(1, NULL);
02788        Defines = NewHash(1, NULL);
02789 }
02790 
02791 void
02792 FinalizeModule_SUBST
02793 (void)
02794 {
02795 
02796 }
02797 
02798 void 
02799 ServerShutdownModule_SUBST
02800 (void)
02801 {
02802        DeleteHash(&TemplateCache);
02803        DeleteHash(&LocalTemplateCache);
02804 
02805        DeleteHash(&GlobalNS);
02806        DeleteHash(&Iterators);
02807        DeleteHash(&Conditionals);
02808        DeleteHash(&SortHash);
02809        DeleteHash(&Defines);
02810 }
02811 
02812 
02813 void
02814 SessionNewModule_SUBST
02815 (wcsession *sess)
02816 {
02817 
02818 }
02819 
02820 void
02821 SessionAttachModule_SUBST
02822 (wcsession *sess)
02823 {
02824 }
02825 
02826 void
02827 SessionDetachModule_SUBST
02828 (wcsession *sess)
02829 {
02830        FreeStrBuf(&sess->WFBuf);
02831 }
02832 
02833 void 
02834 SessionDestroyModule_SUBST  
02835 (wcsession *sess)
02836 {
02837 
02838 }