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:
parent
ce24506f5e
commit
616ae26efa
22 changed files with 1787 additions and 9 deletions
5
Jamfile
5
Jamfile
|
@ -50,4 +50,9 @@ else if $(GTK) = yes
|
|||
SubInclude TOP gtk ;
|
||||
}
|
||||
|
||||
if $(OS) = BEOS
|
||||
{
|
||||
BeOSBuild Transmission : libtransmission.a ;
|
||||
}
|
||||
|
||||
SubInclude TOP libtransmission ;
|
||||
|
|
19
Jamrules
19
Jamrules
|
@ -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
298
beos/TRApplication.cpp
Normal 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
50
beos/TRApplication.h
Normal 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
93
beos/TRInfoWindow.cpp
Normal 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
22
beos/TRInfoWindow.h
Normal 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
165
beos/TRPrefsWindow.cpp
Normal 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
34
beos/TRPrefsWindow.h
Normal 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
235
beos/TRTransfer.cpp
Normal 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
56
beos/TRTransfer.h
Normal 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
457
beos/TRWindow.cpp
Normal 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
67
beos/TRWindow.h
Normal 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
BIN
beos/Transmission.rsrc
Normal file
Binary file not shown.
33
beos/libPrefs/Prefs.h
Normal file
33
beos/libPrefs/Prefs.h
Normal 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
BIN
beos/libPrefs/libPrefs.a
Normal file
Binary file not shown.
107
beos/makefile
Normal file
107
beos/makefile
Normal 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
20
configure
vendored
|
@ -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'."
|
||||
|
|
|
@ -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__ ;
|
||||
|
|
59
libtransmission/platform.c
Normal file
59
libtransmission/platform.c
Normal 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
|
||||
}
|
42
libtransmission/platform.h
Normal file
42
libtransmission/platform.h
Normal 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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue