2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
20 //-----------------------------------------------------------------------------
23 // Desc: Make a connection to the CDDB database
27 //-----------------------------------------------------------------------------
33 #include <taglib/id3v1genres.h>
35 #include "network/DNSNameCache.h"
36 #include "settings/AdvancedSettings.h"
37 #include "utils/StringUtils.h"
38 #include "utils/URIUtils.h"
39 #include "filesystem/File.h"
40 #include "GUIInfoManager.h"
41 #include "utils/CharsetConverter.h"
42 #include "utils/log.h"
44 #include <sys/socket.h>
45 #include <netinet/in.h>
49 using namespace MEDIA_DETECT;
50 using namespace AUTOPTR;
53 //-------------------------------------------------------------------------------------------------------------------
55 : m_cddb_socket(INVALID_SOCKET)
58 m_cddb_ip_adress = g_advancedSettings.m_cddbAddress;
63 //-------------------------------------------------------------------------------------------------------------------
69 //-------------------------------------------------------------------------------------------------------------------
70 bool Xcddb::openSocket()
72 char namebuf[NI_MAXHOST], portbuf[NI_MAXSERV];
73 struct addrinfo hints;
74 struct addrinfo *result, *addr;
77 SOCKET fd = INVALID_SOCKET;
79 memset(&hints, 0, sizeof(hints));
80 hints.ai_family = AF_UNSPEC;
81 hints.ai_socktype = SOCK_STREAM;
82 hints.ai_protocol = IPPROTO_TCP;
83 sprintf(service, "%d", CDDB_PORT);
85 res = getaddrinfo(m_cddb_ip_adress.c_str(), service, &hints, &result);
88 CLog::Log(LOGERROR, "Xcddb::openSocket - failed to lookup %s with error %s", m_cddb_ip_adress.c_str(), gai_strerror(res));
89 res = getaddrinfo("130.179.31.49", service, &hints, &result);
94 for(addr = result; addr; addr = addr->ai_next)
96 if(getnameinfo(addr->ai_addr, addr->ai_addrlen, namebuf, sizeof(namebuf), portbuf, sizeof(portbuf),NI_NUMERICHOST))
98 strcpy(namebuf, "[unknown]");
99 strcpy(portbuf, "[unknown]");
101 CLog::Log(LOGDEBUG, "Xcddb::openSocket - connecting to: %s:%s ...", namebuf, portbuf);
103 fd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
104 if(fd == INVALID_SOCKET)
107 if(connect(fd, addr->ai_addr, addr->ai_addrlen) != SOCKET_ERROR)
114 freeaddrinfo(result);
115 if(fd == INVALID_SOCKET)
117 CLog::Log(LOGERROR, "Xcddb::openSocket - failed to connect to cddb");
121 m_cddb_socket.attach(fd);
125 //-------------------------------------------------------------------------------------------------------------------
126 bool Xcddb::closeSocket()
128 if ( m_cddb_socket.isValid() )
130 m_cddb_socket.reset();
135 //-------------------------------------------------------------------------------------------------------------------
136 bool Xcddb::Send( const void *buffer, int bytes )
138 auto_aptr<char> tmp_buffer (new char[bytes + 10]);
139 strcpy(tmp_buffer.get(), (const char*)buffer);
140 tmp_buffer.get()[bytes] = '.';
141 tmp_buffer.get()[bytes + 1] = 0x0d;
142 tmp_buffer.get()[bytes + 2] = 0x0a;
143 tmp_buffer.get()[bytes + 3] = 0x00;
144 int iErr = send((SOCKET)m_cddb_socket, (const char*)tmp_buffer.get(), bytes + 3, 0);
152 //-------------------------------------------------------------------------------------------------------------------
153 bool Xcddb::Send( const char *buffer)
155 int iErr = Send(buffer, strlen(buffer));
163 //-------------------------------------------------------------------------------------------------------------------
164 string Xcddb::Recv(bool wait4point)
172 //##########################################################
173 // Read the buffer. Character by character
179 prevChar=tmpbuffer[0];
180 lenRead = recv((SOCKET)m_cddb_socket, (char*) & tmpbuffer, 1, 0);
182 //Check if there was any error reading the buffer
183 if(lenRead == 0 || lenRead == SOCKET_ERROR || WSAGetLastError() == WSAECONNRESET)
185 CLog::Log(LOGERROR, "Xcddb::Recv Error reading buffer. lenRead = [%d] and WSAGetLastError = [%d]", lenRead, WSAGetLastError());
189 //Write received data to the return string
190 str_buffer.push_back(tmpbuffer[0]);
192 }while(wait4point ? prevChar != '\n' || tmpbuffer[0] != '.' : tmpbuffer[0] != '\n');
195 //##########################################################
196 // Write captured data information to the xbmc log file
197 CLog::Log(LOGDEBUG,"Xcddb::Recv Captured %d bytes // Buffer= %"PRIdS" bytes. Captured data follows on next line\n%s", counter, str_buffer.size(),(char *)str_buffer.c_str());
203 //-------------------------------------------------------------------------------------------------------------------
204 bool Xcddb::queryCDinfo(CCdInfo* pInfo, int inexact_list_select)
208 m_lastError = E_PARAMETER_WRONG;
212 uint32_t discid = pInfo->GetCddbDiscId();
215 //##########################################################
216 // Compose the cddb query string
217 CStdString read_buffer = getInexactCommand(inexact_list_select);
218 if (read_buffer.size() == 0)
220 CLog::Log(LOGERROR, "Xcddb::queryCDinfo_inexaxt_list_select Size of inexaxt_list_select are 0");
221 m_lastError = E_PARAMETER_WRONG;
226 //##########################################################
227 // Read the data from cddb
228 Recv(false); //erstmal den Müll abholen
229 if ( !Send(read_buffer) )
231 CLog::Log(LOGERROR, "Xcddb::queryCDinfo_inexaxt_list_select Error sending \"%s\"", read_buffer.c_str());
232 CLog::Log(LOGERROR, "Xcddb::queryCDinfo_inexaxt_list_select pInfo == NULL");
233 m_lastError = E_NETWORK_ERROR_SEND;
236 CStdString recv_buffer = Recv(true);
237 m_lastError = atoi(recv_buffer.c_str());
240 case 210: //OK, CDDB database entry follows (until terminating marker)
241 // Cool, I got it ;-)
242 writeCacheFile( recv_buffer.c_str(), discid );
243 parseData(recv_buffer.c_str());
246 case 401: //Specified CDDB entry not found.
247 case 402: //Server error.
248 case 403: //Database entry is corrupt.
249 case 409: //No handshake.
251 CLog::Log(LOGERROR, "Xcddb::queryCDinfo_inexaxt_list_select Error: \"%s\"", recv_buffer.c_str());
256 //##########################################################
258 if ( ! Send("quit") )
260 CLog::Log(LOGERROR, "Xcddb::queryCDinfo_inexaxt_list_select Error sending \"%s\"", "quit");
261 m_lastError = E_NETWORK_ERROR_SEND;
264 recv_buffer = Recv(false);
265 m_lastError = atoi(recv_buffer.c_str());
268 case 0: //By some reason, also 0 is a valid value. This is not documented, and might depend on that no string was found and atoi then returns 0
269 case 230: //Closing connection. Goodbye.
272 case 530: //error, closing connection.
274 CLog::Log(LOGERROR, "Xcddb::queryCDinfo_inexaxt_list_select Error: \"%s\"", recv_buffer.c_str());
279 //##########################################################
281 if ( !closeSocket() )
283 CLog::Log(LOGERROR, "Xcddb::queryCDinfo_inexaxt_list_select Error closing socket");
284 m_lastError = E_NETWORK_ERROR_SEND;
291 //-------------------------------------------------------------------------------------------------------------------
292 int Xcddb::getLastError() const
298 //-------------------------------------------------------------------------------------------------------------------
299 const char *Xcddb::getLastErrorText() const
301 switch (getLastError())
303 case E_TOC_INCORRECT:
304 return "TOC Incorrect";
306 case E_NETWORK_ERROR_OPEN_SOCKET:
307 return "Error open Socket";
309 case E_NETWORK_ERROR_SEND:
310 return "Error send PDU";
312 case E_WAIT_FOR_INPUT:
313 return "Wait for Input";
315 case E_PARAMETER_WRONG:
316 return "Error Parameter Wrong";
318 case 202: return "No match found";
319 case 210: return "Found exact matches, list follows (until terminating marker)";
320 case 211: return "Found inexact matches, list follows (until terminating marker)";
321 case 401: return "Specified CDDB entry not found";
322 case 402: return "Server error";
323 case 403: return "Database entry is corrupt";
324 case 408: return "CGI environment error";
325 case 409: return "No handshake";
326 case 431: return "Handshake not successful, closing connection";
327 case 432: return "No connections allowed: permission denied";
328 case 433: return "No connections allowed: X users allowed, Y currently active";
329 case 434: return "No connections allowed: system load too high";
330 case 500: return "Command syntax error, command unknown, command unimplemented";
331 case 501: return "Illegal protocol level";
332 case 530: return "error, closing connection, Server error, server timeout";
333 default: return "Unknown Error";
338 //-------------------------------------------------------------------------------------------------------------------
339 int Xcddb::cddb_sum(int n)
343 /* For backward compatibility this algorithm must not change */
349 ret = ret + (n % 10);
356 //-------------------------------------------------------------------------------------------------------------------
357 uint32_t Xcddb::calc_disc_id(int tot_trks, toc cdtoc[])
359 int i = 0, t = 0, n = 0;
364 n = n + cddb_sum((cdtoc[i].min * 60) + cdtoc[i].sec);
368 t = ((cdtoc[tot_trks].min * 60) + cdtoc[tot_trks].sec) - ((cdtoc[0].min * 60) + cdtoc[0].sec);
370 return ((n % 0xff) << 24 | t << 8 | tot_trks);
373 //-------------------------------------------------------------------------------------------------------------------
374 void Xcddb::addTitle(const char *buffer)
379 if (buffer[7] == '=')
381 trk_nr = buffer[6] - 47;
382 strcpy(value, buffer + 8);
384 else if (buffer[8] == '=')
386 trk_nr = ((buffer[6] - 48) * 10) + buffer[7] - 47;
387 strcpy(value, buffer + 9);
389 else if (buffer[9] == '=')
391 trk_nr = ((buffer[6] - 48) * 100) + ((buffer[7] - 48) * 10) + buffer[8] - 47;
392 strcpy(value, buffer + 10);
399 // track artist" / "track title
400 CStdString strValue = value;
401 CStdStringArray values;
402 StringUtils::SplitString(value, " / ", values);
403 if (values.size() > 1)
405 g_charsetConverter.unknownToUTF8(values[0]);
406 m_mapArtists[trk_nr] += values[0];
407 g_charsetConverter.unknownToUTF8(values[1]);
408 m_mapTitles[trk_nr] += values[1];
412 g_charsetConverter.unknownToUTF8(values[0]);
413 m_mapTitles[trk_nr] += values[0];
417 //-------------------------------------------------------------------------------------------------------------------
418 const CStdString& Xcddb::getInexactCommand(int select) const
420 typedef map<int, CStdString>::const_iterator iter;
421 iter i = m_mapInexact_cddb_command_list.find(select);
422 if (i == m_mapInexact_cddb_command_list.end())
427 //-------------------------------------------------------------------------------------------------------------------
428 const CStdString& Xcddb::getInexactArtist(int select) const
430 typedef map<int, CStdString>::const_iterator iter;
431 iter i = m_mapInexact_artist_list.find(select);
432 if (i == m_mapInexact_artist_list.end())
437 //-------------------------------------------------------------------------------------------------------------------
438 const CStdString& Xcddb::getInexactTitle(int select) const
440 typedef map<int, CStdString>::const_iterator iter;
441 iter i = m_mapInexact_title_list.find(select);
442 if (i == m_mapInexact_title_list.end())
447 //-------------------------------------------------------------------------------------------------------------------
448 const CStdString& Xcddb::getTrackArtist(int track) const
450 typedef map<int, CStdString>::const_iterator iter;
451 iter i = m_mapArtists.find(track);
452 if (i == m_mapArtists.end())
457 //-------------------------------------------------------------------------------------------------------------------
458 const CStdString& Xcddb::getTrackTitle(int track) const
460 typedef map<int, CStdString>::const_iterator iter;
461 iter i = m_mapTitles.find(track);
462 if (i == m_mapTitles.end())
467 //-------------------------------------------------------------------------------------------------------------------
468 void Xcddb::getDiskTitle(CStdString& strdisk_title) const
470 strdisk_title = m_strDisk_title;
473 //-------------------------------------------------------------------------------------------------------------------
474 void Xcddb::getDiskArtist(CStdString& strdisk_artist) const
476 strdisk_artist = m_strDisk_artist;
479 //-------------------------------------------------------------------------------------------------------------------
480 void Xcddb::parseData(const char *buffer)
482 //writeLog("parseData Start");
484 std::map<CStdString, CStdString> keywords;
485 std::list<CStdString> keywordsOrder; // remember order of keywords as it appears in data received from CDDB
487 // Collect all the keywords and put them in map.
488 // Multiple occurrences of the same keyword indicate that
489 // the data contained on those lines should be concatenated
491 const char trenner[3] = {'\n', '\r', '\0'};
492 strtok((char*)buffer, trenner); // skip first line
493 while ((line = strtok(0, trenner)))
495 // Lines that begin with # are comments, should be ignored
498 char *s = strstr(line, "=");
501 CStdString strKeyword(line, s - line);
502 StringUtils::TrimRight(strKeyword);
504 CStdString strValue(s+1);
505 strValue.Replace("\\n", "\n");
506 strValue.Replace("\\t", "\t");
507 strValue.Replace("\\\\", "\\");
509 std::map<CStdString, CStdString>::const_iterator it = keywords.find(strKeyword);
510 if (it != keywords.end())
511 strValue = it->second + strValue; // keyword occured before, concatenate
513 keywordsOrder.push_back(strKeyword);
515 keywords[strKeyword] = strValue;
521 for (std::list<CStdString>::const_iterator it = keywordsOrder.begin(); it != keywordsOrder.end(); ++it)
523 CStdString strKeyword = *it;
524 CStdString strValue = keywords[strKeyword];
526 if (strKeyword == "DTITLE")
528 // DTITLE may contain artist and disc title, separated with " / ",
529 // for example: DTITLE=Modern Talking / Album: Victory (The 11th Album)
531 for (int i = 0; i < strValue.GetLength() - 2; i++)
533 if (strValue[i] == ' ' && strValue[i + 1] == '/' && strValue[i + 2] == ' ')
535 m_strDisk_artist = TrimToUTF8(strValue.Left(i));
536 m_strDisk_title = TrimToUTF8(strValue.Mid(i+3));
543 m_strDisk_title = TrimToUTF8(strValue);
545 else if (strKeyword == "DYEAR")
546 m_strYear = TrimToUTF8(strValue);
547 else if (strKeyword== "DGENRE")
548 m_strGenre = TrimToUTF8(strValue);
549 else if (strKeyword.Left(6) == "TTITLE")
550 addTitle(strKeyword + "=" + strValue);
551 else if (strKeyword == "EXTD")
553 CStdString strExtd(strValue);
555 if (m_strYear.empty())
557 // Extract Year from extended info
559 int iPos = strExtd.Find("YEAR:");
560 if (iPos > -1) // You never know if you really get UTF-8 strings from cddb
561 g_charsetConverter.unknownToUTF8(strExtd.Mid(iPos + 6, 4), m_strYear);
564 if (m_strGenre.empty())
568 int iPos = strExtd.Find("ID3G:");
571 CStdString strGenre = strExtd.Mid(iPos + 5, 4);
572 StringUtils::TrimLeft(strGenre);
573 if (StringUtils::IsNaturalNumber(strGenre))
575 int iGenre = strtol(strGenre, NULL, 10);
576 m_strGenre = TagLib::ID3v1::genre(iGenre).to8Bit(true);
581 else if (strKeyword.Left(4) == "EXTT")
582 addExtended(strKeyword + "=" + strValue);
585 //writeLog("parseData Ende");
588 //-------------------------------------------------------------------------------------------------------------------
589 void Xcddb::addExtended(const char *buffer)
594 if (buffer[5] == '=')
596 trk_nr = buffer[4] - 47;
597 strcpy(value, buffer + 6);
599 else if (buffer[6] == '=')
601 trk_nr = ((buffer[4] - 48) * 10) + buffer[5] - 47;
602 strcpy(value, buffer + 7);
604 else if (buffer[7] == '=')
606 trk_nr = ((buffer[4] - 48) * 100) + ((buffer[5] - 48) * 10) + buffer[6] - 47;
607 strcpy(value, buffer + 8);
615 CStdString strValueUtf8=value;
616 // You never know if you really get UTF-8 strings from cddb
617 g_charsetConverter.unknownToUTF8(strValueUtf8, strValue);
618 m_mapExtended_track[trk_nr] = strValue;
621 //-------------------------------------------------------------------------------------------------------------------
622 const CStdString& Xcddb::getTrackExtended(int track) const
624 typedef map<int, CStdString>::const_iterator iter;
625 iter i = m_mapExtended_track.find(track);
626 if (i == m_mapExtended_track.end())
631 //-------------------------------------------------------------------------------------------------------------------
632 void Xcddb::addInexactList(const char *list)
635 211 Found inexact matches, list follows (until terminating `.')
636 soundtrack bf0cf90f Modern Talking / Victory - The 11th Album
637 rock c90cf90f Modern Talking / Album: Victory (The 11th Album)
638 misc de0d020f Modern Talking / Ready for the victory
639 rock e00d080f Modern Talking / Album: Victory (The 11th Album)
640 rock c10d150f Modern Talking / Victory (The 11th Album)
645 m_mapInexact_cddb_command_list;
646 m_mapInexact_artist_list;
647 m_mapInexact_title_list;
652 int line_counter = 0;
653 // //writeLog("addInexactList Start");
654 for (unsigned int i = 0;i < strlen(list);i++)
663 if (line_counter > 0)
665 addInexactListLine(line_counter, list + start, end - start - 1);
672 // //writeLog("addInexactList End");
675 //-------------------------------------------------------------------------------------------------------------------
676 void Xcddb::addInexactListLine(int line_cnt, const char *line, int len)
678 // rock c90cf90f Modern Talking / Album: Victory (The 11th Album)
680 char genre[100]; // 0
681 char discid[10]; // 1
682 char artist[1024]; // 2
684 char cddb_command[1024];
686 // //writeLog("addInexactListLine Start");
687 for (int i = 0;i < len;i++)
694 strncpy(genre, line, i);
703 strncpy(discid, line + start, i - start);
704 discid[i - start] = 0x00;
710 if (i + 2 <= len && line[i] == ' ' && line[i + 1] == '/' && line[i + 2] == ' ')
712 strncpy(artist, line + start, i - start);
713 artist[i - start] = 0x00;
714 strncpy(title, line + (i + 3), len - (i + 3));
715 title[len - (i + 3)] = 0x00;
720 sprintf(cddb_command, "cddb read %s %s", genre, discid);
722 m_mapInexact_cddb_command_list[line_cnt] = cddb_command;
724 CStdString strArtist=artist;
725 // You never know if you really get UTF-8 strings from cddb
726 g_charsetConverter.unknownToUTF8(artist, strArtist);
727 m_mapInexact_artist_list[line_cnt] = strArtist;
729 CStdString strTitle=title;
730 // You never know if you really get UTF-8 strings from cddb
731 g_charsetConverter.unknownToUTF8(title, strTitle);
732 m_mapInexact_title_list[line_cnt] = strTitle;
733 // char log_string[1024];
734 // sprintf(log_string,"%u: %s - %s",line_cnt,artist,title);
735 // //writeLog(log_string);
736 // //writeLog("addInexactListLine End");
739 //-------------------------------------------------------------------------------------------------------------------
740 void Xcddb::setCDDBIpAdress(const CStdString& ip_adress)
742 m_cddb_ip_adress = ip_adress;
745 //-------------------------------------------------------------------------------------------------------------------
746 void Xcddb::setCacheDir(const CStdString& pCacheDir )
748 cCacheDir = pCacheDir;
751 //-------------------------------------------------------------------------------------------------------------------
752 bool Xcddb::queryCache( uint32_t discid )
754 if (cCacheDir.size() == 0)
758 if (file.Open(GetCacheFile(discid)))
762 OutputDebugString ( "cddb local cache hit.\n" );
763 file.Read(buffer, 4096);
772 //-------------------------------------------------------------------------------------------------------------------
773 bool Xcddb::writeCacheFile( const char* pBuffer, uint32_t discid )
775 if (cCacheDir.size() == 0)
779 if (file.OpenForWrite(GetCacheFile(discid), true))
781 OutputDebugString ( "Current cd saved to local cddb.\n" );
782 file.Write( (void*) pBuffer, strlen( pBuffer ) + 1 );
790 //-------------------------------------------------------------------------------------------------------------------
791 bool Xcddb::isCDCached( int nr_of_tracks, toc cdtoc[] )
793 if (cCacheDir.size() == 0)
796 return XFILE::CFile::Exists(GetCacheFile(calc_disc_id(nr_of_tracks, cdtoc)));
799 //-------------------------------------------------------------------------------------------------------------------
800 const CStdString& Xcddb::getYear() const
805 //-------------------------------------------------------------------------------------------------------------------
806 const CStdString& Xcddb::getGenre() const
811 //-------------------------------------------------------------------------------------------------------------------
812 bool Xcddb::queryCDinfo(CCdInfo* pInfo)
816 CLog::Log(LOGERROR, "Xcddb::queryCDinfo pInfo == NULL");
817 m_lastError = E_PARAMETER_WRONG;
821 int lead_out = pInfo->GetTrackCount();
822 int real_track_count = pInfo->GetTrackCount();
823 uint32_t discid = pInfo->GetCddbDiscId();
824 unsigned long frames[100];
827 //##########################################################
829 if ( queryCache(discid) )
831 CLog::Log(LOGDEBUG, "Xcddb::queryCDinfo discid [%08x] already cached", discid);
835 //##########################################################
837 for (int i = 0;i < lead_out;i++)
839 frames[i] = pInfo->GetTrackInformation( i + 1 ).nFrames;
840 if (i > 0 && frames[i] < frames[i - 1])
842 CLog::Log(LOGERROR, "Xcddb::queryCDinfo E_TOC_INCORRECT");
843 m_lastError = E_TOC_INCORRECT;
847 unsigned long complete_length = pInfo->GetDiscLength();
850 //##########################################################
851 // Open socket to cddb database
854 CLog::Log(LOGERROR, "Xcddb::queryCDinfo Error opening socket");
855 m_lastError = E_NETWORK_ERROR_OPEN_SOCKET;
858 CStdString recv_buffer = Recv(false);
859 m_lastError = atoi(recv_buffer.c_str());
862 case 200: //OK, read/write allowed
863 case 201: //OK, read only
866 case 432: //No connections allowed: permission denied
867 case 433: //No connections allowed: X users allowed, Y currently active
868 case 434: //No connections allowed: system load too high
870 CLog::Log(LOGERROR, "Xcddb::queryCDinfo Error: \"%s\"", recv_buffer.c_str());
875 //##########################################################
876 // Send the Hello message
877 CStdString version = g_infoManager.GetLabel(SYSTEM_BUILD_VERSION);
878 if (version.Find(" ") >= 0)
879 version = version.Left(version.Find(" "));
880 CStdString strGreeting = "cddb hello xbmc xbmc.org XBMC " + version;
881 if ( ! Send(strGreeting.c_str()) )
883 CLog::Log(LOGERROR, "Xcddb::queryCDinfo Error sending \"%s\"", strGreeting.c_str());
884 m_lastError = E_NETWORK_ERROR_SEND;
887 recv_buffer = Recv(false);
888 m_lastError = atoi(recv_buffer.c_str());
891 case 200: //Handshake successful
892 case 402: //Already shook hands
895 case 431: //Handshake not successful, closing connection
897 CLog::Log(LOGERROR, "Xcddb::queryCDinfo Error: \"%s\"", recv_buffer.c_str());
902 //##########################################################
903 // Set CDDB protocol-level to 5
904 if ( ! Send("proto 5"))
906 CLog::Log(LOGERROR, "Xcddb::queryCDinfo Error sending \"%s\"", "proto 5");
907 m_lastError = E_NETWORK_ERROR_SEND;
910 recv_buffer = Recv(false);
911 m_lastError = atoi(recv_buffer.c_str());
914 case 200: //CDDB protocol level: current cur_level, supported supp_level
915 case 201: //OK, protocol version now: cur_level
916 case 502: //Protocol level already cur_level
919 case 501: //Illegal protocol level.
921 CLog::Log(LOGERROR, "Xcddb::queryCDinfo Error: \"%s\"", recv_buffer.c_str());
926 //##########################################################
927 // Compose the cddb query string
928 char query_buffer[1024];
929 strcpy(query_buffer, "");
930 strcat(query_buffer, "cddb query");
932 char tmp_buffer[256];
933 sprintf(tmp_buffer, " %08x", discid);
934 strcat(query_buffer, tmp_buffer);
937 char tmp_buffer[256];
938 sprintf(tmp_buffer, " %i", real_track_count);
939 strcat(query_buffer, tmp_buffer);
941 for (int i = 0;i < lead_out;i++)
943 char tmp_buffer[256];
944 sprintf(tmp_buffer, " %lu", frames[i]);
945 strcat(query_buffer, tmp_buffer);
948 char tmp_buffer[256];
949 sprintf(tmp_buffer, " %lu", complete_length);
950 strcat(query_buffer, tmp_buffer);
954 //##########################################################
956 if ( ! Send(query_buffer))
958 CLog::Log(LOGERROR, "Xcddb::queryCDinfo Error sending \"%s\"", query_buffer);
959 m_lastError = E_NETWORK_ERROR_SEND;
962 // 200 rock d012180e Soundtrack / Hackers
963 CStdString read_buffer;
964 recv_buffer = Recv(false);
965 m_lastError = atoi(recv_buffer.c_str());
968 case 200: //Found exact match
969 strtok((char *)recv_buffer.c_str(), " ");
970 read_buffer = StringUtils::Format("cddb read %s %08x", strtok(NULL, " "), discid);
973 case 210: //Found exact matches, list follows (until terminating marker)
974 case 211: //Found inexact matches, list follows (until terminating marker)
976 soundtrack bf0cf90f Modern Talking / Victory - The 11th Album
977 rock c90cf90f Modern Talking / Album: Victory (The 11th Album)
978 misc de0d020f Modern Talking / Ready for the victory
979 rock e00d080f Modern Talking / Album: Victory (The 11th Album)
980 rock c10d150f Modern Talking / Victory (The 11th Album)
983 recv_buffer += Recv(true);
984 addInexactList(recv_buffer.c_str());
985 m_lastError=E_WAIT_FOR_INPUT;
986 return false; //This is actually good. The calling method will handle this
988 case 202: //No match found
989 CLog::Log(LOGNOTICE, "Xcddb::queryCDinfo No match found in CDDB database when doing the query shown below:\n%s",query_buffer);
990 case 403: //Database entry is corrupt
991 case 409: //No handshake
993 CLog::Log(LOGERROR, "Xcddb::queryCDinfo Error: \"%s\"", recv_buffer.c_str());
998 //##########################################################
999 // Read the data from cddb
1000 if ( !Send(read_buffer) )
1002 CLog::Log(LOGERROR, "Xcddb::queryCDinfo Error sending \"%s\"", read_buffer.c_str());
1003 m_lastError = E_NETWORK_ERROR_SEND;
1006 recv_buffer = Recv(true);
1007 m_lastError = atoi(recv_buffer.c_str());
1010 case 210: //OK, CDDB database entry follows (until terminating marker)
1011 // Cool, I got it ;-)
1012 writeCacheFile( recv_buffer.c_str(), discid );
1013 parseData(recv_buffer.c_str());
1016 case 401: //Specified CDDB entry not found.
1017 case 402: //Server error.
1018 case 403: //Database entry is corrupt.
1019 case 409: //No handshake.
1021 CLog::Log(LOGERROR, "Xcddb::queryCDinfo Error: \"%s\"", recv_buffer.c_str());
1026 //##########################################################
1028 if ( ! Send("quit") )
1030 CLog::Log(LOGERROR, "Xcddb::queryCDinfo Error sending \"%s\"", "quit");
1031 m_lastError = E_NETWORK_ERROR_SEND;
1034 recv_buffer = Recv(false);
1035 m_lastError = atoi(recv_buffer.c_str());
1038 case 0: //By some reason, also 0 is a valid value. This is not documented, and might depend on that no string was found and atoi then returns 0
1039 case 230: //Closing connection. Goodbye.
1042 case 530: //error, closing connection.
1044 CLog::Log(LOGERROR, "Xcddb::queryCDinfo Error: \"%s\"", recv_buffer.c_str());
1049 //##########################################################
1051 if ( !closeSocket() )
1053 CLog::Log(LOGERROR, "Xcddb::queryCDinfo Error closing socket");
1054 m_lastError = E_NETWORK_ERROR_SEND;
1060 //-------------------------------------------------------------------------------------------------------------------
1061 bool Xcddb::isCDCached( CCdInfo* pInfo )
1063 if (cCacheDir.size() == 0)
1065 if ( pInfo == NULL )
1068 return XFILE::CFile::Exists(GetCacheFile(pInfo->GetCddbDiscId()));
1071 CStdString Xcddb::GetCacheFile(uint32_t disc_id) const
1073 CStdString strFileName;
1074 strFileName = StringUtils::Format("%x.cddb", disc_id);
1075 return URIUtils::AddFileToFolder(cCacheDir, strFileName);
1078 CStdString Xcddb::TrimToUTF8(const CStdString &untrimmedText)
1080 CStdString text(untrimmedText);
1081 StringUtils::Trim(text);
1082 // You never know if you really get UTF-8 strings from cddb
1083 g_charsetConverter.unknownToUTF8(text);