1 /* -*- c-basic-offset: 8; -*- */
2 /* proto_xaudiocast.c: Implementation of protocol xaudiocast.
3 *
4 * Copyright (C) 2002-2004 the Icecast team <team@icecast.org>,
5 * Copyright (C) 2012-2019 Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the Free
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 * $Id$
22 */
23
24 #ifdef HAVE_CONFIG_H
25 # include <config.h>
26 #endif
27
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include <shout/shout.h>
32 #include "shout_private.h"
33
shout_create_xaudiocast_request(shout_t * self,shout_connection_t * connection)34 shout_connection_return_state_t shout_create_xaudiocast_request(shout_t *self, shout_connection_t *connection)
35 {
36 const char *bitrate;
37 const char *val;
38 char *mount = NULL;
39 int ret;
40
41 bitrate = shout_get_audio_info(self, SHOUT_AI_BITRATE);
42 if (!bitrate)
43 bitrate = "0";
44
45 ret = SHOUTERR_MALLOC;
46 do {
47 if (!(mount = _shout_util_url_encode_resource(self->mount)))
48 break;
49 if (shout_queue_printf(connection, "SOURCE %s %s\n", self->password, mount))
50 break;
51 if (shout_queue_printf(connection, "x-audiocast-name: %s\n", shout_get_meta(self, "name")))
52 break;
53 val = shout_get_meta(self, "url");
54 if (shout_queue_printf(connection, "x-audiocast-url: %s\n", val ? val : "http://www.icecast.org/"))
55 break;
56 val = shout_get_meta(self, "genre");
57 if (shout_queue_printf(connection, "x-audiocast-genre: %s\n", val ? val : "icecast"))
58 break;
59 if (shout_queue_printf(connection, "x-audiocast-bitrate: %s\n", bitrate))
60 break;
61 if (shout_queue_printf(connection, "x-audiocast-public: %i\n", self->public))
62 break;
63 val = shout_get_meta(self, "description");
64 if (shout_queue_printf(connection, "x-audiocast-description: %s\n", val ? val : "Broadcasting with the icecast streaming media server!"))
65 break;
66 if (self->dumpfile && shout_queue_printf(connection, "x-audiocast-dumpfile: %s\n", self->dumpfile))
67 break;
68 if (shout_queue_str(connection, "\n"))
69 break;
70
71 ret = SHOUTERR_SUCCESS;
72 } while (0);
73
74 if (mount)
75 free(mount);
76
77 shout_connection_set_error(connection, ret);
78 return ret == SHOUTERR_SUCCESS ? SHOUT_RS_DONE : SHOUT_RS_ERROR;
79 }
80
shout_get_xaudiocast_response(shout_t * self,shout_connection_t * connection)81 shout_connection_return_state_t shout_get_xaudiocast_response(shout_t *self, shout_connection_t *connection)
82 {
83 shout_buf_t *queue = connection->rqueue.head;
84 size_t i;
85
86 if (!connection->rqueue.len)
87 return SHOUT_RS_DONE;
88
89 do {
90 for (i = 0; i < queue->len; i++) {
91 if (queue->data[i] == '\n') {
92 /* got response */
93 return SHOUT_RS_DONE;
94 }
95 }
96 } while ((queue = queue->next));
97
98 /* need more data */
99 return SHOUT_RS_NOTNOW;
100 }
101
shout_parse_xaudiocast_response(shout_t * self,shout_connection_t * connection)102 shout_connection_return_state_t shout_parse_xaudiocast_response(shout_t *self, shout_connection_t *connection)
103 {
104 char *response = NULL;
105
106 if (connection->rqueue.len) {
107 if (shout_queue_collect(connection->rqueue.head, &response) <= 0) {
108 shout_connection_set_error(connection, SHOUTERR_MALLOC);
109 return SHOUT_RS_ERROR;
110 }
111 }
112 shout_queue_free(&connection->rqueue);
113
114 if (!response || !strstr(response, "OK")) {
115 free(response);
116
117 /* check to see if that is a response to a POKE. */
118 if (!(connection->server_caps & LIBSHOUT_CAP_GOTCAPS)) {
119 connection->server_caps |= LIBSHOUT_CAP_GOTCAPS;
120 shout_connection_disconnect(connection);
121 shout_connection_connect(connection, self);
122 connection->current_message_state = SHOUT_MSGSTATE_CREATING0;
123 connection->target_message_state = SHOUT_MSGSTATE_SENDING1;
124 return SHOUT_RS_NOTNOW;
125 } else {
126 shout_connection_set_error(connection, SHOUTERR_NOLOGIN);
127 return SHOUT_RS_ERROR;
128 }
129 }
130 free(response);
131
132 connection->server_caps |= LIBSHOUT_CAP_GOTCAPS;
133 connection->current_message_state = SHOUT_MSGSTATE_SENDING1;
134 connection->target_message_state = SHOUT_MSGSTATE_WAITING1;
135 return SHOUT_RS_DONE;
136 }
137
138 static const shout_protocol_impl_t shout_xaudiocast_impl_real = {
139 .msg_create = shout_create_xaudiocast_request,
140 .msg_get = shout_get_xaudiocast_response,
141 .msg_parse = shout_parse_xaudiocast_response
142 };
143 const shout_protocol_impl_t *shout_xaudiocast_impl = &shout_xaudiocast_impl_real;
144