source: trunk/beos/TRApplication.cpp @ 2549

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

Get BeOS client building on Zeta 1.21 thanks to patches by Fredrik Modéen

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