source: trunk/beos/TRApplication.cpp @ 192

Last change on this file since 192 was 192, checked in by titer, 16 years ago

Handle B_ARGV_RECEIVED messages, apparently needed for browser (and
command line) interaction.

Patch by Alan Westbrook.

File size: 8.3 KB
Line 
1#include "TRApplication.h"
2
3#include <stdio.h>
4#include <string.h>
5#include <stdlib.h>
6
7#include <AppFileInfo.h>
8#include <Alert.h>
9#include <Bitmap.h>
10#include <File.h>
11#include <FindDirectory.h>
12#include <Messenger.h>
13#include <Mime.h>
14#include <Path.h>
15#include <String.h>
16#include <Resources.h>
17#include <Roster.h>
18
19int main(int argc, char** argv) {
20        TRApplication *app = new TRApplication();
21        if (app->InitCheck() == B_OK) {
22                app->Run();
23        } else {
24                BString errMsg("");
25                errMsg << "The following error occurred loading Transmission:\n"
26                       << strerror(app->InitCheck());
27                BAlert *ohNo = new BAlert("Transmission Error", 
28                        errMsg.String(),
29                        "OK", NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT);
30                ohNo->Go();
31        }
32        delete app;
33       
34        return (0);
35}
36
37
38TRApplication::TRApplication() : BApplication(APP_SIG) {
39        status_t err = B_OK;
40        torrentDir = NULL;
41       
42        // Install Mime types if necessary.
43        BMimeType torrentType("application/x-bittorrent");
44        if (torrentType.InitCheck() == B_OK) {
45                if (!torrentType.IsInstalled()) {
46                        fprintf(stderr, "Installing mime type...\n");
47                        // Icon
48                        app_info runningInfo;
49                        GetAppInfo(&runningInfo);
50                        BFile appFile(&(runningInfo.ref), B_READ_ONLY);
51                        BResources res(&appFile, false);
52                       
53                        size_t len = 0;
54                        BBitmap *icon = NULL;
55                        void *iconBits = NULL;
56                       
57                        iconBits = res.FindResource('ICON', "BEOS:L:application/x-bittorrent", &len);
58                        if (iconBits) {
59                                icon = new BBitmap(BRect(0, 0, 31, 31), B_CMAP8);
60                                icon->SetBits(iconBits, len, 0, B_CMAP8);
61                                torrentType.SetIcon(icon, B_LARGE_ICON);
62                                delete icon;
63                                icon = NULL;
64                                len = 0;
65                        }
66                       
67                        iconBits = res.FindResource('ICON', "BEOS:M:application/x-bittorrent", &len);
68                        if (iconBits) {
69                                icon = new BBitmap(BRect(0, 0, 15, 15), B_CMAP8);
70                                icon->SetBits(iconBits, len, 0, B_CMAP8);
71                                torrentType.SetIcon(icon, B_MINI_ICON);
72                                delete icon;
73                        }
74                       
75                        // Extensions
76                        BMessage extensions;
77                        extensions.AddString("extensions", "torrent");
78                        torrentType.SetFileExtensions(&extensions);
79                       
80                        torrentType.SetShortDescription("BitTorrent Meta File");
81                        torrentType.SetLongDescription("BitTorrent Protocol Meta File (http://www.bittorrent.com)");
82                       
83                        // Set Preferred Application
84                        torrentType.SetPreferredApp(APP_SIG, B_OPEN);
85                       
86                        torrentType.Install();
87                }
88        }
89       
90        // Create Settings folder and structure
91        BPath settingsPath;
92        err = find_directory(B_USER_SETTINGS_DIRECTORY, &settingsPath, false);
93        if (err == B_OK) {
94                BDirectory settings(settingsPath.Path());
95                BDirectory *trSettings = new BDirectory();
96               
97                err = settings.CreateDirectory("Transmission", trSettings);
98                if (err == B_FILE_EXISTS) {
99                        err = trSettings->SetTo(&settings, "Transmission");
100                }
101               
102                if (err == B_OK) {
103                        torrentDir = new BDirectory();
104                        err = trSettings->CreateDirectory("Torrents", torrentDir);
105                        if (err != B_OK) {
106                                torrentDir->SetTo(trSettings, "Torrents");
107                        }
108                }
109                delete trSettings;
110        }
111       
112        // Create window
113        window = new TRWindow();
114        window->RescanTorrents();
115        settings = new TRPrefsWindow();
116       
117        openPanel = new BFilePanel();
118        openPanel->SetRefFilter(new TRFilter());
119}
120
121
122TRApplication::~TRApplication() {
123        if (window->Lock()) {
124                window->Quit();
125        }
126        if (settings->Lock()) {
127                settings->Quit();
128        }
129       
130        if (openPanel != NULL) {
131                delete openPanel;
132        }
133       
134        if (torrentDir != NULL) {
135                delete torrentDir;
136        }
137}
138
139
140/**
141 * Checks to make sure our Settings directory structure is in place.
142 * If this fails, then we need to display an alert and vomit.
143 */
144status_t TRApplication::InitCheck() {
145        if (torrentDir != NULL) {
146                return torrentDir->InitCheck();
147        }
148        return B_ERROR;
149}
150
151
152void TRApplication::AboutRequested() {
153        // Read the application version info
154        app_info runningInfo;
155        GetAppInfo(&runningInfo);
156        BFile appFile(&(runningInfo.ref), B_READ_ONLY);
157        BAppFileInfo appInfo(&appFile);
158        version_info vInfo;
159        appInfo.GetVersionInfo(&vInfo, B_APP_VERSION_KIND);
160       
161        BString aboutMsg("");
162        aboutMsg << "Transmission\n"
163                 << "Version " << vInfo.major << "." << vInfo.middle << "." << vInfo.minor << "\n"
164                 << "Eric Petit & Bryan Varner\n";
165        BAlert *aboutBox = new BAlert("About Transmission", aboutMsg.String(), "Close");
166        aboutBox->Go();
167}
168
169
170void TRApplication::ReadyToRun() {
171        SetPulseRate(500000);
172        window->Show();
173}
174
175
176void TRApplication::Pulse() {
177        window->UpdateList(-1, false);
178}
179
180
181/**
182 * When a ref is received, we copy each file that is to be opened into
183 * B_USER_SETTINGS/Transmission/Torrents
184 *
185 * Our window node_monitors this folder for added / removed torrent meta files.
186 *
187 * Each copy is performed in a seperate thread to avoid blocking / locking the app.
188 */
189void TRApplication::RefsReceived(BMessage *message) {
190        int32 count;
191        type_code code;
192        message->GetInfo("refs", &code, &count);
193        for (int i = 0; i < count; i++) {
194                entry_ref *ref = (entry_ref*)calloc(sizeof(entry_ref), 1);
195                if (message->FindRef("refs", i, ref) == B_OK) {
196                        thread_id cp_thread = spawn_thread(TRApplication::Copy, "TorrentDuper",
197                                                           B_NORMAL_PRIORITY, (void *)ref);
198                        if (!((cp_thread) < B_OK)) {
199                                resume_thread(cp_thread);
200                        }
201                }
202        }
203}
204
205/**
206 * Needed for browsers or command line interaction
207 */
208void TRApplication::ArgvReceived(int32 _argc, char** _argv) 
209{
210        entry_ref ref;
211        BMessage refs(B_REFS_RECEIVED);
212        for( int32 i = 0; i < _argc; ++i )
213        {
214                if( B_OK == get_ref_for_path(_argv[i], &ref) )
215                {
216                        refs.AddRef("refs", &ref);
217                }
218        }
219       
220        be_app_messenger.SendMessage(refs);
221}
222
223/**
224 * BMessage handling.
225 */
226void TRApplication::MessageReceived(BMessage *message) {
227        BApplication::MessageReceived(message);
228        /*
229         * When the copy of a torrent file is complete, we get a message
230         * signaling that we should add the now copied .torrent file to our Transfer Window.
231         */
232        if (message->what == TR_ADD) {
233                // Add the torrent to the window.
234                entry_ref torrentRef;
235                if (message->FindRef("torrent", &torrentRef) == B_OK) {
236                        BEntry *entry = new BEntry(&torrentRef, true);
237                        window->AddEntry(entry);
238                        delete entry;
239                }
240        /* Show the Open Dialog */
241        } else if (message->what == TR_OPEN) {
242                openPanel->Show();
243        } else if (message->what == TR_SETTINGS) {
244                settings->MoveTo(window->Frame().left + (window->Frame().Width() - settings->Frame().Width()) / 2, 
245                                 window->Frame().top + (window->Frame().Height() - settings->Frame().Height()) / 2);
246                       
247                settings->Show();
248        } else if (message->what == TR_RELOAD_SETTINGS) {
249                window->LoadSettings();
250        }
251}
252
253bool TRApplication::QuitRequested() {
254        return BApplication::QuitRequested();
255}
256
257/**
258 * Thread Function.
259 * The thread copies the original .torrent file into the torrents folder,
260 * then signals the window to load the torrent meta info from the copy.
261 * The torrent window will then node_monitor the file so that if it's removed
262 * the torrent will cease.
263 *
264 * Keeping the file copy in a separate thread keeps us from blocking up the
265 * rest of our program.
266 *
267 * This behavior lets us kill the original .torrent download from disc (which
268 * speaking as a user I have a tendency to do) but keep the meta around for
269 * Transmission to use later.
270 *
271 * If the user whacks the .torrent file from our settings folder, then we'll
272 * remove it from the list (node_monitor!) and if they remove it from our list
273 * we'll remove it from the file system.
274 */
275int32 TRApplication::Copy(void *data) {
276        entry_ref *ref = (entry_ref*)data;
277       
278        BFile source(ref, B_READ_ONLY);
279        BFile target(((TRApplication*)be_app)->TorrentDir(), ref->name, 
280                     B_WRITE_ONLY | B_CREATE_FILE | B_FAIL_IF_EXISTS);
281       
282        BEntry targetEntry(((TRApplication*)be_app)->TorrentDir(), ref->name);
283        entry_ref targetRef;
284        targetEntry.GetRef(&targetRef);
285       
286        // Only perform the copy if the target is freshly created. Everything is B_OK!
287        if (source.InitCheck() == B_OK && target.InitCheck() == B_OK) {
288                if (target.Lock() == B_OK) {
289                        char *buffer = (char*)calloc(1, 4096); // 4k data buffer.
290                        ssize_t read = 0;
291                        while ((read = source.Read(buffer, 4096)) > 0) {
292                                target.Write(buffer, read);
293                        }
294                        free(buffer);
295                        target.Unlock();
296                }
297        }
298       
299        BMessage msg(TR_ADD);
300        msg.AddRef("torrent", &targetRef);
301        BMessenger messenger(be_app);
302        messenger.SendMessage(&msg);
303       
304        free(ref);
305        return B_OK;
306}
307
308/**
309 * Filters the FilePanel for torrent files and directories.
310 */
311bool TRFilter::Filter(const entry_ref *ref, BNode *node, struct stat *st, const char *mimetype) {
312        return (node->IsDirectory() || 
313           (strcmp(mimetype, "application/x-bittorrent") == 0) ||
314           (strstr(ref->name, ".torrent") != NULL));
315
316}
Note: See TracBrowser for help on using the repository browser.