5 * \defgroup Subst Variable substitution type stuff
6 * \ingroup CitadelConfig
12 #include <sys/types.h>
18 #define SHOW_ME_VAPPEND_PRINTF
21 #include "webserver.h"
23 extern char *static_dirs[PATH_MAX]; /**< Disk representation */
25 HashList *WirelessTemplateCache;
26 HashList *WirelessLocalTemplateCache;
27 HashList *TemplateCache;
28 HashList *LocalTemplateCache;
32 HashList *Contitionals;
34 int LoadTemplates = 0;
37 #define SV_CONDITIONAL 2
38 #define SV_NEG_CONDITIONAL 3
39 #define SV_CUST_STR_CONDITIONAL 4
42 typedef struct _WCTemplate {
47 WCTemplateToken **Tokens;
50 typedef struct _HashHandler {
53 WCHandlerFunc HandlerFunc;
56 void *load_template(StrBuf *filename, StrBuf *Key, HashList *PutThere);
58 void RegisterNS(const char *NSName, long len, int nMinArgs, int nMaxArgs, WCHandlerFunc HandlerFunc)
60 HashHandler *NewHandler;
62 NewHandler = (HashHandler*) malloc(sizeof(HashHandler));
63 NewHandler->nMinArgs = nMinArgs;
64 NewHandler->nMaxArgs = nMaxArgs;
65 NewHandler->HandlerFunc = HandlerFunc;
66 Put(GlobalNS, NSName, len, NewHandler, NULL);
71 * \brief debugging function to print array to log
73 void VarPrintTransition(void *vVar1, void *vVar2, int odd){}
75 * \brief debugging function to print array to log
77 void VarPrintEntry(const char *Key, void *vSubst, int odd)
80 lprintf(1,"Subst[%s] : ", Key);
81 ptr = (wcsubst*) vSubst;
83 switch(ptr->wcs_type) {
85 lprintf(1, " -> %s\n", ChrPtr(ptr->wcs_value));
88 lprintf(1, " -> Server [%s]\n", ChrPtr(ptr->wcs_value));
91 lprintf(1, " -> function at [%0xd]\n", ptr->wcs_function);
94 lprintf(1," WARNING: invalid type: [%ld]!\n", ptr->wcs_type);
101 * \brief Clear out the list of substitution variables local to this session
103 void clear_substs(struct wcsession *wc) {
105 if (wc->vars != NULL) {
106 DeleteHash(&wc->vars);
111 * \brief Clear out the list of substitution variables local to this session
113 void clear_local_substs(void) {
132 void FlushPayload(wcsubst *ptr, int reusestrbuf, int type)
134 int NeedNew = NeedNewBuf(type);
135 switch(ptr->wcs_type) {
139 if (reusestrbuf && NeedNew) {
140 FlushStrBuf(ptr->wcs_value);
144 FreeStrBuf(&ptr->wcs_value);
145 ptr->wcs_value = NULL;
149 ptr->wcs_function = NULL;
150 if (reusestrbuf && NeedNew)
151 ptr->wcs_value = NewStrBuf();
154 ptr->wcs_value = NULL;
155 if (reusestrbuf && NeedNew)
156 ptr->wcs_value = NewStrBuf();
160 if (reusestrbuf && NeedNew)
161 ptr->wcs_value = NewStrBuf();
164 if (reusestrbuf && NeedNew)
165 ptr->wcs_value = NewStrBuf();
172 * \brief destructor; kill one entry.
174 void deletevar(void *data)
176 wcsubst *ptr = (wcsubst*)data;
177 FlushPayload(ptr, 0, ptr->wcs_type);
182 wcsubst *NewSubstVar(const char *keyname, int keylen, int type)
185 struct wcsession *WCC = WC;
187 ptr = (wcsubst *) malloc(sizeof(wcsubst));
188 memset(ptr, 0, sizeof(wcsubst));
190 ptr->wcs_type = type;
191 safestrncpy(ptr->wcs_key, keyname, sizeof ptr->wcs_key);
192 Put(WCC->vars, keyname, keylen, ptr, deletevar);
194 switch(ptr->wcs_type) {
197 ptr->wcs_value = NewStrBuf();
211 * \brief Add a substitution variable (local to this session) (strlen version...)
212 * \param keyname the replacementstring to substitute
213 * \param keytype the kind of the key
214 * \param format the format string ala printf
215 * \param ... the arguments to substitute in the formatstring
217 void SVPRINTF(char *keyname, int keytype, const char *format,...)
223 struct wcsession *WCC = WC;
225 keylen = strlen(keyname);
227 * First look if we're doing a replacement of
230 /*PrintHash(WCC->vars, VarPrintTransition, VarPrintEntry);*/
231 if (GetHash(WCC->vars, keyname, keylen, &vPtr)) {
232 ptr = (wcsubst*)vPtr;
233 FlushPayload(ptr, keytype, keytype);
234 ptr->wcs_type = keytype;
236 else /** Otherwise allocate a new one */
238 ptr = NewSubstVar(keyname, keylen, keytype);
241 /** Format the string */
242 va_start(arg_ptr, format);
243 StrBufVAppendPrintf(ptr->wcs_value, format, arg_ptr);
248 * \brief Add a substitution variable (local to this session)
249 * \param keyname the replacementstring to substitute
250 * \param keytype the kind of the key
251 * \param format the format string ala printf
252 * \param ... the arguments to substitute in the formatstring
254 void svprintf(char *keyname, size_t keylen, int keytype, const char *format,...)
259 struct wcsession *WCC = WC;
262 * First look if we're doing a replacement of
265 /*PrintHash(WCC->vars, VarPrintTransition, VarPrintEntry);*/
266 if (GetHash(WCC->vars, keyname, keylen, &vPtr)) {
267 ptr = (wcsubst*)vPtr;
268 FlushPayload(ptr, 1, keytype);
269 ptr->wcs_type = keytype;
271 else /** Otherwise allocate a new one */
273 ptr = NewSubstVar(keyname, keylen, keytype);
276 /** Format the string and save it */
277 va_start(arg_ptr, format);
278 StrBufVAppendPrintf(ptr->wcs_value, format, arg_ptr);
283 * \brief Add a substitution variable (local to this session)
284 * \param keyname the replacementstring to substitute
285 * \param keytype the kind of the key
286 * \param format the format string ala printf
287 * \param ... the arguments to substitute in the formatstring
289 void SVPut(char *keyname, size_t keylen, int keytype, char *Data)
293 struct wcsession *WCC = WC;
297 * First look if we're doing a replacement of
300 /*PrintHash(WCC->vars, VarPrintTransition, VarPrintEntry);*/
301 if (GetHash(WCC->vars, keyname, keylen, &vPtr)) {
302 ptr = (wcsubst*)vPtr;
303 FlushPayload(ptr, 1, keytype);
304 ptr->wcs_type = keytype;
306 else /** Otherwise allocate a new one */
308 ptr = NewSubstVar(keyname, keylen, keytype);
310 StrBufAppendBufPlain(ptr->wcs_value, Data, -1, 0);
314 * \brief Add a substitution variable (local to this session)
315 * \param keyname the replacementstring to substitute
316 * \param keytype the kind of the key
317 * \param format the format string ala printf
318 * \param ... the arguments to substitute in the formatstring
320 void SVPutLong(char *keyname, size_t keylen, long Data)
324 struct wcsession *WCC = WC;
328 * First look if we're doing a replacement of
331 /*PrintHash(WCC->vars, VarPrintTransition, VarPrintEntry);*/
332 if (GetHash(WCC->vars, keyname, keylen, &vPtr)) {
333 ptr = (wcsubst*)vPtr;
334 FlushPayload(ptr, 1, WCS_LONG);
335 ptr->wcs_type = WCS_LONG;
337 else /** Otherwise allocate a new one */
339 ptr = NewSubstVar(keyname, keylen, WCS_LONG);
345 * \brief Add a substitution variable (local to this session) that does a callback
346 * \param keyname the keystring to substitute
347 * \param fcn_ptr the function callback to give the substitution string
349 void SVCallback(char *keyname, size_t keylen, var_callback_fptr fcn_ptr)
353 struct wcsession *WCC = WC;
356 * First look if we're doing a replacement of
359 /*PrintHash(WCC->vars, VarPrintTransition, VarPrintEntry);*/
360 if (GetHash(WCC->vars, keyname, keylen, &vPtr)) {
361 ptr = (wcsubst*)vPtr;
362 FlushPayload(ptr, 1, WCS_FUNCTION);
363 ptr->wcs_type = WCS_FUNCTION;
365 else /** Otherwise allocate a new one */
367 ptr = NewSubstVar(keyname, keylen, WCS_FUNCTION);
370 ptr->wcs_function = fcn_ptr;
372 inline void SVCALLBACK(char *keyname, var_callback_fptr fcn_ptr)
374 SVCallback(keyname, strlen(keyname), fcn_ptr);
379 void SVPUTBuf(const char *keyname, int keylen, StrBuf *Buf, int ref)
383 struct wcsession *WCC = WC;
386 * First look if we're doing a replacement of
389 /*PrintHash(WCC->vars, VarPrintTransition, VarPrintEntry);*/
390 if (GetHash(WCC->vars, keyname, keylen, &vPtr)) {
391 ptr = (wcsubst*)vPtr;
392 FlushPayload(ptr, 0, (ref)?WCS_STRBUF_REF:WCS_STRBUF);
393 ptr->wcs_type = (ref)?WCS_STRBUF_REF:WCS_STRBUF;
395 else /** Otherwise allocate a new one */
397 ptr = NewSubstVar(keyname, keylen, (ref)?WCS_STRBUF_REF:WCS_STRBUF);
399 ptr->wcs_value = Buf;
403 * \brief back end for print_value_of() ... does a server command
404 * \param servcmd server command to execute on the citadel server
406 void pvo_do_cmd(StrBuf *Target, StrBuf *servcmd) {
410 serv_puts(ChrPtr(servcmd));
411 len = serv_getln(buf, sizeof buf);
417 StrBufAppendPrintf(Target, "%s\n", &buf[4]);
420 _fmout(Target, "CENTER");
423 StrBufAppendPrintf(Target, "%s\n", &buf[4]);
430 * \brief Print the value of a variable
431 * \param keyname get a key to print
433 void print_value_of(StrBuf *Target, const char *keyname, size_t keylen) {
434 struct wcsession *WCC = WC;
438 /*if (WCC->vars != NULL) PrintHash(WCC->vars, VarPrintTransition, VarPrintEntry);*/
439 /// TODO: debricated!
440 if (keyname[0] == '=') {
441 DoTemplate(keyname+1, keylen - 1, NULL, NULL);
444 //////TODO: if param[1] == "U" -> urlescape
446 /** Page-local variables */
447 if ((WCC->vars!= NULL) && GetHash(WCC->vars, keyname, keylen, &vVar)) {
448 ptr = (wcsubst*) vVar;
449 switch(ptr->wcs_type) {
451 StrBufAppendBuf(Target, ptr->wcs_value, 0);
454 pvo_do_cmd(Target, ptr->wcs_value);
457 (*ptr->wcs_function) ();
461 StrBufAppendBuf(Target, ptr->wcs_value, 0);
464 StrBufAppendPrintf(Target, "%ld", ptr->lvalue);
467 lprintf(1,"WARNING: invalid value in SV-Hash at %s!\n", keyname);
468 StrBufAppendPrintf(Target, "<pre>WARNING: \ninvalid value in SV-Hash at %s!</pre>", keyname);
473 int CompareSubstToToken(TemplateParam *ParamToCompare, TemplateParam *ParamToLookup)
475 struct wcsession *WCC = WC;
479 if ((WCC->vars!= NULL) && GetHash(WCC->vars, ParamToLookup->Start,
480 ParamToLookup->len, &vVar)) {
481 ptr = (wcsubst*) vVar;
482 switch(ptr->wcs_type) {
486 if (ParamToCompare->Type == TYPE_STR)
487 return ((ParamToCompare->len == StrLength(ptr->wcs_value)) &&
488 (strcmp(ParamToCompare->Start, ChrPtr(ptr->wcs_value)) == 0));
490 return ParamToCompare->lvalue == StrTol(ptr->wcs_value);
498 if (ParamToCompare->Type == TYPE_STR)
501 return ParamToCompare->lvalue == ptr->lvalue;
504 lprintf(1,"WARNING: invalid value in SV-Hash at %s!\n",
505 ParamToLookup->Start);
511 int CompareSubstToStrBuf(StrBuf *Compare, TemplateParam *ParamToLookup)
513 struct wcsession *WCC = WC;
517 if ((WCC->vars!= NULL) && GetHash(WCC->vars, ParamToLookup->Start,
518 ParamToLookup->len, &vVar)) {
519 ptr = (wcsubst*) vVar;
520 switch(ptr->wcs_type) {
524 return ((StrLength(Compare) == StrLength(ptr->wcs_value)) &&
525 (strcmp(ChrPtr(Compare), ChrPtr(ptr->wcs_value)) == 0));
532 return StrTol(Compare) == ptr->lvalue;
534 lprintf(1,"WARNING: invalid value in SV-Hash at %s!\n",
535 ParamToLookup->Start);
542 void PutNewToken(WCTemplate *Template, WCTemplateToken *NewToken)
544 if (Template->nTokensUsed + 1 >= Template->TokenSpace) {
545 if (Template->TokenSpace <= 0) {
546 Template->Tokens = (WCTemplateToken**)malloc(
547 sizeof(WCTemplateToken*) * 10);
548 Template->TokenSpace = 10;
551 WCTemplateToken **NewTokens;
552 NewTokens= (WCTemplateToken**)malloc(
553 sizeof(WCTemplateToken*) *
554 Template->TokenSpace * 2);
555 memcpy(NewTokens, Template->Tokens,
556 sizeof(WCTemplateToken*) * Template->nTokensUsed);
557 free(Template->Tokens);
558 Template->TokenSpace *= 2;
559 Template->Tokens = NewTokens;
562 Template->Tokens[(Template->nTokensUsed)++] = NewToken;
565 TemplateParam *GetNextParameter(StrBuf *Buf, const char **pCh, const char *pe, WCTemplateToken *Token, WCTemplate *pTmpl)
567 const char *pch = *pCh;
568 const char *pchs, *pche;
569 TemplateParam *Parm = (TemplateParam *) malloc(sizeof(TemplateParam));
572 /* Skip leading whitespaces */
573 while ((*pch == ' ' )||
576 (*pch == '\n')) pch ++;
579 else if (*pch == '\'')
584 Parm->Type = TYPE_STR;
587 ( (pch > pchs) && (*(pch - 1) == '\\'))
593 lprintf(1, "Error (in '%s' line %ld); "
594 "evaluating template param [%s] in Token [%s]\n",
595 ChrPtr(pTmpl->FileName),
597 ChrPtr(Token->FlatToken),
604 StrBufPeek(Buf, pch, -1, '\0');
605 if (LoadTemplates > 1) {
606 lprintf(1, "DBG: got param [%s] %ld %ld\n",
607 pchs, pche - pchs, strlen(pchs));
610 Parm->len = pche - pchs;
611 pch ++; /* move after trailing quote */
615 Parm->Type = TYPE_LONG;
617 while ((pch <= pe) &&
624 StrBufPeek(Buf, pch, -1, '\0');
625 Parm->lvalue = atol(pchs);
631 lprintf(1, "Error (in '%s' line %ld); "
632 "evaluating long template param [%s] in Token [%s]\n",
633 ChrPtr(pTmpl->FileName),
635 ChrPtr(Token->FlatToken),
641 while ((*pch == ' ' )||
645 (*pch == '\n')) pch ++;
651 WCTemplateToken *NewTemplateSubstitute(StrBuf *Buf,
653 const char *pTmplStart,
654 const char *pTmplEnd,
659 TemplateParam *Param;
660 WCTemplateToken *NewToken = (WCTemplateToken*)malloc(sizeof(WCTemplateToken));
663 NewToken->Line = Line + 1;
664 NewToken->pTokenStart = pTmplStart;
665 NewToken->TokenStart = pTmplStart - pStart;
666 NewToken->TokenEnd = (pTmplEnd - pStart) - NewToken->TokenStart;
667 NewToken->pTokenEnd = pTmplEnd;
668 NewToken->NameEnd = NewToken->TokenEnd - 2;
669 NewToken->FlatToken = NewStrBufPlain(pTmplStart + 2, pTmplEnd - pTmplStart - 2);
671 StrBufPeek(Buf, pTmplStart, + 1, '\0');
672 StrBufPeek(Buf, pTmplEnd, -1, '\0');
673 pch = NewToken->pName = pTmplStart + 2;
675 NewToken->HaveParameters = 0;;
676 NewToken->nParameters = 0;
678 while (pch < pTmplEnd - 1) {
680 StrBufPeek(Buf, pch, -1, '\0');
681 NewToken->NameEnd = pch - NewToken->pName;
683 while (pch < pTmplEnd - 1) {
684 Param = GetNextParameter(Buf, &pch, pTmplEnd - 1, NewToken, pTmpl);
686 NewToken->HaveParameters = 1;
687 if (NewToken->nParameters > MAXPARAM) {
688 lprintf(1, "Error (in '%s' line %ld); "
689 "only [%ld] Params allowed in Tokens [%s]\n",
690 ChrPtr(pTmpl->FileName),
693 ChrPtr(NewToken->FlatToken));
697 NewToken->Params[NewToken->nParameters++] = Param;
701 if((NewToken->NameEnd == 1) &&
702 (NewToken->HaveParameters == 1))
705 if ((NewToken->nParameters == 1) &&
706 (*(NewToken->pName) == '_'))
707 NewToken->Flags = SV_GETTEXT;
708 else if ((NewToken->nParameters == 1) &&
709 (*(NewToken->pName) == '='))
710 NewToken->Flags = SV_SUBTEMPL;
711 else if ((NewToken->nParameters >= 2) &&
712 (*(NewToken->pName) == '%'))
713 NewToken->Flags = SV_CUST_STR_CONDITIONAL;
714 else if ((NewToken->nParameters >= 2) &&
715 (*(NewToken->pName) == '?'))
716 NewToken->Flags = SV_CONDITIONAL;
717 else if ((NewToken->nParameters >=2) &&
718 (*(NewToken->pName) == '!'))
719 NewToken->Flags = SV_NEG_CONDITIONAL;
727 void FreeToken(WCTemplateToken **Token)
730 FreeStrBuf(&(*Token)->FlatToken);
731 if ((*Token)->HaveParameters)
732 for (i = 0; i < (*Token)->nParameters; i++)
733 free((*Token)->Params[i]);
740 void FreeWCTemplate(void *vFreeMe)
743 WCTemplate *FreeMe = (WCTemplate*)vFreeMe;
745 if (FreeMe->TokenSpace > 0) {
746 for (i = 0; i < FreeMe->nTokensUsed; i ++) {
747 FreeToken(&FreeMe->Tokens[i]);
749 free(FreeMe->Tokens);
751 FreeStrBuf(&FreeMe->FileName);
752 FreeStrBuf(&FreeMe->Data);
757 int EvaluateConditional(StrBuf *Target, WCTemplateToken *Token, WCTemplate *pTmpl, void *Context, int Neg, int state)
759 void *vConditional = NULL;
760 ConditionalStruct *Cond;
762 if ((Token->Params[0]->len == 1) &&
763 (Token->Params[0]->Start[0] == 'X'))
764 return (state != 0)?Token->Params[1]->lvalue:0;
766 if (!GetHash(Contitionals,
767 Token->Params[0]->Start,
768 Token->Params[0]->len,
770 (vConditional == NULL)) {
771 lprintf(1, "Conditional [%s] (in '%s' line %ld); Not found![%s]\n",
772 Token->Params[0]->Start,
773 ChrPtr(pTmpl->FileName),
775 ChrPtr(Token->FlatToken));
778 "<pre>\nConditional [%s] (in '%s' line %ld); Not found!\n[%s]\n</pre>\n",
779 Token->Params[0]->Start,
780 ChrPtr(pTmpl->FileName),
782 ChrPtr(Token->FlatToken));
785 Cond = (ConditionalStruct *) vConditional;
787 if (Token->nParameters < Cond->nParams) {
788 lprintf(1, "Conditional [%s] (in '%s' line %ld); needs %ld Params![%s]\n",
789 Token->Params[0]->Start,
790 ChrPtr(pTmpl->FileName),
793 ChrPtr(Token->FlatToken));
796 "<pre>\nConditional [%s] (in '%s' line %ld); needs %ld Params!\n[%s]\n</pre>\n",
797 Token->Params[0]->Start,
798 ChrPtr(pTmpl->FileName),
801 ChrPtr(Token->FlatToken));
804 if (Cond->CondF(Token, Context) == Neg)
805 return Token->Params[1]->lvalue;
809 int EvaluateToken(StrBuf *Target, WCTemplateToken *Token, WCTemplate *pTmpl, void *Context, int state)
812 // much output, since pName is not terminated...
813 // lprintf(1,"Doing token: %s\n",Token->pName);
814 switch (Token->Flags) {
816 TmplGettext(Target, Token->nParameters, Token);
818 case SV_CONDITIONAL: /** Forward conditional evaluation */
819 return EvaluateConditional(Target, Token, pTmpl, Context, 1, state);
821 case SV_NEG_CONDITIONAL: /** Reverse conditional evaluation */
822 return EvaluateConditional(Target, Token, pTmpl, Context, 0, state);
824 case SV_CUST_STR_CONDITIONAL: /** Conditional put custom strings from params */
825 if (Token->nParameters >= 6) {
826 if (EvaluateConditional(Target, Token, pTmpl, Context, 0, state))
827 StrBufAppendBufPlain(Target,
828 Token->Params[5]->Start,
829 Token->Params[5]->len,
832 StrBufAppendBufPlain(Target,
833 Token->Params[4]->Start,
834 Token->Params[4]->len,
839 if (Token->nParameters == 1)
840 DoTemplate(Token->Params[0]->Start, Token->Params[0]->len, NULL, NULL);
843 if (GetHash(GlobalNS, Token->pName, Token->NameEnd, &vVar)) {
844 HashHandler *Handler;
845 Handler = (HashHandler*) vVar;
846 if ((Token->nParameters < Handler->nMinArgs) ||
847 (Token->nParameters > Handler->nMaxArgs)) {
848 lprintf(1, "Handler [%s] (in '%s' line %ld); "
849 "doesn't work with %ld params [%s]\n",
851 ChrPtr(pTmpl->FileName),
854 ChrPtr(Token->FlatToken));
857 "<pre>\nHandler [%s] (in '%s' line %ld);"
858 " doesn't work with %ld params!\n[%s]\n</pre>\n",
860 ChrPtr(pTmpl->FileName),
863 ChrPtr(Token->FlatToken));
866 Handler->HandlerFunc(Target,
869 Context); /*TODO: subset of that */
874 print_value_of(Target, Token->pName, Token->NameEnd);
880 void ProcessTemplate(WCTemplate *Tmpl, StrBuf *Target, void *Context)
882 WCTemplate *pTmpl = Tmpl;
885 const char *pData, *pS;
888 if (LoadTemplates != 0) {
889 if (LoadTemplates > 1)
890 lprintf(1, "DBG: ----- loading: [%s] ------ \n",
891 ChrPtr(Tmpl->FileName));
892 pTmpl = load_template(Tmpl->FileName, NULL, NULL);
896 "<pre>\nError loading Template [%s]\n See Logfile for details\n</pre>\n",
897 ChrPtr(Tmpl->FileName));
905 pS = pData = ChrPtr(pTmpl->Data);
906 len = StrLength(pTmpl->Data);
910 if (i >= pTmpl->nTokensUsed) {
911 StrBufAppendBufPlain(Target,
913 len - (pData - pS), 0);
917 StrBufAppendBufPlain(
919 pTmpl->Tokens[i]->pTokenStart - pData, 0);
920 state = EvaluateToken(Target, pTmpl->Tokens[i], pTmpl, Context, state);
921 while ((state != 0) && (i+1 < pTmpl->nTokensUsed)) {
922 /* condition told us to skip till its end condition */
924 if ((pTmpl->Tokens[i]->Flags == SV_CONDITIONAL) ||
925 (pTmpl->Tokens[i]->Flags == SV_NEG_CONDITIONAL)) {
926 if (state == EvaluateConditional(
931 pTmpl->Tokens[i]->Flags,
936 pData = pTmpl->Tokens[i++]->pTokenEnd + 1;
937 if (i > pTmpl->nTokensUsed)
941 if (LoadTemplates != 0) {
942 FreeWCTemplate(pTmpl);
948 * \brief Display a variable-substituted template
949 * \param templatename template file to load
951 void *prepare_template(StrBuf *filename, StrBuf *Key, HashList *PutThere)
953 WCTemplate *NewTemplate;
954 NewTemplate = (WCTemplate *) malloc(sizeof(WCTemplate));
955 NewTemplate->Data = NULL;
956 NewTemplate->FileName = NewStrBufDup(filename);
957 NewTemplate->nTokensUsed = 0;
958 NewTemplate->TokenSpace = 0;
959 NewTemplate->Tokens = NULL;
961 Put(PutThere, ChrPtr(Key), StrLength(Key), NewTemplate, FreeWCTemplate);
966 * \brief Display a variable-substituted template
967 * \param templatename template file to load
969 void *load_template(StrBuf *filename, StrBuf *Key, HashList *PutThere)
973 const char *pS, *pE, *pch, *Err;
976 WCTemplate *NewTemplate;
978 fd = open(ChrPtr(filename), O_RDONLY);
980 lprintf(1, "ERROR: could not open template '%s' - %s\n",
981 ChrPtr(filename), strerror(errno));
985 if (fstat(fd, &statbuf) == -1) {
986 lprintf(1, "ERROR: could not stat template '%s' - %s\n",
987 ChrPtr(filename), strerror(errno));
991 NewTemplate = (WCTemplate *) malloc(sizeof(WCTemplate));
992 NewTemplate->Data = NewStrBufPlain(NULL, statbuf.st_size);
993 NewTemplate->FileName = NewStrBufDup(filename);
994 NewTemplate->nTokensUsed = 0;
995 NewTemplate->TokenSpace = 0;
996 NewTemplate->Tokens = NULL;
997 if (StrBufReadBLOB(NewTemplate->Data, &fd, 1, statbuf.st_size, &Err) < 0) {
999 FreeWCTemplate(NewTemplate);
1000 lprintf(1, "ERROR: reading template '%s' - %s<br />\n",
1001 ChrPtr(filename), strerror(errno));
1007 pS = pch = ChrPtr(NewTemplate->Data);
1008 pE = pS + StrLength(NewTemplate->Data);
1010 const char *pts, *pte;
1012 int InDoubleQuotes = 0;
1014 /** Find one <? > */
1016 for (; pch < pE; pch ++) {
1017 if ((*pch=='<')&&(*(pch + 1)=='?'))
1019 if (*pch=='\n') Line ++;
1025 /** Found one? parse it. */
1026 for (; pch < pE - 1; pch ++) {
1028 InDoubleQuotes = ! InDoubleQuotes;
1029 else if (*pch == '\'')
1030 InQuotes = ! InQuotes;
1031 else if ((!InQuotes && !InDoubleQuotes) &&
1032 ((*pch!='\\')&&(*(pch + 1)=='>'))) {
1040 PutNewToken(NewTemplate,
1041 NewTemplateSubstitute(NewTemplate->Data, pS, pts, pte, Line, NewTemplate));
1044 if (LoadTemplates == 0)
1045 Put(PutThere, ChrPtr(Key), StrLength(Key), NewTemplate, FreeWCTemplate);
1050 ///void PrintTemplate(const char *Key, void *vSubst, int odd)
1051 const char* PrintTemplate(void *vSubst)
1053 WCTemplate *Tmpl = vSubst;
1055 return ChrPtr(Tmpl->FileName);
1061 * \brief Display a variable-substituted template
1062 * \param templatename template file to load
1064 void DoTemplate(const char *templatename, long len, void *Context, StrBuf *Target)
1067 HashList *StaticLocal;
1072 if (WC->is_mobile) {
1073 Static = WirelessTemplateCache;
1074 StaticLocal = WirelessLocalTemplateCache;
1077 Static = TemplateCache;
1078 StaticLocal = LocalTemplateCache;
1083 lprintf (1, "Can't to load a template with empty name!\n");
1084 StrBufAppendPrintf(Target, "<pre>\nCan't to load a template with empty name!\n</pre>");
1088 if (!GetHash(StaticLocal, templatename, len, &vTmpl) &&
1089 !GetHash(Static, templatename, len, &vTmpl)) {
1090 lprintf (1, "didn't find Template [%s] %ld %ld\n", templatename, len , (long)strlen(templatename));
1091 StrBufAppendPrintf(Target, "<pre>\ndidn't find Template [%s] %ld %ld\n</pre>",
1093 (long)strlen(templatename));
1094 /// dbg_PrintHash(Static, PrintTemplate, NULL);
1095 // PrintHash(Static, VarPrintTransition, PrintTemplate);
1100 ProcessTemplate(vTmpl, Target, Context);
1103 int LoadTemplateDir(const char *DirName, HashList *wireless, HashList *big)
1108 DIR *filedir = NULL;
1109 struct dirent *filedir_entry;
1115 StrBufPrintf(Dir, "%s/t", DirName);
1116 filedir = opendir (ChrPtr(Dir));
1117 if (filedir == NULL) {
1122 FileName = NewStrBuf();
1124 while ((filedir_entry = readdir(filedir)))
1128 #ifdef _DIRENT_HAVE_D_NAMELEN
1129 d_namelen = filedir_entry->d_namelen;
1131 d_namelen = strlen(filedir_entry->d_name);
1133 d_without_ext = d_namelen;
1134 while ((d_without_ext > 0) && (filedir_entry->d_name[d_without_ext] != '.'))
1136 if ((d_without_ext == 0) || (d_namelen < 3))
1138 if ((d_namelen > 1) && filedir_entry->d_name[d_namelen - 1] == '~')
1139 continue; /* Ignore backup files... */
1141 IsMobile = (strstr(filedir_entry->d_name, ".m.html")!= NULL);
1142 PStart = filedir_entry->d_name;
1143 StrBufPrintf(FileName, "%s/%s", ChrPtr(Dir), filedir_entry->d_name);
1144 MinorPtr = strchr(filedir_entry->d_name, '.');
1145 if (MinorPtr != NULL)
1147 StrBufPlain(Tag, filedir_entry->d_name, MinorPtr - filedir_entry->d_name);
1150 lprintf(1, "%s %d %s\n",ChrPtr(FileName), IsMobile, ChrPtr(Tag));
1151 if (LoadTemplates == 0)
1152 load_template(FileName, Tag, (IsMobile)?wireless:big);
1154 prepare_template(FileName, Tag, (IsMobile)?wireless:big);
1157 FreeStrBuf(&FileName);
1163 void InitTemplateCache(void)
1165 LoadTemplateDir(static_dirs[0],
1166 WirelessTemplateCache,
1168 LoadTemplateDir(static_dirs[1],
1169 WirelessLocalTemplateCache,
1170 LocalTemplateCache);
1173 void tmplput_serv_ip(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context)
1175 StrBufAppendPrintf(Target, "%d", WC->ctdl_pid);
1178 void tmplput_serv_nodename(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context)
1180 StrEscAppend(Target, NULL, serv_info.serv_nodename, 0, 0);
1183 void tmplput_serv_humannode(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context)
1185 StrEscAppend(Target, NULL, serv_info.serv_humannode, 0, 0);
1188 void tmplput_serv_fqdn(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context)
1190 StrEscAppend(Target, NULL, serv_info.serv_fqdn, 0, 0);
1193 void tmmplput_serv_software(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context)
1195 StrEscAppend(Target, NULL, serv_info.serv_software, 0, 0);
1198 void tmplput_serv_rev_level(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context)
1200 StrBufAppendPrintf(Target, "%d.%02d",
1201 serv_info.serv_rev_level / 100,
1202 serv_info.serv_rev_level % 100);
1205 void tmmplput_serv_bbs_city(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context)
1207 StrEscAppend(Target, NULL, serv_info.serv_bbs_city, 0, 0);
1210 void tmplput_current_user(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context)
1212 StrEscAppend(Target, NULL, WC->wc_fullname, 0, 0);
1215 void tmplput_current_room(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context)
1217 StrEscAppend(Target, NULL, WC->wc_roomname, 0, 0);
1221 typedef struct _HashIterator {
1222 HashList *StaticList;
1223 int AdditionalParams;
1224 RetrieveHashlistFunc GetHash;
1225 HashDestructorFunc Destructor;
1226 SubTemplFunc DoSubTemplate;
1229 void tmpl_iterate_subtmpl(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context)
1241 if (!GetHash(Iterators,
1242 Tokens->Params[0]->Start,
1243 Tokens->Params[0]->len,
1245 lprintf(1, "unknown Iterator [%s] (in line %ld); "
1247 Tokens->Params[0]->Start,
1249 ChrPtr(Tokens->FlatToken));
1252 "<pre>\nunknown Iterator [%s] (in line %ld); \n"
1254 Tokens->Params[0]->Start,
1256 ChrPtr(Tokens->FlatToken));
1260 It = (HashIterator*) vIt;
1262 if (Tokens->nParameters < It->AdditionalParams + 2) {
1263 lprintf(1, "Iterator [%s] (in line %ld); "
1264 "doesn't work with %ld params [%s]\n",
1265 Tokens->Params[0]->Start,
1267 Tokens->nParameters,
1268 ChrPtr(Tokens->FlatToken));
1271 "<pre>Iterator [%s] \n(in line %ld);\n"
1272 "doesn't work with %ld params \n[%s]\n</pre>",
1273 Tokens->Params[0]->Start,
1275 Tokens->nParameters,
1276 ChrPtr(Tokens->FlatToken));
1280 if (It->StaticList == NULL)
1281 List = It->GetHash(Tokens);
1283 List = It->StaticList;
1285 SubBuf = NewStrBuf();
1286 it = GetNewHashPos();
1287 while (GetNextHashPos(List, it, &len, &Key, &vContext)) {
1288 svprintf(HKEY("ITERATE:ODDEVEN"), WCS_STRING, "%s", (oddeven)?"odd":"even");
1289 svprintf(HKEY("ITERATE:KEY"), WCS_STRING, "%s",Key);
1290 It->DoSubTemplate(SubBuf, vContext, Tokens);
1291 DoTemplate(Tokens->Params[1]->Start,
1292 Tokens->Params[1]->len,
1295 StrBufAppendBuf(Target, SubBuf, 0);
1296 FlushStrBuf(SubBuf);
1297 oddeven = ~ oddeven;
1299 FreeStrBuf(&SubBuf);
1301 if (It->Destructor != NULL)
1302 It->Destructor(List);
1305 int ConditionalVar(WCTemplateToken *Tokens, void *Context)
1310 if (!GetHash(WC->vars,
1311 Tokens->Params[2]->Start,
1312 Tokens->Params[2]->len,
1315 subst = (wcsubst*) vsubst;
1316 switch(subst->wcs_type) {
1318 return (subst->wcs_function!=NULL);
1320 lprintf(1, " -> Server [%s]\n", subst->wcs_value);////todo
1324 case WCS_STRBUF_REF:
1325 if (Tokens->nParameters < 4)
1327 return (strcmp(Tokens->Params[3]->Start, ChrPtr(subst->wcs_value)) == 0);
1329 if (Tokens->nParameters < 4)
1330 return (subst->lvalue != 0);
1331 return (subst->lvalue == Tokens->Params[3]->lvalue);
1333 lprintf(1," WARNING: invalid type: [%ld]!\n", subst->wcs_type);
1338 void RegisterITERATOR(const char *Name, long len,
1339 int AdditionalParams,
1340 HashList *StaticList,
1341 RetrieveHashlistFunc GetHash,
1342 SubTemplFunc DoSubTempl,
1343 HashDestructorFunc Destructor)
1345 HashIterator *It = (HashIterator*)malloc(sizeof(HashIterator));
1346 It->StaticList = StaticList;
1347 It->AdditionalParams = AdditionalParams;
1348 It->GetHash = GetHash;
1349 It->DoSubTemplate = DoSubTempl;
1350 It->Destructor = Destructor;
1351 Put(Iterators, Name, len, It, NULL);
1354 void RegisterConditional(const char *Name, long len,
1356 WCConditionalFunc CondF)
1358 ConditionalStruct *Cond = (ConditionalStruct*)malloc(sizeof(ConditionalStruct));
1359 Cond->nParams = nParams;
1360 Cond->CondF = CondF;
1361 Put(Contitionals, Name, len, Cond, NULL);
1364 void tmpl_do_boxed(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context)
1367 StrBuf *Headline = NewStrBuf();
1368 DoTemplate(Tokens->Params[1]->Start,
1369 Tokens->Params[1]->len,
1372 SVPutBuf("BOXTITLE", Headline, 0);
1375 DoTemplate(HKEY("beginbox"), Context, Target);
1376 DoTemplate(Tokens->Params[0]->Start,
1377 Tokens->Params[0]->len,
1380 DoTemplate(HKEY("endbox"), Context, Target);
1383 void tmpl_do_tabbed(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context)
1386 int i, ntabs, nTabs;
1388 nTabs = ntabs = Tokens->nParameters / 2;
1389 TabNames = (StrBuf **) malloc(ntabs * sizeof(StrBuf*));
1391 for (i = 0; i < ntabs; i++) {
1392 TabNames[i] = NewStrBuf();
1393 if (Tokens->Params[i * 2]->len > 0) {
1394 DoTemplate(Tokens->Params[i * 2]->Start,
1395 Tokens->Params[i * 2]->len,
1400 /** A Tab without subject? we can't count that, add it as silent */
1405 StrTabbedDialog(Target, nTabs, TabNames);
1406 for (i = 0; i < ntabs; i++) {
1407 StrBeginTab(Target, i, nTabs);
1409 DoTemplate(Tokens->Params[i * 2 + 1]->Start,
1410 Tokens->Params[i * 2 + 1]->len,
1413 StrEndTab(Target, i, nTabs);
1421 RegisterNamespace("SERV:PID", 0, 0, tmplput_serv_ip);
1422 RegisterNamespace("SERV:NODENAME", 0, 0, tmplput_serv_nodename);
1423 RegisterNamespace("SERV:HUMANNODE", 0, 0, tmplput_serv_humannode);
1424 RegisterNamespace("SERV:FQDN", 0, 0, tmplput_serv_fqdn);
1425 RegisterNamespace("SERV:SOFTWARE", 0, 0, tmmplput_serv_software);
1426 RegisterNamespace("SERV:REV_LEVEL", 0, 0, tmplput_serv_rev_level);
1427 RegisterNamespace("SERV:BBS_CITY", 0, 0, tmmplput_serv_bbs_city);
1428 /// RegisterNamespace("SERV:LDAP_SUPP", 0, 0, tmmplput_serv_ldap_enabled);
1429 RegisterNamespace("CURRENT_USER", 0, 0, tmplput_current_user);
1430 RegisterNamespace("CURRENT_ROOM", 0, 0, tmplput_current_room);
1431 RegisterNamespace("ITERATE", 2, 100, tmpl_iterate_subtmpl);
1432 RegisterNamespace("DOBOXED", 1, 2, tmpl_do_boxed);
1433 RegisterNamespace("DOTABBED", 2, 100, tmpl_do_tabbed);
1434 RegisterConditional(HKEY("COND:SUBST"), 3, ConditionalVar);