- fix Building without Nagra not possible at Nagra_Merlin https://trac.streamboard...
[oscam.git] / module-webif-tpl.c
blob9bb74bdd8d938685c7a76a65487fced30450d941
1 #define MODULE_LOG_PREFIX "webif"
3 #include "globals.h"
5 #ifdef WEBIF
6 #include "webif/pages.h"
7 #include "module-webif-tpl.h"
8 #include "oscam-files.h"
9 #include "oscam-string.h"
10 #ifdef COMPRESSED_TEMPLATES
11 #include "minilzo/minilzo.h"
12 #endif
14 /* struct template templates[] that comes from webif/pages.c is recreated as
15 struct tpl tpls[] because we need to add additional fields such as tpl_name_hash
16 and possibly preprocess templates[] struct before using it. */
18 struct tpl
20 uint32_t tpl_name_hash;
21 const char *tpl_name;
22 const char *tpl_data;
23 const char *tpl_deps;
24 char *extra_data;
25 uint32_t tpl_data_len;
26 uint8_t tpl_type;
29 static struct tpl *tpls;
30 static char *tpls_data;
31 static int tpls_count;
33 static void tpl_init_base64(struct tpl *tpl)
35 // The rest of OSCam expects images to be base64 encoded and contain mime type.
36 if(!template_is_image(tpl->tpl_type))
37 { return; }
38 size_t b64_buf_len = 32 + BASE64_LENGTH(tpl->tpl_data_len); // Enough for base64 and 32 for header (data:XXX;base64,)
39 char *b64_buf;
40 if(!cs_malloc(&b64_buf, b64_buf_len))
42 tpl->tpl_data = "";
43 tpl->tpl_data_len = 0;
44 return;
46 int hdr_len = snprintf(b64_buf, b64_buf_len, "data:%s;base64,", template_get_mimetype(tpl->tpl_type));
47 base64_encode(tpl->tpl_data, tpl->tpl_data_len, b64_buf + hdr_len, b64_buf_len - hdr_len);
48 tpl->tpl_data = tpl->extra_data = b64_buf;
49 tpl->tpl_data_len = cs_strlen(b64_buf);
52 void webif_tpls_prepare(void)
54 int i;
55 const struct template *templates = templates_get();
56 tpls_count = templates_count();
57 if(!cs_malloc(&tpls, tpls_count * sizeof(struct tpl)))
59 tpls_count = 0;
60 return;
62 #ifdef COMPRESSED_TEMPLATES
63 const char *templates_cdata;
64 size_t tpls_data_len, tpls_data_olen;
65 templates_get_data(&templates_cdata, &tpls_data_len, &tpls_data_olen);
66 if(!cs_malloc(&tpls_data, tpls_data_olen))
68 tpls_count = 0;
69 return;
72 lzo_uint new_len = tpls_data_olen;
73 int r = lzo1x_decompress_safe((uint8_t *)templates_cdata, tpls_data_len, (uint8_t *)tpls_data, &new_len, NULL);
74 if(r == LZO_E_OK && new_len == tpls_data_olen)
76 cs_log("webif: decompressed %zu bytes back into %zu bytes", tpls_data_len, tpls_data_olen);
78 else
80 /* this should NEVER happen */
81 cs_log("internal error - decompression failed: %d\n", r);
82 NULLFREE(tpls);
83 tpls_count = 0;
86 for(i = 0; i < tpls_count; ++i)
88 tpls[i].tpl_name = tpls_data + templates[i].tpl_name_ofs;
89 tpls[i].tpl_data = tpls_data + templates[i].tpl_data_ofs;
90 tpls[i].tpl_deps = tpls_data + templates[i].tpl_deps_ofs;
91 tpls[i].tpl_data_len = templates[i].tpl_data_len;
92 tpls[i].tpl_type = templates[i].tpl_type;
93 tpls[i].tpl_name_hash = jhash(tpls[i].tpl_name, cs_strlen(tpls[i].tpl_name));
94 tpl_init_base64(&tpls[i]);
96 #else
97 for(i = 0; i < tpls_count; ++i)
99 tpls[i].tpl_name_hash = jhash(templates[i].tpl_name, cs_strlen(templates[i].tpl_name));
100 tpls[i].tpl_name = templates[i].tpl_name;
101 tpls[i].tpl_data = templates[i].tpl_data;
102 tpls[i].tpl_deps = templates[i].tpl_deps;
103 tpls[i].tpl_data_len = templates[i].tpl_data_len;
104 tpls[i].tpl_type = templates[i].tpl_type;
105 tpl_init_base64(&tpls[i]);
107 #endif
110 void webif_tpls_free(void)
112 int32_t i, tmp;
114 tmp = tpls_count;
115 tpls_count = 0;
117 for(i = 0; i < tmp; ++i)
119 NULLFREE(tpls[i].extra_data);
121 NULLFREE(tpls_data);
122 NULLFREE(tpls);
125 /* Adds a name->value-mapping or appends to it. You will get a reference back which you may freely
126 use (but you should not call free/realloc on this!)*/
127 void tpl_addVar(struct templatevars *vars, uint8_t addmode, const char *name, const char *value)
129 if(name == NULL) { return; }
130 if(value == NULL) { value = ""; }
131 int32_t i;
132 char *tmp = NULL, *result = NULL;
133 for(i = (*vars).varscnt - 1; i >= 0; --i)
135 if(strcmp((*vars).names[i], name) == 0)
137 result = (*vars).values[i];
138 break;
141 if(result == NULL)
143 if((*vars).varsalloc <= (*vars).varscnt)
145 if(!cs_realloc(&(*vars).names, (*vars).varsalloc * 2 * sizeof(char **))) { return; }
146 if(!cs_realloc(&(*vars).values, (*vars).varsalloc * 2 * sizeof(char **))) { return; }
147 if(!cs_realloc(&(*vars).vartypes, (*vars).varsalloc * 2 * sizeof(uint8_t *))) { return; }
148 (*vars).varsalloc = (*vars).varscnt * 2;
150 int32_t len = cs_strlen(name) + 1;
151 if(!cs_malloc(&tmp, len)) { return; }
152 memcpy(tmp, name, len);
153 (*vars).names[(*vars).varscnt] = tmp;
154 len = cs_strlen(value) + 1;
155 if(!cs_malloc(&tmp, len))
157 NULLFREE((*vars).names[(*vars).varscnt]);
158 return;
160 memcpy(tmp, value, len);
161 (*vars).values[(*vars).varscnt] = tmp;
162 (*vars).vartypes[(*vars).varscnt] = addmode;
163 (*vars).varscnt++;
165 else
167 int32_t oldlen = 0, newlen = cs_strlen(value);
168 if(addmode == TPLAPPEND || addmode == TPLAPPENDONCE) { oldlen = cs_strlen((*vars).values[i]); }
169 if(!cs_realloc(&((*vars).values[i]), oldlen + newlen + 1)) { return; }
170 memcpy((*vars).values[i] + oldlen, value, newlen + 1);
171 (*vars).vartypes[i] = addmode;
173 return;
176 /* Adds a message to be output on the page using the TPLMESSAGE template. */
177 void tpl_addMsg(struct templatevars *vars, const char *value)
179 tpl_addVar(vars, TPLADDONCE, "MESSAGE", value);
180 (*vars).messages++;
181 tpl_addVar(vars, TPLAPPEND, "MESSAGES", tpl_getTpl(vars, "MESSAGEBIT"));
184 /* Allows to add a char array which has been allocated by malloc. It will automatically get
185 freed when calling tpl_clear(). Please do NOT free the memory yourself or realloc
186 it after having added the array here! */
187 static char *tpl_addTmp(struct templatevars *vars, char *value)
189 if(value == NULL) { return ""; }
190 if((*vars).tmpalloc <= (*vars).tmpcnt)
192 if(!cs_realloc(&(*vars).tmp, (*vars).tmpalloc * 2 * sizeof(char **))) { return value; }
193 (*vars).tmpalloc = (*vars).tmpcnt * 2;
195 (*vars).tmp[(*vars).tmpcnt] = value;
196 (*vars).tmpcnt++;
197 return value;
200 /* Allows to do a dynamic printf without knowing and defining the needed memory size. If you specify
201 varname, the printf-result will be added/appended to the varlist, if varname=NULL it will only be returned.
202 In either case you will always get a reference back which you may freely use (but you should not call
203 free/realloc on this as it will be automatically cleaned!)*/
204 void tpl_printf(struct templatevars *vars, uint8_t addmode, const char *varname, const char *fmtstring, ...)
206 uint32_t needed;
207 char test[1];
208 va_list argptr;
210 va_start(argptr, fmtstring);
211 needed = vsnprintf(test, 1, fmtstring, argptr);
212 va_end(argptr);
214 char *result;
215 if(!cs_malloc(&result, needed + 1)) { return; }
216 va_start(argptr, fmtstring);
217 vsnprintf(result, needed + 1, fmtstring, argptr);
218 va_end(argptr);
220 if(varname == NULL) { tpl_addTmp(vars, result); }
221 else
223 tpl_addVar(vars, addmode, varname, result);
224 free(result);
226 return;
229 /* Returns the value for a name or an empty string if nothing was found. */
230 char *tpl_getVar(struct templatevars *vars, const char *name)
232 int32_t i;
233 char *result = NULL;
234 for(i = (*vars).varscnt - 1; i >= 0; --i)
236 if(strcmp((*vars).names[i], name) == 0)
238 result = (*vars).values[i];
239 break;
242 if(result == NULL) { return ""; }
243 else
245 if((*vars).vartypes[i] == TPLADDONCE || (*vars).vartypes[i] == TPLAPPENDONCE)
247 // This is a one-time-use variable which gets cleaned up automatically after retrieving it
248 if(!cs_malloc(&(*vars).values[i], 1))
250 (*vars).values[i] = result;
251 result[0] = '\0';
252 return result;
254 else
256 (*vars).values[i][0] = '\0';
257 return tpl_addTmp(vars, result);
260 else { return result; }
264 /* Initializes all variables for a templatevar-structure and returns a pointer to it. Make
265 sure to call tpl_clear() when you are finished or you'll run into a memory leak! */
266 struct templatevars *tpl_create(void)
268 struct templatevars *vars;
269 if(!cs_malloc(&vars, sizeof(struct templatevars))) { return NULL; }
270 (*vars).varsalloc = 64;
271 (*vars).varscnt = 0;
272 (*vars).tmpalloc = 64;
273 (*vars).tmpcnt = 0;
274 if(!cs_malloc(&(*vars).names, (*vars).varsalloc * sizeof(char **)))
276 NULLFREE(vars);
277 return NULL;
279 if(!cs_malloc(&(*vars).values, (*vars).varsalloc * sizeof(char **)))
281 NULLFREE((*vars).names);
282 NULLFREE(vars);
283 return NULL;
285 if(!cs_malloc(&(*vars).vartypes, (*vars).varsalloc * sizeof(uint8_t *)))
287 NULLFREE((*vars).names);
288 NULLFREE((*vars).values);
289 NULLFREE(vars);
290 return NULL;
292 if(!cs_malloc(&(*vars).tmp, (*vars).tmpalloc * sizeof(char **)))
294 NULLFREE((*vars).names);
295 NULLFREE((*vars).values);
296 NULLFREE((*vars).vartypes);
297 NULLFREE(vars);
298 return NULL;
300 return vars;
303 /* Clears all allocated memory for the specified templatevar-structure. */
304 void tpl_clear(struct templatevars *vars)
306 int32_t i;
307 for(i = (*vars).varscnt - 1; i >= 0; --i)
309 NULLFREE((*vars).names[i]);
310 NULLFREE((*vars).values[i]);
312 NULLFREE((*vars).names);
313 NULLFREE((*vars).values);
314 NULLFREE((*vars).vartypes);
315 for(i = (*vars).tmpcnt - 1; i >= 0; --i)
317 NULLFREE((*vars).tmp[i]);
319 NULLFREE((*vars).tmp);
320 NULLFREE(vars);
323 /* Creates a path to a template file. You need to set the resultsize to the correct size of result. */
324 char *tpl_getFilePathInSubdir(const char *path, const char *subdir, const char *name, const char *ext, char *result, uint32_t resultsize)
326 int path_len = cs_strlen(path);
327 const char *path_fixup = "";
328 if(path_len && path[path_len - 1] != '/')
329 { path_fixup = "/"; }
330 if(path_len + cs_strlen(path_fixup) + cs_strlen(name) + cs_strlen(subdir) + cs_strlen(ext) < resultsize)
332 snprintf(result, resultsize, "%s%s%s%s%s", path, path_fixup, subdir, name, ext);
334 else { result[0] = '\0'; }
335 return result;
338 char *tpl_getTplPath(const char *name, const char *path, char *result, uint32_t resultsize)
340 return tpl_getFilePathInSubdir(path, "", name, ".tpl", result, resultsize);
343 #define check_conf(CONFIG_VAR, text) \
344 if (config_enabled(CONFIG_VAR) && strncmp(#CONFIG_VAR, text, len) == 0) { ok = 1; break; }
346 /* Returns an unparsed template either from disk or from internal templates.
347 Note: You must free() the result after using it and you may get NULL if an error occured!*/
348 char *tpl_getUnparsedTpl(const char *name, int8_t removeHeader, const char *subdir)
350 int32_t i;
351 char *result;
352 char *tpl_path;
354 tpl_path = (cfg.http_piconpath && cs_strlen(name) > 3 && name[0] == 'I' && name[1] == 'C' && name[2] == '_') ? cfg.http_piconpath : cfg.http_tpl;
356 if(tpl_path)
358 char path[255];
359 if((cs_strlen(tpl_getFilePathInSubdir(tpl_path, subdir, name, ".tpl", path, 255)) > 0 && file_exists(path))
360 || (cs_strlen(subdir) > 0
361 && cs_strlen(tpl_getFilePathInSubdir(tpl_path, "" , name, ".tpl", path, 255)) > 0 && file_exists(path)))
363 FILE *fp;
364 char buffer[1025];
365 memset(buffer, 0, sizeof(buffer));
366 int32_t readen, allocated = 1025, offset, size = 0;
367 if(!cs_malloc(&result, allocated)) { return NULL; }
368 if((fp = fopen(path, "r")) != NULL)
370 // Use as read size sizeof(buffer) - 1 to ensure that buffer is
371 // zero terminated otherwise strstr can segfault!
372 while((readen = fread(buffer, 1, sizeof(buffer) - 1, fp)) > 0)
374 offset = 0;
375 if(size == 0 && removeHeader)
377 /* Remove version string from output and check if it is valid for output */
378 char *pch1 = strstr(buffer, "<!--OSCam");
379 if(pch1 != NULL)
381 char *pch2 = strstr(pch1, "-->");
382 if(pch2 != NULL)
384 offset = pch2 - buffer + 4;
385 readen -= offset;
386 pch2[0] = '\0';
387 char *ptr1, *ptr2, *saveptr1 = NULL, *saveptr2 = NULL;
388 for(i = 0, ptr1 = strtok_r(pch1 + 10, ";", &saveptr1); (ptr1) && i < 4 ; ptr1 = strtok_r(NULL, ";", &saveptr1), i++)
390 if(i == 3 && cs_strlen(ptr1) > 2)
392 int8_t ok = 0;
393 for(ptr2 = strtok_r(ptr1, ",", &saveptr2); (ptr2) && ok == 0 ; ptr2 = strtok_r(NULL, ",", &saveptr2))
395 size_t len = cs_strlen(ptr2);
396 check_conf(WITH_CARDREADER, ptr2);
397 check_conf(CARDREADER_PHOENIX, ptr2);
398 check_conf(CARDREADER_DRECAS, ptr2);
399 check_conf(CARDREADER_INTERNAL_AZBOX, ptr2);
400 check_conf(CARDREADER_INTERNAL_COOLAPI, ptr2);
401 check_conf(CARDREADER_INTERNAL_SCI, ptr2);
402 check_conf(CARDREADER_SC8IN1, ptr2);
403 check_conf(CARDREADER_MP35, ptr2);
404 check_conf(CARDREADER_SMARGO, ptr2);
405 check_conf(CARDREADER_PCSC, ptr2);
406 check_conf(CARDREADER_SMART, ptr2);
407 check_conf(CARDREADER_DB2COM, ptr2);
408 check_conf(CARDREADER_STAPI, ptr2);
409 check_conf(CARDREADER_STAPI5, ptr2);
410 check_conf(WEBIF_LIVELOG, ptr2);
411 check_conf(WEBIF_JQUERY, ptr2);
412 check_conf(CS_ANTICASC, ptr2);
413 check_conf(CS_CACHEEX, ptr2);
414 check_conf(CS_CACHEEX_AIO, ptr2);
415 check_conf(HAVE_DVBAPI, ptr2);
416 check_conf(WITH_NEUTRINO, ptr2);
417 check_conf(READ_SDT_CHARSETS, ptr2);
418 check_conf(CLOCKFIX, ptr2);
419 check_conf(IPV6SUPPORT, ptr2);
420 check_conf(LCDSUPPORT, ptr2);
421 check_conf(LEDSUPPORT, ptr2);
422 check_conf(MODULE_CAMD33, ptr2);
423 check_conf(MODULE_CAMD35, ptr2);
424 check_conf(MODULE_CAMD35_TCP, ptr2);
425 check_conf(MODULE_CCCAM, ptr2);
426 check_conf(MODULE_CCCSHARE, ptr2);
427 check_conf(MODULE_CONSTCW, ptr2);
428 check_conf(MODULE_GBOX, ptr2);
429 check_conf(MODULE_GHTTP, ptr2);
430 check_conf(MODULE_MONITOR, ptr2);
431 check_conf(MODULE_NEWCAMD, ptr2);
432 check_conf(MODULE_PANDORA, ptr2);
433 check_conf(MODULE_RADEGAST, ptr2);
434 check_conf(MODULE_SERIAL, ptr2);
435 check_conf(MODULE_CW_CYCLE_CHECK, ptr2);
436 check_conf(READER_BULCRYPT, ptr2);
437 check_conf(READER_CONAX, ptr2);
438 check_conf(READER_CRYPTOWORKS, ptr2);
439 check_conf(READER_GRIFFIN, ptr2);
440 check_conf(READER_DGCRYPT, ptr2);
441 check_conf(READER_DRE, ptr2);
442 check_conf(READER_IRDETO, ptr2);
443 check_conf(READER_NAGRA, ptr2);
444 check_conf(READER_NAGRA_MERLIN, ptr2);
445 check_conf(READER_SECA, ptr2);
446 check_conf(READER_TONGFANG, ptr2);
447 check_conf(READER_VIACCESS, ptr2);
448 check_conf(READER_VIDEOGUARD, ptr2);
449 check_conf(WITH_CARDREADER, ptr2);
450 check_conf(WITH_DEBUG, ptr2);
451 check_conf(WITH_LB, ptr2);
452 check_conf(WITH_LIBCRYPTO, ptr2);
453 check_conf(WITH_SSL, ptr2);
454 check_conf(WITH_STAPI, ptr2);
455 check_conf(WITH_STAPI5, ptr2);
456 check_conf(WITH_EMU, ptr2);
457 } // for
458 if(ok == 0)
460 fclose(fp);
461 return result;
463 break;
464 } // if
465 } // for
466 } // if
467 } // if
468 } // if
469 if(allocated < size + readen + 1)
471 allocated += size + 1024;
472 if(!cs_realloc(&result, allocated))
474 fclose(fp);
475 return NULL;
478 memcpy(result + size, buffer + offset, readen);
479 size += readen;
480 } // while
481 result[size] = '\0';
482 fclose(fp);
483 return result;
484 } // if
485 } // if
486 } // if
488 bool found = 0;
489 uint32_t name_hash = jhash(name, cs_strlen(name));
490 for(i = 0; i < tpls_count; i++)
492 if(tpls[i].tpl_name_hash == name_hash)
494 found = 1;
495 break;
499 if(found)
501 const struct tpl *tpl = &tpls[i];
502 if(!cs_malloc(&result, tpl->tpl_data_len + 1)) { return NULL; } // +1 to accomodate \0 at the end
503 memcpy(result, tpl->tpl_data, tpl->tpl_data_len);
505 else
507 if(!cs_malloc(&result, 1)) { return NULL; } // Return empty string
509 return result;
512 /* Returns the specified template with all variables/other templates replaced or an
513 empty string if the template doesn't exist. Do not free the result yourself, it
514 will get automatically cleaned up! */
515 char *tpl_getTpl(struct templatevars *vars, const char *name)
517 char *tplorg = tpl_getUnparsedTpl(name, 1, tpl_getVar(vars, "SUBDIR"));
518 if(!tplorg) { return ""; }
519 char *tplend = tplorg + cs_strlen(tplorg);
520 char *pch, *pch2, *tpl = tplorg;
521 char varname[33];
523 int32_t tmp, respos = 0;
524 int32_t allocated = 2 * cs_strlen(tpl) + 1;
525 char *result;
526 if(!cs_malloc(&result, allocated)) { return ""; }
528 while(tpl < tplend)
530 if(tpl[0] == '#' && tpl[1] == '#' && tpl[2] != '#')
532 pch2 = tpl;
533 pch = tpl + 2;
534 while(pch[0] != '\0' && (pch[0] != '#' || pch[1] != '#')) { ++pch; }
535 if(pch - pch2 < 32 && pch[0] == '#' && pch[1] == '#')
537 memcpy(varname, pch2 + 2, pch - pch2 - 2);
538 varname[pch - pch2 - 2] = '\0';
539 if(strncmp(varname, "TPL", 3) == 0)
541 if((*vars).messages > 0 || strncmp(varname, "TPLMESSAGE", 10) != 0)
542 { pch2 = tpl_getTpl(vars, varname + 3); }
543 else { pch2 = ""; }
545 else
547 pch2 = tpl_getVar(vars, varname);
549 tmp = cs_strlen(pch2);
550 if(tmp + respos + 2 >= allocated)
552 allocated = tmp + respos + 256;
553 if(!cs_realloc(&result, allocated)) { return ""; }
555 memcpy(result + respos, pch2, tmp);
556 respos += tmp;
557 tpl = pch + 2;
560 else
562 if(respos + 2 >= allocated)
564 allocated = respos + 256;
565 if(!cs_realloc(&result, allocated)) { return ""; }
567 result[respos] = tpl[0];
568 ++respos;
569 ++tpl;
572 NULLFREE(tplorg);
573 result[respos] = '\0';
574 tpl_addTmp(vars, result);
575 return result;
578 /* Saves all templates to the specified paths. Existing files will be overwritten! */
579 int32_t tpl_saveIncludedTpls(const char *path)
581 int32_t i, cnt = 0;
582 char tmp[256];
583 FILE *fp;
584 for(i = 0; i < tpls_count; ++i)
586 const struct tpl *tpl = &tpls[i];
587 if(cs_strlen(tpl_getTplPath(tpl->tpl_name, path, tmp, 256)) > 0 && (fp = fopen(tmp, "w")) != NULL)
589 if(strncmp(tpl->tpl_name, "IC", 2) != 0)
591 fprintf(fp, "<!--OSCam;%d;%s;%s;%s-->\n", crc32(0, (uint8_t *)tpl->tpl_data, tpl->tpl_data_len), CS_VERSION, CS_SVN_VERSION, tpl->tpl_deps);
593 fwrite(tpl->tpl_data, tpl->tpl_data_len, 1, fp);
594 fclose(fp);
595 ++cnt;
598 return cnt;
601 /* Checks all disk templates in a directory if they are still current or may need upgrade! */
602 void tpl_checkOneDirDiskRevisions(const char *subdir)
604 char dirpath[255] = "\0";
605 snprintf(dirpath, 255, "%s%s", cfg.http_tpl ? cfg.http_tpl : "", subdir);
606 int32_t i;
607 char path[255];
608 for(i = 0; i < tpls_count; ++i)
610 const struct tpl *tpl = &tpls[i];
611 if(strncmp(tpl->tpl_name, "IC", 2) != 0 && cs_strlen(tpl_getTplPath(tpl->tpl_name, dirpath, path, 255)) > 0 && file_exists(path))
613 int8_t error = 1;
614 char *tplorg = tpl_getUnparsedTpl(tpl->tpl_name, 0, subdir);
615 unsigned long checksum = 0, curchecksum = crc32(0L, (uint8_t *)tpl->tpl_data, tpl->tpl_data_len);
616 char *ifdefs = "", *pch1 = strstr(tplorg, "<!--OSCam");
617 if(pch1 != NULL)
619 char *version = "?", *revision = "?";
620 char *pch2 = strstr(pch1, "-->");
621 if(pch2 != NULL)
623 pch2[0] = '\0';
624 int32_t j;
625 char *ptr1, *saveptr1 = NULL;
626 for(j = 0, ptr1 = strtok_r(pch1 + 10, ";", &saveptr1); (ptr1) && j < 4 ; ptr1 = strtok_r(NULL, ";", &saveptr1), j++)
628 if(j == 0) { checksum = strtoul(ptr1, NULL, 10); }
629 else if(j == 1) { version = ptr1; }
630 else if(j == 2) { revision = ptr1; }
631 else if(j == 3) { ifdefs = ptr1; }
634 if(checksum != curchecksum)
636 cs_log("WARNING: Your http disk template %s was created for an older revision of OSCam and was changed in original OSCam (%s,r%s). Please consider upgrading it!", path, version, revision);
638 else { error = 0; }
640 else { cs_log("WARNING: Your http disk template %s is in the old template format without revision info. Please consider upgrading it!", path); }
641 if(error) { cs_log("If you are sure that it is current, add the following line at the beginning of the template to suppress this warning: <!--OSCam;%lu;%s;%s;%s-->", curchecksum, CS_VERSION, CS_SVN_VERSION, ifdefs); }
642 NULLFREE(tplorg);
647 /* Checks whether disk templates need upgrade - including sub-directories */
648 void tpl_checkDiskRevisions(void)
650 char subdir[255];
651 char dirpath[255];
652 if(cfg.http_tpl)
654 tpl_checkOneDirDiskRevisions("");
655 DIR *hdir;
656 struct dirent entry;
657 struct dirent *result;
658 struct stat s;
659 if((hdir = opendir(cfg.http_tpl)) != NULL)
661 while(cs_readdir_r(hdir, &entry, &result) == 0 && result != NULL)
663 if(strcmp(".", entry.d_name) == 0 || strcmp("..", entry.d_name) == 0)
665 continue;
667 snprintf(dirpath, 255, "%.31s%.31s", cfg.http_tpl, entry.d_name);
668 if(stat(dirpath, &s) == 0)
670 if(s.st_mode & S_IFDIR)
672 snprintf(subdir, 255,
673 #ifdef WIN32
674 "%s\\"
675 #else
676 "%.253s/"
677 #endif
678 , entry.d_name);
679 tpl_checkOneDirDiskRevisions(subdir);
683 closedir(hdir);
688 /* Helper function for urldecode.*/
689 static int32_t x2i(int32_t i)
691 i = toupper(i);
692 i = i - '0';
693 if(i > 9) { i = i - 'A' + '9' + 1; }
694 return i;
697 /* Decodes values in a http url. Note: The original value is modified! */
698 void urldecode(char *s)
700 int32_t c, c1, n;
701 char *t;
702 t = s;
703 n = cs_strlen(s);
704 while(n > 0)
706 c = *s++;
707 if(c == '+') { c = ' '; }
708 else if(c == '%' && n > 2)
710 c = *s++;
711 c1 = c;
712 c = *s++;
713 c = 16 * x2i(c1) + x2i(c);
714 n -= 2;
716 *t++ = c;
717 n--;
719 *t = 0;
722 /* Encode values in a http url. Do not call free() or realloc on the returned reference or you will get memory corruption! */
723 char *urlencode(struct templatevars *vars, const char *str)
725 char *buf;
726 if(!cs_malloc(&buf, cs_strlen(str) * 3 + 1)) { return ""; }
727 const char *pstr = str;
728 char *pbuf = buf;
730 while(*pstr)
732 if(isalnum((uint8_t)*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~') { *pbuf++ = *pstr; }
733 else if(*pstr == ' ') { *pbuf++ = '+'; }
734 else
736 *pbuf++ = '%';
737 *pbuf++ = to_hex(*pstr >> 4);
738 *pbuf++ = to_hex(*pstr & 15);
740 ++pstr;
742 *pbuf = '\0';
743 /* Allocate the needed memory size and store it in the templatevars */
744 if(!cs_realloc(&buf, cs_strlen(buf) + 1)) { return ""; }
745 return tpl_addTmp(vars, buf);
748 /* XML-Escapes a char array. The returned reference will be automatically cleaned through the templatevars-mechanism tpl_clear().
749 Do not call free() or realloc on the returned reference or you will get memory corruption! */
750 char *xml_encode(struct templatevars *vars, const char *chartoencode)
752 if(!chartoencode) { return ""; }
753 int32_t i, pos = 0, len = cs_strlen(chartoencode);
754 char *encoded;
755 char buffer[7];
756 /* In worst case, every character could get converted to 6 chars (we only support ASCII, for Unicode it would be 7)*/
757 if(!cs_malloc(&encoded, len * 6 + 1)) { return ""; }
758 for(i = 0; i < len; ++i)
760 uint8_t tmp = chartoencode[i];
761 switch(tmp)
763 case '&' :
764 memcpy(encoded + pos, "&amp;", 5);
765 pos += 5;
766 break;
767 case '<' :
768 memcpy(encoded + pos, "&lt;", 4);
769 pos += 4;
770 break;
771 case '>' :
772 memcpy(encoded + pos, "&gt;", 4);
773 pos += 4;
774 break;
775 case '"' :
776 memcpy(encoded + pos, "&quot;", 6);
777 pos += 6;
778 break;
779 case '\'':
780 memcpy(encoded + pos, "&apos;", 6);
781 pos += 6;
782 break;
783 case '\n':
784 memcpy(encoded + pos, "\n", 1);
785 pos += 1;
786 break;
787 default:
788 if(tmp < 32 || tmp > 127)
790 snprintf(buffer, 7, "&#%d;", tmp);
791 memcpy(encoded + pos, buffer, cs_strlen(buffer));
792 pos += cs_strlen(buffer);
794 else
796 encoded[pos] = tmp;
797 ++pos;
801 /* Reduce to the really needed memory size and store it in the templatevars */
802 if(!cs_realloc(&encoded, pos + 1)) { return ""; }
803 encoded[pos] = '\0';
804 return tpl_addTmp(vars, encoded);
807 /* Format a seconds integer to hh:mm:ss or dd hh:mm:ss depending hrs >24 */
808 char *sec2timeformat(struct templatevars *vars, int32_t seconds)
810 char *value;
811 if(seconds <= 0)
812 { return "00:00:00"; }
813 if(!cs_malloc(&value, 16))
814 { return "00:00:00"; }
815 int32_t secs = 0, fullmins = 0, mins = 0, fullhours = 0, hours = 0, days = 0;
816 secs = seconds % 60;
817 if(seconds >= 60)
819 fullmins = seconds / 60;
820 mins = fullmins % 60;
821 if(fullmins >= 60)
823 fullhours = fullmins / 60;
824 hours = fullhours % 24;
825 days = fullhours / 24;
828 if(days == 0)
829 { snprintf(value, 16, "%02d:%02d:%02d", hours, mins, secs); }
830 else
831 { snprintf(value, 16, "%02dd %02d:%02d:%02d", days, hours, mins, secs); }
832 return tpl_addTmp(vars, value);
835 #endif