* added gcc printf format checking to wprintf
[citadel.git] / webcit / subst.c
1 /*
2  * $Id$
3  */
4 /**
5  * \defgroup Subst Variable substitution type stuff
6  * \ingroup CitadelConfig
7  */
8
9 /*@{*/
10
11 #include "sysdep.h"
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <unistd.h>
15
16 #include "webcit.h"
17 #include "webserver.h"
18
19 /**
20  * \brief debugging function to print array to log
21  */
22 void VarPrintTransition(void *vVar1, void *vVar2, int odd){}
23 /**
24  * \brief debugging function to print array to log
25  */
26 void VarPrintEntry(const char *Key, void *vSubst, int odd)
27 {
28         wcsubst *ptr;
29         lprintf(1,"Subst[%s] : ", Key);
30         ptr = (wcsubst*) vSubst;
31
32         switch(ptr->wcs_type) {
33         case WCS_STRING:
34                 lprintf(1, "  -> %s\n", ptr->wcs_value);
35                 break;
36         case WCS_SERVCMD:
37                 lprintf(1, "  -> Server [%s]\n", ptr->wcs_value);
38                 break;
39         case WCS_FUNCTION:
40                 lprintf(1, "  -> function at [%0xd]\n", ptr->wcs_function);
41                 break;
42         default:
43                 lprintf(1,"  WARNING: invalid type: [%ld]!\n", ptr->wcs_type);
44         }
45 }
46
47
48
49 /**
50  * \brief Clear out the list of substitution variables local to this session
51  */
52 void clear_substs(struct wcsession *wc) {
53
54         if (wc->vars != NULL) {
55         
56                 DeleteHash(&wc->vars);
57         }
58 }
59
60 /**
61  * \brief Clear out the list of substitution variables local to this session
62  */
63 void clear_local_substs(void) {
64         clear_substs (WC);
65 }
66
67 /**
68  * \brief destructor; kill one entry.
69  */
70 void deletevar(void *data)
71 {
72         wcsubst *ptr = (wcsubst*)data;
73 //              if ((wc->vars->wcs_type == WCS_STRING)
74 //                 || (wc->vars->wcs_type == WCS_SERVCMD)) {
75         if (ptr->wcs_type != WCS_FUNCTION)
76                 free(ptr->wcs_value);
77         free(ptr);      
78 }
79
80 /**
81  * \brief Add a substitution variable (local to this session) (strlen version...)
82  * \param keyname the replacementstring to substitute
83  * \param keytype the kind of the key
84  * \param format the format string ala printf
85  * \param ... the arguments to substitute in the formatstring
86  */
87 void SVPRINTF(char *keyname, int keytype, const char *format,...)
88 {
89         va_list arg_ptr;
90         char wbuf[SIZ];
91         void *vPtr;
92         wcsubst *ptr = NULL;
93         size_t keylen;
94         struct wcsession *WCC = WC;
95         
96         keylen = strlen(keyname);
97         /**
98          * First look if we're doing a replacement of
99          * an existing key
100          */
101         /*PrintHash(WCC->vars, VarPrintTransition, VarPrintEntry);*/
102         if (GetHash(WCC->vars, keyname, keylen, &vPtr)) {
103                 ptr = (wcsubst*)vPtr;
104                 if (ptr->wcs_value != NULL)
105                         free(ptr->wcs_value);
106         }
107         else    /** Otherwise allocate a new one */
108         {
109                 ptr = (wcsubst *) malloc(sizeof(wcsubst));
110                 safestrncpy(ptr->wcs_key, keyname, sizeof ptr->wcs_key);
111                 Put(WCC->vars, keyname, keylen, ptr,  deletevar);
112         }
113
114         /** Format the string and save it */
115
116         va_start(arg_ptr, format);
117         vsnprintf(wbuf, sizeof wbuf, format, arg_ptr);
118         va_end(arg_ptr);
119
120         ptr->wcs_function = NULL;
121         ptr->wcs_type = keytype;
122         ptr->wcs_value = strdup(wbuf);
123 }
124
125 /**
126  * \brief Add a substitution variable (local to this session)
127  * \param keyname the replacementstring to substitute
128  * \param keytype the kind of the key
129  * \param format the format string ala printf
130  * \param ... the arguments to substitute in the formatstring
131  */
132 void svprintf(char *keyname, size_t keylen, int keytype, const char *format,...)
133 {
134         va_list arg_ptr;
135         char wbuf[SIZ];
136         void *vPtr;
137         wcsubst *ptr = NULL;
138         struct wcsession *WCC = WC;
139         size_t len;
140         
141         /**
142          * First look if we're doing a replacement of
143          * an existing key
144          */
145         /*PrintHash(WCC->vars, VarPrintTransition, VarPrintEntry);*/
146         if (GetHash(WCC->vars, keyname, keylen, &vPtr)) {
147                 ptr = (wcsubst*)vPtr;
148                 if (ptr->wcs_value != NULL)
149                         free(ptr->wcs_value);
150         }
151         else    /** Otherwise allocate a new one */
152         {
153                 ptr = (wcsubst *) malloc(sizeof(wcsubst));
154                 safestrncpy(ptr->wcs_key, keyname, sizeof ptr->wcs_key);
155                 Put(WCC->vars, keyname, keylen, ptr,  deletevar);
156         }
157
158         /** Format the string and save it */
159
160         va_start(arg_ptr, format);
161         len = vsnprintf(wbuf, sizeof wbuf, format, arg_ptr);
162         va_end(arg_ptr);
163
164         ptr->wcs_value = (char*) malloc(len + 1);
165         memcpy(ptr->wcs_value, wbuf, len + 1);
166         ptr->wcs_function = NULL;
167         ptr->wcs_type = keytype;
168 }
169
170 /**
171  * \brief Add a substitution variable (local to this session)
172  * \param keyname the replacementstring to substitute
173  * \param keytype the kind of the key
174  * \param format the format string ala printf
175  * \param ... the arguments to substitute in the formatstring
176  */
177 void SVPut(char *keyname, size_t keylen, int keytype, char *Data)
178 {
179         void *vPtr;
180         wcsubst *ptr = NULL;
181         struct wcsession *WCC = WC;
182
183         
184         /**
185          * First look if we're doing a replacement of
186          * an existing key
187          */
188         /*PrintHash(WCC->vars, VarPrintTransition, VarPrintEntry);*/
189         if (GetHash(WCC->vars, keyname, keylen, &vPtr)) {
190                 ptr = (wcsubst*)vPtr;
191                 if (ptr->wcs_value != NULL)
192                         free(ptr->wcs_value);
193         }
194         else    /** Otherwise allocate a new one */
195         {
196                 ptr = (wcsubst *) malloc(sizeof(wcsubst));
197                 safestrncpy(ptr->wcs_key, keyname, sizeof ptr->wcs_key);
198                 Put(WCC->vars, keyname, keylen, ptr,  deletevar);
199         }
200
201         ptr->wcs_function = NULL;
202         ptr->wcs_type = keytype;
203         ptr->wcs_value = strdup(Data);
204 }
205
206 /**
207  * \brief Add a substitution variable (local to this session) that does a callback
208  * \param keyname the keystring to substitute
209  * \param fcn_ptr the function callback to give the substitution string
210  */
211 void SVCallback(char *keyname, size_t keylen, var_callback_fptr fcn_ptr)
212 {
213         wcsubst *ptr;
214         void *vPtr;
215         struct wcsession *WCC = WC;
216
217         /**
218          * First look if we're doing a replacement of
219          * an existing key
220          */
221         /*PrintHash(WCC->vars, VarPrintTransition, VarPrintEntry);*/
222         if (GetHash(WCC->vars, keyname, keylen, &vPtr)) {
223                 ptr = (wcsubst*)vPtr;
224                 if (ptr->wcs_value != NULL)
225                         free(ptr->wcs_value);
226         }
227         else    /** Otherwise allocate a new one */
228         {
229                 ptr = (wcsubst *) malloc(sizeof(wcsubst));
230                 safestrncpy(ptr->wcs_key, keyname, sizeof ptr->wcs_key);
231                 Put(WCC->vars, keyname, keylen, ptr,  deletevar);
232         }
233
234         ptr->wcs_value = NULL;
235         ptr->wcs_type = WCS_FUNCTION;
236         ptr->wcs_function = fcn_ptr;
237 }
238 inline void SVCALLBACK(char *keyname, var_callback_fptr fcn_ptr)
239 {
240         SVCallback(keyname, strlen(keyname), fcn_ptr);
241 }
242
243
244
245 /**
246  * \brief back end for print_value_of() ... does a server command
247  * \param servcmd server command to execute on the citadel server
248  */
249 void pvo_do_cmd(char *servcmd) {
250         char buf[SIZ];
251
252         serv_puts(servcmd);
253         serv_getln(buf, sizeof buf);
254
255         switch(buf[0]) {
256                 case '2':
257                 case '3':
258                 case '5':
259                         wprintf("%s\n", &buf[4]);
260                         break;
261                 case '1':
262                         fmout("CENTER");
263                         break;
264                 case '4':
265                         wprintf("%s\n", &buf[4]);
266                         serv_puts("000");
267                         break;
268         }
269 }
270
271 /**
272  * \brief Print the value of a variable
273  * \param keyname get a key to print
274  */
275 void print_value_of(char *keyname, size_t keylen) {
276         struct wcsession *WCC = WC;
277         wcsubst *ptr;
278         void *fcn();
279         void *vVar;
280
281         /*if (WCC->vars != NULL) PrintHash(WCC->vars, VarPrintTransition, VarPrintEntry);*/
282         if (keyname[0] == '=') {
283                 do_template(&keyname[1]);
284         }
285         /** Page-local variables */
286         if ((WCC->vars!= NULL) && GetHash(WCC->vars, keyname, keylen, &vVar)) {
287                 ptr = (wcsubst*) vVar;
288                 switch(ptr->wcs_type) {
289                 case WCS_STRING:
290                         wprintf("%s", (const char*)ptr->wcs_value);
291                         break;
292                 case WCS_SERVCMD:
293                         pvo_do_cmd(ptr->wcs_value);
294                         break;
295                 case WCS_FUNCTION:
296                         (*ptr->wcs_function) ();
297                         break;
298                 default:
299                         lprintf(1,"WARNING: invalid value in SV-Hash at %s!", keyname);
300                 }
301         }
302         else if (!strcasecmp(keyname, "SERV_PID")) {
303                 wprintf("%d", WCC->ctdl_pid);
304         }
305
306         else if (!strcasecmp(keyname, "SERV_NODENAME")) {
307                 escputs(serv_info.serv_nodename);
308         }
309
310         else if (!strcasecmp(keyname, "SERV_HUMANNODE")) {
311                 escputs(serv_info.serv_humannode);
312         }
313
314         else if (!strcasecmp(keyname, "SERV_FQDN")) {
315                 escputs(serv_info.serv_fqdn);
316         }
317
318         else if (!strcasecmp(keyname, "SERV_SOFTWARE")) {
319                 escputs(serv_info.serv_software);
320         }
321
322         else if (!strcasecmp(keyname, "SERV_REV_LEVEL")) {
323                 wprintf("%d.%02d",
324                         serv_info.serv_rev_level / 100,
325                         serv_info.serv_rev_level % 100
326                 );
327         }
328
329         else if (!strcasecmp(keyname, "SERV_BBS_CITY")) {
330                 escputs(serv_info.serv_bbs_city);
331         }
332
333         else if (!strcasecmp(keyname, "CURRENT_USER")) {
334                 escputs(WCC->wc_fullname);
335         }
336
337         else if (!strcasecmp(keyname, "CURRENT_ROOM")) {
338                 escputs(WCC->wc_roomname);
339         }
340
341 }
342
343 extern char *static_dirs[PATH_MAX];  /**< Disk representation */
344
345 /**
346  * \brief Display a variable-substituted template
347  * \param templatename template file to load
348  */
349 void do_template(void *templatename) {
350         char flat_filename[PATH_MAX];
351         char filename[PATH_MAX];
352         FILE *fp;
353         char inbuf[1024];
354         char outbuf[sizeof inbuf];
355         char key[sizeof inbuf];
356         int i, pos;
357         struct stat mystat;
358
359         strcpy(flat_filename, templatename);
360         if (WC->is_mobile)
361                 strcat(flat_filename, ".m.html");
362         else
363                 strcat(flat_filename, ".html");
364         
365         strcpy(filename, static_dirs[1]);
366         strcat(filename, flat_filename);
367         if (stat(filename, &mystat) == -1)
368         {
369                 strcpy(filename, static_dirs[0]);
370                 strcat(filename, flat_filename);
371         }
372
373         fp = fopen(filename, "r");
374         if (fp == NULL) {
375                 wprintf(_("ERROR: could not open template "));
376                 wprintf("'%s' - %s<br />\n",
377                         (const char*)templatename, strerror(errno));
378                 return;
379         }
380
381         strcpy(inbuf, "");
382
383         while (fgets(inbuf, sizeof inbuf, fp) != NULL) {
384                 int len;
385
386                 strcpy(outbuf, "");
387                 len = strlen(inbuf);
388                 while (len > 0) {
389                         pos = (-1);
390                         for (i=len; i>=0; --i) {
391                                 if ((inbuf[i]=='<')&&(inbuf[i+1]=='?')) pos = i;
392                         }
393                         if (pos < 0) {
394                                 wprintf("%s", inbuf);
395                                 strcpy(inbuf, "");
396                                 len = 0;
397                         }
398                         else {
399                                 strncpy(outbuf, inbuf, pos);
400                                 outbuf[pos] = 0;
401                                 wprintf("%s", outbuf);
402                                 memmove(inbuf, &inbuf[pos], len - pos +1);
403                                 len -= pos;
404                                 pos = 1;
405                                 for (i=len; i>=0; --i) {
406                                         if (inbuf[i]=='>') pos = i;
407                                 }
408                                 strncpy(key, &inbuf[2], pos-2);
409                                 key[pos-2] = 0;
410                                 print_value_of(key, pos-2);
411                                 pos++;
412                                 memmove(inbuf, &inbuf[pos], len - pos + 1);
413                                 len -= pos;
414                         }
415                 }
416         }
417
418         fclose(fp);
419 }
420
421
422
423 /*@}*/