1cfe6baf6SAxel Dörfler /*
2768544f6SAxel Dörfler * Copyright 2008-2016, Haiku, Inc. All Rights Reserved.
3cfe6baf6SAxel Dörfler * Distributed under the terms of the MIT License.
4cfe6baf6SAxel Dörfler *
5cfe6baf6SAxel Dörfler * Authors:
6cfe6baf6SAxel Dörfler * Bruno Albuquerque, bga@bug-br.org.br
7cfe6baf6SAxel Dörfler */
8cfe6baf6SAxel Dörfler
9cfe6baf6SAxel Dörfler
10cfe6baf6SAxel Dörfler #include "cddb_server.h"
11cfe6baf6SAxel Dörfler
12cfe6baf6SAxel Dörfler #include <errno.h>
13cfe6baf6SAxel Dörfler #include <stdio.h>
14cfe6baf6SAxel Dörfler #include <stdlib.h>
15cfe6baf6SAxel Dörfler #include <unistd.h>
16cfe6baf6SAxel Dörfler
17cfe6baf6SAxel Dörfler
18cfe6baf6SAxel Dörfler static const char* kDefaultLocalHostName = "unknown";
19cfe6baf6SAxel Dörfler static const uint32 kDefaultPortNumber = 80;
20cfe6baf6SAxel Dörfler
21cfe6baf6SAxel Dörfler static const uint32 kFramesPerSecond = 75;
22cfe6baf6SAxel Dörfler static const uint32 kFramesPerMinute = kFramesPerSecond * 60;
23cfe6baf6SAxel Dörfler
24cfe6baf6SAxel Dörfler
CDDBServer(const BString & cddbServer)25cfe6baf6SAxel Dörfler CDDBServer::CDDBServer(const BString& cddbServer)
26cfe6baf6SAxel Dörfler :
27cfe6baf6SAxel Dörfler fInitialized(false),
28cfe6baf6SAxel Dörfler fConnected(false)
29cfe6baf6SAxel Dörfler {
30cfe6baf6SAxel Dörfler // Set up local host name.
31cfe6baf6SAxel Dörfler char localHostName[MAXHOSTNAMELEN + 1];
32cfe6baf6SAxel Dörfler if (gethostname(localHostName, MAXHOSTNAMELEN + 1) == 0) {
33cfe6baf6SAxel Dörfler fLocalHostName = localHostName;
34cfe6baf6SAxel Dörfler } else {
35cfe6baf6SAxel Dörfler fLocalHostName = kDefaultLocalHostName;
36cfe6baf6SAxel Dörfler }
37cfe6baf6SAxel Dörfler
38cfe6baf6SAxel Dörfler // Set up local user name.
39cfe6baf6SAxel Dörfler char* user = getenv("USER");
40768544f6SAxel Dörfler if (user == NULL)
41cfe6baf6SAxel Dörfler fLocalUserName = "unknown";
42768544f6SAxel Dörfler else
43cfe6baf6SAxel Dörfler fLocalUserName = user;
44cfe6baf6SAxel Dörfler
45cfe6baf6SAxel Dörfler // Set up server address;
46cfe6baf6SAxel Dörfler if (_ParseAddress(cddbServer) == B_OK)
47cfe6baf6SAxel Dörfler fInitialized = true;
48cfe6baf6SAxel Dörfler }
49cfe6baf6SAxel Dörfler
50cfe6baf6SAxel Dörfler
51cfe6baf6SAxel Dörfler status_t
Query(uint32 cddbID,const scsi_toc_toc * toc,QueryResponseList & queryResponses)52df53a4bfSAxel Dörfler CDDBServer::Query(uint32 cddbID, const scsi_toc_toc* toc,
53768544f6SAxel Dörfler QueryResponseList& queryResponses)
54cfe6baf6SAxel Dörfler {
55cfe6baf6SAxel Dörfler if (_OpenConnection() != B_OK)
56cfe6baf6SAxel Dörfler return B_ERROR;
57cfe6baf6SAxel Dörfler
58cfe6baf6SAxel Dörfler // Convert CDDB id to hexadecimal format.
59cfe6baf6SAxel Dörfler char hexCddbId[9];
60df53a4bfSAxel Dörfler sprintf(hexCddbId, "%08" B_PRIx32, cddbID);
61cfe6baf6SAxel Dörfler
62cfe6baf6SAxel Dörfler // Assemble the Query command.
63cfe6baf6SAxel Dörfler int32 numTracks = toc->last_track + 1 - toc->first_track;
64cfe6baf6SAxel Dörfler
65cfe6baf6SAxel Dörfler BString cddbCommand("cddb query ");
66cfe6baf6SAxel Dörfler cddbCommand << hexCddbId << " " << numTracks << " ";
67cfe6baf6SAxel Dörfler
68cfe6baf6SAxel Dörfler // Add track offsets in frames.
69cfe6baf6SAxel Dörfler for (int32 i = 0; i < numTracks; ++i) {
70cfe6baf6SAxel Dörfler const scsi_cd_msf& start = toc->tracks[i].start.time;
71cfe6baf6SAxel Dörfler
72cfe6baf6SAxel Dörfler uint32 startFrameOffset = start.minute * kFramesPerMinute +
73cfe6baf6SAxel Dörfler start.second * kFramesPerSecond + start.frame;
74cfe6baf6SAxel Dörfler
75cfe6baf6SAxel Dörfler cddbCommand << startFrameOffset << " ";
76cfe6baf6SAxel Dörfler }
77cfe6baf6SAxel Dörfler
78cfe6baf6SAxel Dörfler // Add total disc time in seconds. Last track is lead-out.
79cfe6baf6SAxel Dörfler const scsi_cd_msf& lastTrack = toc->tracks[numTracks].start.time;
80cfe6baf6SAxel Dörfler uint32 totalTimeInSeconds = lastTrack.minute * 60 + lastTrack.second;
81cfe6baf6SAxel Dörfler cddbCommand << totalTimeInSeconds;
82cfe6baf6SAxel Dörfler
83cfe6baf6SAxel Dörfler BString output;
84768544f6SAxel Dörfler status_t result = _SendCommand(cddbCommand, output);
85cfe6baf6SAxel Dörfler if (result == B_OK) {
86cfe6baf6SAxel Dörfler // Remove the header from the reply.
87cfe6baf6SAxel Dörfler output.Remove(0, output.FindFirst("\r\n\r\n") + 4);
88cfe6baf6SAxel Dörfler
89cfe6baf6SAxel Dörfler // Check status code.
90cfe6baf6SAxel Dörfler BString statusCode;
91cfe6baf6SAxel Dörfler output.MoveInto(statusCode, 0, 3);
92cfe6baf6SAxel Dörfler if (statusCode == "210" || statusCode == "211") {
93cfe6baf6SAxel Dörfler // TODO(bga): We can get around with returning the first result
94cfe6baf6SAxel Dörfler // in case of multiple matches, but we most definitely need a
95cfe6baf6SAxel Dörfler // better handling of inexact matches.
96cfe6baf6SAxel Dörfler if (statusCode == "211")
97cfe6baf6SAxel Dörfler printf("Warning : Inexact match found.\n");
98cfe6baf6SAxel Dörfler
99cfe6baf6SAxel Dörfler // Multiple results, remove the first line and parse the others.
100cfe6baf6SAxel Dörfler output.Remove(0, output.FindFirst("\r\n") + 2);
101cfe6baf6SAxel Dörfler } else if (statusCode == "200") {
102cfe6baf6SAxel Dörfler // Remove the first char which is a left over space.
103cfe6baf6SAxel Dörfler output.Remove(0, 1);
104cfe6baf6SAxel Dörfler } else if (statusCode == "202") {
105cfe6baf6SAxel Dörfler // No match found.
106cfe6baf6SAxel Dörfler printf("Error : CDDB entry for id %s not found.\n", hexCddbId);
107cfe6baf6SAxel Dörfler
108cfe6baf6SAxel Dörfler return B_ENTRY_NOT_FOUND;
109cfe6baf6SAxel Dörfler } else {
110cfe6baf6SAxel Dörfler // Something bad happened.
111cfe6baf6SAxel Dörfler if (statusCode.Trim() != "") {
112cfe6baf6SAxel Dörfler printf("Error : CDDB server status code is %s.\n",
113cfe6baf6SAxel Dörfler statusCode.String());
114cfe6baf6SAxel Dörfler } else {
115cfe6baf6SAxel Dörfler printf("Error : Could not find any status code.\n");
116cfe6baf6SAxel Dörfler }
117cfe6baf6SAxel Dörfler
118cfe6baf6SAxel Dörfler return B_ERROR;
119cfe6baf6SAxel Dörfler }
120cfe6baf6SAxel Dörfler
121cfe6baf6SAxel Dörfler // Process all entries.
122cfe6baf6SAxel Dörfler bool done = false;
123cfe6baf6SAxel Dörfler while (!done) {
124cfe6baf6SAxel Dörfler QueryResponseData* responseData = new QueryResponseData;
125cfe6baf6SAxel Dörfler
126cfe6baf6SAxel Dörfler output.MoveInto(responseData->category, 0, output.FindFirst(" "));
127cfe6baf6SAxel Dörfler output.Remove(0, 1);
128cfe6baf6SAxel Dörfler
129df53a4bfSAxel Dörfler output.MoveInto(responseData->cddbID, 0, output.FindFirst(" "));
130cfe6baf6SAxel Dörfler output.Remove(0, 1);
131cfe6baf6SAxel Dörfler
132cfe6baf6SAxel Dörfler output.MoveInto(responseData->artist, 0, output.FindFirst(" / "));
133cfe6baf6SAxel Dörfler output.Remove(0, 3);
134cfe6baf6SAxel Dörfler
135cfe6baf6SAxel Dörfler output.MoveInto(responseData->title, 0, output.FindFirst("\r\n"));
136cfe6baf6SAxel Dörfler output.Remove(0, 2);
137cfe6baf6SAxel Dörfler
138768544f6SAxel Dörfler queryResponses.AddItem(responseData);
139cfe6baf6SAxel Dörfler
140cfe6baf6SAxel Dörfler if (output == "" || output == ".\r\n") {
141cfe6baf6SAxel Dörfler // All returned data was processed exit the loop.
142cfe6baf6SAxel Dörfler done = true;
143cfe6baf6SAxel Dörfler }
144cfe6baf6SAxel Dörfler }
145cfe6baf6SAxel Dörfler } else {
146cfe6baf6SAxel Dörfler printf("Error sending CDDB command : \"%s\".\n", cddbCommand.String());
147cfe6baf6SAxel Dörfler }
148cfe6baf6SAxel Dörfler
149cfe6baf6SAxel Dörfler _CloseConnection();
150cfe6baf6SAxel Dörfler return result;
151cfe6baf6SAxel Dörfler }
152cfe6baf6SAxel Dörfler
153cfe6baf6SAxel Dörfler
154cfe6baf6SAxel Dörfler status_t
Read(const QueryResponseData & diskData,ReadResponseData & readResponse,bool verbose)155768544f6SAxel Dörfler CDDBServer::Read(const QueryResponseData& diskData,
1563008268cSAxel Dörfler ReadResponseData& readResponse, bool verbose)
157cfe6baf6SAxel Dörfler {
158df53a4bfSAxel Dörfler return Read(diskData.category, diskData.cddbID, diskData.artist,
1593008268cSAxel Dörfler readResponse, verbose);
160df53a4bfSAxel Dörfler }
161df53a4bfSAxel Dörfler
162df53a4bfSAxel Dörfler
163df53a4bfSAxel Dörfler status_t
Read(const BString & category,const BString & cddbID,const BString & artist,ReadResponseData & readResponse,bool verbose)164df53a4bfSAxel Dörfler CDDBServer::Read(const BString& category, const BString& cddbID,
1653008268cSAxel Dörfler const BString& artist, ReadResponseData& readResponse, bool verbose)
166df53a4bfSAxel Dörfler {
167cfe6baf6SAxel Dörfler if (_OpenConnection() != B_OK)
168cfe6baf6SAxel Dörfler return B_ERROR;
169cfe6baf6SAxel Dörfler
170cfe6baf6SAxel Dörfler // Assemble the Read command.
171cfe6baf6SAxel Dörfler BString cddbCommand("cddb read ");
172df53a4bfSAxel Dörfler cddbCommand << category << " " << cddbID;
173cfe6baf6SAxel Dörfler
174cfe6baf6SAxel Dörfler BString output;
175768544f6SAxel Dörfler status_t result = _SendCommand(cddbCommand, output);
176cfe6baf6SAxel Dörfler if (result == B_OK) {
1773008268cSAxel Dörfler if (verbose)
1783008268cSAxel Dörfler puts(output);
1793008268cSAxel Dörfler
180cfe6baf6SAxel Dörfler // Remove the header from the reply.
181cfe6baf6SAxel Dörfler output.Remove(0, output.FindFirst("\r\n\r\n") + 4);
182cfe6baf6SAxel Dörfler
183cfe6baf6SAxel Dörfler // Check status code.
184cfe6baf6SAxel Dörfler BString statusCode;
185cfe6baf6SAxel Dörfler output.MoveInto(statusCode, 0, 3);
186cfe6baf6SAxel Dörfler if (statusCode == "210") {
187cfe6baf6SAxel Dörfler // Remove first line and parse the others.
188cfe6baf6SAxel Dörfler output.Remove(0, output.FindFirst("\r\n") + 2);
189cfe6baf6SAxel Dörfler } else {
190cfe6baf6SAxel Dörfler // Something bad happened.
191cfe6baf6SAxel Dörfler return B_ERROR;
192cfe6baf6SAxel Dörfler }
193cfe6baf6SAxel Dörfler
194cfe6baf6SAxel Dörfler // Process all entries.
195cfe6baf6SAxel Dörfler bool done = false;
196cfe6baf6SAxel Dörfler while (!done) {
197cfe6baf6SAxel Dörfler if (output[0] == '#') {
198cfe6baf6SAxel Dörfler // Comment. Remove it.
199cfe6baf6SAxel Dörfler output.Remove(0, output.FindFirst("\r\n") + 2);
200cfe6baf6SAxel Dörfler continue;
201cfe6baf6SAxel Dörfler }
202cfe6baf6SAxel Dörfler
203cfe6baf6SAxel Dörfler // Extract one line to reduce the scope of processing to it.
204cfe6baf6SAxel Dörfler BString line;
205cfe6baf6SAxel Dörfler output.MoveInto(line, 0, output.FindFirst("\r\n"));
206cfe6baf6SAxel Dörfler output.Remove(0, 2);
207cfe6baf6SAxel Dörfler
208cfe6baf6SAxel Dörfler // Obtain prefix.
209cfe6baf6SAxel Dörfler BString prefix;
210cfe6baf6SAxel Dörfler line.MoveInto(prefix, 0, line.FindFirst("="));
211cfe6baf6SAxel Dörfler line.Remove(0, 1);
212cfe6baf6SAxel Dörfler
213cfe6baf6SAxel Dörfler if (prefix == "DTITLE") {
214cfe6baf6SAxel Dörfler // Disk title.
215cfe6baf6SAxel Dörfler BString artist;
216cfe6baf6SAxel Dörfler line.MoveInto(artist, 0, line.FindFirst(" / "));
217cfe6baf6SAxel Dörfler line.Remove(0, 3);
218768544f6SAxel Dörfler readResponse.title = line;
219768544f6SAxel Dörfler readResponse.artist = artist;
220cfe6baf6SAxel Dörfler } else if (prefix == "DYEAR") {
221cfe6baf6SAxel Dörfler // Disk year.
222cfe6baf6SAxel Dörfler char* firstInvalid;
223cfe6baf6SAxel Dörfler errno = 0;
224cfe6baf6SAxel Dörfler uint32 year = strtoul(line.String(), &firstInvalid, 10);
225cfe6baf6SAxel Dörfler if ((errno == ERANGE &&
226cfe6baf6SAxel Dörfler (year == (uint32)LONG_MAX || year == (uint32)LONG_MIN))
227cfe6baf6SAxel Dörfler || (errno != 0 && year == 0)) {
228cfe6baf6SAxel Dörfler // Year out of range.
229cfe6baf6SAxel Dörfler printf("Year out of range: %s\n", line.String());
230cfe6baf6SAxel Dörfler year = 0;
231cfe6baf6SAxel Dörfler }
232cfe6baf6SAxel Dörfler
233cfe6baf6SAxel Dörfler if (firstInvalid == line.String()) {
234cfe6baf6SAxel Dörfler printf("Invalid year: %s\n", line.String());
235cfe6baf6SAxel Dörfler year = 0;
236cfe6baf6SAxel Dörfler }
237cfe6baf6SAxel Dörfler
238768544f6SAxel Dörfler readResponse.year = year;
239cfe6baf6SAxel Dörfler } else if (prefix == "DGENRE") {
240cfe6baf6SAxel Dörfler // Disk genre.
241768544f6SAxel Dörfler readResponse.genre = line;
242cfe6baf6SAxel Dörfler } else if (prefix.FindFirst("TTITLE") == 0) {
243cfe6baf6SAxel Dörfler // Track title.
244cfe6baf6SAxel Dörfler BString index;
245cfe6baf6SAxel Dörfler prefix.MoveInto(index, 6, prefix.Length() - 6);
246cfe6baf6SAxel Dörfler
247cfe6baf6SAxel Dörfler char* firstInvalid;
248cfe6baf6SAxel Dörfler errno = 0;
249cfe6baf6SAxel Dörfler uint32 track = strtoul(index.String(), &firstInvalid, 10);
2507dc0c7b5SAxel Dörfler if (errno != 0 || track > 99) {
251cfe6baf6SAxel Dörfler // Track out of range.
252cfe6baf6SAxel Dörfler printf("Track out of range: %s\n", index.String());
253cfe6baf6SAxel Dörfler return B_ERROR;
254cfe6baf6SAxel Dörfler }
255cfe6baf6SAxel Dörfler
256cfe6baf6SAxel Dörfler if (firstInvalid == index.String()) {
257cfe6baf6SAxel Dörfler printf("Invalid track: %s\n", index.String());
258cfe6baf6SAxel Dörfler return B_ERROR;
259cfe6baf6SAxel Dörfler }
260cfe6baf6SAxel Dörfler
2617dc0c7b5SAxel Dörfler BString trackArtist;
262cfe6baf6SAxel Dörfler int32 pos = line.FindFirst(" / ");
263df53a4bfSAxel Dörfler if (pos >= 0 && artist.ICompare("Various") == 0) {
264cfe6baf6SAxel Dörfler // Disk is set to have a compilation artist and
265cfe6baf6SAxel Dörfler // we have track specific artist information.
2667dc0c7b5SAxel Dörfler line.MoveInto(trackArtist, 0, pos);
267cfe6baf6SAxel Dörfler // Move artist information from line to artist.
268cfe6baf6SAxel Dörfler line.Remove(0, 3);
269cfe6baf6SAxel Dörfler // Remove " / " from line.
270cfe6baf6SAxel Dörfler } else {
2717dc0c7b5SAxel Dörfler trackArtist = artist;
272cfe6baf6SAxel Dörfler }
273cfe6baf6SAxel Dörfler
2747dc0c7b5SAxel Dörfler TrackData* trackData = _Track(readResponse, track);
2757dc0c7b5SAxel Dörfler trackData->artist += trackArtist;
2767dc0c7b5SAxel Dörfler trackData->title += line;
277cfe6baf6SAxel Dörfler }
278cfe6baf6SAxel Dörfler
279cfe6baf6SAxel Dörfler if (output == "" || output == ".\r\n") {
280cfe6baf6SAxel Dörfler // All returned data was processed exit the loop.
281cfe6baf6SAxel Dörfler done = true;
282cfe6baf6SAxel Dörfler }
283cfe6baf6SAxel Dörfler }
284cfe6baf6SAxel Dörfler } else {
285cfe6baf6SAxel Dörfler printf("Error sending CDDB command : \"%s\".\n", cddbCommand.String());
286cfe6baf6SAxel Dörfler }
287cfe6baf6SAxel Dörfler
288cfe6baf6SAxel Dörfler _CloseConnection();
289cfe6baf6SAxel Dörfler return B_OK;
290cfe6baf6SAxel Dörfler }
291cfe6baf6SAxel Dörfler
292cfe6baf6SAxel Dörfler
293cfe6baf6SAxel Dörfler status_t
_ParseAddress(const BString & cddbServer)294cfe6baf6SAxel Dörfler CDDBServer::_ParseAddress(const BString& cddbServer)
295cfe6baf6SAxel Dörfler {
296cfe6baf6SAxel Dörfler // Set up server address.
297cfe6baf6SAxel Dörfler int32 pos = cddbServer.FindFirst(":");
298cfe6baf6SAxel Dörfler if (pos == B_ERROR) {
299cfe6baf6SAxel Dörfler // It seems we do not have the address:port format. Use hostname as-is.
300768544f6SAxel Dörfler fServerAddress.SetTo(cddbServer.String(), kDefaultPortNumber);
301768544f6SAxel Dörfler if (fServerAddress.InitCheck() == B_OK)
302cfe6baf6SAxel Dörfler return B_OK;
303cfe6baf6SAxel Dörfler } else {
304cfe6baf6SAxel Dörfler // Parse address:port format.
305cfe6baf6SAxel Dörfler int32 port;
306cfe6baf6SAxel Dörfler BString newCddbServer(cddbServer);
307cfe6baf6SAxel Dörfler BString portString;
308cfe6baf6SAxel Dörfler newCddbServer.MoveInto(portString, pos + 1,
309cfe6baf6SAxel Dörfler newCddbServer.CountChars() - pos + 1);
310cfe6baf6SAxel Dörfler if (portString.CountChars() > 0) {
311cfe6baf6SAxel Dörfler char* firstInvalid;
312cfe6baf6SAxel Dörfler errno = 0;
313cfe6baf6SAxel Dörfler port = strtol(portString.String(), &firstInvalid, 10);
314fc1d8972SMurai Takashi if ((errno == ERANGE && (port == INT32_MAX || port == INT32_MIN))
315cfe6baf6SAxel Dörfler || (errno != 0 && port == 0)) {
316cfe6baf6SAxel Dörfler return B_ERROR;
317cfe6baf6SAxel Dörfler }
318cfe6baf6SAxel Dörfler if (firstInvalid == portString.String()) {
319cfe6baf6SAxel Dörfler return B_ERROR;
320cfe6baf6SAxel Dörfler }
321cfe6baf6SAxel Dörfler
322cfe6baf6SAxel Dörfler newCddbServer.RemoveAll(":");
323768544f6SAxel Dörfler fServerAddress.SetTo(newCddbServer.String(), port);
324768544f6SAxel Dörfler if (fServerAddress.InitCheck() == B_OK)
325cfe6baf6SAxel Dörfler return B_OK;
326cfe6baf6SAxel Dörfler }
327cfe6baf6SAxel Dörfler }
328cfe6baf6SAxel Dörfler
329cfe6baf6SAxel Dörfler return B_ERROR;
330cfe6baf6SAxel Dörfler }
331cfe6baf6SAxel Dörfler
332cfe6baf6SAxel Dörfler
333cfe6baf6SAxel Dörfler status_t
_OpenConnection()334cfe6baf6SAxel Dörfler CDDBServer::_OpenConnection()
335cfe6baf6SAxel Dörfler {
336cfe6baf6SAxel Dörfler if (!fInitialized)
337cfe6baf6SAxel Dörfler return B_ERROR;
338cfe6baf6SAxel Dörfler
339cfe6baf6SAxel Dörfler if (fConnected)
340cfe6baf6SAxel Dörfler return B_OK;
341cfe6baf6SAxel Dörfler
342768544f6SAxel Dörfler if (fConnection.Connect(fServerAddress) == B_OK) {
343cfe6baf6SAxel Dörfler fConnected = true;
344cfe6baf6SAxel Dörfler return B_OK;
345cfe6baf6SAxel Dörfler }
346cfe6baf6SAxel Dörfler
347cfe6baf6SAxel Dörfler return B_ERROR;
348cfe6baf6SAxel Dörfler }
349cfe6baf6SAxel Dörfler
350cfe6baf6SAxel Dörfler
351cfe6baf6SAxel Dörfler void
_CloseConnection()352cfe6baf6SAxel Dörfler CDDBServer::_CloseConnection()
353cfe6baf6SAxel Dörfler {
354cfe6baf6SAxel Dörfler if (!fConnected)
355cfe6baf6SAxel Dörfler return;
356cfe6baf6SAxel Dörfler
357cfe6baf6SAxel Dörfler fConnection.Close();
358cfe6baf6SAxel Dörfler fConnected = false;
359cfe6baf6SAxel Dörfler }
360cfe6baf6SAxel Dörfler
361cfe6baf6SAxel Dörfler
362cfe6baf6SAxel Dörfler status_t
_SendCommand(const BString & command,BString & output)363768544f6SAxel Dörfler CDDBServer::_SendCommand(const BString& command, BString& output)
364cfe6baf6SAxel Dörfler {
365cfe6baf6SAxel Dörfler if (!fConnected)
366cfe6baf6SAxel Dörfler return B_ERROR;
367cfe6baf6SAxel Dörfler
368cfe6baf6SAxel Dörfler // Assemble full command string.
369cfe6baf6SAxel Dörfler BString fullCommand;
370cfe6baf6SAxel Dörfler fullCommand << command << "&hello=" << fLocalUserName << " " <<
371cfe6baf6SAxel Dörfler fLocalHostName << " cddb_lookup 1.0&proto=6";
372cfe6baf6SAxel Dörfler
373cfe6baf6SAxel Dörfler // Replace spaces by + signs.
374cfe6baf6SAxel Dörfler fullCommand.ReplaceAll(" ", "+");
375cfe6baf6SAxel Dörfler
376cfe6baf6SAxel Dörfler // And now add command header and footer.
377cfe6baf6SAxel Dörfler fullCommand.Prepend("GET /~cddb/cddb.cgi?cmd=");
378*0071f2c4SMurai Takashi fullCommand << " HTTP/1.0\n\n";
379cfe6baf6SAxel Dörfler
380cfe6baf6SAxel Dörfler int32 result = fConnection.Send((void*)fullCommand.String(),
381cfe6baf6SAxel Dörfler fullCommand.Length());
382cfe6baf6SAxel Dörfler if (result == fullCommand.Length()) {
383cfe6baf6SAxel Dörfler BNetBuffer netBuffer;
384cfe6baf6SAxel Dörfler while (fConnection.Receive(netBuffer, 1024) != 0) {
385cfe6baf6SAxel Dörfler // Do nothing. Data is automatically appended to the NetBuffer.
386cfe6baf6SAxel Dörfler }
387cfe6baf6SAxel Dörfler
388cfe6baf6SAxel Dörfler // AppendString automatically adds the terminating \0.
389cfe6baf6SAxel Dörfler netBuffer.AppendString("");
390cfe6baf6SAxel Dörfler
391768544f6SAxel Dörfler output.SetTo((char*)netBuffer.Data(), netBuffer.Size());
392cfe6baf6SAxel Dörfler return B_OK;
393cfe6baf6SAxel Dörfler }
394cfe6baf6SAxel Dörfler
395cfe6baf6SAxel Dörfler return B_ERROR;
396cfe6baf6SAxel Dörfler }
3977dc0c7b5SAxel Dörfler
3987dc0c7b5SAxel Dörfler
3997dc0c7b5SAxel Dörfler TrackData*
_Track(ReadResponseData & response,uint32 track) const4007dc0c7b5SAxel Dörfler CDDBServer::_Track(ReadResponseData& response, uint32 track) const
4017dc0c7b5SAxel Dörfler {
4027dc0c7b5SAxel Dörfler for (int32 i = 0; i < response.tracks.CountItems(); i++) {
4037dc0c7b5SAxel Dörfler TrackData* trackData = response.tracks.ItemAt(i);
4047dc0c7b5SAxel Dörfler if (trackData->trackNumber == track)
4057dc0c7b5SAxel Dörfler return trackData;
4067dc0c7b5SAxel Dörfler }
4077dc0c7b5SAxel Dörfler
4087dc0c7b5SAxel Dörfler TrackData* trackData = new TrackData();
4097dc0c7b5SAxel Dörfler trackData->trackNumber = track;
4107dc0c7b5SAxel Dörfler response.tracks.AddItem(trackData);
4117dc0c7b5SAxel Dörfler
4127dc0c7b5SAxel Dörfler return trackData;
4137dc0c7b5SAxel Dörfler }
414