Work in progress. Just commiting so I don't lose this code due to OpenBFS bugs
for the third time. :P - Implement CDDBServer class. - Include relevant CDDB commands. - Initial processing of CDDB data. Change device name. This is close to be complete but I hit some cdda-fs bugs that need to be fixed before I will finish this. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30703 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -4,5 +4,6 @@ UsePrivateHeaders drivers ;
|
|||||||
|
|
||||||
Server cddb_daemon :
|
Server cddb_daemon :
|
||||||
cddb_daemon.cpp
|
cddb_daemon.cpp
|
||||||
: be
|
cddb_server.cpp
|
||||||
|
: be bnetapi
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -8,12 +8,16 @@
|
|||||||
|
|
||||||
#include "cddb_daemon.h"
|
#include "cddb_daemon.h"
|
||||||
|
|
||||||
|
#include "cddb_server.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <Directory.h>
|
#include <Directory.h>
|
||||||
#include <NodeMonitor.h>
|
#include <NodeMonitor.h>
|
||||||
|
#include <Message.h>
|
||||||
#include <Volume.h>
|
#include <Volume.h>
|
||||||
|
#include <VolumeRoster.h>
|
||||||
|
|
||||||
#include <fs_info.h>
|
#include <fs_info.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -31,16 +35,9 @@ CDDBDaemon::CDDBDaemon()
|
|||||||
|
|
||||||
BVolume volume;
|
BVolume volume;
|
||||||
while (fVolumeRoster->GetNextVolume(&volume) == B_OK) {
|
while (fVolumeRoster->GetNextVolume(&volume) == B_OK) {
|
||||||
scsi_toc_toc* toc = (scsi_toc_toc*)malloc(kMaxTocSize);
|
if (_Lookup(volume.Device()) != B_OK) {
|
||||||
if (toc == NULL)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
uint32 cddbId;
|
|
||||||
if (_CanLookup(volume.Device(), &cddbId, toc)) {
|
|
||||||
printf("CD can be looked up. CDDB id = %lu.\n", cddbId);
|
|
||||||
// TODO(bga): Implement and enable CDDB database lookup.
|
|
||||||
}
|
}
|
||||||
free(toc);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,19 +59,8 @@ CDDBDaemon::MessageReceived(BMessage* message)
|
|||||||
if (opcode == B_DEVICE_MOUNTED) {
|
if (opcode == B_DEVICE_MOUNTED) {
|
||||||
dev_t device;
|
dev_t device;
|
||||||
if (message->FindInt32("new device", &device) == B_OK) {
|
if (message->FindInt32("new device", &device) == B_OK) {
|
||||||
scsi_toc_toc* toc =
|
if (_Lookup(device) != B_OK)
|
||||||
(scsi_toc_toc *)malloc(kMaxTocSize);
|
|
||||||
if (toc == NULL)
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
uint32 cddbId;
|
|
||||||
if (_CanLookup(device, &cddbId, toc)) {
|
|
||||||
printf("CD can be looked up. CDDB id = %lu.\n",
|
|
||||||
cddbId);
|
|
||||||
// TODO(bga): Implement and enable CDDB
|
|
||||||
// database lookup.
|
|
||||||
}
|
|
||||||
free(toc);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -85,6 +71,69 @@ CDDBDaemon::MessageReceived(BMessage* message)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
CDDBDaemon::_Lookup(const dev_t device)
|
||||||
|
{
|
||||||
|
scsi_toc_toc* toc = (scsi_toc_toc*)malloc(kMaxTocSize);
|
||||||
|
if (toc == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
uint32 cddbId;
|
||||||
|
if (!_CanLookup(device, &cddbId, toc)) {
|
||||||
|
free(toc);
|
||||||
|
return B_BAD_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("CD can be looked up. CDDB id = %08lx.\n", cddbId);
|
||||||
|
|
||||||
|
CDDBServer cddb_server("freedb.freedb.org:80");
|
||||||
|
|
||||||
|
status_t result;
|
||||||
|
|
||||||
|
BList queryResponse;
|
||||||
|
if ((result = cddb_server.Query(cddbId, toc, &queryResponse)) != B_OK) {
|
||||||
|
free(toc);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(toc);
|
||||||
|
|
||||||
|
QueryResponseData* diskData = _SelectResult(&queryResponse);
|
||||||
|
if (diskData == NULL) {
|
||||||
|
return B_BAD_INDEX;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadResponseData readResponse;
|
||||||
|
if ((result = cddb_server.Read(diskData, &readResponse)) != B_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_WriteCDData(device, diskData, &readResponse) == B_OK) {
|
||||||
|
printf("CD data saved.\n");
|
||||||
|
} else {
|
||||||
|
printf("CD data not saved.\n" );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete itens in the query response BList;
|
||||||
|
int32 count = queryResponse.CountItems();
|
||||||
|
for (int32 i = 0; i < count; ++i) {
|
||||||
|
delete (QueryResponseData*)queryResponse.RemoveItem(0L);
|
||||||
|
}
|
||||||
|
|
||||||
|
queryResponse.MakeEmpty();
|
||||||
|
|
||||||
|
// Delete itens in the track data BList in the read response data;
|
||||||
|
count = readResponse.tracks.CountItems();
|
||||||
|
for (int32 i = 0; i < count; ++i) {
|
||||||
|
delete (TrackData*)readResponse.tracks.RemoveItem(0L);
|
||||||
|
}
|
||||||
|
|
||||||
|
readResponse.tracks.MakeEmpty();
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CDDBDaemon::_CanLookup(const dev_t device, uint32* cddbId,
|
CDDBDaemon::_CanLookup(const dev_t device, uint32* cddbId,
|
||||||
scsi_toc_toc* toc) const
|
scsi_toc_toc* toc) const
|
||||||
@@ -122,6 +171,37 @@ CDDBDaemon::_CanLookup(const dev_t device, uint32* cddbId,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QueryResponseData*
|
||||||
|
CDDBDaemon::_SelectResult(BList* response) const
|
||||||
|
{
|
||||||
|
// Select a single CD match from the response and return it.
|
||||||
|
//
|
||||||
|
// TODO(bga):Right now it just picks the first entry on the list but
|
||||||
|
// someday we may want to let the user choose one.
|
||||||
|
if (response->CountItems() != 0)
|
||||||
|
return (QueryResponseData*)response->ItemAt(0L);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
CDDBDaemon::_WriteCDData(dev_t device, QueryResponseData* diskData,
|
||||||
|
ReadResponseData* readResponse)
|
||||||
|
{
|
||||||
|
// Rename volume.
|
||||||
|
BVolume volume(device);
|
||||||
|
|
||||||
|
status_t result;
|
||||||
|
if ((result = volume.SetName((diskData->title).String())) != B_OK) {
|
||||||
|
printf("Can't set volume name.\n");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
CDDBDaemon* cddbDaemon = new CDDBDaemon();
|
CDDBDaemon* cddbDaemon = new CDDBDaemon();
|
||||||
cddbDaemon->Run();
|
cddbDaemon->Run();
|
||||||
|
|||||||
@@ -10,23 +10,32 @@
|
|||||||
#define _CDDB_DAEMON_H
|
#define _CDDB_DAEMON_H
|
||||||
|
|
||||||
#include <Application.h>
|
#include <Application.h>
|
||||||
#include <Message.h>
|
|
||||||
#include <VolumeRoster.h>
|
|
||||||
|
|
||||||
#include <scsi_cmds.h>
|
#include <scsi_cmds.h>
|
||||||
|
|
||||||
|
struct ReadResponseData;
|
||||||
|
struct QueryResponseData;
|
||||||
|
|
||||||
|
class BList;
|
||||||
|
class BMessage;
|
||||||
|
class BVolumeRoster;
|
||||||
|
|
||||||
class CDDBDaemon : public BApplication {
|
class CDDBDaemon : public BApplication {
|
||||||
public:
|
public:
|
||||||
CDDBDaemon();
|
CDDBDaemon();
|
||||||
virtual ~CDDBDaemon();
|
virtual ~CDDBDaemon();
|
||||||
|
|
||||||
virtual void MessageReceived(BMessage* message);
|
virtual void MessageReceived(BMessage* message);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _CanLookup(const dev_t device, uint32* cddbId,
|
status_t _Lookup(const dev_t device);
|
||||||
scsi_toc_toc* toc) const;
|
bool _CanLookup(const dev_t device, uint32* cddbId,
|
||||||
|
scsi_toc_toc* toc) const;
|
||||||
|
QueryResponseData* _SelectResult(BList* response) const;
|
||||||
|
status_t _WriteCDData(dev_t device, QueryResponseData* diskData,
|
||||||
|
ReadResponseData* readResponse);
|
||||||
|
|
||||||
BVolumeRoster* fVolumeRoster;
|
BVolumeRoster* fVolumeRoster;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _CDDB_DAEMON_H
|
#endif // _CDDB_DAEMON_H
|
||||||
|
|||||||
@@ -0,0 +1,376 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2008-2009, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Bruno Albuquerque, [email protected]
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "cddb_server.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
|
||||||
|
static const char* kDefaultLocalHostName = "unknown";
|
||||||
|
static const uint32 kDefaultPortNumber = 80;
|
||||||
|
|
||||||
|
static const uint32 kFramesPerSecond = 75;
|
||||||
|
static const uint32 kFramesPerMinute = kFramesPerSecond * 60;
|
||||||
|
|
||||||
|
|
||||||
|
CDDBServer::CDDBServer(const BString& cddbServer):
|
||||||
|
fInitialized(false),
|
||||||
|
fConnected(false)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Set up local host name.
|
||||||
|
char localHostName[MAXHOSTNAMELEN + 1];
|
||||||
|
if (gethostname(localHostName, MAXHOSTNAMELEN + 1) == 0) {
|
||||||
|
fLocalHostName = localHostName;
|
||||||
|
} else {
|
||||||
|
fLocalHostName = kDefaultLocalHostName;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up local user name.
|
||||||
|
char* user = getenv("USER");
|
||||||
|
if (user == NULL) {
|
||||||
|
fLocalUserName = "unknown";
|
||||||
|
} else {
|
||||||
|
fLocalUserName = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up server address;
|
||||||
|
if (_ParseAddress(cddbServer) == B_OK)
|
||||||
|
fInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
CDDBServer::Query(uint32 cddbId, const scsi_toc_toc* toc, BList* queryResponse)
|
||||||
|
{
|
||||||
|
if (_OpenConnection() != B_OK)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
// Convert CDDB id to hexadecimal format.
|
||||||
|
char hexCddbId[9];
|
||||||
|
sprintf(hexCddbId, "%08lx", cddbId);
|
||||||
|
|
||||||
|
// Assemble the Query command.
|
||||||
|
int32 numTracks = toc->last_track + 1 - toc->first_track;
|
||||||
|
|
||||||
|
BString cddbCommand("cddb query ");
|
||||||
|
cddbCommand << hexCddbId << " " << numTracks << " ";
|
||||||
|
|
||||||
|
// Add track offsets in frames.
|
||||||
|
for (int32 i = 0; i < numTracks; ++i) {
|
||||||
|
const scsi_cd_msf& start = toc->tracks[i].start.time;
|
||||||
|
|
||||||
|
uint32 startFrameOffset = start.minute * kFramesPerMinute +
|
||||||
|
start.second * kFramesPerSecond + start.frame;
|
||||||
|
|
||||||
|
cddbCommand << startFrameOffset << " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add total disc time in seconds. Last track is lead-out.
|
||||||
|
const scsi_cd_msf& lastTrack = toc->tracks[numTracks].start.time;
|
||||||
|
uint32 totalTimeInSeconds = lastTrack.minute * 60 + lastTrack.second;
|
||||||
|
cddbCommand << totalTimeInSeconds;
|
||||||
|
|
||||||
|
BString output;
|
||||||
|
status_t result;
|
||||||
|
result = _SendCddbCommand(cddbCommand, &output);
|
||||||
|
|
||||||
|
if (result == B_OK) {
|
||||||
|
// Remove the header from the reply.
|
||||||
|
output.Remove(0, output.FindFirst("\r\n\r\n") + 4);
|
||||||
|
|
||||||
|
// Check status code.
|
||||||
|
BString statusCode;
|
||||||
|
output.MoveInto(statusCode, 0, 3);
|
||||||
|
if (statusCode == "210") {
|
||||||
|
// Multiple results, remove the first line and parse the others.
|
||||||
|
output.Remove(0, output.FindFirst("\r\n") + 2);
|
||||||
|
} else if (statusCode == "200") {
|
||||||
|
// Remove the first char which is a left over space.
|
||||||
|
output.Remove(0, 1);
|
||||||
|
} else {
|
||||||
|
// Something bad happened.
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process all entries.
|
||||||
|
bool done = false;
|
||||||
|
while (!done) {
|
||||||
|
QueryResponseData* responseData = new QueryResponseData;
|
||||||
|
|
||||||
|
output.MoveInto(responseData->category, 0, output.FindFirst(" "));
|
||||||
|
output.Remove(0, 1);
|
||||||
|
|
||||||
|
output.MoveInto(responseData->cddbId, 0, output.FindFirst(" "));
|
||||||
|
output.Remove(0, 1);
|
||||||
|
|
||||||
|
output.MoveInto(responseData->artist, 0, output.FindFirst(" / "));
|
||||||
|
output.Remove(0, 3);
|
||||||
|
|
||||||
|
output.MoveInto(responseData->title, 0, output.FindFirst("\r\n"));
|
||||||
|
output.Remove(0, 2);
|
||||||
|
|
||||||
|
queryResponse->AddItem(responseData);
|
||||||
|
|
||||||
|
if (output == "" || output == ".\r\n") {
|
||||||
|
// All returned data was processed exit the loop.
|
||||||
|
done = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printf("Error sending CDDB command : \"%s\".\n", cddbCommand.String());
|
||||||
|
}
|
||||||
|
|
||||||
|
_CloseConnection();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
CDDBServer::Read(QueryResponseData* diskData, ReadResponseData* readResponse)
|
||||||
|
{
|
||||||
|
if (_OpenConnection() != B_OK)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
// Assemble the Read command.
|
||||||
|
BString cddbCommand("cddb read ");
|
||||||
|
cddbCommand << diskData->category << " " << diskData->cddbId;
|
||||||
|
|
||||||
|
BString output;
|
||||||
|
status_t result;
|
||||||
|
result = _SendCddbCommand(cddbCommand, &output);
|
||||||
|
|
||||||
|
if (result == B_OK) {
|
||||||
|
// Remove the header from the reply.
|
||||||
|
output.Remove(0, output.FindFirst("\r\n\r\n") + 4);
|
||||||
|
|
||||||
|
// Check status code.
|
||||||
|
BString statusCode;
|
||||||
|
output.MoveInto(statusCode, 0, 3);
|
||||||
|
if (statusCode == "210") {
|
||||||
|
// Remove first line and parse the others.
|
||||||
|
output.Remove(0, output.FindFirst("\r\n") + 2);
|
||||||
|
} else {
|
||||||
|
// Something bad happened.
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process all entries.
|
||||||
|
bool done = false;
|
||||||
|
while (!done) {
|
||||||
|
if (output[0] == '#') {
|
||||||
|
// Comment. Remove it.
|
||||||
|
output.Remove(0, output.FindFirst("\r\n") + 2);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract one line to reduce the scope of processing to it.
|
||||||
|
BString line;
|
||||||
|
output.MoveInto(line, 0, output.FindFirst("\r\n"));
|
||||||
|
output.Remove(0, 2);
|
||||||
|
|
||||||
|
// Obtain prefix.
|
||||||
|
BString prefix;
|
||||||
|
line.MoveInto(prefix, 0, line.FindFirst("="));
|
||||||
|
line.Remove(0, 1);
|
||||||
|
|
||||||
|
if (prefix == "DTITLE") {
|
||||||
|
// Disk title.
|
||||||
|
BString artist;
|
||||||
|
line.MoveInto(artist, 0, line.FindFirst(" / "));
|
||||||
|
line.Remove(0, 3);
|
||||||
|
readResponse->title = line;
|
||||||
|
readResponse->artist = artist;
|
||||||
|
} else if (prefix == "DYEAR") {
|
||||||
|
// Disk year.
|
||||||
|
char* firstInvalid;
|
||||||
|
errno = 0;
|
||||||
|
uint32 year = strtoul(line.String(), &firstInvalid, 10);
|
||||||
|
if ((errno == ERANGE &&
|
||||||
|
(year == (uint32)LONG_MAX || year == (uint32)LONG_MIN))
|
||||||
|
|| (errno != 0 && year == 0)) {
|
||||||
|
// Year out of range.
|
||||||
|
printf("Year out of range: %s\n", line.String());
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstInvalid == line.String()) {
|
||||||
|
printf("Invalid year: %s\n", line.String());
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
readResponse->year = year;
|
||||||
|
} else if (prefix == "DGENRE") {
|
||||||
|
// Disk genre.
|
||||||
|
readResponse->genre = line;
|
||||||
|
} else if (prefix.FindFirst("TTITLE") == 0) {
|
||||||
|
// Track title.
|
||||||
|
BString index;
|
||||||
|
prefix.MoveInto(index, 6, prefix.Length() - 6);
|
||||||
|
|
||||||
|
TrackData* trackData = new TrackData;
|
||||||
|
|
||||||
|
char* firstInvalid;
|
||||||
|
errno = 0;
|
||||||
|
uint32 track = strtoul(index.String(), &firstInvalid, 10);
|
||||||
|
if ((errno == ERANGE &&
|
||||||
|
(track == (uint32)LONG_MAX || track == (uint32)LONG_MIN))
|
||||||
|
|| (errno != 0 && track == 0)) {
|
||||||
|
// Track out of range.
|
||||||
|
printf("Track out of range: %s\n", index.String());
|
||||||
|
delete trackData;
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstInvalid == index.String()) {
|
||||||
|
printf("Invalid track: %s\n", index.String());
|
||||||
|
delete trackData;
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
trackData->trackNumber = track;
|
||||||
|
|
||||||
|
int32 pos = line.FindFirst(" / " );
|
||||||
|
if (pos != B_ERROR) {
|
||||||
|
// We have track specific artist information.
|
||||||
|
BString artist;
|
||||||
|
line.MoveInto(artist, 0, pos);
|
||||||
|
line.Remove(0, 3);
|
||||||
|
trackData->artist = artist;
|
||||||
|
} else {
|
||||||
|
trackData->artist = diskData->artist;
|
||||||
|
}
|
||||||
|
|
||||||
|
trackData->title = line;
|
||||||
|
|
||||||
|
(readResponse->tracks).AddItem(trackData);
|
||||||
|
} else {
|
||||||
|
printf("Unhandled or unknown prefix: %s\n", prefix.String());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (output == "" || output == ".\r\n") {
|
||||||
|
// All returned data was processed exit the loop.
|
||||||
|
done = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printf("Error sending CDDB command : \"%s\".\n", cddbCommand.String());
|
||||||
|
}
|
||||||
|
|
||||||
|
_CloseConnection();
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
CDDBServer::_ParseAddress(const BString& cddbServer)
|
||||||
|
{
|
||||||
|
// Set up server address.
|
||||||
|
int32 pos = cddbServer.FindFirst(":");
|
||||||
|
if (pos == B_ERROR) {
|
||||||
|
// It seems we do not have the address:port format. Use hostname as-is.
|
||||||
|
fCddbServerAddr.SetTo(cddbServer.String(), kDefaultPortNumber);
|
||||||
|
if (fCddbServerAddr.InitCheck() == B_OK)
|
||||||
|
return B_OK;
|
||||||
|
} else {
|
||||||
|
// Parse address:port format.
|
||||||
|
int32 port;
|
||||||
|
BString newCddbServer(cddbServer);
|
||||||
|
BString portString;
|
||||||
|
newCddbServer.MoveInto(portString, pos + 1,
|
||||||
|
newCddbServer.CountChars() - pos + 1);
|
||||||
|
if (portString.CountChars() > 0) {
|
||||||
|
char* firstInvalid;
|
||||||
|
errno = 0;
|
||||||
|
port = strtol(portString.String(), &firstInvalid, 10);
|
||||||
|
if ((errno == ERANGE && (port == LONG_MAX || port == LONG_MIN))
|
||||||
|
|| (errno != 0 && port == 0)) {
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
if (firstInvalid == portString.String()) {
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
newCddbServer.RemoveAll(":");
|
||||||
|
fCddbServerAddr.SetTo(newCddbServer.String(), port);
|
||||||
|
if (fCddbServerAddr.InitCheck() == B_OK)
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
CDDBServer::_OpenConnection()
|
||||||
|
{
|
||||||
|
if (!fInitialized)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
if (fConnected)
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
if (fConnection.Connect(fCddbServerAddr) == B_OK) {
|
||||||
|
fConnected = true;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CDDBServer::_CloseConnection()
|
||||||
|
{
|
||||||
|
if (!fConnected)
|
||||||
|
return;
|
||||||
|
|
||||||
|
fConnection.Close();
|
||||||
|
fConnected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
CDDBServer::_SendCddbCommand(const BString& command, BString* output)
|
||||||
|
{
|
||||||
|
if (!fConnected)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
// Assemble full command string.
|
||||||
|
BString fullCommand;
|
||||||
|
fullCommand << command << "&hello=" << fLocalUserName << " " <<
|
||||||
|
fLocalHostName << " cddb_daemon 1.0&proto=6";
|
||||||
|
|
||||||
|
// Replace spaces by + signs.
|
||||||
|
fullCommand.ReplaceAll(" ", "+");
|
||||||
|
|
||||||
|
// And now add command header and footer.
|
||||||
|
fullCommand.Prepend("GET /~cddb/cddb.cgi?cmd=");
|
||||||
|
fullCommand << " HTTP 1.0\n\n";
|
||||||
|
|
||||||
|
int32 result = fConnection.Send((void*)fullCommand.String(),
|
||||||
|
fullCommand.Length());
|
||||||
|
if (result == fullCommand.Length()) {
|
||||||
|
BNetBuffer netBuffer;
|
||||||
|
while (fConnection.Receive(netBuffer, 10) != 0) {
|
||||||
|
// Do nothing. Data is automatically appended to the NetBuffer.
|
||||||
|
}
|
||||||
|
|
||||||
|
// AppendString automatically adds the terminating \0.
|
||||||
|
netBuffer.AppendString("");
|
||||||
|
|
||||||
|
output->SetTo((char*)netBuffer.Data(), netBuffer.Size());
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2008-2009, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Bruno Albuquerque, [email protected]
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _CDDB_SERVER_H
|
||||||
|
#define _CDDB_SERVER_H
|
||||||
|
|
||||||
|
#include <List.h>
|
||||||
|
#include <NetAddress.h>
|
||||||
|
#include <NetEndpoint.h>
|
||||||
|
#include <String.h>
|
||||||
|
|
||||||
|
#include <scsi_cmds.h>
|
||||||
|
|
||||||
|
|
||||||
|
// CD track specific data.
|
||||||
|
struct TrackData {
|
||||||
|
uint32 trackNumber;
|
||||||
|
BString title;
|
||||||
|
BString artist;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Query command response.
|
||||||
|
struct QueryResponseData {
|
||||||
|
BString category;
|
||||||
|
BString cddbId;
|
||||||
|
BString artist;
|
||||||
|
BString title;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Read command response.
|
||||||
|
struct ReadResponseData {
|
||||||
|
BString title;
|
||||||
|
BString artist;
|
||||||
|
BString genre;
|
||||||
|
uint32 year;
|
||||||
|
BList tracks; // TrackData items.
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class CDDBServer {
|
||||||
|
public:
|
||||||
|
CDDBServer(const BString& cddbServer);
|
||||||
|
|
||||||
|
// CDDB commands interface.
|
||||||
|
status_t Query(uint32 cddbId, const scsi_toc_toc* toc,
|
||||||
|
BList* queryResponse);
|
||||||
|
status_t Read(QueryResponseData* diskData,
|
||||||
|
ReadResponseData* readResponse);
|
||||||
|
|
||||||
|
private:
|
||||||
|
status_t _ParseAddress(const BString& cddbServer);
|
||||||
|
|
||||||
|
status_t _OpenConnection();
|
||||||
|
void _CloseConnection();
|
||||||
|
|
||||||
|
status_t _SendCddbCommand(const BString& command, BString* output);
|
||||||
|
|
||||||
|
BString fLocalHostName;
|
||||||
|
BString fLocalUserName;
|
||||||
|
BNetAddress fCddbServerAddr;
|
||||||
|
BNetEndpoint fConnection;
|
||||||
|
bool fInitialized;
|
||||||
|
bool fConnected;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _CDDB_SERVER_H
|
||||||
Reference in New Issue
Block a user