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