xref: /haiku/src/bin/cddb_lookup/cddb_server.cpp (revision 0071f2c47796091551aa3f0bcd09f6443e7fc5f3)
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