/* * tvheadend, AJAX / HTML user interface * Copyright (C) 2008 Andreas Öman * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include "tvhead.h" #include "http.h" #include "ajaxui.h" #include "ajaxui_mailbox.h" #include "dispatch.h" #include "obj/ajaxui.cssh" #include "obj/prototype.jsh" #include "obj/builder.jsh" #include "obj/controls.jsh" #include "obj/dragdrop.jsh" #include "obj/effects.jsh" #include "obj/scriptaculous.jsh" #include "obj/slider.jsh" #include "obj/tvheadend.jsh" #include "obj/sbbody_l.gifh" #include "obj/sbbody_r.gifh" #include "obj/sbhead_l.gifh" #include "obj/sbhead_r.gifh" #include "obj/mapped.pngh" #include "obj/unmapped.pngh" extern const char *htsversion; const char *ajax_tabnames[] = { [AJAX_TAB_CHANNELS] = "Channels", [AJAX_TAB_RECORDER] = "Recorder", [AJAX_TAB_CONFIGURATION] = "Configuration", [AJAX_TAB_ABOUT] = "About", }; const char * ajaxui_escape_apostrophe(const char *content) { static char buf[2000]; int i = 0; while(i < sizeof(buf) - 2 && *content) { if(*content == '\'') buf[i++] = '\\'; buf[i++] = *content++; } buf[i] = 0; return buf; } /** * */ void ajax_generate_select_functions(htsbuf_queue_t *hq, const char *fprefix, char **selvector) { int n; htsbuf_qprintf(hq, "\r\n"); } /** * AJAX table */ void ajax_table_top(ajax_table_t *t, http_connection_t *hc, htsbuf_queue_t *hq, const char *names[], int weights[]) { int n = 0, i, tw = 0; while(names[n]) { tw += weights[n]; n++; } assert(n <= 20); t->columns = n; memset(t, 0, sizeof(ajax_table_t)); t->hq = hq; for(i = 0; i < n; i++) t->csize[i] = 100 * weights[i] / tw; htsbuf_qprintf(hq, "
"); htsbuf_qprintf(hq, "
"); for(i = 0; i < n; i++) htsbuf_qprintf(hq, "
%s
", t->csize[i], *names[i] ? names[i]: " "); htsbuf_qprintf(hq, "

\r\n"); } /** * AJAX table new row */ void ajax_table_row_start(ajax_table_t *t, const char *id) { t->rowid = id; t->rowcol = !t->rowcol; htsbuf_qprintf(t->hq, "%s
", t->inrow ? "
\r\n" : "", t->rowcol ? "background: #fff; " : ""); t->inrow = 1; t->curcol = 0; } /** * AJAX table new row */ void ajax_table_subrow_start(ajax_table_t *t) { htsbuf_qprintf(t->hq, "
"); t->curcol = 0; } /** * AJAX table new row */ void ajax_table_subrow_end(ajax_table_t *t) { htsbuf_qprintf(t->hq, "
"); t->curcol = 0; } /** * AJAX table new row */ void ajax_table_details_start(ajax_table_t *t) { assert(t->inrow == 1); t->inrow = 0; /* Extra info */ htsbuf_qprintf(t->hq, "
", t->rowid, t->rowcol ? "background: #fff; " : ""); } /** * AJAX table new row */ void ajax_table_details_end(ajax_table_t *t) { /* Extra info */ htsbuf_qprintf(t->hq, "
"); } /** * AJAX table cell */ void ajax_table_cell(ajax_table_t *t, const char *id, const char *fmt, ...) { va_list ap; va_start(ap, fmt); if(t->rowid && id) { htsbuf_qprintf(t->hq, "
rowid); } else { htsbuf_qprintf(t->hq, "hq, " style=\"float: left; width: %d%%\">", t->csize[t->curcol]); t->curcol++; if(t->curcol == 20) abort(); if(fmt == NULL) htsbuf_qprintf(t->hq, " "); else htsbuf_vqprintf(t->hq, fmt, ap); va_end(ap); htsbuf_qprintf(t->hq, "
"); } /** * AJAX table cell for toggling display of more details */ void ajax_table_cell_detail_toggler(ajax_table_t *t) { ajax_table_cell(t, NULL, "" "More", t->rowid, t->rowid); } /** * AJAX table cell for selecting row */ void ajax_table_cell_checkbox(ajax_table_t *t) { ajax_table_cell(t, NULL, "", t->rowid); } /** * AJAX table footer */ void ajax_table_bottom(ajax_table_t *t) { htsbuf_qprintf(t->hq, "%s", t->inrow ? "" : ""); } /** * AJAX box start */ void ajax_box_begin(htsbuf_queue_t *hq, ajax_box_t type, const char *id, const char *style, const char *title) { char id0[100], style0[100]; if(id != NULL) snprintf(id0, sizeof(id0), "id=\"%s\" ", id); else id0[0] = 0; if(style != NULL) snprintf(style0, sizeof(style0), "style=\"%s\" ", style); else style0[0] = 0; switch(type) { case AJAX_BOX_SIDEBOX: htsbuf_qprintf(hq, "
" "

%s

\r\n" "
", title, id0, style0); break; case AJAX_BOX_FILLED: htsbuf_qprintf(hq, "
" "" "" "" "" "" "" "
\r\n", id0, style0); break; case AJAX_BOX_BORDER: htsbuf_qprintf(hq, "
" "" "" "" "" "
\r\n", id0, style0); break; } } /** * AJAX box end */ void ajax_box_end(htsbuf_queue_t *hq, ajax_box_t type) { switch(type) { case AJAX_BOX_SIDEBOX: htsbuf_qprintf(hq,"
"); break; case AJAX_BOX_FILLED: htsbuf_qprintf(hq, "
" "" "" "" "" "" "" "
\r\n"); break; case AJAX_BOX_BORDER: htsbuf_qprintf(hq, "
" "" "" "" "" "
\r\n"); break; } } /** * */ void ajax_js(htsbuf_queue_t *hq, const char *fmt, ...) { va_list ap; htsbuf_qprintf(hq, "\r\n"); } /** * Based on the given char[] array, generate a menu bar */ void ajax_menu_bar_from_array(htsbuf_queue_t *hq, const char *name, const char **vec, int num, int cur) { int i; htsbuf_qprintf(hq, "
    "); for(i = 0; i < num; i++) { htsbuf_qprintf(hq, "" "%s" "", cur == i ? " style=\"font-weight:bold;\"" : "", name, i, vec[i]); } htsbuf_qprintf(hq, "
"); } /** * */ void ajax_a_jsfuncf(htsbuf_queue_t *hq, const char *innerhtml, const char *fmt, ...) { va_list ap; va_start(ap, fmt); htsbuf_qprintf(hq, "%s", innerhtml); } /** * */ void ajax_button(htsbuf_queue_t *hq, const char *caption, const char *code, ...) { va_list ap; va_start(ap, code); htsbuf_qprintf(hq, ""); } /* * Titlebar AJAX page */ static int ajax_page_titlebar(http_connection_t *hc, http_reply_t *hr, const char *remain, void *opaque) { if(remain == NULL) return HTTP_STATUS_NOT_FOUND; ajax_menu_bar_from_array(&hr->hr_q, "top", ajax_tabnames, AJAX_TABS, atoi(remain)); http_output_html(hc, hr); return 0; } /** * About */ static int ajax_about_tab(http_connection_t *hc, http_reply_t *hr) { htsbuf_queue_t *hq = &hr->hr_q; htsbuf_qprintf(hq, "
"); htsbuf_qprintf(hq, "
"); ajax_box_begin(hq, AJAX_BOX_SIDEBOX, NULL, NULL, "About"); htsbuf_qprintf(hq, "
"); htsbuf_qprintf(hq, "

HTS / Tvheadend

" "

(c) 2006-2008 Andreas \303\226man

" "

Latest release and information is available at:

" "

" "http://www.lonelycoder.com/hts/

" "

 

" "

This webinterface is powered by

" "

Prototype" " and " "script.aculo.us" "

" "

 

" "

Media formats and codecs by

" "

FFmpeg

" ); htsbuf_qprintf(hq, "
"); ajax_box_end(hq, AJAX_BOX_SIDEBOX); htsbuf_qprintf(hq, "
"); htsbuf_qprintf(hq, "
"); http_output_html(hc, hr); return 0; } /* * Tab AJAX page * * Find the 'tab' id and continue with tab specific code */ static int ajax_page_tab(http_connection_t *hc, http_reply_t *hr, const char *remain, void *opaque) { int tab; if(remain == NULL) return HTTP_STATUS_NOT_FOUND; tab = atoi(remain); switch(tab) { case AJAX_TAB_CHANNELS: return ajax_channelgroup_tab(hc, hr); case AJAX_TAB_CONFIGURATION: return ajax_config_tab(hc, hr); case AJAX_TAB_ABOUT: return ajax_about_tab(hc, hr); default: return HTTP_STATUS_NOT_FOUND; } return 0; } /* * Root page */ static int ajax_page_root(http_connection_t *hc, http_reply_t *hr, const char *remain, void *opaque) { htsbuf_queue_t *hq = &hr->hr_q; htsbuf_qprintf(hq, "" /* "" */ "\r\n" "" "" "HTS/Tvheadend" "\r\n" "\r\n" "\r\n" "\r\n" "\r\n" "\r\n" "\r\n" "" ""); htsbuf_qprintf(hq, "
"); htsbuf_qprintf(hq, "
"); ajax_box_begin(hq, AJAX_BOX_FILLED, NULL, NULL, NULL); htsbuf_qprintf(hq, "
" "
" "Tvheadend (%s)" "
" "
" "
" " " "
" "
", htsversion); ajax_mailbox_start(hq); ajax_box_end(hq, AJAX_BOX_FILLED); htsbuf_qprintf(hq, "
"); ajax_js(hq, "switchtab('top', '0')"); #if 0 htsbuf_qprintf(hq, "
"); ajax_box_begin(hq, AJAX_BOX_SIDEBOX, "statusbox", NULL, "System status"); ajax_box_end(hq, AJAX_BOX_SIDEBOX); #endif htsbuf_qprintf(hq, "
"); http_output_html(hc, hr); return 0; } /** * AJAX user interface */ void ajaxui_start(void) { http_path_add("/ajax/index.html", NULL, ajax_page_root, ACCESS_WEB_INTERFACE); http_path_add("/ajax/topmenu", NULL, ajax_page_titlebar, ACCESS_WEB_INTERFACE); http_path_add("/ajax/toptab", NULL, ajax_page_tab, ACCESS_WEB_INTERFACE); /* Stylesheet */ http_resource_add("/ajax/ajaxui.css", embedded_ajaxui, sizeof(embedded_ajaxui), "text/css", "gzip"); #define ADD_JS_RESOURCE(path, name) \ http_resource_add(path, name, sizeof(name), "text/javascript", "gzip") /* Prototype */ ADD_JS_RESOURCE("/ajax/prototype.js", embedded_prototype); /* Scriptaculous */ ADD_JS_RESOURCE("/ajax/builder.js", embedded_builder); ADD_JS_RESOURCE("/ajax/controls.js", embedded_controls); ADD_JS_RESOURCE("/ajax/dragdrop.js", embedded_dragdrop); ADD_JS_RESOURCE("/ajax/effects.js", embedded_effects); ADD_JS_RESOURCE("/ajax/scriptaculous.js", embedded_scriptaculous); ADD_JS_RESOURCE("/ajax/slider.js", embedded_slider); /* Tvheadend */ ADD_JS_RESOURCE("/ajax/tvheadend.js", embedded_tvheadend); /* Embedded images */ http_resource_add("/sidebox/sbbody-l.gif", embedded_sbbody_l, sizeof(embedded_sbbody_l), "image/gif", NULL); http_resource_add("/sidebox/sbbody-r.gif", embedded_sbbody_r, sizeof(embedded_sbbody_r), "image/gif", NULL); http_resource_add("/sidebox/sbhead-l.gif", embedded_sbhead_l, sizeof(embedded_sbhead_l), "image/gif", NULL); http_resource_add("/sidebox/sbhead-r.gif", embedded_sbhead_r, sizeof(embedded_sbhead_r), "image/gif", NULL); http_resource_add("/gfx/unmapped.png", embedded_unmapped, sizeof(embedded_unmapped), "image/png", NULL); http_resource_add("/gfx/mapped.png", embedded_mapped, sizeof(embedded_mapped), "image/png", NULL); ajax_mailbox_init(); ajax_channels_init(); ajax_config_init(); ajax_config_transport_init(); }