Add support for configuring code word clients

This commit is contained in:
Andreas Öman 2008-05-17 07:31:24 +00:00
parent b95b2b8c5b
commit 27b9a91851
11 changed files with 662 additions and 117 deletions

View file

@ -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

View file

@ -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;

View file

@ -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_ */

View file

@ -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
View 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);
}

View file

@ -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));
}

View file

@ -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
View file

@ -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
View file

@ -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_ */

View file

@ -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);
}

View file

@ -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_ */