1 /**********************************************************
2 * libmp3splt -- library based on mp3splt,
3 * for mp3/ogg splitting without decoding
4 *
5 * Copyright (c) 2002-2005 M. Trotta - <mtrotta@users.sourceforge.net>
6 * Copyright (c) 2005-2014 Alexandru Munteanu - m@ioalex.net
7 *
8 *********************************************************/
9
10 /**********************************************************
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
24 * 02111-1307, USA.
25 *********************************************************/
26
27 /*! \file
28
29 All functions that are needed in order to do a Freedb search
30
31 Don't use these functions directly. The version of these functions
32 that is meant to be used directly are all in mp3splt.c.
33 */
34
35 #include <string.h>
36 #include <unistd.h>
37
38 #ifdef __WIN32__
39 #include <conio.h>
40 #include <winsock2.h>
41 #else
42 #include <netdb.h>
43 #include <sys/socket.h>
44 #include <netinet/in.h>
45 #endif
46
47 #include "splt.h"
48 #include "socket_manager.h"
49 #include "freedb.h"
50
51 #define DONT_SKIP_LINES 0
52 #define SKIP_ONE_LINE 1
53
get_cgi_path_and_cut_server(int type,const char * search_server)54 char *get_cgi_path_and_cut_server(int type, const char *search_server)
55 {
56 char *cgi_path = NULL;
57
58 if (strlen(search_server) == 0)
59 {
60 splt_su_copy("/~cddb/cddb.cgi", &cgi_path);
61 return cgi_path;
62 }
63
64 if (type == SPLT_FREEDB_SEARCH_TYPE_CDDB_CGI ||
65 type == SPLT_FREEDB_GET_FILE_TYPE_CDDB_CGI)
66 {
67 char *path = strchr(search_server, '/');
68 if (path)
69 {
70 splt_su_copy(path, &cgi_path);
71 *path = '\0';
72 }
73 }
74
75 return cgi_path;
76 }
77
splt_freedb_get_server(const char search_server[256])78 static char *splt_freedb_get_server(const char search_server[256])
79 {
80 char *server = NULL;
81
82 if (strlen(search_server) == 0)
83 {
84 splt_su_copy(SPLT_FREEDB2_SITE, &server);
85 }
86 else
87 {
88 splt_su_copy(search_server, &server);
89 }
90
91 return server;
92 }
93
splt_freedb_get_port(int port_number)94 static int splt_freedb_get_port(int port_number)
95 {
96 if (port_number == -1)
97 {
98 return SPLT_FREEDB_CDDB_CGI_PORT;
99 }
100
101 return port_number;
102 }
103
104 //line ="category discid artist / album"
splt_freedb_search_result_processor(const char * line,int line_number,void * user_data)105 static int splt_freedb_search_result_processor(const char *line,
106 int line_number, void *user_data)
107 {
108 char *category = NULL;
109 char *discid = NULL;
110
111 splt_state *state = (splt_state *) user_data;
112
113 const char *category_begin = splt_su_skip_spaces(line);
114 const char *category_end = strchr(category_begin, ' ');
115 if (category_end == NULL) { goto end; }
116 splt_su_append(&category, category_begin, category_end - category_begin + 1, NULL);
117
118 const char *discid_begin = splt_su_skip_spaces(category_end);
119 const char *discid_end = strchr(discid_begin, ' ');
120 if (discid_end == NULL) { goto end; }
121 splt_su_append(&discid, discid_begin, discid_end - discid_begin + 1, NULL);
122
123 splt_fu_freedb_set_disc(state, splt_fu_freedb_get_found_cds(state),
124 discid, category, strlen(category));
125
126 splt_fu_freedb_append_result(state, splt_su_skip_spaces(discid_end), 0);
127
128 splt_fu_freedb_found_cds_next(state);
129
130 end:
131 if (category)
132 {
133 free(category);
134 category = NULL;
135 }
136 if (discid)
137 {
138 free(discid);
139 discid = NULL;
140 }
141
142 return SPLT_TRUE;
143 }
144
145 /*! search the freedb according to "search"
146
147 \param state The central structure this library keeps all its data in
148 \param search_string The string that is to be searched for
149 \param error The error code this action returns in
150 \param search_type the type of the search. Can be set to
151 SPLT_FREEDB_SEARCH_TYPE_CDDB_CGI
152 \param search_server The URL of the search server or NULL to select
153 the default which currently means freedb2.org
154 \param port The port on the server. -1 means default (Which should be
155 80).
156 */
splt_freedb_process_search(splt_state * state,char * search,int search_type,const char search_server[256],int port_number)157 int splt_freedb_process_search(splt_state *state, char *search,
158 int search_type, const char search_server[256],
159 int port_number)
160 {
161 int error = SPLT_FREEDB_OK;
162 int err = SPLT_OK;
163 char *message = NULL;
164
165 splt_socket_handler *sh = splt_sm_socket_handler_new(&error);
166 if (error < 0) { return error; }
167
168 char *cgi_path = get_cgi_path_and_cut_server(search_type, search_server);
169 char *server = splt_freedb_get_server(search_server);
170 int port = splt_freedb_get_port(port_number);
171
172 splt_sm_connect(sh, server, port, state);
173 if (sh->error < 0) { error = sh->error; goto end; }
174
175 if (search_type == SPLT_FREEDB_SEARCH_TYPE_CDDB_CGI)
176 {
177 splt_su_replace_all_char(search, ' ', '+');
178 err = splt_su_append_str(&message,
179 "GET ", cgi_path, "?cmd=cddb+album+", search, SPLT_FREEDB_HELLO_PROTO, NULL);
180 if (err < 0) { error = err; goto disconnect; }
181
182 splt_sm_send_http_message(sh, message, state);
183 if (sh->error < 0) { error = sh->error; goto disconnect; }
184
185 splt_fu_freedb_free_search(state);
186 err = splt_fu_freedb_init_search(state);
187 if (err < 0) { error = err; goto disconnect; }
188
189 splt_sm_receive_and_process_without_headers(sh, state,
190 splt_freedb_search_result_processor, state, SKIP_ONE_LINE);
191 if (sh->error < 0) { error = sh->error; goto disconnect; }
192 }
193 else if (search_type == SPLT_FREEDB_SEARCH_TYPE_CDDB)
194 {
195 //TODO: new freedb web search
196 }
197
198 int found_cds = splt_fu_freedb_get_found_cds(state);
199 if (found_cds == 0)
200 {
201 error = SPLT_FREEDB_NO_CD_FOUND;
202 }
203 else if (found_cds == -1)
204 {
205 splt_e_set_error_data(state, server);
206 error = SPLT_FREEDB_ERROR_GETTING_INFOS;
207 }
208 else if (found_cds == SPLT_MAXCD)
209 {
210 error = SPLT_FREEDB_MAX_CD_REACHED;
211 }
212
213 disconnect:
214 splt_sm_close(sh, state);
215 if (sh->error < 0) { error = sh->error; goto end; }
216
217 end:
218 splt_sm_socket_handler_free(&sh);
219
220 if (cgi_path)
221 {
222 free(cgi_path);
223 cgi_path = NULL;
224 }
225 if (server)
226 {
227 free(server);
228 server = NULL;
229 }
230 if (message)
231 {
232 free(message);
233 message = NULL;
234 }
235
236 return error;
237 }
238
splt_freedb_process_hello_response(const char * line,int line_number,void * user_data)239 static int splt_freedb_process_hello_response(const char *line,
240 int line_number, void *user_data)
241 {
242 int *error = (int *) user_data;
243
244 if ((strncmp(line,"50",2) == 0) ||
245 (strncmp(line,"40",2) == 0))
246 {
247 if (strncmp(line,"401",3) == 0)
248 {
249 *error = SPLT_FREEDB_NO_SUCH_CD_IN_DATABASE;
250 }
251 else
252 {
253 *error = SPLT_FREEDB_ERROR_SITE;
254 }
255 }
256
257 return SPLT_FALSE;
258 }
259
260 char *test = NULL;
261
splt_freedb_process_get_file(const char * line,int line_number,void * user_data)262 static int splt_freedb_process_get_file(const char *line,
263 int line_number, void *user_data)
264 {
265 splt_get_file *get_file = (splt_get_file *) user_data;
266
267 if (line_number == 1)
268 {
269 if ((strncmp(line,"50",2) == 0) ||
270 (strncmp(line,"40",2) == 0))
271 {
272 if (strncmp(line,"401",3) == 0)
273 {
274 get_file->err= SPLT_FREEDB_NO_SUCH_CD_IN_DATABASE;
275 }
276 else
277 {
278 get_file->err = SPLT_FREEDB_ERROR_SITE;
279 }
280
281 return SPLT_FALSE;
282 }
283
284 return SPLT_TRUE;
285 }
286
287 if (get_file->stop_on_dot && strcmp(line, ".") == 0)
288 {
289 return SPLT_FALSE;
290 }
291
292 int err = splt_su_append_str(&get_file->file, line, "\n", NULL);
293 if (err < 0)
294 {
295 get_file->err = err;
296 return SPLT_FALSE;
297 }
298
299 return SPLT_TRUE;
300 }
301
302
303 /*! must only be called after process_freedb_search
304
305 returns the cddb file content corresponding to the last search, for
306 the disc_id (parameter of the function)
307
308 \param state The central structure that keeps all data this library
309 uses
310 \param error Is set to the error code this action results in
311 \param disc_id The freedb disc ID.
312 \param cddb_get_type specifies the type of the get:
313 it can be SPLT_FREEDB_GET_FILE_TYPE_CDDB_CGI (that works for both
314 freedb and freedb2 at the moment - 18_10_06)
315 or SPLT_FREEDB_GET_FILE_TYPE_CDDB (that only work for freedb at
316 the moment - 18_10_06)
317
318 \todo see when we don't have a valid port or get_type
319 */
splt_freedb_get_file(splt_state * state,int disc_id,int * error,int get_type,const char cddb_get_server[256],int port_number)320 char *splt_freedb_get_file(splt_state *state, int disc_id, int *error,
321 int get_type, const char cddb_get_server[256], int port_number)
322 {
323 int err = SPLT_FREEDB_FILE_OK;
324 *error = err;
325 char *message = NULL;
326
327 splt_socket_handler *sh = splt_sm_socket_handler_new(&err);
328 if (err < 0) { *error = err; return NULL; }
329
330 splt_get_file *get_file = malloc(sizeof(splt_get_file));
331 if (!get_file) { *error = SPLT_ERROR_CANNOT_ALLOCATE_MEMORY; return NULL; }
332
333 get_file->err = SPLT_FREEDB_FILE_OK;
334 get_file->file = NULL;
335 get_file->stop_on_dot = SPLT_FALSE;
336
337 char *cgi_path = get_cgi_path_and_cut_server(get_type, cddb_get_server);
338 char *server = splt_freedb_get_server(cddb_get_server);
339 int port = splt_freedb_get_port(port_number);
340
341 const char *cd_category = splt_fu_freedb_get_disc_category(state, disc_id);
342 const char *cd_id = splt_fu_freedb_get_disc_id(state, disc_id);
343
344 splt_sm_connect(sh, server, port, state);
345 if (sh->error < 0) { *error = sh->error; goto end; }
346
347 if (get_type == SPLT_FREEDB_GET_FILE_TYPE_CDDB_CGI)
348 {
349 message = splt_su_get_formatted_message(state,
350 SPLT_FREEDB_CDDB_CGI_GET_FILE, cgi_path, cd_category, cd_id, NULL);
351
352 splt_sm_send_http_message(sh, message, state);
353 if (sh->error < 0) { *error = sh->error; goto disconnect; }
354
355 splt_sm_receive_and_process_without_headers(sh, state,
356 splt_freedb_process_get_file, get_file, DONT_SKIP_LINES);
357 if (get_file->err < 0) { *error = get_file->err; goto disconnect; }
358 if (sh->error < 0) { *error = sh->error; goto disconnect; }
359 }
360 else if (get_type == SPLT_FREEDB_GET_FILE_TYPE_CDDB)
361 {
362 if (splt_pr_has_proxy(state))
363 {
364 *error = SPLT_FREEDB_ERROR_PROXY_NOT_SUPPORTED;
365 goto disconnect;
366 }
367
368 get_file->stop_on_dot = SPLT_TRUE;
369
370 splt_sm_send_http_message(sh, SPLT_FREEDB_HELLO, state);
371 if (sh->error < 0) { *error = sh->error; goto disconnect; }
372
373 splt_sm_receive_and_process(sh, state, splt_freedb_process_hello_response, &err);
374 if (err < 0) { *error = err; goto disconnect; }
375 if (sh->error < 0) { *error = sh->error; goto disconnect; }
376
377 message = splt_su_get_formatted_message(state, SPLT_FREEDB_GET_FILE,
378 cd_category, cd_id, NULL);
379
380 splt_sm_send_http_message(sh, message, state);
381 if (sh->error < 0) { *error = sh->error; goto disconnect; }
382
383 splt_sm_receive_and_process(sh, state, splt_freedb_process_get_file, get_file);
384 if (get_file->err < 0) { *error = get_file->err; goto disconnect; }
385 if (sh->error < 0) { *error = sh->error; goto disconnect; }
386
387 splt_sm_send_http_message(sh, "quit", state);
388 if (sh->error < 0) { *error = sh->error; goto disconnect; }
389 }
390
391 disconnect:
392 splt_sm_close(sh, state);
393 if (sh->error < 0) { *error = sh->error; goto end; }
394
395 end:
396 splt_sm_socket_handler_free(&sh);
397
398 if (cgi_path)
399 {
400 free(cgi_path);
401 cgi_path = NULL;
402 }
403 if (server)
404 {
405 free(server);
406 server = NULL;
407 }
408 if (message)
409 {
410 free(message);
411 message = NULL;
412 }
413
414 if (get_file)
415 {
416 char *file = get_file->file;
417
418 free(get_file);
419 get_file = NULL;
420
421 return file;
422 }
423
424 return NULL;
425 }
426
427