5 * \defgroup Subst Variable substitution type stuff
6 * \ingroup CitadelConfig
12 #include <sys/types.h>
17 #include "webserver.h"
19 HashList *WirelessTemplateCache;
20 HashList *WirelessLocalTemplateCache;
21 HashList *TemplateCache;
22 HashList *LocalTemplateCache;
24 typedef struct _TemplateToken {
25 const char *pTokenStart;
28 const char *pTokenEnd;
35 size_t ParamStart [10];
39 typedef struct _WCTemplate {
43 WCTemplateToken **Tokens;
48 typedef struct _HashHandler {
52 typedef int (*HandlerFunc)(int nArgs, va_list vaarg);
53 void RegisterNS(const char *NSName, int nMinArgs, int nMaxArgs, HandlerFunc Handler)
60 * \brief debugging function to print array to log
62 void VarPrintTransition(void *vVar1, void *vVar2, int odd){}
64 * \brief debugging function to print array to log
66 void VarPrintEntry(const char *Key, void *vSubst, int odd)
69 lprintf(1,"Subst[%s] : ", Key);
70 ptr = (wcsubst*) vSubst;
72 switch(ptr->wcs_type) {
74 lprintf(1, " -> %s\n", ptr->wcs_value);
77 lprintf(1, " -> Server [%s]\n", ptr->wcs_value);
80 lprintf(1, " -> function at [%0xd]\n", ptr->wcs_function);
83 lprintf(1," WARNING: invalid type: [%ld]!\n", ptr->wcs_type);
90 * \brief Clear out the list of substitution variables local to this session
92 void clear_substs(struct wcsession *wc) {
94 if (wc->vars != NULL) {
96 DeleteHash(&wc->vars);
101 * \brief Clear out the list of substitution variables local to this session
103 void clear_local_substs(void) {
108 * \brief destructor; kill one entry.
110 void deletevar(void *data)
112 wcsubst *ptr = (wcsubst*)data;
113 // if ((wc->vars->wcs_type == WCS_STRING)
114 // || (wc->vars->wcs_type == WCS_SERVCMD)) {
115 if (ptr->wcs_type != WCS_FUNCTION)
116 free(ptr->wcs_value);
121 * \brief Add a substitution variable (local to this session) (strlen version...)
122 * \param keyname the replacementstring to substitute
123 * \param keytype the kind of the key
124 * \param format the format string ala printf
125 * \param ... the arguments to substitute in the formatstring
127 void SVPRINTF(char *keyname, int keytype, const char *format,...)
134 struct wcsession *WCC = WC;
136 keylen = strlen(keyname);
138 * First look if we're doing a replacement of
141 /*PrintHash(WCC->vars, VarPrintTransition, VarPrintEntry);*/
142 if (GetHash(WCC->vars, keyname, keylen, &vPtr)) {
143 ptr = (wcsubst*)vPtr;
144 if (ptr->wcs_value != NULL)
145 free(ptr->wcs_value);
147 else /** Otherwise allocate a new one */
149 ptr = (wcsubst *) malloc(sizeof(wcsubst));
150 safestrncpy(ptr->wcs_key, keyname, sizeof ptr->wcs_key);
151 Put(WCC->vars, keyname, keylen, ptr, deletevar);
154 /** Format the string and save it */
156 va_start(arg_ptr, format);
157 vsnprintf(wbuf, sizeof wbuf, format, arg_ptr);
160 ptr->wcs_function = NULL;
161 ptr->wcs_type = keytype;
162 ptr->wcs_value = strdup(wbuf);
166 * \brief Add a substitution variable (local to this session)
167 * \param keyname the replacementstring to substitute
168 * \param keytype the kind of the key
169 * \param format the format string ala printf
170 * \param ... the arguments to substitute in the formatstring
172 void svprintf(char *keyname, size_t keylen, int keytype, const char *format,...)
178 struct wcsession *WCC = WC;
182 * First look if we're doing a replacement of
185 /*PrintHash(WCC->vars, VarPrintTransition, VarPrintEntry);*/
186 if (GetHash(WCC->vars, keyname, keylen, &vPtr)) {
187 ptr = (wcsubst*)vPtr;
188 if (ptr->wcs_value != NULL)
189 free(ptr->wcs_value);
191 else /** Otherwise allocate a new one */
193 ptr = (wcsubst *) malloc(sizeof(wcsubst));
194 safestrncpy(ptr->wcs_key, keyname, sizeof ptr->wcs_key);
195 Put(WCC->vars, keyname, keylen, ptr, deletevar);
198 /** Format the string and save it */
200 va_start(arg_ptr, format);
201 len = vsnprintf(wbuf, sizeof wbuf, format, arg_ptr);
204 ptr->wcs_value = (char*) malloc(len + 1);
205 memcpy(ptr->wcs_value, wbuf, len + 1);
206 ptr->wcs_function = NULL;
207 ptr->wcs_type = keytype;
211 * \brief Add a substitution variable (local to this session)
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 SVPut(char *keyname, size_t keylen, int keytype, char *Data)
221 struct wcsession *WCC = WC;
225 * First look if we're doing a replacement of
228 /*PrintHash(WCC->vars, VarPrintTransition, VarPrintEntry);*/
229 if (GetHash(WCC->vars, keyname, keylen, &vPtr)) {
230 ptr = (wcsubst*)vPtr;
231 if (ptr->wcs_value != NULL)
232 free(ptr->wcs_value);
234 else /** Otherwise allocate a new one */
236 ptr = (wcsubst *) malloc(sizeof(wcsubst));
237 safestrncpy(ptr->wcs_key, keyname, sizeof ptr->wcs_key);
238 Put(WCC->vars, keyname, keylen, ptr, deletevar);
241 ptr->wcs_function = NULL;
242 ptr->wcs_type = keytype;
243 ptr->wcs_value = strdup(Data);
247 * \brief Add a substitution variable (local to this session) that does a callback
248 * \param keyname the keystring to substitute
249 * \param fcn_ptr the function callback to give the substitution string
251 void SVCallback(char *keyname, size_t keylen, var_callback_fptr fcn_ptr)
255 struct wcsession *WCC = WC;
258 * First look if we're doing a replacement of
261 /*PrintHash(WCC->vars, VarPrintTransition, VarPrintEntry);*/
262 if (GetHash(WCC->vars, keyname, keylen, &vPtr)) {
263 ptr = (wcsubst*)vPtr;
264 if (ptr->wcs_value != NULL)
265 free(ptr->wcs_value);
267 else /** Otherwise allocate a new one */
269 ptr = (wcsubst *) malloc(sizeof(wcsubst));
270 safestrncpy(ptr->wcs_key, keyname, sizeof ptr->wcs_key);
271 Put(WCC->vars, keyname, keylen, ptr, deletevar);
274 ptr->wcs_value = NULL;
275 ptr->wcs_type = WCS_FUNCTION;
276 ptr->wcs_function = fcn_ptr;
278 inline void SVCALLBACK(char *keyname, var_callback_fptr fcn_ptr)
280 SVCallback(keyname, strlen(keyname), fcn_ptr);
286 * \brief back end for print_value_of() ... does a server command
287 * \param servcmd server command to execute on the citadel server
289 void pvo_do_cmd(char *servcmd) {
293 serv_getln(buf, sizeof buf);
299 wprintf("%s\n", &buf[4]);
305 wprintf("%s\n", &buf[4]);
312 * \brief Print the value of a variable
313 * \param keyname get a key to print
315 void print_value_of(const char *keyname, size_t keylen) {
316 struct wcsession *WCC = WC;
321 /*if (WCC->vars != NULL) PrintHash(WCC->vars, VarPrintTransition, VarPrintEntry);*/
322 if (keyname[0] == '=') {
323 DoTemplate(keyname+1, keylen - 1);
325 /** Page-local variables */
326 if ((WCC->vars!= NULL) && GetHash(WCC->vars, keyname, keylen, &vVar)) {
327 ptr = (wcsubst*) vVar;
328 switch(ptr->wcs_type) {
330 wprintf("%s", (const char*)ptr->wcs_value);
333 pvo_do_cmd(ptr->wcs_value);
336 (*ptr->wcs_function) ();
339 lprintf(1,"WARNING: invalid value in SV-Hash at %s!", keyname);
344 ch = keyname[keylen];
345 ((char*) keyname)[keylen] = '\0'; ////TODO
346 if (!strcasecmp(keyname, "SERV_PID")) {
347 wprintf("%d", WCC->ctdl_pid);
350 else if (!strcasecmp(keyname, "SERV_NODENAME")) {
351 escputs(serv_info.serv_nodename);
354 else if (!strcasecmp(keyname, "SERV_HUMANNODE")) {
355 escputs(serv_info.serv_humannode);
358 else if (!strcasecmp(keyname, "SERV_FQDN")) {
359 escputs(serv_info.serv_fqdn);
362 else if (!strcasecmp(keyname, "SERV_SOFTWARE")) {
363 escputs(serv_info.serv_software);
366 else if (!strcasecmp(keyname, "SERV_REV_LEVEL")) {
368 serv_info.serv_rev_level / 100,
369 serv_info.serv_rev_level % 100
373 else if (!strcasecmp(keyname, "SERV_BBS_CITY")) {
374 escputs(serv_info.serv_bbs_city);
377 else if (!strcasecmp(keyname, "CURRENT_USER")) {
378 escputs(WCC->wc_fullname);
381 else if (!strcasecmp(keyname, "CURRENT_ROOM")) {
382 escputs(WCC->wc_roomname);
384 ((char*) keyname)[keylen] = ch;//// TODO
390 extern char *static_dirs[PATH_MAX]; /**< Disk representation */
393 void PutNewToken(WCTemplate *Template, WCTemplateToken *NewToken)
395 if (Template->nTokensUsed + 1 >= Template->TokenSpace) {
396 if (Template->TokenSpace <= 0) {
397 Template->Tokens = (WCTemplateToken**)malloc(
398 sizeof(WCTemplateToken*) * 10);
399 Template->TokenSpace = 10;
402 WCTemplateToken **NewTokens;
403 NewTokens= (WCTemplateToken**)malloc(
404 sizeof(WCTemplateToken*) *
405 Template->TokenSpace * 2);
406 memcpy(NewTokens, Template->Tokens,
407 sizeof(WCTemplateToken) * Template->nTokensUsed);
408 free(Template->Tokens);
409 Template->TokenSpace *= 2;
410 Template->Tokens = NewTokens;
415 Template->Tokens[(Template->nTokensUsed)++] = NewToken;
418 WCTemplateToken *NewTemlpateSubstitute(const char *pStart, const char *pTmplStart, const char *pTmplEnd)
420 WCTemplateToken *NewToken = (WCTemplateToken*)malloc(sizeof(WCTemplateToken));
422 NewToken->pTokenStart = pTmplStart;
423 NewToken->TokenStart = pTmplStart - pStart;
424 NewToken->TokenEnd = (pTmplEnd - pStart) - NewToken->TokenStart;
425 NewToken->pTokenEnd = pTmplEnd;
427 NewToken->pName = pTmplStart + 2;
428 NewToken->NameEnd = NewToken->TokenEnd - 2;
429 NewToken->HaveParameters = 0;;
430 NewToken->nParameters = 0;
431 NewToken->ParamStart[0] = 0;
432 NewToken->ParamEnd[0] = 0;
436 void FreeWCTemplate(void *vFreeMe)
439 WCTemplate *FreeMe = (WCTemplate*)vFreeMe;
441 if (FreeMe->TokenSpace > 0) {
442 for (i = 0; i < FreeMe->nTokensUsed; i ++) {
443 free(FreeMe->Tokens[i]);
445 free(FreeMe->Tokens);
450 void EvaluateToken(StrBuf *Target, WCTemplateToken *Token)
455 print_value_of(Token->pName, Token->NameEnd);
459 void ProcessTemplate(WCTemplate *Tmpl, StrBuf *Target)
463 const char *pData, *pS;
466 pS = pData = ChrPtr(Tmpl->Data);
467 len = StrLength(Tmpl->Data);
470 if (i >= Tmpl->nTokensUsed) {
471 StrBufAppendBufPlain(Target, pData, len, 0);
475 StrBufAppendBufPlain(
477 Tmpl->Tokens[i]->pTokenStart - pData, 0);
478 EvaluateToken(Target, Tmpl->Tokens[i]);
479 pData = Tmpl->Tokens[i++]->pTokenEnd + 1;
488 * \brief Display a variable-substituted template
489 * \param templatename template file to load
491 void *load_template(const char *templatename, long len) {
494 HashList *StaticLocal;
495 StrBuf *flat_filename;
496 char filename[PATH_MAX];
499 const char *pS, *pE, *pch, *Err;
502 WCTemplate *NewTemplate;
504 flat_filename = NewStrBufPlain(templatename, len);
506 Static = WirelessTemplateCache;
507 StaticLocal = WirelessLocalTemplateCache;
508 StrBufAppendBufPlain(flat_filename, HKEY(".m.html"), 0);
511 Static = TemplateCache;
512 StaticLocal = LocalTemplateCache;
513 StrBufAppendBufPlain(flat_filename, HKEY(".html"), 0);
516 strcpy(filename, static_dirs[1]);
517 strcat(filename, ChrPtr(flat_filename));
518 pCache = StaticLocal;
519 if (stat(filename, &mystat) == -1)
522 strcpy(filename, static_dirs[0]);
523 strcat(filename, ChrPtr(flat_filename));
526 fd = open(filename, O_RDONLY);
528 wprintf(_("ERROR: could not open template "));
529 wprintf("'%s' - %s<br />\n",
530 (const char*)templatename, strerror(errno));
534 if (fstat(fd, &statbuf) == -1) {
535 wprintf(_("ERROR: could not stat template "));
536 wprintf("'%s' - %s<br />\n",
537 (const char*)templatename, strerror(errno));
541 NewTemplate = (WCTemplate *) malloc(sizeof(WCTemplate));
542 NewTemplate->Data = NewStrBufPlain(NULL, statbuf.st_size);
543 NewTemplate->nTokensUsed = 0;
544 NewTemplate->TokenSpace = 0;
545 NewTemplate->Tokens = NULL;
546 if (StrBufReadBLOB(NewTemplate->Data, &fd, 1, statbuf.st_size, &Err) < 0) {
548 FreeWCTemplate(NewTemplate);
549 wprintf(_("ERROR: reading template "));
550 wprintf("'%s' - %s<br />\n",
551 (const char*)templatename, strerror(errno));
556 pS = pch = ChrPtr(NewTemplate->Data);
557 pE = pS + StrLength(NewTemplate->Data);
559 const char *pts, *pte;
561 int InDoubleQuotes = 0;
563 for (; pch < pE; pch ++) {
564 if ((*pch=='<')&&(*(pch + 1)=='?'))
570 for (; pch < pE - 1; pch ++) {
572 InDoubleQuotes = ! InDoubleQuotes;
573 else if (*pch == '\'')
574 InQuotes = ! InQuotes;
575 else if ((!InQuotes && !InDoubleQuotes) &&
576 ((*pch!='\\')&&(*(pch + 1)=='>'))) {
584 PutNewToken(NewTemplate, NewTemlpateSubstitute(pS, pts, pte));
587 Put(pCache, filename, strlen(filename), NewTemplate, FreeWCTemplate);
592 * \brief Display a variable-substituted template
593 * \param templatename template file to load
595 void DoTemplate(const char *templatename, long len)
598 HashList *StaticLocal;
602 Static = WirelessTemplateCache;
603 StaticLocal = WirelessLocalTemplateCache;
606 Static = TemplateCache;
607 StaticLocal = LocalTemplateCache;
610 if (!GetHash(StaticLocal, templatename, len, &vTmpl) &&
611 !GetHash(Static, templatename, len, &vTmpl)) {
612 vTmpl = load_template(templatename, len);
613 //////TODO: lock this!
617 ProcessTemplate(vTmpl, WC->WBuf);