xref: /haiku/src/bin/cddb_lookup/cddb_server.cpp (revision fc1d8972ac6bc0c8e9b1a856974aa2910121c6bc)
1cfe6baf6SAxel Dörfler /*
2cfe6baf6SAxel Dörfler  * Copyright 2008-2015, 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 
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 
31cfe6baf6SAxel Dörfler 	// Set up local host name.
32cfe6baf6SAxel Dörfler 	char localHostName[MAXHOSTNAMELEN + 1];
33cfe6baf6SAxel Dörfler 	if (gethostname(localHostName,  MAXHOSTNAMELEN + 1) == 0) {
34cfe6baf6SAxel Dörfler 		fLocalHostName = localHostName;
35cfe6baf6SAxel Dörfler 	} else {
36cfe6baf6SAxel Dörfler 		fLocalHostName = kDefaultLocalHostName;
37cfe6baf6SAxel Dörfler 	}
38cfe6baf6SAxel Dörfler 
39cfe6baf6SAxel Dörfler 	// Set up local user name.
40cfe6baf6SAxel Dörfler 	char* user = getenv("USER");
41cfe6baf6SAxel Dörfler 	if (user == NULL) {
42cfe6baf6SAxel Dörfler 		fLocalUserName = "unknown";
43cfe6baf6SAxel Dörfler 	} else {
44cfe6baf6SAxel Dörfler 		fLocalUserName = user;
45cfe6baf6SAxel Dörfler 	}
46cfe6baf6SAxel Dörfler 
47cfe6baf6SAxel Dörfler 	// Set up server address;
48cfe6baf6SAxel Dörfler 	if (_ParseAddress(cddbServer) == B_OK)
49cfe6baf6SAxel Dörfler 		fInitialized = true;
50cfe6baf6SAxel Dörfler }
51cfe6baf6SAxel Dörfler 
52cfe6baf6SAxel Dörfler 
53cfe6baf6SAxel Dörfler status_t
54cfe6baf6SAxel Dörfler CDDBServer::Query(uint32 cddbId, const scsi_toc_toc* toc, BList* queryResponse)
55cfe6baf6SAxel Dörfler {
56cfe6baf6SAxel Dörfler 	if (_OpenConnection() != B_OK)
57cfe6baf6SAxel Dörfler 		return B_ERROR;
58cfe6baf6SAxel Dörfler 
59cfe6baf6SAxel Dörfler 	// Convert CDDB id to hexadecimal format.
60cfe6baf6SAxel Dörfler 	char hexCddbId[9];
61cfe6baf6SAxel Dörfler 	sprintf(hexCddbId, "%08" B_PRIx32 "", cddbId);
62cfe6baf6SAxel Dörfler 
63cfe6baf6SAxel Dörfler 	// Assemble the Query command.
64cfe6baf6SAxel Dörfler 	int32 numTracks = toc->last_track + 1 - toc->first_track;
65cfe6baf6SAxel Dörfler 
66cfe6baf6SAxel Dörfler 	BString cddbCommand("cddb query ");
67cfe6baf6SAxel Dörfler 	cddbCommand << hexCddbId << " " << numTracks << " ";
68cfe6baf6SAxel Dörfler 
69cfe6baf6SAxel Dörfler 	// Add track offsets in frames.
70cfe6baf6SAxel Dörfler 	for (int32 i = 0; i < numTracks; ++i) {
71cfe6baf6SAxel Dörfler 		const scsi_cd_msf& start = toc->tracks[i].start.time;
72cfe6baf6SAxel Dörfler 
73cfe6baf6SAxel Dörfler 		uint32 startFrameOffset = start.minute * kFramesPerMinute +
74cfe6baf6SAxel Dörfler 			start.second * kFramesPerSecond + start.frame;
75cfe6baf6SAxel Dörfler 
76cfe6baf6SAxel Dörfler 		cddbCommand << startFrameOffset << " ";
77cfe6baf6SAxel Dörfler 	}
78cfe6baf6SAxel Dörfler 
79cfe6baf6SAxel Dörfler 	// Add total disc time in seconds. Last track is lead-out.
80cfe6baf6SAxel Dörfler 	const scsi_cd_msf& lastTrack = toc->tracks[numTracks].start.time;
81cfe6baf6SAxel Dörfler 	uint32 totalTimeInSeconds = lastTrack.minute * 60 + lastTrack.second;
82cfe6baf6SAxel Dörfler 	cddbCommand << totalTimeInSeconds;
83cfe6baf6SAxel Dörfler 
84cfe6baf6SAxel Dörfler 	BString output;
85cfe6baf6SAxel Dörfler 	status_t result;
86cfe6baf6SAxel Dörfler 	result = _SendCddbCommand(cddbCommand, &output);
87cfe6baf6SAxel Dörfler 
88cfe6baf6SAxel Dörfler 	if (result == B_OK) {
89cfe6baf6SAxel Dörfler 		// Remove the header from the reply.
90cfe6baf6SAxel Dörfler 		output.Remove(0, output.FindFirst("\r\n\r\n") + 4);
91cfe6baf6SAxel Dörfler 
92cfe6baf6SAxel Dörfler 		// Check status code.
93cfe6baf6SAxel Dörfler 		BString statusCode;
94cfe6baf6SAxel Dörfler 		output.MoveInto(statusCode, 0, 3);
95cfe6baf6SAxel Dörfler 		if (statusCode == "210" || statusCode == "211") {
96cfe6baf6SAxel Dörfler 			// TODO(bga): We can get around with returning the first result
97cfe6baf6SAxel Dörfler 			// in case of multiple matches, but we most definitely need a
98cfe6baf6SAxel Dörfler 			// better handling of inexact matches.
99cfe6baf6SAxel Dörfler 			if (statusCode == "211")
100cfe6baf6SAxel Dörfler 				printf("Warning : Inexact match found.\n");
101cfe6baf6SAxel Dörfler 
102cfe6baf6SAxel Dörfler 			// Multiple results, remove the first line and parse the others.
103cfe6baf6SAxel Dörfler 			output.Remove(0, output.FindFirst("\r\n") + 2);
104cfe6baf6SAxel Dörfler 		} else if (statusCode == "200") {
105cfe6baf6SAxel Dörfler 			// Remove the first char which is a left over space.
106cfe6baf6SAxel Dörfler 			output.Remove(0, 1);
107cfe6baf6SAxel Dörfler 		} else if (statusCode == "202") {
108cfe6baf6SAxel Dörfler 			// No match found.
109cfe6baf6SAxel Dörfler 			printf("Error : CDDB entry for id %s not found.\n", hexCddbId);
110cfe6baf6SAxel Dörfler 
111cfe6baf6SAxel Dörfler 			return B_ENTRY_NOT_FOUND;
112cfe6baf6SAxel Dörfler 		} else {
113cfe6baf6SAxel Dörfler 			// Something bad happened.
114cfe6baf6SAxel Dörfler 			if (statusCode.Trim() != "") {
115cfe6baf6SAxel Dörfler 				printf("Error : CDDB server status code is %s.\n",
116cfe6baf6SAxel Dörfler 					statusCode.String());
117cfe6baf6SAxel Dörfler 			} else {
118cfe6baf6SAxel Dörfler 				printf("Error : Could not find any status code.\n");
119cfe6baf6SAxel Dörfler 			}
120cfe6baf6SAxel Dörfler 
121cfe6baf6SAxel Dörfler 			return B_ERROR;
122cfe6baf6SAxel Dörfler 		}
123cfe6baf6SAxel Dörfler 
124cfe6baf6SAxel Dörfler 		// Process all entries.
125cfe6baf6SAxel Dörfler 		bool done = false;
126cfe6baf6SAxel Dörfler 		while (!done) {
127cfe6baf6SAxel Dörfler 			QueryResponseData* responseData = new QueryResponseData;
128cfe6baf6SAxel Dörfler 
129cfe6baf6SAxel Dörfler 			output.MoveInto(responseData->category, 0, output.FindFirst(" "));
130cfe6baf6SAxel Dörfler 			output.Remove(0, 1);
131cfe6baf6SAxel Dörfler 
132cfe6baf6SAxel Dörfler 			output.MoveInto(responseData->cddbId, 0, output.FindFirst(" "));
133cfe6baf6SAxel Dörfler 			output.Remove(0, 1);
134cfe6baf6SAxel Dörfler 
135cfe6baf6SAxel Dörfler 			output.MoveInto(responseData->artist, 0, output.FindFirst(" / "));
136cfe6baf6SAxel Dörfler 			output.Remove(0, 3);
137cfe6baf6SAxel Dörfler 
138cfe6baf6SAxel Dörfler 			output.MoveInto(responseData->title, 0, output.FindFirst("\r\n"));
139cfe6baf6SAxel Dörfler 			output.Remove(0, 2);
140cfe6baf6SAxel Dörfler 
141cfe6baf6SAxel Dörfler 			queryResponse->AddItem(responseData);
142cfe6baf6SAxel Dörfler 
143cfe6baf6SAxel Dörfler 			if (output == "" || output == ".\r\n") {
144cfe6baf6SAxel Dörfler 				// All returned data was processed exit the loop.
145cfe6baf6SAxel Dörfler 				done = true;
146cfe6baf6SAxel Dörfler 			}
147cfe6baf6SAxel Dörfler 		}
148cfe6baf6SAxel Dörfler 	} else {
149cfe6baf6SAxel Dörfler 		printf("Error sending CDDB command : \"%s\".\n", cddbCommand.String());
150cfe6baf6SAxel Dörfler 	}
151cfe6baf6SAxel Dörfler 
152cfe6baf6SAxel Dörfler 	_CloseConnection();
153cfe6baf6SAxel Dörfler 	return result;
154cfe6baf6SAxel Dörfler }
155cfe6baf6SAxel Dörfler 
156cfe6baf6SAxel Dörfler 
157cfe6baf6SAxel Dörfler status_t
158cfe6baf6SAxel Dörfler CDDBServer::Read(QueryResponseData* diskData, ReadResponseData* readResponse)
159cfe6baf6SAxel Dörfler {
160cfe6baf6SAxel Dörfler 	if (_OpenConnection() != B_OK)
161cfe6baf6SAxel Dörfler 		return B_ERROR;
162cfe6baf6SAxel Dörfler 
163cfe6baf6SAxel Dörfler 	// Assemble the Read command.
164cfe6baf6SAxel Dörfler 	BString cddbCommand("cddb read ");
165cfe6baf6SAxel Dörfler 	cddbCommand << diskData->category << " " << diskData->cddbId;
166cfe6baf6SAxel Dörfler 
167cfe6baf6SAxel Dörfler 	BString output;
168cfe6baf6SAxel Dörfler 	status_t result;
169cfe6baf6SAxel Dörfler 	result = _SendCddbCommand(cddbCommand, &output);
170cfe6baf6SAxel Dörfler 
171cfe6baf6SAxel Dörfler 	if (result == B_OK) {
172cfe6baf6SAxel Dörfler 		// Remove the header from the reply.
173cfe6baf6SAxel Dörfler 		output.Remove(0, output.FindFirst("\r\n\r\n") + 4);
174cfe6baf6SAxel Dörfler 
175cfe6baf6SAxel Dörfler 		// Check status code.
176cfe6baf6SAxel Dörfler 		BString statusCode;
177cfe6baf6SAxel Dörfler 		output.MoveInto(statusCode, 0, 3);
178cfe6baf6SAxel Dörfler 		if (statusCode == "210") {
179cfe6baf6SAxel Dörfler 			// Remove first line and parse the others.
180cfe6baf6SAxel Dörfler 			output.Remove(0, output.FindFirst("\r\n") + 2);
181cfe6baf6SAxel Dörfler 		} else {
182cfe6baf6SAxel Dörfler 			// Something bad happened.
183cfe6baf6SAxel Dörfler 			return B_ERROR;
184cfe6baf6SAxel Dörfler 		}
185cfe6baf6SAxel Dörfler 
186cfe6baf6SAxel Dörfler 		// Process all entries.
187cfe6baf6SAxel Dörfler 		bool done = false;
188cfe6baf6SAxel Dörfler 		while (!done) {
189cfe6baf6SAxel Dörfler 			if (output[0] == '#') {
190cfe6baf6SAxel Dörfler 				// Comment. Remove it.
191cfe6baf6SAxel Dörfler 				output.Remove(0, output.FindFirst("\r\n") + 2);
192cfe6baf6SAxel Dörfler 				continue;
193cfe6baf6SAxel Dörfler 			}
194cfe6baf6SAxel Dörfler 
195cfe6baf6SAxel Dörfler 			// Extract one line to reduce the scope of processing to it.
196cfe6baf6SAxel Dörfler 			BString line;
197cfe6baf6SAxel Dörfler 			output.MoveInto(line, 0, output.FindFirst("\r\n"));
198cfe6baf6SAxel Dörfler 			output.Remove(0, 2);
199cfe6baf6SAxel Dörfler 
200cfe6baf6SAxel Dörfler 			// Obtain prefix.
201cfe6baf6SAxel Dörfler 			BString prefix;
202cfe6baf6SAxel Dörfler 			line.MoveInto(prefix, 0, line.FindFirst("="));
203cfe6baf6SAxel Dörfler 			line.Remove(0, 1);
204cfe6baf6SAxel Dörfler 
205cfe6baf6SAxel Dörfler 			if (prefix == "DTITLE") {
206cfe6baf6SAxel Dörfler 				// Disk title.
207cfe6baf6SAxel Dörfler 				BString artist;
208cfe6baf6SAxel Dörfler 				line.MoveInto(artist, 0, line.FindFirst(" / "));
209cfe6baf6SAxel Dörfler 				line.Remove(0, 3);
210cfe6baf6SAxel Dörfler 				readResponse->title = line;
211cfe6baf6SAxel Dörfler 				readResponse->artist = artist;
212cfe6baf6SAxel Dörfler 			} else if (prefix == "DYEAR") {
213cfe6baf6SAxel Dörfler 				// Disk year.
214cfe6baf6SAxel Dörfler 				char* firstInvalid;
215cfe6baf6SAxel Dörfler 				errno = 0;
216cfe6baf6SAxel Dörfler 				uint32 year = strtoul(line.String(), &firstInvalid, 10);
217cfe6baf6SAxel Dörfler 				if ((errno == ERANGE &&
218cfe6baf6SAxel Dörfler 					(year == (uint32)LONG_MAX || year == (uint32)LONG_MIN))
219cfe6baf6SAxel Dörfler 					|| (errno != 0 && year == 0)) {
220cfe6baf6SAxel Dörfler 					// Year out of range.
221cfe6baf6SAxel Dörfler 					printf("Year out of range: %s\n", line.String());
222cfe6baf6SAxel Dörfler 					year = 0;
223cfe6baf6SAxel Dörfler 				}
224cfe6baf6SAxel Dörfler 
225cfe6baf6SAxel Dörfler 				if (firstInvalid == line.String()) {
226cfe6baf6SAxel Dörfler 					printf("Invalid year: %s\n", line.String());
227cfe6baf6SAxel Dörfler 					year = 0;
228cfe6baf6SAxel Dörfler 				}
229cfe6baf6SAxel Dörfler 
230cfe6baf6SAxel Dörfler 				readResponse->year = year;
231cfe6baf6SAxel Dörfler 			} else if (prefix == "DGENRE") {
232cfe6baf6SAxel Dörfler 				// Disk genre.
233cfe6baf6SAxel Dörfler 				readResponse->genre = line;
234cfe6baf6SAxel Dörfler 			} else if (prefix.FindFirst("TTITLE") == 0) {
235cfe6baf6SAxel Dörfler 				// Track title.
236cfe6baf6SAxel Dörfler 				BString index;
237cfe6baf6SAxel Dörfler 				prefix.MoveInto(index, 6, prefix.Length() - 6);
238cfe6baf6SAxel Dörfler 
239cfe6baf6SAxel Dörfler 				TrackData* trackData = new TrackData;
240cfe6baf6SAxel Dörfler 
241cfe6baf6SAxel Dörfler 				char* firstInvalid;
242cfe6baf6SAxel Dörfler 				errno = 0;
243cfe6baf6SAxel Dörfler 				uint32 track = strtoul(index.String(), &firstInvalid, 10);
244cfe6baf6SAxel Dörfler 				if ((errno == ERANGE &&
245cfe6baf6SAxel Dörfler 					(track == (uint32)LONG_MAX || track == (uint32)LONG_MIN))
246cfe6baf6SAxel Dörfler 					|| (errno != 0 && track == 0)) {
247cfe6baf6SAxel Dörfler 					// Track out of range.
248cfe6baf6SAxel Dörfler 					printf("Track out of range: %s\n", index.String());
249cfe6baf6SAxel Dörfler 					delete trackData;
250cfe6baf6SAxel Dörfler 					return B_ERROR;
251cfe6baf6SAxel Dörfler 				}
252cfe6baf6SAxel Dörfler 
253cfe6baf6SAxel Dörfler 				if (firstInvalid == index.String()) {
254cfe6baf6SAxel Dörfler 					printf("Invalid track: %s\n", index.String());
255cfe6baf6SAxel Dörfler 					delete trackData;
256cfe6baf6SAxel Dörfler 					return B_ERROR;
257cfe6baf6SAxel Dörfler 				}
258cfe6baf6SAxel Dörfler 
259cfe6baf6SAxel Dörfler 				trackData->trackNumber = track;
260cfe6baf6SAxel Dörfler 
261cfe6baf6SAxel Dörfler 				int32 pos = line.FindFirst(" / " );
262cfe6baf6SAxel Dörfler 				if (pos != B_ERROR && diskData->artist.ICompare("Various") == 0) {
263cfe6baf6SAxel Dörfler 					// Disk is set to have a compilation artist and
264cfe6baf6SAxel Dörfler 					// we have track specific artist information.
265cfe6baf6SAxel Dörfler 					BString artist;
266cfe6baf6SAxel Dörfler 					line.MoveInto(artist, 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 					trackData->artist = artist;
271cfe6baf6SAxel Dörfler 				} else {
272cfe6baf6SAxel Dörfler 					trackData->artist = diskData->artist;
273cfe6baf6SAxel Dörfler 				}
274cfe6baf6SAxel Dörfler 
275cfe6baf6SAxel Dörfler 				trackData->title = line;
276cfe6baf6SAxel Dörfler 
277cfe6baf6SAxel Dörfler 				(readResponse->tracks).AddItem(trackData);
278cfe6baf6SAxel Dörfler 			}
279cfe6baf6SAxel Dörfler 
280cfe6baf6SAxel Dörfler 			if (output == "" || output == ".\r\n") {
281cfe6baf6SAxel Dörfler 				// All returned data was processed exit the loop.
282cfe6baf6SAxel Dörfler 				done = true;
283cfe6baf6SAxel Dörfler 			}
284cfe6baf6SAxel Dörfler 		}
285cfe6baf6SAxel Dörfler 	} else {
286cfe6baf6SAxel Dörfler 		printf("Error sending CDDB command : \"%s\".\n", cddbCommand.String());
287cfe6baf6SAxel Dörfler 	}
288cfe6baf6SAxel Dörfler 
289cfe6baf6SAxel Dörfler 	_CloseConnection();
290cfe6baf6SAxel Dörfler 	return B_OK;
291cfe6baf6SAxel Dörfler }
292cfe6baf6SAxel Dörfler 
293cfe6baf6SAxel Dörfler 
294cfe6baf6SAxel Dörfler status_t
295cfe6baf6SAxel Dörfler CDDBServer::_ParseAddress(const BString& cddbServer)
296cfe6baf6SAxel Dörfler {
297cfe6baf6SAxel Dörfler 	// Set up server address.
298cfe6baf6SAxel Dörfler 	int32 pos = cddbServer.FindFirst(":");
299cfe6baf6SAxel Dörfler 	if (pos == B_ERROR) {
300cfe6baf6SAxel Dörfler 		// It seems we do not have the address:port format. Use hostname as-is.
301cfe6baf6SAxel Dörfler 		fCddbServerAddr.SetTo(cddbServer.String(), kDefaultPortNumber);
302cfe6baf6SAxel Dörfler 		if (fCddbServerAddr.InitCheck() == B_OK)
303cfe6baf6SAxel Dörfler 			return B_OK;
304cfe6baf6SAxel Dörfler 	} else {
305cfe6baf6SAxel Dörfler 		// Parse address:port format.
306cfe6baf6SAxel Dörfler 		int32 port;
307cfe6baf6SAxel Dörfler 		BString newCddbServer(cddbServer);
308cfe6baf6SAxel Dörfler 		BString portString;
309cfe6baf6SAxel Dörfler 		newCddbServer.MoveInto(portString, pos + 1,
310cfe6baf6SAxel Dörfler 			newCddbServer.CountChars() - pos + 1);
311cfe6baf6SAxel Dörfler 		if (portString.CountChars() > 0) {
312cfe6baf6SAxel Dörfler 			char* firstInvalid;
313cfe6baf6SAxel Dörfler 			errno = 0;
314cfe6baf6SAxel Dörfler 			port = strtol(portString.String(), &firstInvalid, 10);
315*fc1d8972SMurai Takashi 			if ((errno == ERANGE && (port == INT32_MAX || port == INT32_MIN))
316cfe6baf6SAxel Dörfler 				|| (errno != 0 && port == 0)) {
317cfe6baf6SAxel Dörfler 				return B_ERROR;
318cfe6baf6SAxel Dörfler 			}
319cfe6baf6SAxel Dörfler 			if (firstInvalid == portString.String()) {
320cfe6baf6SAxel Dörfler 				return B_ERROR;
321cfe6baf6SAxel Dörfler 			}
322cfe6baf6SAxel Dörfler 
323cfe6baf6SAxel Dörfler 			newCddbServer.RemoveAll(":");
324cfe6baf6SAxel Dörfler 			fCddbServerAddr.SetTo(newCddbServer.String(), port);
325cfe6baf6SAxel Dörfler 			if (fCddbServerAddr.InitCheck() == B_OK)
326cfe6baf6SAxel Dörfler 				return B_OK;
327cfe6baf6SAxel Dörfler 		}
328cfe6baf6SAxel Dörfler 	}
329cfe6baf6SAxel Dörfler 
330cfe6baf6SAxel Dörfler 	return B_ERROR;
331cfe6baf6SAxel Dörfler }
332cfe6baf6SAxel Dörfler 
333cfe6baf6SAxel Dörfler 
334cfe6baf6SAxel Dörfler status_t
335cfe6baf6SAxel Dörfler CDDBServer::_OpenConnection()
336cfe6baf6SAxel Dörfler {
337cfe6baf6SAxel Dörfler 	if (!fInitialized)
338cfe6baf6SAxel Dörfler 		return B_ERROR;
339cfe6baf6SAxel Dörfler 
340cfe6baf6SAxel Dörfler 	if (fConnected)
341cfe6baf6SAxel Dörfler 		return B_OK;
342cfe6baf6SAxel Dörfler 
343cfe6baf6SAxel Dörfler 	if (fConnection.Connect(fCddbServerAddr) == B_OK) {
344cfe6baf6SAxel Dörfler 		fConnected = true;
345cfe6baf6SAxel Dörfler 		return B_OK;
346cfe6baf6SAxel Dörfler 	}
347cfe6baf6SAxel Dörfler 
348cfe6baf6SAxel Dörfler 	return B_ERROR;
349cfe6baf6SAxel Dörfler }
350cfe6baf6SAxel Dörfler 
351cfe6baf6SAxel Dörfler 
352cfe6baf6SAxel Dörfler void
353cfe6baf6SAxel Dörfler CDDBServer::_CloseConnection()
354cfe6baf6SAxel Dörfler {
355cfe6baf6SAxel Dörfler 	if (!fConnected)
356cfe6baf6SAxel Dörfler 		return;
357cfe6baf6SAxel Dörfler 
358cfe6baf6SAxel Dörfler 	fConnection.Close();
359cfe6baf6SAxel Dörfler 	fConnected = false;
360cfe6baf6SAxel Dörfler }
361cfe6baf6SAxel Dörfler 
362cfe6baf6SAxel Dörfler 
363cfe6baf6SAxel Dörfler status_t
364cfe6baf6SAxel Dörfler CDDBServer::_SendCddbCommand(const BString& command, BString* output)
365cfe6baf6SAxel Dörfler {
366cfe6baf6SAxel Dörfler 	if (!fConnected)
367cfe6baf6SAxel Dörfler 		return B_ERROR;
368cfe6baf6SAxel Dörfler 
369cfe6baf6SAxel Dörfler 	// Assemble full command string.
370cfe6baf6SAxel Dörfler 	BString fullCommand;
371cfe6baf6SAxel Dörfler 	fullCommand << command << "&hello=" << fLocalUserName << " " <<
372cfe6baf6SAxel Dörfler 		fLocalHostName << " cddb_lookup 1.0&proto=6";
373cfe6baf6SAxel Dörfler 
374cfe6baf6SAxel Dörfler 	// Replace spaces by + signs.
375cfe6baf6SAxel Dörfler 	fullCommand.ReplaceAll(" ", "+");
376cfe6baf6SAxel Dörfler 
377cfe6baf6SAxel Dörfler 	// And now add command header and footer.
378cfe6baf6SAxel Dörfler 	fullCommand.Prepend("GET /~cddb/cddb.cgi?cmd=");
379cfe6baf6SAxel Dörfler 	fullCommand << " HTTP 1.0\n\n";
380cfe6baf6SAxel Dörfler 
381cfe6baf6SAxel Dörfler 	int32 result = fConnection.Send((void*)fullCommand.String(),
382cfe6baf6SAxel Dörfler 		fullCommand.Length());
383cfe6baf6SAxel Dörfler 	if (result == fullCommand.Length()) {
384cfe6baf6SAxel Dörfler 		BNetBuffer netBuffer;
385cfe6baf6SAxel Dörfler 		while (fConnection.Receive(netBuffer, 1024) != 0) {
386cfe6baf6SAxel Dörfler 			// Do nothing. Data is automatically appended to the NetBuffer.
387cfe6baf6SAxel Dörfler 		}
388cfe6baf6SAxel Dörfler 
389cfe6baf6SAxel Dörfler 		// AppendString automatically adds the terminating \0.
390cfe6baf6SAxel Dörfler 		netBuffer.AppendString("");
391cfe6baf6SAxel Dörfler 
392cfe6baf6SAxel Dörfler 		output->SetTo((char*)netBuffer.Data(), netBuffer.Size());
393cfe6baf6SAxel Dörfler 		return B_OK;
394cfe6baf6SAxel Dörfler 	}
395cfe6baf6SAxel Dörfler 
396cfe6baf6SAxel Dörfler 	return B_ERROR;
397cfe6baf6SAxel Dörfler }
398