Add support for configuring code word clients
This commit is contained in:
parent
b95b2b8c5b
commit
27b9a91851
11 changed files with 662 additions and 117 deletions
2
Makefile
2
Makefile
|
@ -44,7 +44,7 @@ VPATH += ajaxui
|
|||
SRCS += ajaxui.c ajaxui_mailbox.c ajaxui_channels.c \
|
||||
ajaxui_config.c ajaxui_config_channels.c ajaxui_config_dvb.c \
|
||||
ajaxui_config_transport.c ajaxui_config_xmltv.c \
|
||||
ajaxui_config_access.c
|
||||
ajaxui_config_access.c ajaxui_config_cwc.c
|
||||
|
||||
JSSRCS += tvheadend.js
|
||||
|
||||
|
|
|
@ -87,6 +87,13 @@ img { border: 0; }
|
|||
width: 50%;
|
||||
}
|
||||
|
||||
.cell_20 {
|
||||
margin-top: 2px;
|
||||
margin-bottom: 2px;
|
||||
float: left;
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
.normaltable {
|
||||
height: 300px;
|
||||
overflow: auto;
|
||||
|
|
|
@ -101,6 +101,9 @@ void ajax_config_xmltv_init(void);
|
|||
int ajax_config_access_tab(http_connection_t *hc, http_reply_t *hr);
|
||||
void ajax_config_access_init(void);
|
||||
|
||||
int ajax_config_cwc_tab(http_connection_t *hc, http_reply_t *hr);
|
||||
void ajax_config_cwc_init(void);
|
||||
|
||||
void ajax_config_transport_init(void);
|
||||
|
||||
int ajax_transport_build_list(http_connection_t *hc, tcp_queue_t *tq,
|
||||
|
@ -119,4 +122,5 @@ void ajax_button(tcp_queue_t *tq, const char *caption, const char *code, ...);
|
|||
void ajax_transport_build_mapper_state(char *buf, size_t siz,
|
||||
th_transport_t *t, int mapped);
|
||||
|
||||
|
||||
#endif /* AJAXUI_H_ */
|
||||
|
|
|
@ -32,13 +32,15 @@
|
|||
#define AJAX_CONFIG_TAB_CHANNELS 0
|
||||
#define AJAX_CONFIG_TAB_DVB 1
|
||||
#define AJAX_CONFIG_TAB_XMLTV 2
|
||||
#define AJAX_CONFIG_TAB_ACCESS 3
|
||||
#define AJAX_CONFIG_TABS 4
|
||||
#define AJAX_CONFIG_TAB_CWC 3
|
||||
#define AJAX_CONFIG_TAB_ACCESS 4
|
||||
#define AJAX_CONFIG_TABS 5
|
||||
|
||||
const char *ajax_config_tabnames[] = {
|
||||
[AJAX_CONFIG_TAB_CHANNELS] = "Channels & Groups",
|
||||
[AJAX_CONFIG_TAB_DVB] = "DVB adapters",
|
||||
[AJAX_CONFIG_TAB_XMLTV] = "XML-TV",
|
||||
[AJAX_CONFIG_TAB_CWC] = "Code-word Client",
|
||||
[AJAX_CONFIG_TAB_ACCESS] = "Access control",
|
||||
};
|
||||
|
||||
|
@ -85,6 +87,8 @@ ajax_config_dispatch(http_connection_t *hc, http_reply_t *hr,
|
|||
return ajax_config_dvb_tab(hc, hr);
|
||||
case AJAX_CONFIG_TAB_XMLTV:
|
||||
return ajax_config_xmltv_tab(hc, hr);
|
||||
case AJAX_CONFIG_TAB_CWC:
|
||||
return ajax_config_cwc_tab(hc, hr);
|
||||
case AJAX_CONFIG_TAB_ACCESS:
|
||||
return ajax_config_access_tab(hc, hr);
|
||||
|
||||
|
@ -138,4 +142,5 @@ ajax_config_init(void)
|
|||
ajax_config_dvb_init();
|
||||
ajax_config_xmltv_init();
|
||||
ajax_config_access_init();
|
||||
ajax_config_cwc_init();
|
||||
}
|
||||
|
|
266
ajaxui/ajaxui_config_cwc.c
Normal file
266
ajaxui/ajaxui_config_cwc.c
Normal file
|
@ -0,0 +1,266 @@
|
|||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <pthread.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tvhead.h"
|
||||
#include "http.h"
|
||||
#include "ajaxui.h"
|
||||
#include "cwc.h"
|
||||
/**
|
||||
* CWC configuration
|
||||
*/
|
||||
int
|
||||
ajax_config_cwc_tab(http_connection_t *hc, http_reply_t *hr)
|
||||
{
|
||||
tcp_queue_t *tq = &hr->hr_tq;
|
||||
|
||||
ajax_box_begin(tq, AJAX_BOX_SIDEBOX, NULL, NULL, "Code-word Client");
|
||||
|
||||
tcp_qprintf(tq, "<div id=\"cwclist\"></div>");
|
||||
|
||||
ajax_js(tq,
|
||||
"new Ajax.Updater('cwclist', '/ajax/cwclist', "
|
||||
"{method: 'get', evalScripts: true});");
|
||||
|
||||
tcp_qprintf(tq, "<hr><div style=\"overflow: auto; width: 100%\">");
|
||||
|
||||
tcp_qprintf(tq,
|
||||
"<div class=\"cell_100\">"
|
||||
"<div class=\"infoprefixwidewidefat\">Hostname:</div>"
|
||||
"<div>"
|
||||
"<input type=\"text\" size=40 id=\"hostname\">"
|
||||
"</div></div>");
|
||||
|
||||
tcp_qprintf(tq,
|
||||
"<div class=\"cell_100\">"
|
||||
"<div class=\"infoprefixwidewidefat\">Port:</div>"
|
||||
"<div>"
|
||||
"<input type=\"text\" id=\"port\">"
|
||||
"</div></div>");
|
||||
|
||||
|
||||
tcp_qprintf(tq,
|
||||
"<div class=\"cell_100\">"
|
||||
"<div class=\"infoprefixwidewidefat\">Username:</div>"
|
||||
"<div>"
|
||||
"<input type=\"text\" id=\"username\">"
|
||||
"</div></div>");
|
||||
|
||||
tcp_qprintf(tq,
|
||||
"<div class=\"cell_100\">"
|
||||
"<div class=\"infoprefixwidewidefat\">Password:</div>"
|
||||
"<div>"
|
||||
"<input type=\"password\" id=\"password\">"
|
||||
"</div></div>");
|
||||
|
||||
tcp_qprintf(tq,
|
||||
"<div class=\"cell_100\">"
|
||||
"<div class=\"infoprefixwidewidefat\">DES-key:</div>"
|
||||
"<div>"
|
||||
"<input type=\"text\" size=50 id=\"deskey\">"
|
||||
"</div></div>");
|
||||
|
||||
tcp_qprintf(tq,
|
||||
"<br>"
|
||||
"<input type=\"button\" value=\"Add new server entry\" "
|
||||
"onClick=\"new Ajax.Request('/ajax/cwcadd', "
|
||||
"{parameters: {"
|
||||
"'hostname': $F('hostname'), "
|
||||
"'port': $F('port'), "
|
||||
"'username': $F('username'), "
|
||||
"'password': $F('password'), "
|
||||
"'deskey': $F('deskey') "
|
||||
"}})"
|
||||
"\">");
|
||||
|
||||
tcp_qprintf(tq, "</div>\r\n");
|
||||
|
||||
ajax_box_end(tq, AJAX_BOX_SIDEBOX);
|
||||
|
||||
tcp_qprintf(tq, "</div>");
|
||||
http_output_html(hc, hr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int
|
||||
ajax_cwclist(http_connection_t *hc, http_reply_t *hr,
|
||||
const char *remain, void *opaque)
|
||||
{
|
||||
tcp_queue_t *tq = &hr->hr_tq;
|
||||
ajax_table_t ta;
|
||||
cwc_t *cwc;
|
||||
char id[20];
|
||||
|
||||
ajax_table_top(&ta, hc, tq,
|
||||
(const char *[]){"Code-word Server",
|
||||
"Username",
|
||||
"Enabled",
|
||||
"Status",
|
||||
"Crypto",
|
||||
"",
|
||||
NULL},
|
||||
(int[]){3, 2, 1, 6, 6, 1});
|
||||
|
||||
TAILQ_FOREACH(cwc, &cwcs, cwc_link) {
|
||||
snprintf(id, sizeof(id), "cwc_%d", cwc->cwc_id);
|
||||
ajax_table_row_start(&ta, id);
|
||||
|
||||
ajax_table_cell(&ta, NULL, "%s:%d",
|
||||
cwc->cwc_tcp_session.tcp_hostname,
|
||||
cwc->cwc_tcp_session.tcp_port);
|
||||
|
||||
ajax_table_cell(&ta, NULL, "%s", cwc->cwc_username);
|
||||
|
||||
ajax_table_cell(&ta, NULL,
|
||||
"<input %stype=\"checkbox\" class=\"nicebox\" "
|
||||
"onChange=\"new Ajax.Request('/ajax/cwcchange', "
|
||||
"{parameters: {checked: this.checked, id: %d}})\">",
|
||||
1 ? "checked " : "", cwc->cwc_id);
|
||||
|
||||
ajax_table_cell(&ta, "status", cwc_status_to_text(cwc));
|
||||
|
||||
ajax_table_cell(&ta, "crypto", cwc_crypto_to_text(cwc));
|
||||
|
||||
ajax_table_cell(&ta, NULL,
|
||||
"<a href=\"javascript:void(0)\" "
|
||||
"onClick=\"dellistentry('/ajax/cwcdel', '%d', '%s')\">"
|
||||
"Delete...</a>",
|
||||
cwc->cwc_id, cwc->cwc_tcp_session.tcp_hostname);
|
||||
}
|
||||
|
||||
ajax_table_bottom(&ta);
|
||||
http_output_html(hc, hr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int
|
||||
ajax_cwcadd(http_connection_t *hc, http_reply_t *hr,
|
||||
const char *remain, void *opaque)
|
||||
{
|
||||
tcp_queue_t *tq = &hr->hr_tq;
|
||||
const char *errtxt;
|
||||
|
||||
errtxt = cwc_add(http_arg_get(&hc->hc_req_args, "hostname"),
|
||||
http_arg_get(&hc->hc_req_args, "port"),
|
||||
http_arg_get(&hc->hc_req_args, "username"),
|
||||
http_arg_get(&hc->hc_req_args, "password"),
|
||||
http_arg_get(&hc->hc_req_args, "deskey"),
|
||||
"1", 1, 1);
|
||||
|
||||
if(errtxt != NULL) {
|
||||
tcp_qprintf(tq, "alert('%s');", errtxt);
|
||||
} else {
|
||||
|
||||
tcp_qprintf(tq, "$('hostname').clear();\r\n");
|
||||
tcp_qprintf(tq, "$('port').clear();\r\n");
|
||||
tcp_qprintf(tq, "$('username').clear();\r\n");
|
||||
tcp_qprintf(tq, "$('password').clear();\r\n");
|
||||
tcp_qprintf(tq, "$('deskey').clear();\r\n");
|
||||
tcp_qprintf(tq,
|
||||
"new Ajax.Updater('cwclist', '/ajax/cwclist', "
|
||||
"{method: 'get', evalScripts: true});");
|
||||
}
|
||||
http_output(hc, hr, "text/javascript; charset=UTF8", NULL, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int
|
||||
ajax_cwcdel(http_connection_t *hc, http_reply_t *hr,
|
||||
const char *remain, void *opaque)
|
||||
{
|
||||
tcp_queue_t *tq = &hr->hr_tq;
|
||||
const char *txt;
|
||||
cwc_t *cwc;
|
||||
|
||||
if((txt = http_arg_get(&hc->hc_req_args, "id")) == NULL)
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
|
||||
if((cwc = cwc_find(atoi(txt))) == NULL)
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
|
||||
cwc_delete(cwc);
|
||||
tcp_qprintf(tq,
|
||||
"new Ajax.Updater('cwclist', '/ajax/cwclist', "
|
||||
"{method: 'get', evalScripts: true});");
|
||||
|
||||
http_output(hc, hr, "text/javascript; charset=UTF8", NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int
|
||||
ajax_cwcchange(http_connection_t *hc, http_reply_t *hr,
|
||||
const char *remain, void *opaque)
|
||||
{
|
||||
// tcp_queue_t *tq = &hr->hr_tq;
|
||||
const char *txt;
|
||||
cwc_t *cwc;
|
||||
|
||||
if((txt = http_arg_get(&hc->hc_req_args, "id")) == NULL)
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
|
||||
if((cwc = cwc_find(atoi(txt))) == NULL)
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
|
||||
if((txt = http_arg_get(&hc->hc_req_args, "checked")) == NULL)
|
||||
return HTTP_STATUS_BAD_REQUEST;
|
||||
|
||||
// cwc_set_state(cwc, atoi(txt));
|
||||
http_output(hc, hr, "text/javascript; charset=UTF8", NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
ajax_config_cwc_init(void)
|
||||
{
|
||||
http_path_add("/ajax/cwclist" , NULL, ajax_cwclist,
|
||||
AJAX_ACCESS_CONFIG);
|
||||
http_path_add("/ajax/cwcadd" , NULL, ajax_cwcadd,
|
||||
AJAX_ACCESS_CONFIG);
|
||||
http_path_add("/ajax/cwcdel" , NULL, ajax_cwcdel,
|
||||
AJAX_ACCESS_CONFIG);
|
||||
http_path_add("/ajax/cwcchange" , NULL, ajax_cwcchange,
|
||||
AJAX_ACCESS_CONFIG);
|
||||
}
|
|
@ -33,6 +33,7 @@
|
|||
#include "epg_xmltv.h"
|
||||
#include "dvb_support.h"
|
||||
#include "ajaxui_mailbox.h"
|
||||
#include "cwc.h"
|
||||
|
||||
#define MAILBOX_UNUSED_TIMEOUT 15
|
||||
#define MAILBOX_EMPTY_REPLY_TIMEOUT 10
|
||||
|
@ -485,3 +486,26 @@ ajax_mailbox_transport_status_change(struct th_transport *t)
|
|||
"status", t->tht_identifier,
|
||||
transport_status_to_text(t->tht_last_status));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
ajax_mailbox_cwc_status_change(struct cwc *cwc)
|
||||
{
|
||||
char id[20];
|
||||
snprintf(id, sizeof(id), "cwc_%d", cwc->cwc_id);
|
||||
|
||||
ajax_mailbox_update_div("cwc", "status", id, cwc_status_to_text(cwc));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
ajax_mailbox_cwc_crypto_change(struct cwc *cwc)
|
||||
{
|
||||
char id[20];
|
||||
snprintf(id, sizeof(id), "cwc_%d", cwc->cwc_id);
|
||||
|
||||
ajax_mailbox_update_div("cwc", "crypto", id, cwc_crypto_to_text(cwc));
|
||||
}
|
||||
|
|
|
@ -42,4 +42,9 @@ void ajax_mailbox_xmltv_grabber_status_change(struct xmltv_grabber *xg);
|
|||
struct th_transport;
|
||||
void ajax_mailbox_transport_status_change(struct th_transport *t);
|
||||
|
||||
struct cwc;
|
||||
void ajax_mailbox_cwc_status_change(struct cwc *cwc);
|
||||
|
||||
void ajax_mailbox_cwc_crypto_change(struct cwc *cwc);
|
||||
|
||||
#endif /* AJAXUI_MAILBOX_H_ */
|
||||
|
|
380
cwc.c
380
cwc.c
|
@ -37,6 +37,9 @@
|
|||
#include "dispatch.h"
|
||||
#include "transports.h"
|
||||
#include "cwc.h"
|
||||
#include "notify.h"
|
||||
|
||||
static int cwc_tally;
|
||||
|
||||
#define CWC_KEEPALIVE_INTERVAL 600
|
||||
|
||||
|
@ -66,6 +69,8 @@ typedef enum {
|
|||
MSG_KEEPALIVE = CWS_FIRSTCMDNO + 0x1d
|
||||
} net_msg_type_t;
|
||||
|
||||
struct cwc_queue cwcs;
|
||||
|
||||
extern char *cwc_krypt(const char *key, const char *salt);
|
||||
|
||||
static LIST_HEAD(, cwc_transport) cwc_pending_requests;
|
||||
|
@ -104,45 +109,19 @@ typedef struct cwc_transport {
|
|||
} cwc_transport_t;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
cwc_set_state(cwc_t *cwc, int newstate, const char *errtxt)
|
||||
{
|
||||
cwc->cwc_state = newstate;
|
||||
|
||||
if(newstate == CWC_STATE_IDLE)
|
||||
cwc->cwc_errtxt = errtxt;
|
||||
|
||||
|
||||
typedef struct cwc {
|
||||
tcp_session_t cwc_tcp_session; /* Must be first */
|
||||
|
||||
LIST_ENTRY(cwc) cwc_link;
|
||||
|
||||
LIST_HEAD(, cwc_transport) cwc_transports;
|
||||
|
||||
enum {
|
||||
CWC_STATE_IDLE,
|
||||
CWC_STATE_WAIT_LOGIN_KEY,
|
||||
CWC_STATE_WAIT_LOGIN_ACK,
|
||||
CWC_STATE_WAIT_CARD_DATA,
|
||||
CWC_STATE_RUNNING,
|
||||
} cwc_state;
|
||||
|
||||
uint16_t cwc_caid;
|
||||
|
||||
uint16_t cwc_seq;
|
||||
|
||||
uint8_t cwc_key[16];
|
||||
|
||||
uint8_t cwc_buf[256];
|
||||
int cwc_bufptr;
|
||||
|
||||
/* From configuration */
|
||||
|
||||
uint8_t cwc_confedkey[14];
|
||||
const char *cwc_username;
|
||||
const char *cwc_password; /* salted version */
|
||||
|
||||
dtimer_t cwc_idle_timer;
|
||||
|
||||
dtimer_t cwc_send_ka_timer;
|
||||
} cwc_t;
|
||||
|
||||
static LIST_HEAD(, cwc) cwcs;
|
||||
notify_cwc_status_change(cwc);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -355,7 +334,7 @@ cwc_send_data_req(cwc_t *cwc)
|
|||
{
|
||||
uint8_t buf[CWS_NETMSGSIZE];
|
||||
|
||||
cwc->cwc_state = CWC_STATE_WAIT_CARD_DATA;
|
||||
cwc_set_state(cwc, CWC_STATE_WAIT_CARD_DATA, NULL);
|
||||
|
||||
buf[0] = MSG_CARD_DATA_REQ;
|
||||
buf[1] = 0;
|
||||
|
@ -407,6 +386,8 @@ cwc_dispatch_card_data_reply(cwc_t *cwc, uint8_t msgtype,
|
|||
cwc->cwc_caid = (msg[4] << 8) | msg[5];
|
||||
n = psi_caid2name(cwc->cwc_caid) ?: "Unknown";
|
||||
|
||||
notify_cwc_crypto_change(cwc);
|
||||
|
||||
syslog(LOG_INFO, "cwc: %s: Connected as user 0x%02x "
|
||||
"to a %s-card [0x%04x : %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x] "
|
||||
"with %d providers",
|
||||
|
@ -415,7 +396,7 @@ cwc_dispatch_card_data_reply(cwc_t *cwc, uint8_t msgtype,
|
|||
msg[6], msg[7], msg[8], msg[9], msg[10], msg[11], msg[12], msg[13],
|
||||
msg[14]);
|
||||
|
||||
cwc->cwc_state = CWC_STATE_RUNNING;
|
||||
cwc_set_state(cwc, CWC_STATE_RUNNING, NULL);
|
||||
|
||||
/* Send KA every CWC_KEEPALIVE_INTERVAL seconds */
|
||||
|
||||
|
@ -436,7 +417,7 @@ cwc_send_login(cwc_t *cwc)
|
|||
int ul = strlen(cwc->cwc_username) + 1;
|
||||
int pl = strlen(cwc->cwc_password) + 1;
|
||||
|
||||
cwc->cwc_state = CWC_STATE_WAIT_LOGIN_ACK;
|
||||
cwc_set_state(cwc, CWC_STATE_WAIT_LOGIN_ACK, NULL);
|
||||
|
||||
buf[0] = MSG_CLIENT_2_SERVER_LOGIN;
|
||||
buf[1] = 0;
|
||||
|
@ -621,13 +602,13 @@ cwc_tcp_callback(tcpevent_t event, void *tcpsession)
|
|||
case TCP_CONNECT:
|
||||
cwc->cwc_seq = 0;
|
||||
cwc->cwc_bufptr = 0;
|
||||
cwc->cwc_state = CWC_STATE_WAIT_LOGIN_KEY;
|
||||
cwc_set_state(cwc, CWC_STATE_WAIT_LOGIN_KEY, NULL);
|
||||
/* We want somthing within 20 seconds */
|
||||
dtimer_arm(&cwc->cwc_idle_timer, cwc_timeout, cwc, 20);
|
||||
break;
|
||||
|
||||
case TCP_DISCONNECT:
|
||||
cwc->cwc_state = CWC_STATE_IDLE;
|
||||
cwc_set_state(cwc, CWC_STATE_IDLE, "Disconnected");
|
||||
dtimer_disarm(&cwc->cwc_send_ka_timer);
|
||||
break;
|
||||
|
||||
|
@ -734,21 +715,29 @@ cwc_descramble(th_descrambler_t *td, th_transport_t *t, struct th_stream *st,
|
|||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
cwc_transport_stop(th_descrambler_t *td)
|
||||
static void
|
||||
cwc_transport_destroy(cwc_transport_t *ct)
|
||||
{
|
||||
cwc_transport_t *ct = (cwc_transport_t *)td;
|
||||
|
||||
if(ct->ct_pending)
|
||||
LIST_REMOVE(ct, ct_link);
|
||||
|
||||
LIST_REMOVE(ct, ct_cwc_link);
|
||||
|
||||
LIST_REMOVE(td, td_transport_link);
|
||||
free_key_struct(ct->ct_keys);
|
||||
free(ct);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
cwc_transport_stop(th_descrambler_t *td)
|
||||
{
|
||||
LIST_REMOVE(td, td_transport_link);
|
||||
|
||||
cwc_transport_destroy((cwc_transport_t *)td);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if our CAID's matches, and if so, link
|
||||
|
@ -761,7 +750,7 @@ cwc_transport_start(th_transport_t *t)
|
|||
th_descrambler_t *td;
|
||||
th_stream_t *st;
|
||||
|
||||
LIST_FOREACH(cwc, &cwcs, cwc_link) {
|
||||
TAILQ_FOREACH(cwc, &cwcs, cwc_link) {
|
||||
|
||||
LIST_FOREACH(st, &t->tht_streams, st_link)
|
||||
if(st->st_caid == cwc->cwc_caid)
|
||||
|
@ -785,6 +774,54 @@ cwc_transport_start(th_transport_t *t)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void
|
||||
cwc_save(void)
|
||||
{
|
||||
cwc_t *cwc;
|
||||
|
||||
FILE *fp;
|
||||
char buf[400];
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s/cwc.cfg", settings_dir);
|
||||
if((fp = settings_open_for_write(buf)) == NULL)
|
||||
return;
|
||||
|
||||
TAILQ_FOREACH(cwc, &cwcs, cwc_link) {
|
||||
|
||||
fprintf(fp, "cwc {\n");
|
||||
fprintf(fp, "\thostname = %s\n", cwc->cwc_tcp_session.tcp_hostname);
|
||||
fprintf(fp, "\tport = %d\n", cwc->cwc_tcp_session.tcp_port);
|
||||
|
||||
fprintf(fp, "\tusername = %s\n", cwc->cwc_username);
|
||||
fprintf(fp, "\tpassword = %s\n", cwc->cwc_password);
|
||||
fprintf(fp, "\tdeskey = "
|
||||
"%02x:%02x:%02x:%02x:%02x:%02x:%02x:"
|
||||
"%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
|
||||
cwc->cwc_confedkey[0x0],
|
||||
cwc->cwc_confedkey[0x1],
|
||||
cwc->cwc_confedkey[0x2],
|
||||
cwc->cwc_confedkey[0x3],
|
||||
cwc->cwc_confedkey[0x4],
|
||||
cwc->cwc_confedkey[0x5],
|
||||
cwc->cwc_confedkey[0x6],
|
||||
cwc->cwc_confedkey[0x7],
|
||||
cwc->cwc_confedkey[0x8],
|
||||
cwc->cwc_confedkey[0x9],
|
||||
cwc->cwc_confedkey[0xa],
|
||||
cwc->cwc_confedkey[0xb],
|
||||
cwc->cwc_confedkey[0xc],
|
||||
cwc->cwc_confedkey[0xd]);
|
||||
fprintf(fp, "\tenabled = %d\n", 1);
|
||||
|
||||
|
||||
fprintf(fp, "}\n");
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
}
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -804,80 +841,195 @@ nibble(char c)
|
|||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const char *
|
||||
cwc_add(const char *hostname, const char *porttxt, const char *username,
|
||||
const char *password, const char *deskey, const char *enabled,
|
||||
int save, int salt)
|
||||
{
|
||||
const char *k;
|
||||
cwc_t *cwc;
|
||||
uint8_t key[14];
|
||||
|
||||
int i, u, l, port;
|
||||
|
||||
if(hostname == NULL || strlen(hostname) < 1)
|
||||
return "Invalid hostname";
|
||||
|
||||
if(porttxt == NULL)
|
||||
return "Invalid port";
|
||||
|
||||
port = atoi(porttxt);
|
||||
if(port < 1 || port > 65535)
|
||||
return "Invalid port";
|
||||
|
||||
if(username == NULL || strlen(username) < 1)
|
||||
return "Invalid username";
|
||||
if(password == NULL || strlen(password) < 1)
|
||||
return "Invalid password";
|
||||
|
||||
if(deskey == NULL)
|
||||
return "Invalid DES-key";
|
||||
|
||||
k = deskey;
|
||||
for(i = 0; i < 14; i++) {
|
||||
while(*k != 0 && !isxdigit(*k)) k++;
|
||||
if(*k == 0)
|
||||
break;
|
||||
u = nibble(*k++);
|
||||
while(*k != 0 && !isxdigit(*k)) k++;
|
||||
if(*k == 0)
|
||||
break;
|
||||
l = nibble(*k++);
|
||||
key[i] = (u << 4) | l;
|
||||
}
|
||||
|
||||
if(i != 14)
|
||||
return "DES-key does not contain 14 valid hexadecimal bytes";
|
||||
|
||||
if(enabled == NULL)
|
||||
return "Enabled not set";
|
||||
|
||||
cwc = tcp_create_client(hostname, port, sizeof(cwc_t),
|
||||
"cwc", cwc_tcp_callback);
|
||||
|
||||
// cwc->cwc_enabled = atoi(enabled);
|
||||
cwc->cwc_username = strdup(username);
|
||||
|
||||
if(salt) {
|
||||
cwc->cwc_password = strdup(cwc_krypt(password, "$1$abcdefgh$"));
|
||||
} else {
|
||||
cwc->cwc_password = strdup(password);
|
||||
}
|
||||
|
||||
cwc->cwc_id = ++cwc_tally;
|
||||
|
||||
memcpy(cwc->cwc_confedkey, key, 14);
|
||||
TAILQ_INSERT_TAIL(&cwcs, cwc, cwc_link);
|
||||
|
||||
if(save)
|
||||
cwc_save();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
cwc_t *
|
||||
cwc_find(int id)
|
||||
{
|
||||
cwc_t *cwc;
|
||||
TAILQ_FOREACH(cwc, &cwcs, cwc_link)
|
||||
if(cwc->cwc_id == id)
|
||||
break;
|
||||
return cwc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
cwc_delete(cwc_t *cwc)
|
||||
{
|
||||
cwc_transport_t *ct;
|
||||
|
||||
while((ct = LIST_FIRST(&cwc->cwc_transports)) != NULL)
|
||||
cwc_transport_destroy(ct);
|
||||
|
||||
TAILQ_REMOVE(&cwcs, cwc, cwc_link);
|
||||
free((void *)cwc->cwc_password);
|
||||
free((void *)cwc->cwc_username);
|
||||
|
||||
tcp_destroy_client(&cwc->cwc_tcp_session);
|
||||
cwc_save();
|
||||
}
|
||||
|
||||
#if 0
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
cwc_set_enable(cwc_t *cwc, int enabled)
|
||||
{
|
||||
if(cwc->enabled == enabled)
|
||||
return;
|
||||
|
||||
cwc->enabled = enabled;
|
||||
|
||||
tcp_client_set_state(&cwc->cwc_tcp_session, enabled);
|
||||
cwc_save();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void
|
||||
cwc_init(void)
|
||||
{
|
||||
cwc_t *cwc;
|
||||
void *iterator = NULL, *head;
|
||||
const char *username;
|
||||
const char *password;
|
||||
const char *deskey, *k;
|
||||
const char *hostname;
|
||||
int port;
|
||||
uint8_t key[14];
|
||||
int i, u, l;
|
||||
struct config_head cl;
|
||||
config_entry_t *ce;
|
||||
char buf[400];
|
||||
|
||||
while((head = config_iterate_sections(&iterator, "cwc")) != NULL) {
|
||||
TAILQ_INIT(&cwcs);
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s/cwc.cfg", settings_dir);
|
||||
|
||||
TAILQ_INIT(&cl);
|
||||
config_read_file0(buf, &cl);
|
||||
|
||||
if((hostname = config_get_str_sub(head, "hostname", NULL)) == NULL) {
|
||||
syslog(LOG_INFO, "cwc: config section missing 'hostname'");
|
||||
}
|
||||
|
||||
if((port = atoi(config_get_str_sub(head, "port", "0"))) == 0) {
|
||||
syslog(LOG_INFO, "cwc: config section missing 'port'");
|
||||
}
|
||||
|
||||
if((username = config_get_str_sub(head, "username", NULL)) == NULL) {
|
||||
syslog(LOG_INFO, "cwc: config section missing 'username'");
|
||||
}
|
||||
|
||||
if((password = config_get_str_sub(head, "password", NULL)) == NULL) {
|
||||
syslog(LOG_INFO, "cwc: config section missing 'password'");
|
||||
}
|
||||
|
||||
if((deskey = config_get_str_sub(head, "deskey", NULL)) == NULL) {
|
||||
syslog(LOG_INFO, "cwc: config section missing 'deskey'");
|
||||
}
|
||||
|
||||
|
||||
k = deskey;
|
||||
for(i = 0; i < 14; i++) {
|
||||
while(*k != 0 && !isxdigit(*k)) k++;
|
||||
if(*k == 0)
|
||||
break;
|
||||
u = nibble(*k++);
|
||||
while(*k != 0 && !isxdigit(*k)) k++;
|
||||
if(*k == 0)
|
||||
break;
|
||||
l = nibble(*k++);
|
||||
key[i] = (u << 4) | l;
|
||||
}
|
||||
|
||||
if(i != 14) {
|
||||
syslog(LOG_INFO, "cwc: 'deskey' is not 14 valid hexadecimal bytes");
|
||||
TAILQ_FOREACH(ce, &cl, ce_link) {
|
||||
if(ce->ce_type != CFG_SUB || strcasecmp("cwc", ce->ce_key))
|
||||
continue;
|
||||
}
|
||||
|
||||
if(hostname == NULL || username == NULL || password == NULL ||
|
||||
deskey == NULL || port == 0)
|
||||
continue;
|
||||
|
||||
cwc = tcp_create_client(hostname, port, sizeof(cwc_t),
|
||||
"cwc", cwc_tcp_callback);
|
||||
|
||||
cwc->cwc_username = strdup(username);
|
||||
|
||||
if(!strncmp(password, "$1$", 3)) {
|
||||
cwc->cwc_password = strdup(password);
|
||||
} else {
|
||||
cwc->cwc_password = strdup(cwc_krypt(password, "$1$abcdefgh$"));
|
||||
}
|
||||
|
||||
memcpy(cwc->cwc_confedkey, key, 14);
|
||||
LIST_INSERT_HEAD(&cwcs, cwc, cwc_link);
|
||||
|
||||
|
||||
cwc_add(config_get_str_sub(&ce->ce_sub, "hostname", NULL),
|
||||
config_get_str_sub(&ce->ce_sub, "port", NULL),
|
||||
config_get_str_sub(&ce->ce_sub, "username", NULL),
|
||||
config_get_str_sub(&ce->ce_sub, "password", NULL),
|
||||
config_get_str_sub(&ce->ce_sub, "deskey", NULL),
|
||||
config_get_str_sub(&ce->ce_sub, "enabled", NULL),
|
||||
0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static struct strtab cwcstatustab[] = {
|
||||
{ "Waiting for login key", CWC_STATE_WAIT_LOGIN_KEY },
|
||||
{ "Waiting for login ACK", CWC_STATE_WAIT_LOGIN_ACK },
|
||||
{ "Waiting for card data", CWC_STATE_WAIT_CARD_DATA },
|
||||
{ "Running", CWC_STATE_RUNNING },
|
||||
};
|
||||
|
||||
const char *
|
||||
cwc_status_to_text(struct cwc *cwc)
|
||||
{
|
||||
if(cwc->cwc_state == CWC_STATE_IDLE)
|
||||
return cwc->cwc_errtxt ?: "Not connected";
|
||||
|
||||
return val2str(cwc->cwc_state, cwcstatustab) ?: "Invalid status";
|
||||
}
|
||||
|
||||
const char *
|
||||
cwc_crypto_to_text(struct cwc *cwc)
|
||||
{
|
||||
const char *n;
|
||||
static char buf[40];
|
||||
|
||||
if(cwc->cwc_state != CWC_STATE_RUNNING)
|
||||
return "Unknown";
|
||||
|
||||
n = psi_caid2name(cwc->cwc_caid);
|
||||
if(n != NULL)
|
||||
return n;
|
||||
|
||||
snprintf(buf, sizeof(buf), "0x%x", cwc->cwc_caid);
|
||||
return buf;
|
||||
}
|
||||
|
|
64
cwc.h
64
cwc.h
|
@ -19,8 +19,72 @@
|
|||
#ifndef CWC_H_
|
||||
#define CWC_H_
|
||||
|
||||
#include "tcp.h"
|
||||
|
||||
TAILQ_HEAD(cwc_queue, cwc);
|
||||
|
||||
extern struct cwc_queue cwcs;
|
||||
|
||||
typedef struct cwc {
|
||||
tcp_session_t cwc_tcp_session; /* Must be first */
|
||||
|
||||
TAILQ_ENTRY(cwc) cwc_link;
|
||||
|
||||
LIST_HEAD(, cwc_transport) cwc_transports;
|
||||
|
||||
enum {
|
||||
CWC_STATE_IDLE,
|
||||
CWC_STATE_WAIT_LOGIN_KEY,
|
||||
CWC_STATE_WAIT_LOGIN_ACK,
|
||||
CWC_STATE_WAIT_CARD_DATA,
|
||||
CWC_STATE_RUNNING,
|
||||
CWC_STATE_HOST_ERROR,
|
||||
CWC_STATE_ACCESS_ERROR,
|
||||
} cwc_state;
|
||||
|
||||
uint16_t cwc_caid;
|
||||
|
||||
uint16_t cwc_seq;
|
||||
|
||||
uint8_t cwc_key[16];
|
||||
|
||||
uint8_t cwc_buf[256];
|
||||
int cwc_bufptr;
|
||||
|
||||
/* From configuration */
|
||||
|
||||
uint8_t cwc_confedkey[14];
|
||||
const char *cwc_username;
|
||||
const char *cwc_password; /* salted version */
|
||||
|
||||
dtimer_t cwc_idle_timer;
|
||||
|
||||
dtimer_t cwc_send_ka_timer;
|
||||
|
||||
int cwc_id;
|
||||
|
||||
const char *cwc_errtxt;
|
||||
|
||||
} cwc_t;
|
||||
|
||||
|
||||
void cwc_init(void);
|
||||
|
||||
void cwc_transport_start(th_transport_t *t);
|
||||
|
||||
const char *cwc_add(const char *hostname, const char *porttxt,
|
||||
const char *username, const char *password,
|
||||
const char *deskey, const char *enabled,
|
||||
int save, int salt);
|
||||
|
||||
const char *cwc_status_to_text(struct cwc *cwc);
|
||||
|
||||
cwc_t *cwc_find(int id);
|
||||
|
||||
void cwc_delete(cwc_t *cwc);
|
||||
|
||||
void cwc_set_enable(cwc_t *cwc, int enabled);
|
||||
|
||||
const char *cwc_crypto_to_text(struct cwc *cwc);
|
||||
|
||||
#endif /* CWC_H_ */
|
||||
|
|
13
notify.c
13
notify.c
|
@ -85,3 +85,16 @@ notify_transprot_status_change(struct th_transport *t)
|
|||
|
||||
ajax_mailbox_transport_status_change(t);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
notify_cwc_status_change(struct cwc *cwc)
|
||||
{
|
||||
ajax_mailbox_cwc_status_change(cwc);
|
||||
}
|
||||
|
||||
void
|
||||
notify_cwc_crypto_change(struct cwc *cwc)
|
||||
{
|
||||
ajax_mailbox_cwc_status_change(cwc);
|
||||
}
|
||||
|
|
5
notify.h
5
notify.h
|
@ -40,4 +40,9 @@ void notify_xmltv_grabber_status_change(struct xmltv_grabber *xg);
|
|||
struct th_transport;
|
||||
void notify_transprot_status_change(struct th_transport *t);
|
||||
|
||||
struct cwc;
|
||||
void notify_cwc_status_change(struct cwc *cwc);
|
||||
|
||||
void notify_cwc_crypto_change(struct cwc *cwc);
|
||||
|
||||
#endif /* NOTIFY_H_ */
|
||||
|
|
Loading…
Add table
Reference in a new issue