|
Packit |
eed494 |
/* -*- c-basic-offset: 8; -*- */
|
|
Packit |
eed494 |
/* shout.c: Implementation of public libshout interface shout.h
|
|
Packit |
eed494 |
*
|
|
Packit |
eed494 |
* Copyright (C) 2002-2004 the Icecast team <team@icecast.org>
|
|
Packit |
eed494 |
*
|
|
Packit |
eed494 |
* This library is free software; you can redistribute it and/or
|
|
Packit |
eed494 |
* modify it under the terms of the GNU Library General Public
|
|
Packit |
eed494 |
* License as published by the Free Software Foundation; either
|
|
Packit |
eed494 |
* version 2 of the License, or (at your option) any later version.
|
|
Packit |
eed494 |
*
|
|
Packit |
eed494 |
* This library is distributed in the hope that it will be useful,
|
|
Packit |
eed494 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
eed494 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
eed494 |
* Library General Public License for more details.
|
|
Packit |
eed494 |
*
|
|
Packit |
eed494 |
* You should have received a copy of the GNU Library General Public
|
|
Packit |
eed494 |
* License along with this library; if not, write to the Free
|
|
Packit |
eed494 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
Packit |
eed494 |
*
|
|
Packit |
eed494 |
* $Id: shout.c 11554 2006-06-09 23:09:33Z brendan $
|
|
Packit |
eed494 |
*/
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
#ifdef HAVE_CONFIG_H
|
|
Packit |
eed494 |
#include <config.h>
|
|
Packit |
eed494 |
#endif
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
#include <stdio.h>
|
|
Packit |
eed494 |
#include <stdlib.h>
|
|
Packit |
eed494 |
#include <string.h>
|
|
Packit |
eed494 |
#include <errno.h>
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
#include <shout/shout.h>
|
|
Packit |
eed494 |
#include <net/sock.h>
|
|
Packit |
eed494 |
#include "timing/timing.h"
|
|
Packit |
eed494 |
#include "httpp/httpp.h"
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
#include "shout_private.h"
|
|
Packit |
eed494 |
#include "util.h"
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
/* -- local prototypes -- */
|
|
Packit |
eed494 |
static int queue_data(shout_queue_t *queue, const unsigned char *data, size_t len);
|
|
Packit |
eed494 |
static int queue_str(shout_t *self, const char *str);
|
|
Packit |
eed494 |
static int queue_printf(shout_t *self, const char *fmt, ...);
|
|
Packit |
eed494 |
static inline void queue_free(shout_queue_t *queue);
|
|
Packit |
eed494 |
static int send_queue(shout_t *self);
|
|
Packit |
eed494 |
static int get_response(shout_t *self);
|
|
Packit |
eed494 |
static int try_connect (shout_t *self);
|
|
Packit |
eed494 |
static int try_write (shout_t *self, const void *data, size_t len);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
static int create_request(shout_t *self);
|
|
Packit |
eed494 |
static int create_http_request(shout_t *self);
|
|
Packit |
eed494 |
static int create_xaudiocast_request(shout_t *self);
|
|
Packit |
eed494 |
static int create_icy_request(shout_t *self);
|
|
Packit |
eed494 |
static int parse_response(shout_t *self);
|
|
Packit |
eed494 |
static int parse_http_response(shout_t *self);
|
|
Packit |
eed494 |
static int parse_xaudiocast_response(shout_t *self);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
static char *http_basic_authorization(shout_t *self);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
/* -- static data -- */
|
|
Packit |
eed494 |
static int _initialized = 0;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
/* -- public functions -- */
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
void shout_init(void)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (_initialized)
|
|
Packit |
eed494 |
return;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
sock_initialize();
|
|
Packit |
eed494 |
_initialized = 1;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
void shout_shutdown(void)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!_initialized)
|
|
Packit |
eed494 |
return;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
sock_shutdown();
|
|
Packit |
eed494 |
_initialized = 0;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
shout_t *shout_new(void)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
shout_t *self;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
/* in case users haven't done this explicitly. Should we error
|
|
Packit |
eed494 |
* if not initialized instead? */
|
|
Packit |
eed494 |
shout_init();
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (!(self = (shout_t *)calloc(1, sizeof(shout_t)))) {
|
|
Packit |
eed494 |
return NULL;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (shout_set_host(self, LIBSHOUT_DEFAULT_HOST) != SHOUTERR_SUCCESS) {
|
|
Packit |
eed494 |
shout_free(self);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return NULL;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
if (shout_set_user(self, LIBSHOUT_DEFAULT_USER) != SHOUTERR_SUCCESS) {
|
|
Packit |
eed494 |
shout_free(self);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return NULL;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
if (shout_set_agent(self, LIBSHOUT_DEFAULT_USERAGENT) != SHOUTERR_SUCCESS) {
|
|
Packit |
eed494 |
shout_free(self);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return NULL;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
if (!(self->audio_info = _shout_util_dict_new())) {
|
|
Packit |
eed494 |
shout_free(self);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return NULL;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
self->port = LIBSHOUT_DEFAULT_PORT;
|
|
Packit |
eed494 |
self->format = LIBSHOUT_DEFAULT_FORMAT;
|
|
Packit |
eed494 |
self->protocol = LIBSHOUT_DEFAULT_PROTOCOL;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
void shout_free(shout_t *self)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!self) return;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->host) free(self->host);
|
|
Packit |
eed494 |
if (self->password) free(self->password);
|
|
Packit |
eed494 |
if (self->mount) free(self->mount);
|
|
Packit |
eed494 |
if (self->name) free(self->name);
|
|
Packit |
eed494 |
if (self->url) free(self->url);
|
|
Packit |
eed494 |
if (self->genre) free(self->genre);
|
|
Packit |
eed494 |
if (self->description) free(self->description);
|
|
Packit |
eed494 |
if (self->user) free(self->user);
|
|
Packit |
eed494 |
if (self->useragent) free(self->useragent);
|
|
Packit |
eed494 |
if (self->audio_info) _shout_util_dict_free (self->audio_info);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
free(self);
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
int shout_open(shout_t *self)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
/* sanity check */
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return SHOUTERR_INSANE;
|
|
Packit |
eed494 |
if (self->state != SHOUT_STATE_UNCONNECTED)
|
|
Packit |
eed494 |
return SHOUTERR_CONNECTED;
|
|
Packit |
eed494 |
if (!self->host || !self->password || !self->port)
|
|
Packit |
eed494 |
return self->error = SHOUTERR_INSANE;
|
|
Packit |
eed494 |
if (self->format == SHOUT_FORMAT_OGG && self->protocol != SHOUT_PROTOCOL_HTTP)
|
|
Packit |
eed494 |
return self->error = SHOUTERR_UNSUPPORTED;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self->error = try_connect(self);
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
int shout_close(shout_t *self)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return SHOUTERR_INSANE;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->state == SHOUT_STATE_UNCONNECTED)
|
|
Packit |
eed494 |
return self->error = SHOUTERR_UNCONNECTED;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->state == SHOUT_STATE_CONNECTED && self->close)
|
|
Packit |
eed494 |
self->close(self);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
sock_close(self->socket);
|
|
Packit |
eed494 |
self->state = SHOUT_STATE_UNCONNECTED;
|
|
Packit |
eed494 |
self->starttime = 0;
|
|
Packit |
eed494 |
self->senttime = 0;
|
|
Packit |
eed494 |
queue_free(&self->rqueue);
|
|
Packit |
eed494 |
queue_free(&self->wqueue);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self->error = SHOUTERR_SUCCESS;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
int shout_send(shout_t *self, const unsigned char *data, size_t len)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return SHOUTERR_INSANE;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->state != SHOUT_STATE_CONNECTED)
|
|
Packit |
eed494 |
return self->error = SHOUTERR_UNCONNECTED;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->starttime <= 0)
|
|
Packit |
eed494 |
self->starttime = timing_get_time();
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (!len)
|
|
Packit |
eed494 |
return send_queue(self);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self->send(self, data, len);
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
ssize_t shout_send_raw(shout_t *self, const unsigned char *data, size_t len)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
ssize_t ret;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return SHOUTERR_INSANE;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->state != SHOUT_STATE_CONNECTED)
|
|
Packit |
eed494 |
return SHOUTERR_UNCONNECTED;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
self->error = SHOUTERR_SUCCESS;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
/* send immediately if possible (should be the common case) */
|
|
Packit |
eed494 |
if (len && ! self->wqueue.len) {
|
|
Packit |
eed494 |
if ((ret = try_write(self, data, len)) < 0)
|
|
Packit |
eed494 |
return self->error;
|
|
Packit |
eed494 |
if (ret < len) {
|
|
Packit |
eed494 |
self->error = queue_data(&self->wqueue, data + ret, len - ret);
|
|
Packit |
eed494 |
if (self->error != SHOUTERR_SUCCESS)
|
|
Packit |
eed494 |
return self->error;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return len;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
self->error = queue_data(&self->wqueue, data, len);
|
|
Packit |
eed494 |
if (self->error != SHOUTERR_SUCCESS)
|
|
Packit |
eed494 |
return self->error;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
ret = send_queue(self);
|
|
Packit |
eed494 |
if (ret == SHOUTERR_SUCCESS || (len && ret == SHOUTERR_BUSY))
|
|
Packit |
eed494 |
return len;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return ret;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
ssize_t shout_queuelen(shout_t *self)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return SHOUTERR_INSANE;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return (ssize_t)self->wqueue.len;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
void shout_sync(shout_t *self)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
int64_t sleep;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->senttime == 0)
|
|
Packit |
eed494 |
return;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
sleep = self->senttime / 1000 - (timing_get_time() - self->starttime);
|
|
Packit |
eed494 |
if (sleep > 0)
|
|
Packit |
eed494 |
timing_sleep((uint64_t)sleep);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
int shout_delay(shout_t *self)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return 0;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->senttime == 0)
|
|
Packit |
eed494 |
return 0;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
/* Is this cast to double needed? */
|
|
Packit |
eed494 |
return self->senttime / 1000 - (timing_get_time() - self->starttime);
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
shout_metadata_t *shout_metadata_new(void)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
return _shout_util_dict_new();
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
void shout_metadata_free(shout_metadata_t *self)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
_shout_util_dict_free(self);
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
int shout_metadata_add(shout_metadata_t *self, const char *name, const char *value)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!self || !name)
|
|
Packit |
eed494 |
return SHOUTERR_INSANE;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return _shout_util_dict_set(self, name, value);
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
/* open second socket to server, send HTTP request to change metadata.
|
|
Packit |
eed494 |
* TODO: prettier error-handling. */
|
|
Packit |
eed494 |
int shout_set_metadata(shout_t *self, shout_metadata_t *metadata)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
sock_t socket;
|
|
Packit |
eed494 |
int rv;
|
|
Packit |
eed494 |
char *encvalue;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (!self || !metadata)
|
|
Packit |
eed494 |
return SHOUTERR_INSANE;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (!(encvalue = _shout_util_dict_urlencode(metadata, '&')))
|
|
Packit |
eed494 |
return SHOUTERR_MALLOC;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if ((socket = sock_connect(self->host, self->port)) <= 0)
|
|
Packit |
eed494 |
return SHOUTERR_NOCONNECT;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->protocol == SHOUT_PROTOCOL_ICY)
|
|
Packit |
eed494 |
rv = sock_write(socket, "GET /admin.cgi?mode=updinfo&pass=%s&%s HTTP/1.0\r\nUser-Agent: %s (Mozilla compatible)\r\n\r\n",
|
|
Packit |
eed494 |
self->password, encvalue, shout_get_agent(self));
|
|
Packit |
eed494 |
else if (self->protocol == SHOUT_PROTOCOL_HTTP) {
|
|
Packit |
eed494 |
char *auth = http_basic_authorization(self);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
rv = sock_write(socket, "GET /admin/metadata?mode=updinfo&mount=%s&%s HTTP/1.0\r\nUser-Agent: %s\r\n%s\r\n",
|
|
Packit |
eed494 |
self->mount, encvalue, shout_get_agent(self), auth ? auth : "");
|
|
Packit |
eed494 |
free(auth);
|
|
Packit |
eed494 |
} else
|
|
Packit |
eed494 |
rv = sock_write(socket, "GET /admin.cgi?mode=updinfo&pass=%s&mount=%s&%s HTTP/1.0\r\nUser-Agent: %s\r\n\r\n",
|
|
Packit |
eed494 |
self->password, self->mount, encvalue, shout_get_agent(self));
|
|
Packit |
eed494 |
free(encvalue);
|
|
Packit |
eed494 |
if (!rv) {
|
|
Packit |
eed494 |
sock_close(socket);
|
|
Packit |
eed494 |
return SHOUTERR_SOCKET;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
sock_close(socket);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return SHOUTERR_SUCCESS;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
/* getters/setters */
|
|
Packit |
eed494 |
const char *shout_version(int *major, int *minor, int *patch)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (major)
|
|
Packit |
eed494 |
*major = LIBSHOUT_MAJOR;
|
|
Packit |
eed494 |
if (minor)
|
|
Packit |
eed494 |
*minor = LIBSHOUT_MINOR;
|
|
Packit |
eed494 |
if (patch)
|
|
Packit |
eed494 |
*patch = LIBSHOUT_MICRO;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return VERSION;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
int shout_get_errno(shout_t *self)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
return self->error;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
const char *shout_get_error(shout_t *self)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return "Invalid shout_t";
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
switch (self->error) {
|
|
Packit |
eed494 |
case SHOUTERR_SUCCESS:
|
|
Packit |
eed494 |
return "No error";
|
|
Packit |
eed494 |
case SHOUTERR_INSANE:
|
|
Packit |
eed494 |
return "Nonsensical arguments";
|
|
Packit |
eed494 |
case SHOUTERR_NOCONNECT:
|
|
Packit |
eed494 |
return "Couldn't connect";
|
|
Packit |
eed494 |
case SHOUTERR_NOLOGIN:
|
|
Packit |
eed494 |
return "Login failed";
|
|
Packit |
eed494 |
case SHOUTERR_SOCKET:
|
|
Packit |
eed494 |
return "Socket error";
|
|
Packit |
eed494 |
case SHOUTERR_MALLOC:
|
|
Packit |
eed494 |
return "Out of memory";
|
|
Packit |
eed494 |
case SHOUTERR_CONNECTED:
|
|
Packit |
eed494 |
return "Cannot set parameter while connected";
|
|
Packit |
eed494 |
case SHOUTERR_UNCONNECTED:
|
|
Packit |
eed494 |
return "Not connected";
|
|
Packit |
eed494 |
case SHOUTERR_BUSY:
|
|
Packit |
eed494 |
return "Socket is busy";
|
|
Packit |
eed494 |
case SHOUTERR_UNSUPPORTED:
|
|
Packit |
eed494 |
return "This libshout doesn't support the requested option";
|
|
Packit |
eed494 |
default:
|
|
Packit |
eed494 |
return "Unknown error";
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
/* Returns:
|
|
Packit |
eed494 |
* SHOUTERR_CONNECTED if the connection is open,
|
|
Packit |
eed494 |
* SHOUTERR_UNCONNECTED if it has not yet been opened,
|
|
Packit |
eed494 |
* or an error from try_connect, including SHOUTERR_BUSY
|
|
Packit |
eed494 |
*/
|
|
Packit |
eed494 |
int shout_get_connected(shout_t *self)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
int rc;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return SHOUTERR_INSANE;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->state == SHOUT_STATE_CONNECTED)
|
|
Packit |
eed494 |
return SHOUTERR_CONNECTED;
|
|
Packit |
eed494 |
if (self->state != SHOUT_STATE_UNCONNECTED) {
|
|
Packit |
eed494 |
if ((rc = try_connect(self)) == SHOUTERR_SUCCESS)
|
|
Packit |
eed494 |
return SHOUTERR_CONNECTED;
|
|
Packit |
eed494 |
return rc;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return SHOUTERR_UNCONNECTED;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
int shout_set_host(shout_t *self, const char *host)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return SHOUTERR_INSANE;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->state != SHOUT_STATE_UNCONNECTED)
|
|
Packit |
eed494 |
return self->error = SHOUTERR_CONNECTED;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->host)
|
|
Packit |
eed494 |
free(self->host);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (!(self->host = _shout_util_strdup(host)))
|
|
Packit |
eed494 |
return self->error = SHOUTERR_MALLOC;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self->error = SHOUTERR_SUCCESS;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
const char *shout_get_host(shout_t *self)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return NULL;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self->host;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
int shout_set_port(shout_t *self, unsigned short port)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return SHOUTERR_INSANE;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->state != SHOUT_STATE_UNCONNECTED)
|
|
Packit |
eed494 |
return self->error = SHOUTERR_CONNECTED;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
self->port = port;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self->error = SHOUTERR_SUCCESS;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
unsigned short shout_get_port(shout_t *self)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return 0;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self->port;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
int shout_set_password(shout_t *self, const char *password)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return SHOUTERR_INSANE;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->state != SHOUT_STATE_UNCONNECTED)
|
|
Packit |
eed494 |
return self->error = SHOUTERR_CONNECTED;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->password)
|
|
Packit |
eed494 |
free (self->password);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (!(self->password = _shout_util_strdup(password)))
|
|
Packit |
eed494 |
return self->error = SHOUTERR_MALLOC;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self->error = SHOUTERR_SUCCESS;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
const char* shout_get_password(shout_t *self)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return NULL;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self->password;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
int shout_set_mount(shout_t *self, const char *mount)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
size_t len;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (!self || !mount)
|
|
Packit |
eed494 |
return SHOUTERR_INSANE;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->state != SHOUT_STATE_UNCONNECTED)
|
|
Packit |
eed494 |
return self->error = SHOUTERR_CONNECTED;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->mount)
|
|
Packit |
eed494 |
free(self->mount);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
len = strlen (mount) + 1;
|
|
Packit |
eed494 |
if (mount[0] != '/')
|
|
Packit |
eed494 |
len++;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (!(self->mount = malloc(len)))
|
|
Packit |
eed494 |
return self->error = SHOUTERR_MALLOC;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
sprintf (self->mount, "%s%s", mount[0] == '/' ? "" : "/", mount);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self->error = SHOUTERR_SUCCESS;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
const char *shout_get_mount(shout_t *self)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return NULL;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self->mount;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
int shout_set_name(shout_t *self, const char *name)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return SHOUTERR_INSANE;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->state != SHOUT_STATE_UNCONNECTED)
|
|
Packit |
eed494 |
return self->error = SHOUTERR_CONNECTED;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->name)
|
|
Packit |
eed494 |
free(self->name);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (!(self->name = _shout_util_strdup(name)))
|
|
Packit |
eed494 |
return self->error = SHOUTERR_MALLOC;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self->error = SHOUTERR_SUCCESS;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
const char *shout_get_name(shout_t *self)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return NULL;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self->name;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
int shout_set_url(shout_t *self, const char *url)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return SHOUTERR_INSANE;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->state != SHOUT_STATE_UNCONNECTED)
|
|
Packit |
eed494 |
return self->error = SHOUTERR_CONNECTED;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->url)
|
|
Packit |
eed494 |
free(self->url);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (!(self->url = _shout_util_strdup(url)))
|
|
Packit |
eed494 |
return self->error = SHOUTERR_MALLOC;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self->error = SHOUTERR_SUCCESS;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
const char *shout_get_url(shout_t *self)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return NULL;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self->url;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
int shout_set_genre(shout_t *self, const char *genre)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return SHOUTERR_INSANE;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->state != SHOUT_STATE_UNCONNECTED)
|
|
Packit |
eed494 |
return self->error = SHOUTERR_CONNECTED;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->genre)
|
|
Packit |
eed494 |
free(self->genre);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (! (self->genre = _shout_util_strdup (genre)))
|
|
Packit |
eed494 |
return self->error = SHOUTERR_MALLOC;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self->error = SHOUTERR_SUCCESS;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
const char *shout_get_genre(shout_t *self)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return NULL;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self->genre;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
int shout_set_agent(shout_t *self, const char *agent)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return SHOUTERR_INSANE;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->state != SHOUT_STATE_UNCONNECTED)
|
|
Packit |
eed494 |
return self->error = SHOUTERR_CONNECTED;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->useragent)
|
|
Packit |
eed494 |
free(self->useragent);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (! (self->useragent = _shout_util_strdup (agent)))
|
|
Packit |
eed494 |
return self->error = SHOUTERR_MALLOC;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self->error = SHOUTERR_SUCCESS;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
const char *shout_get_agent(shout_t *self)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return NULL;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self->useragent;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
int shout_set_user(shout_t *self, const char *username)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return SHOUTERR_INSANE;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->state != SHOUT_STATE_UNCONNECTED)
|
|
Packit |
eed494 |
return self->error = SHOUTERR_CONNECTED;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->user)
|
|
Packit |
eed494 |
free(self->user);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (! (self->user = _shout_util_strdup (username)))
|
|
Packit |
eed494 |
return self->error = SHOUTERR_MALLOC;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self->error = SHOUTERR_SUCCESS;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
const char *shout_get_user(shout_t *self)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return NULL;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self->user;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
int shout_set_description(shout_t *self, const char *description)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return SHOUTERR_INSANE;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->state != SHOUT_STATE_UNCONNECTED)
|
|
Packit |
eed494 |
return self->error = SHOUTERR_CONNECTED;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->description)
|
|
Packit |
eed494 |
free(self->description);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (! (self->description = _shout_util_strdup (description)))
|
|
Packit |
eed494 |
return self->error = SHOUTERR_MALLOC;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self->error = SHOUTERR_SUCCESS;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
const char *shout_get_description(shout_t *self)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return NULL;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self->description;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
int shout_set_dumpfile(shout_t *self, const char *dumpfile)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return SHOUTERR_INSANE;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->state != SHOUT_STATE_UNCONNECTED)
|
|
Packit |
eed494 |
return SHOUTERR_CONNECTED;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->dumpfile)
|
|
Packit |
eed494 |
free(self->dumpfile);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (! (self->dumpfile = _shout_util_strdup (dumpfile)))
|
|
Packit |
eed494 |
return self->error = SHOUTERR_MALLOC;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self->error = SHOUTERR_SUCCESS;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
const char *shout_get_dumpfile(shout_t *self)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return NULL;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self->dumpfile;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
int shout_set_audio_info(shout_t *self, const char *name, const char *value)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
return self->error = _shout_util_dict_set(self->audio_info, name, value);
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
const char *shout_get_audio_info(shout_t *self, const char *name)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
return _shout_util_dict_get(self->audio_info, name);
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
int shout_set_public(shout_t *self, unsigned int public)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!self || (public != 0 && public != 1))
|
|
Packit |
eed494 |
return SHOUTERR_INSANE;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->state != SHOUT_STATE_UNCONNECTED)
|
|
Packit |
eed494 |
return self->error = SHOUTERR_CONNECTED;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
self->public = public;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self->error = SHOUTERR_SUCCESS;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
unsigned int shout_get_public(shout_t *self)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return 0;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self->public;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
int shout_set_format(shout_t *self, unsigned int format)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return SHOUTERR_INSANE;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->state != SHOUT_STATE_UNCONNECTED)
|
|
Packit |
eed494 |
return self->error = SHOUTERR_CONNECTED;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (format != SHOUT_FORMAT_OGG && format != SHOUT_FORMAT_MP3)
|
|
Packit |
eed494 |
return self->error = SHOUTERR_UNSUPPORTED;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
self->format = format;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self->error = SHOUTERR_SUCCESS;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
unsigned int shout_get_format(shout_t* self)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return 0;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self->format;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
int shout_set_protocol(shout_t *self, unsigned int protocol)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return SHOUTERR_INSANE;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->state != SHOUT_STATE_UNCONNECTED)
|
|
Packit |
eed494 |
return self->error = SHOUTERR_CONNECTED;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (protocol != SHOUT_PROTOCOL_HTTP &&
|
|
Packit |
eed494 |
protocol != SHOUT_PROTOCOL_XAUDIOCAST &&
|
|
Packit |
eed494 |
protocol != SHOUT_PROTOCOL_ICY)
|
|
Packit |
eed494 |
return self->error = SHOUTERR_UNSUPPORTED;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
self->protocol = protocol;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self->error = SHOUTERR_SUCCESS;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
unsigned int shout_get_protocol(shout_t *self)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return 0;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self->protocol;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
int shout_set_nonblocking(shout_t *self, unsigned int nonblocking)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!self || (nonblocking != 0 && nonblocking != 1))
|
|
Packit |
eed494 |
return SHOUTERR_INSANE;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->state != SHOUT_STATE_UNCONNECTED)
|
|
Packit |
eed494 |
return self->error = SHOUTERR_CONNECTED;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
self->nonblocking = nonblocking;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return SHOUTERR_SUCCESS;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
unsigned int shout_get_nonblocking(shout_t *self)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (!self)
|
|
Packit |
eed494 |
return 0;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self->nonblocking;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
/* -- static function definitions -- */
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
/* queue data in pages of SHOUT_BUFSIZE bytes */
|
|
Packit |
eed494 |
static int queue_data(shout_queue_t *queue, const unsigned char *data, size_t len)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
shout_buf_t *buf;
|
|
Packit |
eed494 |
size_t plen;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (!len)
|
|
Packit |
eed494 |
return SHOUTERR_SUCCESS;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (!queue->len) {
|
|
Packit |
eed494 |
queue->head = calloc(1, sizeof (shout_buf_t));
|
|
Packit |
eed494 |
if (! queue->head)
|
|
Packit |
eed494 |
return SHOUTERR_MALLOC;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
for (buf = queue->head; buf->next; buf = buf->next);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
/* Maybe any added data should be freed if we hit a malloc error?
|
|
Packit |
eed494 |
* Otherwise it'd be impossible to tell where to start requeueing.
|
|
Packit |
eed494 |
* (As if anyone ever tried to recover from a malloc error.) */
|
|
Packit |
eed494 |
while (len > 0) {
|
|
Packit |
eed494 |
if (buf->len == SHOUT_BUFSIZE) {
|
|
Packit |
eed494 |
buf->next = calloc(1, sizeof (shout_buf_t));
|
|
Packit |
eed494 |
if (! buf->next)
|
|
Packit |
eed494 |
return SHOUTERR_MALLOC;
|
|
Packit |
eed494 |
buf->next->prev = buf;
|
|
Packit |
eed494 |
buf = buf->next;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
plen = len > SHOUT_BUFSIZE - buf->len ? SHOUT_BUFSIZE - buf->len : len;
|
|
Packit |
eed494 |
memcpy (buf->data + buf->len, data, plen);
|
|
Packit |
eed494 |
buf->len += plen;
|
|
Packit |
eed494 |
data += plen;
|
|
Packit |
eed494 |
len -= plen;
|
|
Packit |
eed494 |
queue->len += plen;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return SHOUTERR_SUCCESS;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
static inline int queue_str(shout_t *self, const char *str)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
return queue_data(&self->wqueue, (const unsigned char*)str, strlen(str));
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
/* this should be shared with sock_write. Create libicecommon. */
|
|
Packit |
eed494 |
static int queue_printf(shout_t *self, const char *fmt, ...)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
char buffer[1024];
|
|
Packit |
eed494 |
char *buf;
|
|
Packit |
eed494 |
va_list ap, ap_retry;
|
|
Packit |
eed494 |
int len;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
buf = buffer;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
va_start(ap, fmt);
|
|
Packit |
eed494 |
va_copy(ap_retry, ap);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
len = vsnprintf(buf, sizeof(buffer), fmt, ap);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
self->error = SHOUTERR_SUCCESS;
|
|
Packit |
eed494 |
if (len > 0) {
|
|
Packit |
eed494 |
if ((size_t)len < sizeof(buffer))
|
|
Packit |
eed494 |
queue_data(&self->wqueue, (unsigned char*)buf, len);
|
|
Packit |
eed494 |
else {
|
|
Packit |
eed494 |
buf = malloc(++len);
|
|
Packit |
eed494 |
if (buf) {
|
|
Packit |
eed494 |
len = vsnprintf(buf, len, fmt, ap_retry);
|
|
Packit |
eed494 |
queue_data(&self->wqueue, (unsigned char*)buf, len);
|
|
Packit |
eed494 |
free(buf);
|
|
Packit |
eed494 |
} else
|
|
Packit |
eed494 |
self->error = SHOUTERR_MALLOC;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
va_end(ap_retry);
|
|
Packit |
eed494 |
va_end(ap);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self->error;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
static inline void queue_free(shout_queue_t *queue)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
shout_buf_t *prev;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
while (queue->head) {
|
|
Packit |
eed494 |
prev = queue->head;
|
|
Packit |
eed494 |
queue->head = queue->head->next;
|
|
Packit |
eed494 |
free(prev);
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
queue->len = 0;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
static int get_response(shout_t *self)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
char buf[1024];
|
|
Packit |
eed494 |
int rc, blen;
|
|
Packit |
eed494 |
char *pc;
|
|
Packit |
eed494 |
shout_buf_t *queue;
|
|
Packit |
eed494 |
int newlines = 0;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
rc = sock_read_bytes(self->socket, buf, sizeof(buf));
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (rc < 0 && sock_recoverable(sock_error()))
|
|
Packit |
eed494 |
return SHOUTERR_BUSY;
|
|
Packit |
eed494 |
if (rc <= 0)
|
|
Packit |
eed494 |
return SHOUTERR_SOCKET;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if ((rc = queue_data(&self->rqueue, (unsigned char*)buf, rc)))
|
|
Packit |
eed494 |
return rc;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
/* work from the back looking for \r?\n\r?\n. Anything else means more
|
|
Packit |
eed494 |
* is coming. */
|
|
Packit |
eed494 |
for (queue = self->rqueue.head; queue->next; queue = queue->next);
|
|
Packit |
eed494 |
pc = (char*)queue->data + queue->len - 1;
|
|
Packit |
eed494 |
blen = queue->len;
|
|
Packit |
eed494 |
while (blen) {
|
|
Packit |
eed494 |
if (*pc == '\n')
|
|
Packit |
eed494 |
newlines++;
|
|
Packit |
eed494 |
/* we may have to scan the entire queue if we got a response with
|
|
Packit |
eed494 |
* data after the head line (this can happen with eg 401) */
|
|
Packit |
eed494 |
else if (*pc != '\r')
|
|
Packit |
eed494 |
newlines = 0;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (newlines == 2)
|
|
Packit |
eed494 |
return SHOUTERR_SUCCESS;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
blen--;
|
|
Packit |
eed494 |
pc--;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (!blen && queue->prev) {
|
|
Packit |
eed494 |
queue = queue->prev;
|
|
Packit |
eed494 |
pc = (char*)queue->data + queue->len - 1;
|
|
Packit |
eed494 |
blen = queue->len;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return SHOUTERR_BUSY;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
static int try_connect (shout_t *self)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
int rc;
|
|
Packit |
eed494 |
int port;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
/* the breaks between cases are omitted intentionally */
|
|
Packit |
eed494 |
switch (self->state) {
|
|
Packit |
eed494 |
case SHOUT_STATE_UNCONNECTED:
|
|
Packit |
eed494 |
port = self->port;
|
|
Packit |
eed494 |
if (shout_get_protocol(self) == SHOUT_PROTOCOL_ICY)
|
|
Packit |
eed494 |
port++;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (shout_get_nonblocking(self)) {
|
|
Packit |
eed494 |
if ((self->socket = sock_connect_non_blocking(self->host, port)) < 0)
|
|
Packit |
eed494 |
return self->error = SHOUTERR_NOCONNECT;
|
|
Packit |
eed494 |
self->state = SHOUT_STATE_CONNECT_PENDING;
|
|
Packit |
eed494 |
} else {
|
|
Packit |
eed494 |
if ((self->socket = sock_connect(self->host, port)) < 0)
|
|
Packit |
eed494 |
return self->error = SHOUTERR_NOCONNECT;
|
|
Packit |
eed494 |
if ((rc = create_request(self)) != SHOUTERR_SUCCESS)
|
|
Packit |
eed494 |
return rc;
|
|
Packit |
eed494 |
self->state = SHOUT_STATE_REQ_PENDING;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
case SHOUT_STATE_CONNECT_PENDING:
|
|
Packit |
eed494 |
if (shout_get_nonblocking(self)) {
|
|
Packit |
eed494 |
if ((rc = sock_connected(self->socket, 0)) < 1) {
|
|
Packit |
eed494 |
if (rc == SOCK_ERROR) {
|
|
Packit |
eed494 |
rc = SHOUTERR_SOCKET;
|
|
Packit |
eed494 |
goto failure;
|
|
Packit |
eed494 |
} else
|
|
Packit |
eed494 |
return SHOUTERR_BUSY;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
if ((rc = create_request(self)) != SHOUTERR_SUCCESS)
|
|
Packit |
eed494 |
goto failure;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
self->state = SHOUT_STATE_REQ_PENDING;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
case SHOUT_STATE_REQ_PENDING:
|
|
Packit |
eed494 |
do
|
|
Packit |
eed494 |
rc = send_queue(self);
|
|
Packit |
eed494 |
while (!shout_get_nonblocking(self) && rc == SHOUTERR_BUSY);
|
|
Packit |
eed494 |
if (rc == SHOUTERR_BUSY)
|
|
Packit |
eed494 |
return rc;
|
|
Packit |
eed494 |
if (rc != SHOUTERR_SUCCESS)
|
|
Packit |
eed494 |
goto failure;
|
|
Packit |
eed494 |
self->state = SHOUT_STATE_RESP_PENDING;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
case SHOUT_STATE_RESP_PENDING:
|
|
Packit |
eed494 |
do
|
|
Packit |
eed494 |
rc = get_response(self);
|
|
Packit |
eed494 |
while (!shout_get_nonblocking(self) && rc == SHOUTERR_BUSY);
|
|
Packit |
eed494 |
if (rc == SHOUTERR_BUSY)
|
|
Packit |
eed494 |
return rc;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (rc != SHOUTERR_SUCCESS)
|
|
Packit |
eed494 |
goto failure;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if ((rc = parse_response(self)) != SHOUTERR_SUCCESS)
|
|
Packit |
eed494 |
goto failure;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->format == SHOUT_FORMAT_OGG) {
|
|
Packit |
eed494 |
if ((rc = self->error = shout_open_ogg(self)) != SHOUTERR_SUCCESS)
|
|
Packit |
eed494 |
goto failure;
|
|
Packit |
eed494 |
} else if (self->format == SHOUT_FORMAT_MP3) {
|
|
Packit |
eed494 |
if ((rc = self->error = shout_open_mp3(self)) != SHOUTERR_SUCCESS)
|
|
Packit |
eed494 |
goto failure;
|
|
Packit |
eed494 |
} else {
|
|
Packit |
eed494 |
rc = SHOUTERR_INSANE;
|
|
Packit |
eed494 |
goto failure;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
case SHOUT_STATE_CONNECTED:
|
|
Packit |
eed494 |
self->state = SHOUT_STATE_CONNECTED;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return SHOUTERR_SUCCESS;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
failure:
|
|
Packit |
eed494 |
shout_close(self);
|
|
Packit |
eed494 |
return rc;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
static int try_write (shout_t *self, const void *data, size_t len)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
int ret;
|
|
Packit |
eed494 |
size_t pos = 0;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
/* loop until whole buffer is written (unless it would block) */
|
|
Packit |
eed494 |
do {
|
|
Packit |
eed494 |
ret = sock_write_bytes (self->socket, data + pos, len - pos);
|
|
Packit |
eed494 |
if (ret > 0)
|
|
Packit |
eed494 |
pos += ret;
|
|
Packit |
eed494 |
} while (pos < len && ret >= 0);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (ret < 0)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (sock_recoverable (sock_error()))
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
self->error = SHOUTERR_BUSY;
|
|
Packit |
eed494 |
return pos;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
self->error = SHOUTERR_SOCKET;
|
|
Packit |
eed494 |
return ret;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return pos;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
/* collect nodes of a queue into a single buffer */
|
|
Packit |
eed494 |
static int collect_queue(shout_buf_t *queue, char **buf)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
shout_buf_t *node;
|
|
Packit |
eed494 |
int pos = 0;
|
|
Packit |
eed494 |
int len = 0;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
for (node = queue; node; node = node->next)
|
|
Packit |
eed494 |
len += node->len;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (!(*buf = malloc(len)))
|
|
Packit |
eed494 |
return SHOUTERR_MALLOC;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
for (node = queue; node; node = node->next) {
|
|
Packit |
eed494 |
memcpy(*buf + pos, node->data, node->len);
|
|
Packit |
eed494 |
pos += node->len;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return len;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
static int send_queue(shout_t *self)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
shout_buf_t *buf;
|
|
Packit |
eed494 |
int ret;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (!self->wqueue.len)
|
|
Packit |
eed494 |
return SHOUTERR_SUCCESS;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
buf = self->wqueue.head;
|
|
Packit |
eed494 |
while (buf) {
|
|
Packit |
eed494 |
ret = try_write (self, buf->data + buf->pos, buf->len - buf->pos);
|
|
Packit |
eed494 |
if (ret < 0)
|
|
Packit |
eed494 |
return self->error;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
buf->pos += ret;
|
|
Packit |
eed494 |
self->wqueue.len -= ret;
|
|
Packit |
eed494 |
if (buf->pos == buf->len) {
|
|
Packit |
eed494 |
self->wqueue.head = buf->next;
|
|
Packit |
eed494 |
free(buf);
|
|
Packit |
eed494 |
buf = self->wqueue.head;
|
|
Packit |
eed494 |
if (buf)
|
|
Packit |
eed494 |
buf->prev = NULL;
|
|
Packit |
eed494 |
} else /* incomplete write */
|
|
Packit |
eed494 |
return SHOUTERR_BUSY;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self->error = SHOUTERR_SUCCESS;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
static int create_request(shout_t *self)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (self->protocol == SHOUT_PROTOCOL_HTTP)
|
|
Packit |
eed494 |
return create_http_request(self);
|
|
Packit |
eed494 |
else if (self->protocol == SHOUT_PROTOCOL_XAUDIOCAST)
|
|
Packit |
eed494 |
return create_xaudiocast_request(self);
|
|
Packit |
eed494 |
else if (self->protocol == SHOUT_PROTOCOL_ICY)
|
|
Packit |
eed494 |
return create_icy_request(self);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self->error = SHOUTERR_UNSUPPORTED;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
static int create_http_request(shout_t *self)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
char *auth;
|
|
Packit |
eed494 |
char *ai;
|
|
Packit |
eed494 |
int ret = SHOUTERR_MALLOC;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
/* this is lazy code that relies on the only error from queue_* being
|
|
Packit |
eed494 |
* SHOUTERR_MALLOC */
|
|
Packit |
eed494 |
do {
|
|
Packit |
eed494 |
if (queue_printf(self, "SOURCE %s HTTP/1.0\r\n", self->mount))
|
|
Packit |
eed494 |
break;
|
|
Packit |
eed494 |
if (self->password) {
|
|
Packit |
eed494 |
if (! (auth = http_basic_authorization(self)))
|
|
Packit |
eed494 |
break;
|
|
Packit |
eed494 |
if (queue_str(self, auth)) {
|
|
Packit |
eed494 |
free(auth);
|
|
Packit |
eed494 |
break;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
free(auth);
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
if (self->useragent && queue_printf(self, "User-Agent: %s\r\n", self->useragent))
|
|
Packit |
eed494 |
break;
|
|
Packit |
eed494 |
if (self->format == SHOUT_FORMAT_OGG && queue_printf(self, "Content-Type: application/ogg\r\n"))
|
|
Packit |
eed494 |
break;
|
|
Packit |
eed494 |
if (self->format == SHOUT_FORMAT_MP3 && queue_printf(self, "Content-Type: audio/mpeg\r\n"))
|
|
Packit |
eed494 |
break;
|
|
Packit |
eed494 |
if (queue_printf(self, "ice-name: %s\r\n", self->name ? self->name : "no name"))
|
|
Packit |
eed494 |
break;
|
|
Packit |
eed494 |
if (queue_printf(self, "ice-public: %d\r\n", self->public))
|
|
Packit |
eed494 |
break;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (self->url && queue_printf(self, "ice-url: %s\r\n", self->url))
|
|
Packit |
eed494 |
break;
|
|
Packit |
eed494 |
if (self->genre && queue_printf(self, "ice-genre: %s\r\n", self->genre))
|
|
Packit |
eed494 |
break;
|
|
Packit |
eed494 |
if ((ai = _shout_util_dict_urlencode(self->audio_info, ';'))) {
|
|
Packit |
eed494 |
if (queue_printf(self, "ice-audio-info: %s\r\n", ai)) {
|
|
Packit |
eed494 |
free(ai);
|
|
Packit |
eed494 |
break;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
free(ai);
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
if (self->description && queue_printf(self, "ice-description: %s\r\n", self->description))
|
|
Packit |
eed494 |
break;
|
|
Packit |
eed494 |
if (queue_str(self, "\r\n"))
|
|
Packit |
eed494 |
break;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
ret = SHOUTERR_SUCCESS;
|
|
Packit |
eed494 |
} while (0);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return ret;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
static char *http_basic_authorization(shout_t *self)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
char *out, *in;
|
|
Packit |
eed494 |
int len;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (!self || !self->user || !self->password)
|
|
Packit |
eed494 |
return NULL;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
len = strlen(self->user) + strlen(self->password) + 2;
|
|
Packit |
eed494 |
if (!(in = malloc(len)))
|
|
Packit |
eed494 |
return NULL;
|
|
Packit |
eed494 |
sprintf(in, "%s:%s", self->user, self->password);
|
|
Packit |
eed494 |
out = _shout_util_base64_encode(in);
|
|
Packit |
eed494 |
free(in);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
len = strlen(out) + 24;
|
|
Packit |
eed494 |
if (!(in = malloc(len))) {
|
|
Packit |
eed494 |
free(out);
|
|
Packit |
eed494 |
return NULL;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
sprintf(in, "Authorization: Basic %s\r\n", out);
|
|
Packit |
eed494 |
free(out);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return in;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
static int parse_response(shout_t *self)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
if (self->protocol == SHOUT_PROTOCOL_HTTP)
|
|
Packit |
eed494 |
return parse_http_response(self);
|
|
Packit |
eed494 |
else if (self->protocol == SHOUT_PROTOCOL_XAUDIOCAST ||
|
|
Packit |
eed494 |
self->protocol == SHOUT_PROTOCOL_ICY)
|
|
Packit |
eed494 |
return parse_xaudiocast_response(self);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return self->error = SHOUTERR_UNSUPPORTED;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
static int parse_http_response(shout_t *self)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
http_parser_t *parser;
|
|
Packit |
eed494 |
char *header = NULL;
|
|
Packit |
eed494 |
int hlen = 0;
|
|
Packit |
eed494 |
int code;
|
|
Packit |
eed494 |
char *retcode;
|
|
Packit |
eed494 |
#if 0
|
|
Packit |
eed494 |
char *realm;
|
|
Packit |
eed494 |
#endif
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
/* all this copying! */
|
|
Packit |
eed494 |
hlen = collect_queue(self->rqueue.head, &header);
|
|
Packit |
eed494 |
if (hlen <= 0)
|
|
Packit |
eed494 |
return SHOUTERR_MALLOC;
|
|
Packit |
eed494 |
queue_free(&self->rqueue);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
parser = httpp_create_parser();
|
|
Packit |
eed494 |
httpp_initialize(parser, NULL);
|
|
Packit |
eed494 |
if (httpp_parse_response(parser, header, hlen, self->mount)) {
|
|
Packit |
eed494 |
retcode = httpp_getvar(parser, HTTPP_VAR_ERROR_CODE);
|
|
Packit |
eed494 |
code = atoi(retcode);
|
|
Packit |
eed494 |
if(code >= 200 && code < 300) {
|
|
Packit |
eed494 |
httpp_destroy(parser);
|
|
Packit |
eed494 |
free (header);
|
|
Packit |
eed494 |
return SHOUTERR_SUCCESS;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
free(header);
|
|
Packit |
eed494 |
httpp_destroy(parser);
|
|
Packit |
eed494 |
return self->error = SHOUTERR_NOLOGIN;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
static int create_xaudiocast_request(shout_t *self)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
const char *bitrate;
|
|
Packit |
eed494 |
int ret;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
bitrate = shout_get_audio_info(self, SHOUT_AI_BITRATE);
|
|
Packit |
eed494 |
if (!bitrate)
|
|
Packit |
eed494 |
bitrate = "0";
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
ret = SHOUTERR_MALLOC;
|
|
Packit |
eed494 |
do {
|
|
Packit |
eed494 |
if (queue_printf(self, "SOURCE %s %s\n", self->password, self->mount))
|
|
Packit |
eed494 |
break;
|
|
Packit |
eed494 |
if (queue_printf(self, "x-audiocast-name: %s\n", self->name ? self->name : "unnamed"))
|
|
Packit |
eed494 |
break;
|
|
Packit |
eed494 |
if (queue_printf(self, "x-audiocast-url: %s\n", self->url ? self->url : "http://www.icecast.org/"))
|
|
Packit |
eed494 |
break;
|
|
Packit |
eed494 |
if (queue_printf(self, "x-audiocast-genre: %s\n", self->genre ? self->genre : "icecast"))
|
|
Packit |
eed494 |
break;
|
|
Packit |
eed494 |
if (queue_printf(self, "x-audiocast-bitrate: %s\n", bitrate))
|
|
Packit |
eed494 |
break;
|
|
Packit |
eed494 |
if (queue_printf(self, "x-audiocast-public: %i\n", self->public))
|
|
Packit |
eed494 |
break;
|
|
Packit |
eed494 |
if (queue_printf(self, "x-audiocast-description: %s\n", self->description ? self->description : "Broadcasting with the icecast streaming media server!"))
|
|
Packit |
eed494 |
break;
|
|
Packit |
eed494 |
if (self->dumpfile && queue_printf(self, "x-audiocast-dumpfile: %s\n", self->dumpfile))
|
|
Packit |
eed494 |
break;
|
|
Packit |
eed494 |
if (queue_str(self, "\n"))
|
|
Packit |
eed494 |
break;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
ret = SHOUTERR_SUCCESS;
|
|
Packit |
eed494 |
} while (0);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return ret;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
static int parse_xaudiocast_response(shout_t *self)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
char *response;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (collect_queue(self->rqueue.head, &response) <= 0)
|
|
Packit |
eed494 |
return SHOUTERR_MALLOC;
|
|
Packit |
eed494 |
queue_free(&self->rqueue);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
if (!strstr(response, "OK")) {
|
|
Packit |
eed494 |
free(response);
|
|
Packit |
eed494 |
return SHOUTERR_NOLOGIN;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
free(response);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return SHOUTERR_SUCCESS;
|
|
Packit |
eed494 |
}
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
static int create_icy_request(shout_t *self)
|
|
Packit |
eed494 |
{
|
|
Packit |
eed494 |
const char *bitrate;
|
|
Packit |
eed494 |
int ret;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
bitrate = shout_get_audio_info(self, SHOUT_AI_BITRATE);
|
|
Packit |
eed494 |
if (!bitrate)
|
|
Packit |
eed494 |
bitrate = "0";
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
ret = SHOUTERR_MALLOC;
|
|
Packit |
eed494 |
do {
|
|
Packit |
eed494 |
if (queue_printf(self, "%s\n", self->password))
|
|
Packit |
eed494 |
break;
|
|
Packit |
eed494 |
if (queue_printf(self, "icy-name:%s\n", self->name ? self->name : "unnamed"))
|
|
Packit |
eed494 |
break;
|
|
Packit |
eed494 |
if (queue_printf(self, "icy-url:%s\n", self->url ? self->url : "http://www.icecast.org/"))
|
|
Packit |
eed494 |
break;
|
|
Packit |
eed494 |
if (queue_str(self, "icy-irc:\nicy-aim:\nicy-icq:\n"))
|
|
Packit |
eed494 |
break;
|
|
Packit |
eed494 |
if (queue_printf(self, "icy-pub:%i\n", self->public))
|
|
Packit |
eed494 |
break;
|
|
Packit |
eed494 |
if (queue_printf(self, "icy-genre:%s\n", self->genre ? self->genre : "icecast"))
|
|
Packit |
eed494 |
break;
|
|
Packit |
eed494 |
if (queue_printf(self, "icy-br:%s\n\n", bitrate))
|
|
Packit |
eed494 |
break;
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
ret = SHOUTERR_SUCCESS;
|
|
Packit |
eed494 |
} while (0);
|
|
Packit |
eed494 |
|
|
Packit |
eed494 |
return ret;
|
|
Packit |
eed494 |
}
|