2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
11 #include "CompileInfo.h"
12 #include "ServiceBroker.h"
13 #include "filesystem/File.h"
14 #include "network/DNSNameCache.h"
15 #include "settings/AdvancedSettings.h"
16 #include "settings/SettingsComponent.h"
17 #include "utils/CharsetConverter.h"
18 #include "utils/StringUtils.h"
19 #include "utils/SystemInfo.h"
20 #include "utils/URIUtils.h"
21 #include "utils/log.h"
26 #include <netinet/in.h>
27 #include <sys/socket.h>
28 #include <taglib/id3v1genres.h>
30 using namespace MEDIA_DETECT
;
33 //-------------------------------------------------------------------------------------------------------------------
35 #if defined(TARGET_WINDOWS)
36 : m_cddb_socket(closesocket
, INVALID_SOCKET
)
38 : m_cddb_socket(close
, -1)
40 , m_cddb_ip_address(CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_cddbAddress
)
45 //-------------------------------------------------------------------------------------------------------------------
51 //-------------------------------------------------------------------------------------------------------------------
52 bool Xcddb::openSocket()
54 char namebuf
[NI_MAXHOST
], portbuf
[NI_MAXSERV
];
55 struct addrinfo hints
;
56 struct addrinfo
*result
, *addr
;
59 SOCKET fd
= INVALID_SOCKET
;
61 memset(&hints
, 0, sizeof(hints
));
62 hints
.ai_family
= AF_UNSPEC
;
63 hints
.ai_socktype
= SOCK_STREAM
;
64 hints
.ai_protocol
= IPPROTO_TCP
;
65 snprintf(service
, sizeof(service
), "%d", CDDB_PORT
);
67 res
= getaddrinfo(m_cddb_ip_address
.c_str(), service
, &hints
, &result
);
71 #if defined(TARGET_WINDOWS)
72 g_charsetConverter
.wToUTF8(gai_strerror(res
), err
);
74 err
= gai_strerror(res
);
76 CLog::Log(LOGERROR
, "Xcddb::openSocket - failed to lookup {} with error {}", m_cddb_ip_address
,
78 res
= getaddrinfo("130.179.31.49", service
, &hints
, &result
);
83 for(addr
= result
; addr
; addr
= addr
->ai_next
)
85 if(getnameinfo(addr
->ai_addr
, addr
->ai_addrlen
, namebuf
, sizeof(namebuf
), portbuf
, sizeof(portbuf
),NI_NUMERICHOST
))
87 strcpy(namebuf
, "[unknown]");
88 strcpy(portbuf
, "[unknown]");
90 CLog::Log(LOGDEBUG
, "Xcddb::openSocket - connecting to: {}:{} ...", namebuf
, portbuf
);
92 fd
= socket(addr
->ai_family
, addr
->ai_socktype
, addr
->ai_protocol
);
93 if (fd
== INVALID_SOCKET
)
96 if (connect(fd
, addr
->ai_addr
, addr
->ai_addrlen
) != SOCKET_ERROR
)
103 freeaddrinfo(result
);
104 if(fd
== INVALID_SOCKET
)
106 CLog::Log(LOGERROR
, "Xcddb::openSocket - failed to connect to cddb");
110 m_cddb_socket
.attach(fd
);
114 //-------------------------------------------------------------------------------------------------------------------
115 bool Xcddb::closeSocket()
119 m_cddb_socket
.reset();
124 //-------------------------------------------------------------------------------------------------------------------
125 bool Xcddb::Send( const void *buffer
, int bytes
)
127 std::unique_ptr
<char[]> tmp_buffer(new char[bytes
+ 10]);
128 strcpy(tmp_buffer
.get(), (const char*)buffer
);
129 tmp_buffer
.get()[bytes
] = '.';
130 tmp_buffer
.get()[bytes
+ 1] = 0x0d;
131 tmp_buffer
.get()[bytes
+ 2] = 0x0a;
132 tmp_buffer
.get()[bytes
+ 3] = 0x00;
133 int iErr
= send((SOCKET
)m_cddb_socket
, (const char*)tmp_buffer
.get(), bytes
+ 3, 0);
141 //-------------------------------------------------------------------------------------------------------------------
142 bool Xcddb::Send( const char *buffer
)
144 int iErr
= Send(buffer
, strlen(buffer
));
152 //-------------------------------------------------------------------------------------------------------------------
153 std::string
Xcddb::Recv(bool wait4point
)
158 std::string str_buffer
;
161 //##########################################################
162 // Read the buffer. Character by character
168 prevChar
=tmpbuffer
[0];
169 lenRead
= recv((SOCKET
)m_cddb_socket
, (char*) & tmpbuffer
, 1, 0);
171 //Check if there was any error reading the buffer
172 if(lenRead
== 0 || lenRead
== SOCKET_ERROR
|| WSAGetLastError() == WSAECONNRESET
)
175 "Xcddb::Recv Error reading buffer. lenRead = [{}] and WSAGetLastError = [{}]",
176 lenRead
, WSAGetLastError());
180 //Write received data to the return string
181 str_buffer
.push_back(tmpbuffer
[0]);
183 }while(wait4point
? prevChar
!= '\n' || tmpbuffer
[0] != '.' : tmpbuffer
[0] != '\n');
186 //##########################################################
187 // Write captured data information to the xbmc log file
189 "Xcddb::Recv Captured {0} bytes // Buffer= {1} bytes. Captured data follows on next "
191 counter
, str_buffer
.size(), str_buffer
);
197 //-------------------------------------------------------------------------------------------------------------------
198 bool Xcddb::queryCDinfo(CCdInfo
* pInfo
, int inexact_list_select
)
202 m_lastError
= E_PARAMETER_WRONG
;
206 uint32_t discid
= pInfo
->GetCddbDiscId();
209 //##########################################################
210 // Compose the cddb query string
211 std::string read_buffer
= getInexactCommand(inexact_list_select
);
212 if (read_buffer
.empty())
214 CLog::Log(LOGERROR
, "Xcddb::queryCDinfo_inexact_list_select Size of inexact_list_select are 0");
215 m_lastError
= E_PARAMETER_WRONG
;
220 //##########################################################
221 // Read the data from cddb
222 Recv(false); // Clear pending data on our connection
223 if (!Send(read_buffer
.c_str()))
225 CLog::Log(LOGERROR
, "Xcddb::queryCDinfo_inexact_list_select Error sending \"{}\"", read_buffer
);
226 CLog::Log(LOGERROR
, "Xcddb::queryCDinfo_inexact_list_select pInfo == NULL");
227 m_lastError
= E_NETWORK_ERROR_SEND
;
230 std::string recv_buffer
= Recv(true);
231 m_lastError
= atoi(recv_buffer
.c_str());
234 case 210: //OK, CDDB database entry follows (until terminating marker)
235 // Cool, I got it ;-)
236 writeCacheFile( recv_buffer
.c_str(), discid
);
237 parseData(recv_buffer
.c_str());
240 case 401: //Specified CDDB entry not found.
241 case 402: //Server error.
242 case 403: //Database entry is corrupt.
243 case 409: //No handshake.
245 CLog::Log(LOGERROR
, "Xcddb::queryCDinfo_inexact_list_select Error: \"{}\"", recv_buffer
);
250 //##########################################################
252 if ( ! Send("quit") )
254 CLog::Log(LOGERROR
, "Xcddb::queryCDinfo_inexact_list_select Error sending \"{}\"", "quit");
255 m_lastError
= E_NETWORK_ERROR_SEND
;
258 recv_buffer
= Recv(false);
259 m_lastError
= atoi(recv_buffer
.c_str());
262 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
263 case 230: //Closing connection. Goodbye.
266 case 530: //error, closing connection.
268 CLog::Log(LOGERROR
, "Xcddb::queryCDinfo_inexact_list_select Error: \"{}\"", recv_buffer
);
273 //##########################################################
275 if ( !closeSocket() )
277 CLog::Log(LOGERROR
, "Xcddb::queryCDinfo_inexact_list_select Error closing socket");
278 m_lastError
= E_NETWORK_ERROR_SEND
;
285 //-------------------------------------------------------------------------------------------------------------------
286 int Xcddb::getLastError() const
292 //-------------------------------------------------------------------------------------------------------------------
293 const char *Xcddb::getLastErrorText() const
295 switch (getLastError())
297 case E_TOC_INCORRECT
:
298 return "TOC Incorrect";
300 case E_NETWORK_ERROR_OPEN_SOCKET
:
301 return "Error open Socket";
303 case E_NETWORK_ERROR_SEND
:
304 return "Error send PDU";
306 case E_WAIT_FOR_INPUT
:
307 return "Wait for Input";
309 case E_PARAMETER_WRONG
:
310 return "Error Parameter Wrong";
312 case 202: return "No match found";
313 case 210: return "Found exact matches, list follows (until terminating marker)";
314 case 211: return "Found inexact matches, list follows (until terminating marker)";
315 case 401: return "Specified CDDB entry not found";
316 case 402: return "Server error";
317 case 403: return "Database entry is corrupt";
318 case 408: return "CGI environment error";
319 case 409: return "No handshake";
320 case 431: return "Handshake not successful, closing connection";
321 case 432: return "No connections allowed: permission denied";
322 case 433: return "No connections allowed: X users allowed, Y currently active";
323 case 434: return "No connections allowed: system load too high";
324 case 500: return "Command syntax error, command unknown, command unimplemented";
325 case 501: return "Illegal protocol level";
326 case 530: return "error, closing connection, Server error, server timeout";
327 default: return "Unknown Error";
332 //-------------------------------------------------------------------------------------------------------------------
333 int Xcddb::cddb_sum(int n
)
337 /* For backward compatibility this algorithm must not change */
343 ret
= ret
+ (n
% 10);
350 //-------------------------------------------------------------------------------------------------------------------
351 uint32_t Xcddb::calc_disc_id(int tot_trks
, toc cdtoc
[])
353 int i
= 0, t
= 0, n
= 0;
358 n
= n
+ cddb_sum((cdtoc
[i
].min
* 60) + cdtoc
[i
].sec
);
362 t
= ((cdtoc
[tot_trks
].min
* 60) + cdtoc
[tot_trks
].sec
) - ((cdtoc
[0].min
* 60) + cdtoc
[0].sec
);
364 return ((n
% 0xff) << 24 | t
<< 8 | tot_trks
);
367 //-------------------------------------------------------------------------------------------------------------------
368 void Xcddb::addTitle(const char *buffer
)
373 if (buffer
[7] == '=')
375 trk_nr
= buffer
[6] - 47;
376 strncpy(value
, buffer
+ 8, sizeof(value
) - 1);
378 else if (buffer
[8] == '=')
380 trk_nr
= ((buffer
[6] - 48) * 10) + buffer
[7] - 47;
381 strncpy(value
, buffer
+ 9, sizeof(value
) - 1);
383 else if (buffer
[9] == '=')
385 trk_nr
= ((buffer
[6] - 48) * 100) + ((buffer
[7] - 48) * 10) + buffer
[8] - 47;
386 strncpy(value
, buffer
+ 10, sizeof(value
) - 1);
392 value
[sizeof(value
) - 1] = '\0';
394 // track artist" / "track title
395 std::vector
<std::string
> values
= StringUtils::Split(value
, " / ");
396 if (values
.size() > 1)
398 g_charsetConverter
.unknownToUTF8(values
[0]);
399 m_mapArtists
[trk_nr
] += values
[0];
400 g_charsetConverter
.unknownToUTF8(values
[1]);
401 m_mapTitles
[trk_nr
] += values
[1];
403 else if (!values
.empty())
405 g_charsetConverter
.unknownToUTF8(values
[0]);
406 m_mapTitles
[trk_nr
] += values
[0];
410 //-------------------------------------------------------------------------------------------------------------------
411 const std::string
& Xcddb::getInexactCommand(int select
) const
413 typedef std::map
<int, std::string
>::const_iterator iter
;
414 iter i
= m_mapInexact_cddb_command_list
.find(select
);
415 if (i
== m_mapInexact_cddb_command_list
.end())
420 //-------------------------------------------------------------------------------------------------------------------
421 const std::string
& Xcddb::getInexactArtist(int select
) const
423 typedef std::map
<int, std::string
>::const_iterator iter
;
424 iter i
= m_mapInexact_artist_list
.find(select
);
425 if (i
== m_mapInexact_artist_list
.end())
430 //-------------------------------------------------------------------------------------------------------------------
431 const std::string
& Xcddb::getInexactTitle(int select
) const
433 typedef std::map
<int, std::string
>::const_iterator iter
;
434 iter i
= m_mapInexact_title_list
.find(select
);
435 if (i
== m_mapInexact_title_list
.end())
440 //-------------------------------------------------------------------------------------------------------------------
441 const std::string
& Xcddb::getTrackArtist(int track
) const
443 typedef std::map
<int, std::string
>::const_iterator iter
;
444 iter i
= m_mapArtists
.find(track
);
445 if (i
== m_mapArtists
.end())
450 //-------------------------------------------------------------------------------------------------------------------
451 const std::string
& Xcddb::getTrackTitle(int track
) const
453 typedef std::map
<int, std::string
>::const_iterator iter
;
454 iter i
= m_mapTitles
.find(track
);
455 if (i
== m_mapTitles
.end())
460 //-------------------------------------------------------------------------------------------------------------------
461 void Xcddb::getDiskTitle(std::string
& strdisk_title
) const
463 strdisk_title
= m_strDisk_title
;
466 //-------------------------------------------------------------------------------------------------------------------
467 void Xcddb::getDiskArtist(std::string
& strdisk_artist
) const
469 strdisk_artist
= m_strDisk_artist
;
472 //-------------------------------------------------------------------------------------------------------------------
473 void Xcddb::parseData(const char *buffer
)
475 //writeLog("parseData Start");
477 std::map
<std::string
, std::string
> keywords
;
478 std::list
<std::string
> keywordsOrder
; // remember order of keywords as it appears in data received from CDDB
480 // Collect all the keywords and put them in map.
481 // Multiple occurrences of the same keyword indicate that
482 // the data contained on those lines should be concatenated
484 const char trenner
[3] = {'\n', '\r', '\0'};
485 strtok(const_cast<char*>(buffer
), trenner
); // skip first line
486 while ((line
= strtok(0, trenner
)))
488 // Lines that begin with # are comments, should be ignored
491 char *s
= strstr(line
, "=");
494 std::string
strKeyword(line
, s
- line
);
495 StringUtils::TrimRight(strKeyword
);
497 std::string
strValue(s
+1);
498 StringUtils::Replace(strValue
, "\\n", "\n");
499 StringUtils::Replace(strValue
, "\\t", "\t");
500 StringUtils::Replace(strValue
, "\\\\", "\\");
502 std::map
<std::string
, std::string
>::const_iterator it
= keywords
.find(strKeyword
);
503 if (it
!= keywords
.end())
504 strValue
= it
->second
+ strValue
; // keyword occurred before, concatenate
506 keywordsOrder
.push_back(strKeyword
);
508 keywords
[strKeyword
] = strValue
;
514 for (const std::string
& strKeyword
: keywordsOrder
)
516 std::string strValue
= keywords
[strKeyword
];
518 //! @todo STRING_CLEANUP
519 if (strKeyword
== "DTITLE")
521 // DTITLE may contain artist and disc title, separated with " / ",
522 // for example: DTITLE=Modern Talking / Album: Victory (The 11th Album)
524 for (int i
= 0; i
< (int)strValue
.size() - 2; i
++)
526 if (strValue
[i
] == ' ' && strValue
[i
+ 1] == '/' && strValue
[i
+ 2] == ' ')
528 m_strDisk_artist
= TrimToUTF8(strValue
.substr(0, i
));
529 m_strDisk_title
= TrimToUTF8(strValue
.substr(i
+3));
536 m_strDisk_title
= TrimToUTF8(strValue
);
538 else if (strKeyword
== "DYEAR")
539 m_strYear
= TrimToUTF8(strValue
);
540 else if (strKeyword
== "DGENRE")
541 m_strGenre
= TrimToUTF8(strValue
);
542 else if (StringUtils::StartsWith(strKeyword
, "TTITLE"))
543 addTitle((strKeyword
+ "=" + strValue
).c_str());
544 else if (strKeyword
== "EXTD")
546 const std::string
& strExtd(strValue
);
548 if (m_strYear
.empty())
550 // Extract Year from extended info
552 size_t iPos
= strExtd
.find("YEAR: ");
553 if (iPos
!= std::string::npos
) // You never know if you really get UTF-8 strings from cddb
554 g_charsetConverter
.unknownToUTF8(strExtd
.substr(iPos
+ 6, 4), m_strYear
);
557 if (m_strGenre
.empty())
561 size_t iPos
= strExtd
.find("ID3G: ");
562 if (iPos
!= std::string::npos
)
564 std::string strGenre
= strExtd
.substr(iPos
+ 5, 4);
565 StringUtils::TrimLeft(strGenre
);
566 if (StringUtils::IsNaturalNumber(strGenre
))
568 int iGenre
= strtol(strGenre
.c_str(), NULL
, 10);
569 m_strGenre
= TagLib::ID3v1::genre(iGenre
).to8Bit(true);
574 else if (StringUtils::StartsWith(strKeyword
, "EXTT"))
575 addExtended((strKeyword
+ "=" + strValue
).c_str());
578 //writeLog("parseData Ende");
581 //-------------------------------------------------------------------------------------------------------------------
582 void Xcddb::addExtended(const char *buffer
)
587 if (buffer
[5] == '=')
589 trk_nr
= buffer
[4] - 47;
590 strncpy(value
, buffer
+ 6, sizeof(value
) - 1);
592 else if (buffer
[6] == '=')
594 trk_nr
= ((buffer
[4] - 48) * 10) + buffer
[5] - 47;
595 strncpy(value
, buffer
+ 7, sizeof(value
) - 1);
597 else if (buffer
[7] == '=')
599 trk_nr
= ((buffer
[4] - 48) * 100) + ((buffer
[5] - 48) * 10) + buffer
[6] - 47;
600 strncpy(value
, buffer
+ 8, sizeof(value
) - 1);
606 value
[sizeof(value
) - 1] = '\0';
608 std::string strValue
;
609 std::string strValueUtf8
=value
;
610 // You never know if you really get UTF-8 strings from cddb
611 g_charsetConverter
.unknownToUTF8(strValueUtf8
, strValue
);
612 m_mapExtended_track
[trk_nr
] = strValue
;
615 //-------------------------------------------------------------------------------------------------------------------
616 const std::string
& Xcddb::getTrackExtended(int track
) const
618 typedef std::map
<int, std::string
>::const_iterator iter
;
619 iter i
= m_mapExtended_track
.find(track
);
620 if (i
== m_mapExtended_track
.end())
625 //-------------------------------------------------------------------------------------------------------------------
626 void Xcddb::addInexactList(const char *list
)
629 211 Found inexact matches, list follows (until terminating `.')
630 soundtrack bf0cf90f Modern Talking / Victory - The 11th Album
631 rock c90cf90f Modern Talking / Album: Victory (The 11th Album)
632 misc de0d020f Modern Talking / Ready for the victory
633 rock e00d080f Modern Talking / Album: Victory (The 11th Album)
634 rock c10d150f Modern Talking / Victory (The 11th Album)
639 m_mapInexact_cddb_command_list;
640 m_mapInexact_artist_list;
641 m_mapInexact_title_list;
646 int line_counter
= 0;
647 // //writeLog("addInexactList Start");
648 for (unsigned int i
= 0;i
< strlen(list
);i
++)
657 if (line_counter
> 0)
659 addInexactListLine(line_counter
, list
+ start
, end
- start
- 1);
666 // //writeLog("addInexactList End");
669 //-------------------------------------------------------------------------------------------------------------------
670 void Xcddb::addInexactListLine(int line_cnt
, const char *line
, int len
)
672 // rock c90cf90f Modern Talking / Album: Victory (The 11th Album)
674 char genre
[100]; // 0
675 char discid
[10]; // 1
676 char artist
[1024]; // 2
678 char cddb_command
[1024];
680 // //writeLog("addInexactListLine Start");
681 for (int i
= 0;i
< len
;i
++)
688 strncpy(genre
, line
, i
);
697 strncpy(discid
, line
+ start
, i
- start
);
698 discid
[i
- start
] = 0x00;
704 if (i
+ 2 <= len
&& line
[i
] == ' ' && line
[i
+ 1] == '/' && line
[i
+ 2] == ' ')
706 strncpy(artist
, line
+ start
, i
- start
);
707 artist
[i
- start
] = 0x00;
708 strncpy(title
, line
+ (i
+ 3), len
- (i
+ 3));
709 title
[len
- (i
+ 3)] = 0x00;
714 snprintf(cddb_command
, sizeof(cddb_command
), "cddb read %s %s", genre
, discid
);
716 m_mapInexact_cddb_command_list
[line_cnt
] = cddb_command
;
718 std::string strArtist
=artist
;
719 // You never know if you really get UTF-8 strings from cddb
720 g_charsetConverter
.unknownToUTF8(artist
, strArtist
);
721 m_mapInexact_artist_list
[line_cnt
] = strArtist
;
723 std::string strTitle
=title
;
724 // You never know if you really get UTF-8 strings from cddb
725 g_charsetConverter
.unknownToUTF8(title
, strTitle
);
726 m_mapInexact_title_list
[line_cnt
] = strTitle
;
727 // char log_string[1024];
728 // snprintf(log_string, sizeof(log_string), "%u: %s - %s",line_cnt,artist,title);
729 // //writeLog(log_string);
730 // //writeLog("addInexactListLine End");
733 //-------------------------------------------------------------------------------------------------------------------
734 void Xcddb::setCDDBIpAddress(const std::string
& ip_address
)
736 m_cddb_ip_address
= ip_address
;
739 //-------------------------------------------------------------------------------------------------------------------
740 void Xcddb::setCacheDir(const std::string
& pCacheDir
)
742 cCacheDir
= pCacheDir
;
745 //-------------------------------------------------------------------------------------------------------------------
746 bool Xcddb::queryCache( uint32_t discid
)
748 if (cCacheDir
.empty())
752 if (file
.Open(GetCacheFile(discid
)))
756 file
.Read(buffer
, 4096);
765 //-------------------------------------------------------------------------------------------------------------------
766 bool Xcddb::writeCacheFile( const char* pBuffer
, uint32_t discid
)
768 if (cCacheDir
.empty())
772 if (file
.OpenForWrite(GetCacheFile(discid
), true))
774 const bool ret
= ( (size_t) file
.Write((const void*)pBuffer
, strlen(pBuffer
) + 1) == strlen(pBuffer
) + 1);
782 //-------------------------------------------------------------------------------------------------------------------
783 bool Xcddb::isCDCached( int nr_of_tracks
, toc cdtoc
[] )
785 if (cCacheDir
.empty())
788 return XFILE::CFile::Exists(GetCacheFile(calc_disc_id(nr_of_tracks
, cdtoc
)));
791 //-------------------------------------------------------------------------------------------------------------------
792 const std::string
& Xcddb::getYear() const
797 //-------------------------------------------------------------------------------------------------------------------
798 const std::string
& Xcddb::getGenre() const
803 //-------------------------------------------------------------------------------------------------------------------
804 bool Xcddb::queryCDinfo(CCdInfo
* pInfo
)
808 CLog::Log(LOGERROR
, "Xcddb::queryCDinfo pInfo == NULL");
809 m_lastError
= E_PARAMETER_WRONG
;
813 int lead_out
= pInfo
->GetTrackCount();
814 int real_track_count
= pInfo
->GetTrackCount();
815 uint32_t discid
= pInfo
->GetCddbDiscId();
816 unsigned long frames
[100];
819 //##########################################################
821 if ( queryCache(discid
) )
823 CLog::Log(LOGDEBUG
, "Xcddb::queryCDinfo discid [{:08x}] already cached", discid
);
827 //##########################################################
829 for (int i
= 0;i
< lead_out
;i
++)
831 frames
[i
] = pInfo
->GetTrackInformation( i
+ 1 ).nFrames
;
832 if (i
> 0 && frames
[i
] < frames
[i
- 1])
834 CLog::Log(LOGERROR
, "Xcddb::queryCDinfo E_TOC_INCORRECT");
835 m_lastError
= E_TOC_INCORRECT
;
839 unsigned long complete_length
= pInfo
->GetDiscLength();
842 //##########################################################
843 // Open socket to cddb database
846 CLog::Log(LOGERROR
, "Xcddb::queryCDinfo Error opening socket");
847 m_lastError
= E_NETWORK_ERROR_OPEN_SOCKET
;
850 std::string recv_buffer
= Recv(false);
851 m_lastError
= atoi(recv_buffer
.c_str());
854 case 200: //OK, read/write allowed
855 case 201: //OK, read only
858 case 432: //No connections allowed: permission denied
859 case 433: //No connections allowed: X users allowed, Y currently active
860 case 434: //No connections allowed: system load too high
862 CLog::Log(LOGERROR
, "Xcddb::queryCDinfo Error: \"{}\"", recv_buffer
);
867 //##########################################################
868 // Send the Hello message
869 std::string version
= CSysInfo::GetVersion();
870 std::string lcAppName
= CCompileInfo::GetAppName();
871 StringUtils::ToLower(lcAppName
);
872 if (version
.find(' ') != std::string::npos
)
873 version
.resize(version
.find(' '));
874 std::string strGreeting
= "cddb hello " + lcAppName
+ " kodi.tv " + CCompileInfo::GetAppName() + " " + version
;
875 if ( ! Send(strGreeting
.c_str()) )
877 CLog::Log(LOGERROR
, "Xcddb::queryCDinfo Error sending \"{}\"", strGreeting
);
878 m_lastError
= E_NETWORK_ERROR_SEND
;
881 recv_buffer
= Recv(false);
882 m_lastError
= atoi(recv_buffer
.c_str());
885 case 200: //Handshake successful
886 case 402: //Already shook hands
889 case 431: //Handshake not successful, closing connection
891 CLog::Log(LOGERROR
, "Xcddb::queryCDinfo Error: \"{}\"", recv_buffer
);
896 //##########################################################
897 // Set CDDB protocol-level to 5
898 if ( ! Send("proto 5"))
900 CLog::Log(LOGERROR
, "Xcddb::queryCDinfo Error sending \"{}\"", "proto 5");
901 m_lastError
= E_NETWORK_ERROR_SEND
;
904 recv_buffer
= Recv(false);
905 m_lastError
= atoi(recv_buffer
.c_str());
908 case 200: //CDDB protocol level: current cur_level, supported supp_level
909 case 201: //OK, protocol version now: cur_level
910 case 502: //Protocol level already cur_level
913 case 501: //Illegal protocol level.
915 CLog::Log(LOGERROR
, "Xcddb::queryCDinfo Error: \"{}\"", recv_buffer
);
920 //##########################################################
921 // Compose the cddb query string
922 char query_buffer
[1024];
923 strcpy(query_buffer
, "");
924 strcat(query_buffer
, "cddb query");
926 char tmp_buffer
[256];
927 snprintf(tmp_buffer
, sizeof(tmp_buffer
), " %08x", discid
);
928 strcat(query_buffer
, tmp_buffer
);
931 char tmp_buffer
[256];
932 snprintf(tmp_buffer
, sizeof(tmp_buffer
), " %i", real_track_count
);
933 strcat(query_buffer
, tmp_buffer
);
935 for (int i
= 0;i
< lead_out
;i
++)
937 char tmp_buffer
[256];
938 snprintf(tmp_buffer
, sizeof(tmp_buffer
), " %lu", frames
[i
]);
939 strcat(query_buffer
, tmp_buffer
);
942 char tmp_buffer
[256];
943 snprintf(tmp_buffer
, sizeof(tmp_buffer
), " %lu", complete_length
);
944 strcat(query_buffer
, tmp_buffer
);
948 //##########################################################
950 if ( ! Send(query_buffer
))
952 CLog::Log(LOGERROR
, "Xcddb::queryCDinfo Error sending \"{}\"", query_buffer
);
953 m_lastError
= E_NETWORK_ERROR_SEND
;
956 // 200 rock d012180e Soundtrack / Hackers
957 std::string read_buffer
;
958 recv_buffer
= Recv(false);
959 m_lastError
= atoi(recv_buffer
.c_str());
962 case 200: //Found exact match
963 strtok(const_cast<char *>(recv_buffer
.c_str()), " ");
964 read_buffer
= StringUtils::Format("cddb read {} {:08x}", strtok(NULL
, " "), discid
);
967 case 210: //Found exact matches, list follows (until terminating marker)
968 case 211: //Found inexact matches, list follows (until terminating marker)
970 soundtrack bf0cf90f Modern Talking / Victory - The 11th Album
971 rock c90cf90f Modern Talking / Album: Victory (The 11th Album)
972 misc de0d020f Modern Talking / Ready for the victory
973 rock e00d080f Modern Talking / Album: Victory (The 11th Album)
974 rock c10d150f Modern Talking / Victory (The 11th Album)
977 recv_buffer
+= Recv(true);
978 addInexactList(recv_buffer
.c_str());
979 m_lastError
=E_WAIT_FOR_INPUT
;
980 return false; //This is actually good. The calling method will handle this
982 case 202: //No match found
985 "Xcddb::queryCDinfo No match found in CDDB database when doing the query shown below:\n{}",
988 case 403: //Database entry is corrupt
989 case 409: //No handshake
991 CLog::Log(LOGERROR
, "Xcddb::queryCDinfo Error: \"{}\"", recv_buffer
);
996 //##########################################################
997 // Read the data from cddb
998 if ( !Send(read_buffer
.c_str()) )
1000 CLog::Log(LOGERROR
, "Xcddb::queryCDinfo Error sending \"{}\"", read_buffer
);
1001 m_lastError
= E_NETWORK_ERROR_SEND
;
1004 recv_buffer
= Recv(true);
1005 m_lastError
= atoi(recv_buffer
.c_str());
1008 case 210: //OK, CDDB database entry follows (until terminating marker)
1009 // Cool, I got it ;-)
1010 writeCacheFile( recv_buffer
.c_str(), discid
);
1011 parseData(recv_buffer
.c_str());
1014 case 401: //Specified CDDB entry not found.
1015 case 402: //Server error.
1016 case 403: //Database entry is corrupt.
1017 case 409: //No handshake.
1019 CLog::Log(LOGERROR
, "Xcddb::queryCDinfo Error: \"{}\"", recv_buffer
);
1024 //##########################################################
1026 if ( ! Send("quit") )
1028 CLog::Log(LOGERROR
, "Xcddb::queryCDinfo Error sending \"{}\"", "quit");
1029 m_lastError
= E_NETWORK_ERROR_SEND
;
1032 recv_buffer
= Recv(false);
1033 m_lastError
= atoi(recv_buffer
.c_str());
1036 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
1037 case 230: //Closing connection. Goodbye.
1040 case 530: //error, closing connection.
1042 CLog::Log(LOGERROR
, "Xcddb::queryCDinfo Error: \"{}\"", recv_buffer
);
1047 //##########################################################
1049 if ( !closeSocket() )
1051 CLog::Log(LOGERROR
, "Xcddb::queryCDinfo Error closing socket");
1052 m_lastError
= E_NETWORK_ERROR_SEND
;
1058 //-------------------------------------------------------------------------------------------------------------------
1059 bool Xcddb::isCDCached( CCdInfo
* pInfo
)
1061 if (cCacheDir
.empty())
1063 if ( pInfo
== NULL
)
1066 return XFILE::CFile::Exists(GetCacheFile(pInfo
->GetCddbDiscId()));
1069 std::string
Xcddb::GetCacheFile(uint32_t disc_id
) const
1071 std::string strFileName
;
1072 strFileName
= StringUtils::Format("{:x}.cddb", disc_id
);
1073 return URIUtils::AddFileToFolder(cCacheDir
, strFileName
);
1076 std::string
Xcddb::TrimToUTF8(const std::string
&untrimmedText
)
1078 std::string
text(untrimmedText
);
1079 StringUtils::Trim(text
);
1080 // You never know if you really get UTF-8 strings from cddb
1081 g_charsetConverter
.unknownToUTF8(text
);