5 * \defgroup Subst Variable substitution type stuff
6 * \ingroup CitadelConfig
12 #include <sys/types.h>
19 #include "webserver.h"
21 extern char *static_dirs[PATH_MAX]; /**< Disk representation */
23 HashList *WirelessTemplateCache;
24 HashList *WirelessLocalTemplateCache;
25 HashList *TemplateCache;
26 HashList *LocalTemplateCache;
30 typedef struct _TemplateToken {
31 const char *pTokenStart;
34 const char *pTokenEnd;
41 size_t ParamStart [10];
45 typedef struct _WCTemplate {
49 WCTemplateToken **Tokens;
52 typedef void (*WCHandlerFunc)(int nArgs, WCTemplateToken **Tokens); /*TODO: subset of that */
53 typedef struct _HashHandler {
56 WCHandlerFunc HandlerFunc;
59 void RegisterNS(const char *NSName, long len, int nMinArgs, int nMaxArgs, WCHandlerFunc HandlerFunc)
61 HashHandler *NewHandler;
63 NewHandler = (HashHandler*) malloc(sizeof(HashHandler));
64 NewHandler->nMinArgs = nMinArgs;
65 NewHandler->nMaxArgs = nMaxArgs;
66 NewHandler->HandlerFunc = HandlerFunc;
67 Put(GlobalNS, NSName, len, NewHandler, NULL);
72 * \brief debugging function to print array to log
74 void VarPrintTransition(void *vVar1, void *vVar2, int odd){}
76 * \brief debugging function to print array to log
78 void VarPrintEntry(const char *Key, void *vSubst, int odd)
81 lprintf(1,"Subst[%s] : ", Key);
82 ptr = (wcsubst*) vSubst;
84 switch(ptr->wcs_type) {
86 lprintf(1, " -> %s\n", ptr->wcs_value);
89 lprintf(1, " -> Server [%s]\n", ptr->wcs_value);
92 lprintf(1, " -> function at [%0xd]\n", ptr->wcs_function);
95 lprintf(1," WARNING: invalid type: [%ld]!\n", ptr->wcs_type);
102 * \brief Clear out the list of substitution variables local to this session
104 void clear_substs(struct wcsession *wc) {
106 if (wc->vars != NULL) {
108 DeleteHash(&wc->vars);
113 * \brief Clear out the list of substitution variables local to this session
115 void clear_local_substs(void) {
120 * \brief destructor; kill one entry.
122 void deletevar(void *data)
124 wcsubst *ptr = (wcsubst*)data;
125 // if ((wc->vars->wcs_type == WCS_STRING)
126 // || (wc->vars->wcs_type == WCS_SERVCMD)) {
127 if (ptr->wcs_type != WCS_FUNCTION)
128 free(ptr->wcs_value);
133 * \brief Add a substitution variable (local to this session) (strlen version...)
134 * \param keyname the replacementstring to substitute
135 * \param keytype the kind of the key
136 * \param format the format string ala printf
137 * \param ... the arguments to substitute in the formatstring
139 void SVPRINTF(char *keyname, int keytype, const char *format,...)
146 struct wcsession *WCC = WC;
148 keylen = strlen(keyname);
150 * First look if we're doing a replacement of
153 /*PrintHash(WCC->vars, VarPrintTransition, VarPrintEntry);*/
154 if (GetHash(WCC->vars, keyname, keylen, &vPtr)) {
155 ptr = (wcsubst*)vPtr;
156 if (ptr->wcs_value != NULL)
157 free(ptr->wcs_value);
159 else /** Otherwise allocate a new one */
161 ptr = (wcsubst *) malloc(sizeof(wcsubst));
162 safestrncpy(ptr->wcs_key, keyname, sizeof ptr->wcs_key);
163 Put(WCC->vars, keyname, keylen, ptr, deletevar);
166 /** Format the string and save it */
168 va_start(arg_ptr, format);
169 vsnprintf(wbuf, sizeof wbuf, format, arg_ptr);
172 ptr->wcs_function = NULL;
173 ptr->wcs_type = keytype;
174 ptr->wcs_value = strdup(wbuf);
178 * \brief Add a substitution variable (local to this session)
179 * \param keyname the replacementstring to substitute
180 * \param keytype the kind of the key
181 * \param format the format string ala printf
182 * \param ... the arguments to substitute in the formatstring
184 void svprintf(char *keyname, size_t keylen, int keytype, const char *format,...)
190 struct wcsession *WCC = WC;
194 * First look if we're doing a replacement of
197 /*PrintHash(WCC->vars, VarPrintTransition, VarPrintEntry);*/
198 if (GetHash(WCC->vars, keyname, keylen, &vPtr)) {
199 ptr = (wcsubst*)vPtr;
200 if (ptr->wcs_value != NULL)
201 free(ptr->wcs_value);
203 else /** Otherwise allocate a new one */
205 ptr = (wcsubst *) malloc(sizeof(wcsubst));
206 safestrncpy(ptr->wcs_key, keyname, sizeof ptr->wcs_key);
207 Put(WCC->vars, keyname, keylen, ptr, deletevar);
210 /** Format the string and save it */
212 va_start(arg_ptr, format);
213 len = vsnprintf(wbuf, sizeof wbuf, format, arg_ptr);
216 ptr->wcs_value = (char*) malloc(len + 1);
217 memcpy(ptr->wcs_value, wbuf, len + 1);
218 ptr->wcs_function = NULL;
219 ptr->wcs_type = keytype;
223 * \brief Add a substitution variable (local to this session)
224 * \param keyname the replacementstring to substitute
225 * \param keytype the kind of the key
226 * \param format the format string ala printf
227 * \param ... the arguments to substitute in the formatstring
229 void SVPut(char *keyname, size_t keylen, int keytype, char *Data)
233 struct wcsession *WCC = WC;
237 * First look if we're doing a replacement of
240 /*PrintHash(WCC->vars, VarPrintTransition, VarPrintEntry);*/
241 if (GetHash(WCC->vars, keyname, keylen, &vPtr)) {
242 ptr = (wcsubst*)vPtr;
243 if (ptr->wcs_value != NULL)
244 free(ptr->wcs_value);
246 else /** Otherwise allocate a new one */
248 ptr = (wcsubst *) malloc(sizeof(wcsubst));
249 safestrncpy(ptr->wcs_key, keyname, sizeof ptr->wcs_key);
250 Put(WCC->vars, keyname, keylen, ptr, deletevar);
253 ptr->wcs_function = NULL;
254 ptr->wcs_type = keytype;
255 ptr->wcs_value = strdup(Data);
259 * \brief Add a substitution variable (local to this session) that does a callback
260 * \param keyname the keystring to substitute
261 * \param fcn_ptr the function callback to give the substitution string
263 void SVCallback(char *keyname, size_t keylen, var_callback_fptr fcn_ptr)
267 struct wcsession *WCC = WC;
270 * First look if we're doing a replacement of
273 /*PrintHash(WCC->vars, VarPrintTransition, VarPrintEntry);*/
274 if (GetHash(WCC->vars, keyname, keylen, &vPtr)) {
275 ptr = (wcsubst*)vPtr;
276 if (ptr->wcs_value != NULL)
277 free(ptr->wcs_value);
279 else /** Otherwise allocate a new one */
281 ptr = (wcsubst *) malloc(sizeof(wcsubst));
282 safestrncpy(ptr->wcs_key, keyname, sizeof ptr->wcs_key);
283 Put(WCC->vars, keyname, keylen, ptr, deletevar);
286 ptr->wcs_value = NULL;
287 ptr->wcs_type = WCS_FUNCTION;
288 ptr->wcs_function = fcn_ptr;
290 inline void SVCALLBACK(char *keyname, var_callback_fptr fcn_ptr)
292 SVCallback(keyname, strlen(keyname), fcn_ptr);
298 * \brief back end for print_value_of() ... does a server command
299 * \param servcmd server command to execute on the citadel server
301 void pvo_do_cmd(char *servcmd) {
305 serv_getln(buf, sizeof buf);
311 wprintf("%s\n", &buf[4]);
317 wprintf("%s\n", &buf[4]);
324 * \brief Print the value of a variable
325 * \param keyname get a key to print
327 void print_value_of(const char *keyname, size_t keylen) {
328 struct wcsession *WCC = WC;
333 /*if (WCC->vars != NULL) PrintHash(WCC->vars, VarPrintTransition, VarPrintEntry);*/
334 if (keyname[0] == '=') {
335 DoTemplate(keyname+1, keylen - 1);
337 /** Page-local variables */
338 if ((WCC->vars!= NULL) && GetHash(WCC->vars, keyname, keylen, &vVar)) {
339 ptr = (wcsubst*) vVar;
340 switch(ptr->wcs_type) {
342 wprintf("%s", (const char*)ptr->wcs_value);
345 pvo_do_cmd(ptr->wcs_value);
348 (*ptr->wcs_function) ();
351 lprintf(1,"WARNING: invalid value in SV-Hash at %s!", keyname);
357 void PutNewToken(WCTemplate *Template, WCTemplateToken *NewToken)
359 if (Template->nTokensUsed + 1 >= Template->TokenSpace) {
360 if (Template->TokenSpace <= 0) {
361 Template->Tokens = (WCTemplateToken**)malloc(
362 sizeof(WCTemplateToken*) * 10);
363 Template->TokenSpace = 10;
366 WCTemplateToken **NewTokens;
367 NewTokens= (WCTemplateToken**)malloc(
368 sizeof(WCTemplateToken*) *
369 Template->TokenSpace * 2);
370 memcpy(NewTokens, Template->Tokens,
371 sizeof(WCTemplateToken) * Template->nTokensUsed);
372 free(Template->Tokens);
373 Template->TokenSpace *= 2;
374 Template->Tokens = NewTokens;
377 Template->Tokens[(Template->nTokensUsed)++] = NewToken;
380 WCTemplateToken *NewTemlpateSubstitute(const char *pStart, const char *pTmplStart, const char *pTmplEnd)
382 WCTemplateToken *NewToken = (WCTemplateToken*)malloc(sizeof(WCTemplateToken));
384 NewToken->pTokenStart = pTmplStart;
385 NewToken->TokenStart = pTmplStart - pStart;
386 NewToken->TokenEnd = (pTmplEnd - pStart) - NewToken->TokenStart;
387 NewToken->pTokenEnd = pTmplEnd;
389 NewToken->pName = pTmplStart + 2;
390 NewToken->NameEnd = NewToken->TokenEnd - 2;
391 NewToken->HaveParameters = 0;;
392 NewToken->nParameters = 0;
393 NewToken->ParamStart[0] = 0;
394 NewToken->ParamEnd[0] = 0;
398 void FreeWCTemplate(void *vFreeMe)
401 WCTemplate *FreeMe = (WCTemplate*)vFreeMe;
403 if (FreeMe->TokenSpace > 0) {
404 for (i = 0; i < FreeMe->nTokensUsed; i ++) {
405 free(FreeMe->Tokens[i]);
407 free(FreeMe->Tokens);
412 void EvaluateToken(StrBuf *Target, WCTemplateToken *Token)
415 // much output, since pName is not terminated...
416 // lprintf(1,"Doing token: %s\n",Token->pName);
417 if (GetHash(GlobalNS, Token->pName, Token->NameEnd, &vVar)) {
418 HashHandler *Handler;
419 Handler = (HashHandler*) vVar;
420 if ((Token->nParameters < Handler->nMinArgs) ||
421 (Token->nParameters < Handler->nMaxArgs)) {
422 lprintf(1, "Handler [%s] doesn't work with %ld params",
427 Handler->HandlerFunc(Token->nParameters,
428 &Token); /*TODO: subset of that */
434 print_value_of(Token->pName, Token->NameEnd);
438 void ProcessTemplate(WCTemplate *Tmpl, StrBuf *Target)
442 const char *pData, *pS;
445 pS = pData = ChrPtr(Tmpl->Data);
446 len = StrLength(Tmpl->Data);
449 if (i >= Tmpl->nTokensUsed) {
450 StrBufAppendBufPlain(Target, pData, len, 0);
454 StrBufAppendBufPlain(
456 Tmpl->Tokens[i]->pTokenStart - pData, 0);
457 EvaluateToken(Target, Tmpl->Tokens[i]);
458 pData = Tmpl->Tokens[i++]->pTokenEnd + 1;
466 * \brief Display a variable-substituted template
467 * \param templatename template file to load
469 void *load_template(StrBuf *filename, StrBuf *Key, HashList *PutThere)
473 const char *pS, *pE, *pch, *Err;
475 WCTemplate *NewTemplate;
477 fd = open(ChrPtr(filename), O_RDONLY);
479 lprintf(1, "ERROR: could not open template '%s' - %s\n",
480 ChrPtr(filename), strerror(errno));
484 if (fstat(fd, &statbuf) == -1) {
485 lprintf(1, "ERROR: could not stat template '%s' - %s\n",
486 ChrPtr(filename), strerror(errno));
490 NewTemplate = (WCTemplate *) malloc(sizeof(WCTemplate));
491 NewTemplate->Data = NewStrBufPlain(NULL, statbuf.st_size);
492 NewTemplate->nTokensUsed = 0;
493 NewTemplate->TokenSpace = 0;
494 NewTemplate->Tokens = NULL;
495 if (StrBufReadBLOB(NewTemplate->Data, &fd, 1, statbuf.st_size, &Err) < 0) {
497 FreeWCTemplate(NewTemplate);
498 lprintf(1, "ERROR: reading template '%s' - %s<br />\n",
499 ChrPtr(filename), strerror(errno));
504 pS = pch = ChrPtr(NewTemplate->Data);
505 pE = pS + StrLength(NewTemplate->Data);
507 const char *pts, *pte;
509 int InDoubleQuotes = 0;
511 for (; pch < pE; pch ++) {
512 if ((*pch=='<')&&(*(pch + 1)=='?'))
518 for (; pch < pE - 1; pch ++) {
520 InDoubleQuotes = ! InDoubleQuotes;
521 else if (*pch == '\'')
522 InQuotes = ! InQuotes;
523 else if ((!InQuotes && !InDoubleQuotes) &&
524 ((*pch!='\\')&&(*(pch + 1)=='>'))) {
532 PutNewToken(NewTemplate, NewTemlpateSubstitute(pS, pts, pte));
535 Put(PutThere, ChrPtr(Key), StrLength(Key), NewTemplate, FreeWCTemplate);
540 * \brief Display a variable-substituted template
541 * \param templatename template file to load
543 void DoTemplate(const char *templatename, long len)
546 HashList *StaticLocal;
550 Static = WirelessTemplateCache;
551 StaticLocal = WirelessLocalTemplateCache;
554 Static = TemplateCache;
555 StaticLocal = LocalTemplateCache;
558 if (!GetHash(StaticLocal, templatename, len, &vTmpl) &&
559 !GetHash(Static, templatename, len, &vTmpl)) {
560 printf ("didn't find %s\n", templatename);
565 ProcessTemplate(vTmpl, WC->WBuf);
568 int LoadTemplateDir(const char *DirName, HashList *wireless, HashList *big)
574 struct dirent *filedir_entry;
580 StrBufPrintf(Dir, "%s/t", DirName);
581 filedir = opendir (ChrPtr(Dir));
582 if (filedir == NULL) {
586 FileName = NewStrBuf();
588 while ((filedir_entry = readdir(filedir)))
592 #ifdef _DIRENT_HAVE_D_NAMELEN
593 d_namelen = filedir_entry->d_namelen;
595 d_namelen = strlen(filedir_entry->d_name);
597 d_without_ext = d_namelen;
598 while ((d_without_ext > 0) && (filedir_entry->d_name[d_without_ext] != '.'))
600 if ((d_without_ext == 0) || (d_namelen < 3))
603 IsMobile = (strstr(filedir_entry->d_name, ".m.html")!= NULL);
604 PStart = filedir_entry->d_name;
605 StrBufPrintf(FileName, "%s/%s", ChrPtr(Dir), filedir_entry->d_name);
606 MinorPtr = strchr(filedir_entry->d_name, '.');
607 if (MinorPtr != NULL)
609 StrBufPlain(Tag, filedir_entry->d_name, MinorPtr - filedir_entry->d_name);
612 printf("%s %d %s\n",ChrPtr(FileName), IsMobile, ChrPtr(Tag));
613 load_template(FileName, Tag, (IsMobile)?wireless:big);
616 FreeStrBuf(&FileName);
622 void InitTemplateCache(void)
624 LoadTemplateDir(static_dirs[0],
625 WirelessTemplateCache,
627 LoadTemplateDir(static_dirs[1],
628 WirelessLocalTemplateCache,
632 void tmplput_serv_ip(int nArgs, WCTemplateToken **Tokens)
634 wprintf("%d", WC->ctdl_pid);
637 void tmplput_serv_nodename(int nArgs, WCTemplateToken **Tokens)
639 escputs(serv_info.serv_nodename);
642 void tmplput_serv_humannode(int nArgs, WCTemplateToken **Tokens)
644 escputs(serv_info.serv_humannode);
647 void tmplput_serv_fqdn(int nArgs, WCTemplateToken **Tokens)
649 escputs(serv_info.serv_fqdn);
652 void tmmplput_serv_software(int nArgs, WCTemplateToken **Tokens)
654 escputs(serv_info.serv_software);
657 void tmplput_serv_rev_level(int nArgs, WCTemplateToken **Tokens)
660 serv_info.serv_rev_level / 100,
661 serv_info.serv_rev_level % 100);
664 void tmmplput_serv_bbs_city(int nArgs, WCTemplateToken **Tokens)
666 escputs(serv_info.serv_bbs_city);
669 void tmplput_current_user(int nArgs, WCTemplateToken **Tokens)
671 escputs(WC->wc_fullname);
674 void tmplput_current_room(int nArgs, WCTemplateToken **Tokens)
676 escputs(WC->wc_roomname);
683 RegisterNS(HKEY("SERV_PID"), 0, 0, tmplput_serv_ip);
684 RegisterNS(HKEY("SERV_NODENAME"), 0, 0, tmplput_serv_nodename);
685 RegisterNS(HKEY("SERV_HUMANNODE"), 0, 0, tmplput_serv_humannode);
686 RegisterNS(HKEY("SERV_FQDN"), 0, 0, tmplput_serv_fqdn);
687 RegisterNS(HKEY("SERV_SOFTWARE"), 0, 0, tmmplput_serv_software);
688 RegisterNS(HKEY("SERV_REV_LEVEL"), 0, 0, tmplput_serv_rev_level);
689 RegisterNS(HKEY("SERV_BBS_CITY"), 0, 0, tmmplput_serv_bbs_city);
690 RegisterNS(HKEY("CURRENT_USER"), 0, 0, tmplput_current_user);
691 RegisterNS(HKEY("CURRENT_ROOM"), 0, 0, tmplput_current_room);