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