source: trunk/beos/TRApplication.cpp @ 4182

Last change on this file since 4182 was 4182, checked in by charles, 15 years ago

add explicit BSD licensing and copyright ownership by Bryan Varner, so the Debian packagers will be satisfied about is free software status. (#528)

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