[gbx] - fix ccc->gbox reshare
[oscam.git] / module-webif-tpl.c
blob4ed17ebec501bcccb09ea516c260fb37854c296a
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 extern uint8_t cs_http_use_utf8;
16 /* struct template templates[] that comes from webif/pages.c is recreated as
17 struct tpl tpls[] because we need to add additional fields such as tpl_name_hash
18 and possibly preprocess templates[] struct before using it. */
20 struct tpl
22 uint32_t tpl_name_hash;
23 const char *tpl_name;
24 const char *tpl_data;
25 const char *tpl_deps;
26 char *extra_data;
27 uint32_t tpl_data_len;
28 uint8_t tpl_type;
31 static struct tpl *tpls;
32 static char *tpls_data;
33 static int tpls_count;
35 static void tpl_init_base64(struct tpl *tpl)
37 // The rest of OSCam expects images to be base64 encoded and contain mime type.
38 if(!template_is_image(tpl->tpl_type))
39 { return; }
40 size_t b64_buf_len = 32 + BASE64_LENGTH(tpl->tpl_data_len); // Enough for base64 and 32 for header (data:XXX;base64,)
41 char *b64_buf;
42 if(!cs_malloc(&b64_buf, b64_buf_len))
44 tpl->tpl_data = "";
45 tpl->tpl_data_len = 0;
46 return;
48 int hdr_len = snprintf(b64_buf, b64_buf_len, "data:%s;base64,", template_get_mimetype(tpl->tpl_type));
49 base64_encode(tpl->tpl_data, tpl->tpl_data_len, b64_buf + hdr_len, b64_buf_len - hdr_len);
50 tpl->tpl_data = tpl->extra_data = b64_buf;
51 tpl->tpl_data_len = strlen(b64_buf);
54 void webif_tpls_prepare(void)
56 int i;
57 const struct template *templates = templates_get();
58 tpls_count = templates_count();
59 if(!cs_malloc(&tpls, tpls_count * sizeof(struct tpl)))
61 tpls_count = 0;
62 return;
64 #ifdef COMPRESSED_TEMPLATES
65 const char *templates_cdata;
66 size_t tpls_data_len, tpls_data_olen;
67 templates_get_data(&templates_cdata, &tpls_data_len, &tpls_data_olen);
68 if(!cs_malloc(&tpls_data, tpls_data_olen))
70 tpls_count = 0;
71 return;
74 lzo_uint new_len = tpls_data_olen;
75 int r = lzo1x_decompress_safe((uint8_t *)templates_cdata, tpls_data_len, (uint8_t *)tpls_data, &new_len, NULL);
76 if(r == LZO_E_OK && new_len == tpls_data_olen)
78 cs_log("webif: decompressed %zu bytes back into %zu bytes", tpls_data_len, tpls_data_olen);
80 else
82 /* this should NEVER happen */
83 cs_log("internal error - decompression failed: %d\n", r);
84 NULLFREE(tpls);
85 tpls_count = 0;
88 for(i = 0; i < tpls_count; ++i)
90 tpls[i].tpl_name = tpls_data + templates[i].tpl_name_ofs;
91 tpls[i].tpl_data = tpls_data + templates[i].tpl_data_ofs;
92 tpls[i].tpl_deps = tpls_data + templates[i].tpl_deps_ofs;
93 tpls[i].tpl_data_len = templates[i].tpl_data_len;
94 tpls[i].tpl_type = templates[i].tpl_type;
95 tpls[i].tpl_name_hash = jhash(tpls[i].tpl_name, strlen(tpls[i].tpl_name));
96 tpl_init_base64(&tpls[i]);
98 #else
99 for(i = 0; i < tpls_count; ++i)
101 tpls[i].tpl_name_hash = jhash(templates[i].tpl_name, strlen(templates[i].tpl_name));
102 tpls[i].tpl_name = templates[i].tpl_name;
103 tpls[i].tpl_data = templates[i].tpl_data;
104 tpls[i].tpl_deps = templates[i].tpl_deps;
105 tpls[i].tpl_data_len = templates[i].tpl_data_len;
106 tpls[i].tpl_type = templates[i].tpl_type;
107 tpl_init_base64(&tpls[i]);
109 #endif
112 void webif_tpls_free(void)
114 int32_t i, tmp;
116 tmp = tpls_count;
117 tpls_count = 0;
119 for(i = 0; i < tmp; ++i)
121 NULLFREE(tpls[i].extra_data);
123 NULLFREE(tpls_data);
124 NULLFREE(tpls);
127 /* Adds a name->value-mapping or appends to it. You will get a reference back which you may freely
128 use (but you should not call free/realloc on this!)*/
129 void tpl_addVar(struct templatevars *vars, uint8_t addmode, const char *name, const char *value)
131 if(name == NULL) { return; }
132 if(value == NULL) { value = ""; }
133 int32_t i;
134 char *tmp = NULL, *result = NULL;
135 for(i = (*vars).varscnt - 1; i >= 0; --i)
137 if(strcmp((*vars).names[i], name) == 0)
139 result = (*vars).values[i];
140 break;
143 if(result == NULL)
145 if((*vars).varsalloc <= (*vars).varscnt)
147 if(!cs_realloc(&(*vars).names, (*vars).varsalloc * 2 * sizeof(char **))) { return; }
148 if(!cs_realloc(&(*vars).values, (*vars).varsalloc * 2 * sizeof(char **))) { return; }
149 if(!cs_realloc(&(*vars).vartypes, (*vars).varsalloc * 2 * sizeof(uint8_t *))) { return; }
150 (*vars).varsalloc = (*vars).varscnt * 2;
152 int32_t len = strlen(name) + 1;
153 if(!cs_malloc(&tmp, len)) { return; }
154 memcpy(tmp, name, len);
155 (*vars).names[(*vars).varscnt] = tmp;
156 len = strlen(value) + 1;
157 if(!cs_malloc(&tmp, len))
159 NULLFREE((*vars).names[(*vars).varscnt]);
160 return;
162 memcpy(tmp, value, len);
163 (*vars).values[(*vars).varscnt] = tmp;
164 (*vars).vartypes[(*vars).varscnt] = addmode;
165 (*vars).varscnt++;
167 else
169 int32_t oldlen = 0, newlen = strlen(value);
170 if(addmode == TPLAPPEND || addmode == TPLAPPENDONCE) { oldlen = strlen((*vars).values[i]); }
171 if(!cs_realloc(&((*vars).values[i]), oldlen + newlen + 1)) { return; }
172 memcpy((*vars).values[i] + oldlen, value, newlen + 1);
173 (*vars).vartypes[i] = addmode;
175 return;
178 /* Adds a message to be output on the page using the TPLMESSAGE template. */
179 void tpl_addMsg(struct templatevars *vars, const char *value)
181 tpl_addVar(vars, TPLADDONCE, "MESSAGE", value);
182 (*vars).messages++;
183 tpl_addVar(vars, TPLAPPEND, "MESSAGES", tpl_getTpl(vars, "MESSAGEBIT"));
186 /* Allows to add a char array which has been allocated by malloc. It will automatically get
187 freed when calling tpl_clear(). Please do NOT free the memory yourself or realloc
188 it after having added the array here! */
189 static char *tpl_addTmp(struct templatevars *vars, char *value)
191 if(value == NULL) { return ""; }
192 if((*vars).tmpalloc <= (*vars).tmpcnt)
194 if(!cs_realloc(&(*vars).tmp, (*vars).tmpalloc * 2 * sizeof(char **))) { return value; }
195 (*vars).tmpalloc = (*vars).tmpcnt * 2;
197 (*vars).tmp[(*vars).tmpcnt] = value;
198 (*vars).tmpcnt++;
199 return value;
202 /* Allows to do a dynamic printf without knowing and defining the needed memory size. If you specify
203 varname, the printf-result will be added/appended to the varlist, if varname=NULL it will only be returned.
204 In either case you will always get a reference back which you may freely use (but you should not call
205 free/realloc on this as it will be automatically cleaned!)*/
206 void tpl_printf(struct templatevars *vars, uint8_t addmode, const char *varname, const char *fmtstring, ...)
208 uint32_t needed;
209 char test[1];
210 va_list argptr;
212 va_start(argptr, fmtstring);
213 needed = vsnprintf(test, 1, fmtstring, argptr);
214 va_end(argptr);
216 char *result;
217 if(!cs_malloc(&result, needed + 1)) { return; }
218 va_start(argptr, fmtstring);
219 vsnprintf(result, needed + 1, fmtstring, argptr);
220 va_end(argptr);
222 if(varname == NULL) { tpl_addTmp(vars, result); }
223 else
225 tpl_addVar(vars, addmode, varname, result);
226 free(result);
228 return;
231 /* Returns the value for a name or an empty string if nothing was found. */
232 char *tpl_getVar(struct templatevars *vars, const char *name)
234 int32_t i;
235 char *result = NULL;
236 for(i = (*vars).varscnt - 1; i >= 0; --i)
238 if(strcmp((*vars).names[i], name) == 0)
240 result = (*vars).values[i];
241 break;
244 if(result == NULL) { return ""; }
245 else
247 if((*vars).vartypes[i] == TPLADDONCE || (*vars).vartypes[i] == TPLAPPENDONCE)
249 // This is a one-time-use variable which gets cleaned up automatically after retrieving it
250 if(!cs_malloc(&(*vars).values[i], 1))
252 (*vars).values[i] = result;
253 result[0] = '\0';
254 return result;
256 else
258 (*vars).values[i][0] = '\0';
259 return tpl_addTmp(vars, result);
262 else { return result; }
266 /* Initializes all variables for a templatevar-structure and returns a pointer to it. Make
267 sure to call tpl_clear() when you are finished or you'll run into a memory leak! */
268 struct templatevars *tpl_create(void)
270 struct templatevars *vars;
271 if(!cs_malloc(&vars, sizeof(struct templatevars))) { return NULL; }
272 (*vars).varsalloc = 64;
273 (*vars).varscnt = 0;
274 (*vars).tmpalloc = 64;
275 (*vars).tmpcnt = 0;
276 if(!cs_malloc(&(*vars).names, (*vars).varsalloc * sizeof(char **)))
278 NULLFREE(vars);
279 return NULL;
281 if(!cs_malloc(&(*vars).values, (*vars).varsalloc * sizeof(char **)))
283 NULLFREE((*vars).names);
284 NULLFREE(vars);
285 return NULL;
287 if(!cs_malloc(&(*vars).vartypes, (*vars).varsalloc * sizeof(uint8_t *)))
289 NULLFREE((*vars).names);
290 NULLFREE((*vars).values);
291 NULLFREE(vars);
292 return NULL;
294 if(!cs_malloc(&(*vars).tmp, (*vars).tmpalloc * sizeof(char **)))
296 NULLFREE((*vars).names);
297 NULLFREE((*vars).values);
298 NULLFREE((*vars).vartypes);
299 NULLFREE(vars);
300 return NULL;
302 return vars;
305 /* Clears all allocated memory for the specified templatevar-structure. */
306 void tpl_clear(struct templatevars *vars)
308 int32_t i;
309 for(i = (*vars).varscnt - 1; i >= 0; --i)
311 NULLFREE((*vars).names[i]);
312 NULLFREE((*vars).values[i]);
314 NULLFREE((*vars).names);
315 NULLFREE((*vars).values);
316 NULLFREE((*vars).vartypes);
317 for(i = (*vars).tmpcnt - 1; i >= 0; --i)
319 NULLFREE((*vars).tmp[i]);
321 NULLFREE((*vars).tmp);
322 NULLFREE(vars);
325 /* Creates a path to a template file. You need to set the resultsize to the correct size of result. */
326 char *tpl_getFilePathInSubdir(const char *path, const char *subdir, const char *name, const char *ext, char *result, uint32_t resultsize)
328 int path_len = strlen(path);
329 const char *path_fixup = "";
330 if(path_len && path[path_len - 1] != '/')
331 { path_fixup = "/"; }
332 if(path_len + strlen(path_fixup) + strlen(name) + strlen(subdir) + strlen(ext) < resultsize)
334 snprintf(result, resultsize, "%s%s%s%s%s", path, path_fixup, subdir, name, ext);
336 else { result[0] = '\0'; }
337 return result;
340 char *tpl_getTplPath(const char *name, const char *path, char *result, uint32_t resultsize)
342 return tpl_getFilePathInSubdir(path, "", name, ".tpl", result, resultsize);
345 #define check_conf(CONFIG_VAR, text) \
346 if (config_enabled(CONFIG_VAR) && strncmp(#CONFIG_VAR, text, len) == 0) { ok = 1; break; }
348 /* Returns an unparsed template either from disk or from internal templates.
349 Note: You must free() the result after using it and you may get NULL if an error occured!*/
350 char *tpl_getUnparsedTpl(const char *name, int8_t removeHeader, const char *subdir)
352 int32_t i;
353 char *result;
354 char *tpl_path;
356 tpl_path = (cfg.http_piconpath && strlen(name) > 3 && name[0] == 'I' && name[1] == 'C' && name[2] == '_') ? cfg.http_piconpath : cfg.http_tpl;
358 if(tpl_path)
360 char path[255];
361 if((strlen(tpl_getFilePathInSubdir(tpl_path, subdir, name, ".tpl", path, 255)) > 0 && file_exists(path))
362 || (strlen(subdir) > 0
363 #ifdef TOUCH
364 && strcmp(subdir, TOUCH_SUBDIR)
365 #endif
366 && strlen(tpl_getFilePathInSubdir(tpl_path, "" , name, ".tpl", path, 255)) > 0 && file_exists(path)))
368 FILE *fp;
369 char buffer[1025];
370 memset(buffer, 0, sizeof(buffer));
371 int32_t readen, allocated = 1025, offset, size = 0;
372 if(!cs_malloc(&result, allocated)) { return NULL; }
373 if((fp = fopen(path, "r")) != NULL)
375 // Use as read size sizeof(buffer) - 1 to ensure that buffer is
376 // zero terminated otherwise strstr can segfault!
377 while((readen = fread(buffer, 1, sizeof(buffer) - 1, fp)) > 0)
379 offset = 0;
380 if(size == 0 && removeHeader)
382 /* Remove version string from output and check if it is valid for output */
383 char *pch1 = strstr(buffer, "<!--OSCam");
384 if(pch1 != NULL)
386 char *pch2 = strstr(pch1, "-->");
387 if(pch2 != NULL)
389 offset = pch2 - buffer + 4;
390 readen -= offset;
391 pch2[0] = '\0';
392 char *ptr1, *ptr2, *saveptr1 = NULL, *saveptr2 = NULL;
393 for(i = 0, ptr1 = strtok_r(pch1 + 10, ";", &saveptr1); (ptr1) && i < 4 ; ptr1 = strtok_r(NULL, ";", &saveptr1), i++)
395 if(i == 3 && strlen(ptr1) > 2)
397 int8_t ok = 0;
398 for(ptr2 = strtok_r(ptr1, ",", &saveptr2); (ptr2) && ok == 0 ; ptr2 = strtok_r(NULL, ",", &saveptr2))
400 size_t len = strlen(ptr2);
401 check_conf(WITH_CARDREADER, ptr2);
402 check_conf(CARDREADER_PHOENIX, ptr2);
403 check_conf(CARDREADER_DRECAS, ptr2);
404 check_conf(CARDREADER_INTERNAL_AZBOX, ptr2);
405 check_conf(CARDREADER_INTERNAL_COOLAPI, ptr2);
406 check_conf(CARDREADER_INTERNAL_SCI, ptr2);
407 check_conf(CARDREADER_SC8IN1, ptr2);
408 check_conf(CARDREADER_MP35, ptr2);
409 check_conf(CARDREADER_SMARGO, ptr2);
410 check_conf(CARDREADER_PCSC, ptr2);
411 check_conf(CARDREADER_SMART, ptr2);
412 check_conf(CARDREADER_DB2COM, ptr2);
413 check_conf(CARDREADER_STAPI, ptr2);
414 check_conf(CARDREADER_STAPI5, ptr2);
415 check_conf(WEBIF_LIVELOG, ptr2);
416 check_conf(WEBIF_JQUERY, ptr2);
417 check_conf(TOUCH, ptr2);
418 check_conf(CS_ANTICASC, ptr2);
419 check_conf(CS_CACHEEX, ptr2);
420 check_conf(HAVE_DVBAPI, ptr2);
421 check_conf(WITH_NEUTRINO, ptr2);
422 check_conf(READ_SDT_CHARSETS, ptr2);
423 check_conf(CLOCKFIX, ptr2);
424 check_conf(IPV6SUPPORT, ptr2);
425 check_conf(IRDETO_GUESSING, ptr2);
426 check_conf(LCDSUPPORT, ptr2);
427 check_conf(LEDSUPPORT, ptr2);
428 check_conf(MODULE_CAMD33, ptr2);
429 check_conf(MODULE_CAMD35, ptr2);
430 check_conf(MODULE_CAMD35_TCP, ptr2);
431 check_conf(MODULE_CCCAM, ptr2);
432 check_conf(MODULE_CCCSHARE, ptr2);
433 check_conf(MODULE_CONSTCW, ptr2);
434 check_conf(MODULE_GBOX, ptr2);
435 check_conf(MODULE_GHTTP, ptr2);
436 check_conf(MODULE_MONITOR, ptr2);
437 check_conf(MODULE_NEWCAMD, ptr2);
438 check_conf(MODULE_PANDORA, ptr2);
439 check_conf(MODULE_RADEGAST, ptr2);
440 check_conf(MODULE_SERIAL, ptr2);
441 check_conf(MODULE_CW_CYCLE_CHECK, ptr2);
442 check_conf(READER_BULCRYPT, ptr2);
443 check_conf(READER_CONAX, ptr2);
444 check_conf(READER_CRYPTOWORKS, ptr2);
445 check_conf(READER_GRIFFIN, ptr2);
446 check_conf(READER_DGCRYPT, ptr2);
447 check_conf(READER_DRE, ptr2);
448 check_conf(READER_IRDETO, ptr2);
449 check_conf(READER_NAGRA, ptr2);
450 check_conf(READER_NAGRA_MERLIN, ptr2);
451 check_conf(READER_SECA, ptr2);
452 check_conf(READER_TONGFANG, ptr2);
453 check_conf(READER_VIACCESS, ptr2);
454 check_conf(READER_VIDEOGUARD, ptr2);
455 check_conf(WITH_CARDREADER, ptr2);
456 check_conf(WITH_DEBUG, ptr2);
457 check_conf(WITH_LB, ptr2);
458 check_conf(WITH_LIBCRYPTO, ptr2);
459 check_conf(WITH_SSL, ptr2);
460 check_conf(WITH_STAPI, ptr2);
461 check_conf(WITH_STAPI5, ptr2);
462 check_conf(WITH_EMU, ptr2);
463 } // for
464 if(ok == 0)
466 fclose(fp);
467 return result;
469 break;
470 } // if
471 } // for
472 } // if
473 } // if
474 } // if
475 if(allocated < size + readen + 1)
477 allocated += size + 1024;
478 if(!cs_realloc(&result, allocated))
480 fclose(fp);
481 return NULL;
484 memcpy(result + size, buffer + offset, readen);
485 size += readen;
486 } // while
487 result[size] = '\0';
488 fclose(fp);
489 return result;
490 } // if
491 } // if
492 } // if
494 bool found = 0;
495 uint32_t name_hash = jhash(name, strlen(name));
496 for(i = 0; i < tpls_count; i++)
498 if(tpls[i].tpl_name_hash == name_hash)
500 found = 1;
501 break;
505 if(found)
507 const struct tpl *tpl = &tpls[i];
508 if(!cs_malloc(&result, tpl->tpl_data_len + 1)) { return NULL; } // +1 to accomodate \0 at the end
509 memcpy(result, tpl->tpl_data, tpl->tpl_data_len);
511 else
513 if(!cs_malloc(&result, 1)) { return NULL; } // Return empty string
515 return result;
518 /* Returns the specified template with all variables/other templates replaced or an
519 empty string if the template doesn't exist. Do not free the result yourself, it
520 will get automatically cleaned up! */
521 char *tpl_getTpl(struct templatevars *vars, const char *name)
523 char *tplorg = tpl_getUnparsedTpl(name, 1, tpl_getVar(vars, "SUBDIR"));
524 if(!tplorg) { return ""; }
525 char *tplend = tplorg + strlen(tplorg);
526 char *pch, *pch2, *tpl = tplorg;
527 char varname[33];
529 int32_t tmp, respos = 0;
530 int32_t allocated = 2 * strlen(tpl) + 1;
531 char *result;
532 if(!cs_malloc(&result, allocated)) { return ""; }
534 while(tpl < tplend)
536 if(tpl[0] == '#' && tpl[1] == '#' && tpl[2] != '#')
538 pch2 = tpl;
539 pch = tpl + 2;
540 while(pch[0] != '\0' && (pch[0] != '#' || pch[1] != '#')) { ++pch; }
541 if(pch - pch2 < 32 && pch[0] == '#' && pch[1] == '#')
543 memcpy(varname, pch2 + 2, pch - pch2 - 2);
544 varname[pch - pch2 - 2] = '\0';
545 if(strncmp(varname, "TPL", 3) == 0)
547 if((*vars).messages > 0 || strncmp(varname, "TPLMESSAGE", 10) != 0)
548 { pch2 = tpl_getTpl(vars, varname + 3); }
549 else { pch2 = ""; }
551 else
553 pch2 = tpl_getVar(vars, varname);
555 tmp = strlen(pch2);
556 if(tmp + respos + 2 >= allocated)
558 allocated = tmp + respos + 256;
559 if(!cs_realloc(&result, allocated)) { return ""; }
561 memcpy(result + respos, pch2, tmp);
562 respos += tmp;
563 tpl = pch + 2;
566 else
568 if(respos + 2 >= allocated)
570 allocated = respos + 256;
571 if(!cs_realloc(&result, allocated)) { return ""; }
573 result[respos] = tpl[0];
574 ++respos;
575 ++tpl;
578 NULLFREE(tplorg);
579 result[respos] = '\0';
580 tpl_addTmp(vars, result);
581 return result;
584 /* Saves all templates to the specified paths. Existing files will be overwritten! */
585 int32_t tpl_saveIncludedTpls(const char *path)
587 int32_t i, cnt = 0;
588 char tmp[256];
589 FILE *fp;
590 for(i = 0; i < tpls_count; ++i)
592 const struct tpl *tpl = &tpls[i];
593 if(strlen(tpl_getTplPath(tpl->tpl_name, path, tmp, 256)) > 0 && (fp = fopen(tmp, "w")) != NULL)
595 if(strncmp(tpl->tpl_name, "IC", 2) != 0)
597 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);
599 fwrite(tpl->tpl_data, tpl->tpl_data_len, 1, fp);
600 fclose(fp);
601 ++cnt;
604 return cnt;
607 /* Checks all disk templates in a directory if they are still current or may need upgrade! */
608 void tpl_checkOneDirDiskRevisions(const char *subdir)
610 char dirpath[255] = "\0";
611 snprintf(dirpath, 255, "%s%s", cfg.http_tpl ? cfg.http_tpl : "", subdir);
612 int32_t i;
613 char path[255];
614 for(i = 0; i < tpls_count; ++i)
616 const struct tpl *tpl = &tpls[i];
617 if(strncmp(tpl->tpl_name, "IC", 2) != 0 && strlen(tpl_getTplPath(tpl->tpl_name, dirpath, path, 255)) > 0 && file_exists(path))
619 int8_t error = 1;
620 char *tplorg = tpl_getUnparsedTpl(tpl->tpl_name, 0, subdir);
621 unsigned long checksum = 0, curchecksum = crc32(0L, (uint8_t *)tpl->tpl_data, tpl->tpl_data_len);
622 char *ifdefs = "", *pch1 = strstr(tplorg, "<!--OSCam");
623 if(pch1 != NULL)
625 char *version = "?", *revision = "?";
626 char *pch2 = strstr(pch1, "-->");
627 if(pch2 != NULL)
629 pch2[0] = '\0';
630 int32_t j;
631 char *ptr1, *saveptr1 = NULL;
632 for(j = 0, ptr1 = strtok_r(pch1 + 10, ";", &saveptr1); (ptr1) && j < 4 ; ptr1 = strtok_r(NULL, ";", &saveptr1), j++)
634 if(j == 0) { checksum = strtoul(ptr1, NULL, 10); }
635 else if(j == 1) { version = ptr1; }
636 else if(j == 2) { revision = ptr1; }
637 else if(j == 3) { ifdefs = ptr1; }
640 if(checksum != curchecksum)
642 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);
644 else { error = 0; }
646 else { cs_log("WARNING: Your http disk template %s is in the old template format without revision info. Please consider upgrading it!", path); }
647 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); }
648 NULLFREE(tplorg);
653 /* Checks whether disk templates need upgrade - including sub-directories */
654 void tpl_checkDiskRevisions(void)
656 char subdir[255];
657 char dirpath[255];
658 if(cfg.http_tpl)
660 tpl_checkOneDirDiskRevisions("");
661 DIR *hdir;
662 struct dirent entry;
663 struct dirent *result;
664 struct stat s;
665 if((hdir = opendir(cfg.http_tpl)) != NULL)
667 while(cs_readdir_r(hdir, &entry, &result) == 0 && result != NULL)
669 if(strcmp(".", entry.d_name) == 0 || strcmp("..", entry.d_name) == 0)
671 continue;
673 snprintf(dirpath, 255, "%.31s%.31s", cfg.http_tpl, entry.d_name);
674 if(stat(dirpath, &s) == 0)
676 if(s.st_mode & S_IFDIR)
678 snprintf(subdir, 255,
679 #ifdef WIN32
680 "%s\\"
681 #else
682 "%.253s/"
683 #endif
684 , entry.d_name);
685 tpl_checkOneDirDiskRevisions(subdir);
689 closedir(hdir);
694 /* Helper function for urldecode.*/
695 static int32_t x2i(int32_t i)
697 i = toupper(i);
698 i = i - '0';
699 if(i > 9) { i = i - 'A' + '9' + 1; }
700 return i;
703 /* Decodes values in a http url. Note: The original value is modified! */
704 void urldecode(char *s)
706 int32_t c, c1, n;
707 char *t;
708 t = s;
709 n = strlen(s);
710 while(n > 0)
712 c = *s++;
713 if(c == '+') { c = ' '; }
714 else if(c == '%' && n > 2)
716 c = *s++;
717 c1 = c;
718 c = *s++;
719 c = 16 * x2i(c1) + x2i(c);
720 n -= 2;
722 *t++ = c;
723 n--;
725 *t = 0;
728 /* Encode values in a http url. Do not call free() or realloc on the returned reference or you will get memory corruption! */
729 char *urlencode(struct templatevars *vars, const char *str)
731 char *buf;
732 if(!cs_malloc(&buf, strlen(str) * 3 + 1)) { return ""; }
733 const char *pstr = str;
734 char *pbuf = buf;
736 while(*pstr)
738 if(isalnum((uint8_t)*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~') { *pbuf++ = *pstr; }
739 else if(*pstr == ' ') { *pbuf++ = '+'; }
740 else
742 *pbuf++ = '%';
743 *pbuf++ = to_hex(*pstr >> 4);
744 *pbuf++ = to_hex(*pstr & 15);
746 ++pstr;
748 *pbuf = '\0';
749 /* Allocate the needed memory size and store it in the templatevars */
750 if(!cs_realloc(&buf, strlen(buf) + 1)) { return ""; }
751 return tpl_addTmp(vars, buf);
754 /* XML-Escapes a char array. The returned reference will be automatically cleaned through the templatevars-mechanism tpl_clear().
755 Do not call free() or realloc on the returned reference or you will get memory corruption! */
756 char *xml_encode(struct templatevars *vars, const char *chartoencode)
758 if(!chartoencode) { return ""; }
759 int32_t i, pos = 0, len = strlen(chartoencode);
760 char *encoded;
761 char buffer[7];
762 /* In worst case, every character could get converted to 6 chars (we only support ASCII, for Unicode it would be 7)*/
763 if(!cs_malloc(&encoded, len * 6 + 1)) { return ""; }
764 for(i = 0; i < len; ++i)
766 uint8_t tmp = chartoencode[i];
767 switch(tmp)
769 case '&' :
770 memcpy(encoded + pos, "&amp;", 5);
771 pos += 5;
772 break;
773 case '<' :
774 memcpy(encoded + pos, "&lt;", 4);
775 pos += 4;
776 break;
777 case '>' :
778 memcpy(encoded + pos, "&gt;", 4);
779 pos += 4;
780 break;
781 case '"' :
782 memcpy(encoded + pos, "&quot;", 6);
783 pos += 6;
784 break;
785 case '\'':
786 memcpy(encoded + pos, "&#39;", 5);
787 pos += 5;
788 break; // &apos; not supported on older IE
789 case '\n':
790 memcpy(encoded + pos, "\n", 1);
791 pos += 1;
792 break;
793 default:
794 if(tmp < 32 || (cs_http_use_utf8 != 1 && tmp > 127))
796 snprintf(buffer, 7, "&#%d;", tmp);
797 memcpy(encoded + pos, buffer, strlen(buffer));
798 pos += strlen(buffer);
800 else
802 encoded[pos] = tmp;
803 ++pos;
807 /* Reduce to the really needed memory size and store it in the templatevars */
808 if(!cs_realloc(&encoded, pos + 1)) { return ""; }
809 encoded[pos] = '\0';
810 return tpl_addTmp(vars, encoded);
813 /* Format a seconds integer to hh:mm:ss or dd hh:mm:ss depending hrs >24 */
814 char *sec2timeformat(struct templatevars *vars, int32_t seconds)
816 char *value;
817 if(seconds <= 0)
818 { return "00:00:00"; }
819 if(!cs_malloc(&value, 16))
820 { return "00:00:00"; }
821 int32_t secs = 0, fullmins = 0, mins = 0, fullhours = 0, hours = 0, days = 0;
822 secs = seconds % 60;
823 if(seconds >= 60)
825 fullmins = seconds / 60;
826 mins = fullmins % 60;
827 if(fullmins >= 60)
829 fullhours = fullmins / 60;
830 hours = fullhours % 24;
831 days = fullhours / 24;
834 if(days == 0)
835 { snprintf(value, 16, "%02d:%02d:%02d", hours, mins, secs); }
836 else
837 { snprintf(value, 16, "%02dd %02d:%02d:%02d", days, hours, mins, secs); }
838 return tpl_addTmp(vars, value);
841 #endif