Пример #1
0
static int
delete_command(cmyth_conn_t control, cmyth_proginfo_t prog, char *cmd)
{
    long c = 0;
    char *buf;
    unsigned int len = ((2 * CMYTH_LONGLONG_LEN) +
                        (6 * CMYTH_TIMESTAMP_LEN) +
                        (14 * 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];
    char rec_end_ts[CMYTH_TIMESTAMP_LEN + 1];
    char originalairdate[CMYTH_TIMESTAMP_LEN + 1];
    char lastmodified[CMYTH_TIMESTAMP_LEN + 1];
    int err;
    int count;
    long r;
    int ret;

    if (!prog) {
        cmyth_dbg(CMYTH_DBG_ERROR, "%s: no program info\n",
                  __FUNCTION__);
        return -EINVAL;
    }
#define S(a) ((a) == NULL ? "" : (a))

    len += strlen(S(prog->proginfo_title));
    len += strlen(S(prog->proginfo_subtitle));
    len += strlen(S(prog->proginfo_description));
    len += strlen(S(prog->proginfo_category));
    len += strlen(S(prog->proginfo_chanstr));
    len += strlen(S(prog->proginfo_chansign));
    len += strlen(S(prog->proginfo_channame));
    len += strlen(S(prog->proginfo_url));
    len += strlen(S(prog->proginfo_hostname));
    len += strlen(S(prog->proginfo_playgroup));
    len += strlen(S(prog->proginfo_recpriority_2));
    len += strlen(S(prog->proginfo_storagegroup));

    buf = alloca(len + 1+2048);
    if (!buf) {
        return -ENOMEM;
    }

    if(control->conn_version < 14)
    {
        cmyth_timestamp_to_string(start_ts, prog->proginfo_start_ts);
        cmyth_timestamp_to_string(end_ts, prog->proginfo_end_ts);
        cmyth_timestamp_to_string(rec_start_ts,
                                  prog->proginfo_rec_start_ts);
        cmyth_timestamp_to_string(rec_end_ts, prog->proginfo_rec_end_ts);
        cmyth_timestamp_to_string(originalairdate,
                                  prog->proginfo_originalairdate);
        cmyth_timestamp_to_string(lastmodified,
                                  prog->proginfo_lastmodified);
    }
    else
    {
        cmyth_datetime_to_string(start_ts, prog->proginfo_start_ts);
        cmyth_datetime_to_string(end_ts, prog->proginfo_end_ts);
        cmyth_datetime_to_string(rec_start_ts, prog->proginfo_rec_start_ts);
        cmyth_datetime_to_string(rec_end_ts, prog->proginfo_rec_end_ts);
        cmyth_datetime_to_string(originalairdate,
                                 prog->proginfo_originalairdate);
        cmyth_datetime_to_string(lastmodified, prog->proginfo_lastmodified);
    }

    if(control->conn_version > 32) {
        cmyth_timestamp_to_isostring(originalairdate,
                                     prog->proginfo_originalairdate);
    }

    if(control->conn_version < 12)
    {
        cmyth_dbg(CMYTH_DBG_ERROR,
                  "%s: delete not supported with protocol ver %d\n",
                  __FUNCTION__, control->conn_version);
        return -EINVAL;
    } else {
        sprintf(buf,
                "%s 0[]:[]"
                "%s[]:[]%s[]:[]%s[]:[]%s[]:[]%ld[]:[]"
                "%s[]:[]%s[]:[]%s[]:[]%s[]:[]%ld[]:[]"
                "%ld[]:[]%s[]:[]%s[]:[]%s[]:[]%ld[]:[]"
                "%ld[]:[]%s[]:[]%ld[]:[]%ld[]:[]%ld[]:[]"
                "%s[]:[]%ld[]:[]%ld[]:[]%ld[]:[]%ld[]:[]"
                "%ld[]:[]%s[]:[]%s[]:[]%ld[]:[]%ld[]:[]"
                "%s[]:[]%s[]:[]%s[]:[]%s[]:[]"
                "%s[]:[]%s[]:[]%s[]:[]%s[]:[]",
                cmd,
                S(prog->proginfo_title),
                S(prog->proginfo_subtitle),
                S(prog->proginfo_description),
                S(prog->proginfo_category),
                prog->proginfo_chanId,
                S(prog->proginfo_chanstr),
                S(prog->proginfo_chansign),
                S(prog->proginfo_chanicon),
                S(prog->proginfo_url),
                (unsigned long)(prog->proginfo_Length >> 32),
                (unsigned long)(prog->proginfo_Length & 0xffffffff),
                start_ts,
                end_ts,
                S(prog->proginfo_unknown_0),
                prog->proginfo_recording,
                prog->proginfo_override,
                S(prog->proginfo_hostname),
                prog->proginfo_source_id,
                prog->proginfo_card_id,
                prog->proginfo_input_id,
                S(prog->proginfo_rec_priority),
                prog->proginfo_rec_status,
                prog->proginfo_record_id,
                prog->proginfo_rec_type,
                prog->proginfo_rec_dups,
                prog->proginfo_unknown_1,
                rec_start_ts,
                rec_end_ts,
                prog->proginfo_repeat,
                prog->proginfo_program_flags,
                S(prog->proginfo_recgroup),
                S(prog->proginfo_chancommfree),
                S(prog->proginfo_chan_output_filters),
                S(prog->proginfo_seriesid),
                S(prog->proginfo_programid),
                lastmodified,
                S(prog->proginfo_stars),
                originalairdate);
        if (control->conn_version >= 15) {
            sprintf(buf + strlen(buf), "%ld[]:[]",
                    prog->proginfo_hasairdate);
        }
        if (control->conn_version >= 18) {
            sprintf(buf + strlen(buf), "%s[]:[]",
                    S(prog->proginfo_playgroup));
        }
        if (control->conn_version >= 25) {
            sprintf(buf + strlen(buf), "%s[]:[]",
                    S(prog->proginfo_recpriority_2));
        }
        if (control->conn_version >= 31) {
            sprintf(buf + strlen(buf), "%ld[]:[]",
                    prog->proginfo_parentid);
        }
        if (control->conn_version >= 32) {
            sprintf(buf + strlen(buf), "%s[]:[]",
                    S(prog->proginfo_storagegroup));
        }
        if (control->conn_version >= 35) {
            sprintf(buf + strlen(buf), "%ld[]:[]%ld[]:[]%ld[]:[]",
                    prog->proginfo_audioproperties,
                    prog->proginfo_videoproperties,
                    prog->proginfo_subtitletype);
        }
        if (control->conn_version >= 41) {
            sprintf(buf + strlen(buf), "%s[]:[]",
                    S(prog->proginfo_prodyear));
        }
    }
#undef S

    pthread_mutex_lock(&mutex);

    if ((err = cmyth_send_message(control, buf)) < 0) {
        cmyth_dbg(CMYTH_DBG_ERROR,
                  "%s: cmyth_send_message() failed (%d)\n",
                  __FUNCTION__, err);
        ret = err;
        goto out;
    }

    count = cmyth_rcv_length(control);
    if ((r=cmyth_rcv_long(control, &err, &c, count)) < 0) {
        cmyth_dbg(CMYTH_DBG_ERROR,
                  "%s: cmyth_rcv_length() failed (%d)\n",
                  __FUNCTION__, r);
        ret = err;
        goto out;
    }

    /*
     * XXX: for some reason, this seems to return an error, even though
     *      it succeeds...
     */

    ret = 0;

out:
    pthread_mutex_unlock(&mutex);

    return ret;
}
Пример #2
0
int
cmyth_conn_get_freespace(cmyth_conn_t control,
			 long long *total, long long *used)
{
	int err, count, ret = 0;
	int r;
	char msg[256];
	char reply[256];
	long long lreply;

	if (control == NULL)
		return -EINVAL;

	if ((total == NULL) || (used == NULL))
		return -EINVAL;

	pthread_mutex_lock(&mutex);

	if (control->conn_version >= 32)
		{ snprintf(msg, sizeof(msg), "QUERY_FREE_SPACE_SUMMARY"); }
	else if (control->conn_version >= 17)	
		{ snprintf(msg, sizeof(msg), "QUERY_FREE_SPACE"); }
	else
		{ snprintf(msg, sizeof(msg), "QUERY_FREESPACE"); }

	if ((err = cmyth_send_message(control, msg)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_send_message() failed (%d)\n",
			  __FUNCTION__, err);
		ret = err;
		goto out;
	}

	if ((count=cmyth_rcv_length(control)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_length() failed (%d)\n",
			  __FUNCTION__, count);
		ret = count;
		goto out;
	}
	
	if (control->conn_version >= 17) {
		if ((r=cmyth_rcv_long_long(control, &err, &lreply,
					   count)) < 0) {
			cmyth_dbg(CMYTH_DBG_ERROR,
				  "%s: cmyth_rcv_long_long() failed (%d)\n",
				  __FUNCTION__, err);
			ret = err;
			goto out;
		}
		*total = lreply;
		if ((r=cmyth_rcv_long_long(control, &err, &lreply,
					   count-r)) < 0) {
			cmyth_dbg(CMYTH_DBG_ERROR,
				  "%s: cmyth_rcv_long_long() failed (%d)\n",
				  __FUNCTION__, err);
			ret = err;
			goto out;
		}
		*used = lreply;
	}
	else
		{
			if ((r=cmyth_rcv_string(control, &err, reply,
						sizeof(reply)-1, count)) < 0) {
				cmyth_dbg(CMYTH_DBG_ERROR,
					  "%s: cmyth_rcv_string() failed (%d)\n",
					  __FUNCTION__, err);
				ret = err;
				goto out;
			}
			*total = atoi(reply);
			if ((r=cmyth_rcv_string(control, &err, reply,
						sizeof(reply)-1,
						count-r)) < 0) {
				cmyth_dbg(CMYTH_DBG_ERROR,
					  "%s: cmyth_rcv_string() failed (%d)\n",
					  __FUNCTION__, err);
				ret = err;
				goto out;
			}
			*used = atoi(reply);

			*used *= 1024;
			*total *= 1024;
		}

    out:
	pthread_mutex_unlock(&mutex);

	return ret;
}
Пример #3
0
static cmyth_conn_t
cmyth_conn_connect(char *server, unsigned short port, unsigned buflen,
		   int tcp_rcvbuf, int event)
{
	cmyth_conn_t conn;
	char announcement[256];
	unsigned long tmp_ver;
	int attempt = 0;

    top:
	conn = cmyth_connect(server, port, buflen, tcp_rcvbuf);
	if (!conn) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_connect(%s, %d, %d) failed\n",
			  __FUNCTION__, server, port, buflen);
		return NULL;
	}

	/*
	 * Find out what the Myth Protocol Version is for this connection.
	 * Loop around until we get agreement from the server.
	 */
	if (attempt == 0)
		tmp_ver = conn->conn_version;
	conn->conn_version = tmp_ver;

	if (tmp_ver >= 62) {
		myth_protomap_t *map = protomap;
		while (map->version != 0 && map->version != tmp_ver)
			map++;
		if (map->version == 0) {
			cmyth_dbg(CMYTH_DBG_ERROR,
				  "%s: failed to connect with any version\n",
				  __FUNCTION__);
			goto shut;
		}
		sprintf(announcement, "MYTH_PROTO_VERSION %ld %04X", conn->conn_version, map->token);
	} else {
		sprintf(announcement, "MYTH_PROTO_VERSION %ld", conn->conn_version);
	}
	if (cmyth_send_message(conn, announcement) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_send_message('%s') failed\n",
			  __FUNCTION__, announcement);
		goto shut;
	}
	if (cmyth_rcv_version(conn, &tmp_ver) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_version() failed\n",
			  __FUNCTION__);
		goto shut;
	}
	cmyth_dbg(CMYTH_DBG_ERROR,
		  "%s: asked for version %ld, got version %ld\n",
		  __FUNCTION__, conn->conn_version, tmp_ver);
	if (conn->conn_version != tmp_ver) {
		if (attempt == 1) {
			cmyth_dbg(CMYTH_DBG_ERROR,
				  "%s: failed to connect with any version\n",
				  __FUNCTION__);
			goto shut;
		}
		attempt = 1;
		ref_release(conn);
		goto top;
	}
	cmyth_dbg(CMYTH_DBG_PROTO, "%s: agreed on Version %ld protocol\n",
		  __FUNCTION__, conn->conn_version);

	sprintf(announcement, "ANN Playback %s %d", my_hostname, event);
	if (cmyth_send_message(conn, announcement) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_send_message('%s') failed\n",
			  __FUNCTION__, announcement);
		goto shut;
	}
	if (cmyth_rcv_okay(conn, "OK") < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_rcv_okay() failed\n",
			  __FUNCTION__);
		goto shut;
	}
	return conn;

    shut:
	ref_release(conn);
	return NULL;
}
Пример #4
0
static int
cmyth_storagegroup_update_fileinfo(cmyth_conn_t control, cmyth_storagegroup_file_t file)
{
	char msg[256];
	int count;
	int err = 0;
	int consumed; /* = profiles;*/
	char tmp_str[2048];

	if (!control) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no connection\n", __FUNCTION__);
		return -EINVAL;
	}

	if (!file) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no file specified\n", __FUNCTION__);
		return -EINVAL;
	}

	snprintf(msg, sizeof(msg), "QUERY_SG_FILEQUERY[]:[]%s[]:[]%s[]:[]%s", file->hostname , file->storagegroup, file->filename);

	err = cmyth_send_message(control, msg);
	if (err < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_send_message() failed (%d)\n", __FUNCTION__, err);
		return err;
	}

	count = cmyth_rcv_length(control);
	if (count < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_rcv_length() failed (%d)\n", __FUNCTION__, count);
		return -1;
	}

	consumed = cmyth_rcv_string(control, &err, tmp_str, sizeof(tmp_str) - 1, count);
	count -= consumed;

	if (err) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_rcv_string() failed (%d)\n", __FUNCTION__, count);
		return -1;
	} else if (count == 0) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: QUERY_SG_FILEQUERY failed(%s)\n", __FUNCTION__, tmp_str);
		return -1;
	}

	consumed = cmyth_rcv_string(control, &err, tmp_str, sizeof(tmp_str), count);
	count -= consumed;
	if (err) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_rcv_string() failed (%d)\n", __FUNCTION__, count);
		return -1;
	}
	file->lastmodified = atol(tmp_str);

	consumed = cmyth_rcv_new_int64(control, &err, &(file->size), count, 1);
	count -= consumed;
	if (err) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_rcv_int64() failed (%d)\n", __FUNCTION__, count);
		return -1;
	}

	return 0;
}
Пример #5
0
/* Sergio: Added to support the new livetv protocol */
int
cmyth_recorder_spawn_chain_livetv(cmyth_recorder_t rec)
{
	int err;
	int ret = -1;
	char msg[256];
	char myhostname[32];
	char datestr[32];
	time_t t;


	if (!rec) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no recorder connection\n",
			  __FUNCTION__);
		return -ENOSYS;
	}

	pthread_mutex_lock(&mutex);


	/* Get our own IP address */
	gethostname(myhostname, 32);

	/* Get the current date and time to create a unique id */
	t = time(NULL);
	strftime(datestr, 32, "%Y-%m-%dT%H:%M:%S", localtime(&t));
	
	/* Now build the SPAWN_LIVETV message */
	if (rec->rec_conn->conn_version >=50) {
		snprintf(msg, sizeof(msg),
		"QUERY_RECORDER %d[]:[]SPAWN_LIVETV[]:[]live-%s-%s[]:[]%d[]:[]",
		 rec->rec_id, myhostname, datestr, 0);
	}
	else {
		snprintf(msg, sizeof(msg),
		"QUERY_RECORDER %d[]:[]SPAWN_LIVETV[]:[]live-%s-%s[]:[]%d",
		 rec->rec_id, myhostname, datestr, 0);
	}

	if ((err=cmyth_send_message(rec->rec_conn, msg)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_send_message() failed (%d)\n",
			  __FUNCTION__, err);
		goto fail;
	}

	if ((err=cmyth_rcv_okay(rec->rec_conn, "ok")) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_okay() failed (%d)\n",
			  __FUNCTION__, err);
		goto fail;
	}

	/* Create an empty livetv chain with the ID used in the spawn command */
	snprintf(msg, sizeof(msg),
		"live-%s-%s[]:[]",
		  myhostname, datestr);
	rec->rec_livetv_chain = cmyth_livetv_chain_create(msg);

	ret = 0;

    fail:
	pthread_mutex_unlock(&mutex);

	return ret;
}
Пример #6
0
/*
 * cmyth_conn_connect_ring(char *server, unsigned short port, unsigned buflen
 *                         cmyth_recorder_t rec)
 *
 * Scope: PUBLIC
 *
 * Description:
 *
 * Create a new ring buffer connection for use transferring live-tv
 * using the MythTV protocol.  Return a pointer to the newly created
 * ring buffer connection.  The ring buffer connection is returned
 * held, and may be released using ref_release().
 *
 * Return Value:
 *
 * Success: Non-NULL cmyth_conn_t (this is a pointer type)
 *
 * Failure: NULL cmyth_conn_t
 */
int
cmyth_conn_connect_ring(cmyth_recorder_t rec, unsigned buflen, int tcp_rcvbuf)
{
	cmyth_conn_t conn;
	char *announcement;
	int ann_size = sizeof("ANN RingBuffer  ");
	char *server;
	unsigned short port;

	if (!rec) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: rec is NULL\n", __FUNCTION__);
		return -1;
	}

	server = rec->rec_server;
	port = rec->rec_port;

	cmyth_dbg(CMYTH_DBG_PROTO, "%s: connecting ringbuffer\n",
		  __FUNCTION__);
	conn = cmyth_connect(server, port, buflen, tcp_rcvbuf);
	cmyth_dbg(CMYTH_DBG_PROTO,
		  "%s: connecting ringbuffer, conn = %p\n",
		  __FUNCTION__, conn);
	if (!conn) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_connect(%s, %d, %d) failed\n",
			  __FUNCTION__, server, port, buflen);
		return -1;
	}

	ann_size += CMYTH_LONG_LEN + strlen(my_hostname);
	announcement = malloc(ann_size);
	if (!announcement) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: malloc(%d) failed for announcement\n",
			  __FUNCTION__, ann_size);
		goto shut;
	}
	sprintf(announcement,
		"ANN RingBuffer %s %d", my_hostname, rec->rec_id);
	if (cmyth_send_message(conn, announcement) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_send_message('%s') failed\n",
			  __FUNCTION__, announcement);
		free(announcement);
		goto shut;
	}
	free(announcement);
	if (cmyth_rcv_okay(conn, "OK") < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_rcv_okay() failed\n",
			  __FUNCTION__);
		goto shut;
	}

        rec->rec_ring->conn_data = conn;
	return 0;

    shut:
	ref_release(conn);
	return -1;
}
Пример #7
0
cmyth_storagegroup_filelist_t
cmyth_storagegroup_get_filelist(cmyth_conn_t control,char *storagegroup, char *hostname)
{
	char msg[256];
	int res = 0;
	int count = 0;
	int err = 0;
	int i = 0;
	int listsize = 10;
	cmyth_storagegroup_filelist_t ret = NULL;
	cmyth_storagegroup_file_t file = NULL;
	int consumed = 0; /* = profiles; */
	char tmp_str[32768];

	if (!control) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no connection\n", __FUNCTION__);
		return NULL;
	}

	pthread_mutex_lock(&control->conn_mutex);

	snprintf(msg, sizeof(msg), "QUERY_SG_GETFILELIST[]:[]%s[]:[]%s[]:[][]:[]1", hostname, storagegroup);

	err = cmyth_send_message(control, msg);
	if (err < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_send_message() failed (%d)\n", __FUNCTION__, err);
		goto out;
	}

	count = cmyth_rcv_length(control);
	if (count < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_rcv_length() failed (%d)\n", __FUNCTION__, count);
		goto out;
	}

	ret = cmyth_storagegroup_filelist_create();

	if (!ret) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: alloc() failed for list\n", __FUNCTION__);
		goto out;
	}

	ret->storagegroup_filelist_count = 0;
	ret->storagegroup_filelist_list = malloc(listsize * sizeof(cmyth_storagegroup_file_t));
	if (!ret->storagegroup_filelist_list) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: alloc() failed for filelist list\n", __FUNCTION__);
		ref_release(ret);
		ret = NULL;
		goto out;
	}
	while (count) {
		consumed = cmyth_rcv_string(control, &err, tmp_str, sizeof(tmp_str) - 1, count);
		count -= consumed;
		if (err) {
			cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_rcv_string() failed (%d)\n", __FUNCTION__, count);
			ref_release(ret);
			ret = NULL;
			goto out;
		}
		if (res>listsize-1)
		{
			listsize += 10;
			ret->storagegroup_filelist_list = realloc(ret->storagegroup_filelist_list, listsize * sizeof(cmyth_storagegroup_file_t));
			if (!ret->storagegroup_filelist_list) {
				cmyth_dbg(CMYTH_DBG_ERROR, "%s: realloc() failed for filelist list\n", __FUNCTION__);
				ref_release(ret);
				ret = NULL;
				goto out;
			}
		}
		file = cmyth_storagegroup_file_create();
		file->filename = ref_strdup(tmp_str);
		file->storagegroup = ref_strdup(storagegroup);
		file->hostname = ref_strdup(hostname);
		file->size = 0;
		file->lastmodified = 0;
		ret->storagegroup_filelist_list[res] = file;
		res++;
	}
	ret->storagegroup_filelist_count = res;

	for(i = 0;i < ret->storagegroup_filelist_count;i++) {
		cmyth_storagegroup_update_fileinfo(control, ret->storagegroup_filelist_list[i]);
	}

	cmyth_dbg(CMYTH_DBG_DEBUG, "%s: results= %d\n", __FUNCTION__, res);

    out:
	pthread_mutex_unlock(&control->conn_mutex);
	return ret;
}
Пример #8
0
cmyth_proginfo_t
cmyth_proginfo_get_from_timeslot(cmyth_conn_t control, uint32_t chanid, const cmyth_timestamp_t recstartts)
{
	int err = 0;
	int count, i;
	char msg[4096];
	cmyth_proginfo_t prog = NULL;
	cmyth_proglist_t list = NULL;
	char time[15];

	if (!control) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no connection\n",
			  __FUNCTION__);
		return NULL;
	}

	if ((err = cmyth_timestamp_to_numstring(time, recstartts)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_timestamp_to_numstring() failed (%d)\n",
			  __FUNCTION__, err);
		return NULL;
	}

	if(control->conn_version >= 32) {
		pthread_mutex_lock(&control->conn_mutex);

		snprintf(msg, sizeof(msg), "QUERY_RECORDING TIMESLOT %"PRIu32" %s",
			chanid, time);

		if ((err=cmyth_send_message(control, msg)) < 0) {
			cmyth_dbg(CMYTH_DBG_ERROR,
				  "%s: cmyth_send_message() failed (%d)\n",
				  __FUNCTION__, err);
			goto out;
		}

		count = cmyth_rcv_length(control);
		if (count < 0) {
			cmyth_dbg(CMYTH_DBG_ERROR,
				  "%s: cmyth_rcv_length() failed (%d)\n",
				  __FUNCTION__, count);
			goto out;
		}

		i = cmyth_rcv_string(control, &err, msg, sizeof(msg), count);
		if (err) {
			cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_rcv_string() failed\n",
				  __FUNCTION__);
			goto out;
		}
		count -= i;

		if (strcmp(msg, "OK") != 0) {
			cmyth_dbg(CMYTH_DBG_ERROR, "%s: didn't recieve OK as response\n",
				  __FUNCTION__);
			goto out;
		}

		prog = cmyth_proginfo_create();
		if (cmyth_rcv_proginfo(control, &err, prog, count) != count) {
			cmyth_dbg(CMYTH_DBG_ERROR,
				  "%s: cmyth_rcv_proginfo() < count\n", __FUNCTION__);
			goto out;
		}

		pthread_mutex_unlock(&control->conn_mutex);
		return prog;
		out:
		pthread_mutex_unlock(&control->conn_mutex);
		if(prog)
			ref_release(prog);
		return NULL;

	} else {

		list = cmyth_proglist_get_all_recorded(control);
		if (!list) {
			cmyth_dbg(CMYTH_DBG_ERROR, "%s: no program list\n",
				  __FUNCTION__);
		}

		count = cmyth_proglist_get_count(list);
		for (i = 0;i < count; i++) {
			prog = cmyth_proglist_get_item(list, i);
			if (!prog) {
				cmyth_dbg(CMYTH_DBG_DEBUG, "%s: no program info\n",
					  __FUNCTION__);
				continue;
			}
			if (cmyth_timestamp_compare(prog->proginfo_rec_start_ts, recstartts) != 0 ||
					prog->proginfo_chanId != chanid) {
				ref_release(prog);
				prog = NULL;
				continue;
			}
			break;
		}
		ref_release(list);
		return prog;
	}

}
Пример #9
0
/*
 * cmyth_proginfo_stop_recording()
 *
 * Scope: PUBLIC
 *
 * Description
 *
 * Make a request on the control connection 'control' to ask the
 * MythTV back end to stop recording the program described in 'prog'.
 *
 * Return Value:
 *
 * Success: 0
 *
 * Failure: -(ERRNO)
 */
int
cmyth_proginfo_stop_recording(cmyth_conn_t control, cmyth_proginfo_t prog)
{
	int32_t c = 0;
	int err = 0;
	int count = 0;
	int r = 0;
	int ret = 0;
	char *buf;
	char *proginfo;

	if (!control) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no connection\n",
			  __FUNCTION__);
		return -EINVAL;
	}
	if (control->conn_version < 12)
	{
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: stop not supported with protocol ver %d\n",
			  __FUNCTION__, control->conn_version);
		return -EINVAL;
	}

	proginfo = cmyth_proginfo_string(control, prog);
	if (proginfo == NULL) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: program_info failed.\n",
			  __FUNCTION__);
		return -EINVAL;
	}

	buf = malloc(strlen(proginfo) + 21 + 1);
	if (!buf) {
		free(proginfo);
		return -ENOMEM;
	}
	sprintf(buf, "STOP_RECORDING 0[]:[]%s", proginfo);
	free(proginfo);

	pthread_mutex_lock(&control->conn_mutex);

	if ((err = cmyth_send_message(control, buf)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_send_message() failed (%d)\n",
			  __FUNCTION__, err);
		ret = err;
		goto out;
	}

	count = cmyth_rcv_length(control);
	if ((r = cmyth_rcv_int32(control, &err, &c, count)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_length() failed (%d)\n",
			  __FUNCTION__, r);
		ret = err;
		goto out;
	}

	out:
	pthread_mutex_unlock(&control->conn_mutex);
	free(buf);

	return ret;
}
Пример #10
0
/*
 * cmyth_proginfo_fill()
 *
 * Scope: PRIVATE (static)
 *
 * Description
 *
 * Fill out a (possibly incomplete) program info.  Incomplete program
 * info comes from program listings.  Since this modifies the contents of
 * the supplied program info, it must never be called with a program info
 * that has more than one reference).
 *
 * Return Value:
 *
 * Success: 0
 *
 * Failure: a negative error code.
 */
static int
cmyth_proginfo_fill(cmyth_conn_t control, cmyth_proginfo_t prog)
{
	int err = 0;
	int count = 0;
	int ret = 0;
	char *buf;
	char *proginfo;
	int64_t length = 0;

	if (!control) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no connection\n",
			  __FUNCTION__);
		return -EINVAL;
	}
	if (!prog) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no program info\n",
			  __FUNCTION__);
		return -EINVAL;
	}

	proginfo = cmyth_proginfo_string(control, prog);
	if (proginfo == NULL) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: program_info failed.\n",
			  __FUNCTION__);
		return -EINVAL;
	}

	buf = malloc(strlen(proginfo) + 34 + 1);
	if (!buf) {
		free(proginfo);
		return -ENOMEM;
	}
	sprintf(buf, "FILL_PROGRAM_INFO cmyth[]:[]0[]:[]%s", proginfo);
	free(proginfo);

	pthread_mutex_lock(&control->conn_mutex);

	length = prog->proginfo_Length;

	if ((err = cmyth_send_message(control, buf)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_send_message() failed (%d)\n",
			  __FUNCTION__, err);
		ret = err;
		goto out;
	}

	count = cmyth_rcv_length(control);
	if (count < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_length() failed (%d)\n",
			  __FUNCTION__, count);
		ret = count;
		goto out;
	}
	if (cmyth_rcv_proginfo(control, &err, prog, count) != count) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_proginfo() < count\n", __FUNCTION__);
		ret = err;
		goto out;
	}

	/*
	 * Myth seems to cache the program length, rather than call stat()
	 * every time it needs to know.  Using FILL_PROGRAM_INFO has worked
	 * to force mythbackend to call stat() and return the correct length.
	 *
	 * However, some users are reporting that FILL_PROGRAM_INFO is
	 * returning 0 for the program length.  In that case, the original
	 * number is still probably wrong, but it's better than 0.
	 */
	if (prog->proginfo_Length == 0) {
		prog->proginfo_Length = length;
	}

	out:
	pthread_mutex_unlock(&control->conn_mutex);
	free(buf);

	return ret;
}
Пример #11
0
cmyth_proginfo_t
cmyth_proginfo_get_from_basename(cmyth_conn_t control, const char* basename)
{
	int err = 0;
	int count, i;
	char msg[4096];
	char *base;
	cmyth_proginfo_t prog = NULL;
	cmyth_proglist_t list = NULL;

	if (!control) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no connection\n",
			  __FUNCTION__);
		return NULL;
	}

	/*
	 * mythbackend doesn't support spaces in basenames
	 * when doing QUERY_RECORDING.  If there are spaces, fallback
	 * to enumerating all recordings
	 */
	if(control->conn_version >= 32 && strchr(basename, ' ') == NULL) {
		pthread_mutex_lock(&control->conn_mutex);

		snprintf(msg, sizeof(msg), "QUERY_RECORDING BASENAME %s",
			 basename);

		if ((err=cmyth_send_message(control, msg)) < 0) {
			cmyth_dbg(CMYTH_DBG_ERROR,
				  "%s: cmyth_send_message() failed (%d)\n",
			  	__FUNCTION__, err);
			goto out;
		}

		count = cmyth_rcv_length(control);
		if (count < 0) {
			cmyth_dbg(CMYTH_DBG_ERROR,
				  "%s: cmyth_rcv_length() failed (%d)\n",
				  __FUNCTION__, count);
			goto out;
		}

		i = cmyth_rcv_string(control, &err, msg, sizeof(msg), count);
		if (err) {
			cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_rcv_string() failed\n",
				  __FUNCTION__);
			goto out;
		}
		count -= i;

		if (strcmp(msg, "OK") != 0) {
			cmyth_dbg(CMYTH_DBG_ERROR, "%s: didn't recieve OK as response\n",
				  __FUNCTION__);
			goto out;
		}

		prog = cmyth_proginfo_create();
		if (cmyth_rcv_proginfo(control, &err, prog, count) != count) {
			cmyth_dbg(CMYTH_DBG_ERROR,
				  "%s: cmyth_rcv_proginfo() < count\n", __FUNCTION__);
			goto out;
		}

		pthread_mutex_unlock(&control->conn_mutex);
		return prog;
		out:
		pthread_mutex_unlock(&control->conn_mutex);
		if(prog)
			ref_release(prog);
		return NULL;

	} else {

		list = cmyth_proglist_get_all_recorded(control);
		if (!list) {
			cmyth_dbg(CMYTH_DBG_ERROR, "%s: no program list\n",
				  __FUNCTION__);
		}

		count = cmyth_proglist_get_count(list);
		for (i = 0;i < count; i++) {
			prog = cmyth_proglist_get_item(list, i);
			if (!prog) {
				cmyth_dbg(CMYTH_DBG_DEBUG, "%s: no program info\n",
					  __FUNCTION__);
				continue;
			}
			base = strrchr(prog->proginfo_pathname, '/');
			if (!base || strcmp(base+1, basename) !=0) {
				ref_release(prog);
				prog = NULL;
				continue;
			}
			break;
		}
		ref_release(list);
		return prog;
	}

}
Пример #12
0
/*
 * cmyth_ringbuf_seek(
 *                    cmyth_ringbuf_t file, long long offset, int whence)
 * 
 * Scope: PUBLIC
 *
 * Description
 *
 * Seek to a new position in the file based on the value of whence:
 *	SEEK_SET
 *		The offset is set to offset bytes.
 *	SEEK_CUR
 *		The offset is set to the current position plus offset bytes.
 *	SEEK_END
 *		The offset is set to the size of the file minus offset bytes.
 *
 * Return Value:
 *
 * Sucess: 0
 *
 * Failure: an int containing -errno
 */
long long
cmyth_ringbuf_seek(cmyth_recorder_t rec,
		   long long offset, int whence)
{
	char msg[128];
	int err;
	int count;
	long long c;
	long r;
	long long ret;
	cmyth_ringbuf_t ring;

	if (rec == NULL)
		return -EINVAL;

	ring = rec->rec_ring;

	if ((offset == 0) && (whence == SEEK_CUR))
		return ring->file_pos;

	pthread_mutex_lock(&mutex);

	snprintf(msg, sizeof(msg),
		 "QUERY_RECORDER %u[]:[]SEEK_RINGBUF[]:[]%d[]:[]%d[]:[]%d[]:[]%d[]:[]%d",
		 rec->rec_id,
		 (int32_t)(offset >> 32),
		 (int32_t)(offset & 0xffffffff),
		 whence,
		 (int32_t)(ring->file_pos >> 32),
		 (int32_t)(ring->file_pos & 0xffffffff));

	if ((err = cmyth_send_message(rec->rec_conn, msg)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_send_message() failed (%d)\n",
			  __FUNCTION__, err);
		ret = err;
		goto out;
	}

	count = cmyth_rcv_length(rec->rec_conn);
	if ((r=cmyth_rcv_long_long(rec->rec_conn, &err, &c, count)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_length() failed (%d)\n",
			  __FUNCTION__, r);
		ret = err;
		goto out;
	}

	switch (whence) {
	case SEEK_SET:
		ring->file_pos = offset;
		break;
	case SEEK_CUR:
		ring->file_pos += offset;
		break;
	case SEEK_END:
		ring->file_pos = ring->file_length - offset;
		break;
	}

	ret = ring->file_pos;

    out:
	pthread_mutex_unlock(&mutex);
	
	return ret;
}
Пример #13
0
/*
 * cmyth_ringbuf_read (cmyth_recorder_t rec, char *buf, unsigned long len)
 * 
 * Scope: PUBLIC
 *
 * Description
 *
 * Request and read a block of data from backend
 *
 * Return Value:
 *
 * Sucess: number of bytes transfered
 *
 * Failure: an int containing -errno
 */
int cmyth_ringbuf_read(cmyth_recorder_t rec, char *buf, unsigned long len)
{
	int err, count;
	int ret, req, nfds;
	char *end, *cur;
	char msg[256];
	struct timeval tv;
	fd_set fds;

	if (!rec)
	{
		cmyth_dbg (CMYTH_DBG_ERROR, "%s: no connection\n",
		           __FUNCTION__);
		return -EINVAL;
	}

	pthread_mutex_lock (&mutex);

	snprintf(msg, sizeof(msg),
		 "QUERY_RECORDER %u[]:[]REQUEST_BLOCK_RINGBUF[]:[]%ld",
		 rec->rec_id, len);

	if ( (err = cmyth_send_message (rec->rec_conn, msg) ) < 0)
	{
		cmyth_dbg (CMYTH_DBG_ERROR,
		           "%s: cmyth_send_message() failed (%d)\n",
		           __FUNCTION__, err);
		ret = err;
		goto out;
	}

	nfds = 0;
	req = 1;
	cur = buf;
	end = buf+len;

	while (cur < end || req)
	{
		tv.tv_sec = 20;
		tv.tv_usec = 0;
		FD_ZERO (&fds);
		if(req) {
			if((int)rec->rec_conn->conn_fd > nfds)
				nfds = (int)rec->rec_conn->conn_fd;
			FD_SET (rec->rec_conn->conn_fd, &fds);
		}
		if((int)rec->rec_ring->conn_data->conn_fd > nfds)
			nfds = (int)rec->rec_ring->conn_data->conn_fd;
		FD_SET (rec->rec_ring->conn_data->conn_fd, &fds);

		if ((ret = select (nfds+1, &fds, NULL, NULL,&tv)) < 0)
		{
			cmyth_dbg (CMYTH_DBG_ERROR,
			           "%s: select(() failed (%d)\n",
			           __FUNCTION__, ret);
			goto out;
		}

		if (ret == 0)
		{
			rec->rec_ring->conn_data->conn_hang = 1;
			rec->rec_conn->conn_hang = 1;
			ret = -ETIMEDOUT;
			goto out;
		}

		/* check control connection */
		if (FD_ISSET(rec->rec_conn->conn_fd, &fds) )
		{

			if ((count = cmyth_rcv_length (rec->rec_conn)) < 0)
			{
				cmyth_dbg (CMYTH_DBG_ERROR,
				           "%s: cmyth_rcv_length() failed (%d)\n",
				           __FUNCTION__, count);
				ret = count;
				goto out;
			}

			if ((ret = cmyth_rcv_ulong (rec->rec_conn, &err, &len, count))< 0)
			{
				cmyth_dbg (CMYTH_DBG_ERROR,
				           "%s: cmyth_rcv_long() failed (%d)\n",
				           __FUNCTION__, ret);
				ret = err;
				goto out;
			}

			rec->rec_ring->file_pos += len;
			req = 0;
			end = buf+len;
		}

		/* check data connection */
		if (FD_ISSET(rec->rec_ring->conn_data->conn_fd, &fds))
		{

			if ((ret = recv (rec->rec_ring->conn_data->conn_fd, cur, end-cur, 0)) < 0)
			{
				cmyth_dbg (CMYTH_DBG_ERROR,
				           "%s: recv() failed (%d)\n",
				           __FUNCTION__, ret);
				goto out;
			}
			cur += ret;
		}
	}

	ret = end - buf;
out:
	pthread_mutex_unlock (&mutex);
	return ret;
}
Пример #14
0
/*
 * cmyth_ringbuf_setup(cmyth_recorder_t old_rec)
 * 
 * Scope: PUBLIC
 *
 * Description
 *
 * Set up the ring buffer inside a recorder for use in playing live
 * tv.  The recorder is supplied.  This will be duplicated and
 * released, so the caller can re-use the same variable to hold the
 * return.  The new copy of the recorder will have a ringbuffer set up
 * within it.
 *
 * Return Value:
 *
 * Success: A pointer to a new recorder structure with a ringbuffer
 *
 * Faiure: NULL
 */
cmyth_recorder_t
cmyth_ringbuf_setup(cmyth_recorder_t rec)
{
	static const char service[]="rbuf://";
	cmyth_recorder_t new_rec = NULL;
	char *host = NULL;
	char *port = NULL;
	char *path = NULL;
	char tmp;

	int err, count;
	int r;
	long long size, fill;
	char msg[256];
	char url[1024];
	char buf[32];
	cmyth_conn_t control;

	if (!rec) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no recorder connection\n",
			  __FUNCTION__);
		return NULL;
	}

	control = rec->rec_conn;

	pthread_mutex_lock(&mutex);

	snprintf(msg, sizeof(msg),
		 "QUERY_RECORDER %u[]:[]SETUP_RING_BUFFER[]:[]0",
		 rec->rec_id);

	if ((err=cmyth_send_message(control, msg)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_send_message() failed (%d)\n",
			  __FUNCTION__, err);
		goto out;
	}

	count = cmyth_rcv_length(control);

	if (control->conn_version >= 16) {
		r = cmyth_rcv_string(control, &err, buf, sizeof(buf)-1, count);
		count -= r;
	}
	r = cmyth_rcv_string(control, &err, url, sizeof(url)-1, count); 
	count -= r;

	if ((r=cmyth_rcv_long_long(control, &err, &size, count)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_length() failed (%d)\n",
			  __FUNCTION__, r);
		goto out;
	}
	count -= r;

	if ((r=cmyth_rcv_long_long(control, &err, &fill, count)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_length() failed (%d)\n",
			  __FUNCTION__, r);
		goto out;
	}

	cmyth_dbg(CMYTH_DBG_DEBUG, "%s: url is: '%s'\n",
		  __FUNCTION__, url);
	path = url;
	if (strncmp(url, service, sizeof(service) - 1) == 0) {
		/*
		 * The URL starts with rbuf://.  The rest looks like
		 * <host>:<port>/<filename>.
		 */
		host = url + strlen(service);
		port = strchr(host, ':');
		if (!port) {
			/*
			 * This does not seem to be a proper URL, so just
			 * assume it is a filename, and get out.
			 */
			cmyth_dbg(CMYTH_DBG_DEBUG,
				  "%s: 1 port %s, host = %s\n",
				  __FUNCTION__, port, host);
			goto out;
		}
		port = port + 1;
		path = strchr(port, '/');
		if (!path) {
			/*
			 * This does not seem to be a proper URL, so just
			 * assume it is a filename, and get out.
			 */
			cmyth_dbg(CMYTH_DBG_DEBUG, "%s: no path\n",
				  __FUNCTION__);
			goto out;
		}
	}

	new_rec = cmyth_recorder_dup(rec);
	if (new_rec == NULL) {
		cmyth_dbg(CMYTH_DBG_DEBUG, "%s: cannot create recorder\n",
			  __FUNCTION__);
		goto out;
	}
	ref_release(rec);
        new_rec->rec_ring = cmyth_ringbuf_create();
        
	tmp = *(port - 1);
	*(port - 1) = '\0';
	new_rec->rec_ring->ringbuf_hostname = ref_strdup(host);
	*(port - 1) = tmp;
	tmp = *(path);
	*(path) = '\0';
	new_rec->rec_ring->ringbuf_port = atoi(port);
	*(path) = tmp;
	new_rec->rec_ring->ringbuf_url = ref_strdup(url);
	new_rec->rec_ring->ringbuf_size = size;
	new_rec->rec_ring->ringbuf_fill = fill;

    out:
	pthread_mutex_unlock(&mutex);

	return new_rec;
}
Пример #15
0
static cmyth_conn_t
cmyth_conn_connect(char *server, unsigned short port, unsigned buflen,
		   int tcp_rcvbuf, int event)
{
	cmyth_conn_t conn;
	char announcement[256];
	unsigned long tmp_ver;
	int attempt = 0;

    top:
	conn = cmyth_connect(server, port, buflen, tcp_rcvbuf);
	if (!conn) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_connect(%s, %d, %d) failed\n",
			  __FUNCTION__, server, port, buflen);
		return NULL;
	}

	/*
	 * Find out what the Myth Protocol Version is for this connection.
	 * Loop around until we get agreement from the server.
	 */
	if (attempt == 0)
		tmp_ver = conn->conn_version;
	conn->conn_version = tmp_ver;

	/*
	 * Myth 0.23.1 (Myth 0.23 + fixes) introduced an out of sequence protocol version number (23056)
	 * due to the next protocol version number having already been bumped in trunk.
	 *
	 * http://www.mythtv.org/wiki/Myth_Protocol
	 */
	if (tmp_ver >= 62 && tmp_ver != 23056) { // Treat protocol version number 23056 the same as protocol 56
		myth_protomap_t *map = protomap;
		while (map->version != 0 && map->version != tmp_ver)
			map++;
		if (map->version == 0) {
			cmyth_dbg(CMYTH_DBG_ERROR,
				  "%s: failed to connect with any version\n",
				  __FUNCTION__);
			goto shut;
		}
		sprintf(announcement, "MYTH_PROTO_VERSION %ld %s", conn->conn_version, map->token);
	} else {
		sprintf(announcement, "MYTH_PROTO_VERSION %ld", conn->conn_version);
	}
	if (cmyth_send_message(conn, announcement) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_send_message('%s') failed\n",
			  __FUNCTION__, announcement);
		goto shut;
	}
	if (cmyth_rcv_version(conn, &tmp_ver) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_version() failed\n",
			  __FUNCTION__);
		goto shut;
	}
	cmyth_dbg(CMYTH_DBG_ERROR,
		  "%s: asked for version %ld, got version %ld\n",
		  __FUNCTION__, conn->conn_version, tmp_ver);
	if (conn->conn_version != tmp_ver) {
		if (attempt == 1) {
			cmyth_dbg(CMYTH_DBG_ERROR,
				  "%s: failed to connect with any version\n",
				  __FUNCTION__);
			goto shut;
		}
		attempt = 1;
		ref_release(conn);
		goto top;
	}
	cmyth_dbg(CMYTH_DBG_PROTO, "%s: agreed on Version %ld protocol\n",
		  __FUNCTION__, conn->conn_version);

	sprintf(announcement, "ANN Playback %s %d", my_hostname, event);
	if (cmyth_send_message(conn, announcement) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_send_message('%s') failed\n",
			  __FUNCTION__, announcement);
		goto shut;
	}
	if (cmyth_rcv_okay(conn, "OK") < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_rcv_okay() failed\n",
			  __FUNCTION__);
		goto shut;
	}

	/*
	 * All of the downstream code in libcmyth assumes a monotonically increasing version number.
	 * This was not the case for Myth 0.23.1 (0.23 + fixes) where protocol version number 23056
	 * was used since 57 had already been used in trunk.
	 *
	 * Convert from protocol version number 23056 to version number 56 so subsequent code within
	 * libcmyth uses the same logic for the 23056 protocol as would be used for protocol version 56.
	 */
	if (conn->conn_version == 23056) {
		conn->conn_version = 56;
	}

	return conn;

    shut:
	ref_release(conn);
	return NULL;
}
Пример #16
0
Файл: file.c Проект: tsp/cmyth
/*
 * cmyth_file_seek(cmyth_file_t file, long long offset, int whence)
 * 
 * Scope: PUBLIC
 *
 * Description
 *
 * Seek to a new position in the file based on the value of whence:
 *	SEEK_SET
 *		The offset is set to offset bytes.
 *	SEEK_CUR
 *		The offset is set to the current position plus offset bytes.
 *	SEEK_END
 *		The offset is set to the size of the file minus offset bytes.
 *
 * Return Value:
 *
 * Sucess: 0
 *
 * Failure: an int containing -errno
 */
long long
cmyth_file_seek(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;

	pthread_mutex_lock(&mutex);

	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,
			  "%s: cmyth_send_message() failed (%d)\n",
			  __FUNCTION__, err);
		ret = err;
		goto out;
	}

	if ((count=cmyth_rcv_length(file->file_control)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_length() failed (%d)\n",
			  __FUNCTION__, count);
		ret = count;
		goto out;
	}
	if ((r=cmyth_rcv_long_long(file->file_control, &err, &c, count)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_long_long() failed (%d)\n",
			  __FUNCTION__, r);
		ret = err;
		goto out;
	}

	switch (whence) {
	case SEEK_SET:
		file->file_pos = offset;
		break;
	case SEEK_CUR:
		file->file_pos += offset;
		break;
	case SEEK_END:
		file->file_pos = file->file_length - offset;
		break;
	}

	ret = file->file_pos;

    out:
	pthread_mutex_unlock(&mutex);
	
	return ret;
}
Пример #17
0
/*
 * cmyth_conn_connect_path(char* path, cmyth_conn_t control,
 *                         unsigned buflen, int tcp_rcvbuf)
 *
 * Scope: PUBLIC
 *
 * Description:
 *
 * Create a file structure containing a data connection for use
 * transfering a file within the MythTV protocol.  Return a pointer to
 * the newly created file structure.  The connection in the file
 * structure is returned held as is the file structure itself.  The
 * connection will be released when the file structure is released.
 * The file structure can be released using ref_release().
 *
 * Return Value:
 *
 * Success: Non-NULL cmyth_file_t (this is a pointer type)
 *
 * Failure: NULL cmyth_file_t
 */
cmyth_file_t
cmyth_conn_connect_path(char* path, cmyth_conn_t control,
			unsigned buflen, int tcp_rcvbuf)
{
	cmyth_conn_t conn = NULL;
	char *announcement = NULL;
	char reply[16];
	char host[256];
	int err = 0;
	int count = 0;
	int r, port;
	int ann_size = sizeof("ANN FileTransfer []:[][]:[]");
	struct sockaddr_in addr;
        socklen_t addr_size = sizeof(addr);
	cmyth_file_t ret = NULL;

	if (getpeername(control->conn_fd, (struct sockaddr*)&addr, &addr_size)<0) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: getpeername() failed\n",
			  __FUNCTION__);
		goto shut;
	}

	inet_ntop(addr.sin_family, &addr.sin_addr, host, sizeof(host));
	port = ntohs(addr.sin_port);

	ret = cmyth_file_create(control);
	if (!ret) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_file_create() failed\n",
			  __FUNCTION__);
		goto shut;
	}

	cmyth_dbg(CMYTH_DBG_PROTO, "%s: connecting data connection\n",
		  __FUNCTION__);
	conn = cmyth_connect(host, port, buflen, tcp_rcvbuf);
	cmyth_dbg(CMYTH_DBG_PROTO,
		  "%s: done connecting data connection, conn = %p\n",
		  __FUNCTION__, conn);
	if (!conn) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_connect(%s, %d, %d) failed\n",
			  __FUNCTION__, host, port, buflen);
		goto shut;
	}
	ann_size += strlen(path) + strlen(my_hostname);
	announcement = malloc(ann_size);
	if (!announcement) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%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);
	}
	else {
		sprintf(announcement, "ANN FileTransfer %s[]:[]%s",
			  my_hostname, path);
	}
	if (cmyth_send_message(conn, announcement) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_send_message('%s') failed\n",
			  __FUNCTION__, announcement);
		goto shut;
	}
	ret->file_data = ref_hold(conn);
	count = cmyth_rcv_length(conn);
	if (count < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_length() failed (%d)\n",
			  __FUNCTION__, count);
		goto shut;
	}
	reply[sizeof(reply) - 1] = '\0';
	r = cmyth_rcv_string(conn, &err, reply, sizeof(reply) - 1, count); 
	if (err != 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_string() failed (%d)\n",
			  __FUNCTION__, err);
		goto shut;
	}
	if (strcmp(reply, "OK") != 0) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: reply ('%s') is not 'OK'\n",
			  __FUNCTION__, reply);
		goto shut;
	}
	count -= r;
	r = cmyth_rcv_long(conn, &err, &ret->file_id, count);
	if (err) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: (id) cmyth_rcv_long() failed (%d)\n",
			  __FUNCTION__, err);
		goto shut;
	}
	count -= r;
	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",
			  __FUNCTION__, err);
		goto shut;
	}
	count -= r;
	free(announcement);
	ref_release(conn);
	return ret;

    shut:
	if (announcement) {
		free(announcement);
	}
	ref_release(ret);
	ref_release(conn);
	return NULL;
}
Пример #18
0
/*
 * cmyth_conn_connect_path(char* path, cmyth_conn_t control,
 *                         unsigned buflen, int tcp_rcvbuf)
 *
 * Scope: PUBLIC
 *
 * Description:
 *
 * Create a file structure containing a data connection for use
 * transfering a file within the MythTV protocol.  Return a pointer to
 * the newly created file structure.  The connection in the file
 * structure is returned held as is the file structure itself.  The
 * connection will be released when the file structure is released.
 * The file structure can be released using ref_release().
 *
 * Return Value:
 *
 * Success: Non-NULL cmyth_file_t (this is a pointer type)
 *
 * Failure: NULL cmyth_file_t
 */
cmyth_file_t
cmyth_conn_connect_path(char* path, cmyth_conn_t control,
			unsigned buflen, int tcp_rcvbuf, char* storage_group)
{
	cmyth_conn_t conn = NULL;
	char *announcement = NULL;
	char reply[16];
	char host[256];
	int err = 0;
	int count = 0;
	int r, port;
	int ann_size = sizeof("ANN FileTransfer  0[]:[][]:[]");
	struct sockaddr_in addr;
        socklen_t addr_size = sizeof(addr);
	cmyth_file_t ret = NULL;

	if (getpeername(control->conn_fd, (struct sockaddr*)&addr, &addr_size)<0) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: getpeername() failed\n",
			  __FUNCTION__);
		goto shut;
	}

	inet_ntop(addr.sin_family, &addr.sin_addr, host, sizeof(host));
	port = ntohs(addr.sin_port);

	ret = cmyth_file_create(control);
	if (!ret) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_file_create() failed\n",
			  __FUNCTION__);
		goto shut;
	}

	cmyth_dbg(CMYTH_DBG_PROTO, "%s: connecting data connection\n",
		  __FUNCTION__);
	conn = cmyth_connect(host, port, buflen, tcp_rcvbuf);
	cmyth_dbg(CMYTH_DBG_PROTO,
		  "%s: done connecting data connection, conn = %p\n",
		  __FUNCTION__, conn);
	if (!conn) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_connect(%s, %d, %d) failed\n",
			  __FUNCTION__, host, 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(path) + strlen(my_hostname) + strlen(storage_group) + 6;
	announcement = malloc(ann_size);
	if (!announcement) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: malloc(%d) failed for announcement\n",
			  __FUNCTION__, ann_size);
		goto shut;
	}
	if (control->conn_version >= 44) { /*TSP: from version 44 according to the source code*/
		if (strlen(storage_group) > 1) {
			sprintf(announcement, "ANN FileTransfer %s 0 0 0[]:[]%s[]:[]%s",
				  my_hostname, path, storage_group);
		} else {
			sprintf(announcement, "ANN FileTransfer %s 0[]:[]%s[]:[]",  // write = false
				  my_hostname, path);
		}
	} else {
		sprintf(announcement, "ANN FileTransfer %s[]:[]%s",
			  my_hostname, path);
	}
	if (cmyth_send_message(conn, announcement) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_send_message('%s') failed\n",
			  __FUNCTION__, announcement);
		goto shut;
	}
	ret->file_data = ref_hold(conn);
	count = cmyth_rcv_length(conn);
	if (count < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_length() failed (%d)\n",
			  __FUNCTION__, count);
		goto shut;
	}
	reply[sizeof(reply) - 1] = '\0';
	r = cmyth_rcv_string(conn, &err, reply, sizeof(reply) - 1, count); 
	if (err != 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_string() failed (%d)\n",
			  __FUNCTION__, err);
		goto shut;
	}
	if (strcmp(reply, "OK") != 0) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: reply ('%s') is not 'OK'\n",
			  __FUNCTION__, reply);
		goto shut;
	}
	count -= r;
	r = cmyth_rcv_long(conn, &err, &ret->file_id, count);
	if (err) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: (id) cmyth_rcv_long() failed (%d)\n",
			  __FUNCTION__, err);
		goto shut;
	}
	count -= r;
	r = cmyth_rcv_uint64(conn, &err, &ret->file_length, count);
	if (err) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: (length) cmyth_rcv_uint64() failed (%d)\n",
			  __FUNCTION__, err);
		goto shut;
	}
	count -= r;
	free(announcement);
	ref_release(conn);
	return ret;

    shut:
	if (announcement) {
		free(announcement);
	}
	ref_release(ret);
	ref_release(conn);
	return NULL;
}
Пример #19
0
/*
 * cmyth_proglist_get_list()
 *
 * Scope: PRIVATE (static)
 *
 * Description
 *
 * Obtain a program list from the query specified in 'msg' from the
 * function 'func'.  Make the query on 'conn' and put the results in
 * 'proglist'.
 *
 * Return Value:
 *
 * Success: 0
 *
 * Failure: -(ERRNO)
 */
static int
cmyth_proglist_get_list(cmyth_conn_t conn,
                        cmyth_proglist_t proglist,
                        char *msg, const char *func)
{
    int err = 0;
    int count;
    int ret;

    if (!conn) {
        cmyth_dbg(CMYTH_DBG_ERROR, "%s: no connection\n", func);
        return -EINVAL;
    }
    if (!proglist) {
        cmyth_dbg(CMYTH_DBG_ERROR, "%s: no program list\n", func);
        return -EINVAL;
    }

    pthread_mutex_lock(&conn->conn_mutex);

    if ((err = cmyth_send_message(conn, msg)) < 0) {
        cmyth_dbg(CMYTH_DBG_ERROR,
                  "%s: cmyth_send_message() failed (%d)\n",
                  func, err);
        ret = err;
        goto out;
    }
    count = cmyth_rcv_length(conn);
    if (count < 0) {
        cmyth_dbg(CMYTH_DBG_ERROR,
                  "%s: cmyth_rcv_length() failed (%d)\n",
                  func, count);
        ret = count;
        goto out;
    }
    if (strcmp(msg, "QUERY_GETALLPENDING") == 0) {
        int32_t c;
        int r;
        if ((r = cmyth_rcv_int32(conn, &err, &c, count)) < 0) {
            cmyth_dbg(CMYTH_DBG_ERROR,
                      "%s: cmyth_rcv_length() failed (%d)\n",
                      __FUNCTION__, r);
            ret = err;
            goto out;
        }
        count -= r;
    }
    if (cmyth_rcv_proglist(conn, &err, proglist, count) != count) {
        cmyth_dbg(CMYTH_DBG_ERROR,
                  "%s: cmyth_rcv_proglist() < count\n",
                  func);
    }
    if (err) {
        cmyth_dbg(CMYTH_DBG_ERROR,
                  "%s: cmyth_rcv_proglist() failed (%d)\n",
                  func, err);
        ret = -1 * err;
        goto out;
    }

    ret = 0;

out:
    pthread_mutex_unlock(&conn->conn_mutex);

    return ret;
}
Пример #20
0
char *
cmyth_conn_get_backend_hostname(cmyth_conn_t conn)
{
	int count, err;
	char* result = NULL;

  pthread_mutex_lock(&mutex);
	if(conn->conn_version < 17) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: protocol version doesn't support QUERY_HOSTNAME\n",
			  __FUNCTION__);
		return NULL;
	}

	if (!conn) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no connection\n",
			  __FUNCTION__);
		return NULL;
	}

	if ((err = cmyth_send_message(conn,  "QUERY_HOSTNAME")) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_send_message() failed (%d)\n",
			  __FUNCTION__, err);
		goto err;
	}

	if ((count=cmyth_rcv_length(conn)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_length() failed (%d)\n",
			  __FUNCTION__, count);
		goto err;
	}

	result = ref_alloc(count+1);
	count -= cmyth_rcv_string(conn, &err,
				    result, count, count);
	if (err < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_string() failed (%d)\n",
			  __FUNCTION__, err);
		goto err;
	}

	while(count > 0 && !err) {
		char buffer[100];
		count -= cmyth_rcv_string(conn, &err, buffer, sizeof(buffer)-1, count);
		buffer[sizeof(buffer)-1] = 0;
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: odd left over data %s\n", __FUNCTION__, buffer);
	}
	pthread_mutex_unlock(&mutex);

	if(!strcmp("-1",result))  {
		cmyth_dbg(CMYTH_DBG_PROTO, "%s: Failed to retrieve backend hostname.\n",
			  __FUNCTION__);
	return NULL;
	}
	return result;

err:
	pthread_mutex_unlock(&mutex);
	if(result)
		ref_release(result);

	return NULL;
}
Пример #21
0
cmyth_storagegroup_file_t
cmyth_storagegroup_get_fileinfo(cmyth_conn_t control, char *storagegroup, char *hostname, char *filename)
{
	char msg[256];
	int count = 0;
	int err = 0;
	cmyth_storagegroup_file_t ret = NULL;
	int consumed = 0;
	char tmp_str[2048];

	if (!control) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no connection\n", __FUNCTION__);
		return 0;
	}

	pthread_mutex_lock(&control->conn_mutex);

	snprintf(msg, sizeof(msg), "QUERY_SG_FILEQUERY[]:[]%s[]:[]%s[]:[]%s", hostname, storagegroup, filename);

	err = cmyth_send_message(control, msg);
	if (err < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_send_message() failed (%d)\n", __FUNCTION__, err);
		goto out;
	}

	count = cmyth_rcv_length(control);
	if (count < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_rcv_length() failed (%d)\n", __FUNCTION__, count);
		goto out;
	}

	consumed = cmyth_rcv_string(control, &err, tmp_str, sizeof(tmp_str) - 1, count);
	count -= consumed;
	if (err) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_rcv_string() failed (%d)\n", __FUNCTION__, count);
		ret = NULL;
		goto out;
	} else if (count == 0) {
		cmyth_dbg(CMYTH_DBG_WARN, "%s: QUERY_SG_FILEQUERY failed(%s)\n", __FUNCTION__, tmp_str);
		ret = NULL;
		goto out;
	}

	ret = cmyth_storagegroup_file_create();
	if (!ret) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: alloc() failed for file\n", __FUNCTION__);
		ref_release(ret);
		ret = NULL;
		goto out;
	}
	ret->filename = ref_strdup(tmp_str);

	consumed = cmyth_rcv_string(control, &err, tmp_str, sizeof(tmp_str) - 1, count);
	count -= consumed;
	if (err) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_rcv_string() failed (%d)\n", __FUNCTION__, count);
		ref_release(ret);
		ret = NULL;
		goto out;
	}
        ret->lastmodified = atol(tmp_str);

	consumed = cmyth_rcv_new_int64(control, &err, &(ret->size), count, 1);
	count -= consumed;
	if (err) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_rcv_int64() failed (%d)\n", __FUNCTION__, count);
		ref_release(ret);
		ret = NULL;
		goto out;
	}

	cmyth_dbg(CMYTH_DBG_DEBUG, "%s: filename: %s\n", __FUNCTION__, ret->filename);

out:
	pthread_mutex_unlock(&control->conn_mutex);
	return ret;
}
Пример #22
0
/*
 * cmyth_conn_reschedule_recordings(cmyth_conn_t rec, int recordid)
 *
 * Scope: PUBLIC
 *
 * Description
 *
 * Issues a run of the re-scheduler.
 * Takes an optional recordid, or -1 performs a full run.
 *
 * Return Value:
 *
 * Success: 0
 *
 * Failure: -(ERRNO)
 */
int
cmyth_conn_reschedule_recordings(cmyth_conn_t conn, int recordid)
{
	int err = 0;
	int id;
	char msg[256];

	if (conn->conn_version < 15) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: protocol version doesn't support RESCHEDULE_RECORDINGS\n",
			  __FUNCTION__);
		return -1;
	}

	/*
	 * RESCHEDULE_RECORDINGS changed in protocol version 73:
	 *
	 * MATCH reschedule requests should be used when the guide data or a
	 * specific recording rule is changed. The syntax is as follows.
	 *
	 *    MATCH <recordid> <sourceid> <mplexid> <maxstarttime> <reason>
	 *
	 * CHECK reschedule requests should be used when the status of a
	 * specific episode is affected such as when "never record" or "allow
	 * re-record" are selected or a recording finishes or is deleted. The
	 * syntax is as follows.
	 *
	 *    CHECK <recstatus> <recordid> <findid> <reason>
	 *    <title>
	 *    <subtitle>
	 *    <description>
	 *    <programid>
	 */
	if (conn->conn_version < 73) {
		id = (recordid > 0 ? recordid : -1);
		snprintf(msg, sizeof(msg), "RESCHEDULE_RECORDINGS %i", id);
	} else {
		if (recordid == 0) {
			strncpy(msg, "RESCHEDULE_RECORDINGS []:[]CHECK 0 0 0 cmyth[]:[][]:[][]:[][]:[]**any**", sizeof(msg));
		} else {
			id = (recordid > 0 ? recordid : 0);
			snprintf(msg, sizeof(msg), "RESCHEDULE_RECORDINGS []:[]MATCH %i 0 0 - cmyth", id);
		}
	}

	pthread_mutex_lock(&mutex);

	if ((err = cmyth_send_message(conn, msg)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_send_message() failed (%d)\n",
			  __FUNCTION__, err);
		goto out;
	}

	if ((err=cmyth_rcv_feedback(conn, "1")) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_feedback() failed (%d)\n",
			  __FUNCTION__, err);
		goto out;
	}

out:
	pthread_mutex_unlock(&mutex);
	return err;
}
Пример #23
0
/*
 * cmyth_recorder_get_next_program_info(cmyth_recorder_t rec,
 *                                      cmyth_proginfo_t proginfo,
 *                                      cmyth_browsedir_t direction)
 *
 * Scope: PRIVATE (static)
 *
 * Description:
 *
 * Request program information from the recorder 'rec' for the next
 * program in the program guide from the current program (i.e. current
 * channel and time slot) in the direction specified by 'direction'
 * which may have any of the following values:
 *
 *     BROWSE_DIRECTION_SAME        - Stay in the same place
 *     BROWSE_DIRECTION_UP          - Move up one slot (down one channel)
 *     BROWSE_DIRECTION_DOWN        - Move down one slot (up one channel)
 *     BROWSE_DIRECTION_LEFT        - Move left one slot (down one time slot)
 *     BROWSE_DIRECTION_RIGHT       - Move right one slot (up one time slot)
 *     BROWSE_DIRECTION_FAVORITE    - Move to the next favorite slot
 *
 * The program information will be used to fill out 'proginfo'.
 *
 * This does not affect the current recording.
 *
 * Return Value:
 *
 * Success: 1 - valid channel, 0 - invalid channel
 *
 * Failure: -(ERRNO)
 */
int
cmyth_recorder_get_next_program_info(cmyth_recorder_t rec,
				     cmyth_proginfo_t cur_prog,
				     cmyth_proginfo_t next_prog,
				     cmyth_browsedir_t direction)
{
        int err, count;
        int ret = -ENOSYS;
        char msg[256];
        char title[256], subtitle[256], desc[256], category[256];
	char callsign[256], iconpath[256];
	char channelname[256], chanid[256], seriesid[256], programid[256];
	char date[256];
	struct tm *tm;
	time_t t;
	cmyth_conn_t control;

        if (!rec) {
                cmyth_dbg(CMYTH_DBG_ERROR, "%s: no recorder connection\n",
                          __FUNCTION__);
                return -ENOSYS;
        }

	control = rec->rec_conn;

        pthread_mutex_lock(&mutex);

	t = time(NULL);
	tm = localtime(&t);
	snprintf(date, sizeof(date), "%.4d%.2d%.2d%.2d%.2d%.2d",
		 tm->tm_year + 1900, tm->tm_mon + 1,
		 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);

        snprintf(msg, sizeof(msg), "QUERY_RECORDER %d[]:[]GET_NEXT_PROGRAM_INFO[]:[]%s[]:[]%ld[]:[]%i[]:[]%s",
                 rec->rec_id, cur_prog->proginfo_channame,
		 cur_prog->proginfo_chanId, direction, date);

        if ((err=cmyth_send_message(control, msg)) < 0) {
                cmyth_dbg(CMYTH_DBG_ERROR,
                          "%s: cmyth_send_message() failed (%d)\n",
                          __FUNCTION__, err);
                ret = err;
                goto out;
        }

        count = cmyth_rcv_length(control);

	count -= cmyth_rcv_string(control, &err,
				  title, sizeof(title), count);
	count -= cmyth_rcv_string(control, &err,
				  subtitle, sizeof(subtitle), count);
	count -= cmyth_rcv_string(control, &err,
				  desc, sizeof(desc), count);
	count -= cmyth_rcv_string(control, &err,
				  category, sizeof(category), count);
	count -= cmyth_rcv_timestamp(control, &err,
				     &next_prog->proginfo_start_ts, count);
	count -= cmyth_rcv_timestamp(control, &err,
				     &next_prog->proginfo_end_ts, count);
	count -= cmyth_rcv_string(control, &err,
				  callsign, sizeof(callsign), count);
	count -= cmyth_rcv_string(control, &err,
				  iconpath, sizeof(iconpath), count);
	count -= cmyth_rcv_string(control, &err,
				  channelname, sizeof(channelname), count);
	count -= cmyth_rcv_string(control, &err,
				  chanid, sizeof(chanid), count);
	if (control->conn_version >= 12) {
		count -= cmyth_rcv_string(control, &err,
					  seriesid, sizeof(seriesid), count);
		count -= cmyth_rcv_string(control, &err,
					  programid, sizeof(programid), count);
	}

	if (count != 0) {
		ret = -1;
		goto out;
	}

	/*
	 * if the program info is blank, return an error
	 */
	if ((strlen(title) == 0) && (strlen(subtitle) == 0) &&
	    (strlen(desc) == 0) && (strlen(channelname) == 0) &&
	    (strlen(chanid) == 0)) {
                cmyth_dbg(CMYTH_DBG_ERROR,
                          "%s: blank channel found\n", __FUNCTION__);
		ret = -1;
		goto out;
	}

	next_prog->proginfo_title = ref_strdup(title);
	next_prog->proginfo_subtitle = ref_strdup(subtitle);
	next_prog->proginfo_description = ref_strdup(desc);
	next_prog->proginfo_channame = ref_strdup(channelname);
	next_prog->proginfo_chansign = ref_strdup(callsign);
	
	next_prog->proginfo_chanId = atoi(chanid);

	ref_hold(next_prog->proginfo_start_ts);
	ref_hold(next_prog->proginfo_end_ts);

	ret = 0;
 
    out:
        pthread_mutex_unlock(&mutex);

        return ret;
}
Пример #24
0
/*
 * cmyth_file_seek()
 *
 * Scope: PUBLIC
 *
 * Description
 *
 * Seek to a new position in the file based on the value of whence:
 *	WHENCE_SET
 *		The offset is set to offset bytes.
 *	WHENCE_CUR
 *		The offset is set to the current position plus offset bytes.
 *	WHENCE_END
 *		The offset is set to the size of the file minus offset bytes.
 *
 * Return Value:
 *
 * Sucess: 0
 *
 * Failure: an int containing -errno
 */
int64_t
cmyth_file_seek(cmyth_file_t file, int64_t offset, int8_t whence)
{
	char msg[128];
	int err;
	int count;
	int64_t c;
	int r;
	int64_t ret;

	if (file == NULL)
		return -EINVAL;

	if ((offset == 0) && (whence == WHENCE_CUR))
		return file->file_pos;

	if ((offset == file->file_pos) && (whence == WHENCE_SET))
		return file->file_pos;

	pthread_mutex_lock(&mutex);

	ret = 0;
	while(file->file_pos < file->file_req) {
		c = file->file_req - file->file_pos;
		if(c > sizeof(msg))
			c = sizeof(msg);

		if ((ret = cmyth_file_get_block(file, msg, (size_t)c)) < 0)
			break;
	}
	if (ret < 0)
		goto out;

	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 %"PRIu32"[]:[]SEEK[]:[]%"PRId64"[]:[]%"PRId8"[]:[]%"PRId64,
			 file->file_id,
			 offset,
			 whence,
			 file->file_pos);
	}
	else {
		snprintf(msg, sizeof(msg),
			 "QUERY_FILETRANSFER %"PRIu32"[]:[]SEEK[]:[]%"PRId32"[]:[]%"PRId32"[]:[]%"PRId8"[]:[]%"PRId32"[]:[]%"PRId32,
			 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,
			  "%s: cmyth_send_message() failed (%d)\n",
			  __FUNCTION__, err);
		ret = err;
		goto out;
	}

	if ((count=cmyth_rcv_length(file->file_control)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_length() failed (%d)\n",
			  __FUNCTION__, count);
		ret = count;
		goto out;
	}
	if ((r=cmyth_rcv_int64(file->file_control, &err, &c, count)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_int64() failed (%d)\n",
			  __FUNCTION__, r);
		ret = err;
		goto out;
	}

	file->file_pos = c;
	file->file_req = file->file_pos;
	if(file->file_pos > file->file_length)
		file->file_length = file->file_pos;

	ret = file->file_pos;

    out:
	pthread_mutex_unlock(&mutex);

	return ret;
}
Пример #25
0
/*
 * cmyth_conn_get_free_recorder(cmyth_conn_t control, cmyth_recorder_t rec)
 *                             
 * 
 * Scope: PUBLIC
 *
 * Description
 *
 * Obtain the next available free recorder the connection specified by
 * 'control'.  This fills out the recorder structure specified by 'rec'.
 *
 * Return Value:
 *
 * Success: 0 for not complete, 1 for complete
 *
 * Failure: -(errno)
 */
cmyth_recorder_t
cmyth_conn_get_free_recorder(cmyth_conn_t conn)
{
	int err, count;
	int r;
	long port, id;
	char msg[256];
	char reply[256];
	cmyth_recorder_t rec = NULL;

	if (!conn) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no connection\n",
			  __FUNCTION__);
		return NULL;
	}

	pthread_mutex_lock(&mutex);

	if ((rec=cmyth_recorder_create()) == NULL)
		goto fail;

	snprintf(msg, sizeof(msg), "GET_FREE_RECORDER");

	if ((err = cmyth_send_message(conn, msg)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_send_message() failed (%d)\n",
			  __FUNCTION__, err);
		goto fail;
	}

	count = cmyth_rcv_length(conn);
	if (count < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_length() failed (%d)\n",
			  __FUNCTION__, count);
		goto fail;
	}
	if ((r=cmyth_rcv_long(conn, &err, &id, count)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_long() failed (%d)\n",
			  __FUNCTION__, r);
		goto fail;
	}
	count -= r;
	if ((r=cmyth_rcv_string(conn, &err,
				reply, sizeof(reply)-1, count)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_string() failed (%d)\n",
			  __FUNCTION__, r);
		goto fail;
	}
	count -= r;
	if ((r=cmyth_rcv_long(conn, &err, &port, count)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_long() failed (%d)\n",
			  __FUNCTION__, r);
		goto fail;
	}

	if (port == -1)
		goto fail;

	rec->rec_id = id;
	rec->rec_server = ref_strdup(reply);
	rec->rec_port = port;

	if (cmyth_conn_connect_recorder(rec, conn->conn_buflen,
					conn->conn_tcp_rcvbuf) < 0)
		goto fail;

	pthread_mutex_unlock(&mutex);

	return rec;

    fail:
	if (rec)
		ref_release(rec);

	pthread_mutex_unlock(&mutex);

	return NULL;
}
Пример #26
0
/*
 * cmyth_file_read()
 *
 * Scope: PUBLIC
 *
 * Description
 *
 * Request and read a block of data from backend
 *
 * Return Value:
 *
 * Sucess: number of bytes transfered
 *
 * Failure: an int containing -errno
 */
int32_t cmyth_file_read(cmyth_file_t file, char *buf, int32_t len)
{
	int err, count;
	int32_t ret;
	int req, nfds, rec;
	char *end, *cur;
	char msg[256];
	int64_t len64;
	struct timeval tv;
	fd_set fds;

	if (!file || !file->file_data) {
		cmyth_dbg (CMYTH_DBG_ERROR, "%s: no connection\n",
		           __FUNCTION__);
		return -EINVAL;
	}
	if (len == 0)
		return 0;

	if(len > file->file_data->conn_tcp_rcvbuf)
		len = file->file_data->conn_tcp_rcvbuf;

	pthread_mutex_lock (&mutex);

	/* make sure we have outstanding requests that fill the buffer that was called with */
	/* this way we should be able to saturate the network connection better */
	if (file->file_req < file->file_pos + len) {

		snprintf (msg, sizeof (msg),
	            "QUERY_FILETRANSFER %"PRIu32"[]:[]REQUEST_BLOCK[]:[]%"PRId32,
	            file->file_id, (int32_t)(file->file_pos + len - file->file_req));

		if ( (err = cmyth_send_message (file->file_control, msg) ) < 0) {
			cmyth_dbg (CMYTH_DBG_ERROR,
			           "%s: cmyth_send_message() failed (%d)\n",
			           __FUNCTION__, err);
			ret = err;
			goto out;
		}
		req = 1;
	} else {
		req = 0;
	}

	rec = 0;
	cur = buf;
	end = buf+len;

	while (cur == buf || req || rec) {
		if(rec) {
			tv.tv_sec =  0;
			tv.tv_usec = 0;
		} else {
			tv.tv_sec = 20;
			tv.tv_usec = 0;
		}
		nfds = 0;

		FD_ZERO (&fds);
		if (req) {
			if ((int)file->file_control->conn_fd > nfds)
				nfds = (int)file->file_control->conn_fd;
			FD_SET (file->file_control->conn_fd, &fds);
		}
		if ((int)file->file_data->conn_fd > nfds)
			nfds = (int)file->file_data->conn_fd;
		FD_SET (file->file_data->conn_fd, &fds);

		if ((ret = select (nfds+1, &fds, NULL, NULL,&tv)) < 0) {
			cmyth_dbg (CMYTH_DBG_ERROR,
			           "%s: select(() failed (%d)\n",
			           __FUNCTION__, ret);
			goto out;
		}

		if (ret == 0 && !rec) {
			file->file_control->conn_hang = 1;
			file->file_data->conn_hang = 1;
			ret = -ETIMEDOUT;
			goto out;
		}

		/* check control connection */
		if (FD_ISSET(file->file_control->conn_fd, &fds)) {

			if ((count=cmyth_rcv_length (file->file_control)) < 0) {
				cmyth_dbg (CMYTH_DBG_ERROR,
				           "%s: cmyth_rcv_length() failed (%d)\n",
				           __FUNCTION__, count);
				ret = count;
				goto out;
			}

			/*
			 * MythTV originally sent back a signed 32bit value but was changed to a
			 * signed 64bit value in http://svn.mythtv.org/trac/changeset/18011 (1-Aug-2008).
			 *
			 * libcmyth now retrieves the 64-bit signed value, does error-checking,
			 * and then converts to a 32bit signed.
			 *
			 * This rcv_ method needs to be forced to use new_int64 to pull back a
			 * single 64bit number otherwise the handling in rcv_int64 will revert to
			 * the old two 32bit hi and lo long values.
			 */
			if ((ret = cmyth_rcv_new_int64(file->file_control, &err, &len64, count, 1))< 0) {
				cmyth_dbg (CMYTH_DBG_ERROR,
				           "%s: cmyth_rcv_new_int64() failed (%d)\n",
				           __FUNCTION__, ret);
				ret = err;
				goto out;
			}
			if (len64 > 0x7fffffff || len64 < 0) {
				/* -1 seems to be a common result, but isn't valid so use 0 instead. */
				cmyth_dbg (CMYTH_DBG_WARN,
				           "%s: cmyth_rcv_new_int64() returned out of bound value (%"PRId64"). Using 0 instead.\n",
				           __FUNCTION__, len64);
				len64 = 0;
			}
			len = (int32_t)len64;
			req = 0;
			file->file_req += len;

			if (file->file_req < file->file_pos) {
				cmyth_dbg (CMYTH_DBG_ERROR,
				           "%s: received invalid invalid length, read position is ahead of request (req: %"PRId64", pos: %"PRId64", len: %"PRId64")\n",
				           __FUNCTION__, file->file_req, file->file_pos, len64);
				ret = -1;
				goto out;
			}


			/* check if we are already done */
			if (file->file_pos == file->file_req)
				break;
		}

		/* restore direct request fleg */
		rec = 0;

		/* check data connection */
		if (FD_ISSET(file->file_data->conn_fd, &fds)) {
			if (end < cur) {
				cmyth_dbg (CMYTH_DBG_ERROR,
				           "%s: positions invalid on read, bailing out (cur: %x, end: %x)\n",
				           __FUNCTION__, cur, end);
				ret = -1;
				goto out;
			}
			if ((ret = recv (file->file_data->conn_fd, cur, (int32_t)(end - cur), 0)) < 0) {
				cmyth_dbg (CMYTH_DBG_ERROR,
				           "%s: recv() failed (%d)\n",
				           __FUNCTION__, ret);
				goto out;
			}
			cur += ret;
			file->file_pos += ret;
			if(ret)
				rec = 1; /* attempt to read directly again to get all queued packets */
		}
	}

	/* make sure file grows, as we move past length */
	if (file->file_pos > file->file_length)
		file->file_length = file->file_pos;

	ret = (int32_t)(cur - buf);
out:
	pthread_mutex_unlock (&mutex);
	return ret;
}
Пример #27
0
char *
cmyth_conn_get_setting(cmyth_conn_t conn, const char* hostname, const char* setting)
{
	char msg[256];
	int count, err;
	char* result = NULL;

	if(conn->conn_version < 17) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: protocol version doesn't support QUERY_SETTING\n",
			  __FUNCTION__);
		return NULL;
	}

	if (!conn) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no connection\n",
			  __FUNCTION__);
		return NULL;
	}

	pthread_mutex_lock(&mutex);

	snprintf(msg, sizeof(msg), "QUERY_SETTING %s %s", hostname, setting);
	if ((err = cmyth_send_message(conn, msg)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_send_message() failed (%d)\n",
			  __FUNCTION__, err);
		goto err;
	}

	if ((count=cmyth_rcv_length(conn)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_length() failed (%d)\n",
			  __FUNCTION__, count);
		goto err;
	}

	result = ref_alloc(count+1);
	count -= cmyth_rcv_string(conn, &err,
				    result, count, count);
	if (err < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_string() failed (%d)\n",
			  __FUNCTION__, err);
		goto err;
	}

	while(count > 0 && !err) {
		char buffer[100];
		count -= cmyth_rcv_string(conn, &err, buffer, sizeof(buffer)-1, count);
		buffer[sizeof(buffer)-1] = 0;
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: odd left over data %s\n", __FUNCTION__, buffer);
	}

	pthread_mutex_unlock(&mutex);
	return result;
err:
	if(result)
		ref_release(result);
	pthread_mutex_unlock(&mutex);
	return NULL;
}
Пример #28
0
static int
proginfo_command(cmyth_conn_t control, cmyth_proginfo_t prog, char *cmd,
		 long *result)
{
	long c = 0;
	char *buf;
	unsigned int len = ((2 * CMYTH_LONGLONG_LEN) + 
			    (6 * CMYTH_TIMESTAMP_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];
	char rec_end_ts[CMYTH_TIMESTAMP_LEN + 1];
	char originalairdate[CMYTH_TIMESTAMP_LEN + 1];
	char lastmodified[CMYTH_TIMESTAMP_LEN + 1];
	int err = 0;
	int count = 0;
	long r = 0;
	int ret = 0;

	if (!prog) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no program info\n",
			  __FUNCTION__);
		return -EINVAL;
	}

	len += strlen(prog->proginfo_title);
	len += strlen(prog->proginfo_subtitle);
	len += strlen(prog->proginfo_description);
	len += strlen(prog->proginfo_category);
	len += strlen(prog->proginfo_chanstr);
	len += strlen(prog->proginfo_chansign);
	len += strlen(prog->proginfo_channame);
	len += strlen(prog->proginfo_url);
	len += strlen(prog->proginfo_hostname);
	len += strlen(prog->proginfo_playgroup);
	len += strlen(prog->proginfo_seriesid);
	len += strlen(prog->proginfo_programid);
	if (prog->proginfo_inetref) {
		len += strlen(prog->proginfo_inetref);
	}
	if (prog->proginfo_recpriority_2) {
		len += strlen(prog->proginfo_recpriority_2);
	}
	if (prog->proginfo_storagegroup) {
		len += strlen(prog->proginfo_storagegroup);
	}

	buf = alloca(len + 1+2048);
	if (!buf) {
		return -ENOMEM;
	}

	if(control->conn_version < 14)
	{
	    cmyth_timestamp_to_string(start_ts, prog->proginfo_start_ts);
	    cmyth_timestamp_to_string(end_ts, prog->proginfo_end_ts);
	    cmyth_timestamp_to_string(rec_start_ts,
	    			      prog->proginfo_rec_start_ts);
	    cmyth_timestamp_to_string(rec_end_ts, prog->proginfo_rec_end_ts);
	    cmyth_timestamp_to_string(originalairdate,
				      prog->proginfo_originalairdate);
	    cmyth_timestamp_to_string(lastmodified,
				      prog->proginfo_lastmodified);
	}
	else
	{
	    cmyth_datetime_to_string(start_ts, prog->proginfo_start_ts);
	    cmyth_datetime_to_string(end_ts, prog->proginfo_end_ts);
	    cmyth_datetime_to_string(rec_start_ts, prog->proginfo_rec_start_ts);
	    cmyth_datetime_to_string(rec_end_ts, prog->proginfo_rec_end_ts);
	    cmyth_datetime_to_string(originalairdate,
				     prog->proginfo_originalairdate);
	    cmyth_datetime_to_string(lastmodified, prog->proginfo_lastmodified);
	}

	if(control->conn_version > 32) {
	    cmyth_timestamp_to_isostring(originalairdate,
				 prog->proginfo_originalairdate);
	}

	if(control->conn_version < 12)
	{
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: delete not supported with protocol ver %d\n",
			  __FUNCTION__, control->conn_version);
		return -EINVAL;
	}
	sprintf(buf, "%s 0[]:[]", cmd);
	sprintf(buf + strlen(buf), "%s[]:[]",  prog->proginfo_title);
	sprintf(buf + strlen(buf), "%s[]:[]",  prog->proginfo_subtitle);
	sprintf(buf + strlen(buf), "%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[]:[]",  prog->proginfo_category);
	sprintf(buf + strlen(buf), "%ld[]:[]", prog->proginfo_chanId);
	sprintf(buf + strlen(buf), "%s[]:[]",  prog->proginfo_chanstr);
	sprintf(buf + strlen(buf), "%s[]:[]",  prog->proginfo_chansign);
	sprintf(buf + strlen(buf), "%s[]:[]",  prog->proginfo_channame);
	sprintf(buf + strlen(buf), "%s[]:[]",  prog->proginfo_url);
	if (control->conn_version >= 57) {
		sprintf(buf + strlen(buf), "%"PRId64"[]:[]", prog->proginfo_Length);
	} else {
		sprintf(buf + strlen(buf), "%d[]:[]", (int32_t)(prog->proginfo_Length >> 32));
		sprintf(buf + strlen(buf), "%d[]:[]", (int32_t)(prog->proginfo_Length & 0xffffffff));
	}
	sprintf(buf + strlen(buf), "%s[]:[]",  start_ts);
	sprintf(buf + strlen(buf), "%s[]:[]",  end_ts);
	if (control->conn_version < 57) {
		sprintf(buf + strlen(buf), "%s[]:[]", prog->proginfo_unknown_0); // "duplicate"
		sprintf(buf + strlen(buf), "%ld[]:[]", 0L); // "shareable"
	}
	sprintf(buf + strlen(buf), "%ld[]:[]", 0L); // "findid"
	sprintf(buf + strlen(buf), "%s[]:[]",  prog->proginfo_hostname);
	sprintf(buf + strlen(buf), "%ld[]:[]", prog->proginfo_source_id);
	sprintf(buf + strlen(buf), "%ld[]:[]", prog->proginfo_card_id);
	sprintf(buf + strlen(buf), "%ld[]:[]", prog->proginfo_input_id);
	sprintf(buf + strlen(buf), "%s[]:[]",  prog->proginfo_rec_priority);
	sprintf(buf + strlen(buf), "%ld[]:[]", prog->proginfo_rec_status);
	sprintf(buf + strlen(buf), "%ld[]:[]", prog->proginfo_record_id);
	sprintf(buf + strlen(buf), "%ld[]:[]", prog->proginfo_rec_type);
	sprintf(buf + strlen(buf), "%ld[]:[]", prog->proginfo_rec_dups);
	sprintf(buf + strlen(buf), "%ld[]:[]", prog->proginfo_unknown_1); // "dupmethod"
	sprintf(buf + strlen(buf), "%s[]:[]",  rec_start_ts);
	sprintf(buf + strlen(buf), "%s[]:[]",  rec_end_ts);
	if (control->conn_version < 57) {
		sprintf(buf + strlen(buf), "%ld[]:[]", prog->proginfo_repeat);
	}
	sprintf(buf + strlen(buf), "%ld[]:[]", prog->proginfo_program_flags);
	sprintf(buf + strlen(buf), "%s[]:[]",  prog->proginfo_recgroup);
	if (control->conn_version < 57) {
		sprintf(buf + strlen(buf), "%s[]:[]", prog->proginfo_chancommfree);
	}
	sprintf(buf + strlen(buf), "%s[]:[]",  prog->proginfo_chan_output_filters);
	sprintf(buf + strlen(buf), "%s[]:[]",  prog->proginfo_seriesid);
	sprintf(buf + strlen(buf), "%s[]:[]",  prog->proginfo_programid);
	if (control->conn_version >= 67) {
		sprintf(buf + strlen(buf), "%s[]:[]", prog->proginfo_inetref);
	}
	sprintf(buf + strlen(buf), "%s[]:[]",  lastmodified);
	sprintf(buf + strlen(buf), "%s[]:[]",  prog->proginfo_stars);
	sprintf(buf + strlen(buf), "%s[]:[]",  originalairdate);
	if (control->conn_version >= 15 && control->conn_version < 57) {
		sprintf(buf + strlen(buf), "%ld[]:[]", prog->proginfo_hasairdate);
	}
	if (control->conn_version >= 18) {
		sprintf(buf + strlen(buf), "%s[]:[]", prog->proginfo_playgroup);
	}
	if (control->conn_version >= 25) {
		sprintf(buf + strlen(buf), "%s[]:[]", prog->proginfo_recpriority_2);
	}
	if (control->conn_version >= 31) {
		sprintf(buf + strlen(buf), "%ld[]:[]", prog->proginfo_parentid);
	}
	if (control->conn_version >= 32) {
		sprintf(buf + strlen(buf), "%s[]:[]", prog->proginfo_storagegroup);
	}
	if (control->conn_version >= 35) {
		sprintf(buf + strlen(buf), "%ld[]:[]", prog->proginfo_audioproperties);
		sprintf(buf + strlen(buf), "%ld[]:[]", prog->proginfo_videoproperties);
		sprintf(buf + strlen(buf), "%ld[]:[]", prog->proginfo_subtitletype);
	}
	if (control->conn_version >= 43) {
		sprintf(buf + strlen(buf), "%d[]:[]", prog->proginfo_year);
	}

	pthread_mutex_lock(&control->conn_mutex);

	if ((err = cmyth_send_message(control, buf)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_send_message() failed (%d)\n",
			  __FUNCTION__, err);
		ret = err;
		goto out;
	}

	count = cmyth_rcv_length(control);
	if ((r=cmyth_rcv_long(control, &err, &c, count)) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_length() failed (%d)\n",
			  __FUNCTION__, r);
		ret = err;
		goto out;
	}

	if (result) {
		*result = c;
	}

    out:
	pthread_mutex_unlock(&control->conn_mutex);

	return ret;
}
Пример #29
0
/*
 * cmyth_conn_connect_file(char *server, unsigned short port, unsigned buflen
 *                         cmyth_proginfo_t prog)
 *
 * Scope: PUBLIC
 *
 * Description:
 *
 * Create a file structure containing a data connection for use
 * transfering a file within the MythTV protocol.  Return a pointer to
 * the newly created file structure.  The connection in the file
 * structure is returned held as is the file structure itself.  The
 * connection will be released when the file structure is released.
 * The file structure can be released using ref_release().
 *
 * Return Value:
 *
 * Success: Non-NULL cmyth_file_t (this is a pointer type)
 *
 * Failure: NULL cmyth_file_t
 */
cmyth_file_t
cmyth_conn_connect_file(cmyth_proginfo_t prog,  cmyth_conn_t control,
			unsigned buflen, int tcp_rcvbuf)
{
	cmyth_conn_t conn = NULL;
	char *announcement = NULL;
	char *myth_host = NULL;
	char reply[16];
	int err = 0;
	int count = 0;
	int r;
	int ann_size = sizeof("ANN FileTransfer []:[][]:[]");
	cmyth_file_t ret = NULL;

	if (!prog) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: prog is NULL\n", __FUNCTION__);
		goto shut;
	}
	if (!prog->proginfo_host) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: prog host is NULL\n",
			  __FUNCTION__);
		goto shut;
	}
	if (!prog->proginfo_pathname) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: prog has no pathname in it\n",
			  __FUNCTION__);
		goto shut;
	}
	ret = cmyth_file_create(control);
	if (!ret) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_file_create() failed\n",
			  __FUNCTION__);
		goto shut;
	}
	cmyth_dbg(CMYTH_DBG_PROTO, "%s: connecting data connection\n",
		  __FUNCTION__);
	if (control->conn_version >= 17) {
		myth_host = cmyth_conn_get_setting(control, prog->proginfo_host,
		                                   "BackendServerIP");
	}
	if (!myth_host) {
		cmyth_dbg(CMYTH_DBG_PROTO,
		          "%s: BackendServerIP setting not found. Using proginfo_host: %s\n",
		          __FUNCTION__, prog->proginfo_host);
		myth_host = ref_alloc(strlen(prog->proginfo_host) + 1);
		strcpy(myth_host, prog->proginfo_host);
	}
	conn = cmyth_connect(myth_host, prog->proginfo_port,
			     buflen, tcp_rcvbuf);
	cmyth_dbg(CMYTH_DBG_PROTO,
		  "%s: done connecting data connection, conn = %d\n",
		  __FUNCTION__, conn);
	if (!conn) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_connect(%s, %d, %d) failed\n",
			  __FUNCTION__,
			  myth_host, prog->proginfo_port, buflen);
		goto shut;
	}
	ann_size += strlen(prog->proginfo_pathname) + strlen(my_hostname);
	announcement = malloc(ann_size);
	if (!announcement) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%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, prog->proginfo_pathname);
	}
	else {
		sprintf(announcement, "ANN FileTransfer %s[]:[]%s",
			  my_hostname, prog->proginfo_pathname);
	}

	if (cmyth_send_message(conn, announcement) < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_send_message('%s') failed\n",
			  __FUNCTION__, announcement);
		goto shut;
	}
	ret->file_data = ref_hold(conn);
	count = cmyth_rcv_length(conn);
	if (count < 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_length() failed (%d)\n",
			  __FUNCTION__, count);
		goto shut;
	}
	reply[sizeof(reply) - 1] = '\0';
	r = cmyth_rcv_string(conn, &err, reply, sizeof(reply) - 1, count); 
	if (err != 0) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: cmyth_rcv_string() failed (%d)\n",
			  __FUNCTION__, err);
		goto shut;
	}
	if (strcmp(reply, "OK") != 0) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: reply ('%s') is not 'OK'\n",
			  __FUNCTION__, reply);
		goto shut;
	}
	count -= r;
	r = cmyth_rcv_long(conn, &err, &ret->file_id, count);
	if (err) {
		cmyth_dbg(CMYTH_DBG_ERROR,
			  "%s: (id) cmyth_rcv_long() failed (%d)\n",
			  __FUNCTION__, err);
		goto shut;
	}
	count -= r;
	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",
			  __FUNCTION__, err);
		goto shut;
	}
	count -= r;
	free(announcement);
	ref_release(conn);
	ref_release(myth_host);
	return ret;

    shut:
	if (announcement) {
		free(announcement);
	}
	ref_release(ret);
	ref_release(conn);
	ref_release(myth_host);
	return NULL;
}
Пример #30
0
/*
 * cmyth_recorder_get_duration_map()
 *
 * Scope: PUBLIC
 *
 * Description
 *
 * Request a list of {keynum, duration} pairs starting at keynum
 * 'start' and ending with keynum 'end' from the current recording on
 * recorder 'rec'.
 *
 * Return Value:
 *
 * Success: A non-NULL, held cmyth_posmap_t
 * Failure: A NULL pointer
 */
cmyth_posmap_t
cmyth_recorder_get_duration_map(cmyth_recorder_t rec, uint32_t start, uint32_t end)
{
	int err, count, consumed;
	cmyth_posmap_t ret = NULL;
	char msg[256];
	char tmp[1024];

	if (!rec || !rec->rec_conn) {
		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no recorder connection\n",
			  __FUNCTION__);
		return NULL;
	}

	pthread_mutex_lock(&rec->rec_conn->conn_mutex);

	if (rec->rec_conn->conn_version >= 77)
	{
		snprintf(msg, sizeof(msg), "QUERY_RECORDER %"PRIu32"[]:[]FILL_DURATION_MAP[]:[]%"PRIu32"[]:[]%"PRIu32, rec->rec_id, start, end);

		if ((err = cmyth_send_message(rec->rec_conn, msg)) < 0) {
			cmyth_dbg(CMYTH_DBG_ERROR,
				  "%s: cmyth_send_message() failed (%d)\n",
				  __FUNCTION__, err);
			goto fail;
		}

		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 fail;
		}

		ret = cmyth_posmap_create();
		if (ret == NULL) {
			cmyth_dbg(CMYTH_DBG_ERROR,
				  "%s: cmyth_posmap_create() failed\n",
				  __FUNCTION__);
			goto fail;
		}

		if (count > 2) {
			consumed = cmyth_rcv_posmap(rec->rec_conn, &err, ret, count);
			count -= consumed;
			if (err) {
				cmyth_dbg(CMYTH_DBG_ERROR,
				"%s: cmyth_rcv_posmap() failed (%d)\n",
				__FUNCTION__, err);
				ref_release(ret);
				ret = NULL;
			}
		}
		err = 0;
		while(count > 0 && err == 0) {
			consumed = cmyth_rcv_data(rec->rec_conn, &err, (unsigned char*)tmp, sizeof(tmp) - 1, count);
			cmyth_dbg(CMYTH_DBG_ERROR, "%s: leftover data: count %i, read %i, errno %i\n", __FUNCTION__, count, consumed, err);
			count -= consumed;
		}
	}

fail:
	pthread_mutex_unlock(&rec->rec_conn->conn_mutex);

	return ret;
}