PageRenderTime 119ms CodeModel.GetById 3ms app.highlight 102ms RepoModel.GetById 2ms app.codeStats 0ms

/lib/cmyth/libcmyth/socket.c

https://github.com/jzeaherra/xbmc-pvr-addons
C | 2938 lines | 1763 code | 151 blank | 1024 comment | 331 complexity | 8813cc90c2d7b80fff3167cab409dc89 MD5 | raw file
   1/*
   2 *  Copyright (C) 2004-2012, Eric Lund
   3 *  http://www.mvpmc.org/
   4 *
   5 *  This library is free software; you can redistribute it and/or
   6 *  modify it under the terms of the GNU Lesser General Public
   7 *  License as published by the Free Software Foundation; either
   8 *  version 2.1 of the License, or (at your option) any later version.
   9 *
  10 *  This library is distributed in the hope that it will be useful,
  11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13 *  Lesser General Public License for more details.
  14 *
  15 *  You should have received a copy of the GNU Lesser General Public
  16 *  License along with this library; if not, write to the Free Software
  17 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18 */
  19
  20/*
  21 * socket.c - functions to handle low level socket interactions with a
  22 *            MythTV frontend.
  23 */
  24#include <stdlib.h>
  25#include <stdio.h>
  26#include <ctype.h>
  27#include <string.h>
  28#include <errno.h>
  29#include <sys/types.h>
  30#include <cmyth_local.h>
  31
  32#define __UNSIGNED	"0123456789"
  33#define __SIGNED	"+-0123456789"
  34#define __check_num(num)	(strspn((num), __SIGNED) == strlen((num)))
  35#define __check_unum(num)	(strspn((num), __UNSIGNED) == strlen((num)))
  36
  37/*
  38 * cmyth_send_message(cmyth_conn_t conn, char *request)
  39 *
  40 * Scope: PRIVATE (mapped to __cmyth_send_message)
  41 *
  42 * Description
  43 *
  44 * Send a myth protocol on the socket indicated by 'conn'.  The
  45 * message sent has the form:
  46 *
  47 *   <length><request>
  48 *
  49 * Where <length> is the 8 character, space padded, left justified
  50 * ASCII representation of the number of bytes in the message
  51 * (including <length>) and <request> is the string specified in the
  52 * 'request' argument.
  53 *
  54 * Return Value:
  55 *
  56 * Success: 0
  57 *
  58 * Failure: -(errno)
  59 */
  60int
  61cmyth_send_message(cmyth_conn_t conn, char *request)
  62{
  63	/*
  64	 * For now this is unimplemented.
  65	 */
  66	char *msg;
  67	int reqlen;
  68	int written = 0;
  69	int w;
  70	struct timeval tv;
  71	fd_set fds;
  72
  73	cmyth_dbg(CMYTH_DBG_DEBUG, "%s\n", __FUNCTION__);
  74	if (!conn) {
  75		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no connection\n",
  76			  __FUNCTION__);
  77		return -EBADF;
  78	}
  79	if (conn->conn_fd < 0) {
  80		cmyth_dbg(CMYTH_DBG_ERROR, "%s: not connected\n",
  81			  __FUNCTION__);
  82		conn->conn_hang = 1;
  83		return -EBADF;
  84	}
  85	if (!request) {
  86		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no request\n", __FUNCTION__);
  87		return -EINVAL;
  88	}
  89	reqlen = strlen(request);
  90	msg = malloc(9 + reqlen);
  91	if (!msg) {
  92		cmyth_dbg(CMYTH_DBG_ERROR,
  93			  "%s: cannot allocate message buffer\n",
  94			  __FUNCTION__);
  95		return -ENOMEM;
  96	}
  97	sprintf(msg, "%-8d%s", reqlen, request);
  98	cmyth_dbg(CMYTH_DBG_PROTO, "%s: sending message '%s'\n",
  99		  __FUNCTION__, msg);
 100	reqlen += 8;
 101	do {
 102		tv.tv_sec = 10;
 103		tv.tv_usec = 0;
 104		FD_ZERO(&fds);
 105		FD_SET(conn->conn_fd, &fds);
 106		if (select((int)conn->conn_fd+1, NULL, &fds, NULL, &tv) == 0) {
 107			conn->conn_hang = 1;
 108			return -ETIMEDOUT;
 109		} else {
 110			conn->conn_hang = 0;
 111		}
 112		w = send(conn->conn_fd, msg + written, reqlen - written, 0);
 113		if (w < 0) {
 114			cmyth_dbg(CMYTH_DBG_ERROR, "%s: write() failed (%d)\n",
 115				  __FUNCTION__, errno);
 116			free(msg);
 117			conn->conn_hang = 1;
 118			return -errno;
 119		}
 120		written += w;
 121	} while (written < reqlen);
 122
 123	free(msg);
 124	return 0;
 125}
 126
 127/*
 128 * cmyth_rcv_length(cmyth_conn_t conn)
 129 *
 130 * Scope: PRIVATE (mapped to __cmyth_rcv_length)
 131 *
 132 * Description
 133 *
 134 * Receive the <length> portion of a MythTV Protocol message
 135 * on the socket specified by 'conn'
 136 *
 137 * Return Value:
 138 *
 139 * Success: A length value > 0 and < 100000000
 140 *
 141 * Failure: -(errno)
 142 */
 143int
 144cmyth_rcv_length(cmyth_conn_t conn)
 145{
 146	char buf[16];
 147	int rtot = 0;
 148	int r;
 149	int hangcount = 0;
 150	int ret;
 151	struct timeval tv;
 152	fd_set fds;
 153
 154	cmyth_dbg(CMYTH_DBG_DEBUG, "%s\n", __FUNCTION__);
 155	if (!conn) {
 156		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no connection\n",
 157			  __FUNCTION__);
 158		return -EBADF;
 159	}
 160	if (conn->conn_fd < 0) {
 161		cmyth_dbg(CMYTH_DBG_ERROR, "%s: not connected\n",
 162			  __FUNCTION__);
 163		return -EBADF;
 164	}
 165	buf[8] ='\0';
 166	do {
 167		tv.tv_sec = 10;
 168		tv.tv_usec = 0;
 169		FD_ZERO(&fds);
 170		FD_SET(conn->conn_fd, &fds);
 171		r = select((int)conn->conn_fd+1, &fds, NULL, NULL, &tv);
 172		if (r > 0) {
 173			conn->conn_hang = 0;
 174			r = recv(conn->conn_fd, &buf[rtot], 8 - rtot, 0);
 175		}
 176		if (r == 0) {
 177			conn->conn_hang = 1;
 178			if (++hangcount > 2)
 179				return -ETIMEDOUT;
 180		}
 181		if (r < 0) {
 182			cmyth_dbg(CMYTH_DBG_ERROR, "%s: read() failed (%d)\n",
 183				  __FUNCTION__, errno);
 184			conn->conn_hang = 1;
 185			return -EBADF;
 186		}
 187		rtot += r;
 188	} while (rtot < 8);
 189	ret = atoi(buf);
 190	cmyth_dbg(CMYTH_DBG_PROTO, "%s: buffer is '%s' ret = %d\n",
 191		  __FUNCTION__, buf, ret);
 192	return ret;
 193}
 194
 195/*
 196 * cmyth_conn_refill(cmyth_conn_t conn, int len)
 197 *
 198 * Scope: PRIVATE (static)
 199 *
 200 * Description
 201 *
 202 * FIll up the buffer in the connection 'conn' with up to 'len' bytes
 203 * of data.
 204 *
 205 * Return Value:
 206 *
 207 * Success: 0
 208 *
 209 * Failure: -errno
 210 */
 211static int
 212cmyth_conn_refill(cmyth_conn_t conn, int len)
 213{
 214	int r;
 215	int total = 0;
 216	unsigned char *p;
 217	struct timeval tv;
 218	fd_set fds;
 219
 220	if (!conn) {
 221		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no connection\n",
 222			  __FUNCTION__);
 223		return -EINVAL;
 224	}
 225	if (!conn->conn_buf) {
 226		cmyth_dbg(CMYTH_DBG_ERROR, "%s: connection has no buffer\n",
 227			  __FUNCTION__);
 228		return -EINVAL;
 229	}
 230	if ((unsigned)len > conn->conn_buflen) {
 231		len = conn->conn_buflen;
 232	}
 233	p = conn->conn_buf;
 234	while (len > 0) {
 235		tv.tv_sec = 10;
 236		tv.tv_usec = 0;
 237		FD_ZERO(&fds);
 238		FD_SET(conn->conn_fd, &fds);
 239		if ((r=select((int)conn->conn_fd+1, &fds, NULL, NULL, &tv)) == 0) {
 240			conn->conn_hang = 1;
 241			return -ETIMEDOUT;
 242		} else if (r > 0) {
 243			conn->conn_hang = 0;
 244			r = recv(conn->conn_fd, p, len, 0);
 245		}
 246		if (r <= 0) {
 247			if (total == 0) {
 248				cmyth_dbg(CMYTH_DBG_ERROR,
 249					  "%s: read failed (%d)\n",
 250					  __FUNCTION__, errno);
 251	            conn->conn_hang = 1;
 252				if ( r == 0 )
 253					return -1 * EBADF;
 254				else
 255					return -1 * errno;
 256			}
 257			/*
 258			 * There were bytes read before the error, use them and
 259			 * then report the error next time.
 260			 */
 261			break;
 262		}
 263		total += r;
 264		len -= r;
 265		p += r;
 266	}
 267	conn->conn_pos = 0;
 268	conn->conn_len = total;
 269	return 0;
 270}
 271
 272/*
 273 * cmyth_rcv_string(cmyth_conn_t conn, char *buf, int buflen, int count)
 274 *
 275 * Scope: PRIVATE (mapped to __cmyth_rcv_length)
 276 *
 277 * Description
 278 *
 279 * Receive a string token from a list of tokens in a MythTV Protocol
 280 * message.  Tokens in MythTV Protocol messages are separated by the
 281 * string: []:[] or terminated by running out of message.  Up to
 282 * 'count' Bytes will be consumed from the socket specified by 'conn'
 283 * (stopping when a separator is seen or 'count' is exhausted).  Of
 284 * these, the first 'buflen' bytes will be copied into 'buf'.  If
 285 * a full 'buflen' bytes is read, 'buf' will not be terminated with a
 286 * '\0', otherwise it will be.  If an error is encountered and
 287 * 'err' is not NULL, an indication of the nature of the error will be
 288 * recorded by placing an error code in the location pointed to by
 289 * 'err'.  If all goes well, 'err' wil be set to 0.
 290 *
 291 * Return Value:
 292 *
 293 * A value >=0 indicating the number of bytes consumed.
 294 */
 295int
 296cmyth_rcv_string(cmyth_conn_t conn, int *err, char *buf, int buflen, int count)
 297{
 298	static char separator[] = "[]:[]";
 299	int consumed = 0;
 300	int placed = 0;
 301	char *state = separator;
 302	char *sep_start = NULL;
 303	int tmp;
 304
 305	if (!err) {
 306		err = &tmp;
 307	}
 308
 309	if (count < 0) {
 310		/*
 311		 * Strings are terminated by either the next separator or the end of the payload. If
 312		 * the last string requested in the payload is empty the count will be zero. In this case
 313		 * we should return an empty string rather than an error.
 314		 *
 315		 * http://www.mythtv.org/wiki/Myth_Protocol#Packet_Data_Format
 316		 */
 317		*err = EINVAL;
 318		return 0;
 319	}
 320
 321	if (!conn) {
 322		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no connection\n",
 323			  __FUNCTION__);
 324		*err = EBADF;
 325		return 0;
 326	}
 327	if (conn->conn_fd < 0) {
 328		cmyth_dbg(CMYTH_DBG_ERROR, "%s: not connected\n",
 329			  __FUNCTION__);
 330		*err = EBADF;
 331		return 0;
 332	}
 333	if (!conn->conn_buf) {
 334		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no connection buffer\n",
 335			  __FUNCTION__);
 336		*err = EBADF;
 337		return 0;
 338	}
 339	if (!buf) {
 340		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no output buffer\n",
 341			  __FUNCTION__);
 342		*err = EBADF;
 343		return 0;
 344	}
 345
 346	while (1) {
 347		if (consumed >= count) {
 348			/*
 349			 * We have consumed all the characters we were
 350			 * asked to from the stream.  Force a refill
 351			 * on the next call, and return 'consumed'.
 352			 */
 353			conn->conn_pos = conn->conn_len = 0;
 354			if (buflen > placed) {
 355				buf[placed] = '\0';
 356			}
 357			break;
 358		}
 359
 360		if (conn->conn_pos >= conn->conn_len) {
 361			/*
 362			 * We have run out of (or never had any) bytes
 363			 * from the connection.  Refill the buffer.
 364			 */
 365			*err = cmyth_conn_refill(conn, count - consumed);
 366			if (*err < 0) {
 367				*err = -1 * (*err);
 368				break;
 369			}
 370		}
 371
 372		if (sep_start && conn->conn_buf[conn->conn_pos] != (unsigned char)*state) {
 373			/*
 374			 * Reset separator in case the current character does not match
 375			 * the expected part of the separator. This needs to take place
 376			 * before checking if the current character starts a new separator.
 377			 * (To resolve issues with strings that look like [[]:[])
 378			 */
 379			sep_start = NULL;
 380			state = separator;
 381		}
 382
 383		if (conn->conn_buf[conn->conn_pos] == (unsigned char)*state) {
 384			/*
 385			 * We matched the next (possibly first) step
 386			 * of a separator, advance to the next.
 387			 */
 388			if ((state == separator) && (placed < buflen)) {
 389				sep_start = &buf[placed];
 390			}
 391			++state;
 392		}
 393
 394		if (placed < buflen) {
 395			/*
 396			 * This character goes in the output buffer,
 397			 * put it there.
 398			 */
 399			buf[placed++] = conn->conn_buf[conn->conn_pos];
 400		}
 401		++conn->conn_pos;
 402		++consumed;
 403
 404		if (*state == '\0') {
 405			/*
 406			 * Reached the end of a separator, terminate
 407			 * the returned buffer at the beginning of the
 408			 * separator (if it fell within the buffer)
 409			 * and return.
 410			 */
 411			if (sep_start) {
 412				*sep_start = '\0';
 413			} else if (buflen > placed) {
 414				buf[placed] = '\0';
 415			}
 416			break;
 417		}
 418	}
 419	cmyth_dbg(CMYTH_DBG_PROTO, "%s: string received '%s'\n",
 420		  __FUNCTION__, buf);
 421	return consumed;
 422}
 423
 424/*
 425 * cmyth_rcv_uint32(cmyth_conn_t conn, int *err, uint32_t *buf,
 426 *                      int count)
 427 *
 428 * Scope: PRIVATE (mapped to __cmyth_rcv_uint32)
 429 *
 430 * Description
 431 *
 432 * Receive an unsigned (32 bit) integer token from a list of
 433 * tokens in a MythTV Protocol message.  Tokens in MythTV Protocol
 434 * messages are separated by the string: []:[] or terminated by
 435 * running out of message.  Up to 'count' Bytes will be consumed from
 436 * the socket specified by 'conn' (stopping when a separator is seen
 437 * or 'count' is exhausted).  The unsigned long long integer value of
 438 * the token is placed in the location pointed to by 'buf'.  If an
 439 * error is encountered and 'err' is not NULL, an indication of the
 440 * nature of the error will be recorded by placing an error code in
 441 * the location pointed to by 'err'.  If all goes well, 'err' wil be
 442 * set to 0.
 443 *
 444 * Return Value:
 445 *
 446 * A value >=0 indicating the number of bytes consumed.
 447 *
 448 * Error Codes:
 449 *
 450 * In addition to system call error codes, the following errors may be
 451 * placed in 'err':
 452 *
 453 * ERANGE       The token received is too large to fit in an unsinged
 454 *              long long integer
 455 *
 456 * EINVAL       The token received is not numeric or is signed
 457 */
 458int
 459cmyth_rcv_uint32(cmyth_conn_t conn, int *err, uint32_t *buf, int count)
 460{
 461	char num[32];
 462	char *num_p = num;
 463	uint64_t val = 0;
 464	uint64_t limit = UINT32_MAX;
 465	int consumed;
 466	int tmp;
 467
 468	*buf = 0;
 469
 470	if (!err) {
 471		err = &tmp;
 472	}
 473
 474	if (count <= 0) {
 475		*err = EINVAL;
 476		return 0;
 477	}
 478
 479	*err = 0;
 480	consumed = cmyth_rcv_string(conn, err, num, sizeof(num), count);
 481	if (*err) {
 482		cmyth_dbg(CMYTH_DBG_ERROR,
 483			  "%s: cmyth_rcv_string() failed (%d)\n",
 484			  __FUNCTION__, consumed);
 485		return consumed;
 486	}
 487	while (*num_p) {
 488		if (!isdigit(*num_p)) {
 489			cmyth_dbg(CMYTH_DBG_ERROR,
 490				  "%s: received illegal integer: '%s'\n",
 491				  __FUNCTION__, num);
 492			*err = EINVAL;
 493			return consumed;
 494		}
 495		/*
 496		 * If we are about to make 'val' bigger than 32bit,
 497		 * it is ERANGE.
 498		 */
 499		if (val > limit && *num_p > '5') {
 500			*err = ERANGE;
 501			return consumed;
 502		}
 503		val *= 10;
 504		val += ((*num_p) - '0');
 505		num_p++;
 506	}
 507
 508	/*
 509	 * Got a result, return it.
 510	 */
 511	*buf = (uint32_t)val;
 512	return consumed;
 513}
 514
 515/*
 516 * cmyth_rcv_int32(cmyth_conn_t conn, int *err, int32_t *buf, int count)
 517 *
 518 * Scope: PRIVATE (mapped to __cmyth_rcv_int32)
 519 *
 520 * Description
 521 *
 522 * Receive a signed (32 bit) integer token from a list of
 523 * tokens in a MythTV Protocol message.  Tokens in MythTV Protocol
 524 * messages are separated by the string: []:[] or terminated by
 525 * running out of message.  Up to 'count' Bytes will be consumed from
 526 * the socket specified by 'conn' (stopping when a separator is seen
 527 * or 'count' is exhausted).  The long long integer value of the token
 528 * is placed in the location pointed to by 'buf'.  If an error is
 529 * encountered and 'err' is not NULL, an indication of the nature of
 530 * the error will be recorded by placing an error code in the location
 531 * pointed to by 'err'.  If all goes well, 'err' wil be set to 0.
 532 *
 533 * Return Value:
 534 *
 535 * A value >=0 indicating the number of bytes consumed.
 536 *
 537 * Error Codes:
 538 *
 539 * In addition to system call error codes, the following errors may be
 540 * placed in 'err':
 541 *
 542 * ERANGE       The token received is too large to fit in a
 543 *              long long integer
 544 *
 545 * EINVAL       The token received is not numeric
 546 */
 547int
 548cmyth_rcv_int32(cmyth_conn_t conn, int *err, int32_t *buf, int count)
 549{
 550	char num[32];
 551	char *num_p = num;
 552	uint64_t val = 0;
 553	int sign = 1;
 554	uint64_t limit = INT32_MAX;
 555	int consumed;
 556	int tmp;
 557
 558	if (!err) {
 559		err = &tmp;
 560	}
 561	if (count <= 0) {
 562		*err = EINVAL;
 563		return 0;
 564	}
 565	*err = 0;
 566	consumed = cmyth_rcv_string(conn, err, num, sizeof(num), count);
 567	if (*err) {
 568		cmyth_dbg(CMYTH_DBG_ERROR,
 569			  "%s: cmyth_rcv_string() failed (%d)\n",
 570			  __FUNCTION__, consumed);
 571		return consumed;
 572	}
 573	if (*num_p && (*num_p == '-')) {
 574		++num_p;
 575		sign = -1;
 576	}
 577	while (*num_p) {
 578		if (!isdigit(*num_p)) {
 579			cmyth_dbg(CMYTH_DBG_ERROR,
 580				  "%s: received illegal integer: '%s'\n",
 581				  __FUNCTION__, num);
 582			*err = EINVAL;
 583			return consumed;
 584		}
 585		val *= 10;
 586		val += ((*num_p) - '0');
 587		/*
 588		 * Check and make sure we are still under the limit (this is
 589		 * an absolute value limit, sign will be applied later).
 590		 */
 591		if (val > limit) {
 592			cmyth_dbg(CMYTH_DBG_ERROR,
 593				  "%s: long out of range: '%s'\n",
 594				  __FUNCTION__, num);
 595			*err = ERANGE;
 596			return consumed;
 597		}
 598		num_p++;
 599	}
 600
 601	/*
 602	 * Got a result, return it.
 603	 */
 604	*buf = (int32_t)(sign * val);
 605
 606	return consumed;
 607}
 608
 609/*
 610 * cmyth_rcv_okay(cmyth_conn_t conn)
 611 *
 612 * Scope: PRIVATE (mapped to __cmyth_rcv_okay)
 613 *
 614 * Description
 615 *
 616 * Receive an OK response on a connection.
 617 * This is here to easily handle simple acknowledgement from
 618 * the server.
 619 *
 620 * Return Value:
 621 *
 622 * Success: 0
 623 *
 624 * Failure: -(errno)
 625 */
 626int
 627cmyth_rcv_okay(cmyth_conn_t conn)
 628{
 629	int count, consumed;
 630	char buf[3];
 631	char tmp[1024];
 632	int err, ret;
 633
 634	count = cmyth_rcv_length(conn);
 635	if (count < 0) {
 636		cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_rcv_length() failed\n",
 637			  __FUNCTION__);
 638		return count;
 639	}
 640	consumed = cmyth_rcv_string(conn, &err, buf, sizeof(buf), count);
 641	if (err) {
 642		cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_rcv_string() failed\n",
 643			  __FUNCTION__);
 644		return -err;
 645	}
 646	count -= consumed;
 647	cmyth_toupper_string(buf);
 648	ret = (strncmp(buf, "OK",2) == 0) ? 0 : -1;
 649	if (count > 0) {
 650		cmyth_dbg(CMYTH_DBG_INFO,
 651			  "%s: did not consume everything\n",
 652			  __FUNCTION__);
 653		while(count > 0 && err == 0) {
 654			consumed = cmyth_rcv_string(conn, &err, tmp, sizeof(tmp) - 1, count);
 655			count -= consumed;
 656			cmyth_dbg(CMYTH_DBG_DEBUG, "%s: leftover data %s\n", __FUNCTION__, tmp);
 657		}
 658	}
 659	return ret;
 660}
 661
 662/*
 663 * cmyth_rcv_feedback(cmyth_conn_t conn, char *fb)
 664 *
 665 * Scope: PRIVATE (mapped to __cmyth_rcv_feedback)
 666 *
 667 * Description
 668 *
 669 * Receive user specified response on a connection.
 670 * This is here to easily handle simple acknowledgement from
 671 * the server.
 672 *
 673 * Return Value:
 674 *
 675 * Success: 0
 676 *
 677 * Failure: -(errno)
 678 */
 679int
 680cmyth_rcv_feedback(cmyth_conn_t conn, char *fb)
 681{
 682	int count, consumed;
 683	char buf[8];
 684	char tmp[1024];
 685	int err, ret;
 686
 687	count = cmyth_rcv_length(conn);
 688	if (count < 0) {
 689		cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_rcv_length() failed\n",
 690			  __FUNCTION__);
 691		return count;
 692	}
 693	consumed = cmyth_rcv_string(conn, &err, buf, sizeof(buf), count);
 694	if (err) {
 695		cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_rcv_string() failed\n",
 696			  __FUNCTION__);
 697		return -err;
 698	}
 699	count -= consumed;
 700	ret = (strncmp(buf, fb, sizeof(fb)) == 0) ? 0 : -1;
 701	if (count > 0) {
 702		cmyth_dbg(CMYTH_DBG_INFO,
 703			  "%s: did not consume everything\n",
 704			  __FUNCTION__);
 705		while(count > 0 && err == 0) {
 706			consumed = cmyth_rcv_string(conn, &err, tmp, sizeof(tmp) - 1, count);
 707			count -= consumed;
 708			cmyth_dbg(CMYTH_DBG_DEBUG, "%s: leftover data %s\n", __FUNCTION__, tmp);
 709		}
 710	}
 711	return ret;
 712}
 713
 714/*
 715 * cmyth_rcv_version(cmyth_conn_t conn, unsigned long *vers)
 716 *
 717 * Scope: PRIVATE (mapped to __cmyth_rcv_version)
 718 *
 719 * Description
 720 *
 721 * Receive an ACCEPT <version> or REJECT <version> response on a
 722 * connection.  If 'vers' is non-NULL it points to the location where
 723 * the received version number should be placed.  If it is NULL, this
 724 * routine will still read the version but it will throw it away.
 725 *
 726 * Return Value:
 727 *
 728 * Success: 0
 729 *
 730 * Failure: -(errno)
 731 */
 732int
 733cmyth_rcv_version(cmyth_conn_t conn, uint32_t *vers)
 734{
 735	int len;
 736	int consumed;
 737	char buf[8];
 738	uint32_t tmp_vers;
 739	int err;
 740
 741	if (!vers) {
 742		vers = &tmp_vers;
 743	}
 744	len = cmyth_rcv_length(conn);
 745	if (len < 0) {
 746		cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_rcv_length() failed\n",
 747			  __FUNCTION__);
 748		return len;
 749	}
 750	consumed = cmyth_rcv_string(conn, &err, buf, sizeof(buf), len);
 751	if (err) {
 752		cmyth_dbg(CMYTH_DBG_ERROR, "%s: cmyth_rcv_string() failed\n",
 753			  __FUNCTION__);
 754		return -err;
 755	}
 756	len -= consumed;
 757	/*
 758	 * The string we just consumed was either "ACCEPT" or "REJECT".  In
 759	 * either case, the number following it is the correct version, and
 760	 * we use it as an unsigned long.
 761	 */
 762	consumed = cmyth_rcv_uint32(conn, &err, vers, len);
 763	if (consumed < len) {
 764		cmyth_dbg(CMYTH_DBG_ERROR,
 765			  "%s: did not consume everything %d < %d\n",
 766			  __FUNCTION__, consumed, len);
 767	}
 768	return -err;
 769}
 770
 771/*
 772 * cmyth_rcv_int8(cmyth_conn_t conn, int *err, int8_t *buf, int count)
 773 *
 774 * Scope: PRIVATE (mapped to __cmyth_rcv_int8)
 775 *
 776 * Description
 777 *
 778 * Receive a byte (signed 8 bit) integer token from a list of tokens
 779 * in a MythTV Protocol message.  Tokens in MythTV Protocol messages
 780 * are separated by the string: []:[] or terminated by running out of
 781 * message.  Up to 'count' Bytes will be consumed from the socket
 782 * specified by 'conn' (stopping when a separator is seen or 'count'
 783 * is exhausted).  The byte integer value of the token is placed in
 784 * the location pointed to by 'buf'.  If an error is encountered and
 785 * 'err' is not NULL, an indication of the nature of the error will be
 786 * recorded by placing an error code in the location pointed to by
 787 * 'err'.  If all goes well, 'err' wil be set to 0.
 788 *
 789 * Return Value:
 790 *
 791 * Success / Failure: A value >=0 indicating the number of bytes
 792 *                    consumed.
 793 *
 794 * Error Codes:
 795 *
 796 * In addition to system call error codes, the following errors may be
 797 * placed in 'err' by this function:
 798 *
 799 * ERANGE       The token received is too large to fit in a byte integer
 800 *
 801 * EINVAL       The token received is not numeric
 802 */
 803int
 804cmyth_rcv_int8(cmyth_conn_t conn, int *err, int8_t *buf, int count)
 805{
 806	int32_t val;
 807	int consumed;
 808	int tmp;
 809
 810	if (!err) {
 811		err = &tmp;
 812	}
 813	if (count <= 0) {
 814		*err = EINVAL;
 815		return 0;
 816	}
 817	consumed = cmyth_rcv_int32(conn, err, &val, count);
 818	if (*err) {
 819		cmyth_dbg(CMYTH_DBG_ERROR,
 820			  "%s: cmyth_rcv_long() failed (%d)\n",
 821			  __FUNCTION__, consumed);
 822		return consumed;
 823	}
 824	if ((val > 127) || (val < -128)) {
 825		cmyth_dbg(CMYTH_DBG_ERROR, "%s: value doesn't fit: '%"PRId32"'\n",
 826			  __FUNCTION__, val);
 827		*err = ERANGE;
 828		return consumed;
 829	}
 830	*err = 0;
 831	*buf = (int8_t)val;
 832	return consumed;
 833}
 834
 835/*
 836 * cmyth_rcv_int16(cmyth_conn_t conn, int *err, int16_t *buf, int count)
 837 *
 838 * Scope: PRIVATE (mapped to __cmyth_rcv_int16)
 839 *
 840 * Description
 841 *
 842 * Receive a signed (16 bit) integer token from a list of tokens
 843 * in a MythTV Protocol message.  Tokens in MythTV Protocol messages
 844 * are separated by the string: []:[] or terminated by running out of
 845 * message.  Up to 'count' Bytes will be consumed from the socket
 846 * specified by 'conn' (stopping when a separator is seen or 'count'
 847 * is exhausted).  The short integer value of the token is placed in
 848 * the location pointed to by 'buf'.  If an error is encountered and
 849 * 'err' is not NULL, an indication of the nature of the error will be
 850 * recorded by placing an error code in the location pointed to by
 851 * 'err'.  If all goes well, 'err' wil be set to 0.
 852 *
 853 * Return Value:
 854 *
 855 * A value >=0 indicating the number of bytes consumed.
 856 *
 857 * Error Codes:
 858 *
 859 * In addition to system call error codes, the following errors may be
 860 * placed in 'err':
 861 *
 862 * ERANGE       The token received is too large to fit in a short integer
 863 *
 864 * EINVAL       The token received is not numeric
 865 */
 866int
 867cmyth_rcv_int16(cmyth_conn_t conn, int *err, int16_t *buf, int count)
 868{
 869	int32_t val;
 870	int consumed;
 871	int tmp;
 872
 873	if (!err) {
 874		err = &tmp;
 875	}
 876	if (count <= 0) {
 877		*err = EINVAL;
 878		return 0;
 879	}
 880	consumed = cmyth_rcv_int32(conn, err, &val, count);
 881	if (*err) {
 882		cmyth_dbg(CMYTH_DBG_ERROR,
 883			  "%s: cmyth_rcv_long() failed (%d)\n",
 884			  __FUNCTION__, consumed);
 885		return consumed;
 886	}
 887	if ((val > 32767) || (val < -32768)) {
 888		cmyth_dbg(CMYTH_DBG_ERROR, "%s: value doesn't fit: '%"PRId32"'\n",
 889			  __FUNCTION__, val);
 890		*err = ERANGE;
 891		return consumed;
 892	}
 893	*err = 0;
 894	*buf = (int16_t)val;
 895	return consumed;
 896}
 897
 898/*
 899 * cmyth_rcv_old_int64(cmyth_conn_t conn, int *err, long long *buf, int count)
 900 *
 901 * Scope: PRIVATE (mapped to __cmyth_rcv_long)
 902 *
 903 * Description
 904 *
 905 * Receive a long long (signed 64 bit) integer token from a list of tokens
 906 * in a MythTV Protocol message.  Tokens in MythTV Protocol messages
 907 * are separated by the string: []:[] or terminated by running out of
 908 * message.  Up to 'count' Bytes will be consumed from the socket
 909 * specified by 'conn' (stopping when a separator is seen or 'count'
 910 * is exhausted).  The long integer value of the token is placed in
 911 * the location pointed to by 'buf'.  If an error is encountered and
 912 * 'err' is not NULL, an indication of the nature of the error will be
 913 * recorded by placing an error code in the location pointed to by
 914 * 'err'.  If all goes well, 'err' wil be set to 0.
 915 *
 916 * Return Value:
 917 *
 918 * A value >=0 indicating the number of bytes consumed.
 919 *
 920 * Error Codes:
 921 *
 922 * In addition to system call error codes, the following errors may be
 923 * placed in 'err':
 924 *
 925 * ERANGE       The token received is too large to fit in a long integer
 926 *
 927 * EINVAL       The token received is not numeric
 928 */
 929int
 930cmyth_rcv_old_int64(cmyth_conn_t conn, int *err, int64_t *buf, int count)
 931{
 932	int64_t val;
 933	int consumed;
 934	int tmp;
 935	uint32_t hi, lo;
 936
 937	if (!err) {
 938		err = &tmp;
 939	}
 940
 941	if (count <= 0) {
 942		*err = EINVAL;
 943		return 0;
 944	}
 945
 946	consumed = cmyth_rcv_int32(conn, err, (int32_t*)&hi, count);
 947	if (*err) {
 948		cmyth_dbg(CMYTH_DBG_ERROR,
 949			  "%s: cmyth_rcv_u_long() failed (%d)\n",
 950			  __FUNCTION__, consumed);
 951		return consumed;
 952	}
 953	consumed += cmyth_rcv_int32(conn, err, (int32_t*)&lo, count-consumed);
 954	if (*err) {
 955		cmyth_dbg(CMYTH_DBG_ERROR,
 956			  "%s: cmyth_rcv_u_long() failed (%d)\n",
 957			  __FUNCTION__, consumed);
 958		return consumed;
 959	}
 960	val = (((int64_t)hi) << 32) | ((int64_t)(lo & 0xffffffff));
 961
 962	*err = 0;
 963	*buf = val;
 964
 965	return consumed;
 966}
 967
 968/*
 969 * cmyth_rcv_new_int64(cmyth_conn_t conn, int *err, long long *buf, int count)
 970 *
 971 * Scope: PRIVATE (mapped to __cmyth_rcv_long)
 972 *
 973 * Description
 974 *
 975 * Receive a long long (signed 64 bit) integer token from a list of tokens
 976 * in a MythTV Protocol message.  Tokens in MythTV Protocol messages
 977 * are separated by the string: []:[] or terminated by running out of
 978 * message.  Up to 'count' Bytes will be consumed from the socket
 979 * specified by 'conn' (stopping when a separator is seen or 'count'
 980 * is exhausted).  The long integer value of the token is placed in
 981 * the location pointed to by 'buf'.  If an error is encountered and
 982 * 'err' is not NULL, an indication of the nature of the error will be
 983 * recorded by placing an error code in the location pointed to by
 984 * 'err'.  If all goes well, 'err' wil be set to 0.
 985 *
 986 * As of protocol version 57, Myth now sends a single 64bit string instead
 987 * of 2 32bit strings when sending proginfo data.  This does not seem to
 988 * apply uniformly though. For instance 'ANN FILETRANSFER' still uses
 989 * the old method
 990 *
 991 * Return Value:
 992 *
 993 * A value >=0 indicating the number of bytes consumed.
 994 *
 995 * Error Codes:
 996 *
 997 * In addition to system call error codes, the following errors may be
 998 * placed in 'err':
 999 *
1000 * ERANGE       The token received is too large to fit in a long integer
1001 *
1002 * EINVAL       The token received is not numeric
1003 */
1004int
1005cmyth_rcv_new_int64(cmyth_conn_t conn, int *err, int64_t *buf, int count,
1006		    int forced)
1007{
1008	char num[32];
1009	char *num_p = num;
1010	uint64_t val = 0;
1011	int sign = 1;
1012	uint64_t limit = INT64_MAX;
1013	int consumed;
1014	int tmp;
1015
1016	/*
1017	 * Between protocols 57 and 66, not all messages used the new
1018	 * format for 64-bit values.
1019	 */
1020	if ((conn->conn_version < 57) ||
1021	    ((conn->conn_version < 66) && !forced)) {
1022		return cmyth_rcv_old_int64(conn, err, buf, count);
1023	}
1024
1025	if (!err) {
1026		err = &tmp;
1027	}
1028	if (count <= 0) {
1029		*err = EINVAL;
1030		return 0;
1031	}
1032	*err = 0;
1033	consumed = cmyth_rcv_string(conn, err, num, sizeof(num), count);
1034	if (*err) {
1035		cmyth_dbg(CMYTH_DBG_ERROR,
1036			"%s: cmyth_rcv_string() failed (%d)\n",
1037			__FUNCTION__, consumed);
1038		return consumed;
1039	}
1040	if (*num_p && (*num_p == '-')) {
1041		++num_p;
1042		sign = -1;
1043	}
1044	while (*num_p) {
1045		if (!isdigit(*num_p)) {
1046			cmyth_dbg(CMYTH_DBG_ERROR,
1047				  "%s: received illegal integer: '%s'\n",
1048				  __FUNCTION__, num);
1049			*err = EINVAL;
1050			return consumed;
1051		}
1052		val *= 10;
1053		val += ((*num_p) - '0');
1054		/*
1055		 * Check and make sure we are still under the limit (this is
1056		 * an absolute value limit, sign will be applied later).
1057		 */
1058		if (val > limit) {
1059			cmyth_dbg(CMYTH_DBG_ERROR,
1060				  "%s: long long out of range: '%s'\n",
1061				  __FUNCTION__, num);
1062			*err = ERANGE;
1063			return consumed;
1064		}
1065		num_p++;
1066	}
1067
1068	/*
1069	 * Got a result, return it.
1070	 */
1071	*buf = (int64_t)(sign * val);
1072
1073	return consumed;
1074}
1075
1076/*
1077 * cmyth_rcv_uint8(cmyth_conn_t conn, int *err, uint8_t *buf, int count)
1078 *
1079 * Scope: PRIVATE (mapped to __cmyth_rcv_uint8)
1080 *
1081 * Description
1082 *
1083 * Receive an unsigned byte (8 bit) integer token from a list of
1084 * tokens in a MythTV Protocol message.  Tokens in MythTV Protocol
1085 * messages are separated by the string: []:[] or terminated by
1086 * running out of message.  Up to 'count' Bytes will be consumed from
1087 * the socket specified by 'conn' (stopping when a separator is seen
1088 * or 'count' is exhausted).  The unsigned byte integer value of the
1089 * token is placed in the location pointed to by 'buf'.  If an error
1090 * is encountered and 'err' is not NULL, an indication of the nature
1091 * of the error will be recorded by placing an error code in the
1092 * location pointed to by 'err'.  If all goes well, 'err' wil be set
1093 * to 0.
1094 *
1095 * Return Value:
1096 *
1097 * A value >=0 indicating the number of bytes consumed.
1098 *
1099 * Error Codes:
1100 *
1101 * In addition to system call error codes, the following errors may be
1102 * placed in 'err':
1103 *
1104 * ERANGE       The token received is too large to fit in an
1105 #              unsigned byte integer
1106 *
1107 * EINVAL       The token received is not numeric or is signed
1108 */
1109int
1110cmyth_rcv_uint8(cmyth_conn_t conn, int *err, uint8_t *buf, int count)
1111{
1112	uint32_t val;
1113	int consumed;
1114	int tmp;
1115
1116	if (!err) {
1117		err = &tmp;
1118	}
1119	if (count <= 0) {
1120		*err = EINVAL;
1121		return 0;
1122	}
1123	consumed = cmyth_rcv_uint32(conn, err, &val, count);
1124	if (*err) {
1125		cmyth_dbg(CMYTH_DBG_ERROR,
1126			  "%s: cmyth_rcv_ulong() failed (%d)\n",
1127			  __FUNCTION__, consumed);
1128		return consumed;
1129	}
1130	if (val > 255) {
1131		cmyth_dbg(CMYTH_DBG_ERROR, "%s: value doesn't fit: '%llu'\n",
1132			  __FUNCTION__, val);
1133		*err = ERANGE;
1134		return consumed;
1135	}
1136	*err = 0;
1137	*buf = (uint8_t)val;
1138	return consumed;
1139}
1140
1141/*
1142 * cmyth_rcv_uint16(cmyth_conn_t conn, int *err, uint16_t *buf, int count)
1143 *
1144 * Scope: PRIVATE (mapped to __cmyth_rcv_uint16)
1145 *
1146 * Description
1147 *
1148 * Receive an unsigned (16 bit) integer token from a list of
1149 * tokens in a MythTV Protocol message.  Tokens in MythTV Protocol
1150 * messages are separated by the string: []:[] or terminated by
1151 * running out of message.  Up to 'count' Bytes will be consumed from
1152 * the socket specified by 'conn' (stopping when a separator is seen
1153 * or 'count' is exhausted).  The unsigned short integer value of the
1154 * token is placed in the location pointed to by 'buf'.  If an error
1155 * is encountered and 'err' is not NULL, an indication of the nature
1156 * of the error will be recorded by placing an error code in the
1157 * location pointed to by 'err'.  If all goes well, 'err' wil be set
1158 * to 0.
1159 *
1160 * Return Value:
1161 *
1162 * A value >=0 indicating the number of bytes consumed.
1163 *
1164 * Error Codes:
1165 *
1166 * In addition to system call error codes, the following errors may be
1167 * placed in 'err':
1168 *
1169 * ERANGE       The token received is too large to fit in an
1170 *              unsinged short integer
1171 *
1172 * EINVAL       The token received is not numeric or is signed
1173 */
1174int
1175cmyth_rcv_uint16(cmyth_conn_t conn, int *err, uint16_t *buf, int count)
1176{
1177	uint32_t val;
1178	int consumed;
1179	int tmp;
1180
1181	if (!err) {
1182		err = &tmp;
1183	}
1184	if (count <= 0) {
1185		*err = EINVAL;
1186		return 0;
1187	}
1188	consumed = cmyth_rcv_uint32(conn, err, &val, count);
1189	if (*err) {
1190		cmyth_dbg(CMYTH_DBG_ERROR,
1191			  "%s: cmyth_rcv_ulong() failed (%d)\n",
1192			  __FUNCTION__, consumed);
1193		return consumed;
1194	}
1195	if (val > 65535) {
1196		cmyth_dbg(CMYTH_DBG_ERROR, "%s: value doesn't fit: '%llu'\n",
1197			  __FUNCTION__, val);
1198		*err = ERANGE;
1199		return consumed;
1200	}
1201	*err = 0;
1202	*buf = (uint16_t)val;
1203	return consumed;
1204}
1205
1206/*
1207 * cmyth_rcv_timestamp(cmyth_conn_t conn, int *err, cmyth_timestamp_t buf,
1208 *                     int count)
1209 *
1210 * Scope: PRIVATE (mapped to __cmyth_rcv_timestamp)
1211 *
1212 * Description
1213 *
1214 * Receive a timestamp in international format from a list of
1215 * tokens in a MythTV Protocol message.  A time stamp is formatted
1216 * as follows:
1217 *
1218 *     <YYYY>-<MM>-<DD>T<HH>:<MM>:<SS>
1219 *
1220 * Tokens in MythTV Protocol messages are separated by the string:
1221 * []:[] or terminated by running out of message.  Up to 'count' Bytes
1222 * will be consumed from the socket specified by 'conn' (stopping when
1223 * a separator is seen or 'count' is exhausted).  The timestamp
1224 * structure specified in 'buf' will be filled out.  If an error is
1225 * encountered and 'err' is not NULL, an indication of the nature of
1226 * the error will be recorded by placing an error code in the location
1227 * pointed to by 'err'.  If all goes well, 'err' wil be set to 0.
1228 *
1229 * Return Value:
1230 *
1231 * A value >=0 indicating the number of bytes consumed.
1232 *
1233 * Error Codes:
1234 *
1235 * In addition to system call error codes, the following errors may be
1236 * placed in 'err':
1237 *
1238 * ERANGE       The token received did not parse into a timestamp
1239 *
1240 * EINVAL       The token received is not numeric or is signed
1241 */
1242int
1243cmyth_rcv_timestamp(cmyth_conn_t conn, int *err, cmyth_timestamp_t *ts,
1244		    int count)
1245{
1246	int consumed;
1247	char tbuf[CMYTH_TIMESTAMP_LEN + 1];
1248	int tmp;
1249
1250	if (!err) {
1251		err = &tmp;
1252	}
1253	if (count <= 0) {
1254		*err = EINVAL;
1255		return 0;
1256	}
1257	*err = 0;
1258	tbuf[CMYTH_TIMESTAMP_LEN] = '\0';
1259	consumed = cmyth_rcv_string(conn, err, tbuf,
1260				    CMYTH_TIMESTAMP_LEN, count);
1261	if (*err) {
1262		cmyth_dbg(CMYTH_DBG_ERROR,
1263			  "%s: cmyth_rcv_string() failed (%d)\n",
1264			  __FUNCTION__, *err);
1265		return consumed;
1266	}
1267
1268	/*
1269	 * Allow for the timestamp to be empty in the case of livetv
1270	 */
1271        if ((strlen(tbuf) == 1) && (tbuf[0] = ' '))
1272                return consumed;
1273
1274	if (strlen(tbuf) == 0)
1275		return consumed;
1276
1277	if (*ts)
1278		ref_release(*ts);
1279
1280	*ts = cmyth_timestamp_from_string(tbuf);
1281	if (*ts == NULL) {
1282		cmyth_dbg(CMYTH_DBG_ERROR,
1283			  "%s: cmyth_timestamp_from_string() failed\n",
1284			  __FUNCTION__);
1285		*err = -EINVAL;
1286	}
1287	return consumed;
1288}
1289
1290
1291/*
1292 * cmyth_rcv_datetime(cmyth_conn_t conn, int *err, cmyth_timestamp_t buf,
1293 *                     int count)
1294 *
1295 * Scope: PRIVATE (mapped to __cmyth_rcv_datetime)
1296 *
1297 * Description
1298 *
1299 * Receive a datetime as an unsigned integer -- number of seconds
1300 * since Jan 1, 1970.
1301 *
1302 * Tokens in MythTV Protocol messages are separated by the string:
1303 * []:[] or terminated by running out of message.  Up to 'count' Bytes
1304 * will be consumed from the socket specified by 'conn' (stopping when
1305 * a separator is seen or 'count' is exhausted).  The timestamp
1306 * structure specified in 'buf' will be filled out.  If an error is
1307 * encountered and 'err' is not NULL, an indication of the nature of
1308 * the error will be recorded by placing an error code in the location
1309 * pointed to by 'err'.  If all goes well, 'err' wil be set to 0.
1310 *
1311 * Return Value:
1312 *
1313 * A value >=0 indicating the number of bytes consumed.
1314 *
1315 * Error Codes:
1316 *
1317 * In addition to system call error codes, the following errors may be
1318 * placed in 'err':
1319 *
1320 * ERANGE       The token received did not parse into a datetime
1321 *
1322 * EINVAL       The token received is not numeric or is signed
1323 */
1324int
1325cmyth_rcv_datetime(cmyth_conn_t conn, int *err, cmyth_timestamp_t *ts,
1326		   int count)
1327{
1328	int consumed;
1329	char tbuf[CMYTH_INT32_LEN + 1];
1330	int tmp;
1331
1332	if (!err) {
1333		err = &tmp;
1334	}
1335	if (count <= 0) {
1336		*err = EINVAL;
1337		return 0;
1338	}
1339	*err = 0;
1340	tbuf[CMYTH_INT32_LEN] = '\0';
1341	consumed = cmyth_rcv_string(conn, err, tbuf, CMYTH_INT32_LEN, count);
1342	if (*err) {
1343		cmyth_dbg(CMYTH_DBG_ERROR,
1344			  "%s: cmyth_rcv_string() failed (%d)\n",
1345			  __FUNCTION__, *err);
1346		return consumed;
1347	}
1348	if (*ts)
1349		ref_release(*ts);
1350	*ts = cmyth_timestamp_from_unixtime((time_t)atoi(tbuf));
1351	if (*ts == NULL) {
1352		cmyth_dbg(CMYTH_DBG_ERROR,
1353			  "%s: cmyth_datetime_from_string() failed\n",
1354			  __FUNCTION__);
1355		*err = -EINVAL;
1356	}
1357	return consumed;
1358}
1359
1360static void
1361cmyth_proginfo_parse_url(cmyth_proginfo_t p)
1362{
1363	static const char service[]="myth://";
1364	char *host = NULL;
1365	char *port = NULL;
1366	char *path = NULL;
1367	char *placed = NULL;
1368	char *eaddr = NULL;
1369	int ip6 = 0;
1370
1371        if (!p || ! p->proginfo_url ||
1372	    (!strcmp(p->proginfo_url, "none")) ||
1373	    (!strcmp(p->proginfo_url, " "))) {
1374		cmyth_dbg(CMYTH_DBG_ERROR,
1375			  "%s: proginfo or url was NULL, p = %p, url = %p\n",
1376			  __FUNCTION__, p, p ? p->proginfo_url : NULL);
1377		return;
1378	}
1379	cmyth_dbg(CMYTH_DBG_DEBUG, "%s: url is: '%s'\n",
1380		  __FUNCTION__, p->proginfo_url);
1381	path = p->proginfo_url;
1382	if (strncmp(p->proginfo_url, service, sizeof(service) - 1) == 0) {
1383		/*
1384		 * The URL starts with myth://.  The rest looks like
1385		 * <host>:<port>/<filename>.
1386		 */
1387		host = p->proginfo_url + strlen(service);
1388
1389		/* JLB: ipv6 host looks like [...] */
1390		eaddr = strchr(host, '/');
1391		if (!eaddr) {
1392			eaddr = host + strlen(host) + 1;
1393		}
1394		if ((unsigned char)*host == '[') {
1395			placed = strchr(host,']');
1396			if (placed && placed < eaddr && (unsigned char)*(++placed) == ':') {
1397				ip6 = 1;
1398				port = placed;
1399			}
1400			else {
1401				goto out;
1402			}
1403		}
1404		else {
1405			port = strchr(host, ':');
1406		}
1407		if (!port || port > eaddr) {
1408			/*
1409			 * This does not seem to be a proper URL, so
1410			 * just assume it is a filename, and get out.
1411			 */
1412			host = NULL;
1413			port = NULL;
1414			goto out;
1415		}
1416		port = port + 1;
1417		path = strchr(port, '/');
1418		if (!path) {
1419			/*
1420			 * This does not seem to be a proper URL, so
1421			 * just assume it is a filename, and get out.
1422			 */
1423			goto out;
1424		}
1425	}
1426
1427    out:
1428	if (host && port) {
1429		char tmp;
1430	  if (ip6 == 1) {
1431			++host;
1432			tmp = *(port - 2);
1433			*(port - 2) = '\0';
1434			if (p->proginfo_host)
1435				ref_release(p->proginfo_host);
1436			p->proginfo_host = ref_strdup(host);
1437			*(port - 2) = tmp;
1438		}
1439		else {
1440			tmp = *(port - 1);
1441			*(port - 1) = '\0';
1442			if (p->proginfo_host)
1443				ref_release(p->proginfo_host);
1444			p->proginfo_host = ref_strdup(host);
1445			*(port - 1) = tmp;
1446		}
1447		if (path) {
1448			tmp = *(path);
1449			*(path) = '\0';
1450			p->proginfo_port = atoi(port);
1451			*(path) = tmp;
1452		}
1453		else {
1454			p->proginfo_port = atoi(port);
1455		}
1456	} else {
1457		if (p->proginfo_host)
1458			ref_release(p->proginfo_host);
1459		p->proginfo_host = ref_strdup(p->proginfo_hostname);
1460		p->proginfo_port = 6543;
1461	}
1462	if (p->proginfo_pathname)
1463		ref_release(p->proginfo_pathname);
1464	p->proginfo_pathname = ref_strdup(path);
1465}
1466
1467/*
1468 * cmyth_rcv_proginfo(cmyth_conn_t conn, cmyth_proginfo_t buf, int count)
1469 *
1470 * Scope: PRIVATE (mapped to __cmyth_rcv_proginfo)
1471 *
1472 * Description
1473 *
1474 * Receive a program information structure from a list of tokens in a
1475 * MythTV Protocol message.  Tokens in MythTV Protocol messages are
1476 * separated by the string: []:[] or terminated by running out of
1477 * message.  Up to 'count' Bytes will be consumed from the socket
1478 * specified by 'conn' (stopping when a separator is seen or 'count'
1479 * is exhausted).  The proginfo structure specified in 'buf' will be
1480 * filled out.  If an error is encountered and 'err' is not NULL, an
1481 * indication of the nature of the error will be recorded by placing
1482 * an error code in the location pointed to by 'err'.  If all goes
1483 * well, 'err' wil be set to 0.
1484 *
1485 * Return Value:
1486 *
1487 * A value >=0 indicating the number of bytes consumed.
1488 *
1489 * Error Codes:
1490 *
1491 * In addition to system call error codes, the following errors may be
1492 * placed in 'err':
1493 *
1494 * ERANGE       The token received did not parse into a program
1495 *              information structure
1496 *
1497 * EINVAL       The token received is not numeric or is signed
1498 */
1499int
1500cmyth_rcv_proginfo(cmyth_conn_t conn, int *err, cmyth_proginfo_t buf,
1501		   int count)
1502{
1503	int consumed;
1504	int total = 0;
1505	char *failed = NULL;
1506	char tmp_str[32768];
1507
1508	if (count <= 0) {
1509		*err = EINVAL;
1510		return 0;
1511	}
1512
1513	tmp_str[sizeof(tmp_str) - 1] = '\0';
1514
1515	buf->proginfo_version = conn->conn_version;
1516	cmyth_dbg(CMYTH_DBG_DEBUG, "%s: VERSION IS %"PRIu32"\n",
1517		  __FUNCTION__, buf->proginfo_version);
1518
1519	/*
1520	 * Get proginfo_title (string)
1521	 */
1522	consumed = cmyth_rcv_string(conn, err,
1523				    tmp_str, sizeof(tmp_str) - 1, count);
1524	count -= consumed;
1525	total += consumed;
1526	if (*err) {
1527		failed = "cmyth_rcv_string";
1528		goto fail;
1529	}
1530	if (buf->proginfo_title)
1531		ref_release(buf->proginfo_title);
1532	buf->proginfo_title = ref_strdup(tmp_str);
1533
1534	/*
1535	 * Get proginfo_subtitle (string)
1536	 */
1537	consumed = cmyth_rcv_string(conn, err,
1538				    tmp_str, sizeof(tmp_str) - 1, count);
1539	count -= consumed;
1540	total += consumed;
1541	if (*err) {
1542		failed = "cmyth_rcv_string";
1543		goto fail;
1544	}
1545	if (buf->proginfo_subtitle)
1546		ref_release(buf->proginfo_subtitle);
1547	buf->proginfo_subtitle = ref_strdup(tmp_str);
1548
1549	/*
1550	 * Get proginfo_description (string)
1551	 */
1552	consumed = cmyth_rcv_string(conn, err,
1553				    tmp_str, sizeof(tmp_str) - 1, count);
1554	count -= consumed;
1555	total += consumed;
1556	if (*err) {
1557		failed = "cmyth_rcv_string";
1558		goto fail;
1559	}
1560	if (buf->proginfo_description)
1561		ref_release(buf->proginfo_description);
1562	buf->proginfo_description = ref_strdup(tmp_str);
1563
1564	if (buf->proginfo_version >= 67) {
1565		/*
1566		 * Get season and episode (unsigned int)
1567		 */
1568		consumed = cmyth_rcv_uint16(conn, err,
1569					   &buf->proginfo_season, count);
1570		count -= consumed;
1571		total += consumed;
1572		if (*err) {
1573			failed = "cmyth_rcv_ushort";
1574			goto fail;
1575		}
1576
1577		consumed = cmyth_rcv_uint16(conn, err,
1578					   &buf->proginfo_episode, count);
1579		count -= consumed;
1580		total += consumed;
1581		if (*err) {
1582			failed = "cmyth_rcv_ushort";
1583			goto fail;
1584		}
1585	}
1586
1587	/*
1588	 * Get proginfo_category (string)
1589	 */
1590	consumed = cmyth_rcv_string(conn, err,
1591				    tmp_str, sizeof(tmp_str) - 1, count);
1592	count -= consumed;
1593	total += consumed;
1594	if (*err) {
1595		failed = "cmyth_rcv_string";
1596		goto fail;
1597	}
1598	if (buf->proginfo_category)
1599		ref_release(buf->proginfo_category);
1600	buf->proginfo_category = ref_strdup(tmp_str);
1601
1602	/*
1603	 * Get proginfo_chanId (ulong)
1604	 */
1605	consumed = cmyth_rcv_uint32(conn, err,
1606				    &buf->proginfo_chanId, count);
1607	count -= consumed;
1608	total += consumed;
1609	if (*err) {
1610		failed = "cmyth_rcv_ulong";
1611		goto fail;
1612	}
1613
1614	/*
1615	 * Get proginfo_chanstr (string)
1616	 */
1617	consumed = cmyth_rcv_string(conn, err,
1618				    tmp_str, sizeof(tmp_str) - 1, count);
1619	count -= consumed;
1620	total += consumed;
1621	if (*err) {
1622		failed = "cmyth_rcv_string";
1623		goto fail;
1624	}
1625	if (buf->proginfo_chanstr)
1626		ref_release(buf->proginfo_chanstr);
1627	buf->proginfo_chanstr = ref_strdup(tmp_str);
1628
1629	/*
1630	 * Get proginfo_chansign (string)
1631	 */
1632	consumed = cmyth_rcv_string(conn, err,
1633				    tmp_str, sizeof(tmp_str) - 1, count);
1634	count -= consumed;
1635	total += consumed;
1636	if (*err) {
1637		failed = "cmyth_rcv_string";
1638		goto fail;
1639	}
1640	if (buf->proginfo_chansign)
1641		ref_release(buf->proginfo_chansign);
1642	buf->proginfo_chansign = ref_strdup(tmp_str);
1643
1644	/*
1645	 * Get proginfo_channame (string) Version 1 or proginfo_chanicon
1646	 * (string) Version 8.
1647	 */
1648	consumed = cmyth_rcv_string(conn, err,
1649				    tmp_str, sizeof(tmp_str) - 1, count);
1650	count -= consumed;
1651	total += consumed;
1652	if (*err) {
1653		failed = "cmyth_rcv_string";
1654		goto fail;
1655	}
1656	/* FIXME: doesn't seem to match the dump? */
1657	cmyth_dbg(CMYTH_DBG_DEBUG, "%s: GOT TO ICON/NAME\n", __FUNCTION__);
1658	if (buf->proginfo_chanicon)
1659		ref_release(buf->proginfo_chanicon);
1660	if (buf->proginfo_channame)
1661		ref_release(buf->proginfo_channame);
1662	if (buf->proginfo_version >= 8) {
1663		buf->proginfo_chanicon = ref_strdup(tmp_str);
1664		/*
1665		 * Simulate a channel name (Number and Callsign) for
1666		 * compatibility.
1667		 */
1668		sprintf(tmp_str,
1669			"%s %s", buf->proginfo_chanstr,
1670			buf->proginfo_chansign);
1671		buf->proginfo_channame = ref_strdup(tmp_str);
1672	} else { /* Assume version 1 */
1673		buf->proginfo_channame = ref_strdup(tmp_str);
1674		buf->proginfo_chanicon = ref_strdup("");
1675	}
1676
1677	/*
1678	 * Get proginfo_url (string)
1679	 */
1680	consumed = cmyth_rcv_string(conn, err,
1681				    tmp_str, sizeof(tmp_str) - 1, count);
1682	count -= consumed;
1683	total += consumed;
1684	if (*err) {
1685		failed = "cmyth_rcv_string";
1686		goto fail;
1687	}
1688	if (buf->proginfo_url)
1689		ref_release(buf->proginfo_url);
1690	buf->proginfo_url = ref_strdup(tmp_str);
1691
1692	/*
1693	 * Get proginfo_Length (long_long)
1694	 */
1695	if (buf->proginfo_version < 57) {
1696		consumed = cmyth_rcv_old_int64(conn, err, &buf->proginfo_Length,
1697					       count);
1698	} else {
1699		/*
1700		 * Since protocol 57 mythbackend now sends a single 64 bit
1701		 * integer rather than two 32 bit hi and lo integers for the
1702		 * proginfo length.
1703		 */
1704		consumed = cmyth_rcv_new_int64(conn, err, &buf->proginfo_Length,
1705					       count, 1);
1706	}
1707	count -= consumed;
1708	total += consumed;
1709	if (*err) {
1710		failed = "rcv_64";
1711		goto fail;
1712	}
1713
1714	/*
1715	 * Get proginfo_start_ts (timestamp)
1716	 */
1717	cmyth_dbg(CMYTH_DBG_DEBUG, "%s: GOT TO START_TS\n", __FUNCTION__);
1718	if (buf->proginfo_version >= 14) {
1719		consumed = cmyth_rcv_datetime(conn, err,
1720					      &(buf->proginfo_start_ts),
1721					      count);
1722	}
1723	else {
1724		consumed = cmyth_rcv_timestamp(conn, err,
1725					       &(buf->proginfo_start_ts),
1726					       count);
1727	}
1728	count -= consumed;
1729	total += consumed;
1730	if (*err) {
1731		failed = "proginfo_start_ts cmyth_rcv";
1732		goto fail;
1733	}
1734
1735	/*
1736	 * Get proginfo_end_ts (timestamp)
1737	 */
1738	cmyth_dbg(CMYTH_DBG_DEBUG, "%s: GOT TO END_TS\n", __FUNCTION__);
1739	if (buf->proginfo_version >= 14) {
1740		consumed = cmyth_rcv_datetime(conn, err,
1741					      &(buf->proginfo_end_ts), count);
1742	}
1743	else {
1744		consumed = cmyth_rcv_timestamp(conn, err,
1745					       &(buf->proginfo_end_ts), count);
1746	}
1747	count -= consumed;
1748	total += consumed;
1749	if (*err) {
1750		failed = "cmyth_rcv_timestamp";
1751		goto fail;
1752	}
1753
1754	if (buf->proginfo_version < 57) {
1755		/*
1756		 * Get proginfo_conflicting (ulong in Version 1, string in Version 8)
1757		 */
1758		if (buf->proginfo_version >= 8) {
1759			consumed = cmyth_rcv_string(conn, err,
1760						    tmp_str, sizeof(tmp_str) - 1,
1761						    count);
1762			count -= consumed;
1763			total += consumed;
1764			if (*err) {
1765				failed = "cmyth_rcv_string";
1766				goto fail;
1767			}
1768			if (buf->proginfo_unknown_0)
1769				ref_release(buf->proginfo_unknown_0);
1770			buf->proginfo_unknown_0 = ref_strdup(tmp_str);
1771		} else { /* Assume version 1 */
1772			consumed = cmyth_rcv_uint32(conn, err,
1773						   &buf->proginfo_conflicting, count);
1774			count -= consumed;
1775			total += consumed;
1776			if (*err) {
1777				failed = "cmyth_rcv_ulong";
1778				goto fail;
1779			}
1780		}
1781
1782		/*
1783		 * Get proginfo_recording (ulong)
1784		 */
1785		consumed = cmyth_rcv_uint32(conn, err, &buf->proginfo_recording, count);
1786		count -= consumed;
1787		total += consumed;
1788		if (*err) {
1789			failed = "cmyth_rcv_ulong";
1790			goto fail;
1791		}
1792	}
1793
1794	/*
1795	 * Get proginfo_override (ulong)
1796	 */
1797	consumed = cmyth_rcv_uint32(conn, err, &buf->proginfo_override, count);
1798	count -= consumed;
1799	total += consumed;
1800	if (*err) {
1801		failed = "cmyth_rcv_ulong";
1802		goto fail;
1803	}
1804
1805	/*
1806	 * Get proginfo_hostname (string)
1807	 */
1808	consumed = cmyth_rcv_string(conn, err,
1809				    tmp_str, sizeof(tmp_str) - 1, count);
1810	count -= consumed;
1811	total += consumed;
1812	if (*err) {
1813		failed = "cmyth_rcv_string";
1814		goto fail;
1815	}
1816	if (buf->proginfo_hostname)
1817		ref_release(buf->proginfo_hostname);
1818	buf->proginfo_hostname = ref_strdup(tmp_str);
1819
1820	/*
1821	 * Get proginfo_source_id (ulong)
1822	 */
1823	consumed = cmyth_rcv_uint32(conn, err, &buf->proginfo_source_id, count);
1824	count -= consumed;
1825	total += consumed;
1826	if (*err) {
1827		failed = "cmyth_rcv_ulong";
1828		goto fail;
1829	}
1830
1831	/*
1832	 * Get proginfo_card_id (ulong)
1833	 */
1834	consumed = cmyth_rcv_uint32(conn, err, &buf->proginfo_card_id, count);
1835	count -= consumed;
1836	total += consumed;
1837	if (*err) {
1838		failed = "cmyth_rcv_ulong";
1839		goto fail;
1840	}
1841
1842	/*
1843	 * Get proginfo_input_id (ulong)
1844	 */
1845	consumed = cmyth_rcv_uint32(conn, err, &buf->proginfo_input_id, count);
1846	count -= consumed;
1847	total += consumed;
1848	if (*err) {
1849		failed = "cmyth_rcv_ulong";
1850		goto fail;
1851	}
1852
1853	/*
1854	 * Get proginfo_rec_priority (byte)
1855	 */
1856	consumed = cmyth_rcv_int8(conn, err,
1857				    &buf->proginfo_rec_priority, count);
1858	count -= consumed;
1859	total += consumed;
1860	if (*err) {
1861		failed = "cmyth_rcv_long";
1862		goto fail;
1863	}
1864
1865	/*
1866	 * Get proginfo_rec_status (byte)
1867	 */
1868	consumed = cmyth_rcv_int8(conn, err, &buf->proginfo_rec_status, count);
1869	count -= consumed;
1870	total += consumed;
1871	if (*err) {
1872		failed = "cmyth_rcv_byte";
1873		goto fail;
1874	}
1875
1876	/*
1877	 * Get proginfo_record_id (ulong)
1878	 */
1879	consumed = cmyth_rcv_uint32(conn, err, &buf->proginfo_record_id, count);
1880	count -= consumed;
1881	total += consumed;
1882	if (*err) {
1883		failed = "cmyth_rcv_ulong";
1884		goto fail;
1885	}
1886
1887	/*
1888	 * Get proginfo_rec_type (ubyte)
1889	 */
1890	consumed = cmyth_rcv_uint8(conn, err, &buf->proginfo_rec_type, count);
1891	count -= consumed;
1892	total += consumed;
1893	if (*err) {
1894		failed = "cmyth_rcv_ubyte";
1895		goto fail;
1896	}
1897
1898	/*
1899	 * Get proginfo_rec_dupin (ubyte)
1900	 */
1901	consumed = cmyth_rcv_uint8(conn, err, &buf->proginfo_rec_dupin, count);
1902	count -= consumed;
1903	total += consumed;
1904	if (*err) {
1905		failed = "cmyth_rcv_ubyte";
1906		goto fail;
1907	}
1908
1909	if (buf->proginfo_version >= 8) {
1910		/*
1911		 * Get proginfo_rec_dupmethod (ubyte)
1912		 */
1913		consumed = cmyth_rcv_uint8(conn, err,
1914					   &buf->proginfo_rec_dupmethod, count);
1915		count -= consumed;
1916		total += consumed;
1917		if (*err) {
1918			failed = "cmyth_rcv_ubyte";
1919			goto fail;
1920		}
1921	}
1922
1923	/*
1924	 * Get proginfo_rec_start_ts (timestamp)
1925	 */
1926	if (buf->proginfo_version >= 14) {
1927		consumed = cmyth_rcv_datetime(conn, err,
1928					      &(buf->proginfo_rec_start_ts),
1929					      count);
1930	}
1931	else {
1932		consumed = cmyth_rcv_timestamp(conn, err,
1933					       &(buf->proginfo_rec_start_ts),
1934					       count);
1935	}
1936
1937	count -= consumed;
1938	total += consumed;
1939	if (*err) {
1940		failed = "cmyth_rcv_timestamp";
1941		goto fail;
1942	}
1943
1944	/*
1945	 * Get proginfo_rec_end_ts (timestamp)
1946	 */
1947	if (buf->proginfo_version >= 14) {
1948		consumed = cmyth_rcv_datetime(conn, err,
1949					      &(buf->proginfo_rec_end_ts),
1950					      count);
1951	}
1952	else {
1953		consumed = cmyth_rcv_timestamp(conn, err,
1954					       &(buf->proginfo_rec_end_ts),
1955					       count);
1956	}
1957
1958	count -= consumed;
1959	total += consumed;
1960	if (*err) {
1961		failed = "cmyth_rcv_timestamp";
1962		goto fail;
1963	}
1964
1965	if (buf->proginfo_version < 57) {
1966		/*
1967		 * Get proginfo_repeat (ubyte)
1968		 */
1969		consumed = cmyth_rcv_uint8(conn, err, &buf->proginfo_repeat, count);
1970		count -= consumed;
1971		total += consumed;
1972		if (*err) {
1973			failed = "cmyth_rcv_ubyte";
1974			goto fail;
1975		}
1976	}
1977
1978	/*
1979	 * Get proginfo_program_flags (ulong)
1980	 */
1981	consumed = cmyth_rcv_uint32(conn, err, &buf->proginfo_program_flags,
1982				  count);
1983	count -= consumed;
1984	total += consumed;
1985	if (*err) {
1986		failed = "cmyth_rcv_ulong";
1987		goto fail;
1988	}
1989
1990	if (buf->proginfo_version >= 8) {
1991		/*
1992		 * Get proginfo_recgroup (string)
1993		 */
1994		consumed = cmyth_rcv_string(conn, err,
1995					    tmp_str, sizeof(tmp_str) - 1,
1996					    count);
1997		count -= consumed;
1998		total += consumed;
1999		if (*err) {
2000			failed = "cmyth_rcv_string";
2001			goto fail;
2002		}
2003		if (buf->proginfo_recgroup)
2004			ref_release(buf->proginfo_recgroup);
2005		buf->proginfo_recgroup = ref_strdup(tmp_str);
2006	}
2007
2008	if (buf->proginfo_version >= 8 && buf->proginfo_version < 57) {
2009		/*
2010		 * Get proginfo_chancommfree (string)
2011		 */
2012		consumed = cmyth_rcv_string(conn, err,
2013					    tmp_str, sizeof(tmp_str) - 1,
2014					    count);
2015		count -= consumed;
2016		total += consumed;
2017		if (*err) {
2018			failed = "cmyth_rcv_string";
2019			goto fail;
2020		}
2021		if (buf->proginfo_chancommfree)
2022			ref_release(buf->proginfo_chancommfree);
2023		buf->proginfo_chancommfree = ref_strdup(tmp_str);
2024	}
2025
2026	if (buf->proginfo_version >= 8) {
2027		/*
2028		 * Get proginfo_chan_output_filters (string)
2029		 */
2030		consumed = cmyth_rcv_string(conn, err,
2031					    tmp_str, sizeof(tmp_str) - 1,
2032					    count);
2033		count -= consumed;
2034		total += consumed;
2035		if (*err) {
2036			failed = "cmyth_rcv_string";
2037			goto fail;
2038		}
2039		if (buf->proginfo_chan_output_filters)
2040			ref_release(buf->proginfo_chan_output_filters);
2041		buf->proginfo_chan_output_filters = ref_strdup(tmp_str);
2042	}
2043
2044	if (buf->proginfo_version >= 8) {
2045		/*
2046		 * Get proginfo_seriesid (string)
2047		 */
2048		consumed = cmyth_rcv_string(conn, err,
2049					    tmp_str, sizeof(tmp_str) - 1,
2050					    count);
2051		count -= consumed;
2052		total += consumed;
2053		if (*err) {
2054			failed = "cmyth_rcv_string";
2055			goto fail;
2056		}
2057		if (buf->proginfo_seriesid)
2058			ref_release(buf->proginfo_seriesid);
2059		buf->proginfo_seriesid = ref_strdup(tmp_str);
2060	}
2061
2062	if (buf->proginfo_version >= 8) {
2063		/*
2064		 * Get programid (string)
2065		 */
2066		consumed = cmyth_rcv_string(conn, err, tmp_str,
2067					    sizeof(tmp_str) - 1, count);
2068		count -= consumed;
2069		total += consumed;
2070		if (*err) {
2071			failed = "cmyth_rcv_string";
2072			goto fail;
2073		}
2074		if (buf->proginfo_programid)
2075			ref_release(buf->proginfo_programid);
2076		buf->proginfo_programid = ref_strdup(tmp_str);
2077	}
2078
2079	if (buf->proginfo_version >= 67) {
2080		/*
2081		 * Get inetref (string)
2082		 */
2083		consumed = cmyth_rcv_string(conn, err, tmp_str,
2084						sizeof(tmp_str) - 1, count);
2085		count -= consumed;
2086		total += consumed;
2087		if (*err) {
2088			failed = "cmyth_rcv_string";
2089			goto fail;
2090		}
2091		if (buf->proginfo_inetref)
2092			ref_release(buf->proginfo_inetref);
2093		buf->proginfo_inetref = ref_strdup(tmp_str);
2094	}
2095
2096	if (buf->proginfo_version >= 12) {
2097		/*
2098		 * Get lastmodified (string)
2099		 */
2100		if (buf->proginfo_version >= 14) {
2101			consumed =
2102				cmyth_rcv_datetime(conn, err,
2103						   &(buf->proginfo_lastmodified),
2104						   count);
2105		}
2106		else {
2107			consumed =
2108				cmyth_rcv_timestamp(conn, err,
2109						    &(buf->proginfo_lastmodified),
2110						    count);
2111		}
2112		count -= consumed;
2113		total += consumed;
2114		if (*err) {
2115			failed = "cmyth_rcv_timestamp";
2116			goto fail;
2117		}
2118	}
2119
2120	if (buf->proginfo_version >= 12) {
2121		char stars[16];
2122
2123		/*
2124		 * Get stars (string)
2125		 */
2126		consumed = cmyth_rcv_string(conn, err, tmp_str,
2127					    sizeof(tmp_str) - 1, count);
2128		count -= consumed;
2129		total += consumed;
2130		if (*err) {
2131			failed = "cmyth_rcv_string";
2132			goto fail;
2133		}
2134		if (buf->proginfo_stars)
2135			ref_release(buf->proginfo_stars);
2136		snprintf(stars, sizeof(stars), "%3.1f", atof(tmp_str) * 4.0);
2137		buf->proginfo_stars = ref_strdup(stars);
2138	}
2139
2140	if (buf->proginfo_version >= 12) {
2141		/*
2142		 * Get original_air_date (string)
2143		 */
2144		if ((buf->proginfo_version >= 14) & (buf->proginfo_version <=32)) {
2145			consumed =
2146				cmyth_rcv_datetime(conn, err,
2147						   &(buf->proginfo_originalairdate),
2148						   count);
2149		}
2150		else {
2151			consumed =
2152				cmyth_rcv_timestamp(conn, err,
2153						    &(buf->proginfo_originalairdate),
2154						    count);
2155		}
2156		count -= consumed;
2157		total += consumed;
2158		if (*err) {
2159			failed = "cmyth_rcv_string";
2160			goto fail;
2161		}
2162	}
2163
2164	if (buf->proginfo_version >= 15 && buf->proginfo_version < 57) {
2165		/*
2166		 * Get has_air_date (ubyte)
2167		 */
2168		consumed = cmyth_rcv_uint8(conn, err,
2169					   &buf->proginfo_hasairdate, count);
2170		count -= consumed;
2171		total += consumed;
2172		if (*err) {
2173			failed = "cmyth_rcv_ubyte";
2174			goto fail;
2175		}
2176	}
2177
2178	if (buf->proginfo_version >= 18) {
2179		/*
2180		 * Get playgroup (string)
2181		 */
2182		consumed = cmyth_rcv_string(conn, err, tmp_str,
2183					    sizeof(tmp_str) - 1, count);
2184		count -= consumed;
2185		total += consumed;
2186		if (*err) {
2187			failed = "cmyth_rcv_string";
2188			goto fail;
2189		}
2190		if (buf->proginfo_playgroup)
2191			ref_release(buf->proginfo_playgroup);
2192		buf->proginfo_playgroup = ref_strdup(tmp_str);
2193	}
2194	if (buf->proginfo_version >= 25) {
2195		/*
2196		 * Get proginfo_recpriority_2 (byte)
2197		 */
2198		consumed = cmyth_rcv_int8(conn, err,
2199					    &buf->proginfo_recpriority_2,
2200					    count);
2201		count -= consumed;
2202		total += consumed;
2203		if (*err) {
2204			failed = "cmyth_rcv_long";
2205			goto fail;
2206		}
2207	}
2208	if (buf->proginfo_version >= 31) {
2209		/*
2210		 * Get proginfo_parentid (ulong)
2211		 */
2212		consumed = cmyth_rcv_uint32(conn, err,
2213					&buf->proginfo_parentid, count);
2214		count -= consumed;
2215		total += consumed;
2216		if (*err) {
2217			failed = "cmyth_rcv_ulong";
2218			goto fail;
2219		}
2220	}
2221	if (buf->proginfo_version >= 32) {
2222		/*
2223		 * Get storagegroup (string)
2224		 */
2225		consumed = cmyth_rcv_string(conn, err, tmp_str,
2226					    sizeof(tmp_str) - 1, count);
2227		count -= consumed;
2228		total += consumed;
2229		if (*err) {
2230			failed = "cmyth_rcv_string";
2231			goto fail;
2232		}
2233		if (buf->proginfo_storagegroup)
2234			ref_release(buf->proginfo_storagegroup);
2235		buf->proginfo_storagegroup = ref_strdup(tmp_str);
2236	}
2237	if (buf->proginfo_version >= 35) {
2238		/*
2239		 * Get audioproperties,videoproperties,subtitletype (ushort)
2240		 */
2241		consumed = cmyth_rcv_uint16(conn, err,
2242				&buf->proginfo_audioproperties, count);
2243		count -= consumed;
2244		total += consumed;
2245		if (*err) {
2246			failed = "cmyth_rcv_ushort audio";
2247			goto fail;
2248		}
2249		consumed = cmyth_rcv_uint16(conn, err,
2250				&buf->proginfo_videoproperties, count);
2251		count -= consumed;
2252		total += consumed;
2253		if (*err) {
2254			failed = "cmyth_rcv_ushort video";
2255			goto fail;
2256		}
2257		consumed = cmyth_rcv_uint16(conn, err,
2258				&buf->proginfo_subtitletype, count);
2259		count -= consumed;
2260		total += consumed;
2261		if (*err) {
2262			failed = "cmyth_rcv_ushort subtitletype";
2263			goto fail;
2264		}
2265	}
2266
2267	/*
2268	 * Get Year
2269	 */
2270	if (buf->proginfo_version >= 43) {
2271		consumed = cmyth_rcv_uint16(conn, err, &buf->proginfo_year,
2272						count);
2273		count -= consumed;
2274		total += consumed;
2275		if (*err) {
2276			failed = "cmyth_rcv_ushort proginfo_year";
2277			goto fail;
2278		}
2279	}
2280
2281	cmyth_dbg(CMYTH_DBG_INFO, "%s: got recording info\n", __FUNCTION__);
2282
2283	cmyth_proginfo_parse_url(buf);
2284	return total;
2285
2286    fail:
2287	cmyth_dbg(CMYTH_DBG_ERROR, "%s: %s() failed (%d) (count = %d)\n",
2288		  __FUNCTION__, failed, *err, count);
2289	return total;
2290}
2291
2292/*
2293 * cmyth_rcv_chaninfo(cmyth_conn_t conn, cmyth_proginfo_t buf, int count)
2294 *
2295 * Scope: PRIVATE (mapped to __cmyth_rcv_chaninfo)
2296 *
2297 * Description
2298 *
2299 * Receive a program information structure containing channel
2300 * information from a list of tokens in a MythTV Protocol message.
2301 * Channel information is a subset of program information containing
2302 * only the title, episode name (subtitle), description, category,
2303 * start and end timestamps, callsign, icon path (a pathname to the
2304 * channel icon found in filename), channel name, and channel id.
2305 * This is the information returned for each program in a program
2306 * guide when browsing on a recorder.
2307 *
2308 * Tokens in MythTV Protocol messages are separated by the string:
2309 * []:[] or terminated by running out of message.  Up to 'count' Bytes
2310 * will be consumed from the socket specified by 'conn' (stopping when
2311 * a separator is seen or 'count' is exhausted).  The proginfo
2312 * structure specified in 'buf' will be filled out.  If an error is
2313 * encountered and 'err' is not NULL, an indication of the nature of
2314 * the error will be recorded by placing an error code in the location
2315 * pointed to by 'err'.  If all goes well, 'err' wil be set to 0.
2316 *
2317 * Return Value:
2318 *
2319 * A value >=0 indicating the number of bytes consumed.
2320 *
2321 * Error Codes:
2322 *
2323 * In addition to system call error codes, the following errors may be
2324 * placed in 'err':
2325 *
2326 * ERANGE       The token received did not parse into a channel
2327 *              information structure
2328 *
2329 * EINVAL       The token received is not numeric or is signed
2330 */
2331int
2332cmyth_rcv_chaninfo(cmyth_conn_t conn, int *err, cmyth_proginfo_t buf,
2333		   int count)
2334{
2335	int consumed;
2336	int total = 0;
2337	char *failed = NULL;
2338	char tmp_str[32768];
2339
2340	if (count <= 0) {
2341		*err = EINVAL;
2342		return 0;
2343	}
2344
2345	tmp_str[sizeof(tmp_str) - 1] = '\0';
2346
2347	/*
2348	 * Get proginfo_title (string)
2349	 */
2350	consumed = cmyth_rcv_string(conn, err,
2351				    tmp_str, sizeof(tmp_str) - 1, count);
2352	count -= consumed;
2353	total += consumed;
2354	if (*err) {
2355		failed = "cmyth_rcv_string";
2356		goto fail;
2357	}
2358	if (buf->proginfo_title)
2359		ref_release(buf->proginfo_title);
2360	buf->proginfo_title = ref_strdup(tmp_str);
2361
2362	/*
2363	 * Get proginfo_subtitle (string)
2364	 */
2365	consumed = cmyth_rcv_string(conn, err,
2366				    tmp_str, sizeof(tmp_str) - 1, count);
2367	count -= consumed;
2368	total += consumed;
2369	if (*err) {
2370		failed = "cmyth_rcv_string";
2371		goto fail;
2372	}
2373	if (buf->proginfo_subtitle)
2374		ref_release(buf->proginfo_subtitle);
2375	buf->proginfo_subtitle = ref_strdup(tmp_str);
2376
2377	/*
2378	 * Get proginfo_description (string)
2379	 */
2380	consumed = cmyth_rcv_string(conn, err,
2381				    tmp_str, sizeof(tmp_str) - 1, count);
2382	count -= consumed;
2383	total += consumed;
2384	if (*err) {
2385		failed = "cmyth_rcv_string";
2386		goto fail;
2387	}
2388	if (buf->proginfo_description)
2389		ref_release(buf->proginfo_description);
2390	buf->proginfo_description = ref_strdup(tmp_str);
2391
2392	/*
2393	 * Get proginfo_category (string)
2394	 */
2395	consumed = cmyth_rcv_string(conn, err,
2396				    tmp_str, sizeof(tmp_str) - 1, count);
2397	count -= consumed;
2398	total += consumed;
2399	if (*err) {
2400		failed = "cmyth_rcv_string";
2401		goto fail;
2402	}
2403	if (buf->proginfo_category)
2404		ref_release(buf->proginfo_category);
2405	buf->proginfo_category = ref_strdup(tmp_str);
2406
2407	/*
2408	 * Get proginfo_start_ts (timestamp)
2409	 */
2410	consumed = cmyth_rcv_timestamp(conn, err,
2411				       &(buf->proginfo_start_ts), count);
2412	count -= consumed;
2413	total += consumed;
2414	if (*err) {
2415		failed = "cmyth_rcv_timestamp";
2416		goto fail;
2417	}
2418
2419	/*
2420	 * Get proginfo_end_ts (timestamp)
2421	 */
2422	consumed = cmyth_rcv_timestamp(conn, err, &(buf->proginfo_end_ts),
2423				       count);
2424	count -= consumed;
2425	total += consumed;
2426	if (*err) {
2427		failed = "cmyth_rcv_timestamp";
2428		goto fail;
2429	}
2430
2431	/*
2432	 * Get proginfo_chansign (string)
2433	 */
2434	consumed = cmyth_rcv_string(conn, err,
2435				    tmp_str, sizeof(tmp_str) - 1, count);
2436	count -= consumed;
2437	total += consumed;
2438	if (*err) {
2439		failed = "cmyth_rcv_string";
2440		goto fail;
2441	}
2442	if (buf->proginfo_chansign)
2443		ref_release(buf->proginfo_chansign);
2444	buf->proginfo_chansign = ref_strdup(tmp_str);
2445
2446	/*
2447	 * Get proginfo_url (string) (this is the channel icon path)
2448	 *
2449	 * XXX: This isn't a url, but what is it?
2450	 */
2451	consumed = cmyth_rcv_string(conn, err,
2452				    tmp_str, sizeof(tmp_str) - 1, count);
2453	count -= consumed;
2454	total += consumed;
2455	if (*err) {
2456		failed = "cmyth_rcv_string";
2457		goto fail;
2458	}
2459	buf->proginfo_url = NULL;
2460
2461	/*
2462	 * Get proginfo_channame (string)
2463	 */
2464	consumed = cmyth_rcv_string(conn, err,
2465				    tmp_str, sizeof(tmp_str) - 1, count);
2466	count -= consumed;
2467	total += consumed;
2468	if (*err) {
2469		failed = "cmyth_rcv_string";
2470		goto fail;
2471	}
2472	if (buf->proginfo_channame)
2473		ref_release(buf->proginfo_channame);
2474	buf->proginfo_channame = ref_strdup(tmp_str);
2475
2476	/*
2477	 * Get proginfo_chanId (long)
2478	 */
2479	consumed = cmyth_rcv_string(conn, err,
2480				    tmp_str, sizeof(tmp_str) - 1, count);
2481	count -= consumed;
2482	total += consumed;
2483	if (*err) {
2484		failed = "cmyth_rcv_long";
2485		goto fail;
2486	}
2487	buf->proginfo_chanId = atoi(tmp_str);
2488
2489	// get seriesid
2490	consumed = cmyth_rcv_string(conn, err,
2491				    tmp_str, sizeof(tmp_str) - 1, count);
2492	count -= consumed;
2493	total += consumed;
2494	if (*err) {
2495		failed = "cmyth_rcv_string";
2496		goto fail;
2497	}
2498	if (buf->proginfo_seriesid)
2499		ref_release(buf->proginfo_seriesid);
2500	buf->proginfo_seriesid = ref_strdup(tmp_str);
2501
2502	// get programid
2503	consumed = cmyth_rcv_string(conn, err,
2504				    tmp_str, sizeof(tmp_str) - 1, count);
2505	count -= consumed;
2506	total += consumed;
2507	if (*err) {
2508		failed = "cmyth_rcv_string";
2509		goto fail;
2510	}
2511	if (buf->proginfo_programid)
2512		ref_release(buf->proginfo_programid);
2513	buf->proginfo_programid = ref_strdup(tmp_str);
2514
2515	// get chanOutputFilters
2516	consumed = cmyth_rcv_string(conn, err,
2517				    tmp_str, sizeof(tmp_str) - 1, count);
2518	count -= consumed;
2519	total += consumed;
2520	if (*err) {
2521		failed = "cmyth_rcv_string";
2522		goto fail;
2523	}
2524	// get repeat
2525	consumed = cmyth_rcv_string(conn, err,
2526				    tmp_str, sizeof(tmp_str) - 1, count);
2527	count -= consumed;
2528	total += consumed;
2529	if (*err) {
2530		failed = "cmyth_rcv_string";
2531		goto fail;
2532	}
2533	// get airdate
2534	consumed = cmyth_rcv_string(conn, err,
2535				    tmp_str, sizeof(tmp_str) - 1, count);
2536	count -= consumed;
2537	total += consumed;
2538	if (*err) {
2539		failed = "cmyth_rcv_string";
2540		goto fail;
2541	}
2542	// get stars
2543	consumed = cmyth_rcv_string(conn, err,
2544				    tmp_str, sizeof(tmp_str) - 1, count);
2545	count -= consumed;
2546	total += consumed;
2547	if (*err) {
2548		failed = "cmyth_rcv_string";
2549		goto fail;
2550	}
2551
2552	return total;
2553
2554    fail:
2555	cmyth_dbg(CMYTH_DBG_ERROR, "%s: %s() failed (%d) (count = %d)\n",
2556		  __FUNCTION__, failed, *err, count);
2557	return total;
2558}
2559
2560/*
2561 * cmyth_rcv_proglist(cmyth_conn_t conn, int *err, cmyth_proglist_t buf,
2562 *                    int count)
2563 *
2564 * Scope: PRIVATE (mapped to __cmyth_rcv_proglist)
2565 *
2566 * Description
2567 *
2568 * Receive a program list from a list of tokens in a MythTV Protocol
2569 * message.  Tokens in MythTV Protocol messages are separated by the
2570 * string: []:[] or terminated by running out of message.  Up to
2571 * 'count' Bytes will be consumed from the socket specified by 'conn'
2572 * (stopping when a separator is seen or 'count' is exhausted).  The
2573 * program list structure specified in 'buf' will be filled out.  If
2574 * an error is encountered and 'err' is not NULL, an indication of the
2575 * nature of the error will be recorded by placing an error code in
2576 * the location pointed to by 'err'.  If all goes well, 'err' wil be
2577 * set to 0.
2578 *
2579 * Return Value:
2580 *
2581 * A value >=0 indicating the number of bytes consumed.
2582 *
2583 * Error Codes:
2584 *
2585 * In addition to system call error codes, the following errors may be
2586 * placed in 'err':
2587 *
2588 * ERANGE       The token received did not parse into a program list
2589 */
2590int
2591cmyth_rcv_proglist(cmyth_conn_t conn, int *err, cmyth_proglist_t buf,
2592		   int count)
2593{
2594	int tmp_err;
2595	int consumed = 0;
2596	int r;
2597	int c;
2598	cmyth_proginfo_t pi;
2599	int i;
2600
2601	cmyth_dbg(CMYTH_DBG_DEBUG, "%s\n", __FUNCTION__);
2602	if (!err) {
2603		err = &tmp_err;
2604	}
2605	if (count <= 0) {
2606		*err = EINVAL;
2607		return 0;
2608	}
2609	*err = 0;
2610	if(!buf) {
2611		*err = EINVAL;
2612		cmyth_dbg(CMYTH_DBG_ERROR, "%s: NULL buffer\n", __FUNCTION__);
2613		return 0;
2614	}
2615	r = cmyth_rcv_int32(conn, err, &buf->proglist_count, count);
2616	consumed += r;
2617	if (*err) {
2618		cmyth_dbg(CMYTH_DBG_ERROR,
2619			  "%s: cmyth_rcv_long() failed (%d)\n",
2620			  __FUNCTION__, *err);
2621		return consumed;
2622	}
2623	count -= r;
2624	c = buf->proglist_count;
2625	buf->proglist_list = malloc(c * sizeof(cmyth_proginfo_t));
2626	if (!buf->proglist_list) {
2627		cmyth_dbg(CMYTH_DBG_ERROR, "%s: malloc() failed for list\n",
2628			  __FUNCTION__);
2629		*err = ENOMEM;
2630		return consumed;
2631	}
2632	memset(buf->proglist_list, 0, c * sizeof(cmyth_proginfo_t));
2633	for (i = 0; i < c; ++i) {
2634		pi = cmyth_proginfo_create();
2635		if (!pi) {
2636			cmyth_dbg(CMYTH_DBG_ERROR,
2637				  "%s: cmyth_proginfo_create() failed\n",
2638				  __FUNCTION__);
2639			*err = ENOMEM;
2640			break;
2641		}
2642		r = cmyth_rcv_proginfo(conn, err, pi, count);
2643		consumed += r;
2644		count -= r;
2645		if (*err) {
2646			ref_release(pi);
2647			cmyth_dbg(CMYTH_DBG_ERROR,
2648				  "%s: cmyth_rcv_proginfo() failed (%d)\n",
2649				  __FUNCTION__, *err);
2650			break;
2651		}
2652		buf->proglist_list[i] = pi;
2653	}
2654	return consumed;
2655}
2656
2657/*
2658 * cmyth_rcv_keyframe(cmyth_conn_t conn, int *err, cmyth_keyframe_t buf,
2659 *                    int count)
2660 *
2661 * Scope: PRIVATE (mapped to __cmyth_rcv_keyframe)
2662 *
2663 * Description
2664 *
2665 * Receive a keyframe description from a list of tokens in a MythTV
2666 * Protocol message.  Tokens in MythTV Protocol messages are separated
2667 * by the string: []:[] or terminated by running out of message.  Up
2668 * to 'count' Bytes will be consumed from the socket specified by
2669 * 'conn' (stopping when a separator is seen or 'count' is exhausted).
2670 * The keyframe structure specified in 'buf' will be filled out.  If
2671 * an error is encountered and 'err' is not NULL, an indication of the
2672 * nature of the error will be recorded by placing an error code in
2673 * the location pointed to by 'err'.  If all goes well, 'err' wil be
2674 * set to 0.
2675 *
2676 * Return Value:
2677 *
2678 * A value >=0 indicating the number of bytes consumed.
2679 *
2680 * Error Codes:
2681 *
2682 * In addition to system call error codes, the following errors may be
2683 * placed in 'err':
2684 *
2685 * ERANGE       The token received did not parse into a keyframe
2686 *
2687 * EINVAL       The token received is not numeric or is signed
2688 */
2689int
2690cmyth_rcv_keyframe(cmyth_conn_t conn, int *err, cmyth_keyframe_t buf,
2691		   int count)
2692{
2693	int tmp_err;
2694
2695	if (!err) {
2696		err = &tmp_err;
2697	}
2698	/*
2699	 * For now this is unimplemented.
2700	 */
2701	*err = ENOSYS;
2702	return 0;
2703}
2704
2705/*
2706 * cmyth_rcv_freespace(cmyth_conn_t conn, cmyth_freespace_t buf, int count)
2707 *
2708 * Scope: PRIVATE (mapped to __cmyth_rcv_freespace)
2709 *
2710 * Description
2711 *
2712 * Receive a free space description from a list of tokens in a MythTV
2713 * Protocol message.  Tokens in MythTV Protocol messages are separated
2714 * by the string: []:[] or terminated by running out of message.  Up
2715 * to 'count' Bytes will be consumed from the socket specified by
2716 * 'conn' (stopping when a separator is seen or 'count' is exhausted).
2717 * The free space structure specified in 'buf' will be filled out.  If
2718 * an error is encountered and 'err' is not NULL, an indication of the
2719 * nature of the error will be recorded by placing an error code in
2720 * the location pointed to by 'err'.  If all goes well, 'err' wil be
2721 * set to 0.
2722 *
2723 * Return Value:
2724 *
2725 * A value >=0 indicating the number of bytes consumed.
2726 *
2727 * Error Codes:
2728 *
2729 * In addition to system call error codes, the following errors may be
2730 * placed in 'err':
2731 *
2732 * ERANGE       The token received did not parse into a free space
2733 *              description
2734 *
2735 * EINVAL       The token received is not numeric or is signed
2736 */
2737int
2738cmyth_rcv_freespace(cmyth_conn_t conn, int *err, cmyth_freespace_t buf,
2739		    int count)
2740{
2741	int tmp_err;
2742
2743	if (!err) {
2744		err = &tmp_err;
2745	}
2746	/*
2747	 * For now this is unimplemented.
2748	 */
2749	*err = ENOSYS;
2750	return 0;
2751}
2752
2753/*
2754 * cmyth_rcv_recorder(cmyth_conn_t conn, cmyth_recorder_t buf,
2755 *                    int count)
2756 *
2757 * Scope: PRIVATE (mapped to __cmyth_rcv_recorder)
2758 *
2759 * Description
2760 *
2761 * Receive a recorder description from a list of tokens in a MythTV
2762 * Protocol message.  Tokens in MythTV Protocol messages are separated
2763 * by the string: []:[] or terminated by running out of message.  Up
2764 * to 'count' Bytes will be consumed from the socket specified by
2765 * 'conn' (stopping when a separator is seen or 'count' is exhausted).
2766 * The recorder structure specified in 'buf' will be filled out.  If
2767 * an error is encountered and 'err' is not NULL, an indication of the
2768 * nature of the error will be recorded by placing an error code in
2769 * the location pointed to by 'err'.  If all goes well, 'err' wil be
2770 * set to 0.
2771 *
2772 * Return Value:
2773 *
2774 * A value >=0 indicating the number of bytes consumed.
2775 *
2776 * Error Codes:
2777 *
2778 * In addition to system call error codes, the following errors may be
2779 * placed in 'err':
2780 *
2781 * ERANGE       The token received did not parse into a recorder
2782 *              description
2783 *
2784 * EINVAL       The token received is not numeric or is signed
2785 */
2786int
2787cmyth_rcv_recorder(cmyth_conn_t conn, int *err, cmyth_recorder_t buf,
2788		   int count)
2789{
2790	int tmp_err;
2791
2792	if (!err) {
2793		err = &tmp_err;
2794	}
2795	/*
2796	 * For now this is unimplemented.
2797	 */
2798	*err = ENOSYS;
2799	return 0;
2800}
2801
2802/*
2803 * cmyth_rcv_ringbuf(cmyth_conn_t conn, int *err, cmyth_ringbuf_t buf,
2804 *                   int count)
2805 *
2806 * Scope: PRIVATE (mapped to __cmyth_rcv_ringbuf)
2807 *
2808 * Description
2809 *
2810 * Receive a ring buffer description from a list of tokens in a MythTV
2811 * Protocol message.  Tokens in MythTV Protocol messages are separated
2812 * by the string: []:[] or terminated by running out of message.  Up
2813 * to 'count' Bytes will be consumed from the socket specified by
2814 * 'conn' (stopping when a separator is seen or 'count' is exhausted).
2815 * The ring buffer structure specified in 'buf' will be filled out.
2816 * If an error is encountered and 'err' is not NULL, an indication of
2817 * the nature of the error will be recorded by placing an error code
2818 * in the location pointed to by 'err'.  If all goes well, 'err' wil
2819 * be set to 0.
2820 *
2821 * Return Value:
2822 *
2823 * A value >=0 indicating the number of bytes consumed.
2824 *
2825 * Error Codes:
2826 *
2827 * In addition to system call error codes, the following errors may be
2828 * placed in 'err':
2829 *
2830 * ERANGE       The token received did not parse into a recorder
2831 *              description
2832 *
2833 * EINVAL       The token received is not numeric or is signed
2834 */
2835int
2836cmyth_rcv_ringbuf(cmyth_conn_t conn, int *err, cmyth_ringbuf_t buf, int count)
2837{
2838	int tmp_err;
2839
2840	if (!err) {
2841		err = &tmp_err;
2842	}
2843	/*
2844	 * For now this is unimplemented.
2845	 */
2846	*err = ENOSYS;
2847	return 0;
2848}
2849
2850/*
2851 * cmyth_rcv_data(cmyth_conn_t conn, int *err, unsigned char *buf, int count)
2852 *
2853 * Scope: PRIVATE (mapped to __cmyth_rcv_data)
2854 *
2855 * Description
2856 *
2857 * Receive raw data from the socket specified by 'conn' and place it
2858 * in 'buf'.  This function consumes 'count' bytes and places them in
2859 * 'buf'.  If an error is encountered and 'err' is not NULL, an
2860 * indication of the nature of the error will be recorded by placing
2861 * an error code in the location pointed to by 'err'.  If all goes
2862 * well, 'err' wil be set to 0.
2863 *
2864 * Return Value:
2865 *
2866 * A value >=0 indicating the number of bytes consumed.
2867 */
2868int
2869cmyth_rcv_data(cmyth_conn_t conn, int *err, unsigned char *buf, int count)
2870{
2871	int r;
2872	int total = 0;
2873	unsigned char *p;
2874	int tmp_err;
2875	struct timeval tv;
2876	fd_set fds;
2877
2878	if (!err) {
2879		err = &tmp_err;
2880	}
2881	if (count <= 0) {
2882		*err = EINVAL;
2883		return 0;
2884	}
2885	*err = 0;
2886	if (!conn) {
2887		cmyth_dbg(CMYTH_DBG_ERROR, "%s: no connection\n",
2888			  __FUNCTION__);
2889		*err = EINVAL;
2890		return 0;
2891	}
2892	p = buf;
2893	while (count > 0) {
2894		tv.tv_sec = 10;
2895		tv.tv_usec = 0;
2896		FD_ZERO(&fds);
2897		FD_SET(conn->conn_fd, &fds);
2898		if (select((int)conn->conn_fd+1, &fds, NULL, NULL, &tv) == 0) {
2899			conn->conn_hang = 1;
2900			return -ETIMEDOUT;
2901		} else {
2902			conn->conn_hang = 0;
2903		}
2904		r = recv(conn->conn_fd, p, count, 0);
2905		if (r < 0) {
2906			if (total == 0) {
2907				cmyth_dbg(CMYTH_DBG_ERROR,
2908					  "%s: read failed (%d)\n",
2909					  __FUNCTION__, errno);
2910	            conn->conn_hang = 1;
2911				if (r == 0)
2912					*err = -1 * EBADF;
2913				else
2914					*err = -1 * errno;
2915				return 0;
2916			}
2917			/*
2918			 * There were bytes read before the error, use them and
2919			 * then report the error next time.
2920			 */
2921			break;
2922		}
2923		total += r;
2924		count -= r;
2925		p += r;
2926	}
2927	return total;
2928}
2929
2930void cmyth_toupper_string(char *str)
2931{
2932	if (str) {
2933		int i;
2934		for ( i=0 ; i < sizeof(str) && str[i] != '\0' ; i++ ) {
2935			str[i] = toupper(str[i]);
2936		}
2937	}
2938}