summaryrefslogtreecommitdiffstats
path: root/xbmc-11.0-tsp-Eden-pvr.patch
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc-11.0-tsp-Eden-pvr.patch')
-rw-r--r--xbmc-11.0-tsp-Eden-pvr.patch1504
1 files changed, 1331 insertions, 173 deletions
diff --git a/xbmc-11.0-tsp-Eden-pvr.patch b/xbmc-11.0-tsp-Eden-pvr.patch
index 2fa4c15..2d2d3c5 100644
--- a/xbmc-11.0-tsp-Eden-pvr.patch
+++ b/xbmc-11.0-tsp-Eden-pvr.patch
@@ -27774,10 +27774,22 @@ index 0000000..db93c59
+</Project>
\ No newline at end of file
diff --git a/lib/cmyth/Win32/libcmyth.def b/lib/cmyth/Win32/libcmyth.def
-index 7ea4356..a4ed819 100644
+index 7ea4356..4562442 100644
--- a/lib/cmyth/Win32/libcmyth.def
+++ b/lib/cmyth/Win32/libcmyth.def
-@@ -98,6 +98,7 @@ EXPORTS
+@@ -45,6 +45,11 @@ EXPORTS
+ cmyth_file_request_block
+ cmyth_file_seek
+ cmyth_freespace_create
++ cmyth_inputlist_create
++ cmyth_input_destroy
++ cmyth_input_create
++ cmyth_rcv_free_inputlist
++ cmyth_get_free_inputlist
+ cmyth_keyframe_create
+ cmyth_keyframe_fill
+ cmyth_keyframe_string
+@@ -98,6 +103,7 @@ EXPORTS
cmyth_chanlist_get_count
cmyth_channel_chanid
cmyth_channel_channum
@@ -27785,7 +27797,7 @@ index 7ea4356..a4ed819 100644
cmyth_channel_name
cmyth_channel_icon
cmyth_channel_visible
-@@ -117,6 +118,8 @@ EXPORTS
+@@ -117,6 +123,8 @@ EXPORTS
cmyth_proginfo_category
cmyth_proginfo_seriesid
cmyth_proginfo_programid
@@ -27794,7 +27806,7 @@ index 7ea4356..a4ed819 100644
cmyth_proginfo_stars
cmyth_proginfo_playgroup
cmyth_proginfo_originalairdate
-@@ -215,4 +218,66 @@ EXPORTS
+@@ -215,4 +223,66 @@ EXPORTS
cmyth_ringbuf_read
cmyth_file_read
cmyth_livetv_read
@@ -27863,8 +27875,23 @@ index 7ea4356..a4ed819 100644
+ cmyth_storagegroup_file_get_lastmodified
+ cmyth_storagegroup_file_get_size
+
+diff --git a/lib/cmyth/Win32/libcmyth.vcproj b/lib/cmyth/Win32/libcmyth.vcproj
+index 55cf9af..ddca3fb 100644
+--- a/lib/cmyth/Win32/libcmyth.vcproj
++++ b/lib/cmyth/Win32/libcmyth.vcproj
+@@ -216,6 +216,10 @@
+ >
+ </File>
+ <File
++ RelativePath="..\libcmyth\input.c"
++ >
++ </File>
++ <File
+ RelativePath="..\libcmyth\keyframe.c"
+ >
+ </File>
diff --git a/lib/cmyth/Win32/libcmyth.vcxproj b/lib/cmyth/Win32/libcmyth.vcxproj
-index a698d8a..9619138 100644
+index a698d8a..17d7c57 100644
--- a/lib/cmyth/Win32/libcmyth.vcxproj
+++ b/lib/cmyth/Win32/libcmyth.vcxproj
@@ -54,7 +54,7 @@
@@ -27901,11 +27928,57 @@ index a698d8a..9619138 100644
</Link>
<PostBuildEvent>
<Command>
+@@ -137,6 +139,7 @@
+ <ClCompile Include="..\libcmyth\event.c" />
+ <ClCompile Include="..\libcmyth\file.c" />
+ <ClCompile Include="..\libcmyth\freespace.c" />
++ <ClCompile Include="..\libcmyth\input.c" />
+ <ClCompile Include="..\libcmyth\keyframe.c" />
+ <ClCompile Include="..\libcmyth\livetv.c" />
+ <ClCompile Include="..\libcmyth\mysql_query.c" />
+diff --git a/lib/cmyth/Win32/libcmyth.vcxproj.filters b/lib/cmyth/Win32/libcmyth.vcxproj.filters
+index 0032e92..96b7eb2 100644
+--- a/lib/cmyth/Win32/libcmyth.vcxproj.filters
++++ b/lib/cmyth/Win32/libcmyth.vcxproj.filters
+@@ -31,6 +31,9 @@
+ <ClCompile Include="..\libcmyth\freespace.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
++ <ClCompile Include="..\libcmyth\input.c">
++ <Filter>Source Files</Filter>
++ </ClCompile>
+ <ClCompile Include="..\libcmyth\keyframe.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
diff --git a/lib/cmyth/include/cmyth/cmyth.h b/lib/cmyth/include/cmyth/cmyth.h
-index 52f2f68..090381d 100644
+index 52f2f68..51ea428 100644
--- a/lib/cmyth/include/cmyth/cmyth.h
+++ b/lib/cmyth/include/cmyth/cmyth.h
-@@ -255,7 +255,7 @@ extern cmyth_file_t cmyth_conn_connect_file(cmyth_proginfo_t prog,
+@@ -154,6 +154,23 @@ typedef struct cmyth_chanlist *cmyth_chanlist_t;
+ struct cmyth_tvguide_progs;
+ typedef struct cmyth_tvguide_progs *cmyth_tvguide_progs_t;
+
++/* fetzerch: Added to support querying of free inputs (is tunable on) */
++struct cmyth_input {
++ char *inputname;
++ unsigned long sourceid;
++ unsigned long inputid;
++ unsigned long cardid;
++ unsigned long multiplexid;
++ unsigned long livetvorder; /* new in V71 */
++};
++typedef struct cmyth_input *cmyth_input_t;
++
++struct cmyth_inputlist {
++ cmyth_input_t *input_list;
++ long input_count;
++};
++typedef struct cmyth_inputlist *cmyth_inputlist_t;
++
+ /*
+ * -----------------------------------------------------------------
+ * Debug Output Control
+@@ -255,7 +272,7 @@ extern cmyth_file_t cmyth_conn_connect_file(cmyth_proginfo_t prog,
* \return file handle
*/
extern cmyth_file_t cmyth_conn_connect_path(char* path, cmyth_conn_t control,
@@ -27914,7 +27987,7 @@ index 52f2f68..090381d 100644
/**
* Create a ring buffer connection to a recorder.
-@@ -349,6 +349,30 @@ extern int cmyth_conn_get_protocol_version(cmyth_conn_t conn);
+@@ -349,6 +366,30 @@ extern int cmyth_conn_get_protocol_version(cmyth_conn_t conn);
extern char * cmyth_conn_get_setting(cmyth_conn_t conn,
const char* hostname, const char* setting);
@@ -27945,7 +28018,7 @@ index 52f2f68..090381d 100644
/*
* -----------------------------------------------------------------
* Event Operations
-@@ -524,6 +548,8 @@ extern cmyth_livetv_chain_t cmyth_livetv_chain_create(char * chainid);
+@@ -524,6 +565,8 @@ extern cmyth_livetv_chain_t cmyth_livetv_chain_create(char * chainid);
extern cmyth_file_t cmyth_livetv_get_cur_file(cmyth_recorder_t rec);
@@ -27954,7 +28027,7 @@ index 52f2f68..090381d 100644
extern int cmyth_livetv_chain_switch(cmyth_recorder_t rec, int dir);
extern int cmyth_livetv_chain_switch_last(cmyth_recorder_t rec);
-@@ -573,6 +599,9 @@ extern int cmyth_database_set_user(cmyth_database_t db, char *user);
+@@ -573,6 +616,9 @@ extern int cmyth_database_set_user(cmyth_database_t db, char *user);
extern int cmyth_database_set_pass(cmyth_database_t db, char *pass);
extern int cmyth_database_set_name(cmyth_database_t db, char *name);
@@ -27964,10 +28037,38 @@ index 52f2f68..090381d 100644
/*
* -----------------------------------------------------------------
* Ring Buffer Operations
-@@ -805,6 +834,20 @@ extern char *cmyth_proginfo_seriesid(cmyth_proginfo_t prog);
+@@ -749,6 +795,20 @@ extern char *cmyth_proginfo_subtitle(cmyth_proginfo_t prog);
+ extern char *cmyth_proginfo_description(cmyth_proginfo_t prog);
+
+ /**
++ * Retrieve the season of a program.
++ * \param prog proginfo handle
++ * \return season
++ */
++extern unsigned short cmyth_proginfo_season(cmyth_proginfo_t prog);
++
++/**
++ * Retrieve the episode of a program.
++ * \param prog proginfo handle
++ * \return episode
++ */
++extern unsigned short cmyth_proginfo_episode(cmyth_proginfo_t prog);
++
++/**
+ * Retrieve the category of a program.
+ * \param prog proginfo handle
+ * \return null-terminated string
+@@ -805,6 +865,27 @@ extern char *cmyth_proginfo_seriesid(cmyth_proginfo_t prog);
extern char *cmyth_proginfo_programid(cmyth_proginfo_t prog);
/**
++ * Retrieve the inetref of a program.
++ * \param prog proginfo handle
++ * \return null-terminated string
++ */
++extern char *cmyth_proginfo_inetref(cmyth_proginfo_t prog);
++
++/**
+ * Retrieve the record ID of the matching record rule
+ * \param prog proginfo handle
+ * \return unsigned long
@@ -27985,7 +28086,7 @@ index 52f2f68..090381d 100644
* Retrieve the critics rating (number of stars) of a program.
* \param prog proginfo handle
* \return null-terminated string
-@@ -962,6 +1005,10 @@ extern unsigned long long cmyth_file_start(cmyth_file_t file);
+@@ -962,6 +1043,10 @@ extern unsigned long long cmyth_file_start(cmyth_file_t file);
extern unsigned long long cmyth_file_length(cmyth_file_t file);
@@ -27996,7 +28097,7 @@ index 52f2f68..090381d 100644
extern int cmyth_file_get_block(cmyth_file_t file, char *buf,
unsigned long len);
-@@ -988,6 +1035,10 @@ extern long cmyth_channel_chanid(cmyth_channel_t channel);
+@@ -988,6 +1073,10 @@ extern long cmyth_channel_chanid(cmyth_channel_t channel);
extern long cmyth_channel_channum(cmyth_channel_t channel);
@@ -28007,7 +28108,25 @@ index 52f2f68..090381d 100644
extern char * cmyth_channel_name(cmyth_channel_t channel);
extern char * cmyth_channel_icon(cmyth_channel_t channel);
-@@ -1076,4 +1127,107 @@ extern int cmyth_get_delete_list(cmyth_conn_t, char *, cmyth_proglist_t);
+@@ -1023,6 +1112,17 @@ extern cmyth_commbreaklist_t cmyth_get_cutlist(cmyth_conn_t conn, cmyth_proginfo
+ extern int cmyth_rcv_commbreaklist(cmyth_conn_t conn, int *err, cmyth_commbreaklist_t breaklist, int count);
+
+ /*
++ * -------
++ * Card Input Operations
++ * -------
++ */
++extern cmyth_inputlist_t cmyth_inputlist_create(void);
++extern cmyth_input_t cmyth_input_create(void);
++extern cmyth_inputlist_t cmyth_get_free_inputlist(cmyth_recorder_t rec);
++extern int cmyth_rcv_free_inputlist(cmyth_conn_t conn, int *err, cmyth_inputlist_t inputlist, int count);
++
++
++/*
+ * mysql info
+ */
+
+@@ -1076,4 +1176,107 @@ extern int cmyth_get_delete_list(cmyth_conn_t, char *, cmyth_proglist_t);
extern int cmyth_mythtv_remove_previos_recorded(cmyth_database_t db,char *query);
extern cmyth_chanlist_t cmyth_mysql_get_chanlist(cmyth_database_t db);
@@ -28128,8 +28247,71 @@ index 71d9a6e..9aba22e 100644
: "cc", "memory"
);
#elif defined __i386__
+diff --git a/lib/cmyth/libcmyth/Makefile b/lib/cmyth/libcmyth/Makefile
+index 9b37fbf..a83e872 100644
+--- a/lib/cmyth/libcmyth/Makefile
++++ b/lib/cmyth/libcmyth/Makefile
+@@ -1,6 +1,6 @@
+ INCLUDES=-I. -I../include
+
+-SRCS=bookmark.c commbreak.c connection.c event.c file.c freespace.c keyframe.c livetv.c mysql_query.c mythtv_mysql.c posmap.c proginfo.c proglist.c rec_num.c recorder.c ringbuf.c socket.c timestamp.c debug.c utf8tolatin1.c
++SRCS=bookmark.c commbreak.c connection.c event.c file.c freespace.c input.c keyframe.c livetv.c mysql_query.c mythtv_mysql.c posmap.c proginfo.c proglist.c rec_num.c recorder.c ringbuf.c socket.c timestamp.c debug.c utf8tolatin1.c
+
+ LIB=libcmyth.a
+
+diff --git a/lib/cmyth/libcmyth/bookmark.c b/lib/cmyth/libcmyth/bookmark.c
+index af7580f..4681c21 100644
+--- a/lib/cmyth/libcmyth/bookmark.c
++++ b/lib/cmyth/libcmyth/bookmark.c
+@@ -20,6 +20,7 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
++#include <inttypes.h>
+ #include <errno.h>
+ #include <cmyth_local.h>
+
+@@ -59,7 +60,7 @@ long long cmyth_get_bookmark(cmyth_conn_t conn, cmyth_proginfo_t prog)
+ }
+ if ((r=cmyth_rcv_long_long(conn, &err, &ll, count)) < 0) {
+ cmyth_dbg(CMYTH_DBG_ERROR,
+- "%s: cmyth_rcv_longlong() failed (%d)\n",
++ "%s: cmyth_rcv_long_long() failed (%d)\n",
+ __FUNCTION__, r);
+ ret = err;
+ goto out;
+@@ -74,7 +75,7 @@ long long cmyth_get_bookmark(cmyth_conn_t conn, cmyth_proginfo_t prog)
+ int cmyth_set_bookmark(cmyth_conn_t conn, cmyth_proginfo_t prog, long long bookmark)
+ {
+ char *buf;
+- unsigned int len = CMYTH_TIMESTAMP_LEN + CMYTH_LONGLONG_LEN + 18;
++ unsigned int len = CMYTH_TIMESTAMP_LEN + CMYTH_LONGLONG_LEN * 2 + 18;
+ char resultstr[3];
+ int r,err;
+ int ret;
+@@ -85,8 +86,18 @@ int cmyth_set_bookmark(cmyth_conn_t conn, cmyth_proginfo_t prog, long long bookm
+ if (!buf) {
+ return -ENOMEM;
+ }
+- sprintf(buf,"%s %ld %s %lld %lld","SET_BOOKMARK",prog->proginfo_chanId,
+- start_ts_dt, bookmark >> 32,(bookmark & 0xffffffff));
++ if (conn->conn_version >= 66) {
++ /*
++ * Since protocol 66 mythbackend expects a single 64 bit integer rather than two 32 bit
++ * hi and lo integers.
++ */
++ sprintf(buf, "SET_BOOKMARK %ld %s %"PRIu64, prog->proginfo_chanId,
++ start_ts_dt, (int64_t)bookmark);
++ }
++ else {
++ sprintf(buf, "SET_BOOKMARK %ld %s %d %d", prog->proginfo_chanId,
++ start_ts_dt, (int32_t)(bookmark >> 32), (int32_t)(bookmark & 0xffffffff));
++ }
+ pthread_mutex_lock(&mutex);
+ if ((err = cmyth_send_message(conn,buf)) < 0) {
+ cmyth_dbg(CMYTH_DBG_ERROR,
diff --git a/lib/cmyth/libcmyth/cmyth_local.h b/lib/cmyth/libcmyth/cmyth_local.h
-index 40bed11..5dc56e8 100644
+index 40bed11..f6e4352 100644
--- a/lib/cmyth/libcmyth/cmyth_local.h
+++ b/lib/cmyth/libcmyth/cmyth_local.h
@@ -39,12 +39,16 @@
@@ -28249,8 +28431,25 @@ index 40bed11..5dc56e8 100644
struct cmyth_ringbuf {
cmyth_conn_t conn_data;
long file_id;
+@@ -224,6 +295,8 @@ struct cmyth_proginfo {
+ char *proginfo_title;
+ char *proginfo_subtitle;
+ char *proginfo_description;
++ unsigned short proginfo_season; /* new in V67 */
++ unsigned short proginfo_episode; /* new in V67 */
+ char *proginfo_category;
+ long proginfo_chanId;
+ char *proginfo_chanstr;
+@@ -258,6 +331,7 @@ struct cmyth_proginfo {
+ char *proginfo_chan_output_filters; /* new in V8 */
+ char *proginfo_seriesid; /* new in V8 */
+ char *proginfo_programid; /* new in V12 */
++ char *proginfo_inetref; /* new in V67 */
+ cmyth_timestamp_t proginfo_lastmodified; /* new in V12 */
+ char *proginfo_stars; /* new in V12 */
+ cmyth_timestamp_t proginfo_originalairdate; /* new in V12 */
diff --git a/lib/cmyth/libcmyth/connection.c b/lib/cmyth/libcmyth/connection.c
-index 9d5fb0d..10ff548 100644
+index 9d5fb0d..4b9e27d 100644
--- a/lib/cmyth/libcmyth/connection.c
+++ b/lib/cmyth/libcmyth/connection.c
@@ -44,9 +44,32 @@
@@ -28287,7 +28486,32 @@ index 9d5fb0d..10ff548 100644
typedef struct {
int version;
char token[9]; // 8 characters + the terminating NULL character
-@@ -553,7 +576,7 @@ cmyth_conn_connect_file(cmyth_proginfo_t prog, cmyth_conn_t control,
+@@ -56,6 +79,15 @@ static myth_protomap_t protomap[] = {
+ {62, "78B5631E"},
+ {63, "3875641D"},
+ {64, "8675309J"},
++ {65, "D2BB94C2"},
++ {66, "0C0FFEE0"},
++ {67, "0G0G0G0"},
++ {68, "90094EAD"},
++ {69, "63835135"},
++ {70, "53153836"},
++ {71, "05e82186"},
++ {72, "D78EFD6F"},
++ {73, "D7FE8D6F"},
+ {0, 0}
+ };
+
+@@ -527,7 +559,7 @@ cmyth_conn_connect_file(cmyth_proginfo_t prog, cmyth_conn_t control,
+ int err = 0;
+ int count = 0;
+ int r;
+- int ann_size = sizeof("ANN FileTransfer []:[][]:[]");
++ int ann_size = sizeof("ANN FileTransfer 0[]:[][]:[]");
+ cmyth_file_t ret = NULL;
+
+ if (!prog) {
+@@ -553,7 +585,7 @@ cmyth_conn_connect_file(cmyth_proginfo_t prog, cmyth_conn_t control,
cmyth_dbg(CMYTH_DBG_PROTO, "%s: connecting data connection\n",
__FUNCTION__);
if (control->conn_version >= 17) {
@@ -28296,7 +28520,38 @@ index 9d5fb0d..10ff548 100644
"BackendServerIP");
}
if (!myth_host) {
-@@ -674,7 +697,7 @@ cmyth_conn_connect_file(cmyth_proginfo_t prog, cmyth_conn_t control,
+@@ -575,6 +607,12 @@ cmyth_conn_connect_file(cmyth_proginfo_t prog, cmyth_conn_t control,
+ myth_host, prog->proginfo_port, buflen);
+ goto shut;
+ }
++ /*
++ * Explicitly set the conn version to the control version as cmyth_connect() doesn't and some of
++ * the cmyth_rcv_* functions expect it to be the same as the protocol version used by mythbackend.
++ */
++ conn->conn_version = control->conn_version;
++
+ ann_size += strlen(prog->proginfo_pathname) + strlen(my_hostname);
+ announcement = malloc(ann_size);
+ if (!announcement) {
+@@ -584,7 +622,7 @@ cmyth_conn_connect_file(cmyth_proginfo_t prog, cmyth_conn_t control,
+ goto shut;
+ }
+ if (control->conn_version >= 44) {
+- sprintf(announcement, "ANN FileTransfer %s[]:[]%s[]:[]",
++ sprintf(announcement, "ANN FileTransfer %s 0[]:[]%s[]:[]", // write = false
+ my_hostname, prog->proginfo_pathname);
+ }
+ else {
+@@ -631,7 +669,7 @@ cmyth_conn_connect_file(cmyth_proginfo_t prog, cmyth_conn_t control,
+ r = cmyth_rcv_u_long_long(conn, &err, &ret->file_length, count);
+ if (err) {
+ cmyth_dbg(CMYTH_DBG_ERROR,
+- "%s: (length) cmyth_rcv_longlong() failed (%d)\n",
++ "%s: (length) cmyth_rcv_u_long_long() failed (%d)\n",
+ __FUNCTION__, err);
+ goto shut;
+ }
+@@ -674,7 +712,7 @@ cmyth_conn_connect_file(cmyth_proginfo_t prog, cmyth_conn_t control,
*/
cmyth_file_t
cmyth_conn_connect_path(char* path, cmyth_conn_t control,
@@ -28305,38 +28560,61 @@ index 9d5fb0d..10ff548 100644
{
cmyth_conn_t conn = NULL;
char *announcement = NULL;
-@@ -716,7 +739,8 @@ cmyth_conn_connect_path(char* path, cmyth_conn_t control,
+@@ -683,7 +721,7 @@ cmyth_conn_connect_path(char* path, cmyth_conn_t control,
+ int err = 0;
+ int count = 0;
+ int r, port;
+- int ann_size = sizeof("ANN FileTransfer []:[][]:[]");
++ int ann_size = sizeof("ANN FileTransfer 0[]:[][]:[]");
+ struct sockaddr_in addr;
+ socklen_t addr_size = sizeof(addr);
+ cmyth_file_t ret = NULL;
+@@ -716,18 +754,29 @@ cmyth_conn_connect_path(char* path, cmyth_conn_t control,
__FUNCTION__, host, port, buflen);
goto shut;
}
- ann_size += strlen(path) + strlen(my_hostname);
+- announcement = malloc(ann_size);
+- if (!announcement) {
++ /*
++ * Explicitly set the conn version to the control version as cmyth_connect() doesn't and some of
++ * the cmyth_rcv_* functions expect it to be the same as the protocol version used by mythbackend.
++ */
++ conn->conn_version = control->conn_version;
+
+ ann_size += strlen(path) + strlen(my_hostname) + strlen(sgToGetFrom) + 6;
- announcement = malloc(ann_size);
- if (!announcement) {
++ announcement = malloc(ann_size); if (!announcement) {
cmyth_dbg(CMYTH_DBG_ERROR,
-@@ -724,10 +748,16 @@ cmyth_conn_connect_path(char* path, cmyth_conn_t control,
+ "%s: malloc(%d) failed for announcement\n",
__FUNCTION__, ann_size);
goto shut;
}
- if (control->conn_version >= 44) {
- sprintf(announcement, "ANN FileTransfer %s[]:[]%s[]:[]",
-- my_hostname, path);
-- }
+ if (control->conn_version >= 44) { /*TSP: from version 44 according to the source code*/
+ if (strlen(sgToGetFrom) > 1) {
+ sprintf(announcement, "ANN FileTransfer %s 0 0 0[]:[]%s[]:[]%s",
+ my_hostname, path, sgToGetFrom);
+ }
+ else {
-+ sprintf(announcement, "ANN FileTransfer %s[]:[]%s[]:[]",
-+ my_hostname, path);
++ sprintf(announcement, "ANN FileTransfer %s 0[]:[]%s[]:[]", // write = false
+ my_hostname, path);
+- }
+ }
+ }
else {
sprintf(announcement, "ANN FileTransfer %s[]:[]%s",
my_hostname, path);
-@@ -1287,6 +1317,8 @@ cmyth_conn_get_protocol_version(cmyth_conn_t conn)
+@@ -771,7 +820,7 @@ cmyth_conn_connect_path(char* path, cmyth_conn_t control,
+ r = cmyth_rcv_u_long_long(conn, &err, &ret->file_length, count);
+ if (err) {
+ cmyth_dbg(CMYTH_DBG_ERROR,
+- "%s: (length) cmyth_rcv_longlong() failed (%d)\n",
++ "%s: (length) cmyth_rcv_u_long_long() failed (%d)\n",
+ __FUNCTION__, err);
+ goto shut;
+ }
+@@ -1287,6 +1336,8 @@ cmyth_conn_get_protocol_version(cmyth_conn_t conn)
}
@@ -28345,7 +28623,7 @@ index 9d5fb0d..10ff548 100644
int
cmyth_conn_get_free_recorder_count(cmyth_conn_t conn)
{
-@@ -1347,6 +1379,93 @@ cmyth_conn_get_setting(cmyth_conn_t conn, const char* hostname, const char* sett
+@@ -1347,6 +1398,93 @@ cmyth_conn_get_setting(cmyth_conn_t conn, const char* hostname, const char* sett
return result;
}
@@ -28439,7 +28717,7 @@ index 9d5fb0d..10ff548 100644
static char *
cmyth_conn_get_setting_unlocked(cmyth_conn_t conn, const char* hostname, const char* setting)
{
-@@ -1398,6 +1517,12 @@ cmyth_conn_get_setting_unlocked(cmyth_conn_t conn, const char* hostname, const c
+@@ -1398,6 +1536,12 @@ cmyth_conn_get_setting_unlocked(cmyth_conn_t conn, const char* hostname, const c
cmyth_dbg(CMYTH_DBG_ERROR, "%s: odd left over data %s\n", __FUNCTION__, buffer);
}
@@ -28452,7 +28730,7 @@ index 9d5fb0d..10ff548 100644
return result;
err:
if(result)
-@@ -1406,3 +1531,37 @@ err:
+@@ -1406,3 +1550,37 @@ err:
return NULL;
}
@@ -28491,16 +28769,19 @@ index 9d5fb0d..10ff548 100644
+ return 1;
+}
diff --git a/lib/cmyth/libcmyth/event.c b/lib/cmyth/libcmyth/event.c
-index f340ac6..9404d45 100644
+index f340ac6..f45682f 100644
--- a/lib/cmyth/libcmyth/event.c
+++ b/lib/cmyth/libcmyth/event.c
-@@ -88,16 +88,24 @@ cmyth_event_get(cmyth_conn_t conn, char * data, int len)
+@@ -88,16 +88,27 @@ cmyth_event_get(cmyth_conn_t conn, char * data, int len)
event = CMYTH_EVENT_LIVETV_CHAIN_UPDATE;
strncpy(data, tmp + 20, len);
} else if (strncmp(tmp, "SIGNAL", 6) == 0) {
+ int dstlen=len;
event = CMYTH_EVENT_SIGNAL;
-+
++ /*Get Recorder ID */
++ strncat(data,"cardid ",7);
++ strncat(data,tmp+7,consumed-12);
++ strncat(data,";",2);
/* get slock, signal, seen_pat, matching_pat */
- while (count > 0) {
- /* get signalmonitorvalue name */
@@ -28522,7 +28803,7 @@ index f340ac6..9404d45 100644
}
} else if (strncmp(tmp, "ASK_RECORDING", 13) == 0) {
event = CMYTH_EVENT_ASK_RECORDING;
-@@ -164,8 +172,8 @@ cmyth_event_select(cmyth_conn_t conn, struct timeval *timeout)
+@@ -164,8 +175,8 @@ cmyth_event_select(cmyth_conn_t conn, struct timeval *timeout)
int ret;
cmyth_socket_t fd;
@@ -28533,7 +28814,7 @@ index f340ac6..9404d45 100644
if (conn == NULL)
return -EINVAL;
-@@ -177,8 +185,8 @@ cmyth_event_select(cmyth_conn_t conn, struct timeval *timeout)
+@@ -177,8 +188,8 @@ cmyth_event_select(cmyth_conn_t conn, struct timeval *timeout)
ret = select((int)fd+1, &fds, NULL, NULL, timeout);
@@ -28545,10 +28826,18 @@ index f340ac6..9404d45 100644
return ret;
}
diff --git a/lib/cmyth/libcmyth/file.c b/lib/cmyth/libcmyth/file.c
-index 74408ed..5379f99 100644
+index 74408ed..32c8876 100644
--- a/lib/cmyth/libcmyth/file.c
+++ b/lib/cmyth/libcmyth/file.c
-@@ -254,6 +254,56 @@ cmyth_file_length(cmyth_file_t file)
+@@ -20,6 +20,7 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <errno.h>
++#include <inttypes.h>
+ #ifndef _MSC_VER
+ #include <sys/socket.h>
+ #endif
+@@ -254,6 +255,56 @@ cmyth_file_length(cmyth_file_t file)
}
/*
@@ -28605,47 +28894,32 @@ index 74408ed..5379f99 100644
* cmyth_file_get_block(cmyth_file_t file, char *buf, unsigned long len)
*
* Scope: PUBLIC
-@@ -505,6 +555,89 @@ cmyth_file_seek(cmyth_file_t file, long long offset, int whence)
- return ret;
- }
+@@ -449,6 +500,105 @@ cmyth_file_seek(cmyth_file_t file, long long offset, int whence)
-+long long
-+cmyth_file_seek_unlocked(cmyth_file_t file, long long offset, int whence)
-+{
-+ char msg[128];
-+ int err;
-+ int count;
-+ long long c;
-+ long r;
-+ long long ret;
-+
-+ if (file == NULL)
-+ return -EINVAL;
-+
-+ if ((offset == 0) && (whence == SEEK_CUR))
-+ return file->file_pos;
-+
-+ if ((offset == file->file_pos) && (whence == SEEK_SET))
-+ return file->file_pos;
-+
-+ while(file->file_pos < file->file_req) {
-+ c = file->file_req - file->file_pos;
-+ if(c > sizeof(msg))
-+ c = sizeof(msg);
-+
-+ if (cmyth_file_get_block(file, msg, (unsigned long)c) < 0)
-+ return -1;
+ pthread_mutex_lock(&mutex);
+
++ if (file->file_control->conn_version >= 66) {
++ /*
++ * Since protocol 66 mythbackend expects to receive a single 64 bit integer rather than
++ * two 32 bit hi and lo integers.
++ */
++ snprintf(msg, sizeof(msg),
++ "QUERY_FILETRANSFER %ld[]:[]SEEK[]:[]%"PRIu64"[]:[]%d[]:[]%"PRIu64,
++ file->file_id,
++ (int64_t)offset,
++ whence,
++ (int64_t)file->file_pos);
++ }
++ else {
++ snprintf(msg, sizeof(msg),
++ "QUERY_FILETRANSFER %ld[]:[]SEEK[]:[]%d[]:[]%d[]:[]%d[]:[]%d[]:[]%d",
++ file->file_id,
++ (int32_t)(offset >> 32),
++ (int32_t)(offset & 0xffffffff),
++ whence,
++ (int32_t)(file->file_pos >> 32),
++ (int32_t)(file->file_pos & 0xffffffff));
+ }
-+
-+
-+ snprintf(msg, sizeof(msg),
-+ "QUERY_FILETRANSFER %ld[]:[]SEEK[]:[]%d[]:[]%d[]:[]%d[]:[]%d[]:[]%d",
-+ file->file_id,
-+ (int32_t)(offset >> 32),
-+ (int32_t)(offset & 0xffffffff),
-+ whence,
-+ (int32_t)(file->file_pos >> 32),
-+ (int32_t)(file->file_pos & 0xffffffff));
+
+ if ((err = cmyth_send_message(file->file_control, msg)) < 0) {
+ cmyth_dbg(CMYTH_DBG_ERROR,
@@ -28689,12 +28963,296 @@ index 74408ed..5379f99 100644
+ ret = file->file_pos;
+
+ out:
++ pthread_mutex_unlock(&mutex);
+
+ return ret;
+}
++
++long long
++cmyth_file_seek_unlocked(cmyth_file_t file, long long offset, int whence)
++{
++ char msg[128];
++ int err;
++ int count;
++ long long c;
++ long r;
++ long long ret;
++
++ if (file == NULL)
++ return -EINVAL;
++
++ if ((offset == 0) && (whence == SEEK_CUR))
++ return file->file_pos;
++
++ if ((offset == file->file_pos) && (whence == SEEK_SET))
++ return file->file_pos;
++
++ while(file->file_pos < file->file_req) {
++ c = file->file_req - file->file_pos;
++ if(c > sizeof(msg))
++ c = sizeof(msg);
++
++ if (cmyth_file_get_block(file, msg, (unsigned long)c) < 0)
++ return -1;
++ }
++
++
+ snprintf(msg, sizeof(msg),
+ "QUERY_FILETRANSFER %ld[]:[]SEEK[]:[]%d[]:[]%d[]:[]%d[]:[]%d[]:[]%d",
+ file->file_id,
+@@ -500,11 +650,9 @@ cmyth_file_seek(cmyth_file_t file, long long offset, int whence)
+ ret = file->file_pos;
+
+ out:
+- pthread_mutex_unlock(&mutex);
+
+ return ret;
+ }
+-
/*
* cmyth_file_read(cmyth_recorder_t rec, char *buf, unsigned long len)
*
+diff --git a/lib/cmyth/libcmyth/input.c b/lib/cmyth/libcmyth/input.c
+new file mode 100644
+index 0000000..b9bda31
+--- /dev/null
++++ b/lib/cmyth/libcmyth/input.c
+@@ -0,0 +1,235 @@
++/*
++ * Copyright (C) 2012, Christian Fetzer
++ * http://www.mvpmc.org/
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * This library 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
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <errno.h>
++#include <cmyth_local.h>
++
++static void
++cmyth_inputlist_destroy(cmyth_inputlist_t il)
++{
++ int i;
++
++ cmyth_dbg(CMYTH_DBG_DEBUG, "%s\n", __FUNCTION__);
++ if (!il) {
++ return;
++ }
++ for (i = 0; i < il->input_count; ++i) {
++ if (il->input_list[i]) {
++ ref_release(il->input_list[i]);
++ }
++ il->input_list[i] = NULL;
++ }
++ if (il->input_list) {
++ free(il->input_list);
++ }
++}
++
++cmyth_inputlist_t
++cmyth_inputlist_create(void)
++{
++ cmyth_inputlist_t ret;
++
++ cmyth_dbg(CMYTH_DBG_DEBUG, "%s\n", __FUNCTION__);
++ ret = ref_alloc(sizeof(*ret));
++ if (!ret) {
++ return(NULL);
++ }
++ ref_set_destroy(ret, (ref_destroy_t)cmyth_inputlist_destroy);
++
++ ret->input_list = NULL;
++ ret->input_count = 0;
++ return ret;
++}
++
++void
++cmyth_input_destroy(cmyth_input_t i)
++{
++ cmyth_dbg(CMYTH_DBG_DEBUG, "%s {\n", __FUNCTION__);
++ if (!i) {
++ cmyth_dbg(CMYTH_DBG_DEBUG, "%s }!a\n", __FUNCTION__);
++ return;
++ }
++ cmyth_dbg(CMYTH_DBG_DEBUG, "%s }\n", __FUNCTION__);
++
++ if (i->inputname) {
++ ref_release(i->inputname);
++ }
++}
++
++cmyth_input_t
++cmyth_input_create(void)
++{
++ cmyth_input_t ret = ref_alloc(sizeof(*ret));
++
++ cmyth_dbg(CMYTH_DBG_DEBUG, "%s {\n", __FUNCTION__);
++ if (!ret) {
++ cmyth_dbg(CMYTH_DBG_DEBUG, "%s }!\n", __FUNCTION__);
++ return NULL;
++ }
++ ref_set_destroy(ret, (ref_destroy_t)cmyth_input_destroy);
++
++ ret->inputname = NULL;
++ ret->sourceid = 0;
++ ret->inputid = 0;
++ ret->cardid = 0;
++ ret->multiplexid = 0;
++
++ cmyth_dbg(CMYTH_DBG_DEBUG, "%s }\n", __FUNCTION__);
++ return ret;
++}
++
++cmyth_inputlist_t
++cmyth_get_free_inputlist(cmyth_recorder_t rec)
++{
++ unsigned int len = CMYTH_LONGLONG_LEN + 36;
++ int err;
++ int count;
++ char *buf;
++ int r;
++
++ cmyth_inputlist_t inputlist = cmyth_inputlist_create();
++
++ buf = alloca(len);
++ if (!buf) {
++ return inputlist;
++ }
++
++ sprintf(buf,"QUERY_RECORDER %d[]:[]GET_FREE_INPUTS", rec->rec_id);
++ pthread_mutex_lock(&mutex);
++ if ((err = cmyth_send_message(rec->rec_conn, buf)) < 0) {
++ cmyth_dbg(CMYTH_DBG_ERROR,
++ "%s: cmyth_send_message() failed (%d)\n",
++ __FUNCTION__, err);
++ goto out;
++ }
++
++ count = cmyth_rcv_length(rec->rec_conn);
++ if (count < 0) {
++ cmyth_dbg(CMYTH_DBG_ERROR,
++ "%s: cmyth_rcv_length() failed (%d)\n",
++ __FUNCTION__, count);
++ goto out;
++ }
++
++ if ((r = cmyth_rcv_free_inputlist(rec->rec_conn, &err, inputlist, count)) < 0) {
++ cmyth_dbg(CMYTH_DBG_ERROR,
++ "%s: cmyth_rcv_string() failed (%d)\n",
++ __FUNCTION__, r);
++ goto out;
++ }
++
++ out:
++ pthread_mutex_unlock(&mutex);
++ return inputlist;
++}
++
++int cmyth_rcv_free_inputlist(cmyth_conn_t conn, int *err,
++ cmyth_inputlist_t inputlist, int count)
++{
++ int consumed;
++ int total = 0;
++ char *failed = NULL;
++ cmyth_input_t input;
++ char inputname[100];
++ unsigned long sourceid;
++ unsigned long inputid;
++ unsigned long cardid;
++ unsigned long multiplexid;
++ unsigned long livetvorder;
++
++ if (count <= 0) {
++ *err = EINVAL;
++ return 0;
++ }
++
++ while (count) {
++ consumed = cmyth_rcv_string(conn, err, inputname, sizeof(inputname)-1, count);
++ inputname[sizeof(inputname)-1] = 0;
++ count -= consumed;
++ total += consumed;
++ if (*err) {
++ failed = "cmyth_rcv_string";
++ goto fail;
++ }
++
++ consumed = cmyth_rcv_ulong(conn, err, &sourceid, count);
++ count -= consumed;
++ total += consumed;
++ if (*err) {
++ failed = "cmyth_rcv_ulong";
++ goto fail;
++ }
++
++ consumed = cmyth_rcv_ulong(conn, err, &inputid, count);
++ count -= consumed;
++ total += consumed;
++ if (*err) {
++ failed = "cmyth_rcv_ulong";
++ goto fail;
++ }
++
++ consumed = cmyth_rcv_ulong(conn, err, &cardid, count);
++ count -= consumed;
++ total += consumed;
++ if (*err) {
++ failed = "cmyth_rcv_ulong";
++ goto fail;
++ }
++
++ consumed = cmyth_rcv_ulong(conn, err, &multiplexid, count);
++ count -= consumed;
++ total += consumed;
++ if (*err) {
++ failed = "cmyth_rcv_ulong";
++ goto fail;
++ }
++
++ if (conn->conn_version >= 71) {
++ consumed = cmyth_rcv_ulong(conn, err, &livetvorder, count);
++ count -= consumed;
++ total += consumed;
++ if (*err) {
++ failed = "cmyth_rcv_ulong";
++ goto fail;
++ }
++ }
++
++ input = cmyth_input_create();
++ input->inputname = ref_strdup(inputname);
++ input->sourceid = sourceid;
++ input->inputid = inputid;
++ input->cardid = cardid;
++ input->multiplexid = multiplexid;
++ input->livetvorder = livetvorder;
++
++ inputlist->input_list = realloc(inputlist->input_list,
++ (++inputlist->input_count) * sizeof(cmyth_input_t));
++ inputlist->input_list[inputlist->input_count - 1] = input;
++ }
++
++ return total;
++
++ fail:
++ cmyth_dbg(CMYTH_DBG_ERROR, "%s: %s() failed (%d)\n",
++ __FUNCTION__, failed, *err);
++ return total;
++}
diff --git a/lib/cmyth/libcmyth/livetv.c b/lib/cmyth/libcmyth/livetv.c
index 96e50a2..2cb67a2 100644
--- a/lib/cmyth/libcmyth/livetv.c
@@ -28779,7 +29337,7 @@ index 6370e13..7cb7d4e 100644
}
+
diff --git a/lib/cmyth/libcmyth/mythtv_mysql.c b/lib/cmyth/libcmyth/mythtv_mysql.c
-index 3ff23fa..75bf485 100644
+index 3ff23fa..c593b43 100644
--- a/lib/cmyth/libcmyth/mythtv_mysql.c
+++ b/lib/cmyth/libcmyth/mythtv_mysql.c
@@ -57,12 +57,21 @@ cmyth_database_close(cmyth_database_t db)
@@ -28897,6 +29455,15 @@ index 3ff23fa..75bf485 100644
{
cmyth_dbg(CMYTH_DBG_ERROR,"%s, binding of query parameters failed! Maybe we're out of memory?\n", __FUNCTION__);
ref_release(query);
+@@ -936,7 +1013,7 @@ cmyth_mythtv_remove_previos_recorded(cmyth_database_t db,char *query)
+
+ int
+ cmyth_mysql_testdb_connection(cmyth_database_t db,char **message) {
+- char *buf=malloc(sizeof(char)*1001);
++ char *buf=ref_alloc(sizeof(char)*1001);
+ int new_conn = 0;
+ if (db->mysql != NULL) {
+ if (mysql_stat(db->mysql) == NULL) {
@@ -1052,7 +1129,7 @@ cmyth_channel_destroy(cmyth_channel_t pl)
if(pl->callsign)
ref_release(pl->callsign);
@@ -30053,10 +30620,180 @@ index 3ff23fa..75bf485 100644
+}
\ No newline at end of file
diff --git a/lib/cmyth/libcmyth/proginfo.c b/lib/cmyth/libcmyth/proginfo.c
-index b175637..b94a7e8 100644
+index b175637..112329a 100644
--- a/lib/cmyth/libcmyth/proginfo.c
+++ b/lib/cmyth/libcmyth/proginfo.c
-@@ -1526,7 +1526,7 @@ cmyth_proginfo_t
+@@ -116,6 +116,9 @@ cmyth_proginfo_destroy(cmyth_proginfo_t p)
+ if (p->proginfo_programid) {
+ ref_release(p->proginfo_programid);
+ }
++ if (p->proginfo_inetref) {
++ ref_release(p->proginfo_inetref);
++ }
+ if (p->proginfo_stars) {
+ ref_release(p->proginfo_stars);
+ }
+@@ -217,6 +220,8 @@ cmyth_proginfo_create(void)
+ ret->proginfo_title = NULL;
+ ret->proginfo_subtitle = NULL;
+ ret->proginfo_description = NULL;
++ ret->proginfo_season = 0;
++ ret->proginfo_episode = 0;
+ ret->proginfo_category = NULL;
+ ret->proginfo_chanId = 0;
+ ret->proginfo_chanstr = NULL;
+@@ -250,6 +255,7 @@ cmyth_proginfo_create(void)
+ ret->proginfo_chan_output_filters = NULL;
+ ret->proginfo_seriesid = NULL;
+ ret->proginfo_programid = NULL;
++ ret->proginfo_inetref = NULL;
+ ret->proginfo_stars = NULL;
+ ret->proginfo_version = 12;
+ ret->proginfo_hasairdate = 0;
+@@ -307,6 +313,8 @@ cmyth_proginfo_dup(cmyth_proginfo_t p)
+ ret->proginfo_title = ref_hold(p->proginfo_title);
+ ret->proginfo_subtitle = ref_hold(p->proginfo_subtitle);
+ ret->proginfo_description = ref_hold(p->proginfo_description);
++ ret->proginfo_season = p->proginfo_season;
++ ret->proginfo_episode = p->proginfo_episode;
+ ret->proginfo_category = ref_hold(p->proginfo_category);
+ ret->proginfo_chanId = p->proginfo_chanId;
+ ret->proginfo_chanstr = ref_hold(p->proginfo_chanstr);
+@@ -340,6 +348,7 @@ cmyth_proginfo_dup(cmyth_proginfo_t p)
+ ret->proginfo_chan_output_filters = ref_hold(p->proginfo_chan_output_filters);
+ ret->proginfo_seriesid = ref_hold(p->proginfo_seriesid);
+ ret->proginfo_programid = ref_hold(p->proginfo_programid);
++ ret->proginfo_inetref = ref_hold(p->proginfo_inetref);
+ ret->proginfo_stars = ref_hold(p->proginfo_stars);
+ ret->proginfo_version = p->proginfo_version;
+ ret->proginfo_hasairdate = p->proginfo_hasairdate;
+@@ -386,7 +395,7 @@ delete_command(cmyth_conn_t control, cmyth_proginfo_t prog, char *cmd)
+ char *buf;
+ unsigned int len = ((2 * CMYTH_LONGLONG_LEN) +
+ (6 * CMYTH_TIMESTAMP_LEN) +
+- (14 * CMYTH_LONG_LEN));
++ (16 * CMYTH_LONG_LEN));
+ char start_ts[CMYTH_TIMESTAMP_LEN + 1];
+ char end_ts[CMYTH_TIMESTAMP_LEN + 1];
+ char rec_start_ts[CMYTH_TIMESTAMP_LEN + 1];
+@@ -415,8 +424,12 @@ delete_command(cmyth_conn_t control, cmyth_proginfo_t prog, char *cmd)
+ len += strlen(S(prog->proginfo_url));
+ len += strlen(S(prog->proginfo_hostname));
+ len += strlen(S(prog->proginfo_playgroup));
++ len += strlen(S(prog->proginfo_seriesid));
++ len += strlen(S(prog->proginfo_programid));
++ len += strlen(S(prog->proginfo_inetref));
+ len += strlen(S(prog->proginfo_recpriority_2));
+ len += strlen(S(prog->proginfo_storagegroup));
++ len += strlen(S(prog->proginfo_prodyear));
+
+ buf = alloca(len + 1+2048);
+ if (!buf) {
+@@ -462,6 +475,10 @@ delete_command(cmyth_conn_t control, cmyth_proginfo_t prog, char *cmd)
+ sprintf(buf + strlen(buf), "%s[]:[]", S(prog->proginfo_title));
+ sprintf(buf + strlen(buf), "%s[]:[]", S(prog->proginfo_subtitle));
+ sprintf(buf + strlen(buf), "%s[]:[]", S(prog->proginfo_description));
++ if (control->conn_version >= 67) {
++ sprintf(buf + strlen(buf), "%u[]:[]", prog->proginfo_season);
++ sprintf(buf + strlen(buf), "%u[]:[]", prog->proginfo_episode);
++ }
+ sprintf(buf + strlen(buf), "%s[]:[]", S(prog->proginfo_category));
+ sprintf(buf + strlen(buf), "%ld[]:[]", prog->proginfo_chanId);
+ sprintf(buf + strlen(buf), "%s[]:[]", S(prog->proginfo_chanstr));
+@@ -504,6 +521,9 @@ delete_command(cmyth_conn_t control, cmyth_proginfo_t prog, char *cmd)
+ sprintf(buf + strlen(buf), "%s[]:[]", S(prog->proginfo_chan_output_filters));
+ sprintf(buf + strlen(buf), "%s[]:[]", S(prog->proginfo_seriesid));
+ sprintf(buf + strlen(buf), "%s[]:[]", S(prog->proginfo_programid));
++ if (control->conn_version >= 67) {
++ sprintf(buf + strlen(buf), "%s[]:[]", S(prog->proginfo_inetref));
++ }
+ sprintf(buf + strlen(buf), "%s[]:[]", lastmodified);
+ sprintf(buf + strlen(buf), "%s[]:[]", S(prog->proginfo_stars));
+ sprintf(buf + strlen(buf), "%s[]:[]", originalairdate);
+@@ -773,6 +793,24 @@ cmyth_proginfo_description(cmyth_proginfo_t prog)
+ return ref_hold(prog->proginfo_description);
+ }
+
++unsigned short
++cmyth_proginfo_season(cmyth_proginfo_t prog)
++{
++ if (!prog) {
++ return 0;
++ }
++ return prog->proginfo_season;
++}
++
++unsigned short
++cmyth_proginfo_episode(cmyth_proginfo_t prog)
++{
++ if (!prog) {
++ return 0;
++ }
++ return prog->proginfo_episode;
++}
++
+ /*
+ * cmyth_proginfo_category(cmyth_proginfo_t prog)
+ *
+@@ -827,6 +865,17 @@ cmyth_proginfo_programid(cmyth_proginfo_t prog)
+ }
+
+ char *
++cmyth_proginfo_inetref(cmyth_proginfo_t prog)
++{
++ if (!prog) {
++ cmyth_dbg(CMYTH_DBG_ERROR, "%s: NULL inetref\n",
++ __FUNCTION__);
++ return NULL;
++ }
++ return ref_hold(prog->proginfo_inetref);
++}
++
++char *
+ cmyth_proginfo_stars(cmyth_proginfo_t prog)
+ {
+ if (!prog) {
+@@ -1260,7 +1309,7 @@ fill_command(cmyth_conn_t control, cmyth_proginfo_t prog, char *cmd)
+ char *buf;
+ unsigned int len = ((2 * CMYTH_LONGLONG_LEN) +
+ (6 * CMYTH_TIMESTAMP_LEN) +
+- (14 * CMYTH_LONG_LEN));
++ (16 * CMYTH_LONG_LEN));
+ char start_ts[CMYTH_TIMESTAMP_LEN + 1];
+ char end_ts[CMYTH_TIMESTAMP_LEN + 1];
+ char rec_start_ts[CMYTH_TIMESTAMP_LEN + 1];
+@@ -1288,6 +1337,9 @@ fill_command(cmyth_conn_t control, cmyth_proginfo_t prog, char *cmd)
+ len += strlen(S(prog->proginfo_url));
+ len += strlen(S(prog->proginfo_hostname));
+ len += strlen(S(prog->proginfo_playgroup));
++ len += strlen(S(prog->proginfo_seriesid));
++ len += strlen(S(prog->proginfo_programid));
++ len += strlen(S(prog->proginfo_inetref));
+ len += strlen(S(prog->proginfo_recpriority_2));
+ len += strlen(S(prog->proginfo_storagegroup));
+ len += strlen(S(prog->proginfo_prodyear));
+@@ -1336,6 +1388,10 @@ fill_command(cmyth_conn_t control, cmyth_proginfo_t prog, char *cmd)
+ sprintf(buf + strlen(buf), "%s[]:[]", S(prog->proginfo_title));
+ sprintf(buf + strlen(buf), "%s[]:[]", S(prog->proginfo_subtitle));
+ sprintf(buf + strlen(buf), "%s[]:[]", S(prog->proginfo_description));
++ if (control->conn_version >= 67) {
++ sprintf(buf + strlen(buf), "%u[]:[]", prog->proginfo_season);
++ sprintf(buf + strlen(buf), "%u[]:[]", prog->proginfo_episode);
++ }
+ sprintf(buf + strlen(buf), "%s[]:[]", S(prog->proginfo_category));
+ sprintf(buf + strlen(buf), "%ld[]:[]", prog->proginfo_chanId);
+ sprintf(buf + strlen(buf), "%s[]:[]", S(prog->proginfo_chanstr));
+@@ -1378,6 +1434,9 @@ fill_command(cmyth_conn_t control, cmyth_proginfo_t prog, char *cmd)
+ sprintf(buf + strlen(buf), "%s[]:[]", S(prog->proginfo_chan_output_filters));
+ sprintf(buf + strlen(buf), "%s[]:[]", S(prog->proginfo_seriesid));
+ sprintf(buf + strlen(buf), "%s[]:[]", S(prog->proginfo_programid));
++ if (control->conn_version >= 67) {
++ sprintf(buf + strlen(buf), "%s[]:[]", S(prog->proginfo_inetref));
++ }
+ sprintf(buf + strlen(buf), "%s[]:[]", lastmodified);
+ sprintf(buf + strlen(buf), "%s[]:[]", S(prog->proginfo_stars));
+ sprintf(buf + strlen(buf), "%s[]:[]", originalairdate);
+@@ -1526,7 +1585,7 @@ cmyth_proginfo_t
cmyth_proginfo_get_detail(cmyth_conn_t control, cmyth_proginfo_t p)
{
cmyth_proginfo_t ret = cmyth_proginfo_dup(p);
@@ -30065,7 +30802,7 @@ index b175637..b94a7e8 100644
if (ret == NULL) {
cmyth_dbg(CMYTH_DBG_ERROR,
"%s: cmyth_proginfo_dup() failed\n",
-@@ -1540,7 +1540,7 @@ cmyth_proginfo_get_detail(cmyth_conn_t control, cmyth_proginfo_t p)
+@@ -1540,7 +1599,7 @@ cmyth_proginfo_get_detail(cmyth_conn_t control, cmyth_proginfo_t p)
__FUNCTION__);
return NULL;
}
@@ -30074,7 +30811,7 @@ index b175637..b94a7e8 100644
}
/*
-@@ -1636,6 +1636,30 @@ cmyth_proginfo_card_id(cmyth_proginfo_t prog)
+@@ -1636,6 +1695,30 @@ cmyth_proginfo_card_id(cmyth_proginfo_t prog)
return prog->proginfo_card_id;
}
@@ -30106,7 +30843,7 @@ index b175637..b94a7e8 100644
cmyth_proginfo_recgroup(cmyth_proginfo_t prog)
{
diff --git a/lib/cmyth/libcmyth/proglist.c b/lib/cmyth/libcmyth/proglist.c
-index 28e742c..fdc7861 100644
+index 28e742c..8d5ff6d 100644
--- a/lib/cmyth/libcmyth/proglist.c
+++ b/lib/cmyth/libcmyth/proglist.c
@@ -33,6 +33,356 @@
@@ -30466,8 +31203,32 @@ index 28e742c..fdc7861 100644
/*
* cmyth_proglist_destroy(void)
*
+@@ -315,6 +665,7 @@ cmyth_proglist_get_list(cmyth_conn_t conn,
+ cmyth_proglist_t
+ cmyth_proglist_get_all_recorded(cmyth_conn_t control)
+ {
++ char query[32];
+ cmyth_proglist_t proglist = cmyth_proglist_create();
+
+ if (proglist == NULL) {
+@@ -324,8 +675,14 @@ cmyth_proglist_get_all_recorded(cmyth_conn_t control)
+ return NULL;
+ }
+
++ if (control->conn_version < 65) {
++ strcpy(query, "QUERY_RECORDINGS Play");
++ }
++ else {
++ strcpy(query, "QUERY_RECORDINGS Ascending");
++ }
+ if (cmyth_proglist_get_list(control, proglist,
+- "QUERY_RECORDINGS Play",
++ query,
+ __FUNCTION__) < 0) {
+ cmyth_dbg(CMYTH_DBG_ERROR,
+ "%s: cmyth_proglist_get_list() failed\n",
diff --git a/lib/cmyth/libcmyth/socket.c b/lib/cmyth/libcmyth/socket.c
-index f1f9a45..4555860 100644
+index f1f9a45..c3f1326 100644
--- a/lib/cmyth/libcmyth/socket.c
+++ b/lib/cmyth/libcmyth/socket.c
@@ -148,6 +148,7 @@ cmyth_rcv_length(cmyth_conn_t conn)
@@ -30488,7 +31249,210 @@ index f1f9a45..4555860 100644
continue;
} else if (r > 0) {
conn->conn_hang = 0;
-
+@@ -882,23 +886,38 @@ cmyth_rcv_long_long(cmyth_conn_t conn, int *err, long long *buf, int count)
+ *err = EINVAL;
+ return 0;
+ }
+- consumed = cmyth_rcv_u_long(conn, err, &hi, count);
+- if (*err) {
+- cmyth_dbg(CMYTH_DBG_ERROR,
+- "%s: cmyth_rcv_long_long() failed (%d)\n",
+- __FUNCTION__, consumed);
+- return consumed;
++
++ if (conn->conn_version >= 66) {
++ /*
++ * Since protocol 66 mythbackend now sends a single 64 bit integer rather than two hi and lo
++ * 32 bit integers for ALL 64 bit values.
++ */
++ consumed = cmyth_rcv_int64(conn, err, &val, count);
++ if (*err) {
++ cmyth_dbg(CMYTH_DBG_ERROR,
++ "%s: cmyth_rcv_int64() failed (%d)\n",
++ __FUNCTION__, consumed);
++ return consumed;
++ }
+ }
+- consumed += cmyth_rcv_u_long(conn, err, &lo, count-consumed);
+- if (*err) {
+- cmyth_dbg(CMYTH_DBG_ERROR,
+- "%s: cmyth_rcv_long_long() failed (%d)\n",
+- __FUNCTION__, consumed);
+- return consumed;
++ else {
++ consumed = cmyth_rcv_u_long(conn, err, &hi, count);
++ if (*err) {
++ cmyth_dbg(CMYTH_DBG_ERROR,
++ "%s: cmyth_rcv_u_long_long() failed (%d)\n",
++ __FUNCTION__, consumed);
++ return consumed;
++ }
++ consumed += cmyth_rcv_u_long(conn, err, &lo, count-consumed);
++ if (*err) {
++ cmyth_dbg(CMYTH_DBG_ERROR,
++ "%s: cmyth_rcv_u_long_long() failed (%d)\n",
++ __FUNCTION__, consumed);
++ return consumed;
++ }
++ val = (((long long)hi) << 32) | ((long long)(lo & 0xFFFFFFFF));
+ }
+
+- val = (((long long)hi) << 32) | ((long long)(lo & 0xFFFFFFFF));
+-
+ *err = 0;
+ *buf = val;
+
+@@ -1172,6 +1191,7 @@ cmyth_rcv_ulong_long(cmyth_conn_t conn, int *err,
+ unsigned long long *buf, int count)
+ {
+ unsigned long long val;
++ long long val64;
+ unsigned long hi, lo;
+ int consumed;
+ int tmp;
+@@ -1186,23 +1206,45 @@ cmyth_rcv_ulong_long(cmyth_conn_t conn, int *err,
+ *err = EINVAL;
+ return 0;
+ }
+- consumed = cmyth_rcv_u_long(conn, err, &hi, count);
+- if (*err) {
+- cmyth_dbg(CMYTH_DBG_ERROR,
+- "%s: cmyth_rcv_ulong_long() failed (%d)\n",
+- __FUNCTION__, consumed);
+- return consumed;
++
++ if (conn->conn_version >= 66) {
++ /*
++ * Since protocol 66 mythbackend now sends a single 64 bit integer rather than two hi and lo
++ * 32 bit integers for ALL 64 bit values.
++ */
++ consumed = cmyth_rcv_int64(conn, err, &val64, count);
++ if (*err) {
++ cmyth_dbg(CMYTH_DBG_ERROR,
++ "%s: cmyth_rcv_int64() failed (%d)\n",
++ __FUNCTION__, consumed);
++ return consumed;
++ }
++ if (val64 < 0) {
++ cmyth_dbg(CMYTH_DBG_ERROR,
++ "%s: cmyth_rcv_int64() failed as signed 64 bit integer received\n",
++ __FUNCTION__, consumed);
++ *err = EINVAL;
++ return consumed;
++ }
++ val = (unsigned long long)val64;
+ }
+- consumed += cmyth_rcv_u_long(conn, err, &lo, count);
+- if (*err) {
+- cmyth_dbg(CMYTH_DBG_ERROR,
+- "%s: cmyth_rcv_ulong_long() failed (%d)\n",
+- __FUNCTION__, consumed);
+- return consumed;
++ else {
++ consumed = cmyth_rcv_u_long(conn, err, &hi, count);
++ if (*err) {
++ cmyth_dbg(CMYTH_DBG_ERROR,
++ "%s: cmyth_rcv_u_long_long() failed (%d)\n",
++ __FUNCTION__, consumed);
++ return consumed;
++ }
++ consumed += cmyth_rcv_u_long(conn, err, &lo, count);
++ if (*err) {
++ cmyth_dbg(CMYTH_DBG_ERROR,
++ "%s: cmyth_rcv_u_long_long() failed (%d)\n",
++ __FUNCTION__, consumed);
++ return consumed;
++ }
++ val = (((unsigned long long)hi) << 32) | ((unsigned long long)(lo & 0xFFFFFFFF));
+ }
+-
+- val = (((unsigned long long)hi) << 32) | ((unsigned long long)(lo & 0xFFFFFFFF));
+-
+ *err = 0;
+ *buf = val;
+
+@@ -1485,7 +1527,8 @@ cmyth_rcv_proginfo(cmyth_conn_t conn, int *err, cmyth_proginfo_t buf,
+
+ if (buf->proginfo_version >= 57) {
+ /*
+- * Myth now sends a single 64bit int, rather than 2 32bit ints
++ * Since protocol 57 mythbackend now sends a single 64 bit integer rather than two 32 bit
++ * hi and lo integers for the proginfo length.
+ */
+ rcv_64 = &cmyth_rcv_int64;
+ } else {
+@@ -1536,6 +1579,29 @@ cmyth_rcv_proginfo(cmyth_conn_t conn, int *err, cmyth_proginfo_t buf,
+ ref_release(buf->proginfo_description);
+ buf->proginfo_description = ref_strdup(tmp_str);
+
++ if (buf->proginfo_version >= 67) {
++ /*
++ * Get season and episode (unsigned int)
++ */
++ consumed = cmyth_rcv_ushort(conn, err,
++ &buf->proginfo_season, count);
++ count -= consumed;
++ total += consumed;
++ if (*err) {
++ failed = "cmyth_rcv_ushort";
++ goto fail;
++ }
++
++ consumed = cmyth_rcv_ushort(conn, err,
++ &buf->proginfo_episode, count);
++ count -= consumed;
++ total += consumed;
++ if (*err) {
++ failed = "cmyth_rcv_ushort";
++ goto fail;
++ }
++ }
++
+ /*
+ * Get proginfo_category (string)
+ */
+@@ -1649,7 +1715,7 @@ cmyth_rcv_proginfo(cmyth_conn_t conn, int *err, cmyth_proginfo_t buf,
+ count -= consumed;
+ total += consumed;
+ if (*err) {
+- failed = "cmyth_rcv_long_long";
++ failed = "rcv_64";
+ goto fail;
+ }
+
+@@ -2013,7 +2079,7 @@ cmyth_rcv_proginfo(cmyth_conn_t conn, int *err, cmyth_proginfo_t buf,
+ count -= consumed;
+ total += consumed;
+ if (*err) {
+- failed = "cmyth_rcv_timestamp";
++ failed = "cmyth_rcv_string";
+ goto fail;
+ }
+ if (buf->proginfo_programid)
+@@ -2021,6 +2087,23 @@ cmyth_rcv_proginfo(cmyth_conn_t conn, int *err, cmyth_proginfo_t buf,
+ buf->proginfo_programid = ref_strdup(tmp_str);
+ }
+
++ if (buf->proginfo_version >= 67) {
++ /*
++ * Get inetref (string)
++ */
++ consumed = cmyth_rcv_string(conn, err, tmp_str,
++ sizeof(tmp_str) - 1, count);
++ count -= consumed;
++ total += consumed;
++ if (*err) {
++ failed = "cmyth_rcv_string";
++ goto fail;
++ }
++ if (buf->proginfo_inetref)
++ ref_release(buf->proginfo_inetref);
++ buf->proginfo_inetref = ref_strdup(tmp_str);
++ }
++
+ if (buf->proginfo_version >= 12) {
+ /*
+ * Get lastmodified (string)
diff --git a/lib/libhts/Win32/include/stdint.h b/lib/libhts/Win32/include/stdint.h
deleted file mode 100644
index 81ecedc..0000000
@@ -39977,7 +40941,7 @@ index f3b44da..993eb6c 100644
<ClInclude Include="..\..\xbmc\utils\TimeUtils.h" />
<ClInclude Include="..\..\xbmc\utils\TuxBoxUtil.h" />
diff --git a/project/VS2010Express/XBMC.vcxproj.filters b/project/VS2010Express/XBMC.vcxproj.filters
-index 62a6f25..e340659 100644
+index 62a6f25..f061c12 100644
--- a/project/VS2010Express/XBMC.vcxproj.filters
+++ b/project/VS2010Express/XBMC.vcxproj.filters
@@ -226,6 +226,30 @@
@@ -40192,23 +41156,17 @@ index 62a6f25..e340659 100644
<ClCompile Include="..\..\xbmc\input\XBMC_keytable.cpp">
<Filter>input</Filter>
</ClCompile>
-@@ -2565,9 +2736,15 @@
+@@ -2565,6 +2736,9 @@
<ClCompile Include="..\..\xbmc\filesystem\FileUPnP.cpp">
<Filter>filesystem</Filter>
</ClCompile>
+ <ClCompile Include="..\..\xbmc\interfaces\json-rpc\PVROperations.cpp">
+ <Filter>interfaces\json-rpc</Filter>
+ </ClCompile>
-+<<<<<<< HEAD
<ClCompile Include="..\..\xbmc\cores\paplayer\PCMCodec.cpp">
<Filter>cores\paplayer</Filter>
</ClCompile>
-+=======
-+>>>>>>> FIX: VS compile errors.
- </ItemGroup>
- <ItemGroup>
- <ClInclude Include="..\..\xbmc\win32\pch.h">
-@@ -4960,8 +5137,41 @@
+@@ -4960,8 +5134,41 @@
<ClInclude Include="..\..\xbmc\addons\AddonInstaller.h">
<Filter>addons</Filter>
</ClInclude>
@@ -40252,7 +41210,7 @@ index 62a6f25..e340659 100644
</ClInclude>
<ClInclude Include="..\..\xbmc\utils\GLUtils.h">
<Filter>utils</Filter>
-@@ -4972,12 +5182,121 @@
+@@ -4972,12 +5179,121 @@
<ClInclude Include="..\..\xbmc\win32\stat_utf8.h">
<Filter>win32</Filter>
</ClInclude>
@@ -40374,7 +41332,7 @@ index 62a6f25..e340659 100644
<ClInclude Include="..\..\lib\SlingboxLib\SlingboxLib.h">
<Filter>libs\SlingboxLib</Filter>
</ClInclude>
-@@ -4990,6 +5309,9 @@
+@@ -4990,6 +5306,9 @@
<ClInclude Include="..\..\xbmc\dialogs\GUIDialogPlayEject.h">
<Filter>dialogs</Filter>
</ClInclude>
@@ -40384,7 +41342,7 @@ index 62a6f25..e340659 100644
<ClInclude Include="..\..\xbmc\interfaces\json-rpc\JSONServiceDescription.h">
<Filter>interfaces\json-rpc</Filter>
</ClInclude>
-@@ -5003,6 +5325,9 @@
+@@ -5003,6 +5322,9 @@
<ClInclude Include="..\..\xbmc\interfaces\json-rpc\InputOperations.h">
<Filter>interfaces\json-rpc</Filter>
</ClInclude>
@@ -40394,27 +41352,17 @@ index 62a6f25..e340659 100644
<ClInclude Include="..\..\xbmc\input\XBMC_keytable.h">
<Filter>input</Filter>
</ClInclude>
-@@ -5153,6 +5478,10 @@
+@@ -5153,6 +5475,9 @@
<ClInclude Include="..\..\xbmc\filesystem\FileUPnP.h">
<Filter>filesystem</Filter>
</ClInclude>
+ <ClInclude Include="..\..\xbmc\interfaces\json-rpc\PVROperations.h">
+ <Filter>interfaces\json-rpc</Filter>
+ </ClInclude>
-+<<<<<<< HEAD
<ClInclude Include="..\..\xbmc\cores\AudioRenderers\IAudioRenderer.h" />
<ClInclude Include="..\..\xbmc\interfaces\python\xbmcmodule\pythreadstate.h">
<Filter>interfaces\python\xbmcmodule</Filter>
-@@ -5160,6 +5489,8 @@
- <ClInclude Include="..\..\xbmc\cores\paplayer\PCMCodec.h">
- <Filter>cores\paplayer</Filter>
- </ClInclude>
-+=======
-+>>>>>>> FIX: VS compile errors.
- </ItemGroup>
- <ItemGroup>
- <ResourceCompile Include="..\..\xbmc\win32\XBMC_PC.rc">
-@@ -5171,4 +5502,4 @@
+@@ -5171,4 +5496,4 @@
<Filter>win32</Filter>
</CustomBuild>
</ItemGroup>
@@ -95274,10 +96222,10 @@ index 0000000..4e3bf74
+
diff --git a/xbmc/pvrclients/mythtv-cmyth/client.cpp b/xbmc/pvrclients/mythtv-cmyth/client.cpp
new file mode 100644
-index 0000000..22879db
+index 0000000..963ccf8
--- /dev/null
+++ b/xbmc/pvrclients/mythtv-cmyth/client.cpp
-@@ -0,0 +1,743 @@
+@@ -0,0 +1,754 @@
+/*
+ * Copyright (C) 2005-2009 Team XBMC
+ * http://xbmc.org
@@ -95352,33 +96300,40 @@ index 0000000..22879db
+
+ADDON_STATUS ADDON_Create(void* hdl, void* props)
+{
-+ if (!props)
-+ return ADDON_STATUS_UNKNOWN;
-+
-+ PVR_PROPERTIES* pvrprops = (PVR_PROPERTIES*)props;
-+
+ XBMC = new CHelper_libXBMC_addon;
++
+ if (!XBMC->RegisterMe(hdl))
+ return ADDON_STATUS_UNKNOWN;
++ XBMC->Log(LOG_DEBUG, "Creating MythTV cmyth PVR-Client");
++ XBMC->Log(LOG_DEBUG, "Register handle @ libXBMC_addon...done[1/7]");
++
++ XBMC->Log(LOG_DEBUG, "Checking props...");
++ if (!props)
++ return ADDON_STATUS_UNKNOWN;
++ XBMC->Log(LOG_DEBUG, "Checking props...done[2/7]");
+
++ PVR_PROPERTIES* pvrprops = (PVR_PROPERTIES*)props;
++ XBMC->Log(LOG_DEBUG, "Register handle @ libXBMC_pvr...");
+ PVR = new CHelper_libXBMC_pvr;
+ if (!PVR->RegisterMe(hdl))
+ return ADDON_STATUS_UNKNOWN;
++ XBMC->Log(LOG_DEBUG, "Register handle @ libXBMC_addon...done[3/7]");
+
++ XBMC->Log(LOG_DEBUG, "Register handle @ libXBMC_gui...");
+ GUI = new CHelper_libXBMC_gui;
+ if (!GUI->RegisterMe(hdl))
+ return ADDON_STATUS_UNKNOWN;
++ XBMC->Log(LOG_DEBUG, "Register handle @ libXBMC_gui...done[4/7]");
+
-+ XBMC->Log(LOG_DEBUG, "Loading cmyth library");
++ XBMC->Log(LOG_DEBUG, "Loading cmyth library...");
+ CMYTH = new CHelper_libcmyth;
+ if (!CMYTH->RegisterMe(hdl))
+ {
+ XBMC->Log(LOG_ERROR, "Failed to load cmyth library!");
+ return ADDON_STATUS_UNKNOWN;
+ }
-+
-+ XBMC->Log(LOG_DEBUG, "Creating MythTV cmyth PVR-Client");
-+
++ XBMC->Log(LOG_DEBUG, "Loading cmyth library...done[5/7]");
++
+ m_CurStatus = ADDON_STATUS_UNKNOWN;
+ g_iClientID = pvrprops->iClientId;
+ g_szUserPath = pvrprops->strUserPath;
@@ -95480,13 +96435,15 @@ index 0000000..22879db
+
+ free (buffer);
+
-+
++ XBMC->Log(LOG_DEBUG,"Creating PVRClientMythTV...");
+ g_client = new PVRClientMythTV();
+ if (!g_client->Connect())
+ {
++ XBMC->Log(LOG_ERROR,"Failed to connect to backend");
+ m_CurStatus = ADDON_STATUS_LOST_CONNECTION;
+ return m_CurStatus;
+ }
++ XBMC->Log(LOG_DEBUG,"Creating PVRClientMythTV...done[6/7]");
+
+ /* Read setting "LiveTV Priority" from backend database */
+ bool savedLiveTVPriority;
@@ -95505,6 +96462,8 @@ index 0000000..22879db
+
+ m_CurStatus = ADDON_STATUS_OK;
+ g_bCreated = true;
++
++ XBMC->Log(LOG_DEBUG, "MythTV cmyth PVR-Client successfully created[7/7]");
+ return m_CurStatus;
+}
+
@@ -96114,10 +97073,10 @@ index 0000000..ea40975
+#include "cppmyth/MythTimestamp.h"
diff --git a/xbmc/pvrclients/mythtv-cmyth/cppmyth/MythChannel.cpp b/xbmc/pvrclients/mythtv-cmyth/cppmyth/MythChannel.cpp
new file mode 100644
-index 0000000..d732f8f
+index 0000000..c6acfa7
--- /dev/null
+++ b/xbmc/pvrclients/mythtv-cmyth/cppmyth/MythChannel.cpp
-@@ -0,0 +1,79 @@
+@@ -0,0 +1,84 @@
+#include "MythChannel.h"
+#include "client.h"
+
@@ -96165,6 +97124,11 @@ index 0000000..d732f8f
+ return CMYTH->ChannelSourceid(*m_channel_t);
+}
+
++int MythChannel::MultiplexID()
++{
++ return CMYTH->ChannelMultiplex(*m_channel_t);
++}
++
+CStdString MythChannel::Name()
+{
+ char* cChan=CMYTH->ChannelName(*m_channel_t);
@@ -96200,10 +97164,10 @@ index 0000000..d732f8f
\ No newline at end of file
diff --git a/xbmc/pvrclients/mythtv-cmyth/cppmyth/MythChannel.h b/xbmc/pvrclients/mythtv-cmyth/cppmyth/MythChannel.h
new file mode 100644
-index 0000000..f06164e
+index 0000000..ae2aa27
--- /dev/null
+++ b/xbmc/pvrclients/mythtv-cmyth/cppmyth/MythChannel.h
-@@ -0,0 +1,26 @@
+@@ -0,0 +1,27 @@
+#pragma once
+
+#include "MythPointer.h"
@@ -96221,6 +97185,7 @@ index 0000000..f06164e
+ CStdString Number();
+ CStdString Callsign();
+ int SourceID();
++ int MultiplexID();
+ CStdString Name();
+ CStdString Icon();
+ bool Visible();
@@ -96613,7 +97578,7 @@ index 0000000..ce8b55a
+};
diff --git a/xbmc/pvrclients/mythtv-cmyth/cppmyth/MythDatabase.cpp b/xbmc/pvrclients/mythtv-cmyth/cppmyth/MythDatabase.cpp
new file mode 100644
-index 0000000..fe02145
+index 0000000..4c09538
--- /dev/null
+++ b/xbmc/pvrclients/mythtv-cmyth/cppmyth/MythDatabase.cpp
@@ -0,0 +1,224 @@
@@ -96656,7 +97621,7 @@ index 0000000..fe02145
+ m_database_t->Lock();
+ bool retval=CMYTH->MysqlTestdbConnection(*m_database_t,&cmyth_msg)==1;
+ msg=cmyth_msg;
-+ free(cmyth_msg);
++ CMYTH->RefRelease(cmyth_msg);
+ m_database_t->Unlock();
+ return retval;
+}
@@ -96895,10 +97860,10 @@ index 0000000..f045bdc
\ No newline at end of file
diff --git a/xbmc/pvrclients/mythtv-cmyth/cppmyth/MythEventHandler.cpp b/xbmc/pvrclients/mythtv-cmyth/cppmyth/MythEventHandler.cpp
new file mode 100644
-index 0000000..51b0f54
+index 0000000..4aa92c0
--- /dev/null
+++ b/xbmc/pvrclients/mythtv-cmyth/cppmyth/MythEventHandler.cpp
-@@ -0,0 +1,258 @@
+@@ -0,0 +1,268 @@
+#include "MythEventHandler.h"
+#include "MythRecorder.h"
+#include "MythSignal.h"
@@ -97039,8 +98004,9 @@ index 0000000..51b0f54
+ CStdString uniqId=b;
+
+ if (curRecordingId.compare(uniqId) == 0) {
-+ XBMC->Log(LOG_DEBUG,"EVENT: %s, --UPDATING CURRENT RECORDING LENGTH-- EVENT msg: %s %ll",
-+ __FUNCTION__,uniqId.c_str(),length);
++ if(g_bExtraDebug)
++ XBMC->Log(LOG_DEBUG,"EVENT: %s, --UPDATING CURRENT RECORDING LENGTH-- EVENT msg: %s %ll",
++ __FUNCTION__,uniqId.c_str(),length);
+ m_file.UpdateDuration(length);
+ }
+}
@@ -97076,6 +98042,10 @@ index 0000000..51b0f54
+ {
+ m_signal.m_UNC=std::atoi(tok2[1].c_str());
+ }
++ else if(tok2[0]=="cardid")
++ {
++ m_signal.m_ID=std::atoi(tok2[1].c_str());
++ }
+ }
+ }
+}
@@ -97112,13 +98082,15 @@ index 0000000..51b0f54
+ if(CMYTH->EventSelect(m_conn_t,&timeout)>0)
+ {
+ myth_event=CMYTH->EventGet(m_conn_t,databuf,2048);
-+ XBMC->Log(LOG_DEBUG,"EVENT ID: %s, EVENT databuf: %s",events[myth_event],databuf);
++ if(g_bExtraDebug)
++ XBMC->Log(LOG_DEBUG,"EVENT ID: %s, EVENT databuf: %s",events[myth_event],databuf);
+ if(myth_event==CMYTH_EVENT_UPDATE_FILE_SIZE)
+ {
+ CStdString signal=databuf;
+ UpdateFilesize(signal);
+ //1044 2012-03-20T20:00:00 54229688
-+ XBMC->Log(LOG_NOTICE,"%s: FILE_SIZE_UPDATE: %i",__FUNCTION__,databuf);
++ if(g_bExtraDebug)
++ XBMC->Log(LOG_NOTICE,"%s: FILE_SIZE_UPDATE: %i",__FUNCTION__,databuf);
+ }
+ if(myth_event==CMYTH_EVENT_LIVETV_CHAIN_UPDATE)
+ {
@@ -97126,10 +98098,12 @@ index 0000000..51b0f54
+ if(!m_rec.IsNull())
+ {
+ bool retval=m_rec.LiveTVChainUpdate(CStdString(databuf));
-+ XBMC->Log(LOG_NOTICE,"%s: CHAIN_UPDATE: %i",__FUNCTION__,retval);
++ if(g_bExtraDebug)
++ XBMC->Log(LOG_NOTICE,"%s: CHAIN_UPDATE: %i",__FUNCTION__,retval);
+ }
+ else
-+ XBMC->Log(LOG_NOTICE,"%s: CHAIN_UPDATE - No recorder",__FUNCTION__);
++ if(g_bExtraDebug)
++ XBMC->Log(LOG_NOTICE,"%s: CHAIN_UPDATE - No recorder",__FUNCTION__);
+ Unlock();
+ }
+ if(myth_event==CMYTH_EVENT_SIGNAL)
@@ -97139,13 +98113,14 @@ index 0000000..51b0f54
+ }
+ if(myth_event==CMYTH_EVENT_SCHEDULE_CHANGE)
+ {
-+ XBMC->Log(LOG_NOTICE,"Schedule change",__FUNCTION__);
++ if(g_bExtraDebug)
++ XBMC->Log(LOG_NOTICE,"Schedule change",__FUNCTION__);
+ PVR->TriggerTimerUpdate();
+ PVR->TriggerRecordingUpdate();
+ }
+ if(myth_event==CMYTH_EVENT_RECORDING_LIST_CHANGE_ADD||myth_event==CMYTH_EVENT_RECORDING_LIST_CHANGE_DELETE||myth_event==CMYTH_EVENT_RECORDING_LIST_CHANGE_UPDATE||myth_event==CMYTH_EVENT_RECORDING_LIST_CHANGE)
+ {
-+ XBMC->Log(LOG_NOTICE,"Recording list change",__FUNCTION__);
++ // XBMC->Log(LOG_NOTICE,"Recording list change",__FUNCTION__);
+ PVR->TriggerRecordingUpdate();
+ }
+ databuf[0]=0;
@@ -97569,10 +98544,10 @@ index 0000000..cfb4925
+};
diff --git a/xbmc/pvrclients/mythtv-cmyth/cppmyth/MythRecorder.cpp b/xbmc/pvrclients/mythtv-cmyth/cppmyth/MythRecorder.cpp
new file mode 100644
-index 0000000..a0c284e
+index 0000000..48b70b9
--- /dev/null
+++ b/xbmc/pvrclients/mythtv-cmyth/cppmyth/MythRecorder.cpp
-@@ -0,0 +1,223 @@
+@@ -0,0 +1,264 @@
+
+#include "MythRecorder.h"
+#include "MythProgramInfo.h"
@@ -97665,6 +98640,47 @@ index 0000000..a0c284e
+ return retval;
+}
+
++bool MythRecorder::IsTunable(MythChannel &channel)
++{
++ m_conn.Lock();
++
++ XBMC->Log(LOG_DEBUG,"%s: called for recorder %i, channel %i",__FUNCTION__,ID(),channel.ID());
++
++ cmyth_inputlist_t inputlist=CMYTH->GetFreeInputlist(*m_recorder_t);
++
++ bool ret = false;
++ for (int i=0; i < inputlist->input_count; ++i)
++ {
++ cmyth_input_t input = inputlist->input_list[i];
++ if ((int)input->sourceid != channel.SourceID())
++ {
++ XBMC->Log(LOG_DEBUG,"%s: skip input, source id differs (channel: %i, input: %i)",__FUNCTION__, channel.SourceID(), input->sourceid);
++ continue;
++ }
++
++ if (input->multiplexid && (int)input->multiplexid != channel.MultiplexID())
++ {
++ XBMC->Log(LOG_DEBUG,"%s: skip input, multiplex id id differs (channel: %i, input: %i)",__FUNCTION__, channel.MultiplexID(), input->multiplexid);
++ continue;
++ }
++
++ XBMC->Log(LOG_DEBUG,"%s: using recorder, input is tunable: source id: %i, multiplex id: channel: %i, input: %i)",__FUNCTION__, channel.SourceID(), channel.MultiplexID(), input->multiplexid);
++
++ ret = true;
++ break;
++ }
++
++ CMYTH->RefRelease(inputlist);
++ m_conn.Unlock();
++
++ if (!ret)
++ {
++ XBMC->Log(LOG_DEBUG,"%s: recorder is not tunable",__FUNCTION__);
++ }
++
++ return ret;
++}
++
+bool MythRecorder::CheckChannel(MythChannel &channel)
+{
+ m_conn.Lock();
@@ -97798,10 +98814,10 @@ index 0000000..a0c284e
+ }
diff --git a/xbmc/pvrclients/mythtv-cmyth/cppmyth/MythRecorder.h b/xbmc/pvrclients/mythtv-cmyth/cppmyth/MythRecorder.h
new file mode 100644
-index 0000000..908e2db
+index 0000000..6899159
--- /dev/null
+++ b/xbmc/pvrclients/mythtv-cmyth/cppmyth/MythRecorder.h
-@@ -0,0 +1,35 @@
+@@ -0,0 +1,36 @@
+#pragma once
+
+#include "libcmyth.h"
@@ -97823,6 +98839,7 @@ index 0000000..908e2db
+ bool LiveTVChainUpdate(CStdString chainID);
+ bool IsNull();
+ bool IsRecording();
++ bool IsTunable(MythChannel &channel);
+ int ID();
+ bool CheckChannel(MythChannel &channel);
+ bool SetChannel(MythChannel &channel);
@@ -97917,30 +98934,31 @@ index 0000000..11d431c
+};
diff --git a/xbmc/pvrclients/mythtv-cmyth/cppmyth/MythSignal.cpp b/xbmc/pvrclients/mythtv-cmyth/cppmyth/MythSignal.cpp
new file mode 100644
-index 0000000..216e8b1
+index 0000000..15e668d
--- /dev/null
+++ b/xbmc/pvrclients/mythtv-cmyth/cppmyth/MythSignal.cpp
-@@ -0,0 +1,14 @@
+@@ -0,0 +1,15 @@
+#include "MythSignal.h"
+
+/*
+ * MythSignal
+ */
+
-+ MythSignal::MythSignal() :m_AdapterStatus(),m_SNR(0),m_Signal(0),m_BER(0),m_UNC(0) {}
++ MythSignal::MythSignal() :m_AdapterStatus(),m_SNR(0),m_Signal(0),m_BER(0),m_UNC(0),m_ID(0) {}
+
+ CStdString MythSignal::AdapterStatus(){return m_AdapterStatus;} /*!< @brief (optional) status of the adapter that's being used */
+ int MythSignal::SNR(){return m_SNR;} /*!< @brief (optional) signal/noise ratio */
+ int MythSignal::Signal(){return m_Signal;} /*!< @brief (optional) signal strength */
+ long MythSignal::BER(){return m_BER;} /*!< @brief (optional) bit error rate */
+ long MythSignal::UNC(){return m_UNC;} /*!< @brief (optional) uncorrected blocks */
++ int MythSignal::ID(){return m_ID;}
+
diff --git a/xbmc/pvrclients/mythtv-cmyth/cppmyth/MythSignal.h b/xbmc/pvrclients/mythtv-cmyth/cppmyth/MythSignal.h
new file mode 100644
-index 0000000..6ce0ef0
+index 0000000..7b33a43
--- /dev/null
+++ b/xbmc/pvrclients/mythtv-cmyth/cppmyth/MythSignal.h
-@@ -0,0 +1,21 @@
+@@ -0,0 +1,23 @@
+#pragma once
+
+#include "utils/StdString.h"
@@ -97955,12 +98973,14 @@ index 0000000..6ce0ef0
+ int Signal(); /*!< @brief (optional) signal strength */
+ long BER(); /*!< @brief (optional) bit error rate */
+ long UNC(); /*!< @brief (optional) uncorrected blocks */
++ int ID(); /*!< @brief (optional) Recorder ID */
+private:
+ CStdString m_AdapterStatus; /*!< @brief (optional) status of the adapter that's being used */
+ int m_SNR; /*!< @brief (optional) signal/noise ratio */
+ int m_Signal; /*!< @brief (optional) signal strength */
+ long m_BER; /*!< @brief (optional) bit error rate */
+ long m_UNC; /*!< @brief (optional) uncorrected blocks */
++ int m_ID; /*!< @brief (optional) Recorder ID */
+};
\ No newline at end of file
diff --git a/xbmc/pvrclients/mythtv-cmyth/cppmyth/MythTimer.cpp b/xbmc/pvrclients/mythtv-cmyth/cppmyth/MythTimer.cpp
@@ -98623,10 +99643,10 @@ index 0000000..02e2c26
+};
diff --git a/xbmc/pvrclients/mythtv-cmyth/fileOps.cpp b/xbmc/pvrclients/mythtv-cmyth/fileOps.cpp
new file mode 100644
-index 0000000..3ceabb6
+index 0000000..a5deb22
--- /dev/null
+++ b/xbmc/pvrclients/mythtv-cmyth/fileOps.cpp
-@@ -0,0 +1,313 @@
+@@ -0,0 +1,351 @@
+#include <stdio.h>
+#include <map>
+#include <ctime>
@@ -98647,7 +99667,11 @@ index 0000000..3ceabb6
+{
+ m_localBasePath /= "cache";
+ if(!createDirectory(m_localBasePath))
++#if defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3
+ XBMC->Log(LOG_ERROR,"%s - Failed to create cache directory %s",__FUNCTION__,m_localBasePath.c_str());
++#else
++ XBMC->Log(LOG_ERROR,"%s - Failed to create cache directory %s",__FUNCTION__,m_localBasePath.native_file_string().c_str());
++#endif
+ m_sg_strings[FILE_OPS_GET_COVERART] = "coverart";
+ m_sg_strings[FILE_OPS_GET_FANART] = "fanart";
+ m_sg_strings[FILE_OPS_GET_BANNER] = "banner";
@@ -98668,8 +99692,19 @@ index 0000000..3ceabb6
+ XBMC->Log(LOG_DEBUG,"%s: channelicon: %s",__FUNCTION__,remotePath.c_str());
+ if(m_icons.count(remotePath)>0)
+ return m_icons.at(remotePath);
++#if defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3
+ CStdString remoteFilename = boost::filesystem::path(remotePath.c_str()).filename().string();
++#else
++ CStdString remoteFilename = boost::filesystem::path(remotePath.c_str()).filename();
++#endif
++#if defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3
+ boost::filesystem::path localFilePath = m_localBasePath / "channels" / remoteFilename.c_str();
++#else
++ CStdString localFilePathStr = m_localBasePath.native_file_string().c_str();
++ localFilePathStr.append("/channels/");
++ localFilePathStr.append(remoteFilename);
++ boost::filesystem::path localFilePath = localFilePathStr;
++#endif
+ if(!boost::filesystem::exists(localFilePath))
+ {
+ Lock();
@@ -98686,10 +99721,15 @@ index 0000000..3ceabb6
+CStdString fileOps2::getPreviewIconPath(CStdString remotePath)
+{
+ //Check local directory
-+ XBMC->Log(LOG_DEBUG,"%s: preview icon: %s",__FUNCTION__,remotePath.c_str());
++ if(g_bExtraDebug)
++ XBMC->Log(LOG_DEBUG,"%s: preview icon: %s",__FUNCTION__,remotePath.c_str());
+ if(m_preview.count(remotePath)>0)
+ return m_preview.at(remotePath);
++#if defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3
+ CStdString remoteFilename = boost::filesystem::path(remotePath.c_str()).filename().string();
++#else
++ CStdString remoteFilename = boost::filesystem::path(remotePath.c_str()).filename();
++#endif
+ boost::filesystem::path localFilePath = m_localBasePath / "preview" / remoteFilename.c_str();
+ if(!boost::filesystem::exists(localFilePath))
+ {
@@ -98721,7 +99761,11 @@ index 0000000..3ceabb6
+ if(Get_What==FILE_OPS_GET_CHAN_ICONS)
+ {
+ boost::filesystem::path chanicon(title.c_str());
++#if defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3
+ re_string = chanicon.filename().string();
++#else
++ re_string = chanicon.filename();
++#endif
+ }
+ boost::regex re(re_string.c_str());
+ std::vector< MythSGFile >::iterator it = m_SGFilelist.at(Get_What).begin();
@@ -98768,7 +99812,11 @@ index 0000000..3ceabb6
+ for(boost::filesystem::recursive_directory_iterator dit(dirPath);dit != boost::filesystem::recursive_directory_iterator();dit++)
+ {
+ bool deletefile = true;
++#if defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3
+ CStdString filename = dit->path().filename().string();
++#else
++ CStdString filename = dit->path().filename();
++#endif
+ if(boost::regex_search(filename,match,re)&&match[0].matched)
+ {
+ std::string lastmodified = std::string(match[1].first,match[1].second);
@@ -98827,7 +99875,8 @@ index 0000000..3ceabb6
+void* fileOps2::Process()
+{
+ time_t curTime;
-+ time_t lastCacheClean=0;
++ time_t lastCacheClean;
++ time(&lastCacheClean);
+
+ while(!IsStopped())
+ {
@@ -98856,31 +99905,35 @@ index 0000000..3ceabb6
+ }
+ time(&curTime);
+ if(curTime>lastCacheClean+60*60*24)
++ {
+ cleanCache();
++ time(&lastCacheClean);
++ }
+ }
+ return NULL;
+}
+
+bool fileOps2::writeFile(boost::filesystem::path destination, MythFile &source)
+{
++#if defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3
++ CStdString parentPath = destination.parent_path().c_str();
++#else
++ CStdString parentPath = destination.parent_path().native_file_string().c_str();
++#endif
+ if(!createDirectory(destination,true))
+ {
+ XBMC->Log(LOG_ERROR,"%s - Failed to create destination directory: %s",
-+ __FUNCTION__,destination.parent_path().c_str());
++ __FUNCTION__,parentPath.c_str());
+ return false;
+ }
+ if(source.IsNull())
+ {
+ XBMC->Log(LOG_ERROR,"%s - NULL file provided.",
-+ __FUNCTION__,destination.parent_path().c_str());
++ __FUNCTION__,parentPath.c_str());
+ return false;
+ }
+ unsigned long long length = source.Duration();
+
-+ FILE* f = fopen(destination.string().c_str(),"w");
-+ fwrite("HEJ",1,3,f);
-+ fclose(f);
-+
+ FILE* writeFile = fopen(destination.string().c_str(),"w");
+ //std::ofstream writeFile(destination.string(),std::ios_base::binary /*| std::ios_base::trunc*/);
+
@@ -98919,8 +99972,13 @@ index 0000000..3ceabb6
+ delete buffer;
+ if (totalRead < length)
+ {
++#if defined(BOOST_FILESYSTEM_VERSION) && BOOST_FILESYSTEM_VERSION >= 3
++ CStdString destinationStr = destination.c_str();
++#else
++ CStdString destinationStr = destination.native_file_string().c_str();
++#endif
+ XBMC->Log(LOG_DEBUG,"%s - Did not Read all data - %s - %d - %d",
-+ __FUNCTION__,destination.c_str(),totalRead,length);
++ __FUNCTION__,destinationStr.c_str(),totalRead,length);
+ }
+ return true;
+ }
@@ -98942,10 +100000,10 @@ index 0000000..3ceabb6
+
diff --git a/xbmc/pvrclients/mythtv-cmyth/fileOps.h b/xbmc/pvrclients/mythtv-cmyth/fileOps.h
new file mode 100644
-index 0000000..9a6022d
+index 0000000..8d47e8f
--- /dev/null
+++ b/xbmc/pvrclients/mythtv-cmyth/fileOps.h
-@@ -0,0 +1,66 @@
+@@ -0,0 +1,69 @@
+#ifndef __FILEOPS_H
+#define __FILEOPS_H
+//TODO merge into MythConnection ??
@@ -98957,7 +100015,10 @@ index 0000000..9a6022d
+#include "cppmyth/MythSGFile.h"
+#include "../../../lib/platform/threads/threads.h"
+#define BOOST_FILESYSTEM_NO_DEPRECATED
++// Use v3, if it's available.
++#if defined(BOOST_FILESYSTEM_VERSION)
+#define BOOST_FILESYSTEM_VERSION 3
++#endif
+#include <boost/filesystem.hpp>
+
+
@@ -99012,13 +100073,12 @@ index 0000000..9a6022d
+};
+
+#endif
-\ No newline at end of file
diff --git a/xbmc/pvrclients/mythtv-cmyth/libcmyth.h b/xbmc/pvrclients/mythtv-cmyth/libcmyth.h
new file mode 100644
-index 0000000..d6a5933
+index 0000000..abc0c0f
--- /dev/null
+++ b/xbmc/pvrclients/mythtv-cmyth/libcmyth.h
-@@ -0,0 +1,1642 @@
+@@ -0,0 +1,1679 @@
+#pragma once
+/*
+ * Copyright (C) 2005-2010 Team XBMC
@@ -99213,6 +100273,23 @@ index 0000000..d6a5933
+struct cmyth_tvguide_progs;
+typedef struct cmyth_tvguide_progs *cmyth_tvguide_progs_t;
+
++/* fetzerch: Added to support querying of free inputs (is tunable on) */
++struct cmyth_input {
++ char *inputname;
++ unsigned long sourceid;
++ unsigned long inputid;
++ unsigned long cardid;
++ unsigned long multiplexid;
++ unsigned long livetvorder; /* new in V71 */
++};
++typedef struct cmyth_input *cmyth_input_t;
++
++struct cmyth_inputlist {
++ cmyth_input_t *input_list;
++ long input_count;
++};
++typedef struct cmyth_inputlist *cmyth_inputlist_t;
++
+typedef struct cmyth_program {
+ int chanid;
+ char callsign[30];
@@ -100096,6 +101173,22 @@ index 0000000..d6a5933
+dlsym(m_libcmyth, "cmyth_rcv_commbreaklist");
+if (RcvCommbreaklist == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
+
++ InputlistCreate = (cmyth_inputlist_t (*)(void))
++dlsym(m_libcmyth, "cmyth_inputlist_create");
++if (InputlistCreate == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
++
++ InputCreate = (cmyth_input_t (*)(void))
++dlsym(m_libcmyth, "cmyth_input_create");
++if (InputCreate == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
++
++ GetFreeInputlist = (cmyth_inputlist_t (*)(cmyth_recorder_t rec))
++dlsym(m_libcmyth, "cmyth_get_free_inputlist");
++if (GetFreeInputlist == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
++
++ RcvFreeInputlist = (int (*)(cmyth_conn_t conn, int* err, cmyth_inputlist_t inputlist, int count))
++dlsym(m_libcmyth, "cmyth_rcv_free_inputlist");
++if (RcvFreeInputlist == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
++
+ MysqlGetRecgroups = (int (*)(cmyth_database_t, cmyth_recgroups_t**))
+dlsym(m_libcmyth, "cmyth_mysql_get_recgroups");
+if (MysqlGetRecgroups == NULL) { fprintf(stderr, "Unable to assign function %s\n", dlerror()); return false; }
@@ -100571,6 +101664,10 @@ index 0000000..d6a5933
+cmyth_commbreaklist_t (*GetCommbreaklist)(cmyth_conn_t conn, cmyth_proginfo_t prog);
+cmyth_commbreaklist_t (*GetCutlist)(cmyth_conn_t conn, cmyth_proginfo_t prog);
+int (*RcvCommbreaklist)(cmyth_conn_t conn, int* err, cmyth_commbreaklist_t breaklist, int count);
++cmyth_inputlist_t (*InputlistCreate)(void);
++cmyth_input_t (*InputCreate)(void);
++cmyth_inputlist_t (*GetFreeInputlist)(cmyth_recorder_t rec);
++int (*RcvFreeInputlist)(cmyth_conn_t conn, int* err, cmyth_inputlist_t inputlist, int count);
+int (*MysqlGetRecgroups)(cmyth_database_t, cmyth_recgroups_t**);
+int (*MysqlDeleteScheduledRecording)(cmyth_database_t db, char* query);
+int (*MysqlInsertIntoRecord)(cmyth_database_t db, char* query, char* query1, char* query2, char* title, char* subtitle, char* description, char* callsign);
@@ -100981,10 +102078,10 @@ index 0000000..ab01f36
\ No newline at end of file
diff --git a/xbmc/pvrclients/mythtv-cmyth/pvrclient-mythtv.cpp b/xbmc/pvrclients/mythtv-cmyth/pvrclient-mythtv.cpp
new file mode 100644
-index 0000000..a469050
+index 0000000..b033679
--- /dev/null
+++ b/xbmc/pvrclients/mythtv-cmyth/pvrclient-mythtv.cpp
-@@ -0,0 +1,1291 @@
+@@ -0,0 +1,1306 @@
+#include "pvrclient-mythtv.h"
+#include "client.h"
+#include <time.h>
@@ -101410,7 +102507,8 @@ index 0000000..a469050
+ if(iStart!=m_EPGstart&&iEnd!=m_EPGend)
+ {
+ m_EPG=m_db.GetGuide(iStart,iEnd);
-+ XBMC->Log(LOG_DEBUG,"%s: Fetching EPG - size: %i",__FUNCTION__,m_EPG.size());
++ if(g_bExtraDebug)
++ XBMC->Log(LOG_DEBUG,"%s: Fetching EPG - size: %i",__FUNCTION__,m_EPG.size());
+ m_EPGstart=iStart;
+ m_EPGend=iEnd;
+ }
@@ -101692,7 +102790,8 @@ index 0000000..a469050
+ tag.strTitle=title;
+ CStdString summary=proginfo.Description();
+ tag.strSummary=summary;
-+ XBMC->Log(LOG_DEBUG,"%s ## - State: %d - ##",__FUNCTION__,proginfo.Status());
++ if(g_bExtraDebug)
++ XBMC->Log(LOG_DEBUG,"%s ## - State: %d - ##",__FUNCTION__,proginfo.Status());
+ switch(proginfo.Status())
+ {
+ case RS_RECORDING:
@@ -101999,18 +103098,22 @@ index 0000000..a469050
+{
+ if(g_bExtraDebug)
+ XBMC->Log(LOG_DEBUG,"%s - chanID: %i, channumber: %i",__FUNCTION__,channel.iUniqueId,channel.iChannelNumber);
++ SingleLock<PLATFORM::CMutex> lock(&m_lock);
+ if(m_rec.IsNull())
+ {
+ MythChannel chan=m_channels.at(channel.iUniqueId);
+ for(std::vector<int>::iterator it=m_sources.at(chan.SourceID()).begin();it!=m_sources.at(chan.SourceID()).end();it++)
+ {
+ m_rec=m_con.GetRecorder(*it);
-+ if(!m_rec.IsRecording())
++ if(!m_rec.IsRecording() && m_rec.IsTunable(chan))
+ {
-+ XBMC->Log(LOG_DEBUG,"%s: Opening new recorder %i",__FUNCTION__,m_rec.ID());
++ if(g_bExtraDebug)
++ XBMC->Log(LOG_DEBUG,"%s: Opening new recorder %i",__FUNCTION__,m_rec.ID());
+ m_eventHandler.SetRecorder(m_rec);
+ if(m_rec.SpawnLiveTV(chan))
++ {
+ return true;
++ }
+ }
+ m_rec=MythRecorder();
+ m_eventHandler.SetRecorder(m_rec);//Redundant
@@ -102032,6 +103135,7 @@ index 0000000..a469050
+{
+ if(g_bExtraDebug)
+ XBMC->Log(LOG_DEBUG,"%s",__FUNCTION__);
++ SingleLock<PLATFORM::CMutex> lock(&m_lock);
+ m_eventHandler.PreventLiveChainUpdate();
+ m_rec.Stop();
+ m_rec=MythRecorder();
@@ -102046,6 +103150,7 @@ index 0000000..a469050
+{
+ if(g_bExtraDebug)
+ XBMC->Log(LOG_DEBUG,"%s - size: %i",__FUNCTION__,iBufferSize);
++ SingleLock<PLATFORM::CMutex> lock(&m_lock);
+ if(m_rec.IsNull())
+ return -1;
+ int dataread=m_rec.ReadLiveTV(pBuffer,iBufferSize);
@@ -102058,6 +103163,7 @@ index 0000000..a469050
+
+int PVRClientMythTV::GetCurrentClientChannel()
+{
++ SingleLock<PLATFORM::CMutex> lock(&m_lock);
+ if(g_bExtraDebug)
+ XBMC->Log(LOG_DEBUG,"%s",__FUNCTION__);
+ if(m_rec.IsNull())
@@ -102090,6 +103196,9 @@ index 0000000..a469050
+long long PVRClientMythTV::SeekLiveStream(long long iPosition, int iWhence) {
+ if(g_bExtraDebug)
+ XBMC->Log(LOG_DEBUG,"%s - pos: %i, whence: %i",__FUNCTION__,iPosition,iWhence);
++ SingleLock<PLATFORM::CMutex> lock(&m_lock);
++ if(m_rec.IsNull())
++ return -1;
+ int whence=iWhence==SEEK_SET?WHENCE_SET:iWhence==SEEK_CUR?WHENCE_CUR:WHENCE_END;
+ long long retval= m_rec.LiveTVSeek(iPosition,whence);
+ if(g_bExtraDebug)
@@ -102101,6 +103210,9 @@ index 0000000..a469050
+{
+ if(g_bExtraDebug)
+ XBMC->Log(LOG_DEBUG,"%s",__FUNCTION__);
++ SingleLock<PLATFORM::CMutex> lock(&m_lock);
++ if(m_rec.IsNull())
++ return -1;
+ long long retval=m_rec.LiveTVDuration();
+ if(g_bExtraDebug)
+ XBMC->Log(LOG_DEBUG,"%s - Done - duration: %i",__FUNCTION__,retval);
@@ -102121,7 +103233,7 @@ index 0000000..a469050
+ signalStatus.iUNC=signal.UNC();
+ CStdString ID;
+ CStdString adaptorStatus=signal.AdapterStatus();
-+ ID.Format("Myth Recorder %i",m_rec.ID());
++ ID.Format("Myth Recorder %i",signal.ID());
+ strcpy(signalStatus.strAdapterName,ID.Buffer());
+ strcpy(signalStatus.strAdapterStatus,adaptorStatus.Buffer());
+ if(g_bExtraDebug)
@@ -102276,13 +103388,12 @@ index 0000000..a469050
+ m_con.SetSetting(m_con.GetHostname(),"LiveTVPriority",value);
+ }
+}
-\ No newline at end of file
diff --git a/xbmc/pvrclients/mythtv-cmyth/pvrclient-mythtv.h b/xbmc/pvrclients/mythtv-cmyth/pvrclient-mythtv.h
new file mode 100644
-index 0000000..f8e058f
+index 0000000..167a20f
--- /dev/null
+++ b/xbmc/pvrclients/mythtv-cmyth/pvrclient-mythtv.h
-@@ -0,0 +1,109 @@
+@@ -0,0 +1,110 @@
+#include "cppmyth.h"
+#include "xbmc_pvr_types.h"
+#include <map>
@@ -102378,6 +103489,7 @@ index 0000000..f8e058f
+ MythEventHandler m_eventHandler;
+ MythDatabase m_db;
+ MythRecorder m_rec;
++ CMutex m_lock;
+ MythFile m_file;
+ CStdString m_protocolVersion;
+ CStdString m_connectionString;
@@ -102755,10 +103867,10 @@ index 0000000..c3e9ffd
\ No newline at end of file
diff --git a/xbmc/pvrclients/mythtv-cmyth/tools.h b/xbmc/pvrclients/mythtv-cmyth/tools.h
new file mode 100644
-index 0000000..f973d4a
+index 0000000..7627339
--- /dev/null
+++ b/xbmc/pvrclients/mythtv-cmyth/tools.h
-@@ -0,0 +1,99 @@
+@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2005-2009 Team XBMC
+ * http://www.xbmc.org
@@ -102857,6 +103969,52 @@ index 0000000..f973d4a
+ int retval = ptm->tm_wday;
+ return retval;
+}
++
++template <class T> class SingleLock {
++private:
++ T *m_mutex;
++ bool m_locked;
++ bool Lock()
++ {
++ if (m_mutex && !m_locked)
++ {
++ m_mutex->Lock();
++ m_locked = true;
++ return true;
++ }
++ return false;
++ }
++
++ bool Unlock()
++ {
++ if (m_mutex && m_locked)
++ {
++ m_mutex->Unlock();
++ m_locked = false;
++ return true;
++ }
++ return false;
++ }
++
++public:
++ SingleLock(T *Mutex)
++ {
++ m_mutex = Mutex;
++ m_locked = false;
++ Lock();
++ }
++
++ ~SingleLock()
++ {
++ Unlock();
++ }
++
++ void Leave() { Unlock(); }
++ void Enter() { Lock(); }
++};
++
++
++
+#endif //__TOOLS_H
diff --git a/xbmc/pvrclients/mythtv/Makefile.in b/xbmc/pvrclients/mythtv/Makefile.in
new file mode 100644