1
0
Fork 0
mirror of https://github.com/transmission/transmission synced 2025-01-30 19:03:04 +00:00

Update 2005-12-13

This commit is contained in:
Eric Petit 2006-01-12 18:52:15 +00:00
parent ce24506f5e
commit 616ae26efa
22 changed files with 1787 additions and 9 deletions

View file

@ -50,4 +50,9 @@ else if $(GTK) = yes
SubInclude TOP gtk ;
}
if $(OS) = BEOS
{
BeOSBuild Transmission : libtransmission.a ;
}
SubInclude TOP libtransmission ;

View file

@ -8,12 +8,12 @@ if ! $(DEFINES)
VERSION_MAJOR = 0 ;
VERSION_MINOR = 4 ;
# VERSION_STRING = $(VERSION_MAJOR).$(VERSION_MINOR) ;
VERSION_STRING = CVS-20051124 ;
VERSION_STRING = CVS-20051213 ;
DEFINES += VERSION_MAJOR=$(VERSION_MAJOR)
VERSION_MINOR=$(VERSION_MINOR)
VERSION_STRING=\\\"$(VERSION_STRING)\\\" ;
OPTIM = -O3 ;
OPTIM = -O0 ;
RM = rm -Rf ;
rule SystemLibraries
@ -93,3 +93,18 @@ if $(OS) = MACOSX
rm -rf "$TMP"
}
}
if $(OS) = BEOS
{
rule BeOSBuild
{
Depends exe : $(1) ;
Depends $(1) : $(2) ;
Clean clean : $(1) beos/obj.$(CPU) ;
}
actions BeOSBuild
{
$(RM) $(1) && ( cd beos && make ) && \
mv beos/obj.$(CPU)/Transmission $(1)
}
}

298
beos/TRApplication.cpp Normal file
View file

@ -0,0 +1,298 @@
#include "TRApplication.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <AppFileInfo.h>
#include <Alert.h>
#include <Bitmap.h>
#include <File.h>
#include <FindDirectory.h>
#include <Messenger.h>
#include <Mime.h>
#include <Path.h>
#include <String.h>
#include <Resources.h>
#include <Roster.h>
int main(int argc, char** argv) {
TRApplication *app = new TRApplication();
if (app->InitCheck() == B_OK) {
app->Run();
} else {
BString errMsg("");
errMsg << "The following error occurred loading Transmission:\n"
<< strerror(app->InitCheck());
BAlert *ohNo = new BAlert("Transmission Error",
errMsg.String(),
"OK", NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT);
ohNo->Go();
}
delete app;
return (0);
}
TRApplication::TRApplication() : BApplication(APP_SIG) {
status_t err = B_OK;
torrentDir = NULL;
// Install Mime types if necessary.
BMimeType torrentType("application/x-bittorrent");
if (torrentType.InitCheck() == B_OK) {
if (!torrentType.IsInstalled()) {
fprintf(stderr, "Installing mime type...\n");
// Icon
app_info runningInfo;
GetAppInfo(&runningInfo);
BFile appFile(&(runningInfo.ref), B_READ_ONLY);
BResources res(&appFile, false);
size_t len = 0;
BBitmap *icon = NULL;
void *iconBits = NULL;
iconBits = res.FindResource('ICON', "BEOS:L:application/x-bittorrent", &len);
if (iconBits) {
icon = new BBitmap(BRect(0, 0, 31, 31), B_CMAP8);
icon->SetBits(iconBits, len, 0, B_CMAP8);
torrentType.SetIcon(icon, B_LARGE_ICON);
delete icon;
icon = NULL;
len = 0;
}
iconBits = res.FindResource('ICON', "BEOS:M:application/x-bittorrent", &len);
if (iconBits) {
icon = new BBitmap(BRect(0, 0, 15, 15), B_CMAP8);
icon->SetBits(iconBits, len, 0, B_CMAP8);
torrentType.SetIcon(icon, B_MINI_ICON);
delete icon;
}
// Extensions
BMessage extensions;
extensions.AddString("extensions", "torrent");
torrentType.SetFileExtensions(&extensions);
torrentType.SetShortDescription("BitTorrent Meta File");
torrentType.SetLongDescription("BitTorrent Protocol Meta File (http://www.bittorrent.com)");
// Set Preferred Application
torrentType.SetPreferredApp(APP_SIG, B_OPEN);
torrentType.Install();
}
}
// Create Settings folder and structure
BPath settingsPath;
err = find_directory(B_USER_SETTINGS_DIRECTORY, &settingsPath, false);
if (err == B_OK) {
BDirectory settings(settingsPath.Path());
BDirectory *trSettings = new BDirectory();
err = settings.CreateDirectory("Transmission", trSettings);
if (err == B_FILE_EXISTS) {
err = trSettings->SetTo(&settings, "Transmission");
}
if (err == B_OK) {
torrentDir = new BDirectory();
err = trSettings->CreateDirectory("Torrents", torrentDir);
if (err != B_OK) {
torrentDir->SetTo(trSettings, "Torrents");
}
}
delete trSettings;
}
// Create window
window = new TRWindow();
window->RescanTorrents();
settings = new TRPrefsWindow();
openPanel = new BFilePanel();
openPanel->SetRefFilter(new TRFilter());
}
TRApplication::~TRApplication() {
if (window->Lock()) {
window->Quit();
}
if (settings->Lock()) {
settings->Quit();
}
if (openPanel != NULL) {
delete openPanel;
}
if (torrentDir != NULL) {
delete torrentDir;
}
}
/**
* Checks to make sure our Settings directory structure is in place.
* If this fails, then we need to display an alert and vomit.
*/
status_t TRApplication::InitCheck() {
if (torrentDir != NULL) {
return torrentDir->InitCheck();
}
return B_ERROR;
}
void TRApplication::AboutRequested() {
// Read the application version info
app_info runningInfo;
GetAppInfo(&runningInfo);
BFile appFile(&(runningInfo.ref), B_READ_ONLY);
BAppFileInfo appInfo(&appFile);
version_info vInfo;
appInfo.GetVersionInfo(&vInfo, B_APP_VERSION_KIND);
BString aboutMsg("");
aboutMsg << "Transmission\n"
<< "Version " << vInfo.major << "." << vInfo.middle << "." << vInfo.minor << "\n"
<< "Eric Petit & Bryan Varner\n";
BAlert *aboutBox = new BAlert("About Transmission", aboutMsg.String(), "Close");
aboutBox->Go();
}
void TRApplication::ReadyToRun() {
SetPulseRate(500000);
window->Show();
}
void TRApplication::Pulse() {
window->UpdateList(-1, false);
}
/**
* When a ref is received, we copy each file that is to be opened into
* B_USER_SETTINGS/Transmission/Torrents
*
* Our window node_monitors this folder for added / removed torrent meta files.
*
* Each copy is performed in a seperate thread to avoid blocking / locking the app.
*/
void TRApplication::RefsReceived(BMessage *message) {
int32 count;
type_code code;
message->GetInfo("refs", &code, &count);
for (int i = 0; i < count; i++) {
entry_ref *ref = (entry_ref*)calloc(sizeof(entry_ref), 1);
if (message->FindRef("refs", i, ref) == B_OK) {
thread_id cp_thread = spawn_thread(TRApplication::Copy, "TorrentDuper",
B_NORMAL_PRIORITY, (void *)ref);
if (!((cp_thread) < B_OK)) {
resume_thread(cp_thread);
}
}
}
}
/**
* BMessage handling.
*/
void TRApplication::MessageReceived(BMessage *message) {
BApplication::MessageReceived(message);
/*
* When the copy of a torrent file is complete, we get a message
* signaling that we should add the now copied .torrent file to our Transfer Window.
*/
if (message->what == TR_ADD) {
// Add the torrent to the window.
entry_ref torrentRef;
if (message->FindRef("torrent", &torrentRef) == B_OK) {
BEntry *entry = new BEntry(&torrentRef, true);
window->AddEntry(entry);
delete entry;
}
/* Show the Open Dialog */
} else if (message->what == TR_OPEN) {
openPanel->Show();
} else if (message->what == TR_SETTINGS) {
settings->MoveTo(window->Frame().left + (window->Frame().Width() - settings->Frame().Width()) / 2,
window->Frame().top + (window->Frame().Height() - settings->Frame().Height()) / 2);
settings->Show();
} else if (message->what == TR_RELOAD_SETTINGS) {
window->LoadSettings();
}
}
bool TRApplication::QuitRequested() {
return BApplication::QuitRequested();
}
/**
* Thread Function.
* The thread copies the original .torrent file into the torrents folder,
* then signals the window to load the torrent meta info from the copy.
* The torrent window will then node_monitor the file so that if it's removed
* the torrent will cease.
*
* Keeping the file copy in a separate thread keeps us from blocking up the
* rest of our program.
*
* This behavior lets us kill the original .torrent download from disc (which
* speaking as a user I have a tendency to do) but keep the meta around for
* Transmission to use later.
*
* If the user whacks the .torrent file from our settings folder, then we'll
* remove it from the list (node_monitor!) and if they remove it from our list
* we'll remove it from the file system.
*/
int32 TRApplication::Copy(void *data) {
entry_ref *ref = (entry_ref*)data;
BFile source(ref, B_READ_ONLY);
BFile target(((TRApplication*)be_app)->TorrentDir(), ref->name,
B_WRITE_ONLY | B_CREATE_FILE | B_FAIL_IF_EXISTS);
BEntry targetEntry(((TRApplication*)be_app)->TorrentDir(), ref->name);
entry_ref targetRef;
targetEntry.GetRef(&targetRef);
// Only perform the copy if the target is freshly created. Everything is B_OK!
if (source.InitCheck() == B_OK && target.InitCheck() == B_OK) {
if (target.Lock() == B_OK) {
char *buffer = (char*)calloc(1, 4096); // 4k data buffer.
ssize_t read = 0;
while ((read = source.Read(buffer, 4096)) > 0) {
target.Write(buffer, read);
}
free(buffer);
target.Unlock();
}
}
BMessage msg(TR_ADD);
msg.AddRef("torrent", &targetRef);
BMessenger messenger(be_app);
messenger.SendMessage(&msg);
free(ref);
return B_OK;
}
/**
* Filters the FilePanel for torrent files and directories.
*/
bool TRFilter::Filter(const entry_ref *ref, BNode *node, struct stat *st, const char *mimetype) {
return (node->IsDirectory() ||
(strcmp(mimetype, "application/x-bittorrent") == 0) ||
(strstr(ref->name, ".torrent") != NULL));
}

50
beos/TRApplication.h Normal file
View file

@ -0,0 +1,50 @@
#ifndef TR_APP
#define TR_APP
#include <Application.h>
#include <Directory.h>
#include <FilePanel.h>
#include <Message.h>
#include "TRWindow.h"
#define APP_SIG "application/x-vnd.titer-Transmission"
#define TRANSMISSION_SETTINGS "Transmission/settings"
#define TR_ADD 'tAdd'
#define TR_OPEN 'tOpn'
#define TR_RELOAD_SETTINGS 'tRSt'
class TRApplication : public BApplication {
public:
TRApplication();
~TRApplication();
virtual void AboutRequested();
virtual void Pulse();
virtual void ReadyToRun();
virtual void RefsReceived(BMessage *message);
virtual bool QuitRequested();
virtual void MessageReceived(BMessage *message);
static int32 Copy(void *data);
status_t InitCheck();
inline BDirectory* TorrentDir() { return torrentDir; };
private:
TRWindow *window;
TRPrefsWindow *settings;
BFilePanel *openPanel;
BDirectory *torrentDir;
};
/** Torrent File-Type Filter */
class TRFilter : public BRefFilter {
public:
virtual bool Filter(const entry_ref *ref, BNode *node,
struct stat *st, const char *mimetype);
};
#endif /* TR_APP */

93
beos/TRInfoWindow.cpp Normal file
View file

@ -0,0 +1,93 @@
#include "TRInfoWindow.h"
#include <Box.h>
#include <String.h>
#include <TextView.h>
#include <ScrollView.h>
#include <malloc.h>
#include <stdio.h>
TRInfoWindow::TRInfoWindow(tr_stat_t status) : BWindow(BRect(0, 0, 250, 175), "Info",
B_FLOATING_WINDOW, B_ASYNCHRONOUS_CONTROLS | /*B_NOT_RESIZABLE*/ B_NOT_ZOOMABLE,
B_CURRENT_WORKSPACE)
{
BRect viewRect = Bounds();
// Single header, Font Size 14.
BFont headerFont(be_bold_font);
headerFont.SetSize(14.0f);
font_height fh;
headerFont.GetHeight(&fh);
if (headerFont.StringWidth(status.info.name) > Bounds().Width() - 10) {
ResizeBy(headerFont.StringWidth(status.info.name) - Bounds().Width() + 10, 0);
}
viewRect = Bounds();
viewRect.bottom = fh.ascent + fh.descent;
BStringView *strView = new BStringView(viewRect, "header", status.info.name, B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP);
strView->SetFont(&headerFont);
strView->SetAlignment(B_ALIGN_CENTER);
viewRect.left = 5;
viewRect.top = 10;
viewRect.bottom = Bounds().bottom - 5;
BTextView *txtView = new BTextView(viewRect, "infoText", viewRect, B_FOLLOW_LEFT | B_FOLLOW_TOP);
txtView->MakeEditable(false);
BString strTracker(status.info.trackerAddress);
strTracker << ":" << status.info.trackerPort;
BString strPieceSize("");
StringForFileSize(status.info.pieceSize, &strPieceSize);
BString strTotalSize("");
StringForFileSize(status.info.totalSize, &strTotalSize);
BString strDownloaded("");
StringForFileSize(status.downloaded, &strDownloaded);
BString strUploaded("");
StringForFileSize(status.uploaded, &strUploaded);
BString info("");
info << "Tracker: " << strTracker << "\n"
<< "Announce: " << status.info.trackerAnnounce << "\n"
<< "Piece Size: " << strPieceSize << "\n"
<< "Pieces: " << status.info.pieceCount << "\n"
<< "Total Size: " << strTotalSize << "\n"
<< "\n"
<< "Folder: " << status.folder << "\n"
<< "Downloaded: " << strDownloaded << "\n"
<< "Uploaded: " << strUploaded << "\n";
txtView->SetText(info.String());
Lock();
AddChild(strView);
AddChild(txtView);
Unlock();
}
TRInfoWindow::~TRInfoWindow() {
}
void TRInfoWindow::FrameResized(float width, float height) {
}
void TRInfoWindow::StringForFileSize(uint64_t size, BString *str) {
char *s = (char*)calloc(512, sizeof(char));
if (size < 1024) {
sprintf(s, "%lld bytes", size);
} else if (size < 1048576) {
sprintf(s, "%lld.%lld KB", size / 1024, (size % 1024 ) / 103);
} else if (size < 1073741824 ) {
sprintf(s, "%lld.%lld MB", size / 1048576, (size % 1048576) / 104858);
} else {
sprintf(s, "%lld.%lld GB", size / 1073741824, (size % 1073741824) / 107374183);
}
str->SetTo(s);
free(s);
}

22
beos/TRInfoWindow.h Normal file
View file

@ -0,0 +1,22 @@
#ifndef TR_INFO_WIND
#define TR_INFO_WIND
#include <Box.h>
#include <Window.h>
#include <StringView.h>
#include "transmission.h"
class TRInfoWindow : public BWindow {
public:
TRInfoWindow(tr_stat_t status);
~TRInfoWindow();
virtual void FrameResized(float width, float height);
private:
void StringForFileSize(uint64_t size, BString *str);
BBox *fBox;
};
#endif

165
beos/TRPrefsWindow.cpp Normal file
View file

@ -0,0 +1,165 @@
#include "TRPrefsWindow.h"
#include "Prefs.h"
#include <Beep.h>
#include <Box.h>
#include <Font.h>
#include <String.h>
#include <stdlib.h>
#include <stdio.h>
#include "TRApplication.h"
TRPrefsWindow::TRPrefsWindow() : BWindow(BRect(0, 0, 300, 115), "Settings",
B_TITLED_WINDOW,
B_ASYNCHRONOUS_CONTROLS | B_NOT_CLOSABLE | B_NOT_ZOOMABLE | B_NOT_RESIZABLE,
B_CURRENT_WORKSPACE)
{
BRect viewRect = Bounds();
viewRect.InsetBy(-1, -1);
BBox *box = new BBox(viewRect, NULL, B_FOLLOW_ALL);
font_height fh;
be_plain_font->GetHeight(&fh);
// Text Controls.
viewRect.Set(5, 5, viewRect.Width() - 10, fh.leading + fh.ascent + 10);
txtFolder = new BTextControl(viewRect, "txtFolder", "Download directory:", "",
NULL, B_FOLLOW_LEFT | B_FOLLOW_TOP | B_FOLLOW_RIGHT);
box->AddChild(txtFolder);
viewRect.Set(viewRect.left, viewRect.bottom + 10,
viewRect.right, viewRect.bottom + fh.leading + fh.ascent + 15);
txtPort = new BTextControl(viewRect, "txtPort", "Listen On Port:", "",
NULL, B_FOLLOW_LEFT | B_FOLLOW_TOP | B_FOLLOW_RIGHT);
box->AddChild(txtPort);
viewRect.Set(viewRect.left, viewRect.bottom + 10,
viewRect.right, viewRect.bottom + fh.leading + fh.ascent + 15);
txtUpload = new BTextControl(viewRect, "txtUpload", "Upload Limit (KB/sec):", "",
NULL, B_FOLLOW_LEFT | B_FOLLOW_TOP | B_FOLLOW_RIGHT);
box->AddChild(txtUpload);
// Buttons
viewRect.Set(viewRect.left, viewRect.bottom + 20,
viewRect.left + be_plain_font->StringWidth("Defaults") + 20,
viewRect.bottom + fh.leading + fh.ascent + 10);
btnDefaults = new BButton(viewRect, "btnDefault", "Defaults", new BMessage(TR_PREF_DEFAULTS));
box->AddChild(btnDefaults);
viewRect.OffsetBy(viewRect.Width() + 10, 0);
viewRect.right = viewRect.left + be_plain_font->StringWidth("Cancel") + 20;
btnCancel = new BButton(viewRect, "btnCancel", "Cancel", new BMessage(TR_PREF_CANCEL));
box->AddChild(btnCancel);
viewRect.OffsetBy(viewRect.Width() + 15, 0);
viewRect.right = viewRect.left + be_plain_font->StringWidth("Apply") + 20;
btnSave = new BButton(viewRect, "btnSave", "Apply", new BMessage(TR_PREF_SAVE));
btnSave->MakeDefault(true);
box->AddChild(btnSave);
Lock();
AddChild(box);
ResizeTo(Bounds().Width(), viewRect.bottom + btnSave->Bounds().Height());
Unlock();
}
TRPrefsWindow::~TRPrefsWindow() {
}
void TRPrefsWindow::MessageReceived(BMessage *msg) {
if (msg->what == TR_PREF_SAVE) {
if (WritePrefs()) {
Hide();
} else {
beep();
}
} else if (msg->what == TR_PREF_CANCEL) {
Hide();
} else if (msg->what == TR_PREF_DEFAULTS) {
txtFolder->SetText("/boot/home/Downloads");
txtPort->SetText("9000");
txtUpload->SetText("20");
}
BWindow::MessageReceived(msg);
}
void TRPrefsWindow::Show() {
ReadPrefs();
if (Lock()) {
txtFolder->MakeFocus(true);
Unlock();
}
BWindow::Show();
}
void TRPrefsWindow::ReadPrefs() {
if (Lock()) {
Prefs prefs(TRANSMISSION_SETTINGS);
BString str("");
if (prefs.FindString("download.folder", &str) != B_OK) {
prefs.SetString("download.folder", "/boot/home/Downloads");
str << "/boot/home/Downloads";
}
txtFolder->SetText(str.String());
int32 port;
if (prefs.FindInt32("transmission.bindPort", &port) != B_OK) {
prefs.SetInt32("transmission.bindPort", 9000);
port = 9000;
}
str = "";
str << port;
txtPort->SetText(str.String());
int32 upload;
if (prefs.FindInt32("transmission.uploadLimit", &upload) != B_OK) {
prefs.SetInt32("transmission.uploadLimit", 20);
upload = 20;
}
str = "";
str << upload;
txtUpload->SetText(str.String());
Unlock();
}
}
bool TRPrefsWindow::WritePrefs() {
bool valid = true;
int port = atoi(txtPort->Text());
if (port <= 0) {
valid = false;
txtPort->MakeFocus(true);
}
const char* uploadStr = txtUpload->Text();
int uploadLimit = atoi(txtUpload->Text());
for (uint i = 0; i < strlen(uploadStr) && valid; i++) {
if (!(uploadStr[i] >= '0' && uploadStr[i] <= '9')) {
valid = false;
txtUpload->MakeFocus(true);
}
}
if (valid) {
Prefs prefs(TRANSMISSION_SETTINGS);
prefs.SetInt32("transmission.bindPort", (int32)port);
prefs.SetString("download.folder", txtFolder->Text());
prefs.SetInt32("transmission.uploadLimit", (int32)uploadLimit);
be_app_messenger.SendMessage(new BMessage(TR_RELOAD_SETTINGS));
}
return valid;
}

34
beos/TRPrefsWindow.h Normal file
View file

@ -0,0 +1,34 @@
#ifndef TR_PREF_WIND
#define TR_PREF_WIND
#include <Button.h>
#include <TextControl.h>
#include <Slider.h>
#include <Window.h>
#define TR_PREF_SAVE 'tSve'
#define TR_PREF_CANCEL 'tCan'
#define TR_PREF_DEFAULTS 'tDef'
class TRPrefsWindow : public BWindow {
public:
TRPrefsWindow();
~TRPrefsWindow();
virtual void MessageReceived(BMessage *msg);
virtual void Show();
private:
void ReadPrefs();
bool WritePrefs();
BTextControl *txtFolder;
BTextControl *txtPort;
BTextControl *txtUpload;
BButton *btnSave;
BButton *btnCancel;
BButton *btnDefaults;
};
#endif /* TR_PREF_WIND */

235
beos/TRTransfer.cpp Normal file
View file

@ -0,0 +1,235 @@
#include "TRTransfer.h"
#include <Font.h>
#include <malloc.h>
#include <stdio.h>
/**
* BListItem that renders Transfer status.
*/
TRTransfer::TRTransfer(const char *fullpath, node_ref node) : BListItem(0, false), cachedNodeRef(node) {
fBaselineOffset = 0.0f;
fLineSpacing = 0.0f;
cachedPath = new BString(fullpath);
fStatusLock = new BLocker("Status Locker", true);
fStatus = (tr_stat_t*)calloc(1, sizeof(tr_stat_t));
fBarColor.red = 50;
fBarColor.green = 150;
fBarColor.blue = 255;
fBarColor.alpha = 255;
fTimeStr = (char*)calloc(78, sizeof(char));
fTransStr = (char*)calloc(78, sizeof(char));
}
TRTransfer::~TRTransfer() {
if (fStatusLock->Lock()) {
free(fStatus);
fStatusLock->Unlock();
delete fStatusLock;
}
delete cachedPath;
}
void TRTransfer::Update(BView *owner, const BFont *font) {
BListItem::Update(owner, font);
SetHeight(BListItem::Height() * 4);
font_height height;
font->GetHeight(&height);
fBaselineOffset = height.leading + height.ascent;
fLineSpacing = height.descent;
}
/**
* Sets the transfer information to render.
* Returns a bool signaling the view is dirty after the update.
*
* The view is determined to be dirty if the transfer
* status, progress, eta or the "shade" (even or odd)
* position in the list changes from the previous state.
* If the tr_stat_t is in fact different then the new, full
* status is memcpy'd overtop the existing code.
*
* This is a thread-safe function, as all writing to the
* local fStatus requires a successful Lock on fStatusLock.
*/
bool TRTransfer::SetStatus(tr_stat_t *stat, bool shade) {
bool dirty = false;
if (fStatusLock->Lock()) {
if (fStatus->status != stat->status ||
fStatus->progress != stat->progress ||
fStatus->eta != stat->eta ||
fShade != shade)
{
memcpy(fStatus, stat, sizeof(tr_stat_t));
dirty = true;
}
fStatusLock->Unlock();
fShade = shade;
}
return dirty;
}
/**
* Renders (Draws) the current status into the BListView.
*/
void TRTransfer::DrawItem(BView *owner, BRect frame, bool complete) {
rgb_color col;
col.red = 255;
col.green = 255;
col.blue = 255;
owner->PushState();
// Draw the background...
if (IsSelected()) {
owner->SetLowColor(tint_color(col, B_DARKEN_2_TINT));
} else if (fShade) {
owner->SetLowColor(tint_color(tint_color(col, B_DARKEN_1_TINT), B_LIGHTEN_2_TINT));
} else {
owner->SetLowColor(col);
}
owner->FillRect(frame, B_SOLID_LOW);
// Draw the informational text...
owner->SetHighColor(ui_color(B_MENU_ITEM_TEXT_COLOR));
BPoint textLoc = frame.LeftTop();
textLoc.y += (fBaselineOffset / 2);
textLoc += BPoint(2, fBaselineOffset);
if (fStatus != NULL && fStatusLock->Lock()) {
owner->DrawString(fStatus->info.name, textLoc);
if (fStatus->status & TR_STATUS_PAUSE ) {
sprintf(fTimeStr, "Paused (%.2f %%)", 100 * fStatus->progress);
} else if (fStatus->status & TR_STATUS_CHECK ) {
sprintf(fTimeStr, "Checking Existing Files (%.2f %%)",
100 * fStatus->progress);
} else if (fStatus->status & TR_STATUS_DOWNLOAD) {
if (fStatus->eta < 0 ) {
sprintf(fTimeStr, "--:--:-- Remaining (%.2f %%Complete)",
100 * fStatus->progress);
} else {
sprintf(fTimeStr, "%02d:%02d:%02d Remaining (%.2f %%Complete)",
fStatus->eta / 3600, (fStatus->eta / 60) % 60,
fStatus->eta % 60, 100 * fStatus->progress);
}
} else if (fStatus->status & TR_STATUS_SEED) {
sprintf(fTimeStr, "Seeding");
} else if (fStatus->status & TR_STATUS_STOPPING) {
sprintf(fTimeStr, "Stopping...");
} else {
fTimeStr[0] = '\0';
}
textLoc.x = frame.Width() - owner->StringWidth(fTimeStr) - 2;
owner->DrawString(fTimeStr, textLoc);
if (fStatus->status & (TR_STATUS_DOWNLOAD | TR_STATUS_SEED | TR_STATUS_CHECK )) {
// Move to the left of the bottom line.
textLoc.Set(frame.left + 2,
frame.top + fBaselineOffset * 3 + (2 * fLineSpacing) + (fBaselineOffset / 2));
sprintf(fTransStr, "DL: %.2f KB/s (from %i of %i peer%s)",
fStatus->rateDownload, fStatus->peersUploading, fStatus->peersTotal,
(fStatus->peersTotal == 1) ? "" : "s");
owner->DrawString(fTransStr, textLoc);
sprintf(fTransStr, "UL: %.2f KB/s", fStatus->rateUpload);
textLoc.x = frame.Width() - owner->StringWidth(fTransStr) - 2;
owner->DrawString(fTransStr, textLoc);
}
/*
* Progress Bar - Mercilessly ripped from the Haiku source code, and
* modified to handle selection tinting, and list item position shading.
*/
// Custom setup (Transmission Added)
BRect rect(frame.left + 2, frame.top + fBaselineOffset + fLineSpacing + (fBaselineOffset / 2),
frame.Width() - 2, frame.top + fBaselineOffset * 2 + fLineSpacing + (fBaselineOffset / 2));
// First bevel
owner->SetHighColor(tint_color(ui_color ( B_PANEL_BACKGROUND_COLOR ), B_DARKEN_1_TINT));
if (IsSelected()) {
owner->SetHighColor(tint_color(owner->HighColor(), B_DARKEN_1_TINT));
}
owner->StrokeLine(BPoint(rect.left, rect.bottom), BPoint(rect.left, rect.top));
owner->StrokeLine(BPoint(rect.right, rect.top));
owner->SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), B_LIGHTEN_2_TINT));
if (IsSelected()) {
owner->SetHighColor(tint_color(owner->HighColor(), B_DARKEN_1_TINT));
}
owner->StrokeLine(BPoint(rect.left + 1.0f, rect.bottom), BPoint(rect.right, rect.bottom));
owner->StrokeLine(BPoint(rect.right, rect.top + 1.0f));
rect.InsetBy(1.0f, 1.0f);
// Second bevel
owner->SetHighColor(tint_color(ui_color ( B_PANEL_BACKGROUND_COLOR ), B_DARKEN_4_TINT));
if (IsSelected()) {
owner->SetHighColor(tint_color(owner->HighColor(), B_DARKEN_1_TINT));
}
owner->StrokeLine(BPoint(rect.left, rect.bottom), BPoint(rect.left, rect.top));
owner->StrokeLine(BPoint(rect.right, rect.top));
owner->SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR));
if (IsSelected()) {
owner->SetHighColor(tint_color(owner->HighColor(), B_DARKEN_1_TINT));
}
owner->StrokeLine(BPoint(rect.left + 1.0f, rect.bottom), BPoint(rect.right, rect.bottom));
owner->StrokeLine(BPoint(rect.right, rect.top + 1.0f));
rect.InsetBy(1.0f, 1.0f);
// Filling
owner->SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR), B_LIGHTEN_MAX_TINT));
if (IsSelected()) {
owner->SetHighColor(tint_color(owner->HighColor(), B_DARKEN_1_TINT));
}
owner->FillRect(rect);
if (fStatus->progress != 0.0f) {
rect.right = rect.left + (float)ceil(fStatus->progress * (rect.Width() - 4)),
// Bevel
owner->SetHighColor(tint_color(fBarColor, B_LIGHTEN_2_TINT));
if (IsSelected()) {
owner->SetHighColor(tint_color(owner->HighColor(), B_DARKEN_1_TINT));
}
owner->StrokeLine(BPoint(rect.left, rect.bottom), BPoint(rect.left, rect.top));
owner->StrokeLine(BPoint(rect.right, rect.top));
owner->SetHighColor(tint_color(fBarColor, B_DARKEN_2_TINT));
if (IsSelected()) {
owner->SetHighColor(tint_color(owner->HighColor(), B_DARKEN_1_TINT));
}
owner->StrokeLine(BPoint(rect.left, rect.bottom), BPoint(rect.right, rect.bottom));
owner->StrokeLine(BPoint(rect.right, rect.top));
rect.InsetBy(1.0f, 1.0f);
// Filling
owner->SetHighColor(fBarColor);
if (IsSelected()) {
owner->SetHighColor(tint_color(owner->HighColor(), B_DARKEN_1_TINT));
}
owner->FillRect(rect);
}
fStatusLock->Unlock();
} else {
owner->DrawString("loading...", textLoc);
}
owner->PopState();
}

56
beos/TRTransfer.h Normal file
View file

@ -0,0 +1,56 @@
#ifndef TR_TRANSFER
#define TR_TRANSFER
#include <Entry.h>
#include <ListItem.h>
#include <Locker.h>
#include <String.h>
#include <View.h>
#include "transmission.h"
class TRTransfer : public BListItem {
public: // Construction and Controll methods.
TRTransfer(const char *fullpath, node_ref node);
~TRTransfer();
inline node_ref GetCachedNodeRef() { return cachedNodeRef; };
inline const char* GetCachedPath() { return cachedPath->String(); };
bool SetStatus(tr_stat_t *stat, bool shade);
public: // BListItem
virtual void Update(BView *owner, const BFont *font);
virtual void DrawItem(BView *owner, BRect frame, bool complete = false);
private:
/*
* Cached data. The items stored here are _NOT_ necessairly
* the torrent we'll be rendering. It's likely they will be,
* but NOT guaranteed. They are not used for anything relating
* to rendering.
*
* Specifically we needed a way to cache the node_ref and
* reverse-lookup the node from the string path in the
* transmission structs. This seemed the logical place to store
* that information, since it ends up in a BList(View).
*/
node_ref cachedNodeRef;
BString *cachedPath;
private: // Private members used for rendering.
float fBaselineOffset;
float fLineSpacing;
BLocker *fStatusLock;
tr_stat_t *fStatus;
rgb_color fBarColor;
char* fTimeStr;
char* fTransStr;
bool fShade;
};
#endif /* TR_TRANSFER */

457
beos/TRWindow.cpp Normal file
View file

@ -0,0 +1,457 @@
#include "TRWindow.h"
#include <stdio.h>
#include <Alert.h>
#include <Application.h>
#include <File.h>
#include <MenuBar.h>
#include <MenuItem.h>
#include <NodeMonitor.h>
#include <ScrollView.h>
#include <String.h>
#include <malloc.h>
#include "Prefs.h"
#include "TRApplication.h"
#include "TRTransfer.h"
#include "TRInfoWindow.h"
/**
* The Transmission Window! Yay!
*/
TRWindow::TRWindow() : BWindow(BRect(10, 40, 350, 110), "Transmission", B_TITLED_WINDOW,
B_ASYNCHRONOUS_CONTROLS , B_CURRENT_WORKSPACE)
{
engine = NULL;
Prefs prefs(TRANSMISSION_SETTINGS);
BRect *rectFrame = new BRect();
if (prefs.FindRect("window.frame", rectFrame) == B_OK) {
MoveTo(rectFrame->LeftTop());
ResizeTo(rectFrame->Width(), rectFrame->Height());
} else {
rectFrame->Set(10, 40, 350, 110);
}
Lock();
BRect viewRect(0, 0, rectFrame->Width(), rectFrame->Height());
BMenuBar *menubar = new BMenuBar(viewRect, "MenuBar");
BMenu *menu = new BMenu("File");
menu->AddItem(new BMenuItem("Open", new BMessage(TR_OPEN), 'O', B_COMMAND_KEY));
menu->FindItem(TR_OPEN)->SetTarget(be_app_messenger); // send OPEN to the be_app.
menu->AddSeparatorItem();
menu->AddItem(new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED), 'Q', B_COMMAND_KEY));
menubar->AddItem(menu);
menu = new BMenu("Torrent");
menu->AddItem(new BMenuItem("Get Info", new BMessage(TR_INFO), 'I', B_COMMAND_KEY));
menu->FindItem(TR_INFO)->SetEnabled(false);
menu->AddSeparatorItem();
menu->AddItem(new BMenuItem("Resume", new BMessage(TR_RESUME)));
menu->AddItem(new BMenuItem("Pause", new BMessage(TR_PAUSE)));
menu->AddItem(new BMenuItem("Remove", new BMessage(TR_REMOVE)));
menubar->AddItem(menu);
menu = new BMenu("Tools");
menu->AddItem(new BMenuItem("Settings", new BMessage(TR_SETTINGS)));
menu->FindItem(TR_SETTINGS)->SetTarget(be_app_messenger);
menu->AddSeparatorItem();
menu->AddItem(new BMenuItem("About Transmission", new BMessage(B_ABOUT_REQUESTED)));
menu->FindItem(B_ABOUT_REQUESTED)->SetTarget(be_app_messenger);
menubar->AddItem(menu);
AddChild(menubar);
SetKeyMenuBar(menubar);
// TODO: Tool Bar? (Well after everything is working based on Menus)
// Setup the transfers ListView
viewRect.Set(2, menubar->Frame().bottom + 3, rectFrame->Width() - 2 - B_V_SCROLL_BAR_WIDTH, rectFrame->Height() - 2);
transfers = new BListView(viewRect, "TorrentList", B_SINGLE_SELECTION_LIST, B_FOLLOW_ALL);
transfers->SetSelectionMessage(new BMessage(TR_SELECT));
AddChild(new BScrollView("TransferScroller", transfers, B_FOLLOW_ALL, 0, false, true));
Unlock();
delete rectFrame;
// Bring up the Transmission Engine
engine = tr_init();
LoadSettings();
UpdateList(-1, true);
// Start the message loop without showing the window.
Hide();
Show();
}
TRWindow::~TRWindow() {
tr_close(engine);
stop_watching(this);
}
void TRWindow::LoadSettings() {
if (engine != NULL) {
Prefs prefs(TRANSMISSION_SETTINGS);
int32 bindPort;
if (prefs.FindInt32("transmission.bindPort", &bindPort) != B_OK) {
bindPort = 9000;
prefs.SetInt32("transmission.bindPort", bindPort);
}
tr_setBindPort(engine, (int)bindPort);
int32 uploadLimit;
if (prefs.FindInt32("transmission.uploadLimit", &uploadLimit) != B_OK) {
uploadLimit = 20;
prefs.SetInt32("transmission.uploadLimit", uploadLimit);
}
tr_setUploadLimit(engine, (int)uploadLimit);
}
}
/**
* Rescans the active Torrents folder, and will add all the torrents there to the
* engine.
*/
void TRWindow::RescanTorrents() {
if (Lock()) {
TRApplication *app = dynamic_cast<TRApplication*>(be_app);
BEntry *torrentEntry = new BEntry();
status_t err;
if (app->TorrentDir()->InitCheck() == B_OK) {
err = app->TorrentDir()->Rewind();
while (err == B_OK) {
err = app->TorrentDir()->GetNextEntry(torrentEntry, true);
if (err != B_ENTRY_NOT_FOUND) {
AddEntry(torrentEntry);
}
}
}
delete torrentEntry;
Unlock();
}
}
/**
* Adds the file specified by *torrent to the Transmission engine.
* Then adds a new TRTransfer item in the transfers list.
* This item holds cached information about the torrent entry and node.
* These TRTransmission items are _NOT_ guaranteed to render the entry
* they were created from.
*/
void TRWindow::AddEntry(BEntry *torrent) {
node_ref node;
if (torrent->GetNodeRef(&node) == B_OK) {
if (watch_node(&node, B_WATCH_NAME, this) == B_OK) {
BPath path;
torrent->GetPath(&path);
// Try adding the torrent to the engine.
int addStatus = tr_torrentInit(engine, path.Path());
if (addStatus == 0 && Lock()) { // Success. Add the TRTorrent item.
transfers->AddItem(new TRTransfer(path.Path(), node));
// Start the newly added torrent.
worker_info *startData = (worker_info*)calloc(1, sizeof(worker_info));
startData->window = this;
startData->index = tr_torrentCount(engine) - 1;
thread_id start_thread = spawn_thread(TRWindow::AsynchStartTorrent, "BirthCanal",
B_NORMAL_PRIORITY, (void *)startData);
if (!((start_thread) < B_OK)) {
resume_thread(start_thread);
} else { // Fallback and start the old way.
StartTorrent(startData->index);
free(startData);
}
Unlock();
} else {
bool duplicate = false;
TRTransfer* tr;
for (int32 i = 0; i < transfers->CountItems(); i++) {
tr = (TRTransfer*)transfers->ItemAt(i);
if (tr->GetCachedNodeRef() == node) {
duplicate = true;
}
}
if (!duplicate) {
BString errmsg("An error occurred trying to read ");
char namebuf[B_FILE_NAME_LENGTH];
torrent->GetName(namebuf);
errmsg << namebuf;
errmsg << ".";
BAlert *error = new BAlert("Error Opening Torrent",
errmsg.String(),
"Ok", NULL, NULL,
B_WIDTH_AS_USUAL, B_WARNING_ALERT);
error->Go();
torrent->Remove();
}
}
}
}
}
void TRWindow::MessageReceived(BMessage *msg) {
/*
* The only messages we receive from the node_monitor are if we need to
* stop watching the node. Basically, if it's been moved or removed we stop.
*/
if (msg->what == B_NODE_MONITOR) {
node_ref node;
ino_t fromDir;
ino_t toDir;
int32 opcode;
if ((msg->FindInt32("opcode", &opcode) == B_OK) &&
(msg->FindInt64("node", &node.node) == B_OK) &&
(msg->FindInt32("device", &node.device) == B_OK))
{
bool stop = (opcode == B_ENTRY_REMOVED);
if (stop) {
msg->FindInt64("directory", &toDir);
} else { // It must have moved.
stop = ((msg->FindInt64("from directory", &fromDir) == B_OK) &&
(msg->FindInt64("to directory", &toDir) == B_OK) &&
(toDir != fromDir));
}
if (stop) {
watch_node(&node, B_STOP_WATCHING, this);
/* Find the full path from the TRTorrents.
* The index of the TRTorrent that is caching the information
* IS NOT the index of the torrent in the engine. These are
* Totally decoupled, due to the way transmission is written.
*/
char path[B_FILE_NAME_LENGTH];
TRTransfer* item;
for (int32 i = 0; i < transfers->CountItems(); i++) {
item = (TRTransfer*)transfers->ItemAt(i);
if (item->GetCachedNodeRef() == node) {
strcpy(path, item->GetCachedPath());
}
}
// Look for the torrent info in the engine with the matching
// path name.
tr_stat_t *stats;
tr_torrentStat(engine, &stats);
int index;
for (index = 0; index < tr_torrentCount(engine); index++) {
if (strcmp(stats[index].info.torrent, path) == 0) {
tr_torrentClose(engine, index);
transfers->RemoveItem(index);
break;
}
}
free(stats);
}
}
} else if (msg->what == TR_INFO) {
// Display an Info Window.
tr_stat_t *s;
tr_torrentStat(engine, &s);
TRInfoWindow *info = new TRInfoWindow(s[transfers->CurrentSelection()]);
info->MoveTo(Frame().LeftTop() + BPoint(20, 25));
info->Show();
} else if (msg->what == TR_SELECT) {
// Setup the Torrent Menu enabled / disabled state.
int32 selection;
msg->FindInt32("index", &selection);
UpdateList(selection, true);
} else if (msg->what == TR_RESUME) {
worker_info *startData = (worker_info*)calloc(1, sizeof(worker_info));
startData->window = this;
startData->index = (int)transfers->CurrentSelection();
thread_id start_thread = spawn_thread(TRWindow::AsynchStartTorrent, "BirthCanal",
B_NORMAL_PRIORITY, (void *)startData);
if (!((start_thread) < B_OK)) {
resume_thread(start_thread);
} else { // Fallback and start the old way.
StartTorrent(startData->index);
free(startData);
}
} else if (msg->what == TR_PAUSE) {
worker_info *stopData = (worker_info*)calloc(1, sizeof(worker_info));
stopData->window = this;
stopData->index = (int)transfers->CurrentSelection();
thread_id stop_thread = spawn_thread(TRWindow::AsynchStopTorrent, "InUtero",
B_NORMAL_PRIORITY, (void *)stopData);
if (!((stop_thread) < B_OK)) {
resume_thread(stop_thread);
} else { // Fallback and stop it the old way.
StopTorrent(stopData->index);
free(stopData);
}
} else if (msg->what == TR_REMOVE) {
int32 index = transfers->CurrentSelection();
tr_torrentClose(engine, (int)index);
// Remove the file from the filesystem.
TRTransfer *item = (TRTransfer*)transfers->RemoveItem(index);
BEntry *entry = new BEntry(item->GetCachedPath(), true);
entry->Remove();
delete entry;
delete item;
UpdateList(transfers->CurrentSelection(), true);
} else if (msg->what == B_SIMPLE_DATA) {
be_app->RefsReceived(msg);
}
BWindow::MessageReceived(msg);
}
bool TRWindow::QuitRequested() {
bool quit = false;
bool running = false;
tr_stat_t *s;
int max = tr_torrentStat(engine, &s);
for (int i = 0; i < max && !running; i++) {
running = (s[i].status &
(TR_STATUS_CHECK | TR_STATUS_DOWNLOAD | TR_STATUS_SEED));
}
free(s);
if (running) {
BString quitMsg("");
quitMsg << "There's " << max << " torrent";
if (max > 1) {
quitMsg << "s";
}
quitMsg << " currently running.\n"
<< "What would you like to do?";
BAlert *confirmQuit = new BAlert("Confirm Quit", quitMsg.String(),
"Cancel", "Quit", NULL,
B_WIDTH_AS_USUAL, B_WARNING_ALERT);
quit = (confirmQuit->Go() == 1);
} else {
quit = true;
}
if (quit) {
Prefs *prefs = new Prefs(TRANSMISSION_SETTINGS);
prefs->SetRect("window.frame", Frame());
delete prefs;
for (int i = 0; i < tr_torrentCount(engine); i++) {
tr_torrentStop(engine, i);
}
be_app->PostMessage(new BMessage(B_QUIT_REQUESTED));
}
return quit;
}
void TRWindow::FrameResized(float width, float height) {
transfers->Invalidate();
}
/**
* Called from the StopTorrent thread.
*/
void TRWindow::StopTorrent(int index) {
tr_torrentStop(engine, index);
UpdateList(index, true);
}
/**
* Called from StartTorrent thread.
*/
void TRWindow::StartTorrent(int index) {
// Read the settings.
BString folder("");
Prefs *prefs = new Prefs(TRANSMISSION_SETTINGS);
if (prefs->FindString("download.folder", &folder) != B_OK) {
prefs->SetString("download.folder", "/boot/home/Downloads");
folder << "/boot/home/Downloads";
}
tr_torrentSetFolder(engine, index, folder.String());
tr_torrentStart(engine, index);
if (transfers->CurrentSelection() >= 0) {
UpdateList(index, true);
}
delete prefs;
}
/**
* Called from the be_app Pulse();
* This will update the data structures that the TRTorrents use to render,
* and invalidate the view.
*/
void TRWindow::UpdateList(int32 selection = -1, bool menus = true) {
bool running = false;
tr_stat_t * s;
int i = 0;
int max = tr_torrentStat(engine, &s);
bool invalid[max];
for (i = 0; i < max; i++) {
invalid[i] = ((TRTransfer*)transfers->ItemAt(i))->SetStatus(&(s[i]), (i % 2 != 0));
if (menus && i == (int)selection) {
running = (s[selection].status &
(TR_STATUS_CHECK | TR_STATUS_DOWNLOAD | TR_STATUS_SEED));
}
}
free(s);
if (menus) {
KeyMenuBar()->FindItem(TR_INFO)->SetEnabled(selection >= 0);
KeyMenuBar()->FindItem(TR_RESUME)->SetEnabled(selection >= 0 && !running);
KeyMenuBar()->FindItem(TR_PAUSE)->SetEnabled(selection >= 0 && running);
KeyMenuBar()->FindItem(TR_REMOVE)->SetEnabled(selection >= 0 && !running);
}
if (Lock()) {
for (i = 0; i < max; i++) {
if (invalid[i]) {
transfers->InvalidateItem(i);
}
}
Unlock();
}
}
/**
* Thread Function to stop Torrents. This can be expensive and causes the event loop to
* choke.
*/
int32 TRWindow::AsynchStopTorrent(void *data) {
worker_info* stopData = (worker_info*)data;
stopData->window->StopTorrent(stopData->index);
free(stopData);
return B_OK;
}
/**
* Thread Function to start Torrents. This can be expensive and causes the event loop to
* choke.
*/
int32 TRWindow::AsynchStartTorrent(void *data) {
worker_info* startData = (worker_info*)data;
startData->window->StartTorrent(startData->index);
free(startData);
return B_OK;
}

67
beos/TRWindow.h Normal file
View file

@ -0,0 +1,67 @@
#ifndef TR_WIND
#define TR_WIND
#include <Entry.h>
#include <FilePanel.h>
#include <ListView.h>
#include <Window.h>
#include "transmission.h"
#include "TRPrefsWindow.h"
#define TR_INFO 'tNfo'
#define TR_RESUME 'tRes'
#define TR_PAUSE 'tPse'
#define TR_REMOVE 'tRmv'
#define TR_SELECT 'tSel'
#define TR_SETTINGS 'tSet'
/**
* Transmission Window.
*/
class TRWindow : public BWindow {
public: // BWindow
TRWindow();
~TRWindow();
virtual void MessageReceived(BMessage *msg);
virtual bool QuitRequested();
virtual void FrameResized(float width, float height);
public: // TRWindow
void AddEntry(BEntry *torrent);
void UpdateList(int32 selection, bool menus);
void LoadSettings();
void StopTorrent(int index);
void StartTorrent(int index);
static int32 AsynchStopTorrent(void *data);
static int32 AsynchStartTorrent(void *data);
void RescanTorrents();
private:
BListView *transfers;
BFilePanel *openPanel;
tr_handle_t *engine;
TRPrefsWindow *fSettings;
};
/**
* Used to pass info off to the worker thread that runs AsynchStopTorrent
*/
struct worker_info {
TRWindow *window;
int index;
};
#endif /* TR_WIND */

BIN
beos/Transmission.rsrc Normal file

Binary file not shown.

33
beos/libPrefs/Prefs.h Normal file
View file

@ -0,0 +1,33 @@
#ifndef LIBPREFS
#define LIBPREFS
#include <Message.h>
#include <File.h>
#include <FindDirectory.h>
#include <Path.h>
class Prefs: public BMessage {
public:
Prefs(const char *fileName);
~Prefs();
inline status_t InitCheck(void) { return status; };
void Save();
status_t SetBool(const char *name, bool b);
status_t SetInt8(const char *name, int8 i);
status_t SetInt16(const char *name, int16 i);
status_t SetInt32(const char *name, int32 i);
status_t SetInt64(const char *name, int64 i);
status_t SetFloat(const char *name, float f);
status_t SetDouble(const char *name, double d);
status_t SetString(const char *name, const char *string);
status_t SetPoint(const char *name, BPoint p);
status_t SetRect(const char *name, BRect r);
status_t SetMessage(const char *name, const BMessage *message);
status_t SetFlat(const char *name, const BFlattenable *obj);
private:
BPath path;
status_t status;
};
#endif

BIN
beos/libPrefs/libPrefs.a Normal file

Binary file not shown.

107
beos/makefile Normal file
View file

@ -0,0 +1,107 @@
## BeOS Generic Makefile v2.0 ##
## Fill in this file to specify the project being created, and the referenced
## makefile-engine will do all of the hard work for you. This handles both
## Intel and PowerPC builds of the BeOS.
## Application Specific Settings ---------------------------------------------
# specify the name of the binary
NAME=Transmission
# specify the type of binary
# APP: Application
# SHARED: Shared library or add-on
# STATIC: Static library archive
# DRIVER: Kernel Driver
TYPE= APP
# specify the source files to use
# full paths or paths relative to the makefile can be included
# all files, regardless of directory, will have their object
# files created in the common object directory.
# Note that this means this makefile will not work correctly
# if two source files with the same name (source.c or source.cpp)
# are included from different directories. Also note that spaces
# in folder names do not work well with this makefile.
SRCS= \
TRApplication.cpp\
TRWindow.cpp\
TRTransfer.cpp\
TRPrefsWindow.cpp\
TRInfoWindow.cpp\
#
# specify the resource files to use
# full path or a relative path to the resource file can be used.
RSRCS= Transmission.rsrc
# specify additional libraries to link against
# there are two acceptable forms of library specifications
# - if your library follows the naming pattern of:
# libXXX.so or libXXX.a you can simply specify XXX
# library: libbe.so entry: be
#
# - if your library does not follow the standard library
# naming scheme you need to specify the path to the library
# and it's name
# library: my_lib.a entry: my_lib.a or path/my_lib.a
ifeq ($(wildcard /boot/develop/headers/be/bone/arpa/inet.h),)
LIBS = be net tracker transmission Prefs
else
LIBS = be bind socket tracker transmission Prefs
endif
# specify additional paths to directories following the standard
# libXXX.so or libXXX.a naming scheme. You can specify full paths
# or paths relative to the makefile. The paths included may not
# be recursive, so include all of the paths where libraries can
# be found. Directories where source files are found are
# automatically included.
LIBPATHS= ../libtransmission ./libPrefs
# additional paths to look for system headers
# thes use the form: #include <header>
# source file directories are NOT auto-included here
SYSTEM_INCLUDE_PATHS =
# additional paths to look for local headers
# thes use the form: #include "header"
# source file directories are automatically included
LOCAL_INCLUDE_PATHS = ../libtransmission ./libPrefs
# specify the level of optimization that you desire
# NONE, SOME, FULL
OPTIMIZE= SOME
# specify any preprocessor symbols to be defined. The symbols
# will be set to a value of 1. For example specify DEBUG if you want
# DEBUG=1 to be set when compiling.
DEFINES= SYS_BEOS
# specify special warning levels
# if unspecified default warnings will be used
# NONE = supress all warnings
# ALL = enable all warnings
WARNINGS = ALL
# specify whether image symbols will be created
# so that stack crawls in the debugger are meaningful
# if TRUE symbols will be created
SYMBOLS = TRUE
# specify debug settings
# if TRUE will allow application to be run from
# a source-level debugger
DEBUGGER = FALSE
# specify additional compiler flags for all files
COMPILER_FLAGS = -fno-defer-pop
# specify additional linker flags
LINKER_FLAGS =
all: default
## include the makefile-engine
include /boot/develop/etc/makefile-engine

20
configure vendored
View file

@ -124,6 +124,18 @@ case $SYSTEM in
BeOS)
DEFINES="$DEFINES SYS_BEOS"
CC="gcc"
MACHINE=`uname -m`
case $MACHINE in
BePC) # BeOS on x86
CPU="x86"
;;
*)
CPU="ppc"
;;
esac
SYSTEM="$SYSTEM / $CPU"
RELEASE=`uname -r`
case $RELEASE in
6.0|5.0.4) # Zeta or R5 / BONE beta 7
@ -137,7 +149,8 @@ case $SYSTEM in
;;
*)
echo "Unsupported BeOS version"
exit 1 ;;
exit 1
;;
esac
;;
@ -205,6 +218,11 @@ HDRS += $OPENSSL_PREFIX/include ;
LINKFLAGS += -L$OPENSSL_PREFIX/lib ;
EOF
fi
if [ -n "$CPU" ]; then
cat >> config.jam << EOF
CPU = $CPU ;
EOF
fi
echo
echo "To build Transmission, run 'jam'."

View file

@ -3,7 +3,7 @@ SubDir TOP libtransmission ;
LIBTRANSMISSION_SRC =
transmission.c bencode.c net.c tracker.c peer.c inout.c
metainfo.c sha1.c utils.c upload.c fdlimit.c clients.c
completion.c ;
completion.c platform.c ;
Library libtransmission.a : $(LIBTRANSMISSION_SRC) ;
ObjectDefines $(LIBTRANSMISSION_SRC) : __TRANSMISSION__ ;

View file

@ -0,0 +1,59 @@
/******************************************************************************
* Copyright (c) 2005 Eric Petit
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*****************************************************************************/
#include "platform.h"
#ifdef SYS_BEOS
/***********************************************************************
* tr_init_beos
***********************************************************************
* Puts the prefsDirectory in the right place.
**********************************************************************/
void tr_init_beos( tr_handle_t * h )
{
int32 length = 0;
char path[B_FILE_NAME_LENGTH];
find_directory( B_USER_SETTINGS_DIRECTORY, dev_for_path("/boot"),
true, path, length );
snprintf( h->prefsDirectory, B_FILE_NAME_LENGTH,
"%s/Transmission", path );
mkdir( h->prefsDirectory, 0755 );
}
#endif
/***********************************************************************
* tr_init_platform
***********************************************************************
* Setup the prefsDirectory for the current platform.
**********************************************************************/
void tr_init_platform( tr_handle_t *h )
{
#ifdef SYS_BEOS
tr_init_beos( h );
#else
snprintf( h->prefsDirectory, sizeof( h->prefsDirectory ),
"%s/.transmission", getenv( "HOME" ) );
mkdir( h->prefsDirectory, 0755 );
#endif
}

View file

@ -0,0 +1,42 @@
#ifndef TR_PLATFORM_H
#define TR_PLATFORM_H 1
/******************************************************************************
* Copyright (c) 2005 Eric Petit
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*****************************************************************************/
#include "transmission.h"
#ifdef SYS_BEOS
#include <fs_info.h>
#include <FindDirectory.h>
#endif
/***********************************************************************
* tr_init_platform
***********************************************************************
* Performs some platform specific initialization.
**********************************************************************/
void tr_init_platform( tr_handle_t *h );
#endif

View file

@ -22,6 +22,12 @@
#include "transmission.h"
#ifdef __cplusplus
extern "C" {
#endif
#include "platform.h"
/***********************************************************************
* Local prototypes
**********************************************************************/
@ -67,10 +73,8 @@ tr_handle_t * tr_init()
h->bindPort = TR_DEFAULT_PORT;
snprintf( h->prefsDirectory, sizeof( h->prefsDirectory ),
"%s/.transmission", getenv( "HOME" ) );
mkdir( h->prefsDirectory, 0755 );
tr_init_platform( h );
return h;
}
@ -488,6 +492,7 @@ static void downloadLoop( void * _tor )
tr_dbg( "Thread started" );
#ifdef SYS_BEOS
rename_thread(tor->thread, "torrent-tx");
/* This is required because on BeOS, SIGINT is sent to each thread,
which kills them not nicely */
signal( SIGINT, SIG_IGN );
@ -575,3 +580,7 @@ static float rateUpload( tr_torrent_t * tor )
{
return rateGeneric( tor->dates, tor->uploaded );
}
#ifdef __cplusplus
}
#endif

View file

@ -23,10 +23,19 @@
#ifndef TR_TRANSMISSION_H
#define TR_TRANSMISSION_H 1
#ifdef __cplusplus
extern "C" {
#endif
#include <inttypes.h>
#define SHA_DIGEST_LENGTH 20
#define MAX_PATH_LENGTH 1024
#ifdef SYS_BEOS
# include <StorageDefs.h>
# define MAX_PATH_LENGTH B_FILE_NAME_LENGTH
#else
# define MAX_PATH_LENGTH 1024
#endif
#define TR_MAX_TORRENT_COUNT 50
#define TR_DEFAULT_PORT 9090
@ -234,4 +243,8 @@ struct tr_stat_s
# include "internal.h"
#endif
#ifdef __cplusplus
}
#endif
#endif