Codebase list nzbget / 8ba8782
New upstream version 19.1~r2031+dfsg Andreas Moog 6 years ago
89 changed file(s) with 67 addition(s) and 9144 deletion(s). Raw diff Collapse all Expand all
+0
-25
.gitattributes less more
0 * text=auto
1
2 # Use CRLF for certain Windows files.
3 *.vcproj eol=crlf
4 *.sln eol=crlf
5 *.bat eol=crlf
6 README-WINDOWS.txt eol=crlf
7 nzbget-setup.nsi eol=crlf
8 windows/package-info.json eol=crlf
9 windows/resources/resource.h eol=crlf
10 windows/resources/nzbget.rc eol=crlf
11
12 # Configure GitHub's language detector
13 lib/* linguist-vendored linguist-language=C++
14 webui/lib/* linguist-vendored
15 Makefile.in linguist-vendored
16 configure linguist-vendored
17 config.sub linguist-vendored
18 aclocal.m4 linguist-vendored
19 config.guess linguist-vendored
20 depcomp linguist-vendored
21 install-sh linguist-vendored
22 missing linguist-vendored
23 configure.ac linguist-vendored=false
24 Makefile.am linguist-vendored=false
+0
-66
.gitignore less more
0 # Compiled Object files
1 *.slo
2 *.lo
3 *.o
4 *.obj
5
6 # Precompiled Headers
7 *.gch
8 *.pch
9
10 # Compiled Dynamic libraries
11 *.so
12 *.dylib
13 *.dll
14
15 # Compiled Static libraries
16 *.lai
17 *.la
18 *.a
19 *.lib
20
21 # Executables
22 *.exe
23 *.out
24
25 # GNU Autotools
26 .deps/
27 config.h
28 config.log
29 config.status
30 Makefile
31 stamp-h1
32 autom4te.cache/
33
34 # Visual Studio User-specific files
35 *.suo
36 *.user
37 *.userosscache
38 *.sln.docstates
39 .vs/
40 ipch/
41 *.aps
42 *.ncb
43 *.opensdf
44 *.sdf
45 *.cachefile
46 *.ilk
47 *.pch
48 *.pdb
49 *.pgc
50 *.pgd
51 *.rsp
52 *.sbr
53 *.vspscc
54 *.vssscc
55 *.pidb
56 *.svclog
57 *.scc
58 *.sln
59
60 # NZBGet specific
61 nzbget
62 code_revision.cpp
63 *.temp
64 *.pyc
65 pytest.ini
+0
-55
.travis.yml less more
0 sudo: required
1 dist: trusty
2 language: cpp
3
4 matrix:
5 include:
6
7 - compiler: gcc
8 addons:
9 apt:
10 sources:
11 - ubuntu-toolchain-r-test
12 packages:
13 - g++-5
14 - unrar
15 env:
16 - COMPILER=g++-5
17
18 - compiler: gcc
19 addons:
20 apt:
21 sources:
22 - ubuntu-toolchain-r-test
23 packages:
24 - g++-4.9
25 - unrar
26 env:
27 - COMPILER=g++-4.9
28
29 - compiler: gcc
30 addons:
31 apt:
32 packages:
33 - unrar
34 env:
35 - COMPILER=g++-4.8
36 - CXXFLAGS="-std=c++11 -O2 -s"
37 - CONFIGUREOPTS="--disable-cpp-check"
38
39 - compiler: clang
40 addons:
41 apt:
42 sources:
43 - ubuntu-toolchain-r-test
44 - llvm-toolchain-precise-3.6
45 packages:
46 - clang-3.6
47 - unrar
48 env:
49 - COMPILER=clang++-3.6
50
51 script:
52 - $COMPILER --version
53 - CXX=$COMPILER ./configure $CONFIGUREOPTS --enable-tests && make
54 - ./nzbget --tests
0 nzbget-19.1:
1 - please see repository change log at
2 https://github.com/nzbget/nzbget/commits/develop
3
04 nzbget-19.0:
15 - unpack during downloading:
26 - downloaded files can now be unpacked as soon as every archive part is
+0
-18
README.md less more
0 # NZBGet #
1 [![License](https://img.shields.io/badge/license-GPL-blue.svg)](http://www.gnu.org/licenses/)
2 [![Build Status](https://img.shields.io/travis/nzbget/nzbget/develop.svg)](https://travis-ci.org/nzbget/nzbget)
3
4 NZBGet is a binary downloader, which downloads files from Usenet
5 based on information given in nzb-files.
6
7 NZBGet is written in C++ and is known for its extraordinary performance and efficiency.
8
9 NZBGet can be run at almost every platform - classic PCs, NAS, media players, SAT-receivers, WLAN-routers, etc.
10 The download area provides precompiled binaries
11 for Windows, Mac OS X and Linux (compatible with many CPUs and platform variants). For other platforms
12 the program can be compiled from sources.
13
14 - [Home page (nzbget.net)](http://nzbget.net) - for first time visitors, learn more about NZBGet;
15 - [Downloads](http://nzbget.net/download) - get the binaries and sources;
16 - [Documentation](http://nzbget.net/documentation) - installation manuals, HOW-TOs, API;
17 - [Forum](http://forum.nzbget.net) - get support, share your ideas, scripts, add-ons.
0 /* 2031 */
1 /* This file is automatically regenerated on each build. Do not edit it. */
2 #include "nzbget.h"
3 const char* code_revision(void)
4 {
5 const char* revision = "2031";
6 return revision;
7 }
00 #! /bin/sh
11 # Guess values for system-dependent variables and create Makefiles.
2 # Generated by GNU Autoconf 2.61 for nzbget 19.0.
2 # Generated by GNU Autoconf 2.61 for nzbget 19.1-testing.
33 #
44 # Report bugs to <hugbug@users.sourceforge.net>.
55 #
573573 # Identity of this package.
574574 PACKAGE_NAME='nzbget'
575575 PACKAGE_TARNAME='nzbget'
576 PACKAGE_VERSION='19.0'
577 PACKAGE_STRING='nzbget 19.0'
576 PACKAGE_VERSION='19.1-testing'
577 PACKAGE_STRING='nzbget 19.1-testing'
578578 PACKAGE_BUGREPORT='hugbug@users.sourceforge.net'
579579
580580 ac_unique_file="daemon/main/nzbget.cpp"
12541254 # Omit some internal or obsolete options to make the list less imposing.
12551255 # This message is too long to be a string in the A/UX 3.1 sh.
12561256 cat <<_ACEOF
1257 \`configure' configures nzbget 19.0 to adapt to many kinds of systems.
1257 \`configure' configures nzbget 19.1-testing to adapt to many kinds of systems.
12581258
12591259 Usage: $0 [OPTION]... [VAR=VALUE]...
12601260
13251325
13261326 if test -n "$ac_init_help"; then
13271327 case $ac_init_help in
1328 short | recursive ) echo "Configuration of nzbget 19.0:";;
1328 short | recursive ) echo "Configuration of nzbget 19.1-testing:";;
13291329 esac
13301330 cat <<\_ACEOF
13311331
14761476 test -n "$ac_init_help" && exit $ac_status
14771477 if $ac_init_version; then
14781478 cat <<\_ACEOF
1479 nzbget configure 19.0
1479 nzbget configure 19.1-testing
14801480 generated by GNU Autoconf 2.61
14811481
14821482 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
14901490 This file contains any messages produced by compilers while
14911491 running configure, to aid debugging if configure makes a mistake.
14921492
1493 It was created by nzbget $as_me 19.0, which was
1493 It was created by nzbget $as_me 19.1-testing, which was
14941494 generated by GNU Autoconf 2.61. Invocation command line was
14951495
14961496 $ $0 $@
22862286
22872287 # Define the identity of the package.
22882288 PACKAGE='nzbget'
2289 VERSION='19.0'
2289 VERSION='19.1-testing'
22902290
22912291
22922292 cat >>confdefs.h <<_ACEOF
1229612296 # report actual input values of CONFIG_FILES etc. instead of their
1229712297 # values after options handling.
1229812298 ac_log="
12299 This file was extended by nzbget $as_me 19.0, which was
12299 This file was extended by nzbget $as_me 19.1-testing, which was
1230012300 generated by GNU Autoconf 2.61. Invocation command line was
1230112301
1230212302 CONFIG_FILES = $CONFIG_FILES
1234912349 _ACEOF
1235012350 cat >>$CONFIG_STATUS <<_ACEOF
1235112351 ac_cs_version="\\
12352 nzbget config.status 19.0
12352 nzbget config.status 19.1-testing
1235312353 configured by $0, generated by GNU Autoconf 2.61,
1235412354 with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
1235512355
2020 # Process this file with autoconf to produce a configure script.
2121
2222 AC_PREREQ(2.59)
23 AC_INIT(nzbget, 19.0, hugbug@users.sourceforge.net)
23 AC_INIT(nzbget, 19.1-testing, hugbug@users.sourceforge.net)
2424 AC_CONFIG_AUX_DIR(posix)
2525 AC_CANONICAL_TARGET
2626 AM_INIT_AUTOMAKE([foreign])
421421 {
422422 debug("WaitNextVolume for %s", filename);
423423
424 // Stop direct unpack if destination directory was changed during unpack
425 {
426 GuardedDownloadQueue downloadQueue = DownloadQueue::Guard();
427 NzbInfo* nzbInfo = downloadQueue->GetQueue()->Find(m_nzbId);
428 if (nzbInfo && (strcmp(m_destDir, nzbInfo->GetDestDir()) ||
429 strcmp(m_finalDir, nzbInfo->BuildFinalDirName())))
430 {
431 nzbInfo->AddMessage(Message::mkWarning, BString<1024>("Destination directory changed for %s", nzbInfo->GetName()));
432 Stop(downloadQueue, nzbInfo);
433 }
434 }
435
424436 BString<1024> fullFilename("%s%c%s", *m_destDir, PATH_SEPARATOR, filename);
425437 if (FileSystem::FileExists(fullFilename))
426438 {
267267 uint16 size = ((uint16)buf[6] << 8) + buf[5];
268268
269269 uint32 blocksize = size;
270 if (m_encrypted)
271 {
272 // Align to 16 bytes
273 blocksize = (blocksize + ((~blocksize + 1) & (16 - 1)));
274 }
275
270276 block.trailsize = blocksize - sizeof(buf);
271277
272278 uint8 addbuf[4];
223223 volume.GetVolumeNo() == lastVolume->GetVolumeNo() + 1 &&
224224 volume.GetVersion() == lastVolume->GetVersion() &&
225225 lastVolume->GetHasNextVolume() &&
226 ((volume.GetFiles()->at(0).GetSplitBefore() &&
227 lastVolume->GetFiles()->at(0).GetSplitAfter() &&
228 !strcmp(volume.GetFiles()->at(0).GetFilename(), lastVolume->GetFiles()->at(0).GetFilename())) ||
229 (!volume.GetFiles()->at(0).GetSplitBefore() && !lastVolume->GetFiles()->at(0).GetSplitAfter())))
226 ((volume.GetFiles()->front().GetSplitBefore() &&
227 lastVolume->GetFiles()->back().GetSplitAfter() &&
228 !strcmp(volume.GetFiles()->front().GetFilename(), lastVolume->GetFiles()->back().GetFilename())) ||
229 (!volume.GetFiles()->front().GetSplitBefore() && !lastVolume->GetFiles()->back().GetSplitAfter())))
230230 {
231231 debug(" adding %s", FileSystem::BaseFileName(volume.GetFilename()));
232232 set.push_back(&volume);
236236 }
237237 }
238238
239 bool completed = !set.back()->GetHasNextVolume();
239 RarVolume* lastVolume = set.back();
240 bool completed = !lastVolume->GetHasNextVolume() &&
241 (lastVolume->GetFiles()->empty() || !lastVolume->GetFiles()->back().GetSplitAfter());
240242
241243 return !completed;
242244 }),
102102
103103 if (m_hasRarFiles)
104104 {
105 if (m_hasUnpackedRarFiles)
105 if (m_hasNotUnpackedRarFiles || m_unpackDirCreated)
106106 {
107107 if (m_postInfo->GetNzbInfo()->GetDirectUnpackStatus() == NzbInfo::nsSuccess)
108108 {
109 PrintMessage(Message::mkInfo, "Found archive files not processed by direct unpack, unpacking all files again");
109 if (m_unpackDirCreated)
110 {
111 PrintMessage(Message::mkWarning, "Could not find files unpacked by direct unpack, unpacking all files again");
112 }
113 else
114 {
115 PrintMessage(Message::mkInfo, "Found archive files not processed by direct unpack, unpacking all files again");
116 }
110117 }
118
119 // Discard info about extracted archives to prevent reusing on next unpack attempt
120 m_postInfo->GetExtractedArchives()->clear();
121
111122 UnpackArchives(upUnrar, false);
112123 }
113124 else
605616 const char* destDir = !m_finalDir.Empty() ? *m_finalDir : *m_destDir;
606617
607618 m_unpackDir.Format("%s%c%s", destDir, PATH_SEPARATOR, "_unpack");
619 m_unpackDirCreated = !FileSystem::DirectoryExists(m_unpackDir);
608620
609621 detail("Unpacking into %s", *m_unpackDir);
610622
636648 if (regExRar.Match(filename))
637649 {
638650 m_hasRarFiles = true;
639 m_hasUnpackedRarFiles |= std::find(
651 m_hasNotUnpackedRarFiles |= std::find(
640652 m_postInfo->GetExtractedArchives()->begin(),
641653 m_postInfo->GetExtractedArchives()->end(),
642654 filename) == m_postInfo->GetExtractedArchives()->end();
7272 bool m_noFilesMessageReceived = false;
7373 bool m_hasParFiles = false;
7474 bool m_hasRarFiles = false;
75 bool m_hasUnpackedRarFiles = false;
75 bool m_hasNotUnpackedRarFiles = false;
7676 bool m_hasRenamedArchiveFiles = false;
7777 bool m_hasSevenZipFiles = false;
7878 bool m_hasSevenZipMultiFiles = false;
8585 bool m_cleanedUpDisk = false;
8686 bool m_autoTerminated = false;
8787 bool m_finalDirCreated = false;
88 bool m_unpackDirCreated = false;
8889 bool m_passListTried = false;
8990 FileList m_joinedFiles;
9091
+0
-21
daemon/windows/StdAfx.cpp less more
0 /*
1 * This file is part of nzbget. See <http://nzbget.net>.
2 *
3 * Copyright (C) 2015-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19
20 #include "nzbget.h"
+0
-1044
daemon/windows/WinConsole.cpp less more
0 /*
1 * This file is part of nzbget. See <http://nzbget.net>.
2 *
3 * Copyright (C) 2014-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19
20 #include "nzbget.h"
21 #include "Log.h"
22 #include "Options.h"
23 #include "FeedCoordinator.h"
24 #include "StatMeter.h"
25 #include "WinConsole.h"
26 #include "WinService.h"
27 #include "FileSystem.h"
28 #include "Util.h"
29 #include "resource.h"
30
31 extern Options* g_Options;
32 extern char* (*g_Arguments)[];
33 extern int g_ArgumentCount;
34 extern void ExitProc();
35 extern void Reload();
36 extern WinConsole* g_WinConsole;
37 extern FeedCoordinator* g_FeedCoordinator;
38 extern StatMeter* g_StatMeter;
39
40 #define UM_TRAYICON (WM_USER + 1)
41 #define UM_QUIT (WM_USER + 2)
42 #define UM_SHOWWEBUI (WM_USER + 3)
43 #define UM_PREFSCHANGED (WM_USER + 4)
44
45 #pragma comment(linker, \
46 "\"/manifestdependency:type='Win32' "\
47 "name='Microsoft.Windows.Common-Controls' version='6.0.0.0' "\
48 "processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
49
50 bool mayStartBrowser = true;
51
52 BOOL WINAPI WinConsole::ConsoleCtrlHandler(DWORD dwCtrlType)
53 {
54 switch (dwCtrlType)
55 {
56 case CTRL_C_EVENT:
57 case CTRL_BREAK_EVENT:
58 case CTRL_CLOSE_EVENT:
59 case CTRL_LOGOFF_EVENT:
60 case CTRL_SHUTDOWN_EVENT:
61 ExitProc();
62 while (g_WinConsole)
63 {
64 usleep(20 * 1000);
65 }
66 return TRUE;
67
68 default:
69 return FALSE;
70 }
71 }
72
73 WinConsole::~WinConsole()
74 {
75 if (m_initialArguments)
76 {
77 g_Arguments = (char*(*)[])m_initialArguments;
78 g_ArgumentCount = m_initialArgumentCount;
79 }
80 free(m_defaultArguments);
81 delete m_iconData;
82 }
83
84 void WinConsole::InitAppMode()
85 {
86 SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
87
88 m_instance = (HINSTANCE)GetModuleHandle(0);
89 DWORD processId;
90 GetWindowThreadProcessId(GetConsoleWindow(), &processId);
91
92 if (GetCurrentProcessId() == processId && g_ArgumentCount == 1)
93 {
94 m_initialArguments = (char**)g_Arguments;
95 m_initialArgumentCount = g_ArgumentCount;
96
97 // make command line to start in server mode
98 m_defaultArguments = (char**)malloc(sizeof(char*) * 3);
99 m_defaultArguments[0] = (*g_Arguments)[0];
100 m_defaultArguments[1] = "-s";
101 m_defaultArguments[2] = nullptr;
102 g_Arguments = (char*(*)[])m_defaultArguments;
103 g_ArgumentCount = 2;
104 m_appMode = true;
105 }
106 else if (GetCurrentProcessId() == processId && g_ArgumentCount > 1)
107 {
108 for (int i = 1; i < g_ArgumentCount; i++)
109 {
110 if (!strcmp((*g_Arguments)[i], "-D"))
111 {
112 break;
113 }
114 else if (!strcmp((*g_Arguments)[i], "-app"))
115 {
116 m_appMode = true;
117 }
118 else if (!strcmp((*g_Arguments)[i], "-auto"))
119 {
120 m_autoParam = true;
121 }
122 else if (!strcmp((*g_Arguments)[i], "-A"))
123 {
124 m_addParam = true;
125 }
126 }
127
128 if (m_appMode || m_autoParam)
129 {
130 m_initialArguments = (char**)g_Arguments;
131 m_initialArgumentCount = g_ArgumentCount;
132
133 // remove "-app" from command line
134 int argc = g_ArgumentCount - (m_appMode ? 1 : 0) - (m_autoParam ? 1 : 0);
135 m_defaultArguments = (char**)malloc(sizeof(char*) * (argc + 2));
136
137 int p = 0;
138 for (int i = 0; i < g_ArgumentCount; i++)
139 {
140 if (strcmp((*g_Arguments)[i], "-app") &&
141 strcmp((*g_Arguments)[i], "-auto"))
142 {
143 m_defaultArguments[p++] = (*g_Arguments)[i];
144 }
145 }
146 m_defaultArguments[p] = nullptr;
147 g_Arguments = (char*(*)[])m_defaultArguments;
148 g_ArgumentCount = p;
149 }
150 }
151
152 if (m_addParam)
153 {
154 RunAnotherInstance();
155 return;
156 }
157
158 // m_appMode indicates whether the program was started as a standalone app
159 // (not from a dos box window). In that case we hide the console window,
160 // show the tray icon and start in server mode
161
162 if (m_appMode)
163 {
164 CreateResources();
165 CheckRunning();
166 }
167 }
168
169 void WinConsole::Run()
170 {
171 if (!m_appMode || m_addParam)
172 {
173 return;
174 }
175
176 CreateTrayIcon();
177
178 LoadPrefs();
179 ApplyPrefs();
180
181 BuildMenu();
182
183 if (m_showWebUI && !m_autoParam && mayStartBrowser)
184 {
185 ShowWebUI();
186 }
187 mayStartBrowser = false;
188
189 int counter = 0;
190 while (!IsStopped())
191 {
192 MSG msg;
193 if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
194 {
195 TranslateMessage(&msg);
196 DispatchMessage(&msg);
197 }
198 else
199 {
200 usleep(20 * 1000);
201 counter += 20;
202 if (counter >= 200)
203 {
204 UpdateTrayIcon();
205 counter = 0;
206 }
207 }
208 }
209
210 Shell_NotifyIcon(NIM_DELETE, m_iconData);
211 }
212
213 void WinConsole::Stop()
214 {
215 if (m_appMode)
216 {
217 PostMessage(m_trayWindow, WM_QUIT, 0, 0);
218 }
219
220 Thread::Stop();
221 }
222
223 void WinConsole::CreateResources()
224 {
225 m_menu = LoadMenu(m_instance, MAKEINTRESOURCE(IDR_TRAYMENU));
226 m_menu = GetSubMenu(m_menu, 0);
227
228 HDC hdc = GetDC(nullptr);
229 long height = -MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72);
230 m_linkFont = CreateFont(height, 0, 0, 0, 0, 0, TRUE, 0, 0, 0, 0, 0, 0, "Tahoma");
231 height = -MulDiv(11, GetDeviceCaps(hdc, LOGPIXELSY), 72);
232 m_nameFont = CreateFont(height, 0, 0, 0, FW_BOLD, 0, 0, 0, 0, 0, 0, 0, 0, "Tahoma");
233 height = -MulDiv(10, GetDeviceCaps(hdc, LOGPIXELSY), 72);
234 m_titleFont = CreateFont(height, 0, 0, 0, FW_BOLD, 0, 0, 0, 0, 0, 0, 0, 0, "Tahoma");
235 ReleaseDC(nullptr, hdc);
236
237 m_handCursor = LoadCursor(nullptr, IDC_HAND);
238 m_aboutIcon = (HICON)LoadImage(m_instance, MAKEINTRESOURCE(IDI_MAINICON), IMAGE_ICON, 64, 64, 0);
239 m_runningIcon = (HICON)LoadImage(m_instance, MAKEINTRESOURCE(IDI_MAINICON), IMAGE_ICON, 48, 48, 0);
240
241 m_idleIcon = LoadIcon(m_instance, MAKEINTRESOURCE(IDI_TRAYICON_IDLE));
242 m_workingIcon = LoadIcon(m_instance, MAKEINTRESOURCE(IDI_TRAYICON_WORKING));
243 m_pausedIcon = LoadIcon(m_instance, MAKEINTRESOURCE(IDI_TRAYICON_PAUSED));
244 }
245
246 void WinConsole::CreateTrayIcon()
247 {
248 m_taskbarCreatedMessage = RegisterWindowMessageA("TaskbarCreated") ;
249
250 char className[] = "NZBGet tray window";
251 WNDCLASSEX wnd;
252 memset(&wnd, 0, sizeof(wnd));
253 wnd.hInstance = m_instance;
254 wnd.lpszClassName = className;
255 wnd.lpfnWndProc = TrayWndProcStat;
256 wnd.style = 0;
257 wnd.cbSize = sizeof(WNDCLASSEX);
258 RegisterClassEx(&wnd);
259
260 m_trayWindow = CreateWindowEx(0, className, "NZBGet", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
261 CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, m_instance, nullptr);
262
263 m_iconData = new NOTIFYICONDATA;
264 memset(m_iconData, 0, sizeof(NOTIFYICONDATA));
265 m_iconData->cbSize = sizeof(NOTIFYICONDATA);
266 m_iconData->hWnd = m_trayWindow;
267 m_iconData->uID = 100;
268 m_iconData->uCallbackMessage = UM_TRAYICON;
269 m_iconData->hIcon = m_workingIcon;
270 strncpy(m_iconData->szTip, "NZBGet", sizeof(m_iconData->szTip));
271 m_iconData->uFlags = NIF_MESSAGE | NIF_ICON | NIF_TIP;
272 }
273
274 LRESULT CALLBACK WinConsole::TrayWndProcStat(HWND hwndWin, UINT uMsg, WPARAM wParam, LPARAM lParam)
275 {
276 return g_WinConsole->TrayWndProc(hwndWin, uMsg, wParam, lParam);
277 }
278
279 LRESULT WinConsole::TrayWndProc(HWND hwndWin, UINT uMsg, WPARAM wParam, LPARAM lParam)
280 {
281 if (uMsg == m_taskbarCreatedMessage)
282 {
283 ApplyPrefs();
284 return 0;
285 }
286
287 switch (uMsg)
288 {
289 case UM_TRAYICON:
290 if (lParam == WM_LBUTTONUP && !m_doubleClick)
291 {
292 g_Options->SetPauseDownload(!g_Options->GetPauseDownload());
293 g_Options->SetPausePostProcess(g_Options->GetPauseDownload());
294 g_Options->SetPauseScan(g_Options->GetPauseDownload());
295 g_Options->SetResumeTime(0);
296 UpdateTrayIcon();
297 }
298 else if (lParam == WM_LBUTTONDBLCLK && m_doubleClick)
299 {
300 ShowWebUI();
301 }
302 else if (lParam == WM_RBUTTONDOWN)
303 {
304 ShowMenu();
305 }
306 return 0;
307
308 case UM_QUIT:
309 ExitProc();
310 return 0;
311
312 case UM_SHOWWEBUI:
313 ShowWebUI();
314 return 0;
315
316 case UM_PREFSCHANGED:
317 LoadPrefs();
318 ApplyPrefs();
319 return 0;
320
321 default:
322 return DefWindowProc(hwndWin, uMsg, wParam, lParam);
323 }
324 }
325
326 void WinConsole::ShowMenu()
327 {
328 POINT curPoint;
329 GetCursorPos(&curPoint);
330 SetForegroundWindow(m_trayWindow);
331
332 UINT itemId = TrackPopupMenu(m_menu, TPM_RETURNCMD | TPM_NONOTIFY, curPoint.x, curPoint.y, 0, m_trayWindow, nullptr);
333
334 switch(itemId)
335 {
336 case ID_SHOWWEBUI:
337 ShowWebUI();
338 break;
339
340 case ID_SHOW_DESTDIR:
341 ShowInExplorer(g_Options->GetDestDir());
342 break;
343
344 case ID_SHOW_INTERDIR:
345 ShowInExplorer(g_Options->GetInterDir());
346 break;
347
348 case ID_SHOW_NZBDIR:
349 ShowInExplorer(g_Options->GetNzbDir());
350 break;
351
352 case ID_SHOW_CONFIGFILE:
353 ShowInExplorer(g_Options->GetConfigFilename());
354 break;
355
356 case ID_SHOW_LOGFILE:
357 ShowInExplorer(g_Options->GetLogFile());
358 break;
359
360 case ID_SHOW_SCRIPTDIR:
361 {
362 CString firstScriptDir = g_Options->GetScriptDir();
363 // Taking the first path from the list
364 if (char* p = strpbrk(firstScriptDir, ";,")) *p = '\0';
365 ShowInExplorer(firstScriptDir);
366 break;
367 }
368
369 case ID_INFO_HOMEPAGE:
370 ShellExecute(0, "open", "http://nzbget.net", nullptr, nullptr, SW_SHOWNORMAL);
371 break;
372
373 case ID_INFO_DOWNLOADS:
374 ShellExecute(0, "open", "http://nzbget.net/download", nullptr, nullptr, SW_SHOWNORMAL);
375 break;
376
377 case ID_INFO_FORUM:
378 ShellExecute(0, "open", "http://nzbget.net/forum", nullptr, nullptr, SW_SHOWNORMAL);
379 break;
380
381 case ID_ABOUT:
382 ShowAboutBox();
383 break;
384
385 case ID_PREFERENCES:
386 ShowPrefsDialog();
387 break;
388
389 case ID_EXIT:
390 ExitProc();
391 break;
392
393 case ID_TROUBLESHOOTING_RESTART:
394 mayStartBrowser = true;
395 Reload();
396 break;
397
398 case ID_TROUBLESHOOTING_OPENCONFIG:
399 OpenConfigFileInTextEdit();
400 break;
401
402 case ID_TROUBLESHOOTING_FACTORYRESET:
403 ShowFactoryResetDialog();
404 break;
405 }
406
407 if (itemId >= ID_SHOW_DESTDIR + 1000 && itemId < ID_SHOW_DESTDIR + 2000)
408 {
409 ShowCategoryDir(itemId - (ID_SHOW_DESTDIR + 1000));
410 }
411 }
412
413 void WinConsole::ShowWebUI()
414 {
415 const char* iP = g_Options->GetControlIp();
416 if (!strcmp(g_Options->GetControlIp(), "localhost") ||
417 !strcmp(g_Options->GetControlIp(), "0.0.0.0"))
418 {
419 iP = "127.0.0.1";
420 }
421
422 BString<1024> url("http://%s:%i", iP, g_Options->GetControlPort());
423 ShellExecute(0, "open", url, nullptr, nullptr, SW_SHOWNORMAL);
424 }
425
426 void WinConsole::ShowInExplorer(const char* filename)
427 {
428 BString<1024> fileName2 = filename;
429 FileSystem::NormalizePathSeparators(fileName2);
430
431 if (!FileSystem::FileExists(fileName2) && !FileSystem::DirectoryExists(fileName2))
432 {
433 BString<1024> message("Directory or file %s doesn't exist (yet).", *fileName2);
434 MessageBox(m_trayWindow, message, "Information", MB_ICONINFORMATION);
435 return;
436 }
437
438 WString wideFilename = FileSystem::UtfPathToWidePath(fileName2);
439
440 CoInitialize(nullptr);
441 LPITEMIDLIST pidl;
442 HRESULT H = SHParseDisplayName(wideFilename, nullptr, &pidl, 0, nullptr);
443 H = SHOpenFolderAndSelectItems(pidl, 0, 0, 0);
444 }
445
446 void WinConsole::ShowAboutBox()
447 {
448 if (m_modal)
449 {
450 return;
451 }
452
453 m_modal = true;
454 DialogBox(m_instance, MAKEINTRESOURCE(IDD_ABOUTBOX), m_trayWindow, AboutDialogProcStat);
455 m_modal = false;
456 }
457
458 BOOL CALLBACK WinConsole::AboutDialogProcStat(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
459 {
460 return g_WinConsole->AboutDialogProc(hwndDlg, uMsg, wParam, lParam);
461 }
462
463 BOOL WinConsole::AboutDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
464 {
465 switch(uMsg)
466 {
467 case WM_INITDIALOG:
468 SendDlgItemMessage(hwndDlg, IDC_ABOUT_NAME, WM_SETFONT, (WPARAM)m_nameFont, 0);
469 SetDlgItemText(hwndDlg, IDC_ABOUT_VERSION, BString<100>("Version %s", Util::VersionRevision()));
470 SendDlgItemMessage(hwndDlg, IDC_ABOUT_ICON, STM_SETICON, (WPARAM)m_aboutIcon, 0);
471 SendDlgItemMessage(hwndDlg, IDC_ABOUT_HOMEPAGE, WM_SETFONT, (WPARAM)m_linkFont, 0);
472 SendDlgItemMessage(hwndDlg, IDC_ABOUT_GPL, WM_SETFONT, (WPARAM)m_linkFont, 0);
473 return FALSE;
474
475 case WM_CLOSE:
476 EndDialog(hwndDlg, 0);
477 return TRUE;
478
479 case WM_COMMAND:
480 if (LOWORD(wParam) == IDOK)
481 {
482 EndDialog(hwndDlg, 0);
483 }
484 else if (LOWORD(wParam) == IDC_ABOUT_HOMEPAGE && HIWORD(wParam) == STN_CLICKED)
485 {
486 ShellExecute(0, "open", "http://nzbget.net", nullptr, nullptr, SW_SHOWNORMAL);
487 }
488 else if (LOWORD(wParam) == IDC_ABOUT_GPL && HIWORD(wParam) == STN_CLICKED)
489 {
490 ShellExecute(0, "open", "http://www.gnu.org/licenses/gpl-2.0.html", nullptr, nullptr, SW_SHOWNORMAL);
491 }
492 return TRUE;
493
494 case WM_CTLCOLORSTATIC:
495 if ((HWND)lParam == GetDlgItem(hwndDlg, IDC_ABOUT_HOMEPAGE) ||
496 (HWND)lParam == GetDlgItem(hwndDlg, IDC_ABOUT_GPL))
497 {
498 SetTextColor((HDC)wParam, RGB(0, 0, 255));
499 SetBkColor((HDC)wParam, GetSysColor(COLOR_BTNFACE));
500 return (INT_PTR)GetSysColorBrush(COLOR_BTNFACE);
501 }
502 return FALSE;
503
504 case WM_SETCURSOR:
505 if ((HWND)wParam == GetDlgItem(hwndDlg, IDC_ABOUT_HOMEPAGE) ||
506 (HWND)wParam == GetDlgItem(hwndDlg, IDC_ABOUT_GPL))
507 {
508 SetCursor(m_handCursor);
509 SetWindowLong(hwndDlg, DWL_MSGRESULT, TRUE);
510 return TRUE;
511 }
512 return FALSE;
513
514 default:
515 return FALSE;
516 }
517 }
518
519 void WinConsole::ShowPrefsDialog()
520 {
521 if (m_modal)
522 {
523 return;
524 }
525
526 m_modal = true;
527 DialogBox(m_instance, MAKEINTRESOURCE(IDD_PREFDIALOG), m_trayWindow, PrefsDialogProcStat);
528 m_modal = false;
529 }
530
531 BOOL CALLBACK WinConsole::PrefsDialogProcStat(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
532 {
533 return g_WinConsole->PrefsDialogProc(hwndDlg, uMsg, wParam, lParam);
534 }
535
536 BOOL WinConsole::PrefsDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
537 {
538 switch(uMsg)
539 {
540 case WM_INITDIALOG:
541 LoadPrefs();
542
543 SendDlgItemMessage(hwndDlg, IDC_PREF_AUTOSTART, BM_SETCHECK, m_autostart, 0);
544 SendDlgItemMessage(hwndDlg, IDC_PREF_TRAY, BM_SETCHECK, m_showTrayIcon, 0);
545 SendDlgItemMessage(hwndDlg, IDC_PREF_CONSOLE, BM_SETCHECK, m_showConsole, 0);
546 SendDlgItemMessage(hwndDlg, IDC_PREF_WEBUI, BM_SETCHECK, m_showWebUI, 0);
547 SendDlgItemMessage(hwndDlg, IDC_PREF_TRAYPAUSE, BM_SETCHECK, !m_doubleClick, 0);
548 SendDlgItemMessage(hwndDlg, IDC_PREF_TRAYWEBUI, BM_SETCHECK, m_doubleClick, 0);
549
550 return FALSE;
551
552 case WM_CLOSE:
553 EndDialog(hwndDlg, 0);
554 return TRUE;
555
556 case WM_COMMAND:
557 if (LOWORD(wParam) == IDOK)
558 {
559 m_autostart = SendDlgItemMessage(hwndDlg, IDC_PREF_AUTOSTART, BM_GETCHECK, 0, 0) == BST_CHECKED;
560 m_showTrayIcon = SendDlgItemMessage(hwndDlg, IDC_PREF_TRAY, BM_GETCHECK, 0, 0) == BST_CHECKED;
561 m_showConsole = SendDlgItemMessage(hwndDlg, IDC_PREF_CONSOLE, BM_GETCHECK, 0, 0) == BST_CHECKED;
562 m_showWebUI = SendDlgItemMessage(hwndDlg, IDC_PREF_WEBUI, BM_GETCHECK, 0, 0) == BST_CHECKED;
563 m_doubleClick = SendDlgItemMessage(hwndDlg, IDC_PREF_TRAYWEBUI, BM_GETCHECK, 0, 0) == BST_CHECKED;
564
565 SavePrefs();
566 if (!m_running)
567 {
568 ApplyPrefs();
569 }
570
571 EndDialog(hwndDlg, 0);
572 }
573 else if (LOWORD(wParam) == IDCANCEL)
574 {
575 EndDialog(hwndDlg, 0);
576 }
577 return TRUE;
578
579 default:
580 return FALSE;
581 }
582 }
583
584 void WinConsole::SavePrefs()
585 {
586 DWORD val;
587 HKEY hKey;
588 RegCreateKey(HKEY_CURRENT_USER, "Software\\NZBGet", &hKey);
589
590 val = m_showTrayIcon;
591 RegSetValueEx(hKey, "ShowTrayIcon", 0, REG_DWORD, (BYTE*)&val, sizeof(val));
592
593 val = m_showConsole;
594 RegSetValueEx(hKey, "ShowConsole", 0, REG_DWORD, (BYTE*)&val, sizeof(val));
595
596 val = m_showWebUI;
597 RegSetValueEx(hKey, "ShowWebUI", 0, REG_DWORD, (BYTE*)&val, sizeof(val));
598
599 val = m_doubleClick;
600 RegSetValueEx(hKey, "TrayDoubleClick", 0, REG_DWORD, (BYTE*)&val, sizeof(val));
601
602 RegCloseKey(hKey);
603
604 // Autostart-setting
605 RegCreateKey(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Run", &hKey);
606 if (m_autostart)
607 {
608 char filename[MAX_PATH + 1];
609 GetModuleFileName(nullptr, filename, sizeof(filename));
610 BString<1024> startCommand("\"%s\" -s -app -auto", filename);
611 RegSetValueEx(hKey, "NZBGet", 0, REG_SZ, (BYTE*)(char*)startCommand, strlen(startCommand) + 1);
612 }
613 else
614 {
615 RegDeleteValue(hKey, "NZBGet");
616 }
617 RegCloseKey(hKey);
618 }
619
620 void WinConsole::LoadPrefs()
621 {
622 DWORD val;
623 DWORD cval;
624 DWORD typ;
625 HKEY hKey;
626
627 if (RegOpenKey(HKEY_CURRENT_USER, "Software\\NZBGet", &hKey) == ERROR_SUCCESS)
628 {
629 if (RegQueryValueEx(hKey, "ShowTrayIcon", 0, &typ, (LPBYTE)&val, &cval) == ERROR_SUCCESS)
630 {
631 m_showTrayIcon = val;
632 }
633
634 if (RegQueryValueEx(hKey, "ShowConsole", 0, &typ, (LPBYTE)&val, &cval) == ERROR_SUCCESS)
635 {
636 m_showConsole = val;
637 }
638
639 if (RegQueryValueEx(hKey, "ShowWebUI", 0, &typ, (LPBYTE)&val, &cval) == ERROR_SUCCESS)
640 {
641 m_showWebUI = val;
642 }
643
644 if (RegQueryValueEx(hKey, "TrayDoubleClick", 0, &typ, (LPBYTE)&val, &cval) == ERROR_SUCCESS)
645 {
646 m_doubleClick = val;
647 }
648
649 RegCloseKey(hKey);
650 }
651
652 // Autostart-setting
653 if (RegOpenKey(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Run", &hKey) == ERROR_SUCCESS)
654 {
655 m_autostart = RegQueryValueEx(hKey, "NZBGet", 0, &typ, nullptr, nullptr) == ERROR_SUCCESS;
656 RegCloseKey(hKey);
657 }
658 }
659
660 void WinConsole::ApplyPrefs()
661 {
662 ShowWindow(GetConsoleWindow(), m_showConsole ? SW_SHOW : SW_HIDE);
663 if (m_showTrayIcon)
664 {
665 UpdateTrayIcon();
666 }
667 Shell_NotifyIcon(m_showTrayIcon ? NIM_ADD : NIM_DELETE, m_iconData);
668 }
669
670 void WinConsole::CheckRunning()
671 {
672 HWND hTrayWindow = FindWindow("NZBGet tray window", nullptr);
673 if (hTrayWindow)
674 {
675 ShowRunningDialog();
676 ExitProcess(1);
677 }
678
679 if (IsServiceRunning())
680 {
681 m_runningService = true;
682 ShowRunningDialog();
683 ExitProcess(1);
684 }
685 }
686
687 void WinConsole::ShowRunningDialog()
688 {
689 ShowWindow(GetConsoleWindow(), m_showConsole ? SW_SHOW : SW_HIDE);
690 HWND hTrayWindow = FindWindow("NZBGet tray window", nullptr);
691 m_running = true;
692
693 int result = DialogBox(m_instance, MAKEINTRESOURCE(IDD_RUNNINGDIALOG), m_trayWindow, RunningDialogProcStat);
694
695 switch (result)
696 {
697 case IDC_RUNNING_WEBUI:
698 PostMessage(hTrayWindow, UM_SHOWWEBUI, 0, 0);
699 break;
700
701 case IDC_RUNNING_PREFS:
702 ShowPrefsDialog();
703 PostMessage(hTrayWindow, UM_PREFSCHANGED, 0, 0);
704 break;
705
706 case IDC_RUNNING_QUIT:
707 PostMessage(hTrayWindow, UM_QUIT, 0, 0);
708 break;
709 }
710 }
711
712 BOOL CALLBACK WinConsole::RunningDialogProcStat(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
713 {
714 return g_WinConsole->RunningDialogProc(hwndDlg, uMsg, wParam, lParam);
715 }
716
717 BOOL WinConsole::RunningDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
718 {
719 switch(uMsg)
720 {
721 case WM_INITDIALOG:
722 SendDlgItemMessage(hwndDlg, IDC_RUNNING_ICON, STM_SETICON, (WPARAM)m_runningIcon, 0);
723 SendDlgItemMessage(hwndDlg, IDC_RUNNING_TITLE, WM_SETFONT, (WPARAM)m_titleFont, 0);
724
725 if (m_runningService)
726 {
727 SetDlgItemText(hwndDlg, IDC_RUNNING_TEXT, "Another instance of NZBGet is running as Windows Service. Please use Management Console to control the service.");
728 ShowWindow(GetDlgItem(hwndDlg, IDC_RUNNING_WEBUI), SW_HIDE);
729 ShowWindow(GetDlgItem(hwndDlg, IDC_RUNNING_PREFS), SW_HIDE);
730 ShowWindow(GetDlgItem(hwndDlg, IDC_RUNNING_QUIT), SW_HIDE);
731 ShowWindow(GetDlgItem(hwndDlg, IDC_RUNNING_OK), SW_SHOW);
732 }
733
734 return FALSE;
735
736 case WM_CLOSE:
737 EndDialog(hwndDlg, 0);
738 return TRUE;
739
740 case WM_COMMAND:
741 EndDialog(hwndDlg, LOWORD(wParam));
742 return TRUE;
743
744 default:
745 return FALSE;
746 }
747 }
748
749 void WinConsole::UpdateTrayIcon()
750 {
751 if (!m_showTrayIcon)
752 {
753 return;
754 }
755
756 HICON hOldIcon = m_iconData->hIcon;
757
758 char oldTip[200];
759 strncpy(oldTip, m_iconData->szTip, sizeof(m_iconData->szTip));
760 oldTip[200-1] = '\0';
761
762 if (g_Options->GetPauseDownload())
763 {
764 m_iconData->hIcon = m_pausedIcon;
765 strncpy(m_iconData->szTip, "NZBGet - paused", sizeof(m_iconData->szTip));
766 }
767 else if (!g_StatMeter->GetStandBy())
768 {
769 m_iconData->hIcon = m_workingIcon;
770 BString<100> tip("NZBGet - downloading at %s", *Util::FormatSpeed(g_StatMeter->CalcCurrentDownloadSpeed()));
771 strncpy(m_iconData->szTip, tip, sizeof(m_iconData->szTip));
772 }
773 else
774 {
775 int postJobCount = 0;
776 int urlCount = 0;
777 {
778 GuardedDownloadQueue downloadQueue = DownloadQueue::Guard();
779 for (NzbInfo* nzbInfo : downloadQueue->GetQueue())
780 {
781 postJobCount += nzbInfo->GetPostInfo() ? 1 : 0;
782 urlCount += nzbInfo->GetKind() == NzbInfo::nkUrl ? 1 : 0;
783 }
784 }
785
786 if (postJobCount > 0)
787 {
788 m_iconData->hIcon = m_workingIcon;
789 strncpy(m_iconData->szTip, "NZBGet - post-processing", sizeof(m_iconData->szTip));
790 }
791 else if (urlCount > 0)
792 {
793 m_iconData->hIcon = m_workingIcon;
794 strncpy(m_iconData->szTip, "NZBGet - fetching URLs", sizeof(m_iconData->szTip));
795 }
796 else if (g_FeedCoordinator->HasActiveDownloads())
797 {
798 m_iconData->hIcon = m_workingIcon;
799 strncpy(m_iconData->szTip, "NZBGet - fetching feeds", sizeof(m_iconData->szTip));
800 }
801 else
802 {
803 m_iconData->hIcon = m_idleIcon;
804 strncpy(m_iconData->szTip, "NZBGet - idle", sizeof(m_iconData->szTip));
805 }
806 }
807
808 if (m_iconData->hIcon != hOldIcon || strcmp(oldTip, m_iconData->szTip))
809 {
810 Shell_NotifyIcon(NIM_MODIFY, m_iconData);
811 }
812 }
813
814 void WinConsole::BuildMenu()
815 {
816 int index = 0;
817 for (Options::Category& category : g_Options->GetCategories())
818 {
819 BString<1024> caption("Category %i: %s", index + 1, category.GetName());
820
821 MENUITEMINFO item;
822 ZeroMemory(&item, sizeof(MENUITEMINFO));
823 item.cbSize = sizeof(MENUITEMINFO);
824 item.fMask = MIIM_ID | MIIM_STRING;
825 item.fType = MFT_STRING;
826 item.fState = MFS_DEFAULT;
827 item.wID = ID_SHOW_DESTDIR + 1000 + index;
828 item.dwTypeData = caption;
829 InsertMenuItem(GetSubMenu(m_menu, 1), 2 + index, TRUE, &item);
830
831 index++;
832 }
833
834 /*
835 BOOL DeleteMenu(
836
837 HMENU hMenu, // handle to menu
838 UINT uPosition, // menu item identifier or position
839 UINT uFlags // menu item flag
840 );
841 */
842 }
843
844 void WinConsole::ShowCategoryDir(int catIndex)
845 {
846 Options::Category& category = g_Options->GetCategories()->at(catIndex);
847
848 BString<1024> destDir = category.GetDestDir();
849
850 if (destDir.Empty())
851 {
852 CString categoryDir = FileSystem::MakeValidFilename(category.GetName(), true);
853 destDir.Format("%s%c%s", g_Options->GetDestDir(), PATH_SEPARATOR, *categoryDir);
854 }
855
856 ShowInExplorer(destDir);
857 }
858
859 void WinConsole::OpenConfigFileInTextEdit()
860 {
861 ShellExecute(0, "open", "notepad.exe", BString<1024>("\"%s\"", g_Options->GetConfigFilename()), nullptr, SW_SHOWNORMAL);
862 }
863
864 void WinConsole::SetupFirstStart()
865 {
866 SetupConfigFile();
867 }
868
869 void WinConsole::SetupConfigFile()
870 {
871 // create new config-file from config template
872
873 char commonAppDataPath[MAX_PATH];
874 SHGetFolderPath(nullptr, CSIDL_COMMON_APPDATA, nullptr, 0, commonAppDataPath);
875
876 BString<1024> filename("%s\\NZBGet\\nzbget.conf", commonAppDataPath);
877
878 BString<1024> appDataPath("%s\\NZBGet", commonAppDataPath);
879 FileSystem::CreateDirectory(appDataPath);
880
881 BString<1024> confTemplateFilename("%s\\nzbget.conf.template", g_Options->GetAppDir());
882 CopyFile(confTemplateFilename, filename, FALSE);
883
884 // set MainDir in the config-file
885 int size = 0;
886 CharBuffer config;
887 if (FileSystem::LoadFileIntoBuffer(filename, config, true))
888 {
889 const char* SIGNATURE = "MainDir=${AppDir}\\downloads";
890 char* p = strstr(config, SIGNATURE);
891 if (p)
892 {
893 DiskFile outfile;
894 if (outfile.Open(filename, DiskFile::omWrite))
895 {
896 outfile.Write(config, p - config);
897 outfile.Write("MainDir=", 8);
898 outfile.Write(appDataPath, strlen(appDataPath));
899 outfile.Write(p + strlen(SIGNATURE), config.Size() - 1 - (p + strlen(SIGNATURE) - config) - 1);
900 outfile.Close();
901 }
902 }
903 }
904
905 // create default destination directory (which is not created on start automatically)
906 BString<1024> completeDir("%s\\NZBGet\\complete", commonAppDataPath);
907 FileSystem::CreateDirectory(completeDir);
908 }
909
910 void WinConsole::ShowFactoryResetDialog()
911 {
912 HWND hTrayWindow = FindWindow("NZBGet tray window", nullptr);
913 m_running = true;
914
915 int result = DialogBox(m_instance, MAKEINTRESOURCE(IDD_FACTORYRESETDIALOG), m_trayWindow, FactoryResetDialogProcStat);
916
917 switch (result)
918 {
919 case IDC_FACTORYRESET_RESET:
920 ResetFactoryDefaults();
921 break;
922 }
923 }
924
925 BOOL CALLBACK WinConsole::FactoryResetDialogProcStat(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
926 {
927 return g_WinConsole->FactoryResetDialogProc(hwndDlg, uMsg, wParam, lParam);
928 }
929
930 BOOL WinConsole::FactoryResetDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
931 {
932 switch(uMsg)
933 {
934 case WM_INITDIALOG:
935 SendDlgItemMessage(hwndDlg, IDC_FACTORYRESET_ICON, STM_SETICON, (WPARAM)m_runningIcon, 0);
936 SendDlgItemMessage(hwndDlg, IDC_FACTORYRESET_TITLE, WM_SETFONT, (WPARAM)m_titleFont, 0);
937 return FALSE;
938
939 case WM_CLOSE:
940 EndDialog(hwndDlg, 0);
941 return TRUE;
942
943 case WM_COMMAND:
944 EndDialog(hwndDlg, LOWORD(wParam));
945 return TRUE;
946
947 default:
948 return FALSE;
949 }
950 }
951
952 void WinConsole::ResetFactoryDefaults()
953 {
954 BString<1024> path;
955 CString errmsg;
956
957 g_Options->SetPauseDownload(true);
958 g_Options->SetPausePostProcess(true);
959
960 char commonAppDataPath[MAX_PATH];
961 SHGetFolderPath(nullptr, CSIDL_COMMON_APPDATA, nullptr, 0, commonAppDataPath);
962
963 // delete default directories
964 const char* DefDirs[] = {"nzb", "tmp", "queue", "scripts"};
965 for (int i=0; i < 4; i++)
966 {
967 path.Format("%s\\NZBGet\\%s", commonAppDataPath, DefDirs[i]);
968
969 // try to delete the directory
970 int retry = 10;
971 while (retry > 0 && FileSystem::DirectoryExists(path) &&
972 !FileSystem::DeleteDirectoryWithContent(path, errmsg))
973 {
974 usleep(200 * 1000);
975 retry--;
976 }
977
978 if (FileSystem::DirectoryExists(path))
979 {
980 MessageBox(m_trayWindow,
981 BString<1024>("Could not delete directory %s:\n%s.\nPlease delete the directory manually and try again.", *path, *errmsg),
982 "NZBGet", MB_ICONERROR);
983 return;
984 }
985 }
986
987 // delete old config file in the program's directory
988 path.Format("%s\\nzbget.conf", g_Options->GetAppDir());
989
990 FileSystem::DeleteFile(path);
991 errmsg = FileSystem::GetLastErrorMessage();
992
993 if (FileSystem::FileExists(path))
994 {
995 MessageBox(m_trayWindow,
996 BString<1024>("Could not delete file %s:\n%s.\nPlease delete the file manually and try again.", *path, *errmsg),
997 "NZBGet", MB_ICONERROR);
998 return;
999 }
1000
1001 // delete config file in default directory
1002 path.Format("%s\\NZBGet\\nzbget.conf", commonAppDataPath);
1003
1004 FileSystem::DeleteFile(path);
1005 errmsg = FileSystem::GetLastErrorMessage();
1006
1007 if (FileSystem::FileExists(path))
1008 {
1009 MessageBox(m_trayWindow,
1010 BString<1024>("Could not delete file %s:\n%s.\nPlease delete the file manually and try again.", *path, *errmsg),
1011 "NZBGet", MB_ICONERROR);
1012 return;
1013 }
1014
1015 // delete log files in default directory
1016 path.Format("%s\\NZBGet", commonAppDataPath);
1017
1018 DirBrowser dir(path);
1019 while (const char* filename = dir.Next())
1020 {
1021 if (Util::MatchFileExt(filename, ".log", ","))
1022 {
1023 BString<1024> fullFilename("%s%c%s", *path, PATH_SEPARATOR, filename);
1024 FileSystem::DeleteFile(fullFilename);
1025 // ignore errors
1026 }
1027 }
1028
1029 MessageBox(m_trayWindow, "The program has been reset to factory defaults.",
1030 "NZBGet", MB_ICONINFORMATION);
1031
1032 mayStartBrowser = true;
1033 Reload();
1034 }
1035
1036 void WinConsole::RunAnotherInstance()
1037 {
1038 ShowWindow(GetConsoleWindow(), SW_HIDE);
1039 if (!(FindWindow("NZBGet tray window", nullptr) || IsServiceRunning()))
1040 {
1041 ShellExecute(0, "open", (*g_Arguments)[0], nullptr, nullptr, SW_SHOWNORMAL);
1042 }
1043 }
+0
-102
daemon/windows/WinConsole.h less more
0 /*
1 * This file is part of nzbget. See <http://nzbget.net>.
2 *
3 * Copyright (C) 2014-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19
20 #ifndef WINCONSOLE_H
21 #define WINCONSOLE_H
22
23 #include "Thread.h"
24
25 class WinConsole : public Thread
26 {
27 public:
28 ~WinConsole();
29 virtual void Stop();
30 void InitAppMode();
31 bool GetAppMode() { return m_appMode; }
32 void SetupFirstStart();
33
34 protected:
35 virtual void Run();
36
37 private:
38 bool m_appMode = false;
39 char** m_defaultArguments = nullptr;
40 char** m_initialArguments = nullptr;
41 int m_initialArgumentCount = 0;
42 HWND m_trayWindow = 0;
43 NOTIFYICONDATA* m_iconData = nullptr;
44 UINT m_taskbarCreatedMessage;
45 HMENU m_menu;
46 HINSTANCE m_instance;
47 bool m_modal = false;
48 HFONT m_linkFont;
49 HFONT m_nameFont;
50 HFONT m_titleFont;
51 HCURSOR m_handCursor;
52 HICON m_aboutIcon;
53 HICON m_runningIcon;
54 HICON m_idleIcon;
55 HICON m_workingIcon;
56 HICON m_pausedIcon;
57 bool m_autostart = false;
58 bool m_showTrayIcon = true;
59 bool m_showConsole = false;
60 bool m_showWebUI = true;
61 bool m_autoParam = false;
62 bool m_addParam = false;
63 bool m_running = false;
64 bool m_runningService = false;
65 bool m_doubleClick = false;
66
67 void CreateResources();
68 void CreateTrayIcon();
69 void ShowWebUI();
70 void ShowMenu();
71 void ShowInExplorer(const char* filename);
72 void ShowAboutBox();
73 void OpenConfigFileInTextEdit();
74 void ShowPrefsDialog();
75 void SavePrefs();
76 void LoadPrefs();
77 void ApplyPrefs();
78 void ShowRunningDialog();
79 void CheckRunning();
80 void UpdateTrayIcon();
81 void BuildMenu();
82 void ShowCategoryDir(int catIndex);
83 void SetupConfigFile();
84 void ShowFactoryResetDialog();
85 void ResetFactoryDefaults();
86 void RunAnotherInstance();
87
88 static BOOL WINAPI ConsoleCtrlHandler(DWORD dwCtrlType);
89 static LRESULT CALLBACK TrayWndProcStat(HWND hwndWin, UINT uMsg, WPARAM wParam, LPARAM lParam);
90 LRESULT TrayWndProc(HWND hwndWin, UINT uMsg, WPARAM wParam, LPARAM lParam);
91 static BOOL CALLBACK AboutDialogProcStat(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
92 BOOL AboutDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
93 static BOOL CALLBACK PrefsDialogProcStat(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
94 BOOL PrefsDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
95 static BOOL CALLBACK RunningDialogProcStat(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
96 BOOL RunningDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
97 static BOOL CALLBACK FactoryResetDialogProcStat(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
98 BOOL FactoryResetDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
99 };
100
101 #endif
+0
-208
daemon/windows/WinService.cpp less more
0 /*
1 * This file is part of nzbget. See <http://nzbget.net>.
2 *
3 * Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19
20 #include "nzbget.h"
21 #include "Log.h"
22 #include "WinService.h"
23
24 extern void ExitProc();
25 RunProc Run = nullptr;
26
27 char* strServiceName = "NZBGet";
28 SERVICE_STATUS_HANDLE nServiceStatusHandle;
29 DWORD nServiceCurrentStatus;
30
31 BOOL UpdateServiceStatus(DWORD dwCurrentState, DWORD dwWaitHint)
32 {
33 BOOL success;
34 SERVICE_STATUS nServiceStatus;
35 nServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
36 nServiceStatus.dwCurrentState = dwCurrentState;
37 if (dwCurrentState == SERVICE_START_PENDING)
38 {
39 nServiceStatus.dwControlsAccepted = 0;
40 }
41 else
42 {
43 nServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
44 }
45 nServiceStatus.dwWin32ExitCode = NO_ERROR;
46 nServiceStatus.dwServiceSpecificExitCode = 0;
47 nServiceStatus.dwCheckPoint = 0;
48 nServiceStatus.dwWaitHint = dwWaitHint;
49
50 success = SetServiceStatus(nServiceStatusHandle, &nServiceStatus);
51
52 return success;
53 }
54
55 void ServiceCtrlHandler(DWORD nControlCode)
56 {
57 switch(nControlCode)
58 {
59 case SERVICE_CONTROL_SHUTDOWN:
60 case SERVICE_CONTROL_STOP:
61 nServiceCurrentStatus = SERVICE_STOP_PENDING;
62 UpdateServiceStatus(SERVICE_STOP_PENDING, 10000);
63 ExitProc();
64 return;
65 default:
66 break;
67 }
68 UpdateServiceStatus(nServiceCurrentStatus, 0);
69 }
70
71 void ServiceMain(DWORD argc, LPTSTR *argv)
72 {
73 BOOL success;
74 nServiceStatusHandle = RegisterServiceCtrlHandler(strServiceName,
75 (LPHANDLER_FUNCTION)ServiceCtrlHandler);
76 if(!nServiceStatusHandle)
77 {
78 return;
79 }
80 success = UpdateServiceStatus(SERVICE_START_PENDING, 10000);
81 if(!success)
82 {
83 return;
84 }
85 nServiceCurrentStatus=SERVICE_RUNNING;
86 success=UpdateServiceStatus(SERVICE_RUNNING, 0);
87 if(!success)
88 {
89 return;
90 }
91
92 Run();
93
94 UpdateServiceStatus(SERVICE_STOPPED, 0);
95 }
96
97 void StartService(RunProc RunProcPtr)
98 {
99 Run = RunProcPtr;
100
101 SERVICE_TABLE_ENTRY servicetable[]=
102 {
103 {strServiceName,(LPSERVICE_MAIN_FUNCTION)ServiceMain},
104 {nullptr,nullptr}
105 };
106 BOOL success = StartServiceCtrlDispatcher(servicetable);
107 if(!success)
108 {
109 error("Could not start service");
110 }
111 }
112
113 void InstallService(int argc, char *argv[])
114 {
115 SC_HANDLE scm = OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE);
116 if(!scm)
117 {
118 printf("Could not install service\n");
119 return;
120 }
121
122 char exeName[1024];
123 GetModuleFileName(nullptr, exeName, 1024);
124 exeName[1024-1] = '\0';
125
126 BString<1024> cmdLine("%s -D", exeName);
127
128 SC_HANDLE hService = CreateService(scm, strServiceName,
129 strServiceName,
130 SERVICE_ALL_ACCESS,SERVICE_WIN32_OWN_PROCESS,SERVICE_DEMAND_START,
131 SERVICE_ERROR_NORMAL,
132 cmdLine,
133 0,0,0,0,0);
134 if(!hService)
135 {
136 CloseServiceHandle(scm);
137 printf("Could not install service\n");
138 return;
139 }
140 CloseServiceHandle(hService);
141 CloseServiceHandle(scm);
142 printf("Service \"%s\" sucessfully installed\n", strServiceName);
143 }
144
145 void UnInstallService()
146 {
147 BOOL success;
148 SC_HANDLE scm = OpenSCManager(0,0,SC_MANAGER_CONNECT);
149 if(!scm)
150 {
151 printf("Could not uninstall service\n");
152 return;
153 }
154
155 SC_HANDLE hService = OpenService(scm, strServiceName, STANDARD_RIGHTS_REQUIRED);
156 if(!hService)
157 {
158 CloseServiceHandle(scm);
159 printf("Could not uninstall service\n");
160 return;
161 }
162
163 success = DeleteService(hService);
164 if(!success)
165 {
166 error("Could not uninstall service");
167 }
168 CloseServiceHandle(hService);
169 CloseServiceHandle(scm);
170 printf("Service \"%s\" sucessfully uninstalled\n", strServiceName);
171 }
172
173 void InstallUninstallServiceCheck(int argc, char *argv[])
174 {
175 if (argc > 1 && (!strcasecmp(argv[1], "/install") || !strcasecmp(argv[1], "-install")))
176 {
177 InstallService(argc, argv);
178 exit(0);
179 }
180 else if (argc > 1 && (!strcasecmp(argv[1], "/uninstall") || !strcasecmp(argv[1], "/remove") ||
181 !strcasecmp(argv[1], "-uninstall") || !strcasecmp(argv[1], "-remove")))
182 {
183 UnInstallService();
184 exit(0);
185 }
186 }
187
188 bool IsServiceRunning()
189 {
190 SC_HANDLE scm = OpenSCManager(0, 0, 0);
191 if (!scm)
192 {
193 return false;
194 }
195
196 SC_HANDLE hService = OpenService(scm, "NZBGet", SERVICE_QUERY_STATUS);
197 SERVICE_STATUS ServiceStatus;
198 bool running = false;
199 if (hService && QueryServiceStatus(hService, &ServiceStatus))
200 {
201 running = ServiceStatus.dwCurrentState != SERVICE_STOPPED;
202 }
203
204 CloseServiceHandle(scm);
205
206 return running;
207 }
+0
-30
daemon/windows/WinService.h less more
0 /*
1 * This file is part of nzbget. See <http://nzbget.net>.
2 *
3 * Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19
20 #ifndef WINSERVICE_H
21 #define WINSERVICE_H
22
23 typedef void (*RunProc)(void);
24
25 void InstallUninstallServiceCheck(int argc, char *argv[]);
26 void StartService(RunProc RunProcPtr);
27 bool IsServiceRunning();
28
29 #endif
5151 <ClCompile>
5252 <Optimization>Disabled</Optimization>
5353 <AdditionalIncludeDirectories>.\daemon\connect;.\daemon\extension;.\daemon\feed;.\daemon\frontend;.\daemon\main;.\daemon\nserv;.\daemon\nntp;.\daemon\postprocess;.\daemon\queue;.\daemon\remote;.\daemon\util;.\daemon\windows;.\lib\par2;.\windows\resources;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
54 <PreprocessorDefinitions>WIN32;PACKAGE="nzbget";VERSION="19.0";_DEBUG;_CONSOLE;DEBUG;_WIN32_WINNT=0x0403;%(PreprocessorDefinitions)</PreprocessorDefinitions>
54 <PreprocessorDefinitions>WIN32;PACKAGE="nzbget";VERSION="19.1-testing";_DEBUG;_CONSOLE;DEBUG;_WIN32_WINNT=0x0403;%(PreprocessorDefinitions)</PreprocessorDefinitions>
5555 <MinimalRebuild>false</MinimalRebuild>
5656 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
5757 <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
7171 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
7272 <ClCompile>
7373 <AdditionalIncludeDirectories>.\daemon\connect;.\daemon\extension;.\daemon\feed;.\daemon\frontend;.\daemon\main;.\daemon\nserv;.\daemon\nntp;.\daemon\postprocess;.\daemon\queue;.\daemon\remote;.\daemon\util;.\daemon\windows;.\lib\par2;.\windows\resources;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
74 <PreprocessorDefinitions>WIN32;PACKAGE="nzbget";VERSION="19.0";NDEBUG;_CONSOLE;_WIN32_WINNT=0x0403;%(PreprocessorDefinitions)</PreprocessorDefinitions>
74 <PreprocessorDefinitions>WIN32;PACKAGE="nzbget";VERSION="19.1-testing";NDEBUG;_CONSOLE;_WIN32_WINNT=0x0403;%(PreprocessorDefinitions)</PreprocessorDefinitions>
7575 <ExceptionHandling>Sync</ExceptionHandling>
7676 <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
7777 <PrecompiledHeader>Use</PrecompiledHeader>
+0
-36
osx/App_Prefix.pch less more
0 /*
1 * This file is part of nzbget. See <http://nzbget.net>.
2 *
3 * Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #ifdef __OBJC__
20 #import <Cocoa/Cocoa.h>
21 #endif
22
23 #ifdef DEBUG
24 # define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
25 #else
26 # define DLog(...) do {} while (0)
27 #endif
28
29 #define SuppressPerformSelectorLeakWarning(Stuff) \
30 do { \
31 _Pragma("clang diagnostic push") \
32 _Pragma("clang diagnostic ignored \"-Warc-performSelector-leaks\"") \
33 Stuff; \
34 _Pragma("clang diagnostic pop") \
35 } while (0)
+0
-68
osx/DaemonController.h less more
0 /*
1 * This file is part of nzbget. See <http://nzbget.net>.
2 *
3 * Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #import <Cocoa/Cocoa.h>
20
21 @protocol DaemonControllerDelegate
22
23 - (void)daemonConfigLoaded;
24 - (void)daemonStatusUpdated;
25
26 @end
27
28
29 @interface DaemonController : NSObject {
30 NSString* lockFilePath;
31 NSDictionary* config;
32 int restartCounter;
33 int restartPid;
34 NSTimer* updateTimer;
35 int lastUptime;
36 BOOL factoryReset;
37 }
38
39 @property (nonatomic, assign) NSTimeInterval updateInterval;
40 @property (nonatomic, readonly) BOOL connected;
41 @property (nonatomic, readonly) BOOL restarting;
42 @property (nonatomic, readonly) BOOL recoveryMode;
43 @property (nonatomic, readonly) NSString* configFilePath;
44 @property (nonatomic, readonly) NSString* browserUrl;
45 @property (nonatomic, readonly) NSDate* lastUpdate;
46 @property (nonatomic, assign) id<DaemonControllerDelegate> delegate;
47 @property (nonatomic, readonly) NSDictionary* status;
48
49 - (id)init;
50
51 - (NSString*)valueForOption:(NSString*)option;
52
53 - (void)start;
54
55 - (void)stop;
56
57 - (void)restartInRecoveryMode:(BOOL)recovery withFactoryReset:(BOOL)reset;
58
59 - (NSString *)browserUrl;
60
61 - (void)updateStatus;
62
63 - (void)rpc:(NSString*)method success:(SEL)successCallback failure:(SEL)failureCallback;
64
65 - (void)setUpdateInterval:(NSTimeInterval)updateInterval;
66
67 @end
+0
-334
osx/DaemonController.m less more
0 /*
1 * This file is part of nzbget. See <http://nzbget.net>.
2 *
3 * Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <libproc.h>
20 #import <Cocoa/Cocoa.h>
21 #import "DaemonController.h"
22 #import "RPC.h"
23
24 NSString* MAIN_DIR = @"${AppSupDir}";
25 NSString* LOCK_FILE = @"${AppSupDir}/nzbget.lock";
26 NSString* CONFIG_FILE = @"${AppSupDir}/nzbget.conf";
27 NSString* SCRIPTS_DIR = @"${AppSupDir}/scripts";
28 NSString* NZB_DIR = @"${AppSupDir}/nzb";
29 NSString* QUEUE_DIR = @"${AppSupDir}/queue";
30 NSString* TMP_DIR = @"${AppSupDir}/tmp";
31
32 @implementation DaemonController
33
34 - (id)init {
35 self = [super init];
36
37 _configFilePath = [self resolveAppSupDir:CONFIG_FILE];
38 lockFilePath = [self resolveAppSupDir:LOCK_FILE];
39
40 return self;
41 }
42
43 - (NSString *) bundlePath {
44 return [[NSBundle mainBundle] pathForResource:@"daemon" ofType:nil];
45 }
46
47 - (NSString *) resolveAppSupDir:(NSString *)dir {
48 NSString *appSupPath = [@"${AppSupDir}/Application Support/NZBGet" stringByExpandingTildeInPath];
49
50 NSArray* paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
51 if (paths.count > 0)
52 {
53 appSupPath = [paths objectAtIndex:0];
54 appSupPath = [appSupPath stringByAppendingPathComponent:@"NZBGet"];
55 }
56
57 dir = [dir stringByReplacingOccurrencesOfString:@"${AppSupDir}"
58 withString:appSupPath
59 options:NSCaseInsensitiveSearch
60 range:NSMakeRange(0, dir.length)];
61 return dir;
62 }
63
64 - (void) checkDefaults {
65 NSString* mainDir = [self resolveAppSupDir:MAIN_DIR];
66 if (![[NSFileManager defaultManager] fileExistsAtPath:mainDir]) {
67 [[NSFileManager defaultManager] createDirectoryAtPath:mainDir withIntermediateDirectories:YES attributes:nil error:nil];
68 }
69
70 NSString* bundlePath = [self bundlePath];
71
72 if (![[NSFileManager defaultManager] fileExistsAtPath:_configFilePath]) {
73 NSString* configTemplate = [NSString stringWithFormat:@"%@/usr/local/share/nzbget/nzbget.conf", bundlePath];
74 [[NSFileManager defaultManager] copyItemAtPath:configTemplate toPath:_configFilePath error:nil];
75 }
76
77 NSString* scriptsDir = [self resolveAppSupDir:SCRIPTS_DIR];
78 if (![[NSFileManager defaultManager] fileExistsAtPath:scriptsDir]) {
79 NSString* scriptsTemplate = [NSString stringWithFormat:@"%@/usr/local/share/nzbget/scripts", bundlePath];
80 [[NSFileManager defaultManager] copyItemAtPath:scriptsTemplate toPath:scriptsDir error:nil];
81 }
82 }
83
84 - (int)readLockFilePid {
85 if ([[NSFileManager defaultManager] fileExistsAtPath:lockFilePath]) {
86 // Lock file exists
87 // read pid from lock file
88 int pid = [[NSString stringWithContentsOfFile:lockFilePath encoding:NSUTF8StringEncoding error:nil] intValue];
89 DLog(@"pid: %i", pid);
90
91 // check if the process name is "nzbget" to avoid killing of other proceses
92 char pathbuf[PROC_PIDPATHINFO_MAXSIZE];
93 int ret = proc_pidpath(pid, pathbuf, sizeof(pathbuf));
94 if (ret <= 0) {
95 // error
96 return 0;
97 }
98
99 DLog(@"proc %d: %s\n", pid, pathbuf);
100
101 NSString* instancePath = [NSString stringWithUTF8String:pathbuf];
102 if ([instancePath hasSuffix:@".app/Contents/Resources/daemon/usr/local/bin/nzbget"]) {
103 return pid;
104 }
105 }
106
107 return 0;
108 }
109
110 - (void)killDaemonWithSignal:(int)signal {
111 int pid = [self readLockFilePid];
112 if (pid > 0) {
113 kill(pid, signal);
114 [[NSFileManager defaultManager] removeItemAtPath:lockFilePath error:nil];
115 }
116 }
117
118 - (void)start {
119 DLog(@"DaemonController->start");
120
121 [self checkDefaults];
122 [self killDaemonWithSignal:SIGKILL];
123 [self readConfigFile];
124 [self initRpcUrl];
125 [self initBrowserUrl];
126
127 NSString* bundlePath = [self bundlePath];
128 NSString* daemonPath = [NSString stringWithFormat:@"%@/usr/local/bin/nzbget", bundlePath];
129 NSString* optionWebDir = [NSString stringWithFormat:@"WebDir=%@/usr/local/share/nzbget/webui", bundlePath];
130 NSString* optionConfigTemplate = [NSString stringWithFormat:@"ConfigTemplate=%@/usr/local/share/nzbget/nzbget.conf", bundlePath];
131 NSString* optionLockFile = [NSString stringWithFormat:@"LockFile=%@", lockFilePath];
132
133 NSMutableArray* arguments = [NSMutableArray arrayWithObjects:
134 @"-c", _configFilePath,
135 @"-D",
136 @"-o", optionWebDir,
137 @"-o", optionConfigTemplate,
138 @"-o", optionLockFile,
139 nil];
140
141 if (_recoveryMode) {
142 [arguments addObjectsFromArray: [NSArray arrayWithObjects:
143 @"-o", @"ControlIP=127.0.0.1",
144 @"-o", @"ControlPort=6789",
145 @"-o", @"ControlPassword=",
146 @"-o", @"SecureControl=no",
147 nil
148 ]];
149 }
150
151 NSTask* task = [[NSTask alloc] init];
152 [task setLaunchPath: daemonPath];
153 [task setArguments: arguments];
154 [task launch];
155
156 _restarting = NO;
157 [self scheduleNextUpdate];
158 }
159
160 - (void)stop {
161 DLog(@"DaemonController->stop");
162 [self killDaemonWithSignal:SIGTERM];
163 }
164
165 - (void)restartInRecoveryMode:(BOOL)recovery withFactoryReset:(BOOL)reset {
166 _recoveryMode = recovery;
167 factoryReset = reset;
168 _restarting = YES;
169 restartPid = [self readLockFilePid];
170 [self stop];
171
172 // in timer wait for deletion of lockfile for 10 seconds,
173 // after that call "start" which will kill the old process.
174 restartCounter = 0;
175 [self restartWait];
176 }
177
178 - (void)restartWait {
179 DLog(@"DaemonController->restartWait");
180 restartCounter++;
181
182 char pathbuf[PROC_PIDPATHINFO_MAXSIZE];
183 int ret = proc_pidpath(restartPid, pathbuf, sizeof(pathbuf));
184 if (ret > 0 && restartCounter < 100) {
185 DLog(@"restartWait: scheduleNextRestartWait");
186 [self scheduleNextRestartWait];
187 } else {
188 DLog(@"restartWait: start");
189 if (factoryReset) {
190 [self resetToFactoryDefaults];
191 }
192 [self start];
193 }
194 }
195
196 - (void)resetToFactoryDefaults {
197 DLog(@"DaemonController->resetToFactoryDefaults");
198 [[NSFileManager defaultManager] removeItemAtPath:_configFilePath error:nil];
199 [[NSFileManager defaultManager] removeItemAtPath:[self resolveAppSupDir:QUEUE_DIR] error:nil];
200 [[NSFileManager defaultManager] removeItemAtPath:[self resolveAppSupDir:SCRIPTS_DIR] error:nil];
201 [[NSFileManager defaultManager] removeItemAtPath:[self resolveAppSupDir:NZB_DIR] error:nil];
202 [[NSFileManager defaultManager] removeItemAtPath:[self resolveAppSupDir:TMP_DIR] error:nil];
203 }
204
205 - (void)scheduleNextRestartWait {
206 NSTimer* timer = [NSTimer timerWithTimeInterval:0.100 target:self selector:@selector(restartWait) userInfo:nil repeats:NO];
207 [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
208 }
209
210 - (void)readConfigFile {
211 DLog(@"DaemonController->readConfigFile");
212 NSString* str = [NSString stringWithContentsOfFile:_configFilePath encoding:NSUTF8StringEncoding error:nil];
213 NSArray* conf = [str componentsSeparatedByString: @"\n"];
214 config = [[NSMutableDictionary alloc] init];
215
216 for (NSString* opt in conf) {
217 if ([opt hasPrefix:@"#"]) {
218 continue;
219 }
220 NSRange pos = [opt rangeOfString:@"="];
221 if (pos.location != NSNotFound) {
222 NSString* name = [opt substringToIndex:pos.location];
223 name = [name stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceCharacterSet]];
224 NSString* value = [opt substringFromIndex:pos.location + 1];
225 value = [value stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceCharacterSet]];
226 [config setValue:value forKey:[name uppercaseString]];
227 }
228 }
229
230 if (_recoveryMode) {
231 [config setValue:@"localhost" forKey:@"CONTROLIP"];
232 [config setValue:@"6789" forKey:@"CONTROLPORT"];
233 [config setValue:@"" forKey:@"CONTROLPASSWORD"];
234 }
235
236 [_delegate daemonConfigLoaded];
237 }
238
239 - (NSString*)valueForOption:(NSString*)option {
240 return [config valueForKey:[option uppercaseString]];
241 }
242
243 - (void)initBrowserUrl {
244 NSString* ip = [self valueForOption:@"ControlIP"];
245 if ([ip isEqualToString:@"0.0.0.0"] || [ip isEqualToString:@"127.0.0.1"]) {
246 ip = @"localhost";
247 }
248 NSString* port = [self valueForOption:@"ControlPort"];
249 _browserUrl = [NSString stringWithFormat:@"http://@%@:%@", ip, port];
250 }
251
252 - (void)initRpcUrl {
253 NSString* ip = [self valueForOption:@"ControlIP"];
254 if ([ip isEqualToString:@"0.0.0.0"]) {
255 ip = @"127.0.0.1";
256 }
257 NSString* port = [self valueForOption:@"ControlPort"];
258 NSString* username = [self valueForOption:@"ControlUsername"];
259 NSString* password = [self valueForOption:@"ControlPassword"];
260 NSString* RpcUrl = [NSString stringWithFormat:@"http://%@:%@/%@:%@/jsonrpc/", ip, port, username, password];
261 [RPC setRpcUrl:RpcUrl];
262 }
263
264 - (void)setUpdateInterval:(NSTimeInterval)updateInterval {
265 _updateInterval = updateInterval;
266 if (_connected) {
267 [updateTimer invalidate];
268 [self updateStatus];
269 }
270 }
271
272 - (void)scheduleNextUpdate {
273 updateTimer = [NSTimer timerWithTimeInterval:_updateInterval target:self selector:@selector(updateStatus) userInfo:nil repeats:NO];
274 [[NSRunLoop currentRunLoop] addTimer:updateTimer forMode:NSRunLoopCommonModes];
275 }
276
277 - (void)rpc:(NSString*)method success:(SEL)successCallback failure:(SEL)failureCallback {
278 RPC* rpc = [[RPC alloc] initWithMethod:method receiver:self success:successCallback failure:failureCallback];
279 [rpc start];
280 }
281
282 - (void)receiveStatus:(NSDictionary*)status {
283 //DLog(@"receiveStatus");
284 if (_restarting) {
285 return;
286 }
287
288 _connected = YES;
289 _lastUpdate = [NSDate date];
290 _status = status;
291
292 //DLog(@"response: %@", status);
293
294 int uptime = [(NSNumber*)[status objectForKey:@"UpTimeSec"] integerValue];
295 if (lastUptime == 0) {
296 lastUptime = uptime;
297 } else if (lastUptime > uptime) {
298 // daemon was reloaded (soft-restart)
299 [self readConfigFile];
300 }
301
302 [_delegate daemonStatusUpdated];
303 [self scheduleNextUpdate];
304 }
305
306 - (void)failureStatus {
307 DLog(@"failureStatus");
308 if (_restarting) {
309 return;
310 }
311
312 _connected = NO;
313
314 int pid = [self readLockFilePid];
315 if (pid == 0) {
316 // Daemon is not running. Crashed?
317 _restarting = YES;
318 [_delegate daemonStatusUpdated];
319 [self start];
320 } else {
321 [_delegate daemonStatusUpdated];
322 [self scheduleNextUpdate];
323 }
324 }
325
326 - (void)updateStatus {
327 if (_restarting) {
328 return;
329 }
330 [self rpc:@"status" success:@selector(receiveStatus:) failure:@selector(failureStatus)];
331 }
332
333 @end
+0
-81
osx/MainApp.h less more
0 /*
1 * This file is part of nzbget. See <http://nzbget.net>.
2 *
3 * Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #import <Cocoa/Cocoa.h>
20 #import <IOKit/pwr_mgt/IOPMLib.h>
21 #import "DaemonController.h"
22
23 @interface MainApp : NSObject <NSMenuDelegate, DaemonControllerDelegate> {
24 IBOutlet NSMenu *statusMenu;
25 NSStatusItem *statusItem;
26 IBOutlet NSMenuItem *webuiItem;
27 IBOutlet NSMenuItem *homePageItem;
28 IBOutlet NSMenuItem *downloadsItem;
29 IBOutlet NSMenuItem *forumItem;
30 IBOutlet NSMenuItem *info1Item;
31 IBOutlet NSMenuItem *info2Item;
32 IBOutlet NSMenuItem *restartRecoveryItem;
33 IBOutlet NSMenuItem *factoryResetItem;
34 IBOutlet NSMenuItem *destDirItem;
35 IBOutlet NSMenuItem *interDirItem;
36 IBOutlet NSMenuItem *nzbDirItem;
37 IBOutlet NSMenuItem *scriptDirItem;
38 IBOutlet NSMenuItem *configFileItem;
39 IBOutlet NSMenuItem *logFileItem;
40 IBOutlet NSMenuItem *destDirSeparator;
41 NSWindowController *welcomeDialog;
42 NSWindowController *preferencesDialog;
43 DaemonController *daemonController;
44 int connectionAttempts;
45 BOOL restarting;
46 BOOL resetting;
47 BOOL preventingSleep;
48 IOPMAssertionID sleepID;
49 NSTimer* restartTimer;
50 NSMutableArray* categoryItems;
51 NSMutableArray* categoryDirs;
52 }
53
54 + (void)setupAppDefaults;
55
56 - (void)setupDefaultsObserver;
57
58 - (IBAction)quitClicked:(id)sender;
59
60 - (IBAction)preferencesClicked:(id)sender;
61
62 - (void)userDefaultsDidChange:(id)sender;
63
64 - (IBAction)aboutClicked:(id)sender;
65
66 + (BOOL)wasLaunchedAsLoginItem;
67
68 - (IBAction)webuiClicked:(id)sender;
69
70 - (IBAction)infoLinkClicked:(id)sender;
71
72 - (IBAction)openConfigInTextEditClicked:(id)sender;
73
74 - (IBAction)restartClicked:(id)sender;
75
76 - (IBAction)showInFinderClicked:(id)sender;
77
78 - (void)updateSleepState:(BOOL)preventSleep;
79
80 @end
+0
-605
osx/MainApp.m less more
0 /*
1 * This file is part of nzbget. See <http://nzbget.net>.
2 *
3 * Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #import "MainApp.h"
20 #import "PreferencesDialog.h"
21 #import "WelcomeDialog.h"
22 #import "PFMoveApplication.h"
23
24 NSString *PreferencesContext = @"PreferencesContext";
25 const NSTimeInterval NORMAL_UPDATE_INTERVAL = 10.000;
26 const NSTimeInterval MENUOPEN_UPDATE_INTERVAL = 1.000;
27 const NSTimeInterval START_UPDATE_INTERVAL = 0.500;
28
29 int main(int argc, char *argv[]) {
30 return NSApplicationMain(argc, (const char **)argv);
31 }
32
33 /*
34 * Signal handler
35 */
36 void SignalProc(int iSignal)
37 {
38 switch (iSignal)
39 {
40 case SIGINT:
41 case SIGTERM:
42 signal(iSignal, SIG_DFL); // Reset the signal handler
43 [NSApp terminate:nil];
44 break;
45 }
46 }
47
48 // we install seignal handler in order to properly terminat app from Activity Mo1nitor
49 void InstallSignalHandlers()
50 {
51 signal(SIGINT, SignalProc);
52 signal(SIGTERM, SignalProc);
53 signal(SIGPIPE, SIG_IGN);
54 }
55
56 @implementation MainApp
57
58 - (void)applicationWillFinishLaunching:(NSNotification *)aNotification {
59 [self checkOtherRunningInstances];
60 #ifndef DEBUG
61 PFMoveToApplicationsFolderIfNecessary();
62 #endif
63 }
64
65 - (void)checkOtherRunningInstances {
66 for (NSRunningApplication *runningApplication in [NSRunningApplication runningApplicationsWithBundleIdentifier:[[NSBundle mainBundle] bundleIdentifier]]) {
67 if (![[runningApplication executableURL] isEqualTo:[[NSRunningApplication currentApplication] executableURL]]) {
68 NSString *executablePath = [[runningApplication executableURL] path];
69 executablePath = [[[executablePath stringByDeletingLastPathComponent] stringByDeletingLastPathComponent] stringByDeletingLastPathComponent];
70 DLog(@"Switching to an already running instance: %@", executablePath);
71 [[NSTask launchedTaskWithLaunchPath:@"/usr/bin/open"
72 arguments:[NSArray arrayWithObjects:executablePath, @"--args", @"--second-instance", nil]] waitUntilExit];
73 exit(0);
74 }
75 }
76 }
77
78 - (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
79 BOOL autoStartWebUI = [[NSUserDefaults standardUserDefaults] boolForKey:@"AutoStartWebUI"];
80
81 daemonController = [[DaemonController alloc] init];
82 daemonController.updateInterval = autoStartWebUI ? START_UPDATE_INTERVAL : NORMAL_UPDATE_INTERVAL;
83 daemonController.delegate = self;
84
85 [self setupDefaultsObserver];
86 [self userDefaultsDidChange:nil];
87
88 if (![MainApp wasLaunchedAsLoginItem]) {
89 [self showWelcomeScreen];
90 }
91
92 InstallSignalHandlers();
93
94 DLog(@"Start Daemon");
95 [daemonController start];
96 }
97
98 - (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag {
99 DLog(@"applicationShouldHandleReopen");
100 [self showAlreadyRunning];
101 return YES;
102 }
103
104 + (void)initialize {
105 [self setupAppDefaults];
106 }
107
108 - (void)awakeFromNib {
109 DLog(@"awakeFromNib");
110 [statusMenu setDelegate:self];
111 }
112
113 + (void)setupAppDefaults {
114 NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
115 NSDictionary *appDefaults = [NSDictionary dictionaryWithObjectsAndKeys:
116 @"YES", @"ShowInMenubar",
117 @"NO", @"Autostart",
118 @"YES", @"AutoStartWebUI",
119 nil];
120 [userDefaults registerDefaults:appDefaults];
121 }
122
123 - (void)setupDefaultsObserver {
124 NSUserDefaultsController *sdc = [NSUserDefaultsController sharedUserDefaultsController];
125 [sdc addObserver:self forKeyPath:@"values.ShowInMenubar" options:0 context:(__bridge void *)(PreferencesContext)];
126 [sdc addObserver:self forKeyPath:@"values.AutoStartWebUI" options:0 context:(__bridge void *)(PreferencesContext)];
127 }
128
129 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
130 if (context == (__bridge void *)(PreferencesContext)) {
131 [self userDefaultsDidChange:nil];
132 }
133 else {
134 [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
135 }
136 }
137
138 - (void)userDefaultsDidChange:(id)sender {
139 DLog(@"userDefaultsDidChange: %@", sender);
140 BOOL showInMenubar = [[NSUserDefaults standardUserDefaults] boolForKey:@"ShowInMenubar"];
141 if (showInMenubar != (statusItem != nil)) {
142 if (showInMenubar) {
143 statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength];
144 [statusItem setHighlightMode:YES];
145 [statusItem setMenu:statusMenu];
146 NSImage* icon = [NSImage imageNamed:@"statusicon.png"];
147 [icon setTemplate:YES];
148 [statusItem setImage:icon];
149 }
150 else {
151 statusItem = nil;
152 }
153 }
154 }
155
156 - (IBAction)preferencesClicked:(id)sender {
157 [self showPreferences];
158 }
159
160 - (void)showPreferences {
161 [NSApp activateIgnoringOtherApps:TRUE];
162 if (preferencesDialog) {
163 return;
164 }
165 preferencesDialog = [[PreferencesDialog alloc] init];
166 [[preferencesDialog window] center];
167 [preferencesDialog showWindow:nil];
168 [[NSNotificationCenter defaultCenter] addObserver:self
169 selector:@selector(preferencesWillClose:)
170 name:NSWindowWillCloseNotification
171 object:[preferencesDialog window]];
172 }
173
174 - (void)preferencesWillClose:(NSNotification *)notification {
175 DLog(@"Pref Closed");
176 [[NSNotificationCenter defaultCenter] removeObserver:self
177 name:NSWindowWillCloseNotification
178 object:[preferencesDialog window]];
179 preferencesDialog = nil;
180 [self userDefaultsDidChange:nil];
181 }
182
183 - (IBAction)aboutClicked:(id)sender {
184 [NSApp activateIgnoringOtherApps:TRUE];
185 [NSApp orderFrontStandardAboutPanel:nil];
186 }
187
188 - (IBAction)quitClicked:(id)sender {
189 DLog(@"Quit");
190 [NSApp terminate:nil];
191 }
192
193 - (void)showWelcomeScreen {
194 welcomeDialog = [[WelcomeDialog alloc] init];
195 [(WelcomeDialog*)welcomeDialog setMainDelegate:self];
196 [(WelcomeDialog*)welcomeDialog showDialog];
197 }
198
199 - (void)showAlreadyRunning {
200 BOOL showInMenubar = [[NSUserDefaults standardUserDefaults] boolForKey:@"ShowInMenubar"];
201
202 [NSApp activateIgnoringOtherApps:TRUE];
203 NSAlert *alert = [[NSAlert alloc] init];
204 [alert setMessageText:NSLocalizedString(@"AlreadyRunning.MessageText", nil)];
205 [alert setInformativeText:NSLocalizedString(showInMenubar ? @"AlreadyRunning.InformativeTextWithIcon" : @"AlreadyRunning.InformativeTextWithoutIcon", nil)];
206 NSButton* webUIButton = [alert addButtonWithTitle:NSLocalizedString(@"AlreadyRunning.WebUI", nil)];
207 [alert addButtonWithTitle:NSLocalizedString(@"AlreadyRunning.Preferences", nil)];
208 [alert addButtonWithTitle:NSLocalizedString(@"AlreadyRunning.Quit", nil)];
209 [alert.window makeFirstResponder:webUIButton];
210 [webUIButton setKeyEquivalent:@"\r"];
211 switch ([alert runModal]) {
212 case NSAlertFirstButtonReturn:
213 [self showWebUI];
214 break;
215
216 case NSAlertSecondButtonReturn:
217 [self showPreferences];
218 break;
219
220 case NSAlertThirdButtonReturn:
221 [self quitClicked:nil];
222 break;
223 }
224 }
225
226 + (BOOL)wasLaunchedByProcess:(NSString*)creator {
227 BOOL wasLaunchedByProcess = NO;
228
229 // Get our PSN
230 OSStatus err;
231 ProcessSerialNumber currPSN;
232 err = GetCurrentProcess (&currPSN);
233 if (!err) {
234 // We don't use ProcessInformationCopyDictionary() because the 'ParentPSN' item in the dictionary
235 // has endianness problems in 10.4, fixed in 10.5 however.
236 ProcessInfoRec procInfo;
237 bzero (&procInfo, sizeof (procInfo));
238 procInfo.processInfoLength = (UInt32)sizeof (ProcessInfoRec);
239 err = GetProcessInformation (&currPSN, &procInfo);
240 if (!err) {
241 ProcessSerialNumber parentPSN = procInfo.processLauncher;
242
243 // Get info on the launching process
244 NSDictionary* parentDict = (__bridge NSDictionary*)ProcessInformationCopyDictionary (&parentPSN, kProcessDictionaryIncludeAllInformationMask);
245
246 // Test the creator code of the launching app
247 if (parentDict) {
248 wasLaunchedByProcess = [[parentDict objectForKey:@"FileCreator"] isEqualToString:creator];
249 }
250 }
251 }
252
253 return wasLaunchedByProcess;
254 }
255
256 + (BOOL)wasLaunchedAsLoginItem {
257 // If the launching process was 'loginwindow', we were launched as a login item
258 return [self wasLaunchedByProcess:@"lgnw"];
259 }
260
261 - (IBAction)webuiClicked:(id)sender {
262 if (daemonController.connected) {
263 [self showWebUI];
264 } else {
265 [NSApp activateIgnoringOtherApps:TRUE];
266 NSAlert *alert = [[NSAlert alloc] init];
267 [alert setMessageText:NSLocalizedString(@"ShowWebUINoConnection.MessageText", nil)];
268 [alert setInformativeText:NSLocalizedString(@"ShowWebUINoConnection.InformativeText", nil)];
269 [alert setAlertStyle:NSWarningAlertStyle];
270 [alert runModal];
271 }
272 }
273
274 - (void)showWebUI {
275 DLog(@"showWebUI");
276 [[NSWorkspace sharedWorkspace] openURL: [NSURL URLWithString:daemonController.browserUrl]];
277 }
278
279 - (IBAction)openConfigInTextEditClicked:(id)sender {
280 NSString *configFile = [daemonController configFilePath];
281 [[NSWorkspace sharedWorkspace] openFile:configFile withApplication:@"TextEdit"];
282 }
283
284 - (IBAction)restartClicked:(id)sender {
285 if (sender == factoryResetItem) {
286 [NSApp activateIgnoringOtherApps:TRUE];
287 NSAlert *alert = [[NSAlert alloc] init];
288 [alert setMessageText:NSLocalizedString(@"FactoryReset.MessageText", nil)];
289 [alert setInformativeText:NSLocalizedString(@"FactoryReset.InformativeText", nil)];
290 [alert setAlertStyle:NSCriticalAlertStyle];
291 NSButton* cancelButton = [alert addButtonWithTitle:NSLocalizedString(@"FactoryReset.Cancel", nil)];
292 // we use middle invisible button to align the third RESET-button at left side
293 [[alert addButtonWithTitle:@"Cancel"] setHidden:YES];
294 [alert addButtonWithTitle:NSLocalizedString(@"FactoryReset.Reset", nil)];
295 [alert.window makeFirstResponder:cancelButton];
296 [cancelButton setKeyEquivalent:@"\E"];
297 if ([alert runModal] != NSAlertThirdButtonReturn) {
298 return;
299 }
300 }
301
302 restarting = YES;
303 resetting = sender == factoryResetItem;
304 [self updateStatus];
305 [daemonController restartInRecoveryMode: sender == restartRecoveryItem withFactoryReset: sender == factoryResetItem];
306 daemonController.updateInterval = START_UPDATE_INTERVAL;
307
308 restartTimer = [NSTimer timerWithTimeInterval:10.000 target:self selector:@selector(restartFailed) userInfo:nil repeats:NO];
309 [[NSRunLoop currentRunLoop] addTimer:restartTimer forMode:NSRunLoopCommonModes];
310 }
311
312 - (void)welcomeContinue {
313 DLog(@"welcomeContinue");
314 BOOL autoStartWebUI = [[NSUserDefaults standardUserDefaults] boolForKey:@"AutoStartWebUI"];
315 if (autoStartWebUI) {
316 if (daemonController.connected) {
317 if (daemonController.updateInterval == START_UPDATE_INTERVAL)
318 {
319 daemonController.updateInterval = NORMAL_UPDATE_INTERVAL;
320 }
321 [self showWebUI];
322 } else {
323 // try again in 100 msec for max. 25 seconds, then give up
324 connectionAttempts++;
325 if (connectionAttempts < 250) {
326 [self performSelector:@selector(welcomeContinue) withObject:nil afterDelay: 0.100];
327 } else {
328 // show error message
329 [self webuiClicked:nil];
330 }
331 }
332 }
333 }
334
335 - (void)applicationWillTerminate:(NSNotification *)aNotification {
336 DLog(@"Stop Daemon");
337 [daemonController stop];
338 }
339
340 - (void)menuWillOpen:(NSMenu *)menu {
341 DLog(@"menuWillOpen");
342 daemonController.updateInterval = MENUOPEN_UPDATE_INTERVAL;
343 }
344
345 - (void)menuDidClose:(NSMenu *)menu {
346 DLog(@"menuDidClose");
347 daemonController.updateInterval = NORMAL_UPDATE_INTERVAL;
348 }
349
350 - (IBAction)infoLinkClicked:(id)sender {
351 NSString *url;
352
353 if (sender == homePageItem) {
354 url = NSLocalizedString(@"Menu.LinkHomePage", nil);
355 }
356 else if (sender == downloadsItem) {
357 url = NSLocalizedString(@"Menu.LinkDownloads", nil);
358 }
359 else if (sender == forumItem) {
360 url = NSLocalizedString(@"Menu.LinkForum", nil);
361 }
362
363 [[NSWorkspace sharedWorkspace] openURL: [NSURL URLWithString:url]];
364 }
365
366 - (void)restartFailed {
367 if (restarting) {
368 restarting = NO;
369 resetting = NO;
370 daemonController.updateInterval = NORMAL_UPDATE_INTERVAL;
371 [NSApp activateIgnoringOtherApps:TRUE];
372 NSAlert *alert = [[NSAlert alloc] init];
373 [alert setMessageText:NSLocalizedString(@"RestartNoConnection.MessageText", nil)];
374 [alert setInformativeText:NSLocalizedString(@"RestartNoConnection.InformativeText", nil)];
375 [alert setAlertStyle:NSWarningAlertStyle];
376 [alert runModal];
377 }
378 }
379
380 - (IBAction)showInFinderClicked:(id)sender {
381 NSString* dir = nil;
382 NSString* option = nil;
383
384 if (sender == destDirItem) {
385 option = @"DestDir";
386 } else if (sender == interDirItem) {
387 option = @"InterDir";
388 } else if (sender == nzbDirItem) {
389 option = @"NzbDir";
390 } else if (sender == scriptDirItem) {
391 option = @"ScriptDir";
392 } else if (sender == logFileItem) {
393 option = @"LogFile";
394 } else if (sender == configFileItem) {
395 dir = [daemonController configFilePath];
396 } else if ([categoryItems containsObject:sender]) {
397 int index = [categoryItems indexOfObject:sender];
398 dir = [categoryDirs objectAtIndex:index];
399 } else {
400 return;
401 }
402
403 if (dir == nil) {
404 NSString* mainDir = [[daemonController valueForOption:@"MainDir"] stringByExpandingTildeInPath];
405 dir = [[daemonController valueForOption:option] stringByExpandingTildeInPath];
406 dir = [dir stringByReplacingOccurrencesOfString:@"${MainDir}"
407 withString:mainDir
408 options:NSCaseInsensitiveSearch
409 range:NSMakeRange(0, [dir length])];
410 }
411
412 dir = [[dir componentsSeparatedByCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:@";,"]] objectAtIndex:0];
413
414 if (dir.length == 0 || ![[NSFileManager defaultManager] fileExistsAtPath:dir]) {
415 [NSApp activateIgnoringOtherApps:TRUE];
416 NSAlert *alert = [[NSAlert alloc] init];
417 [alert setMessageText:[NSString stringWithFormat:NSLocalizedString(@"CantShowInFinder.MessageText", nil), dir]];
418 [alert setInformativeText:[NSString stringWithFormat:NSLocalizedString(option == nil ? @"CantShowInFinder.InformativeTextForCategory" : @"CantShowInFinder.InformativeTextWithOption", nil), option]];
419 [alert runModal];
420 return;
421 }
422
423 [[NSWorkspace sharedWorkspace] activateFileViewerSelectingURLs:@[[NSURL fileURLWithPath:dir isDirectory:YES]]];
424 }
425
426 - (void)daemonStatusUpdated {
427 if (restarting && daemonController.connected) {
428 restarting = NO;
429 [restartTimer invalidate];
430 [NSApp activateIgnoringOtherApps:TRUE];
431 NSAlert *alert = [[NSAlert alloc] init];
432 [alert setMessageText:NSLocalizedString(resetting ? @"FactoryResetted.MessageText" : daemonController.recoveryMode ? @"RestartedRecoveryMode.MessageText" : @"Restarted.MessageText", nil)];
433 [alert setInformativeText:NSLocalizedString(resetting ? @"FactoryResetted.InformativeText" : daemonController.recoveryMode ? @"RestartedRecoveryMode.InformativeText" : @"Restarted.InformativeText", nil)];
434 [alert setAlertStyle:NSInformationalAlertStyle];
435 [alert addButtonWithTitle:NSLocalizedString(@"Restarted.OK", nil)];
436 [alert addButtonWithTitle:NSLocalizedString(@"Restarted.WebUI", nil)];
437 if ([alert runModal] == NSAlertSecondButtonReturn) {
438 [self showWebUI];
439 }
440 resetting = NO;
441 } else {
442 [self updateStatus];
443 }
444 }
445
446 - (void)updateStatus {
447 //DLog(@"updateStatus");
448
449 NSString* info1 = @"";
450 NSString* info2 = nil;
451 BOOL preventSleep = NO;
452
453 NSDictionary* status = [daemonController status];
454 if (restarting || daemonController.restarting) {
455 info1 = NSLocalizedString(@"Status.Restarting", nil);
456 } else if (!daemonController.connected) {
457 info1 = NSLocalizedString(@"Status.NoConnection", nil);
458 } else if ([(NSNumber*)[status objectForKey:@"ServerStandBy"] integerValue] == 1) {
459 if ([(NSNumber*)[status objectForKey:@"PostJobCount"] integerValue] > 0) {
460 info1 = NSLocalizedString(@"Status.Post-Processing", nil);
461 preventSleep = YES;
462 }
463 else if ([(NSNumber*)[status objectForKey:@"UrlCount"] integerValue] > 0) {
464 info1 = NSLocalizedString(@"Status.Fetching NZBs", nil);
465 }
466 else if ([(NSNumber*)[status objectForKey:@"FeedActive"] integerValue] == 1) {
467 info1 = NSLocalizedString(@"Status.Fetching Feeds", nil);
468 }
469 else if ([(NSNumber*)[status objectForKey:@"DownloadPaused"] integerValue] == 1 ||
470 [(NSNumber*)[status objectForKey:@"Download2Paused"] integerValue] == 1) {
471 info1 = NSLocalizedString(@"Status.Paused", nil);
472 } else {
473 info1 = NSLocalizedString(@"Status.Idle", nil);
474 }
475 } else {
476 int speed = [(NSNumber*)[status objectForKey:@"DownloadRate"] integerValue];
477 if (speed >= 1024 * 1024 * 10) {
478 info1 = [NSString stringWithFormat:NSLocalizedString(@"Status.DownloadingMB10", nil), speed / 1024 / 1024];
479 }
480 else if (speed >= 1024 * 1024) {
481 info1 = [NSString stringWithFormat:NSLocalizedString(@"Status.DownloadingMB", nil), (float)speed / 1024.0 / 1024.0];
482 }
483 else {
484 info1 = [NSString stringWithFormat:NSLocalizedString(@"Status.DownloadingKB", nil), speed / 1024];
485 }
486 preventSleep = YES;
487
488 if (speed > 0) {
489 long long remaining = ([(NSNumber*)[status objectForKey:@"RemainingSizeHi"] integerValue] << 32) + [(NSNumber*)[status objectForKey:@"RemainingSizeLo"] integerValue];
490 int secondsLeft = remaining / speed;
491 info2 = [NSString stringWithFormat:NSLocalizedString(@"Status.Left", nil), [self formatTimeLeft:secondsLeft]];
492 }
493 }
494
495 if (preventSleep != preventingSleep) {
496 [self updateSleepState:preventSleep];
497 }
498
499 [info1Item setTitle:info1];
500
501 [info2Item setHidden:info2 == nil];
502 if (info2 != nil) {
503 [info2Item setTitle:info2];
504 }
505 }
506
507 - (void)updateSleepState:(BOOL)preventSleep {
508 if (preventSleep) {
509 sleepID = 0;
510 NSString* reason = NSLocalizedString(@"Status.PreventSleep", nil);
511 IOPMAssertionCreateWithName(kIOPMAssertionTypePreventUserIdleSystemSleep,
512 kIOPMAssertionLevelOn, (__bridge CFStringRef)reason, &sleepID);
513 }
514 else if (sleepID != 0) {
515 IOPMAssertionRelease(sleepID);
516 }
517 preventingSleep = preventSleep;
518 }
519
520 - (NSString*)formatTimeLeft:(int)sec {
521 int days = floor(sec / 86400);
522 int hours = floor((sec % 86400) / 3600);
523 int minutes = floor((sec / 60) % 60);
524 int seconds = floor(sec % 60);
525
526 if (days > 10)
527 {
528 return [NSString stringWithFormat:NSLocalizedString(@"Left.Days", nil), days];
529 }
530 if (days > 0)
531 {
532 return [NSString stringWithFormat:NSLocalizedString(@"Left.Days.Hours", nil), days, hours];
533 }
534 if (hours > 10)
535 {
536 return [NSString stringWithFormat:NSLocalizedString(@"Left.Hours", nil), hours];
537 }
538 if (hours > 0)
539 {
540 return [NSString stringWithFormat:NSLocalizedString(@"Left.Hours.Minutes", nil), hours, minutes];
541 }
542 if (minutes > 10)
543 {
544 return [NSString stringWithFormat:NSLocalizedString(@"Left.Minutes", nil), minutes];
545 }
546 if (minutes > 0)
547 {
548 return [NSString stringWithFormat:NSLocalizedString(@"Left.Minutes.Seconds", nil), minutes, seconds];
549 }
550
551 return [NSString stringWithFormat:NSLocalizedString(@"Left.Seconds", nil), seconds];
552 }
553
554 - (void)daemonConfigLoaded {
555 DLog(@"config loaded");
556 [self updateCategoriesMenu];
557 }
558
559 - (void)updateCategoriesMenu {
560 NSMenu *submenu = destDirItem.parentItem.submenu;
561
562 for (NSMenuItem* item in categoryItems) {
563 [submenu removeItem:item];
564 }
565
566 categoryItems = [NSMutableArray array];
567 categoryDirs = [NSMutableArray array];
568
569 NSString* mainDir = [[daemonController valueForOption:@"MainDir"] stringByExpandingTildeInPath];
570 NSString* destDir = [[daemonController valueForOption:@"DestDir"] stringByExpandingTildeInPath];
571
572 for (int i=1; ; i++) {
573 NSString* catName = [daemonController valueForOption:[NSString stringWithFormat:@"Category%i.Name", i]];
574 NSString* catDir = [daemonController valueForOption:[NSString stringWithFormat:@"Category%i.DestDir", i]];
575
576 if (catName.length == 0) {
577 break;
578 }
579
580 if (catDir.length == 0) {
581 catDir = [destDir stringByAppendingPathComponent:catName];
582 }
583
584 NSString* dir = [catDir stringByExpandingTildeInPath];
585 dir = [dir stringByReplacingOccurrencesOfString:@"${MainDir}"
586 withString:mainDir
587 options:NSCaseInsensitiveSearch
588 range:NSMakeRange(0, dir.length)];
589 dir = [dir stringByReplacingOccurrencesOfString:@"${DestDir}"
590 withString:destDir
591 options:NSCaseInsensitiveSearch
592 range:NSMakeRange(0, dir.length)];
593
594 NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:[NSString stringWithFormat:@"Category%i: %@", i, catName]
595 action:@selector(showInFinderClicked:) keyEquivalent:@""];
596 [item setTarget:self];
597 [submenu insertItem:item atIndex:[submenu indexOfItem:destDirSeparator]];
598
599 [categoryItems addObject:item];
600 [categoryDirs addObject:dir];
601 }
602 }
603
604 @end
+0
-989
osx/MainApp.xib less more
0 <?xml version="1.0" encoding="UTF-8"?>
1 <archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
2 <data>
3 <int key="IBDocument.SystemTarget">1070</int>
4 <string key="IBDocument.SystemVersion">11G63</string>
5 <string key="IBDocument.InterfaceBuilderVersion">3084</string>
6 <string key="IBDocument.AppKitVersion">1138.51</string>
7 <string key="IBDocument.HIToolboxVersion">569.00</string>
8 <object class="NSMutableDictionary" key="IBDocument.PluginVersions">
9 <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
10 <string key="NS.object.0">3084</string>
11 </object>
12 <object class="NSArray" key="IBDocument.IntegratedClassDependencies">
13 <bool key="EncodedWithXMLCoder">YES</bool>
14 <string>NSCustomObject</string>
15 <string>NSMenu</string>
16 <string>NSMenuItem</string>
17 <string>NSUserDefaultsController</string>
18 </object>
19 <object class="NSArray" key="IBDocument.PluginDependencies">
20 <bool key="EncodedWithXMLCoder">YES</bool>
21 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
22 </object>
23 <object class="NSMutableDictionary" key="IBDocument.Metadata">
24 <string key="NS.key.0">PluginDependencyRecalculationVersion</string>
25 <integer value="1" key="NS.object.0"/>
26 </object>
27 <object class="NSMutableArray" key="IBDocument.RootObjects" id="1048">
28 <bool key="EncodedWithXMLCoder">YES</bool>
29 <object class="NSCustomObject" id="1021">
30 <string key="NSClassName">NSApplication</string>
31 </object>
32 <object class="NSCustomObject" id="1014">
33 <string key="NSClassName">FirstResponder</string>
34 </object>
35 <object class="NSCustomObject" id="1050">
36 <string key="NSClassName">NSApplication</string>
37 </object>
38 <object class="NSCustomObject" id="163992474">
39 <string key="NSClassName">NSFontManager</string>
40 </object>
41 <object class="NSCustomObject" id="584004514">
42 <string key="NSClassName">MainApp</string>
43 </object>
44 <object class="NSMenu" id="1071488544">
45 <string key="NSTitle"/>
46 <object class="NSMutableArray" key="NSMenuItems">
47 <bool key="EncodedWithXMLCoder">YES</bool>
48 <object class="NSMenuItem" id="913321237">
49 <reference key="NSMenu" ref="1071488544"/>
50 <bool key="NSIsDisabled">YES</bool>
51 <string key="NSTitle">Starting</string>
52 <string key="NSKeyEquiv"/>
53 <int key="NSMnemonicLoc">2147483647</int>
54 <object class="NSCustomResource" key="NSOnImage" id="723905397">
55 <string key="NSClassName">NSImage</string>
56 <string key="NSResourceName">NSMenuCheckmark</string>
57 </object>
58 <object class="NSCustomResource" key="NSMixedImage" id="488763290">
59 <string key="NSClassName">NSImage</string>
60 <string key="NSResourceName">NSMenuMixedState</string>
61 </object>
62 </object>
63 <object class="NSMenuItem" id="687450617">
64 <reference key="NSMenu" ref="1071488544"/>
65 <bool key="NSIsDisabled">YES</bool>
66 <bool key="NSIsHidden">YES</bool>
67 <string key="NSTitle">Left</string>
68 <string key="NSKeyEquiv"/>
69 <int key="NSMnemonicLoc">2147483647</int>
70 <reference key="NSOnImage" ref="723905397"/>
71 <reference key="NSMixedImage" ref="488763290"/>
72 </object>
73 <object class="NSMenuItem" id="893657456">
74 <reference key="NSMenu" ref="1071488544"/>
75 <bool key="NSIsDisabled">YES</bool>
76 <bool key="NSIsSeparator">YES</bool>
77 <string key="NSTitle"/>
78 <string key="NSKeyEquiv"/>
79 <int key="NSMnemonicLoc">2147483647</int>
80 <reference key="NSOnImage" ref="723905397"/>
81 <reference key="NSMixedImage" ref="488763290"/>
82 </object>
83 <object class="NSMenuItem" id="332065098">
84 <reference key="NSMenu" ref="1071488544"/>
85 <string key="NSTitle">Show Web-Interface</string>
86 <string key="NSKeyEquiv"/>
87 <int key="NSMnemonicLoc">2147483647</int>
88 <reference key="NSOnImage" ref="723905397"/>
89 <reference key="NSMixedImage" ref="488763290"/>
90 </object>
91 <object class="NSMenuItem" id="984846223">
92 <reference key="NSMenu" ref="1071488544"/>
93 <string key="NSTitle">Show in Finder</string>
94 <string key="NSKeyEquiv"/>
95 <int key="NSMnemonicLoc">2147483647</int>
96 <reference key="NSOnImage" ref="723905397"/>
97 <reference key="NSMixedImage" ref="488763290"/>
98 <string key="NSAction">submenuAction:</string>
99 <object class="NSMenu" key="NSSubmenu" id="309075451">
100 <string key="NSTitle">Show in Finder</string>
101 <object class="NSMutableArray" key="NSMenuItems">
102 <bool key="EncodedWithXMLCoder">YES</bool>
103 <object class="NSMenuItem" id="19318460">
104 <reference key="NSMenu" ref="309075451"/>
105 <string key="NSTitle">Default Destination</string>
106 <string key="NSKeyEquiv"/>
107 <int key="NSMnemonicLoc">2147483647</int>
108 <reference key="NSOnImage" ref="723905397"/>
109 <reference key="NSMixedImage" ref="488763290"/>
110 </object>
111 <object class="NSMenuItem" id="945655763">
112 <reference key="NSMenu" ref="309075451"/>
113 <bool key="NSIsDisabled">YES</bool>
114 <bool key="NSIsSeparator">YES</bool>
115 <string key="NSTitle"/>
116 <string key="NSKeyEquiv"/>
117 <int key="NSMnemonicLoc">2147483647</int>
118 <reference key="NSOnImage" ref="723905397"/>
119 <reference key="NSMixedImage" ref="488763290"/>
120 </object>
121 <object class="NSMenuItem" id="833448292">
122 <reference key="NSMenu" ref="309075451"/>
123 <string key="NSTitle">Intermediate Files</string>
124 <string key="NSKeyEquiv"/>
125 <int key="NSMnemonicLoc">2147483647</int>
126 <reference key="NSOnImage" ref="723905397"/>
127 <reference key="NSMixedImage" ref="488763290"/>
128 </object>
129 <object class="NSMenuItem" id="374625387">
130 <reference key="NSMenu" ref="309075451"/>
131 <string key="NSTitle">Incoming NZBs</string>
132 <string key="NSKeyEquiv"/>
133 <int key="NSMnemonicLoc">2147483647</int>
134 <reference key="NSOnImage" ref="723905397"/>
135 <reference key="NSMixedImage" ref="488763290"/>
136 </object>
137 <object class="NSMenuItem" id="942754376">
138 <reference key="NSMenu" ref="309075451"/>
139 <string key="NSTitle">Scripts</string>
140 <string key="NSKeyEquiv"/>
141 <int key="NSMnemonicLoc">2147483647</int>
142 <reference key="NSOnImage" ref="723905397"/>
143 <reference key="NSMixedImage" ref="488763290"/>
144 </object>
145 <object class="NSMenuItem" id="831099071">
146 <reference key="NSMenu" ref="309075451"/>
147 <bool key="NSIsDisabled">YES</bool>
148 <bool key="NSIsSeparator">YES</bool>
149 <string key="NSTitle"/>
150 <string key="NSKeyEquiv"/>
151 <int key="NSMnemonicLoc">2147483647</int>
152 <reference key="NSOnImage" ref="723905397"/>
153 <reference key="NSMixedImage" ref="488763290"/>
154 </object>
155 <object class="NSMenuItem" id="163691210">
156 <reference key="NSMenu" ref="309075451"/>
157 <string key="NSTitle">Config-File</string>
158 <string key="NSKeyEquiv"/>
159 <int key="NSMnemonicLoc">2147483647</int>
160 <reference key="NSOnImage" ref="723905397"/>
161 <reference key="NSMixedImage" ref="488763290"/>
162 </object>
163 <object class="NSMenuItem" id="297452147">
164 <reference key="NSMenu" ref="309075451"/>
165 <string key="NSTitle">Log-File</string>
166 <string key="NSKeyEquiv"/>
167 <int key="NSMnemonicLoc">2147483647</int>
168 <reference key="NSOnImage" ref="723905397"/>
169 <reference key="NSMixedImage" ref="488763290"/>
170 </object>
171 </object>
172 </object>
173 </object>
174 <object class="NSMenuItem" id="750438089">
175 <reference key="NSMenu" ref="1071488544"/>
176 <string key="NSTitle">Info-Links</string>
177 <string key="NSKeyEquiv"/>
178 <int key="NSMnemonicLoc">2147483647</int>
179 <reference key="NSOnImage" ref="723905397"/>
180 <reference key="NSMixedImage" ref="488763290"/>
181 <string key="NSAction">submenuAction:</string>
182 <object class="NSMenu" key="NSSubmenu" id="322188981">
183 <string key="NSTitle">Info-Links</string>
184 <object class="NSMutableArray" key="NSMenuItems">
185 <bool key="EncodedWithXMLCoder">YES</bool>
186 <object class="NSMenuItem" id="812981948">
187 <reference key="NSMenu" ref="322188981"/>
188 <string key="NSTitle">Home Page</string>
189 <string key="NSKeyEquiv"/>
190 <int key="NSMnemonicLoc">2147483647</int>
191 <reference key="NSOnImage" ref="723905397"/>
192 <reference key="NSMixedImage" ref="488763290"/>
193 </object>
194 <object class="NSMenuItem" id="179994147">
195 <reference key="NSMenu" ref="322188981"/>
196 <string key="NSTitle">Downloads</string>
197 <string key="NSKeyEquiv"/>
198 <int key="NSMnemonicLoc">2147483647</int>
199 <reference key="NSOnImage" ref="723905397"/>
200 <reference key="NSMixedImage" ref="488763290"/>
201 </object>
202 <object class="NSMenuItem" id="100406801">
203 <reference key="NSMenu" ref="322188981"/>
204 <string key="NSTitle">Forum</string>
205 <string key="NSKeyEquiv"/>
206 <int key="NSMnemonicLoc">2147483647</int>
207 <reference key="NSOnImage" ref="723905397"/>
208 <reference key="NSMixedImage" ref="488763290"/>
209 </object>
210 </object>
211 </object>
212 </object>
213 <object class="NSMenuItem" id="22060917">
214 <reference key="NSMenu" ref="1071488544"/>
215 <string key="NSTitle">Troubleshooting</string>
216 <string key="NSKeyEquiv"/>
217 <int key="NSMnemonicLoc">2147483647</int>
218 <reference key="NSOnImage" ref="723905397"/>
219 <reference key="NSMixedImage" ref="488763290"/>
220 <string key="NSAction">submenuAction:</string>
221 <object class="NSMenu" key="NSSubmenu" id="987038733">
222 <string key="NSTitle">Troubleshooting</string>
223 <object class="NSMutableArray" key="NSMenuItems">
224 <bool key="EncodedWithXMLCoder">YES</bool>
225 <object class="NSMenuItem" id="305652885">
226 <reference key="NSMenu" ref="987038733"/>
227 <string key="NSTitle">Restart</string>
228 <string key="NSKeyEquiv"/>
229 <int key="NSMnemonicLoc">2147483647</int>
230 <reference key="NSOnImage" ref="723905397"/>
231 <reference key="NSMixedImage" ref="488763290"/>
232 </object>
233 <object class="NSMenuItem" id="298404849">
234 <reference key="NSMenu" ref="987038733"/>
235 <string key="NSTitle">Restart in Recovery Mode</string>
236 <string key="NSKeyEquiv"/>
237 <int key="NSMnemonicLoc">2147483647</int>
238 <reference key="NSOnImage" ref="723905397"/>
239 <reference key="NSMixedImage" ref="488763290"/>
240 </object>
241 <object class="NSMenuItem" id="846476020">
242 <reference key="NSMenu" ref="987038733"/>
243 <string key="NSTitle">Open Config in TextEdit</string>
244 <string key="NSKeyEquiv"/>
245 <int key="NSMnemonicLoc">2147483647</int>
246 <reference key="NSOnImage" ref="723905397"/>
247 <reference key="NSMixedImage" ref="488763290"/>
248 </object>
249 <object class="NSMenuItem" id="631055199">
250 <reference key="NSMenu" ref="987038733"/>
251 <bool key="NSIsDisabled">YES</bool>
252 <bool key="NSIsSeparator">YES</bool>
253 <string key="NSTitle"/>
254 <string key="NSKeyEquiv"/>
255 <int key="NSMnemonicLoc">2147483647</int>
256 <reference key="NSOnImage" ref="723905397"/>
257 <reference key="NSMixedImage" ref="488763290"/>
258 </object>
259 <object class="NSMenuItem" id="408663019">
260 <reference key="NSMenu" ref="987038733"/>
261 <string key="NSTitle">Reset to Factory Defaults</string>
262 <string key="NSKeyEquiv"/>
263 <int key="NSMnemonicLoc">2147483647</int>
264 <reference key="NSOnImage" ref="723905397"/>
265 <reference key="NSMixedImage" ref="488763290"/>
266 </object>
267 </object>
268 </object>
269 </object>
270 <object class="NSMenuItem" id="239974611">
271 <reference key="NSMenu" ref="1071488544"/>
272 <bool key="NSIsDisabled">YES</bool>
273 <bool key="NSIsSeparator">YES</bool>
274 <string key="NSTitle"/>
275 <string key="NSKeyEquiv"/>
276 <int key="NSMnemonicLoc">2147483647</int>
277 <reference key="NSOnImage" ref="723905397"/>
278 <reference key="NSMixedImage" ref="488763290"/>
279 </object>
280 <object class="NSMenuItem" id="7270580">
281 <reference key="NSMenu" ref="1071488544"/>
282 <string key="NSTitle">About NZBGet</string>
283 <string key="NSKeyEquiv"/>
284 <int key="NSMnemonicLoc">2147483647</int>
285 <reference key="NSOnImage" ref="723905397"/>
286 <reference key="NSMixedImage" ref="488763290"/>
287 </object>
288 <object class="NSMenuItem" id="845819171">
289 <reference key="NSMenu" ref="1071488544"/>
290 <string key="NSTitle">Preferences...</string>
291 <string key="NSKeyEquiv"/>
292 <int key="NSMnemonicLoc">2147483647</int>
293 <reference key="NSOnImage" ref="723905397"/>
294 <reference key="NSMixedImage" ref="488763290"/>
295 </object>
296 <object class="NSMenuItem" id="4615620">
297 <reference key="NSMenu" ref="1071488544"/>
298 <bool key="NSIsDisabled">YES</bool>
299 <bool key="NSIsSeparator">YES</bool>
300 <string key="NSTitle"/>
301 <string key="NSKeyEquiv"/>
302 <int key="NSMnemonicLoc">2147483647</int>
303 <reference key="NSOnImage" ref="723905397"/>
304 <reference key="NSMixedImage" ref="488763290"/>
305 </object>
306 <object class="NSMenuItem" id="667042401">
307 <reference key="NSMenu" ref="1071488544"/>
308 <string key="NSTitle">Quit NZBGet</string>
309 <string key="NSKeyEquiv"/>
310 <int key="NSMnemonicLoc">2147483647</int>
311 <reference key="NSOnImage" ref="723905397"/>
312 <reference key="NSMixedImage" ref="488763290"/>
313 </object>
314 </object>
315 </object>
316 <object class="NSUserDefaultsController" id="821481866">
317 <bool key="NSSharedInstance">YES</bool>
318 </object>
319 </object>
320 <object class="IBObjectContainer" key="IBDocument.Objects">
321 <object class="NSMutableArray" key="connectionRecords">
322 <bool key="EncodedWithXMLCoder">YES</bool>
323 <object class="IBConnectionRecord">
324 <object class="IBOutletConnection" key="connection">
325 <string key="label">delegate</string>
326 <reference key="source" ref="1021"/>
327 <reference key="destination" ref="584004514"/>
328 </object>
329 <int key="connectionID">824</int>
330 </object>
331 <object class="IBConnectionRecord">
332 <object class="IBOutletConnection" key="connection">
333 <string key="label">statusMenu</string>
334 <reference key="source" ref="584004514"/>
335 <reference key="destination" ref="1071488544"/>
336 </object>
337 <int key="connectionID">831</int>
338 </object>
339 <object class="IBConnectionRecord">
340 <object class="IBActionConnection" key="connection">
341 <string key="label">quitClicked:</string>
342 <reference key="source" ref="584004514"/>
343 <reference key="destination" ref="667042401"/>
344 </object>
345 <int key="connectionID">832</int>
346 </object>
347 <object class="IBConnectionRecord">
348 <object class="IBActionConnection" key="connection">
349 <string key="label">preferencesClicked:</string>
350 <reference key="source" ref="584004514"/>
351 <reference key="destination" ref="845819171"/>
352 </object>
353 <int key="connectionID">850</int>
354 </object>
355 <object class="IBConnectionRecord">
356 <object class="IBActionConnection" key="connection">
357 <string key="label">aboutClicked:</string>
358 <reference key="source" ref="584004514"/>
359 <reference key="destination" ref="7270580"/>
360 </object>
361 <int key="connectionID">856</int>
362 </object>
363 <object class="IBConnectionRecord">
364 <object class="IBActionConnection" key="connection">
365 <string key="label">webuiClicked:</string>
366 <reference key="source" ref="584004514"/>
367 <reference key="destination" ref="332065098"/>
368 </object>
369 <int key="connectionID">865</int>
370 </object>
371 <object class="IBConnectionRecord">
372 <object class="IBOutletConnection" key="connection">
373 <string key="label">webuiItem</string>
374 <reference key="source" ref="584004514"/>
375 <reference key="destination" ref="332065098"/>
376 </object>
377 <int key="connectionID">866</int>
378 </object>
379 <object class="IBConnectionRecord">
380 <object class="IBOutletConnection" key="connection">
381 <string key="label">homePageItem</string>
382 <reference key="source" ref="584004514"/>
383 <reference key="destination" ref="812981948"/>
384 </object>
385 <int key="connectionID">874</int>
386 </object>
387 <object class="IBConnectionRecord">
388 <object class="IBOutletConnection" key="connection">
389 <string key="label">downloadsItem</string>
390 <reference key="source" ref="584004514"/>
391 <reference key="destination" ref="179994147"/>
392 </object>
393 <int key="connectionID">875</int>
394 </object>
395 <object class="IBConnectionRecord">
396 <object class="IBOutletConnection" key="connection">
397 <string key="label">forumItem</string>
398 <reference key="source" ref="584004514"/>
399 <reference key="destination" ref="100406801"/>
400 </object>
401 <int key="connectionID">876</int>
402 </object>
403 <object class="IBConnectionRecord">
404 <object class="IBActionConnection" key="connection">
405 <string key="label">infoLinkClicked:</string>
406 <reference key="source" ref="584004514"/>
407 <reference key="destination" ref="812981948"/>
408 </object>
409 <int key="connectionID">877</int>
410 </object>
411 <object class="IBConnectionRecord">
412 <object class="IBActionConnection" key="connection">
413 <string key="label">infoLinkClicked:</string>
414 <reference key="source" ref="584004514"/>
415 <reference key="destination" ref="179994147"/>
416 </object>
417 <int key="connectionID">878</int>
418 </object>
419 <object class="IBConnectionRecord">
420 <object class="IBActionConnection" key="connection">
421 <string key="label">infoLinkClicked:</string>
422 <reference key="source" ref="584004514"/>
423 <reference key="destination" ref="100406801"/>
424 </object>
425 <int key="connectionID">879</int>
426 </object>
427 <object class="IBConnectionRecord">
428 <object class="IBOutletConnection" key="connection">
429 <string key="label">infoItem</string>
430 <reference key="source" ref="584004514"/>
431 <reference key="destination" ref="913321237"/>
432 </object>
433 <int key="connectionID">893</int>
434 </object>
435 <object class="IBConnectionRecord">
436 <object class="IBOutletConnection" key="connection">
437 <string key="label">restartRecoveryItem</string>
438 <reference key="source" ref="584004514"/>
439 <reference key="destination" ref="298404849"/>
440 </object>
441 <int key="connectionID">896</int>
442 </object>
443 <object class="IBConnectionRecord">
444 <object class="IBOutletConnection" key="connection">
445 <string key="label">destDirItem</string>
446 <reference key="source" ref="584004514"/>
447 <reference key="destination" ref="19318460"/>
448 </object>
449 <int key="connectionID">911</int>
450 </object>
451 <object class="IBConnectionRecord">
452 <object class="IBOutletConnection" key="connection">
453 <string key="label">interDirItem</string>
454 <reference key="source" ref="584004514"/>
455 <reference key="destination" ref="833448292"/>
456 </object>
457 <int key="connectionID">912</int>
458 </object>
459 <object class="IBConnectionRecord">
460 <object class="IBOutletConnection" key="connection">
461 <string key="label">nzbDirItem</string>
462 <reference key="source" ref="584004514"/>
463 <reference key="destination" ref="374625387"/>
464 </object>
465 <int key="connectionID">913</int>
466 </object>
467 <object class="IBConnectionRecord">
468 <object class="IBOutletConnection" key="connection">
469 <string key="label">scriptDirItem</string>
470 <reference key="source" ref="584004514"/>
471 <reference key="destination" ref="942754376"/>
472 </object>
473 <int key="connectionID">915</int>
474 </object>
475 <object class="IBConnectionRecord">
476 <object class="IBActionConnection" key="connection">
477 <string key="label">showInFinderClicked:</string>
478 <reference key="source" ref="584004514"/>
479 <reference key="destination" ref="19318460"/>
480 </object>
481 <int key="connectionID">916</int>
482 </object>
483 <object class="IBConnectionRecord">
484 <object class="IBActionConnection" key="connection">
485 <string key="label">showInFinderClicked:</string>
486 <reference key="source" ref="584004514"/>
487 <reference key="destination" ref="833448292"/>
488 </object>
489 <int key="connectionID">917</int>
490 </object>
491 <object class="IBConnectionRecord">
492 <object class="IBActionConnection" key="connection">
493 <string key="label">showInFinderClicked:</string>
494 <reference key="source" ref="584004514"/>
495 <reference key="destination" ref="374625387"/>
496 </object>
497 <int key="connectionID">918</int>
498 </object>
499 <object class="IBConnectionRecord">
500 <object class="IBActionConnection" key="connection">
501 <string key="label">showInFinderClicked:</string>
502 <reference key="source" ref="584004514"/>
503 <reference key="destination" ref="942754376"/>
504 </object>
505 <int key="connectionID">919</int>
506 </object>
507 <object class="IBConnectionRecord">
508 <object class="IBActionConnection" key="connection">
509 <string key="label">showInFinderClicked:</string>
510 <reference key="source" ref="584004514"/>
511 <reference key="destination" ref="163691210"/>
512 </object>
513 <int key="connectionID">922</int>
514 </object>
515 <object class="IBConnectionRecord">
516 <object class="IBOutletConnection" key="connection">
517 <string key="label">info2Item</string>
518 <reference key="source" ref="584004514"/>
519 <reference key="destination" ref="687450617"/>
520 </object>
521 <int key="connectionID">925</int>
522 </object>
523 <object class="IBConnectionRecord">
524 <object class="IBOutletConnection" key="connection">
525 <string key="label">info1Item</string>
526 <reference key="source" ref="584004514"/>
527 <reference key="destination" ref="913321237"/>
528 </object>
529 <int key="connectionID">926</int>
530 </object>
531 <object class="IBConnectionRecord">
532 <object class="IBOutletConnection" key="connection">
533 <string key="label">destDirSeparator</string>
534 <reference key="source" ref="584004514"/>
535 <reference key="destination" ref="945655763"/>
536 </object>
537 <int key="connectionID">927</int>
538 </object>
539 <object class="IBConnectionRecord">
540 <object class="IBActionConnection" key="connection">
541 <string key="label">showInFinderClicked:</string>
542 <reference key="source" ref="584004514"/>
543 <reference key="destination" ref="297452147"/>
544 </object>
545 <int key="connectionID">929</int>
546 </object>
547 <object class="IBConnectionRecord">
548 <object class="IBOutletConnection" key="connection">
549 <string key="label">configFileItem</string>
550 <reference key="source" ref="584004514"/>
551 <reference key="destination" ref="163691210"/>
552 </object>
553 <int key="connectionID">930</int>
554 </object>
555 <object class="IBConnectionRecord">
556 <object class="IBOutletConnection" key="connection">
557 <string key="label">logFileItem</string>
558 <reference key="source" ref="584004514"/>
559 <reference key="destination" ref="297452147"/>
560 </object>
561 <int key="connectionID">931</int>
562 </object>
563 <object class="IBConnectionRecord">
564 <object class="IBActionConnection" key="connection">
565 <string key="label">restartClicked:</string>
566 <reference key="source" ref="584004514"/>
567 <reference key="destination" ref="298404849"/>
568 </object>
569 <int key="connectionID">940</int>
570 </object>
571 <object class="IBConnectionRecord">
572 <object class="IBActionConnection" key="connection">
573 <string key="label">openConfigInTextEditClicked:</string>
574 <reference key="source" ref="584004514"/>
575 <reference key="destination" ref="846476020"/>
576 </object>
577 <int key="connectionID">941</int>
578 </object>
579 <object class="IBConnectionRecord">
580 <object class="IBActionConnection" key="connection">
581 <string key="label">restartClicked:</string>
582 <reference key="source" ref="584004514"/>
583 <reference key="destination" ref="305652885"/>
584 </object>
585 <int key="connectionID">943</int>
586 </object>
587 <object class="IBConnectionRecord">
588 <object class="IBActionConnection" key="connection">
589 <string key="label">restartClicked:</string>
590 <reference key="source" ref="584004514"/>
591 <reference key="destination" ref="408663019"/>
592 </object>
593 <int key="connectionID">944</int>
594 </object>
595 <object class="IBConnectionRecord">
596 <object class="IBOutletConnection" key="connection">
597 <string key="label">factoryResetItem</string>
598 <reference key="source" ref="584004514"/>
599 <reference key="destination" ref="408663019"/>
600 </object>
601 <int key="connectionID">945</int>
602 </object>
603 </object>
604 <object class="IBMutableOrderedSet" key="objectRecords">
605 <object class="NSArray" key="orderedObjects">
606 <bool key="EncodedWithXMLCoder">YES</bool>
607 <object class="IBObjectRecord">
608 <int key="objectID">0</int>
609 <object class="NSArray" key="object" id="0">
610 <bool key="EncodedWithXMLCoder">YES</bool>
611 </object>
612 <reference key="children" ref="1048"/>
613 <nil key="parent"/>
614 </object>
615 <object class="IBObjectRecord">
616 <int key="objectID">-2</int>
617 <reference key="object" ref="1021"/>
618 <reference key="parent" ref="0"/>
619 <string key="objectName">File's Owner</string>
620 </object>
621 <object class="IBObjectRecord">
622 <int key="objectID">-1</int>
623 <reference key="object" ref="1014"/>
624 <reference key="parent" ref="0"/>
625 <string key="objectName">First Responder</string>
626 </object>
627 <object class="IBObjectRecord">
628 <int key="objectID">-3</int>
629 <reference key="object" ref="1050"/>
630 <reference key="parent" ref="0"/>
631 <string key="objectName">Application</string>
632 </object>
633 <object class="IBObjectRecord">
634 <int key="objectID">373</int>
635 <reference key="object" ref="163992474"/>
636 <reference key="parent" ref="0"/>
637 </object>
638 <object class="IBObjectRecord">
639 <int key="objectID">823</int>
640 <reference key="object" ref="584004514"/>
641 <reference key="parent" ref="0"/>
642 </object>
643 <object class="IBObjectRecord">
644 <int key="objectID">827</int>
645 <reference key="object" ref="1071488544"/>
646 <object class="NSMutableArray" key="children">
647 <bool key="EncodedWithXMLCoder">YES</bool>
648 <reference ref="667042401"/>
649 <reference ref="332065098"/>
650 <reference ref="893657456"/>
651 <reference ref="22060917"/>
652 <reference ref="239974611"/>
653 <reference ref="913321237"/>
654 <reference ref="7270580"/>
655 <reference ref="845819171"/>
656 <reference ref="4615620"/>
657 <reference ref="750438089"/>
658 <reference ref="984846223"/>
659 <reference ref="687450617"/>
660 </object>
661 <reference key="parent" ref="0"/>
662 </object>
663 <object class="IBObjectRecord">
664 <int key="objectID">828</int>
665 <reference key="object" ref="667042401"/>
666 <reference key="parent" ref="1071488544"/>
667 </object>
668 <object class="IBObjectRecord">
669 <int key="objectID">840</int>
670 <reference key="object" ref="821481866"/>
671 <reference key="parent" ref="0"/>
672 </object>
673 <object class="IBObjectRecord">
674 <int key="objectID">849</int>
675 <reference key="object" ref="845819171"/>
676 <reference key="parent" ref="1071488544"/>
677 </object>
678 <object class="IBObjectRecord">
679 <int key="objectID">851</int>
680 <reference key="object" ref="7270580"/>
681 <reference key="parent" ref="1071488544"/>
682 </object>
683 <object class="IBObjectRecord">
684 <int key="objectID">860</int>
685 <reference key="object" ref="893657456"/>
686 <reference key="parent" ref="1071488544"/>
687 </object>
688 <object class="IBObjectRecord">
689 <int key="objectID">861</int>
690 <reference key="object" ref="332065098"/>
691 <reference key="parent" ref="1071488544"/>
692 </object>
693 <object class="IBObjectRecord">
694 <int key="objectID">867</int>
695 <reference key="object" ref="750438089"/>
696 <object class="NSMutableArray" key="children">
697 <bool key="EncodedWithXMLCoder">YES</bool>
698 <reference ref="322188981"/>
699 </object>
700 <reference key="parent" ref="1071488544"/>
701 </object>
702 <object class="IBObjectRecord">
703 <int key="objectID">868</int>
704 <reference key="object" ref="322188981"/>
705 <object class="NSMutableArray" key="children">
706 <bool key="EncodedWithXMLCoder">YES</bool>
707 <reference ref="812981948"/>
708 <reference ref="100406801"/>
709 <reference ref="179994147"/>
710 </object>
711 <reference key="parent" ref="750438089"/>
712 </object>
713 <object class="IBObjectRecord">
714 <int key="objectID">869</int>
715 <reference key="object" ref="812981948"/>
716 <reference key="parent" ref="322188981"/>
717 </object>
718 <object class="IBObjectRecord">
719 <int key="objectID">870</int>
720 <reference key="object" ref="100406801"/>
721 <reference key="parent" ref="322188981"/>
722 </object>
723 <object class="IBObjectRecord">
724 <int key="objectID">872</int>
725 <reference key="object" ref="179994147"/>
726 <reference key="parent" ref="322188981"/>
727 </object>
728 <object class="IBObjectRecord">
729 <int key="objectID">880</int>
730 <reference key="object" ref="22060917"/>
731 <object class="NSMutableArray" key="children">
732 <bool key="EncodedWithXMLCoder">YES</bool>
733 <reference ref="987038733"/>
734 </object>
735 <reference key="parent" ref="1071488544"/>
736 </object>
737 <object class="IBObjectRecord">
738 <int key="objectID">881</int>
739 <reference key="object" ref="987038733"/>
740 <object class="NSMutableArray" key="children">
741 <bool key="EncodedWithXMLCoder">YES</bool>
742 <reference ref="305652885"/>
743 <reference ref="846476020"/>
744 <reference ref="298404849"/>
745 <reference ref="631055199"/>
746 <reference ref="408663019"/>
747 </object>
748 <reference key="parent" ref="22060917"/>
749 </object>
750 <object class="IBObjectRecord">
751 <int key="objectID">882</int>
752 <reference key="object" ref="305652885"/>
753 <reference key="parent" ref="987038733"/>
754 </object>
755 <object class="IBObjectRecord">
756 <int key="objectID">885</int>
757 <reference key="object" ref="846476020"/>
758 <reference key="parent" ref="987038733"/>
759 </object>
760 <object class="IBObjectRecord">
761 <int key="objectID">887</int>
762 <reference key="object" ref="298404849"/>
763 <reference key="parent" ref="987038733"/>
764 </object>
765 <object class="IBObjectRecord">
766 <int key="objectID">889</int>
767 <reference key="object" ref="239974611"/>
768 <reference key="parent" ref="1071488544"/>
769 </object>
770 <object class="IBObjectRecord">
771 <int key="objectID">890</int>
772 <reference key="object" ref="913321237"/>
773 <reference key="parent" ref="1071488544"/>
774 </object>
775 <object class="IBObjectRecord">
776 <int key="objectID">897</int>
777 <reference key="object" ref="4615620"/>
778 <reference key="parent" ref="1071488544"/>
779 </object>
780 <object class="IBObjectRecord">
781 <int key="objectID">898</int>
782 <reference key="object" ref="984846223"/>
783 <object class="NSMutableArray" key="children">
784 <bool key="EncodedWithXMLCoder">YES</bool>
785 <reference ref="309075451"/>
786 </object>
787 <reference key="parent" ref="1071488544"/>
788 </object>
789 <object class="IBObjectRecord">
790 <int key="objectID">899</int>
791 <reference key="object" ref="309075451"/>
792 <object class="NSMutableArray" key="children">
793 <bool key="EncodedWithXMLCoder">YES</bool>
794 <reference ref="19318460"/>
795 <reference ref="942754376"/>
796 <reference ref="831099071"/>
797 <reference ref="945655763"/>
798 <reference ref="374625387"/>
799 <reference ref="833448292"/>
800 <reference ref="163691210"/>
801 <reference ref="297452147"/>
802 </object>
803 <reference key="parent" ref="984846223"/>
804 </object>
805 <object class="IBObjectRecord">
806 <int key="objectID">900</int>
807 <reference key="object" ref="19318460"/>
808 <reference key="parent" ref="309075451"/>
809 </object>
810 <object class="IBObjectRecord">
811 <int key="objectID">902</int>
812 <reference key="object" ref="833448292"/>
813 <reference key="parent" ref="309075451"/>
814 </object>
815 <object class="IBObjectRecord">
816 <int key="objectID">906</int>
817 <reference key="object" ref="374625387"/>
818 <reference key="parent" ref="309075451"/>
819 </object>
820 <object class="IBObjectRecord">
821 <int key="objectID">908</int>
822 <reference key="object" ref="942754376"/>
823 <reference key="parent" ref="309075451"/>
824 </object>
825 <object class="IBObjectRecord">
826 <int key="objectID">910</int>
827 <reference key="object" ref="831099071"/>
828 <reference key="parent" ref="309075451"/>
829 </object>
830 <object class="IBObjectRecord">
831 <int key="objectID">920</int>
832 <reference key="object" ref="945655763"/>
833 <reference key="parent" ref="309075451"/>
834 </object>
835 <object class="IBObjectRecord">
836 <int key="objectID">921</int>
837 <reference key="object" ref="163691210"/>
838 <reference key="parent" ref="309075451"/>
839 </object>
840 <object class="IBObjectRecord">
841 <int key="objectID">924</int>
842 <reference key="object" ref="687450617"/>
843 <reference key="parent" ref="1071488544"/>
844 </object>
845 <object class="IBObjectRecord">
846 <int key="objectID">928</int>
847 <reference key="object" ref="297452147"/>
848 <reference key="parent" ref="309075451"/>
849 </object>
850 <object class="IBObjectRecord">
851 <int key="objectID">934</int>
852 <reference key="object" ref="631055199"/>
853 <reference key="parent" ref="987038733"/>
854 </object>
855 <object class="IBObjectRecord">
856 <int key="objectID">935</int>
857 <reference key="object" ref="408663019"/>
858 <reference key="parent" ref="987038733"/>
859 </object>
860 </object>
861 </object>
862 <object class="NSMutableDictionary" key="flattenedProperties">
863 <bool key="EncodedWithXMLCoder">YES</bool>
864 <object class="NSArray" key="dict.sortedKeys">
865 <bool key="EncodedWithXMLCoder">YES</bool>
866 <string>-1.IBPluginDependency</string>
867 <string>-2.IBPluginDependency</string>
868 <string>-3.IBPluginDependency</string>
869 <string>373.IBPluginDependency</string>
870 <string>823.IBPluginDependency</string>
871 <string>827.IBPluginDependency</string>
872 <string>828.IBPluginDependency</string>
873 <string>840.IBPluginDependency</string>
874 <string>849.IBPluginDependency</string>
875 <string>851.IBPluginDependency</string>
876 <string>860.IBPluginDependency</string>
877 <string>861.IBPluginDependency</string>
878 <string>867.IBPluginDependency</string>
879 <string>868.IBPluginDependency</string>
880 <string>869.IBPluginDependency</string>
881 <string>870.IBPluginDependency</string>
882 <string>872.IBPluginDependency</string>
883 <string>880.IBPluginDependency</string>
884 <string>881.IBPluginDependency</string>
885 <string>882.IBPluginDependency</string>
886 <string>885.IBPluginDependency</string>
887 <string>887.IBPluginDependency</string>
888 <string>889.IBPluginDependency</string>
889 <string>890.IBPluginDependency</string>
890 <string>897.IBPluginDependency</string>
891 <string>898.IBPluginDependency</string>
892 <string>899.IBPluginDependency</string>
893 <string>900.IBPluginDependency</string>
894 <string>902.IBPluginDependency</string>
895 <string>906.IBPluginDependency</string>
896 <string>908.IBPluginDependency</string>
897 <string>910.IBPluginDependency</string>
898 <string>920.IBPluginDependency</string>
899 <string>921.IBPluginDependency</string>
900 <string>924.IBPluginDependency</string>
901 <string>928.IBPluginDependency</string>
902 <string>934.IBPluginDependency</string>
903 <string>935.IBPluginDependency</string>
904 </object>
905 <object class="NSArray" key="dict.values">
906 <bool key="EncodedWithXMLCoder">YES</bool>
907 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
908 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
909 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
910 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
911 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
912 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
913 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
914 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
915 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
916 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
917 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
918 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
919 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
920 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
921 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
922 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
923 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
924 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
925 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
926 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
927 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
928 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
929 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
930 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
931 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
932 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
933 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
934 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
935 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
936 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
937 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
938 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
939 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
940 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
941 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
942 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
943 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
944 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
945 </object>
946 </object>
947 <object class="NSMutableDictionary" key="unlocalizedProperties">
948 <bool key="EncodedWithXMLCoder">YES</bool>
949 <reference key="dict.sortedKeys" ref="0"/>
950 <reference key="dict.values" ref="0"/>
951 </object>
952 <nil key="activeLocalization"/>
953 <object class="NSMutableDictionary" key="localizations">
954 <bool key="EncodedWithXMLCoder">YES</bool>
955 <reference key="dict.sortedKeys" ref="0"/>
956 <reference key="dict.values" ref="0"/>
957 </object>
958 <nil key="sourceID"/>
959 <int key="maxID">945</int>
960 </object>
961 <object class="IBClassDescriber" key="IBDocument.Classes"/>
962 <int key="IBDocument.localizationMode">0</int>
963 <string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
964 <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencyDefaults">
965 <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
966 <real value="1070" key="NS.object.0"/>
967 </object>
968 <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
969 <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3</string>
970 <integer value="3000" key="NS.object.0"/>
971 </object>
972 <bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
973 <int key="IBDocument.defaultPropertyAccessControl">3</int>
974 <object class="NSMutableDictionary" key="IBDocument.LastKnownImageSizes">
975 <bool key="EncodedWithXMLCoder">YES</bool>
976 <object class="NSArray" key="dict.sortedKeys">
977 <bool key="EncodedWithXMLCoder">YES</bool>
978 <string>NSMenuCheckmark</string>
979 <string>NSMenuMixedState</string>
980 </object>
981 <object class="NSArray" key="dict.values">
982 <bool key="EncodedWithXMLCoder">YES</bool>
983 <string>{11, 11}</string>
984 <string>{10, 3}</string>
985 </object>
986 </object>
987 </data>
988 </archive>
+0
-39
osx/NZBGet-Info.plist less more
0 <?xml version="1.0" encoding="UTF-8"?>
1 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
2 <plist version="1.0">
3 <dict>
4 <key>CFBundleDevelopmentRegion</key>
5 <string>English</string>
6 <key>CFBundleExecutable</key>
7 <string>${EXECUTABLE_NAME}</string>
8 <key>CFBundleIconFile</key>
9 <string>mainicon.icns</string>
10 <key>CFBundleIdentifier</key>
11 <string>net.sourceforge.nzbget</string>
12 <key>CFBundleInfoDictionaryVersion</key>
13 <string>6.0</string>
14 <key>CFBundleName</key>
15 <string>${PRODUCT_NAME}</string>
16 <key>CFBundlePackageType</key>
17 <string>APPL</string>
18 <key>CFBundleShortVersionString</key>
19 <string>15.0-testing</string>
20 <key>LSApplicationCategoryType</key>
21 <string>public.app-category.utilities</string>
22 <key>LSMinimumSystemVersion</key>
23 <string>10.7</string>
24 <key>LSUIElement</key>
25 <true/>
26 <key>NSHumanReadableCopyright</key>
27 <string>Copyright © 2007-2017 Andrey Prygunkov</string>
28 <key>NSMainNibFile</key>
29 <string>MainApp</string>
30 <key>NSAppTransportSecurity</key>
31 <dict>
32 <key>NSAllowsArbitraryLoads</key>
33 <true/>
34 </dict>
35 <key>NSPrincipalClass</key>
36 <string>NSApplication</string>
37 </dict>
38 </plist>
+0
-405
osx/NZBGet.xcodeproj/project.pbxproj less more
0 // !$*UTF8*$!
1 {
2 archiveVersion = 1;
3 classes = {
4 };
5 objectVersion = 46;
6 objects = {
7
8 /* Begin PBXBuildFile section */
9 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
10 F20FC6E217C6BAAE00C392AC /* PFMoveApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = F20FC6DF17C6B9FC00C392AC /* PFMoveApplication.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
11 F20FC6E417C6BC8D00C392AC /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F20FC6E317C6BC8D00C392AC /* Security.framework */; };
12 F21D369B13BF387F00E6D821 /* PreferencesDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = F21D369A13BF387F00E6D821 /* PreferencesDialog.m */; };
13 F26CBA8B136DE86A00DCB596 /* MainApp.m in Sources */ = {isa = PBXBuildFile; fileRef = F26CBA8A136DE86A00DCB596 /* MainApp.m */; };
14 F26D959317C0E81800E58E5D /* Welcome.rtf in Resources */ = {isa = PBXBuildFile; fileRef = F26D959217C0E81800E58E5D /* Welcome.rtf */; };
15 F26D959517C0E86300E58E5D /* MainApp.xib in Resources */ = {isa = PBXBuildFile; fileRef = F26D959417C0E86300E58E5D /* MainApp.xib */; };
16 F26D959717C0E87E00E58E5D /* PreferencesDialog.xib in Resources */ = {isa = PBXBuildFile; fileRef = F26D959617C0E87E00E58E5D /* PreferencesDialog.xib */; };
17 F26D959917C0E88700E58E5D /* WelcomeDialog.xib in Resources */ = {isa = PBXBuildFile; fileRef = F26D959817C0E88700E58E5D /* WelcomeDialog.xib */; };
18 F26D959B17C0E89D00E58E5D /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = F26D959A17C0E89D00E58E5D /* Localizable.strings */; };
19 F29ABB2617BFC61B0023A423 /* DaemonController.m in Sources */ = {isa = PBXBuildFile; fileRef = F29ABB2417BFC03D0023A423 /* DaemonController.m */; };
20 F29ABB2B17C00E150023A423 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 29B97324FDCFA39411CA2CEA /* AppKit.framework */; };
21 F29ABB2C17C00E190023A423 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 29B97325FDCFA39411CA2CEA /* Foundation.framework */; };
22 F2A55D3717C4CA9000D6FFE1 /* daemon in Resources */ = {isa = PBXBuildFile; fileRef = F2A55D3617C4CA9000D6FFE1 /* daemon */; };
23 F2A55D3B17C4CAF800D6FFE1 /* tools in Resources */ = {isa = PBXBuildFile; fileRef = F2A55D3A17C4CAF800D6FFE1 /* tools */; };
24 F2A6E11117C8E42300D910CB /* statusicon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F2A6E10F17C8E42300D910CB /* statusicon@2x.png */; };
25 F2BBD9C613E083160037473A /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = F2FC0F8B13BF595700D834E3 /* Credits.rtf */; };
26 F2C040481A18E946003EAB32 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F2C040471A18E946003EAB32 /* IOKit.framework */; };
27 F2CD856817C282080019D2CA /* RPC.m in Sources */ = {isa = PBXBuildFile; fileRef = F2CD856517C254A90019D2CA /* RPC.m */; };
28 F2CD856B17C282820019D2CA /* WebClient.m in Sources */ = {isa = PBXBuildFile; fileRef = F2CD856A17C282800019D2CA /* WebClient.m */; };
29 F2D2A2F113CBA680000824B4 /* WelcomeDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = F2D2A2EF13CBA680000824B4 /* WelcomeDialog.m */; };
30 F2F9804A17C9081D004623D6 /* licenses in Resources */ = {isa = PBXBuildFile; fileRef = F2F9804917C9081D004623D6 /* licenses */; };
31 F2FCD73B13BB9CE900FC81F5 /* mainicon.icns in Resources */ = {isa = PBXBuildFile; fileRef = F2FCD73A13BB9CE900FC81F5 /* mainicon.icns */; };
32 F2FCD7D913BBDAED00FC81F5 /* statusicon.png in Resources */ = {isa = PBXBuildFile; fileRef = F2FCD7D813BBDAED00FC81F5 /* statusicon.png */; };
33 /* End PBXBuildFile section */
34
35 /* Begin PBXFileReference section */
36 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
37 256AC3F00F4B6AF500CF3369 /* App_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = App_Prefix.pch; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
38 29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
39 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
40 8D1107310486CEB800E47090 /* NZBGet-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "NZBGet-Info.plist"; sourceTree = "<group>"; };
41 8D1107320486CEB800E47090 /* NZBGet.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = NZBGet.app; sourceTree = BUILT_PRODUCTS_DIR; };
42 F20FC6DE17C6B9FC00C392AC /* PFMoveApplication.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PFMoveApplication.h; sourceTree = "<group>"; };
43 F20FC6DF17C6B9FC00C392AC /* PFMoveApplication.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PFMoveApplication.m; sourceTree = "<group>"; };
44 F20FC6E317C6BC8D00C392AC /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; };
45 F21D369913BF387F00E6D821 /* PreferencesDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PreferencesDialog.h; sourceTree = "<group>"; };
46 F21D369A13BF387F00E6D821 /* PreferencesDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PreferencesDialog.m; sourceTree = "<group>"; };
47 F26CBA89136DE86A00DCB596 /* MainApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MainApp.h; sourceTree = "<group>"; };
48 F26CBA8A136DE86A00DCB596 /* MainApp.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = MainApp.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
49 F26D959217C0E81800E58E5D /* Welcome.rtf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.rtf; name = Welcome.rtf; path = Resources/Welcome.rtf; sourceTree = "<group>"; };
50 F26D959417C0E86300E58E5D /* MainApp.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainApp.xib; sourceTree = "<group>"; };
51 F26D959617C0E87E00E58E5D /* PreferencesDialog.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PreferencesDialog.xib; sourceTree = "<group>"; };
52 F26D959817C0E88700E58E5D /* WelcomeDialog.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = WelcomeDialog.xib; sourceTree = "<group>"; };
53 F26D959A17C0E89D00E58E5D /* Localizable.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = Localizable.strings; path = Resources/Localizable.strings; sourceTree = "<group>"; };
54 F29ABB2317BFC03D0023A423 /* DaemonController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DaemonController.h; sourceTree = "<group>"; };
55 F29ABB2417BFC03D0023A423 /* DaemonController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DaemonController.m; sourceTree = "<group>"; };
56 F2A55D3617C4CA9000D6FFE1 /* daemon */ = {isa = PBXFileReference; lastKnownFileType = folder; name = daemon; path = Resources/daemon; sourceTree = "<group>"; };
57 F2A55D3A17C4CAF800D6FFE1 /* tools */ = {isa = PBXFileReference; lastKnownFileType = folder; name = tools; path = Resources/tools; sourceTree = "<group>"; };
58 F2A6E10F17C8E42300D910CB /* statusicon@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "statusicon@2x.png"; path = "Images/statusicon@2x.png"; sourceTree = "<group>"; };
59 F2C040471A18E946003EAB32 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk/System/Library/Frameworks/IOKit.framework; sourceTree = DEVELOPER_DIR; };
60 F2CD856417C254A90019D2CA /* RPC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RPC.h; sourceTree = "<group>"; };
61 F2CD856517C254A90019D2CA /* RPC.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RPC.m; sourceTree = "<group>"; };
62 F2CD856917C282800019D2CA /* WebClient.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebClient.h; sourceTree = "<group>"; };
63 F2CD856A17C282800019D2CA /* WebClient.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = WebClient.m; sourceTree = "<group>"; };
64 F2D2A2EE13CBA680000824B4 /* WelcomeDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WelcomeDialog.h; sourceTree = "<group>"; };
65 F2D2A2EF13CBA680000824B4 /* WelcomeDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WelcomeDialog.m; sourceTree = "<group>"; };
66 F2F9804917C9081D004623D6 /* licenses */ = {isa = PBXFileReference; lastKnownFileType = folder; name = licenses; path = Resources/licenses; sourceTree = "<group>"; };
67 F2FC0F8B13BF595700D834E3 /* Credits.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = Credits.rtf; path = Resources/Credits.rtf; sourceTree = "<group>"; };
68 F2FCD73A13BB9CE900FC81F5 /* mainicon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = mainicon.icns; path = Images/mainicon.icns; sourceTree = "<group>"; };
69 F2FCD7D813BBDAED00FC81F5 /* statusicon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = statusicon.png; path = Images/statusicon.png; sourceTree = "<group>"; };
70 /* End PBXFileReference section */
71
72 /* Begin PBXFrameworksBuildPhase section */
73 8D11072E0486CEB800E47090 /* Frameworks */ = {
74 isa = PBXFrameworksBuildPhase;
75 buildActionMask = 2147483647;
76 files = (
77 F2C040481A18E946003EAB32 /* IOKit.framework in Frameworks */,
78 F20FC6E417C6BC8D00C392AC /* Security.framework in Frameworks */,
79 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */,
80 F29ABB2B17C00E150023A423 /* AppKit.framework in Frameworks */,
81 F29ABB2C17C00E190023A423 /* Foundation.framework in Frameworks */,
82 );
83 runOnlyForDeploymentPostprocessing = 0;
84 };
85 /* End PBXFrameworksBuildPhase section */
86
87 /* Begin PBXGroup section */
88 19C28FACFE9D520D11CA2CBB /* Products */ = {
89 isa = PBXGroup;
90 children = (
91 8D1107320486CEB800E47090 /* NZBGet.app */,
92 );
93 name = Products;
94 sourceTree = "<group>";
95 };
96 29B97314FDCFA39411CA2CEA /* NZBGet */ = {
97 isa = PBXGroup;
98 children = (
99 F26CBA8C136DE87500DCB596 /* Main */,
100 F29ABB2517BFC0450023A423 /* DaemonController */,
101 F2D2A2F213CBA7C8000824B4 /* WelcomeDialog */,
102 F21D343013BE339300E6D821 /* Preferences */,
103 F20FC6E017C6BA0100C392AC /* LetsMove */,
104 29B97315FDCFA39411CA2CEA /* Other Sources */,
105 29B97317FDCFA39411CA2CEA /* Resources */,
106 29B97323FDCFA39411CA2CEA /* Frameworks */,
107 19C28FACFE9D520D11CA2CBB /* Products */,
108 );
109 name = NZBGet;
110 sourceTree = "<group>";
111 };
112 29B97315FDCFA39411CA2CEA /* Other Sources */ = {
113 isa = PBXGroup;
114 children = (
115 256AC3F00F4B6AF500CF3369 /* App_Prefix.pch */,
116 );
117 name = "Other Sources";
118 sourceTree = "<group>";
119 };
120 29B97317FDCFA39411CA2CEA /* Resources */ = {
121 isa = PBXGroup;
122 children = (
123 F2F9804917C9081D004623D6 /* licenses */,
124 F2A55D3617C4CA9000D6FFE1 /* daemon */,
125 F2A55D3A17C4CAF800D6FFE1 /* tools */,
126 F2D370AE13C0859A002C0573 /* Images */,
127 F26D959A17C0E89D00E58E5D /* Localizable.strings */,
128 F26D959217C0E81800E58E5D /* Welcome.rtf */,
129 F2FC0F8B13BF595700D834E3 /* Credits.rtf */,
130 8D1107310486CEB800E47090 /* NZBGet-Info.plist */,
131 );
132 name = Resources;
133 sourceTree = "<group>";
134 };
135 29B97323FDCFA39411CA2CEA /* Frameworks */ = {
136 isa = PBXGroup;
137 children = (
138 F2C040471A18E946003EAB32 /* IOKit.framework */,
139 29B97324FDCFA39411CA2CEA /* AppKit.framework */,
140 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */,
141 29B97325FDCFA39411CA2CEA /* Foundation.framework */,
142 F20FC6E317C6BC8D00C392AC /* Security.framework */,
143 );
144 name = Frameworks;
145 sourceTree = "<group>";
146 };
147 F20FC6E017C6BA0100C392AC /* LetsMove */ = {
148 isa = PBXGroup;
149 children = (
150 F20FC6DE17C6B9FC00C392AC /* PFMoveApplication.h */,
151 F20FC6DF17C6B9FC00C392AC /* PFMoveApplication.m */,
152 );
153 name = LetsMove;
154 sourceTree = "<group>";
155 };
156 F21D343013BE339300E6D821 /* Preferences */ = {
157 isa = PBXGroup;
158 children = (
159 F26D959617C0E87E00E58E5D /* PreferencesDialog.xib */,
160 F21D369913BF387F00E6D821 /* PreferencesDialog.h */,
161 F21D369A13BF387F00E6D821 /* PreferencesDialog.m */,
162 );
163 name = Preferences;
164 sourceTree = "<group>";
165 };
166 F26CBA8C136DE87500DCB596 /* Main */ = {
167 isa = PBXGroup;
168 children = (
169 F26D959417C0E86300E58E5D /* MainApp.xib */,
170 F26CBA89136DE86A00DCB596 /* MainApp.h */,
171 F26CBA8A136DE86A00DCB596 /* MainApp.m */,
172 );
173 name = Main;
174 sourceTree = "<group>";
175 };
176 F29ABB2517BFC0450023A423 /* DaemonController */ = {
177 isa = PBXGroup;
178 children = (
179 F2CD856917C282800019D2CA /* WebClient.h */,
180 F2CD856A17C282800019D2CA /* WebClient.m */,
181 F2CD856417C254A90019D2CA /* RPC.h */,
182 F2CD856517C254A90019D2CA /* RPC.m */,
183 F29ABB2317BFC03D0023A423 /* DaemonController.h */,
184 F29ABB2417BFC03D0023A423 /* DaemonController.m */,
185 );
186 name = DaemonController;
187 sourceTree = "<group>";
188 };
189 F2D2A2F213CBA7C8000824B4 /* WelcomeDialog */ = {
190 isa = PBXGroup;
191 children = (
192 F26D959817C0E88700E58E5D /* WelcomeDialog.xib */,
193 F2D2A2EE13CBA680000824B4 /* WelcomeDialog.h */,
194 F2D2A2EF13CBA680000824B4 /* WelcomeDialog.m */,
195 );
196 name = WelcomeDialog;
197 sourceTree = "<group>";
198 };
199 F2D370AE13C0859A002C0573 /* Images */ = {
200 isa = PBXGroup;
201 children = (
202 F2FCD73A13BB9CE900FC81F5 /* mainicon.icns */,
203 F2A6E10F17C8E42300D910CB /* statusicon@2x.png */,
204 F2FCD7D813BBDAED00FC81F5 /* statusicon.png */,
205 );
206 name = Images;
207 path = Resources;
208 sourceTree = "<group>";
209 };
210 /* End PBXGroup section */
211
212 /* Begin PBXNativeTarget section */
213 8D1107260486CEB800E47090 /* NZBGet */ = {
214 isa = PBXNativeTarget;
215 buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "NZBGet" */;
216 buildPhases = (
217 8D1107290486CEB800E47090 /* Resources */,
218 8D11072C0486CEB800E47090 /* Sources */,
219 8D11072E0486CEB800E47090 /* Frameworks */,
220 );
221 buildRules = (
222 );
223 dependencies = (
224 );
225 name = NZBGet;
226 productInstallPath = "$(HOME)/Applications";
227 productName = NZBGet;
228 productReference = 8D1107320486CEB800E47090 /* NZBGet.app */;
229 productType = "com.apple.product-type.application";
230 };
231 /* End PBXNativeTarget section */
232
233 /* Begin PBXProject section */
234 29B97313FDCFA39411CA2CEA /* Project object */ = {
235 isa = PBXProject;
236 attributes = {
237 LastUpgradeCheck = 0460;
238 ORGANIZATIONNAME = "Andrey Prygunkov";
239 };
240 buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "NZBGet" */;
241 compatibilityVersion = "Xcode 3.2";
242 developmentRegion = English;
243 hasScannedForEncodings = 1;
244 knownRegions = (
245 English,
246 Japanese,
247 French,
248 German,
249 Russian,
250 de,
251 ru,
252 );
253 mainGroup = 29B97314FDCFA39411CA2CEA /* NZBGet */;
254 projectDirPath = "";
255 projectRoot = "";
256 targets = (
257 8D1107260486CEB800E47090 /* NZBGet */,
258 );
259 };
260 /* End PBXProject section */
261
262 /* Begin PBXResourcesBuildPhase section */
263 8D1107290486CEB800E47090 /* Resources */ = {
264 isa = PBXResourcesBuildPhase;
265 buildActionMask = 2147483647;
266 files = (
267 F2FCD73B13BB9CE900FC81F5 /* mainicon.icns in Resources */,
268 F2FCD7D913BBDAED00FC81F5 /* statusicon.png in Resources */,
269 F2BBD9C613E083160037473A /* Credits.rtf in Resources */,
270 F26D959317C0E81800E58E5D /* Welcome.rtf in Resources */,
271 F26D959517C0E86300E58E5D /* MainApp.xib in Resources */,
272 F26D959717C0E87E00E58E5D /* PreferencesDialog.xib in Resources */,
273 F26D959917C0E88700E58E5D /* WelcomeDialog.xib in Resources */,
274 F26D959B17C0E89D00E58E5D /* Localizable.strings in Resources */,
275 F2A55D3717C4CA9000D6FFE1 /* daemon in Resources */,
276 F2A55D3B17C4CAF800D6FFE1 /* tools in Resources */,
277 F2A6E11117C8E42300D910CB /* statusicon@2x.png in Resources */,
278 F2F9804A17C9081D004623D6 /* licenses in Resources */,
279 );
280 runOnlyForDeploymentPostprocessing = 0;
281 };
282 /* End PBXResourcesBuildPhase section */
283
284 /* Begin PBXSourcesBuildPhase section */
285 8D11072C0486CEB800E47090 /* Sources */ = {
286 isa = PBXSourcesBuildPhase;
287 buildActionMask = 2147483647;
288 files = (
289 F26CBA8B136DE86A00DCB596 /* MainApp.m in Sources */,
290 F21D369B13BF387F00E6D821 /* PreferencesDialog.m in Sources */,
291 F2D2A2F113CBA680000824B4 /* WelcomeDialog.m in Sources */,
292 F29ABB2617BFC61B0023A423 /* DaemonController.m in Sources */,
293 F2CD856817C282080019D2CA /* RPC.m in Sources */,
294 F2CD856B17C282820019D2CA /* WebClient.m in Sources */,
295 F20FC6E217C6BAAE00C392AC /* PFMoveApplication.m in Sources */,
296 );
297 runOnlyForDeploymentPostprocessing = 0;
298 };
299 /* End PBXSourcesBuildPhase section */
300
301 /* Begin XCBuildConfiguration section */
302 C01FCF4B08A954540054247B /* Debug */ = {
303 isa = XCBuildConfiguration;
304 buildSettings = {
305 ALWAYS_SEARCH_USER_PATHS = NO;
306 CLANG_ENABLE_OBJC_ARC = YES;
307 COPY_PHASE_STRIP = NO;
308 DEBUG_INFORMATION_FORMAT = dwarf;
309 FRAMEWORK_SEARCH_PATHS = (
310 "$(inherited)",
311 "\"$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/Frameworks/ApplicationServices.framework/Frameworks\"",
312 );
313 GCC_DYNAMIC_NO_PIC = NO;
314 GCC_MODEL_TUNING = G5;
315 GCC_OPTIMIZATION_LEVEL = 0;
316 GCC_PRECOMPILE_PREFIX_HEADER = YES;
317 GCC_PREFIX_HEADER = App_Prefix.pch;
318 "GCC_PREPROCESSOR_DEFINITIONS[arch=*]" = DEBUG;
319 HEADER_SEARCH_PATHS = "";
320 INFOPLIST_FILE = "NZBGet-Info.plist";
321 INSTALL_PATH = "$(HOME)/Applications";
322 MACOSX_DEPLOYMENT_TARGET = 10.7;
323 OTHER_LDFLAGS = "";
324 PRODUCT_NAME = NZBGet;
325 SDKROOT = macosx;
326 VALID_ARCHS = x86_64;
327 };
328 name = Debug;
329 };
330 C01FCF4C08A954540054247B /* Release */ = {
331 isa = XCBuildConfiguration;
332 buildSettings = {
333 ALWAYS_SEARCH_USER_PATHS = NO;
334 CLANG_ENABLE_OBJC_ARC = YES;
335 CODE_SIGN_IDENTITY = "";
336 DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
337 FRAMEWORK_SEARCH_PATHS = (
338 "$(inherited)",
339 "\"$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/Frameworks/ApplicationServices.framework/Frameworks\"",
340 );
341 GCC_MODEL_TUNING = G5;
342 GCC_PRECOMPILE_PREFIX_HEADER = YES;
343 GCC_PREFIX_HEADER = App_Prefix.pch;
344 INFOPLIST_FILE = "NZBGet-Info.plist";
345 INSTALL_PATH = "$(HOME)/Applications";
346 MACOSX_DEPLOYMENT_TARGET = 10.7;
347 PRODUCT_NAME = NZBGet;
348 SDKROOT = macosx;
349 VALID_ARCHS = x86_64;
350 };
351 name = Release;
352 };
353 C01FCF4F08A954540054247B /* Debug */ = {
354 isa = XCBuildConfiguration;
355 buildSettings = {
356 ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
357 GCC_C_LANGUAGE_STANDARD = gnu99;
358 GCC_OPTIMIZATION_LEVEL = 0;
359 GCC_WARN_ABOUT_RETURN_TYPE = YES;
360 GCC_WARN_UNUSED_VARIABLE = YES;
361 ONLY_ACTIVE_ARCH = YES;
362 PRODUCT_NAME = "";
363 SDKROOT = macosx10.6;
364 };
365 name = Debug;
366 };
367 C01FCF5008A954540054247B /* Release */ = {
368 isa = XCBuildConfiguration;
369 buildSettings = {
370 ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
371 CODE_SIGN_IDENTITY = "";
372 GCC_C_LANGUAGE_STANDARD = gnu99;
373 GCC_WARN_ABOUT_RETURN_TYPE = YES;
374 GCC_WARN_UNUSED_VARIABLE = YES;
375 PRODUCT_NAME = "";
376 SDKROOT = macosx10.6;
377 };
378 name = Release;
379 };
380 /* End XCBuildConfiguration section */
381
382 /* Begin XCConfigurationList section */
383 C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "NZBGet" */ = {
384 isa = XCConfigurationList;
385 buildConfigurations = (
386 C01FCF4B08A954540054247B /* Debug */,
387 C01FCF4C08A954540054247B /* Release */,
388 );
389 defaultConfigurationIsVisible = 0;
390 defaultConfigurationName = Release;
391 };
392 C01FCF4E08A954540054247B /* Build configuration list for PBXProject "NZBGet" */ = {
393 isa = XCConfigurationList;
394 buildConfigurations = (
395 C01FCF4F08A954540054247B /* Debug */,
396 C01FCF5008A954540054247B /* Release */,
397 );
398 defaultConfigurationIsVisible = 0;
399 defaultConfigurationName = Release;
400 };
401 /* End XCConfigurationList section */
402 };
403 rootObject = 29B97313FDCFA39411CA2CEA /* Project object */;
404 }
+0
-11
osx/PFMoveApplication.h less more
0 //
1 // PFMoveApplication.h, version 1.8
2 // LetsMove
3 //
4 // Created by Andy Kim at Potion Factory LLC on 9/17/09
5 //
6 // The contents of this file are dedicated to the public domain.
7
8 #import <Foundation/Foundation.h>
9
10 void PFMoveToApplicationsFolderIfNecessary(void);
+0
-460
osx/PFMoveApplication.m less more
0 //
1 // PFMoveApplication.m, version 1.8
2 // LetsMove
3 //
4 // Created by Andy Kim at Potion Factory LLC on 9/17/09
5 //
6 // The contents of this file are dedicated to the public domain.
7
8 #import "PFMoveApplication.h"
9 // Andrey Prygunkov (NZBGet):
10 // all references to "NSString+SymlinksAndAliases.h" removed because
11 // it has a BSD like license which might not be compatible with GPLv2.
12 // This makes the function a little bit less robust not properly handle some rare cases.
13 //#import "NSString+SymlinksAndAliases.h"
14 #import <Security/Security.h>
15 #import <dlfcn.h>
16
17 // Strings
18 // These are macros to be able to use custom i18n tools
19 #define _I10NS(nsstr) NSLocalizedStringFromTable(nsstr, @"MoveApplication", nil)
20 #define kStrMoveApplicationCouldNotMove _I10NS(@"Could not move to Applications folder")
21 #define kStrMoveApplicationQuestionTitle _I10NS(@"Move to Applications folder?")
22 #define kStrMoveApplicationQuestionTitleHome _I10NS(@"Move to Applications folder in your Home folder?")
23 #define kStrMoveApplicationQuestionMessage _I10NS(@"NZBGet can move itself to the Applications folder if you'd like.")
24 #define kStrMoveApplicationButtonMove _I10NS(@"Move to Applications Folder")
25 #define kStrMoveApplicationButtonDoNotMove _I10NS(@"Do Not Move")
26 #define kStrMoveApplicationQuestionInfoWillRequirePasswd _I10NS(@"Note that this will require an administrator password.")
27 #define kStrMoveApplicationQuestionInfoInDownloadsFolder _I10NS(@"This will keep your Downloads folder uncluttered.")
28
29 // Needs to be defined for compiling under 10.4 SDK
30 #ifndef NSAppKitVersionNumber10_4
31 #define NSAppKitVersionNumber10_4 824
32 #endif
33 // Needs to be defined for compiling under 10.5 SDK
34 #ifndef NSAppKitVersionNumber10_5
35 #define NSAppKitVersionNumber10_5 949
36 #endif
37
38 // By default, we use a small control/font for the suppression button.
39 // If you prefer to use the system default (to match your other alerts),
40 // set this to 0.
41 #define PFUseSmallAlertSuppressCheckbox 1
42
43
44 static NSString *AlertSuppressKey = @"moveToApplicationsFolderAlertSuppress";
45
46
47 // Helper functions
48 static NSString *PreferredInstallLocation(BOOL *isUserDirectory);
49 static BOOL IsInApplicationsFolder(NSString *path);
50 static BOOL IsInDownloadsFolder(NSString *path);
51 static BOOL IsLaunchedFromDMG();
52 static BOOL Trash(NSString *path);
53 static BOOL AuthorizedInstall(NSString *srcPath, NSString *dstPath, BOOL *canceled);
54 static BOOL CopyBundle(NSString *srcPath, NSString *dstPath);
55 static void Relaunch();
56
57 // Main worker function
58 void PFMoveToApplicationsFolderIfNecessary(void) {
59 // Skip if user suppressed the alert before
60 if ([[NSUserDefaults standardUserDefaults] boolForKey:AlertSuppressKey]) return;
61
62 // Path of the bundle
63 NSString *bundlePath = [[NSBundle mainBundle] bundlePath];
64
65 // Skip if the application is already in some Applications folder
66 if (IsInApplicationsFolder(bundlePath)) return;
67
68 // File Manager
69 NSFileManager *fm = [NSFileManager defaultManager];
70
71 BOOL isLaunchedFromDMG = IsLaunchedFromDMG();
72
73 // Since we are good to go, get the preferred installation directory.
74 BOOL installToUserApplications = NO;
75 NSString *applicationsDirectory = PreferredInstallLocation(&installToUserApplications);
76 NSString *bundleName = [bundlePath lastPathComponent];
77 NSString *destinationPath = [applicationsDirectory stringByAppendingPathComponent:bundleName];
78
79 // Check if we need admin password to write to the Applications directory
80 BOOL needAuthorization = ([fm isWritableFileAtPath:applicationsDirectory] == NO);
81
82 // Check if the destination bundle is already there but not writable
83 needAuthorization |= ([fm fileExistsAtPath:destinationPath] && ![fm isWritableFileAtPath:destinationPath]);
84
85 // Setup the alert
86 NSAlert *alert = [[[NSAlert alloc] init] autorelease];
87 {
88 NSString *informativeText = nil;
89
90 [alert setMessageText:(installToUserApplications ? kStrMoveApplicationQuestionTitleHome : kStrMoveApplicationQuestionTitle)];
91
92 informativeText = kStrMoveApplicationQuestionMessage;
93
94 if (needAuthorization) {
95 informativeText = [informativeText stringByAppendingString:@" "];
96 informativeText = [informativeText stringByAppendingString:kStrMoveApplicationQuestionInfoWillRequirePasswd];
97 }
98 else if (IsInDownloadsFolder(bundlePath)) {
99 // Don't mention this stuff if we need authentication. The informative text is long enough as it is in that case.
100 informativeText = [informativeText stringByAppendingString:@" "];
101 informativeText = [informativeText stringByAppendingString:kStrMoveApplicationQuestionInfoInDownloadsFolder];
102 }
103
104 [alert setInformativeText:informativeText];
105
106 // Add accept button
107 [alert addButtonWithTitle:kStrMoveApplicationButtonMove];
108
109 // Add deny button
110 NSButton *cancelButton = [alert addButtonWithTitle:kStrMoveApplicationButtonDoNotMove];
111 [cancelButton setKeyEquivalent:@"\e"];
112
113 #if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_4
114 if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_4) {
115 // Setup suppression button
116 [alert setShowsSuppressionButton:YES];
117
118 if (PFUseSmallAlertSuppressCheckbox) {
119 [[[alert suppressionButton] cell] setControlSize:NSSmallControlSize];
120 [[[alert suppressionButton] cell] setFont:[NSFont systemFontOfSize:[NSFont smallSystemFontSize]]];
121 }
122 }
123 #endif
124 }
125
126 // Activate app -- work-around for focus issues related to "scary file from internet" OS dialog.
127 if (![NSApp isActive]) {
128 [NSApp activateIgnoringOtherApps:YES];
129 }
130
131 if ([alert runModal] == NSAlertFirstButtonReturn) {
132 DLog(@"INFO -- Moving myself to the Applications folder");
133
134 // Move
135 if (needAuthorization) {
136 BOOL authorizationCanceled;
137
138 if (!AuthorizedInstall(bundlePath, destinationPath, &authorizationCanceled)) {
139 if (authorizationCanceled) {
140 DLog(@"INFO -- Not moving because user canceled authorization");
141 return;
142 }
143 else {
144 DLog(@"ERROR -- Could not copy myself to /Applications with authorization");
145 goto fail;
146 }
147 }
148 }
149 else {
150 // If a copy already exists in the Applications folder, put it in the Trash
151 if ([fm fileExistsAtPath:destinationPath]) {
152 // But first, make sure that it's not running
153 BOOL destinationIsRunning = NO;
154
155 // Use the shell to determine if the app is already running on systems 10.5 or lower
156 if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_5) {
157 NSString *script = [NSString stringWithFormat:@"ps ax -o comm | grep '%@/' | grep -v grep >/dev/null", destinationPath];
158 NSTask *task = [NSTask launchedTaskWithLaunchPath:@"/bin/sh" arguments:[NSArray arrayWithObjects:@"-c", script, nil]];
159 [task waitUntilExit];
160
161 // If the task terminated with status 0, it means that the final grep produced 1 or more lines of output.
162 // Which means that the app is already running
163 destinationIsRunning = ([task terminationStatus] == 0);
164 }
165 // Use the new API on 10.6 or higher
166 else {
167 for (NSRunningApplication *runningApplication in [[NSWorkspace sharedWorkspace] runningApplications]) {
168 NSString *executablePath = [[runningApplication executableURL] path];
169 if ([executablePath hasPrefix:destinationPath]) {
170 destinationIsRunning = YES;
171 break;
172 }
173 }
174 }
175
176 if (destinationIsRunning) {
177 // Give the running app focus and terminate myself
178 DLog(@"INFO -- Switching to an already running version");
179 [[NSTask launchedTaskWithLaunchPath:@"/usr/bin/open" arguments:[NSArray arrayWithObject:destinationPath]] waitUntilExit];
180 exit(0);
181 }
182 else {
183 if (!Trash([applicationsDirectory stringByAppendingPathComponent:bundleName]))
184 goto fail;
185 }
186 }
187
188 if (!CopyBundle(bundlePath, destinationPath)) {
189 DLog(@"ERROR -- Could not copy myself to %@", destinationPath);
190 goto fail;
191 }
192 }
193
194 // Trash the original app. It's okay if this fails.
195 // NOTE: This final delete does not work if the source bundle is in a network mounted volume.
196 // Calling rm or file manager's delete method doesn't work either. It's unlikely to happen
197 // but it'd be great if someone could fix this.
198 if (!isLaunchedFromDMG && !Trash(bundlePath)) {
199 DLog(@"WARNING -- Could not delete application after moving it to Applications folder");
200 }
201
202 // Relaunch.
203 Relaunch(destinationPath);
204 }
205 else {
206 if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_4) {
207 // Save the alert suppress preference if checked
208 #if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_4
209 if ([[alert suppressionButton] state] == NSOnState) {
210 [[NSUserDefaults standardUserDefaults] setBool:YES forKey:AlertSuppressKey];
211 }
212 #endif
213 }
214 else {
215 // Always suppress after the first decline on 10.4 since there is no suppression checkbox
216 [[NSUserDefaults standardUserDefaults] setBool:YES forKey:AlertSuppressKey];
217 }
218 }
219
220 return;
221
222 fail:
223 {
224 // Show failure message
225 alert = [[[NSAlert alloc] init] autorelease];
226 [alert setMessageText:kStrMoveApplicationCouldNotMove];
227 [alert runModal];
228 }
229 }
230
231 #pragma mark -
232 #pragma mark Helper Functions
233
234 static NSString *PreferredInstallLocation(BOOL *isUserDirectory) {
235 // Return the preferred install location.
236 // Assume that if the user has a ~/Applications folder, they'd prefer their
237 // applications to go there.
238
239 NSFileManager *fm = [NSFileManager defaultManager];
240
241 NSArray *userApplicationsDirs = NSSearchPathForDirectoriesInDomains(NSApplicationDirectory, NSUserDomainMask, YES);
242
243 if ([userApplicationsDirs count] > 0) {
244 NSString *userApplicationsDir = [userApplicationsDirs objectAtIndex:0];
245 BOOL isDirectory;
246
247 if ([fm fileExistsAtPath:userApplicationsDir isDirectory:&isDirectory] && isDirectory) {
248 // User Applications directory exists. Get the directory contents.
249 NSArray *contents = [fm contentsOfDirectoryAtPath:userApplicationsDir error:NULL];
250
251 // Check if there is at least one ".app" inside the directory.
252 for (NSString *contentsPath in contents) {
253 if ([[contentsPath pathExtension] isEqualToString:@"app"]) {
254 if (isUserDirectory) *isUserDirectory = YES;
255 //return [userApplicationsDir stringByResolvingSymlinksAndAliases];
256 return userApplicationsDir;
257 }
258 }
259 }
260 }
261
262 // No user Applications directory in use. Return the machine local Applications directory
263 if (isUserDirectory) *isUserDirectory = NO;
264 //return [[NSSearchPathForDirectoriesInDomains(NSApplicationDirectory, NSLocalDomainMask, YES) lastObject] stringByResolvingSymlinksAndAliases];
265 return [NSSearchPathForDirectoriesInDomains(NSApplicationDirectory, NSLocalDomainMask, YES) lastObject];
266 }
267
268 static BOOL IsInApplicationsFolder(NSString *path) {
269 // Check all the normal Application directories
270 NSEnumerator *e = [NSSearchPathForDirectoriesInDomains(NSApplicationDirectory, NSAllDomainsMask, YES) objectEnumerator];
271 NSString *appDirPath = nil;
272
273 while ((appDirPath = [e nextObject])) {
274 if ([path hasPrefix:appDirPath]) return YES;
275 }
276
277 // Also, handle the case that the user has some other Application directory (perhaps on a separate data partition).
278 if ([[path pathComponents] containsObject:@"Applications"]) {
279 return YES;
280 }
281
282 return NO;
283 }
284
285 static BOOL IsInDownloadsFolder(NSString *path) {
286 #if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_4
287 // 10.5 or higher has NSDownloadsDirectory
288 if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_4) {
289 NSEnumerator *e = [NSSearchPathForDirectoriesInDomains(NSDownloadsDirectory, NSAllDomainsMask, YES) objectEnumerator];
290 NSString *downloadsDirPath = nil;
291
292 while ((downloadsDirPath = [e nextObject])) {
293 if ([path hasPrefix:downloadsDirPath]) return YES;
294 }
295
296 return NO;
297 }
298 #endif
299 // 10.4
300 return [[[path stringByDeletingLastPathComponent] lastPathComponent] isEqualToString:@"Downloads"];
301 }
302
303 static BOOL IsLaunchedFromDMG() {
304 // Guess if we have launched from a disk image
305 NSString *bundlePath = [[NSBundle mainBundle] bundlePath];
306 NSFileManager *fm = [NSFileManager defaultManager];
307 BOOL bundlePathIsWritable = [fm isWritableFileAtPath:bundlePath];
308
309 return [bundlePath hasPrefix:@"/Volumes/"] && !bundlePathIsWritable;
310 }
311
312 static BOOL Trash(NSString *path) {
313 if ([[NSWorkspace sharedWorkspace] performFileOperation:NSWorkspaceRecycleOperation
314 source:[path stringByDeletingLastPathComponent]
315 destination:@""
316 files:[NSArray arrayWithObject:[path lastPathComponent]]
317 tag:NULL]) {
318 return YES;
319 }
320 else {
321 DLog(@"ERROR -- Could not trash '%@'", path);
322 return NO;
323 }
324 }
325
326 static BOOL AuthorizedInstall(NSString *srcPath, NSString *dstPath, BOOL *canceled) {
327 if (canceled) *canceled = NO;
328
329 // Make sure that the destination path is an app bundle. We're essentially running 'sudo rm -rf'
330 // so we really don't want to fuck this up.
331 if (![dstPath hasSuffix:@".app"]) return NO;
332
333 // Do some more checks
334 if ([[dstPath stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] length] == 0) return NO;
335 if ([[srcPath stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] length] == 0) return NO;
336
337 int pid, status;
338 AuthorizationRef myAuthorizationRef;
339
340 // Get the authorization
341 OSStatus err = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &myAuthorizationRef);
342 if (err != errAuthorizationSuccess) return NO;
343
344 AuthorizationItem myItems = {kAuthorizationRightExecute, 0, NULL, 0};
345 AuthorizationRights myRights = {1, &myItems};
346 AuthorizationFlags myFlags = kAuthorizationFlagInteractionAllowed | kAuthorizationFlagPreAuthorize | kAuthorizationFlagExtendRights;
347
348 err = AuthorizationCopyRights(myAuthorizationRef, &myRights, NULL, myFlags, NULL);
349 if (err != errAuthorizationSuccess) {
350 if (err == errAuthorizationCanceled && canceled)
351 *canceled = YES;
352 goto fail;
353 }
354
355 static OSStatus (*security_AuthorizationExecuteWithPrivileges)(AuthorizationRef authorization, const char *pathToTool,
356 AuthorizationFlags options, char * const *arguments,
357 FILE **communicationsPipe) = NULL;
358 if (!security_AuthorizationExecuteWithPrivileges) {
359 // On 10.7, AuthorizationExecuteWithPrivileges is deprecated. We want to still use it since there's no
360 // good alternative (without requiring code signing). We'll look up the function through dyld and fail
361 // if it is no longer accessible. If Apple removes the function entirely this will fail gracefully. If
362 // they keep the function and throw some sort of exception, this won't fail gracefully, but that's a
363 // risk we'll have to take for now.
364 security_AuthorizationExecuteWithPrivileges = dlsym(RTLD_DEFAULT, "AuthorizationExecuteWithPrivileges");
365 }
366 if (!security_AuthorizationExecuteWithPrivileges) {
367 goto fail;
368 }
369
370 // Delete the destination
371 {
372 char *args[] = {"-rf", (char *)[dstPath fileSystemRepresentation], NULL};
373 err = security_AuthorizationExecuteWithPrivileges(myAuthorizationRef, "/bin/rm", kAuthorizationFlagDefaults, args, NULL);
374 if (err != errAuthorizationSuccess) goto fail;
375
376 // Wait until it's done
377 pid = wait(&status);
378 if (pid == -1 || !WIFEXITED(status)) goto fail; // We don't care about exit status as the destination most likely does not exist
379 }
380
381 // Copy
382 {
383 char *args[] = {"-pR", (char *)[srcPath fileSystemRepresentation], (char *)[dstPath fileSystemRepresentation], NULL};
384 err = security_AuthorizationExecuteWithPrivileges(myAuthorizationRef, "/bin/cp", kAuthorizationFlagDefaults, args, NULL);
385 if (err != errAuthorizationSuccess) goto fail;
386
387 // Wait until it's done
388 pid = wait(&status);
389 if (pid == -1 || !WIFEXITED(status) || WEXITSTATUS(status)) goto fail;
390 }
391
392 AuthorizationFree(myAuthorizationRef, kAuthorizationFlagDefaults);
393 return YES;
394
395 fail:
396 AuthorizationFree(myAuthorizationRef, kAuthorizationFlagDefaults);
397 return NO;
398 }
399
400 static BOOL CopyBundle(NSString *srcPath, NSString *dstPath) {
401 NSFileManager *fm = [NSFileManager defaultManager];
402
403 #if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_4
404 // 10.5 or higher
405 if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_4) {
406 NSError *error = nil;
407 if ([fm copyItemAtPath:srcPath toPath:dstPath error:&error]) {
408 return YES;
409 }
410 else {
411 DLog(@"ERROR -- Could not copy '%@' to '%@' (%@)", srcPath, dstPath, error);
412 }
413 }
414 #endif
415 #if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4
416 if ([fm copyPath:srcPath toPath:dstPath handler:nil]) {
417 return YES;
418 }
419 else {
420 DLog(@"ERROR -- Could not copy '%@' to '%@'", srcPath, dstPath);
421 }
422 #endif
423 return NO;
424 }
425
426 static void Relaunch(NSString *destinationPath) {
427 // The shell script waits until the original app process terminates.
428 // This is done so that the relaunched app opens as the front-most app.
429 int pid = [[NSProcessInfo processInfo] processIdentifier];
430
431 // Command run just before running open /final/path
432 NSString *preOpenCmd = @"";
433
434 // OS X >=10.5:
435 // Before we launch the new app, clear xattr:com.apple.quarantine to avoid
436 // duplicate "scary file from the internet" dialog.
437 #if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_4
438 if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_5) {
439 // Add the -r flag on 10.6
440 preOpenCmd = [NSString stringWithFormat:@"/usr/bin/xattr -d -r com.apple.quarantine '%@';", destinationPath];
441 }
442 else if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_4) {
443 preOpenCmd = [NSString stringWithFormat:@"/usr/bin/xattr -d com.apple.quarantine '%@';", destinationPath];
444 }
445 #endif
446
447 NSString *script = [NSString stringWithFormat:@"(while [ `ps -p %d | wc -l` -gt 1 ]; do sleep 0.1; done; %@ open '%@') &", pid, preOpenCmd, destinationPath];
448
449 [NSTask launchedTaskWithLaunchPath:@"/bin/sh" arguments:[NSArray arrayWithObjects:@"-c", script, nil]];
450
451 // Launched from within a DMG? -- unmount (if no files are open after 5 seconds,
452 // otherwise leave it mounted).
453 if (IsLaunchedFromDMG()) {
454 script = [NSString stringWithFormat:@"(sleep 5 && hdiutil detach '%@') &", [[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent]];
455 [NSTask launchedTaskWithLaunchPath:@"/bin/sh" arguments:[NSArray arrayWithObjects:@"-c", script, nil]];
456 }
457
458 exit(0);
459 }
+0
-32
osx/PreferencesDialog.h less more
0 /*
1 * This file is part of nzbget. See <http://nzbget.net>.
2 *
3 * Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #import <Cocoa/Cocoa.h>
20
21 @interface PreferencesDialog : NSWindowController {
22 IBOutlet NSButton *autostartButton;
23 IBOutlet NSButton *showStatusIconButton;
24 IBOutlet NSTextField *generalText;
25 IBOutlet NSTextField *appearanceText;
26 IBOutlet NSButton *autoShowWebUI;
27 }
28
29 - (IBAction)autostartButtonClicked:(id)sender;
30
31 @end
+0
-111
osx/PreferencesDialog.m less more
0 /*
1 * This file is part of nzbget. See <http://nzbget.net>.
2 *
3 * Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #import "PreferencesDialog.h"
20
21
22 @implementation PreferencesDialog
23
24 - (id)init {
25 return [super initWithWindowNibName:@"PreferencesDialog"];
26 }
27
28 - (void)windowDidLoad {
29 }
30
31 - (void)enableLoginItemWithLoginItemsReference:(LSSharedFileListRef )theLoginItemsRefs ForPath:(NSString *)appPath {
32 // We call LSSharedFileListInsertItemURL to insert the item at the bottom of Login Items list.
33 CFURLRef url = (__bridge CFURLRef)[NSURL fileURLWithPath:appPath];
34 LSSharedFileListItemRef item = LSSharedFileListInsertItemURL(theLoginItemsRefs, kLSSharedFileListItemLast, NULL, NULL, url, NULL, NULL);
35 if (item)
36 CFRelease(item);
37 }
38
39 - (void)disableLoginItemWithLoginItemsReference:(LSSharedFileListRef )theLoginItemsRefs ForPath:(NSString *)appPath {
40 UInt32 seedValue;
41 CFURLRef thePath;
42 // We're going to grab the contents of the shared file list (LSSharedFileListItemRef objects)
43 // and pop it in an array so we can iterate through it to find our item.
44 CFArrayRef loginItemsArray = LSSharedFileListCopySnapshot(theLoginItemsRefs, &seedValue);
45 for (id item in (__bridge NSArray *)loginItemsArray) {
46 LSSharedFileListItemRef itemRef = (__bridge LSSharedFileListItemRef)item;
47 if (LSSharedFileListItemResolve(itemRef, 0, (CFURLRef*) &thePath, NULL) == noErr) {
48 if ([[(__bridge NSURL *)thePath path] hasPrefix:appPath]) {
49 LSSharedFileListItemRemove(theLoginItemsRefs, itemRef); // Deleting the item
50 }
51 // Docs for LSSharedFileListItemResolve say we're responsible
52 // for releasing the CFURLRef that is returned
53 CFRelease(thePath);
54 }
55 }
56 CFRelease(loginItemsArray);
57 }
58
59 - (BOOL)loginItemExistsWithLoginItemReference:(LSSharedFileListRef)theLoginItemsRefs ForPath:(NSString *)appPath {
60 BOOL found = NO;
61 UInt32 seedValue;
62 CFURLRef thePath;
63
64 // We're going to grab the contents of the shared file list (LSSharedFileListItemRef objects)
65 // and pop it in an array so we can iterate through it to find our item.
66 CFArrayRef loginItemsArray = LSSharedFileListCopySnapshot(theLoginItemsRefs, &seedValue);
67 for (id item in (__bridge NSArray *)loginItemsArray) {
68 LSSharedFileListItemRef itemRef = (__bridge LSSharedFileListItemRef)item;
69 if (LSSharedFileListItemResolve(itemRef, 0, (CFURLRef*) &thePath, NULL) == noErr) {
70 if ([[(__bridge NSURL *)thePath path] hasPrefix:appPath]) {
71 found = YES;
72 break;
73 }
74 // Docs for LSSharedFileListItemResolve say we're responsible
75 // for releasing the CFURLRef that is returned
76 CFRelease(thePath);
77 }
78 }
79 CFRelease(loginItemsArray);
80
81 return found;
82 }
83
84 - (void)awakeFromNib {
85 // This will retrieve the path for the application
86 // For example, /Applications/test.app
87 NSString * appPath = [[NSBundle mainBundle] bundlePath];
88
89 LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
90 if ([self loginItemExistsWithLoginItemReference:loginItems ForPath:appPath]) {
91 [autostartButton setState:NSOnState];
92 }
93 CFRelease(loginItems);
94 }
95
96 - (IBAction)autostartButtonClicked:(id)sender {
97 NSString * appPath = [[NSBundle mainBundle] bundlePath];
98
99 // Create a reference to the shared file list.
100 LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
101 if (loginItems) {
102 if ([sender state] == NSOnState)
103 [self enableLoginItemWithLoginItemsReference:loginItems ForPath:appPath];
104 else
105 [self disableLoginItemWithLoginItemsReference:loginItems ForPath:appPath];
106 }
107 CFRelease(loginItems);
108 }
109
110 @end
+0
-623
osx/PreferencesDialog.xib less more
0 <?xml version="1.0" encoding="UTF-8"?>
1 <archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
2 <data>
3 <int key="IBDocument.SystemTarget">1070</int>
4 <string key="IBDocument.SystemVersion">11G63</string>
5 <string key="IBDocument.InterfaceBuilderVersion">3084</string>
6 <string key="IBDocument.AppKitVersion">1138.51</string>
7 <string key="IBDocument.HIToolboxVersion">569.00</string>
8 <object class="NSMutableDictionary" key="IBDocument.PluginVersions">
9 <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
10 <string key="NS.object.0">3084</string>
11 </object>
12 <object class="NSArray" key="IBDocument.IntegratedClassDependencies">
13 <bool key="EncodedWithXMLCoder">YES</bool>
14 <string>NSButton</string>
15 <string>NSButtonCell</string>
16 <string>NSCustomObject</string>
17 <string>NSImageCell</string>
18 <string>NSImageView</string>
19 <string>NSTextField</string>
20 <string>NSTextFieldCell</string>
21 <string>NSUserDefaultsController</string>
22 <string>NSView</string>
23 <string>NSWindowTemplate</string>
24 </object>
25 <object class="NSArray" key="IBDocument.PluginDependencies">
26 <bool key="EncodedWithXMLCoder">YES</bool>
27 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
28 </object>
29 <object class="NSMutableDictionary" key="IBDocument.Metadata">
30 <string key="NS.key.0">PluginDependencyRecalculationVersion</string>
31 <integer value="1" key="NS.object.0"/>
32 </object>
33 <object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
34 <bool key="EncodedWithXMLCoder">YES</bool>
35 <object class="NSCustomObject" id="1001">
36 <string key="NSClassName">PreferencesDialog</string>
37 </object>
38 <object class="NSCustomObject" id="1003">
39 <string key="NSClassName">FirstResponder</string>
40 </object>
41 <object class="NSCustomObject" id="1004">
42 <string key="NSClassName">NSApplication</string>
43 </object>
44 <object class="NSWindowTemplate" id="1005">
45 <int key="NSWindowStyleMask">3</int>
46 <int key="NSWindowBacking">2</int>
47 <string key="NSWindowRect">{{196, 436}, {357, 155}}</string>
48 <int key="NSWTFlags">544735232</int>
49 <string key="NSWindowTitle">NZBGet Preferences</string>
50 <string key="NSWindowClass">NSWindow</string>
51 <nil key="NSViewClass"/>
52 <nil key="NSUserInterfaceItemIdentifier"/>
53 <object class="NSView" key="NSWindowView" id="1006">
54 <reference key="NSNextResponder"/>
55 <int key="NSvFlags">256</int>
56 <object class="NSMutableArray" key="NSSubviews">
57 <bool key="EncodedWithXMLCoder">YES</bool>
58 <object class="NSButton" id="668723838">
59 <reference key="NSNextResponder" ref="1006"/>
60 <int key="NSvFlags">268</int>
61 <string key="NSFrame">{{67, 119}, {213, 18}}</string>
62 <reference key="NSSuperview" ref="1006"/>
63 <reference key="NSWindow"/>
64 <reference key="NSNextKeyView" ref="445769"/>
65 <bool key="NSEnabled">YES</bool>
66 <object class="NSButtonCell" key="NSCell" id="474631304">
67 <int key="NSCellFlags">67239424</int>
68 <int key="NSCellFlags2">0</int>
69 <string key="NSContents">Start at login</string>
70 <object class="NSFont" key="NSSupport" id="1028951332">
71 <string key="NSName">LucidaGrande</string>
72 <double key="NSSize">13</double>
73 <int key="NSfFlags">1044</int>
74 </object>
75 <reference key="NSControlView" ref="668723838"/>
76 <int key="NSButtonFlags">1211912703</int>
77 <int key="NSButtonFlags2">2</int>
78 <object class="NSCustomResource" key="NSNormalImage" id="167410980">
79 <string key="NSClassName">NSImage</string>
80 <string key="NSResourceName">NSSwitch</string>
81 </object>
82 <object class="NSButtonImageSource" key="NSAlternateImage" id="341711700">
83 <string key="NSImageName">NSSwitch</string>
84 </object>
85 <string key="NSAlternateContents"/>
86 <string key="NSKeyEquivalent"/>
87 <int key="NSPeriodicDelay">200</int>
88 <int key="NSPeriodicInterval">25</int>
89 </object>
90 </object>
91 <object class="NSButton" id="445769">
92 <reference key="NSNextResponder" ref="1006"/>
93 <int key="NSvFlags">268</int>
94 <string key="NSFrame">{{67, 99}, {213, 18}}</string>
95 <reference key="NSSuperview" ref="1006"/>
96 <reference key="NSWindow"/>
97 <reference key="NSNextKeyView" ref="897618223"/>
98 <bool key="NSEnabled">YES</bool>
99 <object class="NSButtonCell" key="NSCell" id="741315823">
100 <int key="NSCellFlags">67239424</int>
101 <int key="NSCellFlags2">0</int>
102 <string key="NSContents">Show in menubar</string>
103 <reference key="NSSupport" ref="1028951332"/>
104 <reference key="NSControlView" ref="445769"/>
105 <int key="NSButtonFlags">1211912703</int>
106 <int key="NSButtonFlags2">2</int>
107 <reference key="NSNormalImage" ref="167410980"/>
108 <reference key="NSAlternateImage" ref="341711700"/>
109 <string key="NSAlternateContents"/>
110 <string key="NSKeyEquivalent"/>
111 <int key="NSPeriodicDelay">200</int>
112 <int key="NSPeriodicInterval">25</int>
113 </object>
114 </object>
115 <object class="NSButton" id="897618223">
116 <reference key="NSNextResponder" ref="1006"/>
117 <int key="NSvFlags">268</int>
118 <string key="NSFrame">{{67, 79}, {213, 18}}</string>
119 <reference key="NSSuperview" ref="1006"/>
120 <reference key="NSWindow"/>
121 <reference key="NSNextKeyView" ref="205669972"/>
122 <bool key="NSEnabled">YES</bool>
123 <object class="NSButtonCell" key="NSCell" id="395093705">
124 <int key="NSCellFlags">67239424</int>
125 <int key="NSCellFlags2">0</int>
126 <string key="NSContents">Show Web-Interface on start</string>
127 <reference key="NSSupport" ref="1028951332"/>
128 <reference key="NSControlView" ref="897618223"/>
129 <int key="NSButtonFlags">1211912703</int>
130 <int key="NSButtonFlags2">2</int>
131 <reference key="NSNormalImage" ref="167410980"/>
132 <reference key="NSAlternateImage" ref="341711700"/>
133 <string key="NSAlternateContents"/>
134 <string key="NSKeyEquivalent"/>
135 <int key="NSPeriodicDelay">200</int>
136 <int key="NSPeriodicInterval">25</int>
137 </object>
138 </object>
139 <object class="NSImageView" id="205669972">
140 <reference key="NSNextResponder" ref="1006"/>
141 <int key="NSvFlags">268</int>
142 <object class="NSMutableSet" key="NSDragTypes">
143 <bool key="EncodedWithXMLCoder">YES</bool>
144 <object class="NSArray" key="set.sortedObjects">
145 <bool key="EncodedWithXMLCoder">YES</bool>
146 <string>Apple PDF pasteboard type</string>
147 <string>Apple PICT pasteboard type</string>
148 <string>Apple PNG pasteboard type</string>
149 <string>NSFilenamesPboardType</string>
150 <string>NeXT Encapsulated PostScript v1.2 pasteboard type</string>
151 <string>NeXT TIFF v4.0 pasteboard type</string>
152 </object>
153 </object>
154 <string key="NSFrame">{{20, 30}, {32, 32}}</string>
155 <reference key="NSSuperview" ref="1006"/>
156 <reference key="NSWindow"/>
157 <reference key="NSNextKeyView" ref="371541245"/>
158 <int key="NSViewLayerContentsRedrawPolicy">2</int>
159 <bool key="NSEnabled">YES</bool>
160 <object class="NSImageCell" key="NSCell" id="15570902">
161 <int key="NSCellFlags">134348288</int>
162 <int key="NSCellFlags2">33554432</int>
163 <object class="NSCustomResource" key="NSContents">
164 <string key="NSClassName">NSImage</string>
165 <string key="NSResourceName">NSInfo</string>
166 </object>
167 <int key="NSAlign">0</int>
168 <int key="NSScale">3</int>
169 <int key="NSStyle">0</int>
170 <bool key="NSAnimates">NO</bool>
171 </object>
172 <bool key="NSEditable">YES</bool>
173 </object>
174 <object class="NSTextField" id="371541245">
175 <reference key="NSNextResponder" ref="1006"/>
176 <int key="NSvFlags">268</int>
177 <string key="NSFrame">{{66, 20}, {244, 42}}</string>
178 <reference key="NSSuperview" ref="1006"/>
179 <reference key="NSWindow"/>
180 <string key="NSReuseIdentifierKey">_NS:1535</string>
181 <bool key="NSEnabled">YES</bool>
182 <object class="NSTextFieldCell" key="NSCell" id="833412041">
183 <int key="NSCellFlags">67108864</int>
184 <int key="NSCellFlags2">4325376</int>
185 <string key="NSContents">Only OSX-specific options are located here. For all other options see Settings page in Web-Interface.</string>
186 <object class="NSFont" key="NSSupport">
187 <string key="NSName">LucidaGrande</string>
188 <double key="NSSize">11</double>
189 <int key="NSfFlags">3100</int>
190 </object>
191 <string key="NSCellIdentifier">_NS:1535</string>
192 <reference key="NSControlView" ref="371541245"/>
193 <object class="NSColor" key="NSBackgroundColor">
194 <int key="NSColorSpace">6</int>
195 <string key="NSCatalogName">System</string>
196 <string key="NSColorName">controlColor</string>
197 <object class="NSColor" key="NSColor">
198 <int key="NSColorSpace">3</int>
199 <bytes key="NSWhite">MC42NjY2NjY2NjY3AA</bytes>
200 </object>
201 </object>
202 <object class="NSColor" key="NSTextColor">
203 <int key="NSColorSpace">6</int>
204 <string key="NSCatalogName">System</string>
205 <string key="NSColorName">controlTextColor</string>
206 <object class="NSColor" key="NSColor">
207 <int key="NSColorSpace">3</int>
208 <bytes key="NSWhite">MAA</bytes>
209 </object>
210 </object>
211 </object>
212 </object>
213 </object>
214 <string key="NSFrameSize">{357, 155}</string>
215 <reference key="NSSuperview"/>
216 <reference key="NSWindow"/>
217 <reference key="NSNextKeyView" ref="668723838"/>
218 </object>
219 <string key="NSScreenRect">{{0, 0}, {1440, 878}}</string>
220 <string key="NSMaxSize">{10000000000000, 10000000000000}</string>
221 <bool key="NSWindowIsRestorable">YES</bool>
222 </object>
223 <object class="NSUserDefaultsController" id="575306214">
224 <bool key="NSSharedInstance">YES</bool>
225 </object>
226 </object>
227 <object class="IBObjectContainer" key="IBDocument.Objects">
228 <object class="NSMutableArray" key="connectionRecords">
229 <bool key="EncodedWithXMLCoder">YES</bool>
230 <object class="IBConnectionRecord">
231 <object class="IBOutletConnection" key="connection">
232 <string key="label">window</string>
233 <reference key="source" ref="1001"/>
234 <reference key="destination" ref="1005"/>
235 </object>
236 <int key="connectionID">11</int>
237 </object>
238 <object class="IBConnectionRecord">
239 <object class="IBActionConnection" key="connection">
240 <string key="label">autostartButtonClicked:</string>
241 <reference key="source" ref="1001"/>
242 <reference key="destination" ref="668723838"/>
243 </object>
244 <int key="connectionID">24</int>
245 </object>
246 <object class="IBConnectionRecord">
247 <object class="IBOutletConnection" key="connection">
248 <string key="label">autostartButton</string>
249 <reference key="source" ref="1001"/>
250 <reference key="destination" ref="668723838"/>
251 </object>
252 <int key="connectionID">25</int>
253 </object>
254 <object class="IBConnectionRecord">
255 <object class="IBOutletConnection" key="connection">
256 <string key="label">showStatusIconButton</string>
257 <reference key="source" ref="1001"/>
258 <reference key="destination" ref="445769"/>
259 </object>
260 <int key="connectionID">28</int>
261 </object>
262 <object class="IBConnectionRecord">
263 <object class="IBOutletConnection" key="connection">
264 <string key="label">autoShowWebUI</string>
265 <reference key="source" ref="1001"/>
266 <reference key="destination" ref="897618223"/>
267 </object>
268 <int key="connectionID">32</int>
269 </object>
270 <object class="IBConnectionRecord">
271 <object class="IBOutletConnection" key="connection">
272 <string key="label">delegate</string>
273 <reference key="source" ref="1005"/>
274 <reference key="destination" ref="1001"/>
275 </object>
276 <int key="connectionID">12</int>
277 </object>
278 <object class="IBConnectionRecord">
279 <object class="IBBindingConnection" key="connection">
280 <string key="label">value: values.ShowInMenubar</string>
281 <reference key="source" ref="445769"/>
282 <reference key="destination" ref="575306214"/>
283 <object class="NSNibBindingConnector" key="connector">
284 <reference key="NSSource" ref="445769"/>
285 <reference key="NSDestination" ref="575306214"/>
286 <string key="NSLabel">value: values.ShowInMenubar</string>
287 <string key="NSBinding">value</string>
288 <string key="NSKeyPath">values.ShowInMenubar</string>
289 <object class="NSDictionary" key="NSOptions">
290 <string key="NS.key.0">NSValidatesImmediately</string>
291 <boolean value="YES" key="NS.object.0"/>
292 </object>
293 <int key="NSNibBindingConnectorVersion">2</int>
294 </object>
295 </object>
296 <int key="connectionID">23</int>
297 </object>
298 <object class="IBConnectionRecord">
299 <object class="IBBindingConnection" key="connection">
300 <string key="label">value: values.AutoStartWebUI</string>
301 <reference key="source" ref="897618223"/>
302 <reference key="destination" ref="575306214"/>
303 <object class="NSNibBindingConnector" key="connector">
304 <reference key="NSSource" ref="897618223"/>
305 <reference key="NSDestination" ref="575306214"/>
306 <string key="NSLabel">value: values.AutoStartWebUI</string>
307 <string key="NSBinding">value</string>
308 <string key="NSKeyPath">values.AutoStartWebUI</string>
309 <object class="NSDictionary" key="NSOptions">
310 <string key="NS.key.0">NSValidatesImmediately</string>
311 <boolean value="YES" key="NS.object.0"/>
312 </object>
313 <int key="NSNibBindingConnectorVersion">2</int>
314 </object>
315 </object>
316 <int key="connectionID">34</int>
317 </object>
318 </object>
319 <object class="IBMutableOrderedSet" key="objectRecords">
320 <object class="NSArray" key="orderedObjects">
321 <bool key="EncodedWithXMLCoder">YES</bool>
322 <object class="IBObjectRecord">
323 <int key="objectID">0</int>
324 <object class="NSArray" key="object" id="0">
325 <bool key="EncodedWithXMLCoder">YES</bool>
326 </object>
327 <reference key="children" ref="1000"/>
328 <nil key="parent"/>
329 </object>
330 <object class="IBObjectRecord">
331 <int key="objectID">-2</int>
332 <reference key="object" ref="1001"/>
333 <reference key="parent" ref="0"/>
334 <string key="objectName">File's Owner</string>
335 </object>
336 <object class="IBObjectRecord">
337 <int key="objectID">-1</int>
338 <reference key="object" ref="1003"/>
339 <reference key="parent" ref="0"/>
340 <string key="objectName">First Responder</string>
341 </object>
342 <object class="IBObjectRecord">
343 <int key="objectID">-3</int>
344 <reference key="object" ref="1004"/>
345 <reference key="parent" ref="0"/>
346 <string key="objectName">Application</string>
347 </object>
348 <object class="IBObjectRecord">
349 <int key="objectID">1</int>
350 <reference key="object" ref="1005"/>
351 <object class="NSMutableArray" key="children">
352 <bool key="EncodedWithXMLCoder">YES</bool>
353 <reference ref="1006"/>
354 </object>
355 <reference key="parent" ref="0"/>
356 </object>
357 <object class="IBObjectRecord">
358 <int key="objectID">2</int>
359 <reference key="object" ref="1006"/>
360 <object class="NSMutableArray" key="children">
361 <bool key="EncodedWithXMLCoder">YES</bool>
362 <reference ref="668723838"/>
363 <reference ref="445769"/>
364 <reference ref="897618223"/>
365 <reference ref="371541245"/>
366 <reference ref="205669972"/>
367 </object>
368 <reference key="parent" ref="1005"/>
369 </object>
370 <object class="IBObjectRecord">
371 <int key="objectID">3</int>
372 <reference key="object" ref="668723838"/>
373 <object class="NSMutableArray" key="children">
374 <bool key="EncodedWithXMLCoder">YES</bool>
375 <reference ref="474631304"/>
376 </object>
377 <reference key="parent" ref="1006"/>
378 </object>
379 <object class="IBObjectRecord">
380 <int key="objectID">4</int>
381 <reference key="object" ref="474631304"/>
382 <reference key="parent" ref="668723838"/>
383 </object>
384 <object class="IBObjectRecord">
385 <int key="objectID">8</int>
386 <reference key="object" ref="445769"/>
387 <object class="NSMutableArray" key="children">
388 <bool key="EncodedWithXMLCoder">YES</bool>
389 <reference ref="741315823"/>
390 </object>
391 <reference key="parent" ref="1006"/>
392 </object>
393 <object class="IBObjectRecord">
394 <int key="objectID">9</int>
395 <reference key="object" ref="741315823"/>
396 <reference key="parent" ref="445769"/>
397 </object>
398 <object class="IBObjectRecord">
399 <int key="objectID">14</int>
400 <reference key="object" ref="575306214"/>
401 <reference key="parent" ref="0"/>
402 </object>
403 <object class="IBObjectRecord">
404 <int key="objectID">29</int>
405 <reference key="object" ref="897618223"/>
406 <object class="NSMutableArray" key="children">
407 <bool key="EncodedWithXMLCoder">YES</bool>
408 <reference ref="395093705"/>
409 </object>
410 <reference key="parent" ref="1006"/>
411 </object>
412 <object class="IBObjectRecord">
413 <int key="objectID">30</int>
414 <reference key="object" ref="395093705"/>
415 <reference key="parent" ref="897618223"/>
416 </object>
417 <object class="IBObjectRecord">
418 <int key="objectID">35</int>
419 <reference key="object" ref="205669972"/>
420 <object class="NSMutableArray" key="children">
421 <bool key="EncodedWithXMLCoder">YES</bool>
422 <reference ref="15570902"/>
423 </object>
424 <reference key="parent" ref="1006"/>
425 </object>
426 <object class="IBObjectRecord">
427 <int key="objectID">36</int>
428 <reference key="object" ref="15570902"/>
429 <reference key="parent" ref="205669972"/>
430 </object>
431 <object class="IBObjectRecord">
432 <int key="objectID">37</int>
433 <reference key="object" ref="371541245"/>
434 <object class="NSMutableArray" key="children">
435 <bool key="EncodedWithXMLCoder">YES</bool>
436 <reference ref="833412041"/>
437 </object>
438 <reference key="parent" ref="1006"/>
439 </object>
440 <object class="IBObjectRecord">
441 <int key="objectID">38</int>
442 <reference key="object" ref="833412041"/>
443 <reference key="parent" ref="371541245"/>
444 </object>
445 </object>
446 </object>
447 <object class="NSMutableDictionary" key="flattenedProperties">
448 <bool key="EncodedWithXMLCoder">YES</bool>
449 <object class="NSArray" key="dict.sortedKeys">
450 <bool key="EncodedWithXMLCoder">YES</bool>
451 <string>-1.IBPluginDependency</string>
452 <string>-2.IBPluginDependency</string>
453 <string>-3.IBPluginDependency</string>
454 <string>1.IBPluginDependency</string>
455 <string>1.IBWindowTemplateEditedContentRect</string>
456 <string>1.NSWindowTemplate.visibleAtLaunch</string>
457 <string>14.IBPluginDependency</string>
458 <string>2.IBPluginDependency</string>
459 <string>2.IBUserGuides</string>
460 <string>29.IBPluginDependency</string>
461 <string>3.IBPluginDependency</string>
462 <string>30.IBPluginDependency</string>
463 <string>35.IBAttributePlaceholdersKey</string>
464 <string>35.IBPluginDependency</string>
465 <string>36.IBPluginDependency</string>
466 <string>37.IBPluginDependency</string>
467 <string>38.IBPluginDependency</string>
468 <string>4.IBPluginDependency</string>
469 <string>8.IBPluginDependency</string>
470 <string>9.IBPluginDependency</string>
471 </object>
472 <object class="NSArray" key="dict.values">
473 <bool key="EncodedWithXMLCoder">YES</bool>
474 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
475 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
476 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
477 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
478 <string>{{322, 782}, {298, 74}}</string>
479 <boolean value="NO"/>
480 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
481 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
482 <object class="NSMutableArray">
483 <bool key="EncodedWithXMLCoder">YES</bool>
484 </object>
485 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
486 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
487 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
488 <object class="NSMutableDictionary">
489 <string key="NS.key.0">AccessibilityDescription</string>
490 <object class="IBAccessibilityAttribute" key="NS.object.0">
491 <string key="name">AccessibilityDescription</string>
492 <reference key="object" ref="205669972"/>
493 <string key="accessibilityValue">information</string>
494 </object>
495 </object>
496 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
497 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
498 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
499 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
500 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
501 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
502 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
503 </object>
504 </object>
505 <object class="NSMutableDictionary" key="unlocalizedProperties">
506 <bool key="EncodedWithXMLCoder">YES</bool>
507 <reference key="dict.sortedKeys" ref="0"/>
508 <reference key="dict.values" ref="0"/>
509 </object>
510 <nil key="activeLocalization"/>
511 <object class="NSMutableDictionary" key="localizations">
512 <bool key="EncodedWithXMLCoder">YES</bool>
513 <reference key="dict.sortedKeys" ref="0"/>
514 <reference key="dict.values" ref="0"/>
515 </object>
516 <nil key="sourceID"/>
517 <int key="maxID">38</int>
518 </object>
519 <object class="IBClassDescriber" key="IBDocument.Classes">
520 <object class="NSMutableArray" key="referencedPartialClassDescriptions">
521 <bool key="EncodedWithXMLCoder">YES</bool>
522 <object class="IBPartialClassDescription">
523 <string key="className">PreferencesDialog</string>
524 <string key="superclassName">NSWindowController</string>
525 <object class="NSMutableDictionary" key="actions">
526 <string key="NS.key.0">autostartButtonClicked:</string>
527 <string key="NS.object.0">id</string>
528 </object>
529 <object class="NSMutableDictionary" key="actionInfosByName">
530 <string key="NS.key.0">autostartButtonClicked:</string>
531 <object class="IBActionInfo" key="NS.object.0">
532 <string key="name">autostartButtonClicked:</string>
533 <string key="candidateClassName">id</string>
534 </object>
535 </object>
536 <object class="NSMutableDictionary" key="outlets">
537 <bool key="EncodedWithXMLCoder">YES</bool>
538 <object class="NSArray" key="dict.sortedKeys">
539 <bool key="EncodedWithXMLCoder">YES</bool>
540 <string>appearanceText</string>
541 <string>autoShowWebUI</string>
542 <string>autostartButton</string>
543 <string>generalText</string>
544 <string>showStatusIconButton</string>
545 </object>
546 <object class="NSArray" key="dict.values">
547 <bool key="EncodedWithXMLCoder">YES</bool>
548 <string>NSTextField</string>
549 <string>NSButton</string>
550 <string>NSButton</string>
551 <string>NSTextField</string>
552 <string>NSButton</string>
553 </object>
554 </object>
555 <object class="NSMutableDictionary" key="toOneOutletInfosByName">
556 <bool key="EncodedWithXMLCoder">YES</bool>
557 <object class="NSArray" key="dict.sortedKeys">
558 <bool key="EncodedWithXMLCoder">YES</bool>
559 <string>appearanceText</string>
560 <string>autoShowWebUI</string>
561 <string>autostartButton</string>
562 <string>generalText</string>
563 <string>showStatusIconButton</string>
564 </object>
565 <object class="NSArray" key="dict.values">
566 <bool key="EncodedWithXMLCoder">YES</bool>
567 <object class="IBToOneOutletInfo">
568 <string key="name">appearanceText</string>
569 <string key="candidateClassName">NSTextField</string>
570 </object>
571 <object class="IBToOneOutletInfo">
572 <string key="name">autoShowWebUI</string>
573 <string key="candidateClassName">NSButton</string>
574 </object>
575 <object class="IBToOneOutletInfo">
576 <string key="name">autostartButton</string>
577 <string key="candidateClassName">NSButton</string>
578 </object>
579 <object class="IBToOneOutletInfo">
580 <string key="name">generalText</string>
581 <string key="candidateClassName">NSTextField</string>
582 </object>
583 <object class="IBToOneOutletInfo">
584 <string key="name">showStatusIconButton</string>
585 <string key="candidateClassName">NSButton</string>
586 </object>
587 </object>
588 </object>
589 <object class="IBClassDescriptionSource" key="sourceIdentifier">
590 <string key="majorKey">IBProjectSource</string>
591 <string key="minorKey">./Classes/PreferencesDialog.h</string>
592 </object>
593 </object>
594 </object>
595 </object>
596 <int key="IBDocument.localizationMode">0</int>
597 <string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
598 <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencyDefaults">
599 <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
600 <real value="1070" key="NS.object.0"/>
601 </object>
602 <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
603 <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3</string>
604 <integer value="3000" key="NS.object.0"/>
605 </object>
606 <bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
607 <int key="IBDocument.defaultPropertyAccessControl">3</int>
608 <object class="NSMutableDictionary" key="IBDocument.LastKnownImageSizes">
609 <bool key="EncodedWithXMLCoder">YES</bool>
610 <object class="NSArray" key="dict.sortedKeys">
611 <bool key="EncodedWithXMLCoder">YES</bool>
612 <string>NSInfo</string>
613 <string>NSSwitch</string>
614 </object>
615 <object class="NSArray" key="dict.values">
616 <bool key="EncodedWithXMLCoder">YES</bool>
617 <string>{32, 32}</string>
618 <string>{15, 15}</string>
619 </object>
620 </object>
621 </data>
622 </archive>
+0
-33
osx/RPC.h less more
0 /*
1 * This file is part of nzbget. See <http://nzbget.net>.
2 *
3 * Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #import <Cocoa/Cocoa.h>
20 #import "WebClient.h"
21
22 @interface RPC : WebClient {
23 }
24
25 - (id)initWithMethod:(NSString*)method
26 receiver:(id)receiver
27 success:(SEL)successCallback
28 failure:(SEL)failureCallback;
29
30 + (void)setRpcUrl:(NSString*)url;
31
32 @end
+0
-57
osx/RPC.m less more
0 /*
1 * This file is part of nzbget. See <http://nzbget.net>.
2 *
3 * Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #import <Cocoa/Cocoa.h>
20 #import "RPC.h"
21
22 @implementation RPC
23
24 NSString* rpcUrl;
25
26 - (id)initWithMethod:(NSString*)method
27 receiver:(id)receiver
28 success:(SEL)successCallback
29 failure:(SEL)failureCallback {
30 NSString* urlStr = [rpcUrl stringByAppendingString:method];
31 self = [super initWithURLString:urlStr receiver:receiver success:successCallback failure:failureCallback];
32 return self;
33 }
34
35 + (void)setRpcUrl:(NSString*)url {
36 rpcUrl = url;
37 }
38
39 - (void)success {
40 NSError *error = nil;
41 id dataObj = [NSJSONSerialization
42 JSONObjectWithData:data
43 options:0
44 error:&error];
45
46 if (error || ![dataObj isKindOfClass:[NSDictionary class]]) {
47 /* JSON was malformed, act appropriately here */
48 failureCode = 999;
49 [self failure];
50 }
51
52 id result = [dataObj valueForKey:@"result"];
53 SuppressPerformSelectorLeakWarning([_receiver performSelector:_successCallback withObject:result];);
54 }
55
56 @end
+0
-17
osx/Resources/Credits.rtf less more
0 {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510
1 {\fonttbl\f0\fnil\fcharset0 LucidaGrande;}
2 {\colortbl;\red255\green255\blue255;\red0\green0\blue255;}
3 \vieww10800\viewh8400\viewkind0
4 \deftab720
5 \pard\pardeftab720\sa260\qc
6
7 \f0\fs22 \cf0 Lightweight usenet downloader\
8 \pard\pardeftab720\qc
9 \cf0 NZBGet is free software; use it under the\
10 terms of the {\field{\*\fldinst{HYPERLINK "http://www.gnu.org/licenses/gpl-2.0.html"}}{\fldrslt GNU General Public License}}.\
11 \
12 The package also includes other software;\
13 see folder "licenses" inside the package.\
14 \
15 \pard\pardeftab720\qc
16 \cf2 \ul \ulc2 http://{\field{\*\fldinst{HYPERLINK "http://nzbget.net"}}{\fldrslt nzbget.net}}}
osx/Resources/Images/mainicon.icns less more
Binary diff not shown
osx/Resources/Images/statusicon.png less more
Binary diff not shown
osx/Resources/Images/statusicon@2x.png less more
Binary diff not shown
+0
-76
osx/Resources/Localizable.strings less more
0 /*
1 * This file is part of nzbget. See <http://nzbget.net>.
2 *
3 * Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 "Status.DownloadingKB"="Downloading at %i KB/s";
20 "Status.DownloadingMB"="Downloading at %1.1f MB/s";
21 "Status.DownloadingMB10"="Downloading at %i MB/s";
22 "Status.Post-Processing"="Post-Processing";
23 "Status.Fetching NZBs"="Fetching NZBs";
24 "Status.Fetching Feeds"="Fetching Feeds";
25 "Status.Paused"="Paused";
26 "Status.Idle"="Idle";
27 "Status.Left"="%@ left";
28 "Status.NoConnection"="Downloader Not Responding";
29 "Status.Restarting"="Restarting";
30 "Status.PreventSleep"="NZBGet is downloading or post-processing";
31
32 "Left.Days"="%i days";
33 "Left.Days.Hours"="%id %ih";
34 "Left.Hours"="%i hours";
35 "Left.Hours.Minutes"="%ih %02im";
36 "Left.Minutes"="%im";
37 "Left.Minutes.Seconds"="%im %02is";
38 "Left.Seconds"="%is";
39
40 "Menu.LinkHomePage"="http://nzbget.net";
41 "Menu.LinkDownloads"="http://nzbget.net/download";
42 "Menu.LinkForum"="http://nzbget.net/forum";
43
44 "ShowWebUINoConnection.MessageText"="Could not establish connection to downloader (background process).";
45 "ShowWebUINoConnection.InformativeText"="Try to restart the program via Troubleshooting-menu.";
46
47 "RestartNoConnection.MessageText"="Could not establish connection to downloader (background process).";
48 "RestartNoConnection.InformativeText"="Try to restart the program in recovery mode via Troubleshooting-menu.";
49
50 "Restarted.MessageText"="The program has been successfully restarted.";
51 "Restarted.InformativeText"="";
52 "Restarted.WebUI"="Show Web-Interface";
53 "Restarted.OK"="OK";
54
55 "RestartedRecoveryMode.MessageText"="The program has been successfully restarted and is now working on address http://127.0.0.1:6789 without password.";
56 "RestartedRecoveryMode.InformativeText"="To access the program via address, port and password defined in settings the program must be restarted in normal mode using Troubleshooting-menu. A soft-restart via web-interface is not sufficient!";
57
58 "FactoryResetted.MessageText"="The program has been reset to factory defaults.";
59 "FactoryResetted.InformativeText"="";
60
61 "FactoryReset.MessageText"="Reset to factory defaults?";
62 "FactoryReset.InformativeText"="All settings will be reset to defaults. The download queue, history, statistics, log-file, default incoming nzb-directory and default scripts-directory will be erased. ";
63 "FactoryReset.Cancel"="Cancel";
64 "FactoryReset.Reset"="Erase and Reset";
65
66 "AlreadyRunning.MessageText"="NZBGet is already running.";
67 "AlreadyRunning.InformativeTextWithIcon" = "You can control NZBGet using web-interface or icon in menubar.";
68 "AlreadyRunning.InformativeTextWithoutIcon" = "You can control NZBGet using web-interface. The icon in menubar is currently not displayed because the option 'Show in menubar' was unselected in preferences.";
69 "AlreadyRunning.Quit"="Quit NZBGet";
70 "AlreadyRunning.Preferences"="Open Preferences";
71 "AlreadyRunning.WebUI"="Show Web-Interface";
72
73 "CantShowInFinder.MessageText"="Cannot open %@.";
74 "CantShowInFinder.InformativeTextWithOption"="The path doesn't exist or refers to a volume not mounted at the moment. Check option %@.";
75 "CantShowInFinder.InformativeTextForCategory"="The path doesn't exist or refers to a volume not mounted at the moment. Please also note that destination directories for categories are created upon first use.";
+0
-23
osx/Resources/Welcome.rtf less more
0 {\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510
1 {\fonttbl\f0\fnil\fcharset0 LucidaGrande;\f1\fswiss\fcharset0 Helvetica;}
2 {\colortbl;\red255\green255\blue255;}
3 \margl1440\margr1440\vieww9000\viewh8400\viewkind0
4 \pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural
5
6 \f0\fs32 \cf0 Welcome!
7 \f1\fs24 \
8 \
9 \pard\pardeftab720\sa260
10
11 \f0\fs26 \cf0 NZBGet is a downloader from binary newsgroups. An account on a news server is needed to use this program.
12 \fs18 \
13 \pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural
14
15 \fs26 \cf0 NZBGet works as a background process and can be controlled from a web-browser. An icon in menubar gives a quick access to few important functions.
16 \fs18 \
17 \pard\pardeftab720
18
19 \fs26 \cf0 \
20 This program is free software; you can redistribute it and/or modify it under the terms of the {\field{\*\fldinst{HYPERLINK "http://www.gnu.org/licenses/gpl-2.0.html"}}{\fldrslt GNU General Public License}}.\
21 \
22 For more information visit {\field{\*\fldinst{HYPERLINK "http://nzbget.net"}}{\fldrslt NZBGet home page}}.}
+0
-176
osx/Resources/licenses/license-bootstrap.txt less more
0 Apache License
1 Version 2.0, January 2004
2 http://www.apache.org/licenses/
3
4 TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
5
6 1. Definitions.
7
8 "License" shall mean the terms and conditions for use, reproduction,
9 and distribution as defined by Sections 1 through 9 of this document.
10
11 "Licensor" shall mean the copyright owner or entity authorized by
12 the copyright owner that is granting the License.
13
14 "Legal Entity" shall mean the union of the acting entity and all
15 other entities that control, are controlled by, or are under common
16 control with that entity. For the purposes of this definition,
17 "control" means (i) the power, direct or indirect, to cause the
18 direction or management of such entity, whether by contract or
19 otherwise, or (ii) ownership of fifty percent (50%) or more of the
20 outstanding shares, or (iii) beneficial ownership of such entity.
21
22 "You" (or "Your") shall mean an individual or Legal Entity
23 exercising permissions granted by this License.
24
25 "Source" form shall mean the preferred form for making modifications,
26 including but not limited to software source code, documentation
27 source, and configuration files.
28
29 "Object" form shall mean any form resulting from mechanical
30 transformation or translation of a Source form, including but
31 not limited to compiled object code, generated documentation,
32 and conversions to other media types.
33
34 "Work" shall mean the work of authorship, whether in Source or
35 Object form, made available under the License, as indicated by a
36 copyright notice that is included in or attached to the work
37 (an example is provided in the Appendix below).
38
39 "Derivative Works" shall mean any work, whether in Source or Object
40 form, that is based on (or derived from) the Work and for which the
41 editorial revisions, annotations, elaborations, or other modifications
42 represent, as a whole, an original work of authorship. For the purposes
43 of this License, Derivative Works shall not include works that remain
44 separable from, or merely link (or bind by name) to the interfaces of,
45 the Work and Derivative Works thereof.
46
47 "Contribution" shall mean any work of authorship, including
48 the original version of the Work and any modifications or additions
49 to that Work or Derivative Works thereof, that is intentionally
50 submitted to Licensor for inclusion in the Work by the copyright owner
51 or by an individual or Legal Entity authorized to submit on behalf of
52 the copyright owner. For the purposes of this definition, "submitted"
53 means any form of electronic, verbal, or written communication sent
54 to the Licensor or its representatives, including but not limited to
55 communication on electronic mailing lists, source code control systems,
56 and issue tracking systems that are managed by, or on behalf of, the
57 Licensor for the purpose of discussing and improving the Work, but
58 excluding communication that is conspicuously marked or otherwise
59 designated in writing by the copyright owner as "Not a Contribution."
60
61 "Contributor" shall mean Licensor and any individual or Legal Entity
62 on behalf of whom a Contribution has been received by Licensor and
63 subsequently incorporated within the Work.
64
65 2. Grant of Copyright License. Subject to the terms and conditions of
66 this License, each Contributor hereby grants to You a perpetual,
67 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
68 copyright license to reproduce, prepare Derivative Works of,
69 publicly display, publicly perform, sublicense, and distribute the
70 Work and such Derivative Works in Source or Object form.
71
72 3. Grant of Patent License. Subject to the terms and conditions of
73 this License, each Contributor hereby grants to You a perpetual,
74 worldwide, non-exclusive, no-charge, royalty-free, irrevocable
75 (except as stated in this section) patent license to make, have made,
76 use, offer to sell, sell, import, and otherwise transfer the Work,
77 where such license applies only to those patent claims licensable
78 by such Contributor that are necessarily infringed by their
79 Contribution(s) alone or by combination of their Contribution(s)
80 with the Work to which such Contribution(s) was submitted. If You
81 institute patent litigation against any entity (including a
82 cross-claim or counterclaim in a lawsuit) alleging that the Work
83 or a Contribution incorporated within the Work constitutes direct
84 or contributory patent infringement, then any patent licenses
85 granted to You under this License for that Work shall terminate
86 as of the date such litigation is filed.
87
88 4. Redistribution. You may reproduce and distribute copies of the
89 Work or Derivative Works thereof in any medium, with or without
90 modifications, and in Source or Object form, provided that You
91 meet the following conditions:
92
93 (a) You must give any other recipients of the Work or
94 Derivative Works a copy of this License; and
95
96 (b) You must cause any modified files to carry prominent notices
97 stating that You changed the files; and
98
99 (c) You must retain, in the Source form of any Derivative Works
100 that You distribute, all copyright, patent, trademark, and
101 attribution notices from the Source form of the Work,
102 excluding those notices that do not pertain to any part of
103 the Derivative Works; and
104
105 (d) If the Work includes a "NOTICE" text file as part of its
106 distribution, then any Derivative Works that You distribute must
107 include a readable copy of the attribution notices contained
108 within such NOTICE file, excluding those notices that do not
109 pertain to any part of the Derivative Works, in at least one
110 of the following places: within a NOTICE text file distributed
111 as part of the Derivative Works; within the Source form or
112 documentation, if provided along with the Derivative Works; or,
113 within a display generated by the Derivative Works, if and
114 wherever such third-party notices normally appear. The contents
115 of the NOTICE file are for informational purposes only and
116 do not modify the License. You may add Your own attribution
117 notices within Derivative Works that You distribute, alongside
118 or as an addendum to the NOTICE text from the Work, provided
119 that such additional attribution notices cannot be construed
120 as modifying the License.
121
122 You may add Your own copyright statement to Your modifications and
123 may provide additional or different license terms and conditions
124 for use, reproduction, or distribution of Your modifications, or
125 for any such Derivative Works as a whole, provided Your use,
126 reproduction, and distribution of the Work otherwise complies with
127 the conditions stated in this License.
128
129 5. Submission of Contributions. Unless You explicitly state otherwise,
130 any Contribution intentionally submitted for inclusion in the Work
131 by You to the Licensor shall be under the terms and conditions of
132 this License, without any additional terms or conditions.
133 Notwithstanding the above, nothing herein shall supersede or modify
134 the terms of any separate license agreement you may have executed
135 with Licensor regarding such Contributions.
136
137 6. Trademarks. This License does not grant permission to use the trade
138 names, trademarks, service marks, or product names of the Licensor,
139 except as required for reasonable and customary use in describing the
140 origin of the Work and reproducing the content of the NOTICE file.
141
142 7. Disclaimer of Warranty. Unless required by applicable law or
143 agreed to in writing, Licensor provides the Work (and each
144 Contributor provides its Contributions) on an "AS IS" BASIS,
145 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
146 implied, including, without limitation, any warranties or conditions
147 of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
148 PARTICULAR PURPOSE. You are solely responsible for determining the
149 appropriateness of using or redistributing the Work and assume any
150 risks associated with Your exercise of permissions under this License.
151
152 8. Limitation of Liability. In no event and under no legal theory,
153 whether in tort (including negligence), contract, or otherwise,
154 unless required by applicable law (such as deliberate and grossly
155 negligent acts) or agreed to in writing, shall any Contributor be
156 liable to You for damages, including any direct, indirect, special,
157 incidental, or consequential damages of any character arising as a
158 result of this License or out of the use or inability to use the
159 Work (including but not limited to damages for loss of goodwill,
160 work stoppage, computer failure or malfunction, or any and all
161 other commercial damages or losses), even if such Contributor
162 has been advised of the possibility of such damages.
163
164 9. Accepting Warranty or Additional Liability. While redistributing
165 the Work or Derivative Works thereof, You may choose to offer,
166 and charge a fee for, acceptance of support, warranty, indemnity,
167 or other liability obligations and/or rights consistent with this
168 License. However, in accepting such obligations, You may act only
169 on Your own behalf and on Your sole responsibility, not on behalf
170 of any other Contributor, and only if You agree to indemnify,
171 defend, and hold each Contributor harmless for any liability
172 incurred by, or claims asserted against, such Contributor by reason
173 of your accepting any such warranty or additional liability.
174
175 END OF TERMS AND CONDITIONS
+0
-340
osx/Resources/licenses/license-jquery-GPL.txt less more
0 GNU GENERAL PUBLIC LICENSE
1 Version 2, June 1991
2
3 Copyright (C) 1989, 1991 Free Software Foundation, Inc.
4 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
5 Everyone is permitted to copy and distribute verbatim copies
6 of this license document, but changing it is not allowed.
7
8 Preamble
9
10 The licenses for most software are designed to take away your
11 freedom to share and change it. By contrast, the GNU General Public
12 License is intended to guarantee your freedom to share and change free
13 software--to make sure the software is free for all its users. This
14 General Public License applies to most of the Free Software
15 Foundation's software and to any other program whose authors commit to
16 using it. (Some other Free Software Foundation software is covered by
17 the GNU Library General Public License instead.) You can apply it to
18 your programs, too.
19
20 When we speak of free software, we are referring to freedom, not
21 price. Our General Public Licenses are designed to make sure that you
22 have the freedom to distribute copies of free software (and charge for
23 this service if you wish), that you receive source code or can get it
24 if you want it, that you can change the software or use pieces of it
25 in new free programs; and that you know you can do these things.
26
27 To protect your rights, we need to make restrictions that forbid
28 anyone to deny you these rights or to ask you to surrender the rights.
29 These restrictions translate to certain responsibilities for you if you
30 distribute copies of the software, or if you modify it.
31
32 For example, if you distribute copies of such a program, whether
33 gratis or for a fee, you must give the recipients all the rights that
34 you have. You must make sure that they, too, receive or can get the
35 source code. And you must show them these terms so they know their
36 rights.
37
38 We protect your rights with two steps: (1) copyright the software, and
39 (2) offer you this license which gives you legal permission to copy,
40 distribute and/or modify the software.
41
42 Also, for each author's protection and ours, we want to make certain
43 that everyone understands that there is no warranty for this free
44 software. If the software is modified by someone else and passed on, we
45 want its recipients to know that what they have is not the original, so
46 that any problems introduced by others will not reflect on the original
47 authors' reputations.
48
49 Finally, any free program is threatened constantly by software
50 patents. We wish to avoid the danger that redistributors of a free
51 program will individually obtain patent licenses, in effect making the
52 program proprietary. To prevent this, we have made it clear that any
53 patent must be licensed for everyone's free use or not licensed at all.
54
55 The precise terms and conditions for copying, distribution and
56 modification follow.
57
58 GNU GENERAL PUBLIC LICENSE
59 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
60
61 0. This License applies to any program or other work which contains
62 a notice placed by the copyright holder saying it may be distributed
63 under the terms of this General Public License. The "Program", below,
64 refers to any such program or work, and a "work based on the Program"
65 means either the Program or any derivative work under copyright law:
66 that is to say, a work containing the Program or a portion of it,
67 either verbatim or with modifications and/or translated into another
68 language. (Hereinafter, translation is included without limitation in
69 the term "modification".) Each licensee is addressed as "you".
70
71 Activities other than copying, distribution and modification are not
72 covered by this License; they are outside its scope. The act of
73 running the Program is not restricted, and the output from the Program
74 is covered only if its contents constitute a work based on the
75 Program (independent of having been made by running the Program).
76 Whether that is true depends on what the Program does.
77
78 1. You may copy and distribute verbatim copies of the Program's
79 source code as you receive it, in any medium, provided that you
80 conspicuously and appropriately publish on each copy an appropriate
81 copyright notice and disclaimer of warranty; keep intact all the
82 notices that refer to this License and to the absence of any warranty;
83 and give any other recipients of the Program a copy of this License
84 along with the Program.
85
86 You may charge a fee for the physical act of transferring a copy, and
87 you may at your option offer warranty protection in exchange for a fee.
88
89 2. You may modify your copy or copies of the Program or any portion
90 of it, thus forming a work based on the Program, and copy and
91 distribute such modifications or work under the terms of Section 1
92 above, provided that you also meet all of these conditions:
93
94 a) You must cause the modified files to carry prominent notices
95 stating that you changed the files and the date of any change.
96
97 b) You must cause any work that you distribute or publish, that in
98 whole or in part contains or is derived from the Program or any
99 part thereof, to be licensed as a whole at no charge to all third
100 parties under the terms of this License.
101
102 c) If the modified program normally reads commands interactively
103 when run, you must cause it, when started running for such
104 interactive use in the most ordinary way, to print or display an
105 announcement including an appropriate copyright notice and a
106 notice that there is no warranty (or else, saying that you provide
107 a warranty) and that users may redistribute the program under
108 these conditions, and telling the user how to view a copy of this
109 License. (Exception: if the Program itself is interactive but
110 does not normally print such an announcement, your work based on
111 the Program is not required to print an announcement.)
112
113 These requirements apply to the modified work as a whole. If
114 identifiable sections of that work are not derived from the Program,
115 and can be reasonably considered independent and separate works in
116 themselves, then this License, and its terms, do not apply to those
117 sections when you distribute them as separate works. But when you
118 distribute the same sections as part of a whole which is a work based
119 on the Program, the distribution of the whole must be on the terms of
120 this License, whose permissions for other licensees extend to the
121 entire whole, and thus to each and every part regardless of who wrote it.
122
123 Thus, it is not the intent of this section to claim rights or contest
124 your rights to work written entirely by you; rather, the intent is to
125 exercise the right to control the distribution of derivative or
126 collective works based on the Program.
127
128 In addition, mere aggregation of another work not based on the Program
129 with the Program (or with a work based on the Program) on a volume of
130 a storage or distribution medium does not bring the other work under
131 the scope of this License.
132
133 3. You may copy and distribute the Program (or a work based on it,
134 under Section 2) in object code or executable form under the terms of
135 Sections 1 and 2 above provided that you also do one of the following:
136
137 a) Accompany it with the complete corresponding machine-readable
138 source code, which must be distributed under the terms of Sections
139 1 and 2 above on a medium customarily used for software interchange; or,
140
141 b) Accompany it with a written offer, valid for at least three
142 years, to give any third party, for a charge no more than your
143 cost of physically performing source distribution, a complete
144 machine-readable copy of the corresponding source code, to be
145 distributed under the terms of Sections 1 and 2 above on a medium
146 customarily used for software interchange; or,
147
148 c) Accompany it with the information you received as to the offer
149 to distribute corresponding source code. (This alternative is
150 allowed only for noncommercial distribution and only if you
151 received the program in object code or executable form with such
152 an offer, in accord with Subsection b above.)
153
154 The source code for a work means the preferred form of the work for
155 making modifications to it. For an executable work, complete source
156 code means all the source code for all modules it contains, plus any
157 associated interface definition files, plus the scripts used to
158 control compilation and installation of the executable. However, as a
159 special exception, the source code distributed need not include
160 anything that is normally distributed (in either source or binary
161 form) with the major components (compiler, kernel, and so on) of the
162 operating system on which the executable runs, unless that component
163 itself accompanies the executable.
164
165 If distribution of executable or object code is made by offering
166 access to copy from a designated place, then offering equivalent
167 access to copy the source code from the same place counts as
168 distribution of the source code, even though third parties are not
169 compelled to copy the source along with the object code.
170
171 4. You may not copy, modify, sublicense, or distribute the Program
172 except as expressly provided under this License. Any attempt
173 otherwise to copy, modify, sublicense or distribute the Program is
174 void, and will automatically terminate your rights under this License.
175 However, parties who have received copies, or rights, from you under
176 this License will not have their licenses terminated so long as such
177 parties remain in full compliance.
178
179 5. You are not required to accept this License, since you have not
180 signed it. However, nothing else grants you permission to modify or
181 distribute the Program or its derivative works. These actions are
182 prohibited by law if you do not accept this License. Therefore, by
183 modifying or distributing the Program (or any work based on the
184 Program), you indicate your acceptance of this License to do so, and
185 all its terms and conditions for copying, distributing or modifying
186 the Program or works based on it.
187
188 6. Each time you redistribute the Program (or any work based on the
189 Program), the recipient automatically receives a license from the
190 original licensor to copy, distribute or modify the Program subject to
191 these terms and conditions. You may not impose any further
192 restrictions on the recipients' exercise of the rights granted herein.
193 You are not responsible for enforcing compliance by third parties to
194 this License.
195
196 7. If, as a consequence of a court judgment or allegation of patent
197 infringement or for any other reason (not limited to patent issues),
198 conditions are imposed on you (whether by court order, agreement or
199 otherwise) that contradict the conditions of this License, they do not
200 excuse you from the conditions of this License. If you cannot
201 distribute so as to satisfy simultaneously your obligations under this
202 License and any other pertinent obligations, then as a consequence you
203 may not distribute the Program at all. For example, if a patent
204 license would not permit royalty-free redistribution of the Program by
205 all those who receive copies directly or indirectly through you, then
206 the only way you could satisfy both it and this License would be to
207 refrain entirely from distribution of the Program.
208
209 If any portion of this section is held invalid or unenforceable under
210 any particular circumstance, the balance of the section is intended to
211 apply and the section as a whole is intended to apply in other
212 circumstances.
213
214 It is not the purpose of this section to induce you to infringe any
215 patents or other property right claims or to contest validity of any
216 such claims; this section has the sole purpose of protecting the
217 integrity of the free software distribution system, which is
218 implemented by public license practices. Many people have made
219 generous contributions to the wide range of software distributed
220 through that system in reliance on consistent application of that
221 system; it is up to the author/donor to decide if he or she is willing
222 to distribute software through any other system and a licensee cannot
223 impose that choice.
224
225 This section is intended to make thoroughly clear what is believed to
226 be a consequence of the rest of this License.
227
228 8. If the distribution and/or use of the Program is restricted in
229 certain countries either by patents or by copyrighted interfaces, the
230 original copyright holder who places the Program under this License
231 may add an explicit geographical distribution limitation excluding
232 those countries, so that distribution is permitted only in or among
233 countries not thus excluded. In such case, this License incorporates
234 the limitation as if written in the body of this License.
235
236 9. The Free Software Foundation may publish revised and/or new versions
237 of the General Public License from time to time. Such new versions will
238 be similar in spirit to the present version, but may differ in detail to
239 address new problems or concerns.
240
241 Each version is given a distinguishing version number. If the Program
242 specifies a version number of this License which applies to it and "any
243 later version", you have the option of following the terms and conditions
244 either of that version or of any later version published by the Free
245 Software Foundation. If the Program does not specify a version number of
246 this License, you may choose any version ever published by the Free Software
247 Foundation.
248
249 10. If you wish to incorporate parts of the Program into other free
250 programs whose distribution conditions are different, write to the author
251 to ask for permission. For software which is copyrighted by the Free
252 Software Foundation, write to the Free Software Foundation; we sometimes
253 make exceptions for this. Our decision will be guided by the two goals
254 of preserving the free status of all derivatives of our free software and
255 of promoting the sharing and reuse of software generally.
256
257 NO WARRANTY
258
259 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
260 FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
261 OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
262 PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
263 OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
264 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
265 TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
266 PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
267 REPAIR OR CORRECTION.
268
269 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
270 WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
271 REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
272 INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
273 OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
274 TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
275 YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
276 PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
277 POSSIBILITY OF SUCH DAMAGES.
278
279 END OF TERMS AND CONDITIONS
280
281 How to Apply These Terms to Your New Programs
282
283 If you develop a new program, and you want it to be of the greatest
284 possible use to the public, the best way to achieve this is to make it
285 free software which everyone can redistribute and change under these terms.
286
287 To do so, attach the following notices to the program. It is safest
288 to attach them to the start of each source file to most effectively
289 convey the exclusion of warranty; and each file should have at least
290 the "copyright" line and a pointer to where the full notice is found.
291
292 <one line to give the program's name and a brief idea of what it does.>
293 Copyright (C) <year> <name of author>
294
295 This program is free software; you can redistribute it and/or modify
296 it under the terms of the GNU General Public License as published by
297 the Free Software Foundation; either version 2 of the License, or
298 (at your option) any later version.
299
300 This program is distributed in the hope that it will be useful,
301 but WITHOUT ANY WARRANTY; without even the implied warranty of
302 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
303 GNU General Public License for more details.
304
305 You should have received a copy of the GNU General Public License
306 along with this program; if not, write to the Free Software
307 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
308
309
310 Also add information on how to contact you by electronic and paper mail.
311
312 If the program is interactive, make it output a short notice like this
313 when it starts in an interactive mode:
314
315 Gnomovision version 69, Copyright (C) year name of author
316 Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 This is free software, and you are welcome to redistribute it
318 under certain conditions; type `show c' for details.
319
320 The hypothetical commands `show w' and `show c' should show the appropriate
321 parts of the General Public License. Of course, the commands you use may
322 be called something other than `show w' and `show c'; they could even be
323 mouse-clicks or menu items--whatever suits your program.
324
325 You should also get your employer (if you work as a programmer) or your
326 school, if any, to sign a "copyright disclaimer" for the program, if
327 necessary. Here is a sample; alter the names:
328
329 Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 `Gnomovision' (which makes passes at compilers) written by James Hacker.
331
332 <signature of Ty Coon>, 1 April 1989
333 Ty Coon, President of Vice
334
335 This General Public License does not permit incorporating your program into
336 proprietary programs. If your program is a subroutine library, you may
337 consider it more useful to permit linking proprietary applications with the
338 library. If this is what you want to do, use the GNU Library General
339 Public License instead of this License.
+0
-21
osx/Resources/licenses/license-jquery-MIT.txt less more
0 Copyright 2013 jQuery Foundation and other contributors
1 http://jquery.com/
2
3 Permission is hereby granted, free of charge, to any person obtaining
4 a copy of this software and associated documentation files (the
5 "Software"), to deal in the Software without restriction, including
6 without limitation the rights to use, copy, modify, merge, publish,
7 distribute, sublicense, and/or sell copies of the Software, and to
8 permit persons to whom the Software is furnished to do so, subject to
9 the following conditions:
10
11 The above copyright notice and this permission notice shall be
12 included in all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+0
-43
osx/WebClient.h less more
0 /*
1 * This file is part of nzbget. See <http://nzbget.net>.
2 *
3 * Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #import <Cocoa/Cocoa.h>
20
21 @interface WebClient : NSObject {
22 id _receiver;
23 SEL _successCallback;
24 SEL _failureCallback;
25 NSURLConnection *connection;
26 NSMutableData *data;
27 NSInteger failureCode;
28 NSDictionary *responseHeaderFields;
29 }
30
31 - (id)initWithURLString:(NSString*)urlStr
32 receiver:(id)receiver
33 success:(SEL)successCallback
34 failure:(SEL)failureCallback;
35
36 - (void)start;
37
38 - (void)success;
39
40 - (void)failure;
41
42 @end
+0
-92
osx/WebClient.m less more
0 /*
1 * This file is part of nzbget. See <http://nzbget.net>.
2 *
3 * Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #import <Cocoa/Cocoa.h>
20 #import "WebClient.h"
21
22 @implementation WebClient
23
24 - (id)initWithURLString:(NSString*)urlStr
25 receiver:(id)receiver
26 success:(SEL)successCallback
27 failure:(SEL)failureCallback {
28 self = [super init];
29
30 _receiver = receiver;
31 _successCallback = successCallback;
32 _failureCallback = failureCallback;
33 NSURL *url = [NSURL URLWithString:urlStr];
34 NSURLRequest *request = [NSURLRequest requestWithURL:url];
35 connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
36 [connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
37
38 return self;
39 }
40
41 - (void) start {
42 [connection start];
43 }
44
45 - (void)connection:(NSURLConnection *)aConnection didReceiveResponse:(NSHTTPURLResponse *)aResponse {
46 responseHeaderFields = [aResponse allHeaderFields];
47
48 if ([aResponse statusCode] != 200)
49 {
50 failureCode = [aResponse statusCode];
51 [connection cancel];
52 [self failure];
53 return;
54 }
55
56 NSInteger contentLength = [[responseHeaderFields objectForKey:@"Content-Length"] integerValue];
57 if (contentLength > 0) {
58 data = [[NSMutableData alloc] initWithCapacity:contentLength];
59 } else {
60 data = [[NSMutableData alloc] init];
61 }
62 }
63
64 - (void)connection:(NSURLConnection *)aConnection didReceiveData:(NSData *)newData {
65 [data appendData:newData];
66 }
67
68 - (void)connectionDidFinishLoading:(NSURLConnection *)aConnection {
69 [connection cancel];
70 [self success];
71 }
72
73 - (void)connection:(NSURLConnection *)aConnection didFailWithError:(NSError *)error {
74 if ([[error domain] isEqual:NSURLErrorDomain])
75 {
76 failureCode = [error code];
77 }
78
79 [connection cancel];
80 [self failure];
81 }
82
83 - (void)success {
84 SuppressPerformSelectorLeakWarning([_receiver performSelector:_successCallback withObject:data];);
85 }
86
87 - (void)failure {
88 SuppressPerformSelectorLeakWarning([_receiver performSelector:_failureCallback];);
89 }
90
91 @end
+0
-38
osx/WelcomeDialog.h less more
0 /*
1 * This file is part of nzbget. See <http://nzbget.net>.
2 *
3 * Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #import <Cocoa/Cocoa.h>
20
21 @interface WelcomeDialog : NSWindowController {
22 IBOutlet NSButton *_okButton;
23 IBOutlet NSButton *_dontShowAgainButton;
24 IBOutlet NSImageView *_badgeView;
25 IBOutlet NSImageView * _imageView;
26 IBOutlet NSScrollView * _messageTextScrollView;
27 IBOutlet NSTextView * _messageText;
28 id _mainDelegate;
29 }
30
31 - (void)setMainDelegate:(id)mainDelegate;
32
33 - (IBAction)okButtonPressed:(id)sender;
34
35 - (void)showDialog;
36
37 @end
+0
-80
osx/WelcomeDialog.m less more
0 /*
1 * This file is part of nzbget. See <http://nzbget.net>.
2 *
3 * Copyright (C) 2007-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #import "WelcomeDialog.h"
20
21 @implementation WelcomeDialog
22
23 - (id)init {
24 self = [super initWithWindowNibName:@"WelcomeDialog"];
25 return self;
26 }
27
28 - (void)setMainDelegate:(id)mainDelegate{
29 _mainDelegate = mainDelegate;
30 }
31
32 - (void)showDialog {
33 BOOL doNotShowWelcomeDialog = [[NSUserDefaults standardUserDefaults] boolForKey:@"DoNotShowWelcomeDialog"];
34 if (doNotShowWelcomeDialog) {
35 [_mainDelegate performSelector:@selector(welcomeContinue)];
36 return;
37 }
38
39 DLog(@"creating window");
40 NSWindow *window = [self window];
41 DLog(@"creating window - END");
42
43 // set file icon
44 NSImage *image = [NSImage imageNamed:@"mainicon.icns"];
45 [_imageView setImage:image];
46
47 // load warning icon
48 [_badgeView setImage:[[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kAlertNoteIcon)]];
49
50 [[_messageText textStorage] readFromURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"Welcome" ofType:@"rtf"]] options:nil documentAttributes:nil];
51
52 // adjust height of text control and window
53 [[_messageText layoutManager] ensureLayoutForTextContainer:[_messageText textContainer]];
54
55 NSSize scrollSize = [_messageTextScrollView frame].size;
56 float deltaHeight = [_messageText frame].size.height - scrollSize.height + 6;
57 if (deltaHeight < 0) {
58 deltaHeight = 0;
59 }
60
61 NSSize winSize = [[window contentView] frame ].size;
62 winSize.height += deltaHeight;
63 [window setContentSize:winSize];
64
65 // set active control
66 [window makeFirstResponder:_okButton];
67
68 // show modal dialog
69 [NSApp activateIgnoringOtherApps:TRUE];
70 [window center];
71 [self showWindow:nil];
72 }
73
74 - (IBAction)okButtonPressed:(id)sender {
75 [self close];
76 [_mainDelegate performSelector:@selector(welcomeContinue)];
77 }
78
79 @end
+0
-599
osx/WelcomeDialog.xib less more
0 <?xml version="1.0" encoding="UTF-8"?>
1 <archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="8.00">
2 <data>
3 <int key="IBDocument.SystemTarget">1060</int>
4 <string key="IBDocument.SystemVersion">11G63</string>
5 <string key="IBDocument.InterfaceBuilderVersion">3084</string>
6 <string key="IBDocument.AppKitVersion">1138.51</string>
7 <string key="IBDocument.HIToolboxVersion">569.00</string>
8 <object class="NSMutableDictionary" key="IBDocument.PluginVersions">
9 <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
10 <string key="NS.object.0">3084</string>
11 </object>
12 <array key="IBDocument.IntegratedClassDependencies">
13 <string>NSButton</string>
14 <string>NSButtonCell</string>
15 <string>NSCustomObject</string>
16 <string>NSImageCell</string>
17 <string>NSImageView</string>
18 <string>NSScrollView</string>
19 <string>NSScroller</string>
20 <string>NSTextView</string>
21 <string>NSUserDefaultsController</string>
22 <string>NSView</string>
23 <string>NSWindowTemplate</string>
24 </array>
25 <array key="IBDocument.PluginDependencies">
26 <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
27 </array>
28 <object class="NSMutableDictionary" key="IBDocument.Metadata">
29 <string key="NS.key.0">PluginDependencyRecalculationVersion</string>
30 <integer value="1" key="NS.object.0"/>
31 </object>
32 <array class="NSMutableArray" key="IBDocument.RootObjects" id="388536329">
33 <object class="NSCustomObject" id="994796463">
34 <string key="NSClassName">WelcomeDialog</string>
35 </object>
36 <object class="NSCustomObject" id="849836966">
37 <string key="NSClassName">FirstResponder</string>
38 </object>
39 <object class="NSCustomObject" id="678532319">
40 <string key="NSClassName">NSApplication</string>
41 </object>
42 <object class="NSUserDefaultsController" id="149727877">
43 <bool key="NSSharedInstance">YES</bool>
44 </object>
45 <object class="NSWindowTemplate" id="741728999">
46 <int key="NSWindowStyleMask">1</int>
47 <int key="NSWindowBacking">2</int>
48 <string key="NSWindowRect">{{196, 240}, {497, 136}}</string>
49 <int key="NSWTFlags">611844096</int>
50 <string key="NSWindowTitle">NZBGet</string>
51 <string key="NSWindowClass">NSWindow</string>
52 <nil key="NSViewClass"/>
53 <nil key="NSUserInterfaceItemIdentifier"/>
54 <object class="NSView" key="NSWindowView" id="149501230">
55 <reference key="NSNextResponder"/>
56 <int key="NSvFlags">256</int>
57 <array class="NSMutableArray" key="NSSubviews">
58 <object class="NSImageView" id="878938783">
59 <reference key="NSNextResponder" ref="149501230"/>
60 <int key="NSvFlags">268</int>
61 <set class="NSMutableSet" key="NSDragTypes">
62 <string>Apple PDF pasteboard type</string>
63 <string>Apple PICT pasteboard type</string>
64 <string>Apple PNG pasteboard type</string>
65 <string>NSFilenamesPboardType</string>
66 <string>NeXT Encapsulated PostScript v1.2 pasteboard type</string>
67 <string>NeXT TIFF v4.0 pasteboard type</string>
68 </set>
69 <string key="NSFrame">{{20, 52}, {64, 64}}</string>
70 <reference key="NSSuperview" ref="149501230"/>
71 <reference key="NSNextKeyView" ref="447421602"/>
72 <int key="NSViewLayerContentsRedrawPolicy">2</int>
73 <bool key="NSEnabled">YES</bool>
74 <object class="NSImageCell" key="NSCell" id="807890907">
75 <int key="NSCellFlags">134348288</int>
76 <int key="NSCellFlags2">33554432</int>
77 <object class="NSCustomResource" key="NSContents" id="438165365">
78 <string key="NSClassName">NSImage</string>
79 <string key="NSResourceName">NSInfo</string>
80 </object>
81 <int key="NSAlign">0</int>
82 <int key="NSScale">3</int>
83 <int key="NSStyle">0</int>
84 <bool key="NSAnimates">NO</bool>
85 </object>
86 <bool key="NSEditable">YES</bool>
87 </object>
88 <object class="NSImageView" id="447421602">
89 <reference key="NSNextResponder" ref="149501230"/>
90 <int key="NSvFlags">-2147483380</int>
91 <set class="NSMutableSet" key="NSDragTypes">
92 <string>Apple PDF pasteboard type</string>
93 <string>Apple PICT pasteboard type</string>
94 <string>Apple PNG pasteboard type</string>
95 <string>NSFilenamesPboardType</string>
96 <string>NeXT Encapsulated PostScript v1.2 pasteboard type</string>
97 <string>NeXT TIFF v4.0 pasteboard type</string>
98 </set>
99 <string key="NSFrame">{{60, 60}, {16, 16}}</string>
100 <reference key="NSSuperview" ref="149501230"/>
101 <reference key="NSNextKeyView" ref="578681479"/>
102 <int key="NSViewLayerContentsRedrawPolicy">2</int>
103 <bool key="NSEnabled">YES</bool>
104 <object class="NSImageCell" key="NSCell" id="592350070">
105 <int key="NSCellFlags">134348288</int>
106 <int key="NSCellFlags2">33554432</int>
107 <reference key="NSContents" ref="438165365"/>
108 <int key="NSAlign">0</int>
109 <int key="NSScale">3</int>
110 <int key="NSStyle">0</int>
111 <bool key="NSAnimates">NO</bool>
112 </object>
113 <bool key="NSEditable">YES</bool>
114 </object>
115 <object class="NSButton" id="636314400">
116 <reference key="NSNextResponder" ref="149501230"/>
117 <int key="NSvFlags">292</int>
118 <string key="NSFrame">{{17, 18}, {153, 18}}</string>
119 <reference key="NSSuperview" ref="149501230"/>
120 <reference key="NSNextKeyView" ref="591072398"/>
121 <int key="NSViewLayerContentsRedrawPolicy">2</int>
122 <bool key="NSEnabled">YES</bool>
123 <object class="NSButtonCell" key="NSCell" id="805293456">
124 <int key="NSCellFlags">67239424</int>
125 <int key="NSCellFlags2">131072</int>
126 <string key="NSContents">Don't show again</string>
127 <object class="NSFont" key="NSSupport">
128 <string key="NSName">LucidaGrande</string>
129 <double key="NSSize">11</double>
130 <int key="NSfFlags">16</int>
131 </object>
132 <reference key="NSControlView" ref="636314400"/>
133 <int key="NSButtonFlags">1211912703</int>
134 <int key="NSButtonFlags2">2</int>
135 <object class="NSCustomResource" key="NSNormalImage">
136 <string key="NSClassName">NSImage</string>
137 <string key="NSResourceName">NSSwitch</string>
138 </object>
139 <object class="NSButtonImageSource" key="NSAlternateImage">
140 <string key="NSImageName">NSSwitch</string>
141 </object>
142 <string key="NSAlternateContents"/>
143 <string key="NSKeyEquivalent"/>
144 <int key="NSPeriodicDelay">200</int>
145 <int key="NSPeriodicInterval">25</int>
146 </object>
147 </object>
148 <object class="NSButton" id="591072398">
149 <reference key="NSNextResponder" ref="149501230"/>
150 <int key="NSvFlags">289</int>
151 <string key="NSFrame">{{387, 12}, {97, 32}}</string>
152 <reference key="NSSuperview" ref="149501230"/>
153 <int key="NSViewLayerContentsRedrawPolicy">2</int>
154 <bool key="NSEnabled">YES</bool>
155 <object class="NSButtonCell" key="NSCell" id="905061247">
156 <int key="NSCellFlags">67239424</int>
157 <int key="NSCellFlags2">134217728</int>
158 <string key="NSContents">Continue</string>
159 <object class="NSFont" key="NSSupport">
160 <string key="NSName">LucidaGrande</string>
161 <double key="NSSize">13</double>
162 <int key="NSfFlags">1044</int>
163 </object>
164 <reference key="NSControlView" ref="591072398"/>
165 <int key="NSButtonFlags">-2038284033</int>
166 <int key="NSButtonFlags2">129</int>
167 <string key="NSAlternateContents"/>
168 <string type="base64-UTF8" key="NSKeyEquivalent">DQ</string>
169 <int key="NSPeriodicDelay">200</int>
170 <int key="NSPeriodicInterval">25</int>
171 </object>
172 </object>
173 <object class="NSScrollView" id="578681479">
174 <reference key="NSNextResponder" ref="149501230"/>
175 <int key="NSvFlags">274</int>
176 <array class="NSMutableArray" key="NSSubviews">
177 <object class="NSClipView" id="724600643">
178 <reference key="NSNextResponder" ref="578681479"/>
179 <int key="NSvFlags">2304</int>
180 <array class="NSMutableArray" key="NSSubviews">
181 <object class="NSTextView" id="179401146">
182 <reference key="NSNextResponder" ref="724600643"/>
183 <int key="NSvFlags">2322</int>
184 <string key="NSFrameSize">{375, 36}</string>
185 <reference key="NSSuperview" ref="724600643"/>
186 <reference key="NSNextKeyView" ref="636314400"/>
187 <object class="NSTextContainer" key="NSTextContainer" id="512008014">
188 <object class="NSLayoutManager" key="NSLayoutManager">
189 <object class="NSTextStorage" key="NSTextStorage">
190 <object class="NSMutableString" key="NSString">
191 <characters key="NS.bytes"/>
192 </object>
193 <nil key="NSDelegate"/>
194 </object>
195 <array class="NSMutableArray" key="NSTextContainers">
196 <reference ref="512008014"/>
197 </array>
198 <int key="NSLMFlags">134</int>
199 <nil key="NSDelegate"/>
200 </object>
201 <reference key="NSTextView" ref="179401146"/>
202 <double key="NSWidth">375</double>
203 <int key="NSTCFlags">1</int>
204 </object>
205 <object class="NSTextViewSharedData" key="NSSharedData">
206 <int key="NSFlags">67119717</int>
207 <int key="NSTextCheckingTypes">0</int>
208 <nil key="NSMarkedAttributes"/>
209 <object class="NSColor" key="NSBackgroundColor" id="711870198">
210 <int key="NSColorSpace">3</int>
211 <bytes key="NSWhite">MQA</bytes>
212 </object>
213 <dictionary key="NSSelectedAttributes">
214 <object class="NSColor" key="NSBackgroundColor">
215 <int key="NSColorSpace">6</int>
216 <string key="NSCatalogName">System</string>
217 <string key="NSColorName">selectedTextBackgroundColor</string>
218 <object class="NSColor" key="NSColor">
219 <int key="NSColorSpace">3</int>
220 <bytes key="NSWhite">MC42NjY2NjY2NjY3AA</bytes>
221 </object>
222 </object>
223 <object class="NSColor" key="NSColor">
224 <int key="NSColorSpace">6</int>
225 <string key="NSCatalogName">System</string>
226 <string key="NSColorName">selectedTextColor</string>
227 <object class="NSColor" key="NSColor" id="144811132">
228 <int key="NSColorSpace">3</int>
229 <bytes key="NSWhite">MAA</bytes>
230 </object>
231 </object>
232 </dictionary>
233 <reference key="NSInsertionColor" ref="144811132"/>
234 <dictionary key="NSLinkAttributes">
235 <object class="NSColor" key="NSColor">
236 <int key="NSColorSpace">1</int>
237 <bytes key="NSRGB">MCAwIDEAA</bytes>
238 </object>
239 <object class="NSCursor" key="NSCursor">
240 <string key="NSHotSpot">{8, -8}</string>
241 <int key="NSCursorType">13</int>
242 </object>
243 <integer value="1" key="NSUnderline"/>
244 </dictionary>
245 <nil key="NSDefaultParagraphStyle"/>
246 <nil key="NSTextFinder"/>
247 <int key="NSPreferredTextFinderStyle">1</int>
248 </object>
249 <int key="NSTVFlags">6</int>
250 <string key="NSMaxSize">{463, 10000000}</string>
251 <string key="NSMinize">{223, 36}</string>
252 <nil key="NSDelegate"/>
253 </object>
254 </array>
255 <string key="NSFrameSize">{375, 64}</string>
256 <reference key="NSSuperview" ref="578681479"/>
257 <reference key="NSNextKeyView" ref="179401146"/>
258 <reference key="NSDocView" ref="179401146"/>
259 <reference key="NSBGColor" ref="711870198"/>
260 <object class="NSCursor" key="NSCursor">
261 <string key="NSHotSpot">{4, 5}</string>
262 <object class="NSImage" key="NSImage">
263 <int key="NSImageFlags">79691776</int>
264 <array key="NSReps">
265 <array>
266 <integer value="5"/>
267 <object class="NSURL">
268 <nil key="NS.base"/>
269 <string key="NS.relative">file://localhost/Applications/Xcode.app/Contents/SharedFrameworks/DVTKit.framework/Resources/DVTIbeamCursor.tiff</string>
270 </object>
271 </array>
272 </array>
273 <object class="NSColor" key="NSColor">
274 <int key="NSColorSpace">3</int>
275 <bytes key="NSWhite">MCAwAA</bytes>
276 </object>
277 </object>
278 </object>
279 <int key="NScvFlags">2</int>
280 </object>
281 <object class="NSScroller" id="453040178">
282 <reference key="NSNextResponder" ref="578681479"/>
283 <int key="NSvFlags">-2147483392</int>
284 <string key="NSFrame">{{-100, -100}, {15, 62}}</string>
285 <reference key="NSSuperview" ref="578681479"/>
286 <reference key="NSNextKeyView" ref="995383783"/>
287 <reference key="NSTarget" ref="578681479"/>
288 <string key="NSAction">_doScroller:</string>
289 <double key="NSCurValue">1</double>
290 <double key="NSPercent">0.85256409645080566</double>
291 </object>
292 <object class="NSScroller" id="995383783">
293 <reference key="NSNextResponder" ref="578681479"/>
294 <int key="NSvFlags">-2147483392</int>
295 <string key="NSFrame">{{-100, -100}, {87, 18}}</string>
296 <reference key="NSSuperview" ref="578681479"/>
297 <reference key="NSNextKeyView" ref="724600643"/>
298 <int key="NSsFlags">1</int>
299 <reference key="NSTarget" ref="578681479"/>
300 <string key="NSAction">_doScroller:</string>
301 <double key="NSCurValue">1</double>
302 <double key="NSPercent">0.94565218687057495</double>
303 </object>
304 </array>
305 <string key="NSFrame">{{102, 52}, {375, 64}}</string>
306 <reference key="NSSuperview" ref="149501230"/>
307 <reference key="NSNextKeyView" ref="453040178"/>
308 <int key="NSsFlags">133120</int>
309 <reference key="NSVScroller" ref="453040178"/>
310 <reference key="NSHScroller" ref="995383783"/>
311 <reference key="NSContentView" ref="724600643"/>
312 </object>
313 </array>
314 <string key="NSFrameSize">{497, 136}</string>
315 <reference key="NSSuperview"/>
316 <reference key="NSNextKeyView" ref="878938783"/>
317 </object>
318 <string key="NSScreenRect">{{0, 0}, {1440, 878}}</string>
319 <string key="NSMaxSize">{10000000000000, 10000000000000}</string>
320 <string key="NSFrameAutosaveName">WelcomeDIalog</string>
321 <bool key="NSWindowIsRestorable">YES</bool>
322 </object>
323 </array>
324 <object class="IBObjectContainer" key="IBDocument.Objects">
325 <array class="NSMutableArray" key="connectionRecords">
326 <object class="IBConnectionRecord">
327 <object class="IBActionConnection" key="connection">
328 <string key="label">okButtonPressed:</string>
329 <reference key="source" ref="994796463"/>
330 <reference key="destination" ref="591072398"/>
331 </object>
332 <int key="connectionID">428</int>
333 </object>
334 <object class="IBConnectionRecord">
335 <object class="IBOutletConnection" key="connection">
336 <string key="label">_badgeView</string>
337 <reference key="source" ref="994796463"/>
338 <reference key="destination" ref="447421602"/>
339 </object>
340 <int key="connectionID">441</int>
341 </object>
342 <object class="IBConnectionRecord">
343 <object class="IBOutletConnection" key="connection">
344 <string key="label">_imageView</string>
345 <reference key="source" ref="994796463"/>
346 <reference key="destination" ref="878938783"/>
347 </object>
348 <int key="connectionID">442</int>
349 </object>
350 <object class="IBConnectionRecord">
351 <object class="IBOutletConnection" key="connection">
352 <string key="label">_okButton</string>
353 <reference key="source" ref="994796463"/>
354 <reference key="destination" ref="591072398"/>
355 </object>
356 <int key="connectionID">443</int>
357 </object>
358 <object class="IBConnectionRecord">
359 <object class="IBOutletConnection" key="connection">
360 <string key="label">window</string>
361 <reference key="source" ref="994796463"/>
362 <reference key="destination" ref="741728999"/>
363 </object>
364 <int key="connectionID">445</int>
365 </object>
366 <object class="IBConnectionRecord">
367 <object class="IBOutletConnection" key="connection">
368 <string key="label">_dontShowAgainButton</string>
369 <reference key="source" ref="994796463"/>
370 <reference key="destination" ref="636314400"/>
371 </object>
372 <int key="connectionID">449</int>
373 </object>
374 <object class="IBConnectionRecord">
375 <object class="IBOutletConnection" key="connection">
376 <string key="label">_messageText</string>
377 <reference key="source" ref="994796463"/>
378 <reference key="destination" ref="179401146"/>
379 </object>
380 <int key="connectionID">454</int>
381 </object>
382 <object class="IBConnectionRecord">
383 <object class="IBOutletConnection" key="connection">
384 <string key="label">_messageTextScrollView</string>
385 <reference key="source" ref="994796463"/>
386 <reference key="destination" ref="578681479"/>
387 </object>
388 <int key="connectionID">455</int>
389 </object>
390 <object class="IBConnectionRecord">
391 <object class="IBBindingConnection" key="connection">
392 <string key="label">value: values.DoNotShowWelcomeDialog</string>
393 <reference key="source" ref="636314400"/>
394 <reference key="destination" ref="149727877"/>
395 <object class="NSNibBindingConnector" key="connector">
396 <reference key="NSSource" ref="636314400"/>
397 <reference key="NSDestination" ref="149727877"/>
398 <string key="NSLabel">value: values.DoNotShowWelcomeDialog</string>
399 <string key="NSBinding">value</string>
400 <string key="NSKeyPath">values.DoNotShowWelcomeDialog</string>
401 <int key="NSNibBindingConnectorVersion">2</int>
402 </object>
403 </object>
404 <int key="connectionID">424</int>
405 </object>
406 </array>
407 <object class="IBMutableOrderedSet" key="objectRecords">
408 <array key="orderedObjects">
409 <object class="IBObjectRecord">
410 <int key="objectID">0</int>
411 <array key="object" id="0"/>
412 <reference key="children" ref="388536329"/>
413 <nil key="parent"/>
414 </object>
415 <object class="IBObjectRecord">
416 <int key="objectID">-2</int>
417 <reference key="object" ref="994796463"/>
418 <reference key="parent" ref="0"/>
419 <string key="objectName">File's Owner</string>
420 </object>
421 <object class="IBObjectRecord">
422 <int key="objectID">-1</int>
423 <reference key="object" ref="849836966"/>
424 <reference key="parent" ref="0"/>
425 <string key="objectName">First Responder</string>
426 </object>
427 <object class="IBObjectRecord">
428 <int key="objectID">-3</int>
429 <reference key="object" ref="678532319"/>
430 <reference key="parent" ref="0"/>
431 <string key="objectName">Application</string>
432 </object>
433 <object class="IBObjectRecord">
434 <int key="objectID">356</int>
435 <reference key="object" ref="149727877"/>
436 <reference key="parent" ref="0"/>
437 </object>
438 <object class="IBObjectRecord">
439 <int key="objectID">383</int>
440 <reference key="object" ref="741728999"/>
441 <array class="NSMutableArray" key="children">
442 <reference ref="149501230"/>
443 </array>
444 <reference key="parent" ref="0"/>
445 </object>
446 <object class="IBObjectRecord">
447 <int key="objectID">384</int>
448 <reference key="object" ref="149501230"/>
449 <array class="NSMutableArray" key="children">
450 <reference ref="447421602"/>
451 <reference ref="878938783"/>
452 <reference ref="591072398"/>
453 <reference ref="636314400"/>
454 <reference ref="578681479"/>
455 </array>
456 <reference key="parent" ref="741728999"/>
457 </object>
458 <object class="IBObjectRecord">
459 <int key="objectID">387</int>
460 <reference key="object" ref="878938783"/>
461 <array class="NSMutableArray" key="children">
462 <reference ref="807890907"/>
463 </array>
464 <reference key="parent" ref="149501230"/>
465 </object>
466 <object class="IBObjectRecord">
467 <int key="objectID">388</int>
468 <reference key="object" ref="447421602"/>
469 <array class="NSMutableArray" key="children">
470 <reference ref="592350070"/>
471 </array>
472 <reference key="parent" ref="149501230"/>
473 </object>
474 <object class="IBObjectRecord">
475 <int key="objectID">397</int>
476 <reference key="object" ref="592350070"/>
477 <reference key="parent" ref="447421602"/>
478 </object>
479 <object class="IBObjectRecord">
480 <int key="objectID">398</int>
481 <reference key="object" ref="807890907"/>
482 <reference key="parent" ref="878938783"/>
483 </object>
484 <object class="IBObjectRecord">
485 <int key="objectID">417</int>
486 <reference key="object" ref="636314400"/>
487 <array class="NSMutableArray" key="children">
488 <reference ref="805293456"/>
489 </array>
490 <reference key="parent" ref="149501230"/>
491 </object>
492 <object class="IBObjectRecord">
493 <int key="objectID">418</int>
494 <reference key="object" ref="805293456"/>
495 <reference key="parent" ref="636314400"/>
496 </object>
497 <object class="IBObjectRecord">
498 <int key="objectID">426</int>
499 <reference key="object" ref="591072398"/>
500 <array class="NSMutableArray" key="children">
501 <reference ref="905061247"/>
502 </array>
503 <reference key="parent" ref="149501230"/>
504 </object>
505 <object class="IBObjectRecord">
506 <int key="objectID">427</int>
507 <reference key="object" ref="905061247"/>
508 <reference key="parent" ref="591072398"/>
509 </object>
510 <object class="IBObjectRecord">
511 <int key="objectID">450</int>
512 <reference key="object" ref="578681479"/>
513 <array class="NSMutableArray" key="children">
514 <reference ref="453040178"/>
515 <reference ref="995383783"/>
516 <reference ref="179401146"/>
517 </array>
518 <reference key="parent" ref="149501230"/>
519 </object>
520 <object class="IBObjectRecord">
521 <int key="objectID">451</int>
522 <reference key="object" ref="453040178"/>
523 <reference key="parent" ref="578681479"/>
524 </object>
525 <object class="IBObjectRecord">
526 <int key="objectID">452</int>
527 <reference key="object" ref="995383783"/>
528 <reference key="parent" ref="578681479"/>
529 </object>
530 <object class="IBObjectRecord">
531 <int key="objectID">453</int>
532 <reference key="object" ref="179401146"/>
533 <reference key="parent" ref="578681479"/>
534 </object>
535 </array>
536 </object>
537 <dictionary class="NSMutableDictionary" key="flattenedProperties">
538 <string key="-1.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
539 <string key="-2.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
540 <string key="-3.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
541 <string key="356.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
542 <string key="383.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
543 <boolean value="NO" key="383.NSWindowTemplate.visibleAtLaunch"/>
544 <string key="384.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
545 <object class="NSMutableDictionary" key="387.IBAttributePlaceholdersKey">
546 <string key="NS.key.0">AccessibilityDescription</string>
547 <object class="IBAccessibilityAttribute" key="NS.object.0">
548 <string key="name">AccessibilityDescription</string>
549 <reference key="object" ref="878938783"/>
550 <string key="accessibilityValue">information</string>
551 </object>
552 </object>
553 <string key="387.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
554 <object class="NSMutableDictionary" key="388.IBAttributePlaceholdersKey">
555 <string key="NS.key.0">AccessibilityDescription</string>
556 <object class="IBAccessibilityAttribute" key="NS.object.0">
557 <string key="name">AccessibilityDescription</string>
558 <reference key="object" ref="447421602"/>
559 <string key="accessibilityValue">information</string>
560 </object>
561 </object>
562 <string key="388.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
563 <string key="397.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
564 <string key="398.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
565 <string key="417.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
566 <string key="418.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
567 <string key="426.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
568 <string key="427.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
569 <string key="450.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
570 <string key="451.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
571 <string key="452.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
572 <string key="453.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string>
573 </dictionary>
574 <dictionary class="NSMutableDictionary" key="unlocalizedProperties"/>
575 <nil key="activeLocalization"/>
576 <dictionary class="NSMutableDictionary" key="localizations"/>
577 <nil key="sourceID"/>
578 <int key="maxID">455</int>
579 </object>
580 <object class="IBClassDescriber" key="IBDocument.Classes"/>
581 <int key="IBDocument.localizationMode">0</int>
582 <string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
583 <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencies">
584 <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
585 <integer value="1060" key="NS.object.0"/>
586 </object>
587 <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencyDefaults">
588 <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
589 <real value="1070" key="NS.object.0"/>
590 </object>
591 <bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
592 <int key="IBDocument.defaultPropertyAccessControl">3</int>
593 <dictionary class="NSMutableDictionary" key="IBDocument.LastKnownImageSizes">
594 <string key="NSInfo">{32, 32}</string>
595 <string key="NSSwitch">{15, 15}</string>
596 </dictionary>
597 </data>
598 </archive>
+0
-9
pubkey.pem less more
0 -----BEGIN PUBLIC KEY-----
1 MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8m960JctNp/i7cnaNzW9
2 CINq4TJ0c5mkTn9pnRR5h3BPf9FhOyeCm8YipAqj1GN5Ct8UfN8GZ6ChwS1ebMSL
3 WePXFKS9URDyCBRRhnPLQTgqOoBYD7kr7wPPekYSheT2jajYJtQu6DV+zf49hHl1
4 8z7xGd2ihNmrPBG2Mo72E8zDrMyMbipjPXAJE1+/IrkGTVBtaaiht6qfwty6Imbx
5 74k1k5/ZyYdTrdE2ar94sbfrFIM8BAm733VoBz0Y3Ncqnx5LDkXLxg/wEf536l6+
6 ypZwCf+d46E17As0D0v+hOTD4ZA0hLZrqmb09YwWwyDyoWI090zsJvA+NDtK/xSk
7 twIDAQAB
8 -----END PUBLIC KEY-----
+0
-219
tests/functional/conftest.py less more
0 import pytest
1 import subprocess
2 import os
3 import sys
4 import time
5 import shutil
6 import base64
7 try:
8 from xmlrpclib import ServerProxy # python 2
9 except ImportError:
10 from xmlrpc.client import ServerProxy # python 3
11
12 nzbget_srcdir = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
13 nzbget_maindir = nzbget_srcdir + '/tests/testdata/nzbget.temp'
14 nzbget_configfile = nzbget_maindir + '/nzbget.conf'
15 nzbget_rpcurl = 'http://127.0.0.1:6789/xmlrpc';
16
17 nzbget_bin = nzbget_srcdir + '/nzbget'
18 if os.name == 'nt':
19 nzbget_bin += '.exe'
20 nserv_datadir = nzbget_srcdir + '/tests/testdata/nserv.temp'
21
22 if os.name == 'nt':
23 sevenzip_bin = nzbget_srcdir + '/7z.exe'
24 else:
25 sevenzip_bin = nzbget_srcdir + '/p7zip'
26
27 has_failures = False
28
29 def pytest_addoption(parser):
30 parser.addini('nzbget_bin', 'path to nzbget binary', default=nzbget_bin)
31 parser.addini('nserv_datadir', 'path to nserv datadir', default=nserv_datadir)
32 parser.addini('nzbget_maindir', 'path to nzbget maindir', default=nzbget_maindir)
33 parser.addini('sevenzip_bin', 'path to 7-zip', default=sevenzip_bin)
34 parser.addoption("--hold", action="store_true", help="Hold at the end of test (keep NZBGet running)")
35
36 def check_config():
37 global nzbget_bin
38 nzbget_bin = pytest.config.getini('nzbget_bin')
39 if not os.path.exists(nzbget_bin):
40 pytest.exit('Could not find nzbget binary at ' + nzbget_bin + '. Alternative path can be set via pytest ini option "nzbget_bin".')
41
42 global sevenzip_bin
43 sevenzip_bin = pytest.config.getini('sevenzip_bin')
44 if not os.path.exists(sevenzip_bin):
45 pytest.exit('Could not find 7-zip binary at ' + sevenzip_bin + '. Alternative path can be set via pytest ini option "sevenzip_bin".')
46
47 global nserv_datadir
48 nserv_datadir = pytest.config.getini('nserv_datadir')
49
50 global nzbget_maindir
51 nzbget_maindir = pytest.config.getini('nzbget_maindir')
52 global nzbget_configfile
53 nzbget_configfile = nzbget_maindir + '/nzbget.conf'
54
55 class NServ:
56
57 def __init__(self):
58 self.process = subprocess.Popen([nzbget_bin, '--nserv', '-d', nserv_datadir, '-v', '0', '-i', '2'])
59
60 def finalize(self):
61 self.process.kill()
62
63 @pytest.fixture(scope='session')
64
65 def nserv(request):
66 check_config()
67
68 instance = NServ()
69 request.addfinalizer(instance.finalize)
70 return instance
71
72
73 class Nzbget:
74
75 def __init__(self, options, session):
76 self.options = options
77 self.session = session
78 self.api = ServerProxy(nzbget_rpcurl)
79 self.prepare_session()
80 self.process = subprocess.Popen([nzbget_bin, '-c', nzbget_configfile, '-s', '-o', 'outputmode=log'])
81 self.wait_until_started()
82
83 def finalize(self):
84 if pytest.config.getoption("--hold"):
85 print('\nNZBGet is still running, press Ctrl+C to quit')
86 time.sleep(100000)
87 self.process.kill()
88 if not has_failures:
89 self.remove_tempdir()
90
91 def remove_tempdir(self):
92 if os.path.exists(nzbget_maindir + '.old'):
93 shutil.rmtree(nzbget_maindir + '.old')
94 if os.path.exists(nzbget_maindir):
95 os.rename(nzbget_maindir, nzbget_maindir + '.old')
96 shutil.rmtree(nzbget_maindir + '.old')
97
98 def prepare_session(self):
99 self.remove_tempdir()
100 os.makedirs(nzbget_maindir)
101 config = open(nzbget_configfile, 'w')
102 config.write('MainDir=' + nzbget_maindir + '\n')
103 config.write('DestDir=${MainDir}/complete\n')
104 config.write('InterDir=${MainDir}/intermediate\n')
105 config.write('TempDir=${MainDir}/temp\n')
106 config.write('QueueDir=${MainDir}/queue\n')
107 config.write('NzbDir=${MainDir}/nzb\n')
108 config.write('LogFile=${MainDir}/nzbget.log\n')
109 config.write('SevenZipCmd=' + sevenzip_bin + '\n')
110 config.write('WriteLog=append\n')
111 config.write('DetailTarget=log\n')
112 config.write('InfoTarget=log\n')
113 config.write('WarningTarget=log\n')
114 config.write('ErrorTarget=log\n')
115 config.write('DebugTarget=none\n')
116 config.write('CrashTrace=no\n')
117 config.write('CrashDump=yes\n')
118 config.write('ContinuePartial=no\n')
119 config.write('DirectWrite=yes\n')
120 config.write('ArticleCache=500\n')
121 config.write('WriteBuffer=1024\n')
122 config.write('NzbDirInterval=0\n')
123 config.write('FlushQueue=no\n')
124 config.write('WebDir=' + nzbget_srcdir + '/webui\n')
125 config.write('ConfigTemplate=' + nzbget_srcdir + '/nzbget.conf\n')
126 config.write('ControlUsername=\n')
127 config.write('ControlPassword=\n')
128 config.write('ControlIP=127.0.0.1\n')
129 config.write('Server1.host=127.0.0.1\n')
130 config.write('Server1.port=6791\n')
131 config.write('Server1.connections=10\n')
132 config.write('Server1.level=0\n')
133 config.write('Server2.host=127.0.0.1\n')
134 config.write('Server2.port=6792\n')
135 config.write('Server2.connections=10\n')
136 config.write('Server2.level=1\n')
137 config.write('Server2.active=no\n')
138 for opt in self.options:
139 config.write(opt + '\n')
140
141 def wait_until_started(self):
142 print('Waiting for nzbget to start')
143 stat = None
144 for x in range(0, 3):
145 try:
146 stat = self.api.status()
147 except:
148 time.sleep(0.5)
149
150 if stat == None:
151 raise Exception('Could not start nzbget')
152 print('Started')
153
154 def append_nzb(self, nzb_name, nzb_content, unpack = None, dupekey = '', dupescore = 0, dupemode = 'FORCE', params = None):
155 nzbcontent64 = base64.standard_b64encode(nzb_content)
156 if params == None:
157 params = []
158 if unpack == True:
159 params.append(('*unpack:', 'yes'))
160 elif unpack == False:
161 params.append(('*unpack:', 'no'))
162 return self.api.append(nzb_name, nzbcontent64, 'test', 0, False, False, dupekey, dupescore, dupemode, params)
163
164 def load_nzb(self, nzb_name):
165 fullfilename = nserv_datadir + '/' + nzb_name
166 in_file = open(fullfilename, 'r')
167
168 nzbcontent = in_file.read()
169
170 in_file.close()
171 return nzbcontent
172
173
174 def download_nzb(self, nzb_name, nzb_content = None, unpack = None, dupekey = '', dupescore = 0, dupemode = 'FORCE', params = None):
175 if not nzb_content:
176 nzb_content = self.load_nzb(nzb_name)
177 self.append_nzb(nzb_name, nzb_content, unpack, dupekey, dupescore, dupemode, params)
178 hist = self.wait_nzb(nzb_name)
179 return hist
180
181 def wait_nzb(self, nzb_name):
182 print('Waiting for download completion')
183 hist = None
184 while not hist:
185 history = self.api.history()
186 for hist1 in history:
187 if hist1['NZBFilename'] == nzb_name:
188 hist = hist1
189 break
190 time.sleep(0.1)
191 return hist
192
193 def clear(self):
194 self.api.editqueue('HistoryFinalDelete', 0, '', range(1, 1000));
195
196 @pytest.fixture(scope='module')
197
198 def nzbget(request):
199
200 check_config()
201
202 instance = Nzbget(getattr(request.module, 'nzbget_options', []), request.session)
203 request.addfinalizer(instance.finalize)
204 return instance
205
206
207 @pytest.hookimpl(tryfirst=True, hookwrapper=True)
208
209 def pytest_runtest_makereport(item, call):
210
211 # execute all other hooks to obtain the report object
212
213 outcome = yield
214
215 rep = outcome.get_result()
216 global has_failures
217
218 has_failures = has_failures or rep.failed
+0
-69
tests/functional/download/conftest.py less more
0 import os
1 import shutil
2 import subprocess
3 import random
4 import array
5 import pytest
6
7
8 def pytest_addoption(parser):
9 parser.addini('sample_medium', 'size of meidum nzb (megabytes)', default=192)
10 parser.addini('sample_large', 'size of large nzb (megabytes)', default=1024)
11
12
13 @pytest.fixture(scope='session', autouse=True)
14 def prepare_testdata(request):
15 print('Preparing test data for "download"')
16
17 nserv_datadir = pytest.config.getini('nserv_datadir')
18 nzbget_bin = pytest.config.getini('nzbget_bin')
19 sevenzip_bin = pytest.config.getini('sevenzip_bin')
20
21 if not os.path.exists(nserv_datadir):
22 print('Creating nserv datadir')
23 os.makedirs(nserv_datadir)
24
25 if not os.path.exists(nserv_datadir + '/medium.nzb'):
26 sizemb = int(pytest.config.getini('sample_medium'))
27 create_test_file(nserv_datadir + '/medium', sevenzip_bin, sizemb)
28
29 if not os.path.exists(nserv_datadir + '/large.nzb'):
30 sizemb = int(pytest.config.getini('sample_large'))
31 create_test_file(nserv_datadir + '/large', sevenzip_bin, sizemb)
32
33 if not os.path.exists(nserv_datadir + '/medium.nzb') or not os.path.exists(nserv_datadir + '/large.nzb'):
34 if 0 != subprocess.call([nzbget_bin, '--nserv', '-d', nserv_datadir, '-v', '2', '-z', '500000', '-q']):
35 pytest.exit('Test file generation failed')
36
37 nzbget_srcdir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
38 if not os.path.exists(nserv_datadir + '/small.nzb'):
39 if not os.path.exists(nserv_datadir + '/small'):
40 os.makedirs(nserv_datadir + '/small')
41 shutil.copyfile(nzbget_srcdir +'/COPYING', nserv_datadir + '/small/small.dat')
42
43 if not os.path.exists(nserv_datadir + '/small-obfuscated.nzb'):
44 if not os.path.exists(nserv_datadir + '/small-obfuscated'):
45 os.makedirs(nserv_datadir + '/small-obfuscated')
46 shutil.copyfile(nzbget_srcdir +'/COPYING', nserv_datadir + '/small-obfuscated/fsdkhKHGuwuMNBKskd')
47
48 if 0 != subprocess.call([nzbget_bin, '--nserv', '-d', nserv_datadir, '-v', '2', '-z', '3000', '-q']):
49 pytest.exit('Test file generation failed')
50
51
52 def create_test_file(bigdir, sevenzip_bin, sizemb):
53 print('Preparing test file (' + str(sizemb) + 'MB)')
54
55 if not os.path.exists(bigdir):
56 os.makedirs(bigdir)
57
58 f = open(bigdir + '/' + str(sizemb) + 'mb.dat', 'wb')
59 for n in xrange(64 * sizemb / 1024):
60 if n % 8 == 0:
61 print('Writing block %i from %i' % (n, 64 * sizemb / 1024))
62 f.write(os.urandom(1024 * 1024 * 16))
63 f.close()
64
65 if 0 != subprocess.call([sevenzip_bin, 'a', bigdir + '/' + str(sizemb) + 'mb.7z', '-mx=0', '-v50m', bigdir + '/' + str(sizemb) + 'mb.dat']):
66 pytest.exit('Test file generation failed')
67
68 os.remove(bigdir + '/' + str(sizemb) + 'mb.dat')
+0
-58
tests/functional/download/download_base_test.py less more
0 nzbget_options = ['HealthCheck=none', 'ArticleCache=500', 'DirectWrite=yes']
1
2 def test_small(nserv, nzbget):
3 hist = nzbget.download_nzb('small.nzb')
4 assert hist['Status'] == 'SUCCESS/HEALTH'
5
6 def test_small_bad(nserv, nzbget):
7 nzb_content = nzbget.load_nzb('small.nzb')
8 nzb_content = nzb_content.replace('?3=6000:3000', '?3=6000:3000!0')
9 hist = nzbget.download_nzb('small.bad.nzb', nzb_content)
10 assert hist['Status'] == 'FAILURE/HEALTH'
11
12 def test_medium(nserv, nzbget):
13 hist = nzbget.download_nzb('medium.nzb')
14 assert hist['Status'] == 'SUCCESS/HEALTH'
15
16 def test_medium_unpack(nserv, nzbget):
17 nzb_content = nzbget.load_nzb('medium.nzb')
18 hist = nzbget.download_nzb('medium_unpack.nzb', nzb_content, unpack=True)
19 assert hist['Status'] == 'SUCCESS/UNPACK'
20
21 def test_large(nserv, nzbget):
22 hist = nzbget.download_nzb('large.nzb')
23 assert hist['Status'] == 'SUCCESS/HEALTH'
24
25 def test_oneserver_small_success(nserv, nzbget):
26 nzb_content = nzbget.load_nzb('small.nzb')
27 nzb_content = nzb_content.replace('?3=6000:3000', '?3=6000:3000!1')
28 hist = nzbget.download_nzb('small.success.nzb', nzb_content)
29 assert hist['Status'] == 'SUCCESS/HEALTH'
30
31 def test_oneserver_small_bad(nserv, nzbget):
32 nzb_content = nzbget.load_nzb('small.nzb')
33 nzb_content = nzb_content.replace('?3=6000:3000', '?3=6000:3000!2')
34 hist = nzbget.download_nzb('small.bad2.nzb', nzb_content)
35 assert hist['Status'] == 'FAILURE/HEALTH'
36
37 def test_twoservers_small_success(nserv, nzbget):
38 nzbget.api.editserver(2, True)
39 nzb_content = nzbget.load_nzb('small.nzb')
40 nzb_content = nzb_content.replace('?3=6000:3000', '?3=6000:3000!2')
41 hist = nzbget.download_nzb('small.twoservers.nzb', nzb_content)
42 nzbget.api.editserver(2, False)
43 assert hist['Status'] == 'SUCCESS/HEALTH'
44
45 def test_oneserver_medium_failed(nserv, nzbget):
46 nzb_content = nzbget.load_nzb('medium.nzb')
47 nzb_content = nzb_content.replace(':500000', ':500000!2')
48 hist = nzbget.download_nzb('medium-health-failed.nzb', nzb_content)
49 assert hist['Status'] == 'FAILURE/HEALTH'
50
51 def test_twoservers_medium_success(nserv, nzbget):
52 nzbget.api.editserver(2, True)
53 nzb_content = nzbget.load_nzb('medium.nzb')
54 nzb_content = nzb_content.replace(':500000', ':500000!2')
55 hist = nzbget.download_nzb('medium-health-two.nzb', nzb_content)
56 nzbget.api.editserver(2, False)
57 assert hist['Status'] == 'SUCCESS/HEALTH'
+0
-28
tests/functional/download/download_filename_test.py less more
0 import os
1
2 nzbget_options = ['HealthCheck=none', 'ArticleCache=500', 'DirectWrite=yes', 'FileNaming=auto']
3
4 def test_small_obfuscated(nserv, nzbget):
5 hist = nzbget.download_nzb('small-obfuscated.nzb')
6 assert hist['Status'] == 'SUCCESS/HEALTH'
7 assert os.path.exists(hist['DestDir'] + '/fsdkhKHGuwuMNBKskd')
8
9 def test_small_obfuscated_bad(nserv, nzbget):
10 nzb_content = nzbget.load_nzb('small-obfuscated.nzb')
11 nzb_content = nzb_content.replace(';fsdkhKHGuwuMNBKskd', ';gpl.txt')
12 hist = nzbget.download_nzb('small-obfuscated.mod.nzb', nzb_content, params=[('*naming', 'nzb')])
13 assert hist['Status'] == 'SUCCESS/HEALTH'
14 assert not os.path.exists(hist['DestDir'] + '/fsdkhKHGuwuMNBKskd')
15 assert os.path.exists(hist['DestDir'] + '/gpl.txt')
16
17 def test_small(nserv, nzbget):
18 hist = nzbget.download_nzb('small.nzb')
19 assert hist['Status'] == 'SUCCESS/HEALTH'
20 assert os.path.exists(hist['DestDir'] + '/small.dat')
21
22 def test_small_changed(nserv, nzbget):
23 nzb_content = nzbget.load_nzb('small.nzb')
24 nzb_content = nzb_content.replace(';small.dat', ';small-changed.dat')
25 hist = nzbget.download_nzb('small-changed.nzb', nzb_content)
26 assert hist['Status'] == 'SUCCESS/HEALTH'
27 assert os.path.exists(hist['DestDir'] + '/small.dat')
+0
-11
tests/functional/download/download_opt1_test.py less more
0 nzbget_options = ['ArticleCache=0', 'DirectWrite=no']
1
2 def test_small(nserv, nzbget):
3 hist = nzbget.download_nzb('small.nzb')
4 assert hist['Status'] == 'SUCCESS/HEALTH'
5
6 def test_medium_unpack(nserv, nzbget):
7 nzb_content = nzbget.load_nzb('medium.nzb')
8 hist = nzbget.download_nzb('medium_unpack.nzb', nzb_content, unpack=True)
9 assert hist['Status'] == 'SUCCESS/UNPACK'
10
+0
-11
tests/functional/download/download_opt2_test.py less more
0 nzbget_options = ['ArticleCache=0', 'DirectWrite=yes']
1
2 def test_small(nserv, nzbget):
3 hist = nzbget.download_nzb('small.nzb')
4 assert hist['Status'] == 'SUCCESS/HEALTH'
5
6 def test_medium_unpack(nserv, nzbget):
7 nzb_content = nzbget.load_nzb('medium.nzb')
8 hist = nzbget.download_nzb('medium_unpack.nzb', nzb_content, unpack=True)
9 assert hist['Status'] == 'SUCCESS/UNPACK'
10
+0
-11
tests/functional/download/download_opt3_test.py less more
0 nzbget_options = ['ArticleCache=500', 'DirectWrite=no']
1
2 def test_small(nserv, nzbget):
3 hist = nzbget.download_nzb('small.nzb')
4 assert hist['Status'] == 'SUCCESS/HEALTH'
5
6 def test_medium_unpack(nserv, nzbget):
7 nzb_content = nzbget.load_nzb('medium.nzb')
8 hist = nzbget.download_nzb('medium_unpack.nzb', nzb_content, unpack=True)
9 assert hist['Status'] == 'SUCCESS/UNPACK'
10
+0
-19
tests/functional/download/dupecheck_test.py less more
0 import base64
1
2 nzbget_options = ['HealthCheck=none', 'DupeCheck=yes']
3
4 def test_dupecheck_small_copy(nserv, nzbget):
5 hist = nzbget.download_nzb('small.nzb', dupemode = 'SCORE')
6 assert hist['Status'] == 'SUCCESS/HEALTH'
7 nzb_content = nzbget.load_nzb('small.nzb')
8 hist = nzbget.download_nzb('small.copy.nzb', nzb_content, dupemode = 'SCORE')
9 assert hist['Status'] == 'DELETED/COPY'
10
11 def test_dupecheck_small_id(nserv, nzbget):
12 nzbget.clear()
13 hist = nzbget.download_nzb('small.nzb', dupemode = 'SCORE')
14 assert hist['Status'] == 'SUCCESS/HEALTH'
15 nzb_content = nzbget.load_nzb('small.nzb')
16 nzbcontent64 = base64.standard_b64encode(nzb_content)
17 id = nzbget.api.append('small.copy2.nzb', nzbcontent64, 'test', 0, False, False, '', 0, 'SCORE', [])
18 assert id > 0
+0
-8
tests/functional/download/health_test.py less more
0 nzbget_options = ['HealthCheck=delete']
1
2 def test_medium_health(nserv, nzbget):
3 nzb_content = nzbget.load_nzb('medium.nzb')
4 nzb_content = nzb_content.replace('.7z', '-does-not-exist.7z')
5 hist = nzbget.download_nzb('medium-health.nzb', nzb_content)
6 assert hist['Status'] == 'FAILURE/HEALTH'
7 assert hist['DeleteStatus'] == 'HEALTH'
+0
-58
tests/functional/download/retry_base_test.py less more
0 nzbget_options = ['HealthCheck=park', 'ArticleCache=500', 'DirectWrite=yes']
1
2 def test_retry_small_redownload(nserv, nzbget):
3 nzb_content = nzbget.load_nzb('small.nzb')
4 nzb_content = nzb_content.replace('?3=6000:3000', '?3=6000:3000!2')
5 hist = nzbget.download_nzb('small.bad2.nzb', nzb_content)
6 assert hist['Status'] == 'FAILURE/HEALTH'
7 nzbget.api.editserver(2, True)
8 nzbget.api.editqueue('HistoryRedownload', 0, '', [hist['NZBID']])
9 hist = nzbget.wait_nzb('small.bad2.nzb')
10 nzbget.api.editserver(2, False)
11 assert hist['Status'] == 'SUCCESS/HEALTH'
12
13 def test_retry_small_retryfailed(nserv, nzbget):
14 nzb_content = nzbget.load_nzb('small.nzb')
15 nzb_content = nzb_content.replace('?3=6000:3000', '?3=6000:3000!2')
16 hist = nzbget.download_nzb('small.bad3.nzb', nzb_content)
17 assert hist['Status'] == 'FAILURE/HEALTH'
18 nzbget.api.editqueue('HistoryRetryFailed', 0, '', [hist['NZBID']])
19 hist = nzbget.wait_nzb('small.bad3.nzb')
20 assert hist['Status'] == 'FAILURE/HEALTH'
21 nzbget.api.editserver(2, True)
22 nzbget.api.editqueue('HistoryRetryFailed', 0, '', [hist['NZBID']])
23 hist = nzbget.wait_nzb('small.bad3.nzb')
24 nzbget.api.editserver(2, False)
25 assert hist['Status'] == 'SUCCESS/HEALTH'
26
27 def test_retry_medium_failed(nserv, nzbget):
28 nzb_content = nzbget.load_nzb('medium.nzb')
29 nzb_content = nzb_content.replace('000000:500000', '000000:500000!2')
30 hist = nzbget.download_nzb('medium.nzb', nzb_content)
31 assert hist['Status'] == 'FAILURE/HEALTH'
32 assert hist['DeleteStatus'] == 'HEALTH'
33
34 def test_retry_medium_redownload(nserv, nzbget):
35 nzb_content = nzbget.load_nzb('medium.nzb')
36 nzb_content = nzb_content.replace('0000000:500000', '0000000:500000!2')
37 hist = nzbget.download_nzb('medium.bad.nzb', nzb_content)
38 assert hist['Status'] == 'FAILURE/HEALTH'
39 nzbget.api.editserver(2, True)
40 nzbget.api.editqueue('HistoryRedownload', 0, '', [hist['NZBID']])
41 hist = nzbget.wait_nzb('medium.bad.nzb')
42 nzbget.api.editserver(2, False)
43 assert hist['Status'] == 'SUCCESS/HEALTH'
44
45 def test_retry_medium_retryfailed(nserv, nzbget):
46 nzb_content = nzbget.load_nzb('medium.nzb')
47 nzb_content = nzb_content.replace('0000000:500000', '0000000:500000!2')
48 hist = nzbget.download_nzb('medium.bad3.nzb', nzb_content)
49 assert hist['Status'] == 'FAILURE/HEALTH'
50 nzbget.api.editqueue('HistoryRetryFailed', 0, '', [hist['NZBID']])
51 hist = nzbget.wait_nzb('medium.bad3.nzb')
52 assert hist['Status'] == 'FAILURE/HEALTH'
53 nzbget.api.editserver(2, True)
54 nzbget.api.editqueue('HistoryRetryFailed', 0, '', [hist['NZBID']])
55 hist = nzbget.wait_nzb('medium.bad3.nzb')
56 nzbget.api.editserver(2, False)
57 assert hist['Status'] == 'SUCCESS/HEALTH'
+0
-29
tests/functional/download/retry_opt1_test.py less more
0 nzbget_options = ['HealthCheck=park', 'ArticleCache=500', 'DirectWrite=no']
1
2 def test_retry_small_retryfailed(nserv, nzbget):
3 nzb_content = nzbget.load_nzb('small.nzb')
4 nzb_content = nzb_content.replace('?3=6000:3000', '?3=6000:3000!2')
5 hist = nzbget.download_nzb('small.bad3.nzb', nzb_content)
6 assert hist['Status'] == 'FAILURE/HEALTH'
7 nzbget.api.editqueue('HistoryRetryFailed', 0, '', [hist['NZBID']])
8 hist = nzbget.wait_nzb('small.bad3.nzb')
9 assert hist['Status'] == 'FAILURE/HEALTH'
10 nzbget.api.editserver(2, True)
11 nzbget.api.editqueue('HistoryRetryFailed', 0, '', [hist['NZBID']])
12 hist = nzbget.wait_nzb('small.bad3.nzb')
13 nzbget.api.editserver(2, False)
14 assert hist['Status'] == 'SUCCESS/HEALTH'
15
16 def test_retry_medium_retryfailed(nserv, nzbget):
17 nzb_content = nzbget.load_nzb('medium.nzb')
18 nzb_content = nzb_content.replace('0000000:500000', '0000000:500000!2')
19 hist = nzbget.download_nzb('medium.bad3.nzb', nzb_content)
20 assert hist['Status'] == 'FAILURE/HEALTH'
21 nzbget.api.editqueue('HistoryRetryFailed', 0, '', [hist['NZBID']])
22 hist = nzbget.wait_nzb('medium.bad3.nzb')
23 assert hist['Status'] == 'FAILURE/HEALTH'
24 nzbget.api.editserver(2, True)
25 nzbget.api.editqueue('HistoryRetryFailed', 0, '', [hist['NZBID']])
26 hist = nzbget.wait_nzb('medium.bad3.nzb')
27 nzbget.api.editserver(2, False)
28 assert hist['Status'] == 'SUCCESS/HEALTH'
+0
-29
tests/functional/download/retry_opt2_test.py less more
0 nzbget_options = ['HealthCheck=park', 'ArticleCache=0', 'DirectWrite=no']
1
2 def test_retry_small_retryfailed(nserv, nzbget):
3 nzb_content = nzbget.load_nzb('small.nzb')
4 nzb_content = nzb_content.replace('?3=6000:3000', '?3=6000:3000!2')
5 hist = nzbget.download_nzb('small.bad3.nzb', nzb_content)
6 assert hist['Status'] == 'FAILURE/HEALTH'
7 nzbget.api.editqueue('HistoryRetryFailed', 0, '', [hist['NZBID']])
8 hist = nzbget.wait_nzb('small.bad3.nzb')
9 assert hist['Status'] == 'FAILURE/HEALTH'
10 nzbget.api.editserver(2, True)
11 nzbget.api.editqueue('HistoryRetryFailed', 0, '', [hist['NZBID']])
12 hist = nzbget.wait_nzb('small.bad3.nzb')
13 nzbget.api.editserver(2, False)
14 assert hist['Status'] == 'SUCCESS/HEALTH'
15
16 def test_retry_medium_retryfailed(nserv, nzbget):
17 nzb_content = nzbget.load_nzb('medium.nzb')
18 nzb_content = nzb_content.replace('0000000:500000', '0000000:500000!2')
19 hist = nzbget.download_nzb('medium.bad3.nzb', nzb_content)
20 assert hist['Status'] == 'FAILURE/HEALTH'
21 nzbget.api.editqueue('HistoryRetryFailed', 0, '', [hist['NZBID']])
22 hist = nzbget.wait_nzb('medium.bad3.nzb')
23 assert hist['Status'] == 'FAILURE/HEALTH'
24 nzbget.api.editserver(2, True)
25 nzbget.api.editqueue('HistoryRetryFailed', 0, '', [hist['NZBID']])
26 hist = nzbget.wait_nzb('medium.bad3.nzb')
27 nzbget.api.editserver(2, False)
28 assert hist['Status'] == 'SUCCESS/HEALTH'
+0
-94
tests/functional/editqueue/editqueue_move_test.py less more
0 nzbget_options = ['SaveQueue=no']
1
2 import os
3 import time
4
5 nzbget = None
6
7 def prepare_queue(nzbget_instance):
8 global nzbget
9
10 if nzbget != None:
11 nzbget.api.editqueue('GroupSort', 'Name', [])
12 check_list([1,2,3,4,5,6,7,8,9])
13 return
14
15 print('prepare_queue')
16 nzbget = nzbget_instance
17
18 nzbget.api.pausedownload()
19
20 nzbget_srcdir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
21 testdata_dir = nzbget_srcdir + '/tests/testdata'
22 fullfilename = nzbget_srcdir + '/tests/testdata/nzbfile/plain.nzb'
23 in_file = open(fullfilename, 'r')
24 nzb_content = in_file.read()
25 in_file.close()
26
27 nzbget.append_nzb('1', nzb_content)
28 nzbget.append_nzb('2', nzb_content)
29 nzbget.append_nzb('3', nzb_content)
30 nzbget.append_nzb('4', nzb_content)
31 nzbget.append_nzb('5', nzb_content)
32 nzbget.append_nzb('6', nzb_content)
33 nzbget.append_nzb('7', nzb_content)
34 nzbget.append_nzb('8', nzb_content)
35 nzbget.append_nzb('9', nzb_content)
36
37 def check_list(req):
38 queue = nzbget.api.listgroups()
39 assert len(req) == len(queue)
40 for i in range(len(req)):
41 assert req[i] == queue[i]['NZBID']
42
43 def test_editqueue_move_offset(nzbget):
44 prepare_queue(nzbget)
45
46 check_list([1,2,3,4,5,6,7,8,9])
47
48 nzbget.api.editqueue('GroupMoveOffset', '1', [2])
49 check_list([1,3,2,4,5,6,7,8,9])
50
51 nzbget.api.editqueue('GroupMoveOffset', '-1', [2])
52 check_list([1,2,3,4,5,6,7,8,9])
53
54 nzbget.api.editqueue('GroupMoveOffset', '2', [4,5,6])
55 check_list([1,2,3,7,8,4,5,6,9])
56
57 nzbget.api.editqueue('GroupMoveOffset', '-2', [4,5,6])
58 check_list([1,2,3,4,5,6,7,8,9])
59
60 nzbget.api.editqueue('GroupMoveOffset', '5', [4,6])
61 check_list([1,2,3,5,7,8,9,4,6])
62
63 nzbget.api.editqueue('GroupMoveOffset', '-5', [2,5,7])
64 check_list([2,5,7,1,3,8,9,4,6])
65
66 def test_editqueue_move_before_after(nzbget):
67 prepare_queue(nzbget)
68
69 check_list([1,2,3,4,5,6,7,8,9])
70
71 nzbget.api.editqueue('GroupMoveBefore', '2', [8,9])
72 check_list([1,8,9,2,3,4,5,6,7])
73
74 nzbget.api.editqueue('GroupMoveBefore', '2', [8,9])
75 check_list([1,8,9,2,3,4,5,6,7])
76
77 nzbget.api.editqueue('GroupMoveAfter', '2', [8,9])
78 check_list([1,2,8,9,3,4,5,6,7])
79
80 nzbget.api.editqueue('GroupMoveAfter', '7', [1,8,9])
81 check_list([2,3,4,5,6,7,1,8,9])
82
83 nzbget.api.editqueue('GroupMoveBefore', '2', [5,1,9])
84 check_list([5,1,9,2,3,4,6,7,8])
85
86 nzbget.api.editqueue('GroupMoveBefore', '2', [5,1,9])
87 check_list([5,1,9,2,3,4,6,7,8])
88
89 nzbget.api.editqueue('GroupMoveAfter', '2', [5,1,9])
90 check_list([2,5,1,9,3,4,6,7,8])
91
92 nzbget.api.editqueue('GroupMoveAfter', '8', [5,2])
93 check_list([1,9,3,4,6,7,8,2,5])
+0
-26
tests/functional/parcheck/conftest.py less more
0 import os
1 import shutil
2 import subprocess
3 import pytest
4
5
6 @pytest.fixture(scope='session', autouse=True)
7 def prepare_testdata(request):
8 print('Preparing test data for "parcheck"')
9
10 nserv_datadir = pytest.config.getini('nserv_datadir')
11 nzbget_bin = pytest.config.getini('nzbget_bin')
12 sevenzip_bin = pytest.config.getini('sevenzip_bin')
13
14 if not os.path.exists(nserv_datadir):
15 print('Creating nserv datadir')
16 os.makedirs(nserv_datadir)
17
18 nzbget_srcdir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
19
20 testdata_dir = nzbget_srcdir + '/tests/testdata'
21 if not os.path.exists(nserv_datadir + '/parchecker'):
22 shutil.copytree(testdata_dir +'/parchecker', nserv_datadir + '/parchecker')
23
24 if 0 != subprocess.call([nzbget_bin, '--nserv', '-d', nserv_datadir, '-v', '2', '-z', '3000', '-q']):
25 pytest.exit('Test file generation failed')
+0
-19
tests/functional/parcheck/parcheck_base_test.py less more
0 nzbget_options = ['ParCheck=auto', 'ParQuick=yes', 'PostStrategy=sequential']
1
2 def test_parchecker_healthy(nserv, nzbget):
3 hist = nzbget.download_nzb('parchecker.nzb')
4 assert hist['Status'] == 'SUCCESS/HEALTH'
5
6 def test_parchecker_repair(nserv, nzbget):
7 nzb_content = nzbget.load_nzb('parchecker.nzb')
8 nzb_content = nzb_content.replace('parchecker/testfile.dat?1=0:3000', 'parchecker/testfile.dat?1=0:3000!0')
9 hist = nzbget.download_nzb('parchecker.repair.nzb', nzb_content)
10 assert hist['Status'] == 'SUCCESS/PAR'
11
12 def test_parchecker_subject(nserv, nzbget):
13 nzb_content = nzbget.load_nzb('parchecker.nzb')
14 nzb_content = nzb_content.replace('parchecker/testfile.dat?1=0:3000', 'parchecker/testfile.dat?1=0:3000!0')
15 nzb_content = nzb_content.replace('subject="&quot;', 'subject="')
16 nzb_content = nzb_content.replace('&quot; yEnc', '.dat yEnc')
17 hist = nzbget.download_nzb('parchecker.subject.nzb', nzb_content)
18 assert hist['Status'] == 'SUCCESS/PAR'
+0
-11
tests/functional/parcheck/parcheck_opt1_test.py less more
0 nzbget_options = ['ParCheck=force', 'ParQuick=yes', 'PostStrategy=sequential']
1
2 def test_parchecker_healthy(nserv, nzbget):
3 hist = nzbget.download_nzb('parchecker.nzb')
4 assert hist['Status'] == 'SUCCESS/PAR'
5
6 def test_parchecker_repair(nserv, nzbget):
7 nzb_content = nzbget.load_nzb('parchecker.nzb')
8 nzb_content = nzb_content.replace('parchecker/testfile.dat?1=0:3000', 'parchecker/testfile.dat?1=0:3000!0')
9 hist = nzbget.download_nzb('parchecker.repair.nzb', nzb_content)
10 assert hist['Status'] == 'SUCCESS/PAR'
+0
-11
tests/functional/parcheck/parcheck_opt2_test.py less more
0 nzbget_options = ['ParCheck=manual', 'ParQuick=yes', 'PostStrategy=sequential']
1
2 def test_parchecker_healthy(nserv, nzbget):
3 hist = nzbget.download_nzb('parchecker.nzb')
4 assert hist['Status'] == 'SUCCESS/HEALTH'
5
6 def test_parchecker_repair(nserv, nzbget):
7 nzb_content = nzbget.load_nzb('parchecker.nzb')
8 nzb_content = nzb_content.replace('parchecker/testfile.dat?1=0:3000', 'parchecker/testfile.dat?1=0:3000!0')
9 hist = nzbget.download_nzb('parchecker.repair.nzb', nzb_content)
10 assert hist['Status'] == 'WARNING/DAMAGED'
+0
-11
tests/functional/parcheck/parcheck_opt3_test.py less more
0 nzbget_options = ['ParCheck=auto', 'ParQuick=yes', 'PostStrategy=balanced']
1
2 def test_parchecker_healthy(nserv, nzbget):
3 hist = nzbget.download_nzb('parchecker.nzb')
4 assert hist['Status'] == 'SUCCESS/HEALTH'
5
6 def test_parchecker_repair(nserv, nzbget):
7 nzb_content = nzbget.load_nzb('parchecker.nzb')
8 nzb_content = nzb_content.replace('parchecker/testfile.dat?1=0:3000', 'parchecker/testfile.dat?1=0:3000!0')
9 hist = nzbget.download_nzb('parchecker.repair.nzb', nzb_content)
10 assert hist['Status'] == 'SUCCESS/PAR'
+0
-11
tests/functional/parcheck/parcheck_opt4_test.py less more
0 nzbget_options = ['ParCheck=force', 'ParQuick=yes', 'PostStrategy=balanced']
1
2 def test_parchecker_healthy(nserv, nzbget):
3 hist = nzbget.download_nzb('parchecker.nzb')
4 assert hist['Status'] == 'SUCCESS/PAR'
5
6 def test_parchecker_repair(nserv, nzbget):
7 nzb_content = nzbget.load_nzb('parchecker.nzb')
8 nzb_content = nzb_content.replace('parchecker/testfile.dat?1=0:3000', 'parchecker/testfile.dat?1=0:3000!0')
9 hist = nzbget.download_nzb('parchecker.repair.nzb', nzb_content)
10 assert hist['Status'] == 'SUCCESS/PAR'
+0
-11
tests/functional/parcheck/parcheck_opt5_test.py less more
0 nzbget_options = ['ParCheck=manual', 'ParQuick=yes', 'PostStrategy=balanced']
1
2 def test_parchecker_healthy(nserv, nzbget):
3 hist = nzbget.download_nzb('parchecker.nzb')
4 assert hist['Status'] == 'SUCCESS/HEALTH'
5
6 def test_parchecker_repair(nserv, nzbget):
7 nzb_content = nzbget.load_nzb('parchecker.nzb')
8 nzb_content = nzb_content.replace('parchecker/testfile.dat?1=0:3000', 'parchecker/testfile.dat?1=0:3000!0')
9 hist = nzbget.download_nzb('parchecker.repair.nzb', nzb_content)
10 assert hist['Status'] == 'WARNING/DAMAGED'
+0
-11
tests/functional/parcheck/parcheck_opt6_test.py less more
0 nzbget_options = ['ParCheck=force', 'ParQuick=no', 'PostStrategy=balanced']
1
2 def test_parchecker_healthy(nserv, nzbget):
3 hist = nzbget.download_nzb('parchecker.nzb')
4 assert hist['Status'] == 'SUCCESS/PAR'
5
6 def test_parchecker_repair(nserv, nzbget):
7 nzb_content = nzbget.load_nzb('parchecker.nzb')
8 nzb_content = nzb_content.replace('parchecker/testfile.dat?1=0:3000', 'parchecker/testfile.dat?1=0:3000!0')
9 hist = nzbget.download_nzb('parchecker.repair.nzb', nzb_content)
10 assert hist['Status'] == 'SUCCESS/PAR'
+0
-27
tests/functional/parcheck/parcheck_opt7_test.py less more
0 nzbget_options = ['ParCheck=auto', 'ParQuick=no', 'PostStrategy=rocket']
1
2 def test_parchecker_healthy(nserv, nzbget):
3 hist = nzbget.download_nzb('parchecker.nzb')
4 assert hist['Status'] == 'SUCCESS/HEALTH'
5
6 def test_parchecker_repair(nserv, nzbget):
7 nzbget.api.pausepost();
8 nzb_content = nzbget.load_nzb('parchecker.nzb')
9 nzb_content = nzb_content.replace('parchecker/testfile.dat?1=0:3000', 'parchecker/testfile.dat?1=0:3000!0')
10 nzbget.append_nzb('parchecker.1.nzb', nzb_content, dupemode='FORCE')
11 nzbget.append_nzb('parchecker.2.nzb', nzb_content, dupemode='FORCE')
12 nzbget.append_nzb('parchecker.3.nzb', nzb_content, dupemode='FORCE')
13
14 while True:
15 status = nzbget.api.status()
16 if status['RemainingSizeMB'] == 0:
17 break
18 time.sleep(0.1)
19
20 nzbget.api.resumepost();
21 hist1 = nzbget.wait_nzb('parchecker.3.nzb');
22 hist2 = nzbget.wait_nzb('parchecker.3.nzb');
23 hist3 = nzbget.wait_nzb('parchecker.3.nzb');
24 assert hist1['Status'] == 'SUCCESS/PAR'
25 assert hist2['Status'] == 'SUCCESS/PAR'
26 assert hist3['Status'] == 'SUCCESS/PAR'
+0
-174
tests/functional/rename/conftest.py less more
0 import os
1 import shutil
2 import subprocess
3 import pytest
4
5 def pytest_addoption(parser):
6 parser.addini('par2_bin', 'path to par2 binary', default=None)
7
8 @pytest.fixture(scope='session', autouse=True)
9 def prepare_testdata(request):
10 print('Preparing test data for "rename"')
11
12 nserv_datadir = pytest.config.getini('nserv_datadir')
13 nzbget_bin = pytest.config.getini('nzbget_bin')
14 sevenzip_bin = pytest.config.getini('sevenzip_bin')
15 par2_bin = pytest.config.getini('par2_bin')
16
17 if not os.path.exists(par2_bin):
18 pytest.exit('Cannot prepare test files. Set option "par2_bin in pytest.ini"')
19
20 if not os.path.exists(nserv_datadir):
21 print('Creating nserv datadir')
22 os.makedirs(nserv_datadir)
23
24 nzbget_srcdir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
25 testdata_dir = nzbget_srcdir + '/tests/testdata'
26
27 if not os.path.exists(nserv_datadir + '/parrename'):
28 os.makedirs(nserv_datadir + '/parrename')
29 shutil.copyfile(testdata_dir + '/rarrenamer/testfile3.part01.rar', nserv_datadir + '/parrename/testfile3.part01.rar')
30 shutil.copyfile(testdata_dir + '/rarrenamer/testfile3.part02.rar', nserv_datadir + '/parrename/testfile3.part02.rar')
31 shutil.copyfile(testdata_dir + '/rarrenamer/testfile3.part03.rar', nserv_datadir + '/parrename/testfile3.part03.rar')
32 os.chdir(nserv_datadir + '/parrename')
33 if 0 != subprocess.call([par2_bin, 'c', '-b20', 'parrename.par2', '*']):
34 pytest.exit('Test file generation failed')
35 os.rename(nserv_datadir + '/parrename/testfile3.part01.rar', nserv_datadir + '/parrename/abc.21')
36 os.rename(nserv_datadir + '/parrename/testfile3.part02.rar', nserv_datadir + '/parrename/abc.02')
37 os.rename(nserv_datadir + '/parrename/testfile3.part03.rar', nserv_datadir + '/parrename/abc.15')
38
39 def prepare_test(dirname, testfile):
40 if not os.path.exists(nserv_datadir + '/' + dirname + '.nzb'):
41 os.makedirs(nserv_datadir + '/' + dirname)
42 shutil.copyfile(testdata_dir + '/rarrenamer/' + testfile + '.part01.rar', nserv_datadir + '/' + dirname + '/abc.21')
43 shutil.copyfile(testdata_dir + '/rarrenamer/' + testfile + '.part02.rar', nserv_datadir + '/' + dirname + '/abc.02')
44 shutil.copyfile(testdata_dir + '/rarrenamer/' + testfile + '.part03.rar', nserv_datadir + '/' + dirname + '/abc.15')
45 os.chdir(nserv_datadir + '/' + dirname)
46 if 0 != subprocess.call([par2_bin, 'c', '-b20', 'parrename.par2', '*']):
47 pytest.exit('Test file generation failed')
48
49 prepare_test('rarrename3', 'testfile3')
50 prepare_test('rarrename5', 'testfile5')
51 prepare_test('rarrename3encdata', 'testfile3encdata')
52 prepare_test('rarrename5encdata', 'testfile5encdata')
53 prepare_test('rarrename3encnam', 'testfile3encnam')
54 prepare_test('rarrename5encnam', 'testfile5encnam')
55
56 if not os.path.exists(nserv_datadir + '/rarrename2sets'):
57 os.makedirs(nserv_datadir + '/rarrename2sets')
58 shutil.copyfile(testdata_dir + '/rarrenamer/testfile3.part01.rar', nserv_datadir + '/rarrename2sets/abc.21')
59 shutil.copyfile(testdata_dir + '/rarrenamer/testfile3.part02.rar', nserv_datadir + '/rarrename2sets/abc.02')
60 shutil.copyfile(testdata_dir + '/rarrenamer/testfile3.part03.rar', nserv_datadir + '/rarrename2sets/abc.15')
61 shutil.copyfile(testdata_dir + '/rarrenamer/testfile5.part01.rar', nserv_datadir + '/rarrename2sets/abc.22')
62 shutil.copyfile(testdata_dir + '/rarrenamer/testfile5.part02.rar', nserv_datadir + '/rarrename2sets/abc.03')
63 shutil.copyfile(testdata_dir + '/rarrenamer/testfile5.part03.rar', nserv_datadir + '/rarrename2sets/abc.14')
64
65 if not os.path.exists(nserv_datadir + '/rarrename3oldnam'):
66 os.makedirs(nserv_datadir + '/rarrename3oldnam')
67 shutil.copyfile(testdata_dir + '/rarrenamer/testfile3oldnam.rar', nserv_datadir + '/rarrename3oldnam/abc.61')
68 shutil.copyfile(testdata_dir + '/rarrenamer/testfile3oldnam.r00', nserv_datadir + '/rarrename3oldnam/abc.32')
69 shutil.copyfile(testdata_dir + '/rarrenamer/testfile3oldnam.r01', nserv_datadir + '/rarrename3oldnam/abc.45')
70
71 if not os.path.exists(nserv_datadir + '/rarrename3badext'):
72 os.makedirs(nserv_datadir + '/rarrename3badext')
73 shutil.copyfile(testdata_dir + '/rarrenamer/testfile3oldnam.rar', nserv_datadir + '/rarrename3badext/testfile3oldnam.rar')
74 shutil.copyfile(testdata_dir + '/rarrenamer/testfile3oldnam.r00', nserv_datadir + '/rarrename3badext/testfile3oldnam.r03')
75 shutil.copyfile(testdata_dir + '/rarrenamer/testfile3oldnam.r01', nserv_datadir + '/rarrename3badext/testfile3oldnam.r02')
76
77 if not os.path.exists(nserv_datadir + '/rarrename5badext'):
78 os.makedirs(nserv_datadir + '/rarrename5badext')
79 shutil.copyfile(testdata_dir + '/rarrenamer/testfile3.part01.rar', nserv_datadir + '/rarrename5badext/testfile3.part01.rar')
80 shutil.copyfile(testdata_dir + '/rarrenamer/testfile3.part02.rar', nserv_datadir + '/rarrename5badext/testfile3.part0002.rar')
81 shutil.copyfile(testdata_dir + '/rarrenamer/testfile3.part03.rar', nserv_datadir + '/rarrename5badext/testfile3.part03.rar')
82
83 if not os.path.exists(nserv_datadir + '/rar3ignoreext'):
84 os.makedirs(nserv_datadir + '/rar3ignoreext')
85 shutil.copyfile(testdata_dir + '/rarrenamer/testfile3.part01.rar', nserv_datadir + '/rar3ignoreext/testfile3-1.cbr')
86 shutil.copyfile(testdata_dir + '/rarrenamer/testfile3.part02.rar', nserv_datadir + '/rar3ignoreext/testfile3-2.cbr')
87 shutil.copyfile(testdata_dir + '/rarrenamer/testfile3.part03.rar', nserv_datadir + '/rar3ignoreext/testfile3-3.cbr')
88
89 if 0 != subprocess.call([nzbget_bin, '--nserv', '-d', nserv_datadir, '-v', '2', '-z', '3000', '-q']):
90 pytest.exit('Test file generation failed')
91
92 if not os.path.exists(nserv_datadir + '/rarrename3sm'):
93 os.makedirs(nserv_datadir + '/rarrename3sm')
94 shutil.copyfile(testdata_dir + '/rarrenamer/testfile3oldnam.rar', nserv_datadir + '/rarrename3sm/abc.61')
95 shutil.copyfile(testdata_dir + '/rarrenamer/testfile3oldnam.r00', nserv_datadir + '/rarrename3sm/abc.32')
96 shutil.copyfile(testdata_dir + '/rarrenamer/testfile3oldnam.r01', nserv_datadir + '/rarrename3sm/abc.45')
97 os.chdir(nserv_datadir + '/rarrename3sm')
98 if 0 != subprocess.call([par2_bin, 'c', '-b100', 'parrename.par2', '*']):
99 pytest.exit('Test file generation failed')
100 if 0 != subprocess.call([nzbget_bin, '--nserv', '-d', nserv_datadir, '-v', '2', '-z', '500', '-q']):
101 pytest.exit('Test file generation failed')
102
103 if not os.path.exists(nserv_datadir + '/obfuscated1.nzb'):
104 create_test_file(nserv_datadir + '/obfuscated1', sevenzip_bin, 5, 1)
105 os.chdir(nserv_datadir + '/obfuscated1')
106 if 0 != subprocess.call([par2_bin, 'c', '-b100', 'parrename.par2', '*']):
107 pytest.exit('Test file generation failed')
108 os.rename(nserv_datadir + '/obfuscated1/5mb.7z.001', nserv_datadir + '/obfuscated1/abc.51')
109 os.rename(nserv_datadir + '/obfuscated1/5mb.7z.002', nserv_datadir + '/obfuscated1/abc.01')
110 os.rename(nserv_datadir + '/obfuscated1/5mb.7z.003', nserv_datadir + '/obfuscated1/abc.21')
111 os.rename(nserv_datadir + '/obfuscated1/5mb.7z.004', nserv_datadir + '/obfuscated1/abc.34')
112 os.rename(nserv_datadir + '/obfuscated1/5mb.7z.005', nserv_datadir + '/obfuscated1/abc.17')
113 os.rename(nserv_datadir + '/obfuscated1/5mb.7z.006', nserv_datadir + '/obfuscated1/abc.00')
114 if 0 != subprocess.call([nzbget_bin, '--nserv', '-d', nserv_datadir, '-v', '2', '-z', '100000', '-q']):
115 pytest.exit('Test file generation failed')
116
117 if not os.path.exists(nserv_datadir + '/obfuscated2.nzb'):
118 create_test_file(nserv_datadir + '/obfuscated2', sevenzip_bin, 5, 1)
119 os.chdir(nserv_datadir + '/obfuscated2')
120 if 0 != subprocess.call([par2_bin, 'c', '-b100', 'parrename.par2', '*']):
121 pytest.exit('Test file generation failed')
122 os.rename(nserv_datadir + '/obfuscated2/5mb.7z.001', nserv_datadir + '/obfuscated2/abc.51')
123 os.rename(nserv_datadir + '/obfuscated2/5mb.7z.002', nserv_datadir + '/obfuscated2/abc.01')
124 os.rename(nserv_datadir + '/obfuscated2/5mb.7z.003', nserv_datadir + '/obfuscated2/abc.21')
125 os.rename(nserv_datadir + '/obfuscated2/5mb.7z.004', nserv_datadir + '/obfuscated2/abc.34')
126 os.rename(nserv_datadir + '/obfuscated2/5mb.7z.005', nserv_datadir + '/obfuscated2/abc.17')
127 os.rename(nserv_datadir + '/obfuscated2/5mb.7z.006', nserv_datadir + '/obfuscated2/abc.00')
128 os.rename(nserv_datadir + '/obfuscated2/parrename.par2', nserv_datadir + '/obfuscated2/abc.90')
129 os.rename(nserv_datadir + '/obfuscated2/parrename.vol0+1.par2', nserv_datadir + '/obfuscated2/abc.95')
130 os.rename(nserv_datadir + '/obfuscated2/parrename.vol1+2.par2', nserv_datadir + '/obfuscated2/abc.91')
131 os.rename(nserv_datadir + '/obfuscated2/parrename.vol3+2.par2', nserv_datadir + '/obfuscated2/abc.92')
132 if 0 != subprocess.call([nzbget_bin, '--nserv', '-d', nserv_datadir, '-v', '2', '-z', '100000', '-q']):
133 pytest.exit('Test file generation failed')
134
135 if not os.path.exists(nserv_datadir + '/obfuscated3.nzb'):
136 create_test_file(nserv_datadir + '/obfuscated3', sevenzip_bin, 100, 10)
137 os.chdir(nserv_datadir + '/obfuscated3')
138 if 0 != subprocess.call([par2_bin, 'c', '-b100', 'parrename.par2', '*']):
139 pytest.exit('Test file generation failed')
140 os.rename(nserv_datadir + '/obfuscated3/100mb.7z.001', nserv_datadir + '/obfuscated3/abc.51')
141 os.rename(nserv_datadir + '/obfuscated3/100mb.7z.002', nserv_datadir + '/obfuscated3/abc.01')
142 os.rename(nserv_datadir + '/obfuscated3/100mb.7z.003', nserv_datadir + '/obfuscated3/abc.21')
143 os.rename(nserv_datadir + '/obfuscated3/100mb.7z.004', nserv_datadir + '/obfuscated3/abc.34')
144 os.rename(nserv_datadir + '/obfuscated3/100mb.7z.005', nserv_datadir + '/obfuscated3/abc.17')
145 os.rename(nserv_datadir + '/obfuscated3/100mb.7z.006', nserv_datadir + '/obfuscated3/abc.60')
146 os.rename(nserv_datadir + '/obfuscated3/100mb.7z.007', nserv_datadir + '/obfuscated3/abc.32')
147 os.rename(nserv_datadir + '/obfuscated3/100mb.7z.008', nserv_datadir + '/obfuscated3/abc.35')
148 os.rename(nserv_datadir + '/obfuscated3/100mb.7z.009', nserv_datadir + '/obfuscated3/abc.41')
149 os.rename(nserv_datadir + '/obfuscated3/100mb.7z.010', nserv_datadir + '/obfuscated3/abc.50')
150 os.rename(nserv_datadir + '/obfuscated3/100mb.7z.011', nserv_datadir + '/obfuscated3/abc.43')
151 os.rename(nserv_datadir + '/obfuscated3/parrename.par2', nserv_datadir + '/obfuscated3/abc.00')
152 os.rename(nserv_datadir + '/obfuscated3/parrename.vol0+1.par2', nserv_datadir + '/obfuscated3/abc.02')
153 os.rename(nserv_datadir + '/obfuscated3/parrename.vol1+2.par2', nserv_datadir + '/obfuscated3/abc.91')
154 os.rename(nserv_datadir + '/obfuscated3/parrename.vol3+2.par2', nserv_datadir + '/obfuscated3/abc.92')
155 if 0 != subprocess.call([nzbget_bin, '--nserv', '-d', nserv_datadir, '-v', '2', '-z', '100000', '-q']):
156 pytest.exit('Test file generation failed')
157
158 def create_test_file(bigdir, sevenzip_bin, sizemb, partmb):
159 print('Preparing test file (' + str(sizemb) + 'MB)')
160
161 if not os.path.exists(bigdir):
162 os.makedirs(bigdir)
163
164 f = open(bigdir + '/' + str(sizemb) + 'mb.dat', 'wb')
165 for n in xrange(sizemb / partmb):
166 print('Writing block %i from %i' % (n + 1, sizemb / partmb))
167 f.write(os.urandom(partmb * 1024 * 1024))
168 f.close()
169
170 if 0 != subprocess.call([sevenzip_bin, 'a', bigdir + '/' + str(sizemb) + 'mb.7z', '-mx=0', '-v' + str(partmb) + 'm', bigdir + '/' + str(sizemb) + 'mb.dat']):
171 pytest.exit('Test file generation failed')
172
173 os.remove(bigdir + '/' + str(sizemb) + 'mb.dat')
+0
-86
tests/functional/rename/rename_base_test.py less more
0 nzbget_options = ['ParRename=yes', 'RarRename=yes', 'UnpackIgnoreExt=.cbr', 'DirectRename=no']
1
2 def test_parrename(nserv, nzbget):
3 hist = nzbget.download_nzb('parrename.nzb', unpack=True)
4 assert hist['Status'] == 'SUCCESS/UNPACK'
5
6 def test_parrename_backup(nserv, nzbget):
7 nzb_content = nzbget.load_nzb('parrename.nzb')
8 nzb_content = nzb_content.replace('parrename/parrename.par2?', 'parrename/parrename.par2.damaged?')
9 hist = nzbget.download_nzb('parrename.backup.nzb', nzb_content, unpack=True)
10 assert hist['Status'] == 'SUCCESS/UNPACK'
11 log = nzbget.api.loadlog(int(hist['ID']), 0, 1000)
12 renamed = False
13 for entry in log:
14 print(entry['Text'])
15 if entry['Text'].find('Successfully renamed') > -1 and entry['Text'].find('archive') == -1:
16 renamed = True
17 assert renamed == True
18
19
20 def test_rarrename_rar3(nserv, nzbget):
21 hist = nzbget.download_nzb('rarrename3.nzb', unpack=True)
22 assert hist['Status'] == 'SUCCESS/UNPACK'
23
24 def test_rarrename_rar5(nserv, nzbget):
25 hist = nzbget.download_nzb('rarrename5.nzb', unpack=True)
26 assert hist['Status'] == 'SUCCESS/UNPACK'
27
28 def test_rarrename_rar3oldnam(nserv, nzbget):
29 hist = nzbget.download_nzb('rarrename3oldnam.nzb', unpack=True)
30 assert hist['Status'] == 'SUCCESS/UNPACK'
31
32 def test_rarrename_rar3badext(nserv, nzbget):
33 hist = nzbget.download_nzb('rarrename3badext.nzb', unpack=True)
34 assert hist['Status'] == 'SUCCESS/UNPACK'
35
36 def test_rarrename_rar5badext(nserv, nzbget):
37 hist = nzbget.download_nzb('rarrename5badext.nzb', unpack=True)
38 assert hist['Status'] == 'SUCCESS/UNPACK'
39
40 def test_rarrename_2sets(nserv, nzbget):
41 hist = nzbget.download_nzb('rarrename2sets.nzb', unpack=True)
42 assert hist['Status'] == 'SUCCESS/UNPACK'
43
44 def test_rarrename_rar3damaged(nserv, nzbget):
45 nzb_content = nzbget.load_nzb('rarrename3sm.nzb')
46 nzb_content = nzb_content.replace('abc.32?14=6500:500', 'abc.32?14=6500:500!2')
47 hist = nzbget.download_nzb('rarrename3sm.nzb', nzb_content, unpack=True)
48 assert hist['Status'] == 'SUCCESS/UNPACK'
49
50 def test_rarrename_rar3encdata(nserv, nzbget):
51 hist = nzbget.download_nzb('rarrename3encdata.nzb', unpack=True, params=[('*unpack:password', '123')])
52 assert hist['Status'] == 'SUCCESS/UNPACK'
53
54 def test_rarrename_rar5encdata(nserv, nzbget):
55 hist = nzbget.download_nzb('rarrename5encdata.nzb', unpack=True, params=[('*unpack:password', '123')])
56 assert hist['Status'] == 'SUCCESS/UNPACK'
57
58 def test_rarrename_rar3encnam(nserv, nzbget):
59 hist = nzbget.download_nzb('rarrename3encnam.nzb', unpack=True, params=[('*unpack:password', '123')])
60 assert hist['Status'] == 'SUCCESS/UNPACK'
61
62 def test_rarrename_rar5encnam(nserv, nzbget):
63 hist = nzbget.download_nzb('rarrename5encnam.nzb', unpack=True, params=[('*unpack:password', '123')])
64 assert hist['Status'] == 'SUCCESS/UNPACK'
65
66 def test_rarrename_rar3ignoreext(nserv, nzbget):
67 hist = nzbget.download_nzb('rar3ignoreext.nzb', unpack=True)
68 assert hist['Status'] == 'SUCCESS/HEALTH'
69
70
71 def test_rename_obf1(nserv, nzbget):
72 hist = nzbget.download_nzb('obfuscated1.nzb', unpack=True)
73 assert hist['Status'] == 'SUCCESS/UNPACK'
74
75 def test_rename_obf1ch(nserv, nzbget):
76 nzb_content = nzbget.load_nzb('obfuscated1.nzb')
77 nzb_content = nzb_content.replace(';5mb.7z', ';abc')
78 nzb_content = nzb_content.replace(';parrename', ';def')
79 nzb_content = nzb_content.replace('.par2&', '&')
80 hist = nzbget.download_nzb('obfuscated1-changed.nzb', nzb_content, unpack=True)
81 assert hist['Status'] == 'SUCCESS/UNPACK'
82
83 def test_rename_obf2(nserv, nzbget):
84 hist = nzbget.download_nzb('obfuscated2.nzb', unpack=True)
85 assert hist['Status'] == 'SUCCESS/UNPACK'
+0
-17
tests/functional/rename/rename_opt1_test.py less more
0 nzbget_options = ['ParRename=no', 'RarRename=no', 'ParCheck=manual', 'DirectRename=no']
1
2 def test_rename_obf1(nserv, nzbget):
3 hist = nzbget.download_nzb('obfuscated1.nzb', unpack=True)
4 assert hist['Status'] == 'WARNING/DAMAGED'
5
6 def test_rename_obf1ch(nserv, nzbget):
7 nzb_content = nzbget.load_nzb('obfuscated1.nzb')
8 nzb_content = nzb_content.replace(';5mb.7z', ';abc')
9 nzb_content = nzb_content.replace(';parrename.par2', ';def')
10 nzb_content = nzb_content.replace('.par2&', '&')
11 hist = nzbget.download_nzb('obfuscated1-changed.nzb', nzb_content, unpack=True)
12 assert hist['Status'] == 'WARNING/DAMAGED'
13
14 def test_rename_obf2(nserv, nzbget):
15 hist = nzbget.download_nzb('obfuscated2.nzb', unpack=True)
16 assert hist['Status'] == 'SUCCESS/HEALTH'
+0
-83
tests/functional/rename/rename_opt2_test.py less more
0 nzbget_options = ['ParRename=no', 'RarRename=no', 'ParCheck=auto', 'DirectRename=yes']
1
2 def test_rename_obf1(nserv, nzbget):
3 hist = nzbget.download_nzb('obfuscated1.nzb', unpack=True)
4 assert hist['Status'] == 'SUCCESS/UNPACK'
5
6 def test_rename_obf1ch(nserv, nzbget):
7 nzb_content = nzbget.load_nzb('obfuscated1.nzb')
8 nzb_content = nzb_content.replace(';5mb.7z', ';abc')
9 nzb_content = nzb_content.replace(';parrename', ';def')
10 nzb_content = nzb_content.replace('.par2&', '&')
11 hist = nzbget.download_nzb('obfuscated1-changed.nzb', nzb_content, unpack=True)
12 assert hist['Status'] == 'SUCCESS/UNPACK'
13
14 def test_rename_obf2(nserv, nzbget):
15 hist = nzbget.download_nzb('obfuscated2.nzb', unpack=True)
16 assert hist['Status'] == 'SUCCESS/UNPACK'
17
18 def test_rename_obf3(nserv, nzbget):
19 hist = nzbget.download_nzb('obfuscated3.nzb', unpack=True)
20 assert hist['Status'] == 'SUCCESS/UNPACK'
21
22 def test_rename_obf1dm(nserv, nzbget):
23 nzb_content = nzbget.load_nzb('obfuscated1.nzb')
24 nzb_content = nzb_content.replace('abc.01?4=300000:100000', 'abc.01?4=300000:100000!0')
25 hist = nzbget.download_nzb('obfuscated1-damaged.nzb', nzb_content, unpack=True)
26 assert hist['Status'] == 'SUCCESS/UNPACK'
27
28 def test_rename_obf1dmf(nserv, nzbget):
29 nzb_content = nzbget.load_nzb('obfuscated1.nzb')
30 nzb_content = nzb_content.replace('abc.01?1=0:100000', 'abc.01?1=0:100000!0')
31 hist = nzbget.download_nzb('obfuscated1-damaged-first.nzb', nzb_content, unpack=True)
32 assert hist['Status'] == 'SUCCESS/UNPACK'
33
34 def test_rename_obf1dmf2(nserv, nzbget):
35 nzb_content = nzbget.load_nzb('obfuscated1.nzb')
36 nzb_content = nzb_content.replace('abc.01?1=0:100000', 'abc.01?1=0:100000!0')
37 nzb_content = nzb_content.replace('abc.00?1=0:108', 'abc.00?1=0:108!0')
38 hist = nzbget.download_nzb('obfuscated1-damaged-first2.nzb', nzb_content, unpack=True)
39 assert hist['Status'] == 'SUCCESS/UNPACK'
40
41 def test_rename_obf1dmp(nserv, nzbget):
42 nzb_content = nzbget.load_nzb('obfuscated1.nzb')
43 nzb_content = nzb_content.replace('parrename.vol0+1.par2?1=0:57736', 'parrename.vol0+1.par2?1=0:57736!0')
44 hist = nzbget.download_nzb('obfuscated1-damaged-par.nzb', nzb_content, unpack=True)
45 assert hist['Status'] == 'SUCCESS/UNPACK'
46
47 def test_rename_obf3dm(nserv, nzbget):
48 nzb_content = nzbget.load_nzb('obfuscated3.nzb')
49 nzb_content = nzb_content.replace('abc.01?17=1600000:100000', 'abc.01?17=1600000:100000!0')
50 hist = nzbget.download_nzb('obfuscated3-damaged.nzb', nzb_content, unpack=True)
51 assert hist['Status'] == 'SUCCESS/UNPACK'
52
53 def test_rename_obf3dmf(nserv, nzbget):
54 nzb_content = nzbget.load_nzb('obfuscated3.nzb')
55 nzb_content = nzb_content.replace('abc.01?11=0:100000', 'abc.01?11=0:100000!0')
56 hist = nzbget.download_nzb('obfuscated3-damaged-first.nzb', nzb_content, unpack=True)
57 assert hist['Status'] == 'SUCCESS/UNPACK'
58
59 def test_rename_obf3dmf2(nserv, nzbget):
60 nzb_content = nzbget.load_nzb('obfuscated3.nzb')
61 nzb_content = nzb_content.replace('abc.01?11=0:100000', 'abc.01?11=0:100000!0')
62 nzb_content = nzb_content.replace('abc.00?1=0:4704', 'abc.00?1=0:4704!0')
63 hist = nzbget.download_nzb('obfuscated3-damaged-first2.nzb', nzb_content, unpack=True)
64 assert hist['Status'] == 'WARNING/HEALTH'
65
66 def test_renameparchecker_healthy(nserv, nzbget):
67 hist = nzbget.download_nzb('parchecker.nzb')
68 assert hist['Status'] == 'SUCCESS/HEALTH'
69
70 def test_parchecker_repair(nserv, nzbget):
71 nzb_content = nzbget.load_nzb('parchecker.nzb')
72 nzb_content = nzb_content.replace('parchecker/testfile.dat?1=0:3000', 'parchecker/testfile.dat?1=0:3000!0')
73 hist = nzbget.download_nzb('parchecker.repair.nzb', nzb_content)
74 assert hist['Status'] == 'SUCCESS/PAR'
75
76 def test_parchecker_dmp(nserv, nzbget):
77 nzb_content = nzbget.load_nzb('parchecker.nzb')
78 nzb_content = nzb_content.replace('parchecker/testfile.par2?1=0:3000', 'parchecker/testfile.par2?1=0:3000!0')
79 hist = nzbget.download_nzb('parchecker.damagedpar.nzb', nzb_content)
80 assert hist['Status'] == 'SUCCESS/HEALTH'
81 for entry in nzbget.api.loadlog(hist['ID'], 0, 10000):
82 assert entry['Kind'] != 'ERROR', entry['Text']
+0
-83
tests/functional/rename/rename_opt3_test.py less more
0 nzbget_options = ['ParRename=yes', 'RarRename=yes', 'ParCheck=auto', 'DirectRename=yes']
1
2 def test_rename_obf1(nserv, nzbget):
3 hist = nzbget.download_nzb('obfuscated1.nzb', unpack=True)
4 assert hist['Status'] == 'SUCCESS/UNPACK'
5
6 def test_rename_obf1ch(nserv, nzbget):
7 nzb_content = nzbget.load_nzb('obfuscated1.nzb')
8 nzb_content = nzb_content.replace(';5mb.7z', ';abc')
9 nzb_content = nzb_content.replace(';parrename', ';def')
10 nzb_content = nzb_content.replace('.par2&', '&')
11 hist = nzbget.download_nzb('obfuscated1-changed.nzb', nzb_content, unpack=True)
12 assert hist['Status'] == 'SUCCESS/UNPACK'
13
14 def test_rename_obf2(nserv, nzbget):
15 hist = nzbget.download_nzb('obfuscated2.nzb', unpack=True)
16 assert hist['Status'] == 'SUCCESS/UNPACK'
17
18 def test_rename_obf3(nserv, nzbget):
19 hist = nzbget.download_nzb('obfuscated3.nzb', unpack=True)
20 assert hist['Status'] == 'SUCCESS/UNPACK'
21
22 def test_rename_obf1dm(nserv, nzbget):
23 nzb_content = nzbget.load_nzb('obfuscated1.nzb')
24 nzb_content = nzb_content.replace('abc.01?4=300000:100000', 'abc.01?4=300000:100000!0')
25 hist = nzbget.download_nzb('obfuscated1-damaged.nzb', nzb_content, unpack=True)
26 assert hist['Status'] == 'SUCCESS/UNPACK'
27
28 def test_rename_obf1dmf(nserv, nzbget):
29 nzb_content = nzbget.load_nzb('obfuscated1.nzb')
30 nzb_content = nzb_content.replace('abc.01?1=0:100000', 'abc.01?1=0:100000!0')
31 hist = nzbget.download_nzb('obfuscated1-damaged-first.nzb', nzb_content, unpack=True)
32 assert hist['Status'] == 'SUCCESS/UNPACK'
33
34 def test_rename_obf1dmf2(nserv, nzbget):
35 nzb_content = nzbget.load_nzb('obfuscated1.nzb')
36 nzb_content = nzb_content.replace('abc.01?1=0:100000', 'abc.01?1=0:100000!0')
37 nzb_content = nzb_content.replace('abc.00?1=0:108', 'abc.00?1=0:108!0')
38 hist = nzbget.download_nzb('obfuscated1-damaged-first2.nzb', nzb_content, unpack=True)
39 assert hist['Status'] == 'SUCCESS/UNPACK'
40
41 def test_rename_obf1dmp(nserv, nzbget):
42 nzb_content = nzbget.load_nzb('obfuscated1.nzb')
43 nzb_content = nzb_content.replace('parrename.vol0+1.par2?1=0:57736', 'parrename.vol0+1.par2?1=0:57736!0')
44 hist = nzbget.download_nzb('obfuscated1-damaged-par.nzb', nzb_content, unpack=True)
45 assert hist['Status'] == 'SUCCESS/UNPACK'
46
47 def test_rename_obf3dm(nserv, nzbget):
48 nzb_content = nzbget.load_nzb('obfuscated3.nzb')
49 nzb_content = nzb_content.replace('abc.01?17=1600000:100000', 'abc.01?17=1600000:100000!0')
50 hist = nzbget.download_nzb('obfuscated3-damaged.nzb', nzb_content, unpack=True)
51 assert hist['Status'] == 'SUCCESS/UNPACK'
52
53 def test_rename_obf3dmf(nserv, nzbget):
54 nzb_content = nzbget.load_nzb('obfuscated3.nzb')
55 nzb_content = nzb_content.replace('abc.01?11=0:100000', 'abc.01?11=0:100000!0')
56 hist = nzbget.download_nzb('obfuscated3-damaged-first.nzb', nzb_content, unpack=True)
57 assert hist['Status'] == 'SUCCESS/UNPACK'
58
59 def test_rename_obf3dmf2(nserv, nzbget):
60 nzb_content = nzbget.load_nzb('obfuscated3.nzb')
61 nzb_content = nzb_content.replace('abc.01?11=0:100000', 'abc.01?11=0:100000!0')
62 nzb_content = nzb_content.replace('abc.00?1=0:4704', 'abc.00?1=0:4704!0')
63 hist = nzbget.download_nzb('obfuscated3-damaged-first2.nzb', nzb_content, unpack=True)
64 assert hist['Status'] == 'SUCCESS/UNPACK'
65
66 def test_parchecker_healthy(nserv, nzbget):
67 hist = nzbget.download_nzb('parchecker.nzb')
68 assert hist['Status'] == 'SUCCESS/HEALTH'
69
70 def test_parchecker_repair(nserv, nzbget):
71 nzb_content = nzbget.load_nzb('parchecker.nzb')
72 nzb_content = nzb_content.replace('parchecker/testfile.dat?1=0:3000', 'parchecker/testfile.dat?1=0:3000!0')
73 hist = nzbget.download_nzb('parchecker.repair.nzb', nzb_content)
74 assert hist['Status'] == 'SUCCESS/PAR'
75
76 def test_parchecker_dmp(nserv, nzbget):
77 nzb_content = nzbget.load_nzb('parchecker.nzb')
78 nzb_content = nzb_content.replace('parchecker/testfile.par2?1=0:3000', 'parchecker/testfile.par2?1=0:3000!0')
79 hist = nzbget.download_nzb('parchecker.damagedpar.nzb', nzb_content)
80 assert hist['Status'] == 'SUCCESS/HEALTH'
81 for entry in nzbget.api.loadlog(hist['ID'], 0, 10000):
82 assert entry['Kind'] != 'ERROR', entry['Text']
+0
-43
windows/README-WINDOWS.txt less more
0 =====================================
1 NZBGet ReadMe for Windows
2 =====================================
3
4 This is a short documentation. For more info visit
5 http://nzbget.net/Installation_on_Windows
6
7 =====================================
8
9 NZBGet can be used in application mode (tray icon and optional
10 DOS window) or as a service. When you use the program for the
11 first time you should start it at least once in application mode
12 to create the necessary configuration file from template.
13
14
15 =====================
16 Provided batch-file:
17 =====================
18
19 nzbget-command-shell.bat
20 Starts console window (DOS box) where you can execute remote
21 commands to communicate with running NZBGet.
22
23
24 =====================
25 Service mode
26 =====================
27
28 First you need to install the service.
29 From NZBGet shell (batch file nzbget-shell.bat) use command:
30 nzbget -install
31
32 To remove the service use command:
33 nzbget -remove
34
35 To start service:
36 net start NZBGet
37
38 To stop service:
39 net stop NZBGet
40
41 ===================================================================
42 For description of the program and more information see file README.
+0
-282
windows/install-update.bat less more
0 @echo off
1
2 rem
3 rem Batch file to update nzbget from web-interface
4 rem
5 rem Copyright (C) 2015-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
6 rem
7 rem This program is free software; you can redistribute it and/or modify
8 rem it under the terms of the GNU General Public License as published by
9 rem the Free Software Foundation; either version 2 of the License, or
10 rem (at your option) any later version.
11 rem
12 rem This program is distributed in the hope that it will be useful,
13 rem but WITHOUT ANY WARRANTY; without even the implied warranty of
14 rem MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 rem GNU General Public License for more details.
16 rem
17 rem You should have received a copy of the GNU General Public License
18 rem along with this program. If not, see <http://www.gnu.org/licenses/>.
19 rem
20
21 title Updating NZBGet
22
23 rem make sure the commands "tasklist", "find" and "ping" use default system programs
24 set PATH=%SystemRoot%\system32;%PATH%
25
26 if "%1"=="/step2" goto STEP2
27 if "%1"=="/step3" goto STEP3
28
29 if x%NZBUP_BRANCH%==x (
30 echo This script is executed by NZBGet during update and is not supposed to be started manually by user.
31 echo.
32 echo.To update NZBGet go to Web-interface - Settings - System - Check for updates.
33 echo.
34 pause
35 exit
36 )
37
38 @setlocal enabledelayedexpansion
39
40 rem extracting link to update-info-URL from "webui\package-info.json"
41 set UPDATE_INFO_LINK=
42 for /f "delims=" %%a in ('type "%NZBOP_WEBDIR%\package-info.json"') do (
43 set line=%%a
44 set line=!line:update-info-link=!
45 if not %%a==!line! (
46 set UPDATE_INFO_LINK=!line!
47 rem deleting tabs, spaces, quotation marks and commas
48 set UPDATE_INFO_LINK=!UPDATE_INFO_LINK: =!
49 set UPDATE_INFO_LINK=!UPDATE_INFO_LINK: =!
50 set UPDATE_INFO_LINK=!UPDATE_INFO_LINK:"=!
51 set UPDATE_INFO_LINK=!UPDATE_INFO_LINK:,=!
52 rem deleting the leading colon
53 set UPDATE_INFO_LINK=!UPDATE_INFO_LINK:~1%!
54 )
55 )
56
57 rem "%~dp0" means the location of the current batch file
58 set NZBGET_DIR=%~dp0
59 cd /D %NZBGET_DIR%
60
61 rem Determine if NZBGet is running as a service
62 set NZBGET_SERVICE=no
63 for /F "tokens=3 delims=: " %%H in ('sc query "NZBGet" ^| findstr " STATE"') do (
64 if /I "%%H" EQU "RUNNING" (
65 set NZBGET_SERVICE=yes
66 )
67 )
68
69 echo Downloading version information...
70 rem using special command "-B webget" NZBGet works like a simple wget
71 rem and fetches files from web-servers
72 nzbget.exe -B webget "%TEMP%\NZBGET_UPDATE.txt" "%UPDATE_INFO_LINK%"
73 if errorlevel 1 goto DOWNLOAD_FAILURE
74
75 rem extracting version number from info file
76 if %NZBUP_BRANCH%==TESTING set VER_FIELD=testing-version
77 if %NZBUP_BRANCH%==STABLE set VER_FIELD=stable-version
78 set VER=0
79 for /f "delims=" %%a in ('type "%TEMP%\NZBGET_UPDATE.txt"') do (
80 set line=%%a
81 set line=!line:%VER_FIELD%=!
82 if not %%a==!line! (
83 set VER=!line!
84 rem deleting tabs, spaces, quotation marks, colons and commas
85 set VER=!VER: =!
86 set VER=!VER: =!
87 set VER=!VER:"=!
88 set VER=!VER::=!
89 set VER=!VER:,=!
90 )
91 )
92
93 rem extracting setup URL from info file
94 if %NZBUP_BRANCH%==TESTING set VER_FIELD=testing-download
95 if %NZBUP_BRANCH%==STABLE set VER_FIELD=stable-download
96 set DNL_URL=
97 for /f "delims=" %%a in ('type "%TEMP%\NZBGET_UPDATE.txt"') do (
98 set line=%%a
99 set line=!line:%VER_FIELD%=!
100 if not %%a==!line! (
101 set DNL_URL=!line!
102 rem deleting tabs, spaces, quotation marks and commas
103 set DNL_URL=!DNL_URL: =!
104 set DNL_URL=!DNL_URL: =!
105 set DNL_URL=!DNL_URL:"=!
106 set DNL_URL=!DNL_URL:,=!
107 rem delete first character (colon)
108 set DNL_URL=!DNL_URL:~1,1000!
109 )
110 )
111
112 rem extracting signature URL from info file
113 if %NZBUP_BRANCH%==TESTING set VER_FIELD=testing-signature
114 if %NZBUP_BRANCH%==STABLE set VER_FIELD=stable-signature
115 set SIG_URL=
116 for /f "delims=" %%a in ('type "%TEMP%\NZBGET_UPDATE.txt"') do (
117 set line=%%a
118 set line=!line:%VER_FIELD%=!
119 if not %%a==!line! (
120 set SIG_URL=!line!
121 rem deleting tabs, spaces, quotation marks and commas
122 set SIG_URL=!SIG_URL: =!
123 set SIG_URL=!SIG_URL: =!
124 set SIG_URL=!SIG_URL:"=!
125 set SIG_URL=!SIG_URL:,=!
126 rem delete first character (colon)
127 set SIG_URL=!SIG_URL:~1,1000!
128 )
129 )
130
131 SET SIG_FILE=nzbget-%VER%.sig.txt
132 echo Downloading verification signature...
133 nzbget.exe -B webget "%TEMP%\%SIG_FILE%" "%SIG_URL%"
134 if errorlevel 1 goto DOWNLOAD_FAILURE
135
136 SET SETUP_EXE=nzbget-%VER%-bin-win32-setup.exe
137
138 echo Downloading %SETUP_EXE%...
139 nzbget.exe -B webget "%TEMP%\%SETUP_EXE%" "%DNL_URL%"
140 if errorlevel 1 goto DOWNLOAD_FAILURE
141
142 echo Verifying package authenticity...
143 nzbget.exe -B verify "%NZBOP_APPDIR%\pubkey.pem" "%TEMP%\%SIG_FILE%" "%TEMP%\%SETUP_EXE%"
144 if not "%ERRORLEVEL%"=="93" (
145 del "%TEMP%\%SIG_FILE%"
146 del "%TEMP%\%SETUP_EXE%"
147 goto VERIFY_FAILURE
148 )
149
150 del "%TEMP%\%SIG_FILE%"
151
152 rem using ping as wait-command, the third parameter (2) causes ping to wait 1 (one) second
153 ping 127.0.0.1 -n 2 -w 1000 > nul
154
155 echo Stopping NZBGet and installing update...
156 ping 127.0.0.1 -n 2 -w 1000 > nul
157
158 rem After NZBGet is stopped the script cannot pring any messages to web-interface
159 rem In order for user to see any error messages we start another instance of the
160 rem script with its own a console window.
161 rem We need to do that because of another reeson too. When the update is installed
162 rem it is possible that the script "install-update.bat" will be updated too.
163 rem In that case the command interpreter will go grazy because it doesn't like the
164 rem batch files being replaced during execution.
165 copy install-update.bat "%TEMP%\nzbget-update.bat" > nul
166 if errorlevel 1 goto COPYSCRIPT_FAILURE
167 start "Updating NZBGet" /I /MIN CALL "%TEMP%\nzbget-update.bat" /step2 "%NZBGET_DIR%" %SETUP_EXE% %NZBGET_SERVICE%
168
169 echo [NZB] QUIT
170
171 exit
172
173
174 :STEP3
175 echo Third stage
176 goto UPDATE
177
178 :STEP2
179 echo Second stage
180
181 :UPDATE
182 rem init from command line params
183 set NZBGET_DIR=%2
184 set NZBGET_DIR=%NZBGET_DIR:"=%
185 cd "%NZBGET_DIR%"
186 set SETUP_EXE=%3
187 set NZBGET_SERVICE=%4
188
189 rem in service mode redirecting the output into install-update.log
190 if "%1"=="/step2" (
191 if "%NZBGET_SERVICE%"=="yes" (
192 "%TEMP%\nzbget-update.bat" /step3 "%NZBGET_DIR%" %SETUP_EXE% %NZBGET_SERVICE% > "%NZBGET_DIR%\install-update.log" 2>&1
193 )
194 )
195
196 rem check if nzbget.exe is running
197 echo Stopping NZBGet...
198 echo.
199
200 tasklist 2> nul > nul
201 if errorlevel 1 goto WINXPHOME
202
203 set WAIT_SECONDS=30
204 :CHECK_RUNNING
205 if "%WAIT_SECONDS%"=="0" goto QUIT_FAILURE
206 tasklist 2> nul | find /I /N "nzbget.exe" > nul
207 if "%ERRORLEVEL%"=="0" (
208 ping 127.0.0.1 -n 2 -w 1000 > nul
209 set /a "WAIT_SECONDS=%WAIT_SECONDS%-1"
210 goto CHECK_RUNNING
211 )
212
213 goto INSTALL
214
215 :WINXPHOME
216 rem Alternative solution when command "tasklist" isn't available:
217 rem just wait 30 seconds
218 ping 127.0.0.1 -n 31 -w 1000 > nul
219
220 :INSTALL
221
222 echo Installing new version...
223 echo.
224 "%TEMP%\%SETUP_EXE%" /S
225
226 del "%TEMP%\%SETUP_EXE%"
227
228 echo Starting NZBGet...
229
230 if "%NZBGET_SERVICE%"=="yes" (
231 net start NZBGet
232 ) else (
233 start /MIN nzbget.exe -app -auto -s
234 )
235 if errorlevel 1 goto START_FAILURE
236 ping 127.0.0.1 -n 2 -w 1000 > nul
237 exit
238
239
240 :DOWNLOAD_FAILURE
241 rem This is in the first instance, the error is printed to web-interface
242 echo.
243 echo [ERROR] ***********************************************
244 echo [ERROR] Download failed, please try again later
245 echo [ERROR] ***********************************************
246 echo.
247 exit
248
249
250 :VERIFY_FAILURE
251 rem This is in the first instance, the error is printed to web-interface
252 echo.
253 echo [ERROR] ***********************************************
254 echo [ERROR] Package authenticity verification failed
255 echo [ERROR] ***********************************************
256 echo.
257 exit
258
259
260 :COPYSCRIPT_FAILURE
261 rem This is in the first instance, the error is printed to web-interface
262 echo.
263 echo [ERROR] ***********************************************
264 echo [ERROR] Failed to copy the update script
265 echo [ERROR] ***********************************************
266 echo.
267 exit
268
269
270 :QUIT_FAILURE
271 rem This is in the second instance, the error is printed to console window
272 start "Error during update" CMD /c "echo ERROR: Failed to stop NZBGet && pause"
273 ping 127.0.0.1 -n 11 -w 1000 > nul
274 exit
275
276
277 :START_FAILURE
278 rem This is in the second instance, the error is printed to console window
279 start "Error during update" CMD /c "echo ERROR: Failed to start NZBGet && pause"
280 ping 127.0.0.1 -n 11 -w 1000 > nul
281 exit
+0
-34
windows/nzbget-command-shell.bat less more
0 @echo off
1
2 rem
3 rem Batch file to start nzbget shell
4 rem
5 rem Copyright (C) 2009 orbisvicis <orbisvicis@users.sourceforge.net>
6 rem Copyright (C) 2009-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
7 rem
8 rem This program is free software; you can redistribute it and/or modify
9 rem it under the terms of the GNU General Public License as published by
10 rem the Free Software Foundation; either version 2 of the License, or
11 rem (at your option) any later version.
12 rem
13 rem This program is distributed in the hope that it will be useful,
14 rem but WITHOUT ANY WARRANTY; without even the implied warranty of
15 rem MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 rem GNU General Public License for more details.
17 rem
18 rem You should have received a copy of the GNU General Public License
19 rem along with this program. If not, see <http://www.gnu.org/licenses/>.
20 rem
21
22 rem ####################### Usage instructions #######################
23 rem
24 rem After starting the batch file you can use all nzbget commands
25 rem (like nzbget -s, nzbget -L, etc) without typing the full
26 rem path to nzbget executable.
27 rem
28 rem ####################### End of Usage instructions #######################
29
30
31 rem expression "%~dp0" means the location of an executing batch file
32 set PATH=%PATH%;%~dp0
33 cmd /U /K "cd %USERPROFILE% & nzbget"
+0
-4
windows/package-info.json less more
0 {
1 "update-info-link": "http://nzbget.net/info/nzbget-version-win32.json",
2 "install-script": "install-update.bat"
3 }
windows/resources/mainicon.ico less more
Binary diff not shown
+0
-235
windows/resources/nzbget.rc less more
0 // Microsoft Visual C++ generated resource script.
1 //
2 #include "resource.h"
3
4 #define APSTUDIO_READONLY_SYMBOLS
5 /////////////////////////////////////////////////////////////////////////////
6 //
7 // Generated from the TEXTINCLUDE 2 resource.
8 //
9 #include "afxres.h"
10 /////////////////////////////////////////////////////////////////////////////
11 #undef APSTUDIO_READONLY_SYMBOLS
12
13 /////////////////////////////////////////////////////////////////////////////
14 // Neutral resources
15
16 #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU)
17 #ifdef _WIN32
18 LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
19 #pragma code_page(1252)
20 #endif //_WIN32
21
22 /////////////////////////////////////////////////////////////////////////////
23 //
24 // Menu
25 //
26
27 IDR_TRAYMENU MENU
28 BEGIN
29 POPUP "Menu"
30 BEGIN
31 MENUITEM "Show Web-Interface", ID_SHOWWEBUI
32 POPUP "Show in Windows Explorer"
33 BEGIN
34 MENUITEM "Default Destination", ID_SHOW_DESTDIR
35 MENUITEM SEPARATOR
36 MENUITEM SEPARATOR
37 MENUITEM "Intermediate Files", ID_SHOW_INTERDIR
38 MENUITEM "Incoming NZBs", ID_SHOW_NZBDIR
39 MENUITEM "Scripts", ID_SHOW_SCRIPTDIR
40 MENUITEM SEPARATOR
41 MENUITEM "Config-File", ID_SHOW_CONFIGFILE
42 MENUITEM "Log-File", ID_SHOW_LOGFILE
43 END
44 POPUP "Info-Links"
45 BEGIN
46 MENUITEM "Home Page", ID_INFO_HOMEPAGE
47 MENUITEM "Downloads", ID_INFO_DOWNLOADS
48 MENUITEM "Forum", ID_INFO_FORUM
49 END
50 POPUP "Troubleshooting"
51 BEGIN
52 MENUITEM "Restart", ID_TROUBLESHOOTING_RESTART
53 MENUITEM "Open Config-File in a Text Editor", ID_TROUBLESHOOTING_OPENCONFIG
54 MENUITEM SEPARATOR
55 MENUITEM "Reset to Factory Defaults", ID_TROUBLESHOOTING_FACTORYRESET
56 END
57 MENUITEM SEPARATOR
58 MENUITEM "About...", ID_ABOUT
59 MENUITEM "Preferences...", ID_PREFERENCES
60 MENUITEM SEPARATOR
61 MENUITEM "Exit", ID_EXIT
62 END
63 END
64
65
66 /////////////////////////////////////////////////////////////////////////////
67 //
68 // Icon
69 //
70
71 // Icon with lowest ID value placed first to ensure application icon
72 // remains consistent on all systems.
73 IDI_MAINICON ICON "mainicon.ico"
74 IDI_TRAYICON_IDLE ICON "trayicon_idle.ico"
75 IDI_TRAYICON_PAUSED ICON "trayicon_paused.ico"
76 IDI_TRAYICON_WORKING ICON "trayicon_working.ico"
77
78 /////////////////////////////////////////////////////////////////////////////
79 //
80 // Dialog
81 //
82
83 IDD_ABOUTBOX DIALOGEX 0, 0, 176, 194
84 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
85 CAPTION "About NZBGet"
86 FONT 8, "Tahoma", 400, 0, 0x0
87 BEGIN
88 DEFPUSHBUTTON "OK",IDOK,63,173,50,14
89 CTEXT "Version 15.0-testing-r1200",IDC_ABOUT_VERSION,16,70,144,8
90 CTEXT "Lightweight usenet downloader",IDC_STATIC,16,83,144,8
91 CTEXT "http://nzbget.net",IDC_ABOUT_HOMEPAGE,55,144,64,9,SS_NOTIFY
92 CTEXT "Copyright © 2007-2017 Andrey Prygunkov",IDC_STATIC,16,156,144,8
93 ICON "",IDC_ABOUT_ICON,67,7,21,20
94 CTEXT "NZBGet",IDC_ABOUT_NAME,16,51,144,16
95 CTEXT "The package includes other software; see program's folder for licenses.",IDC_STATIC,16,121,144,20
96 CTEXT "NZBGet is free software; use it under the terms of the ",IDC_STATIC,16,99,144,20
97 CTEXT "GNU General Public License",IDC_ABOUT_GPL,62,107,90,8,SS_NOTIFY
98 LTEXT ".",IDC_STATIC,151,107,8,8,SS_NOTIFY
99 END
100
101 IDD_PREFDIALOG DIALOGEX 0, 0, 243, 174
102 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
103 CAPTION "NZBGet Preferences"
104 FONT 8, "Tahoma", 400, 0, 0x0
105 BEGIN
106 DEFPUSHBUTTON "OK",IDOK,132,153,50,14
107 PUSHBUTTON "Cancel",IDCANCEL,186,153,50,14
108 LTEXT "*",IDC_STATIC,13,109,8,9
109 CONTROL "Start at login *",IDC_PREF_AUTOSTART,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,13,58,10
110 CONTROL "Show console window",IDC_PREF_CONSOLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,37,86,10
111 CONTROL "Show in tray (near clock)",IDC_PREF_TRAY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,25,94,10
112 CONTROL "Show Web-Interface on start",IDC_PREF_WEBUI,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,49,108,10
113 LTEXT "Only Windows-specific options are located here. For all other options see Settings page in Web-Interface.",IDC_STATIC,22,128,214,17
114 LTEXT "NZBGet can also run as Windows service. See README-WINDOWS.txt for details.",IDC_STATIC,21,107,207,16
115 CONTROL "Single click pauses/resumes, double click does nothing",IDC_PREF_TRAYPAUSE,
116 "Button",BS_AUTORADIOBUTTON,13,78,207,10
117 CONTROL "Double click opens web-interface, single click does nothing",IDC_PREF_TRAYWEBUI,
118 "Button",BS_AUTORADIOBUTTON,13,89,202,10
119 LTEXT "Tray icon behavior",IDC_STATIC,13,65,60,8
120 END
121
122 IDD_FACTORYRESETDIALOG DIALOGEX 0, 0, 297, 76
123 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
124 CAPTION "NZBGet"
125 FONT 8, "Tahoma", 400, 0, 0x0
126 BEGIN
127 PUSHBUTTON "Erase and Reset",IDC_FACTORYRESET_RESET,131,55,90,14
128 LTEXT "Reset to factory defaults?",IDC_FACTORYRESET_TITLE,54,7,236,13
129 ICON "",IDC_FACTORYRESET_ICON,7,7,20,20
130 LTEXT "All settings will be reset to defaults. The download queue, history, statistics, log-file, default incoming nzb-directory and default scripts-directory will be erased.",IDC_FACTORYRESET_TEXT,54,21,236,27
131 DEFPUSHBUTTON "Cancel",IDC_FACTORYRESET_CANCEL,227,55,63,14
132 END
133
134 IDD_RUNNINGDIALOG DIALOGEX 0, 0, 342, 69
135 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
136 CAPTION "NZBGet"
137 FONT 8, "Tahoma", 400, 0, 0x0
138 BEGIN
139 DEFPUSHBUTTON "Show Web-Interface",IDC_RUNNING_WEBUI,54,48,90,14
140 LTEXT "NZBGet is already running.",IDC_RUNNING_TITLE,54,7,272,13
141 ICON "",IDC_RUNNING_ICON,7,7,21,20
142 LTEXT "Please use tray icon near clock to acces the program's menu.",IDC_RUNNING_TEXT,54,21,276,18
143 PUSHBUTTON "Open Preferences...",IDC_RUNNING_PREFS,149,48,90,14
144 PUSHBUTTON "Quit NZBGet",IDC_RUNNING_QUIT,245,48,90,14
145 PUSHBUTTON "OK",IDC_RUNNING_OK,140,48,61,14,NOT WS_VISIBLE
146 END
147
148
149 /////////////////////////////////////////////////////////////////////////////
150 //
151 // DESIGNINFO
152 //
153
154 #ifdef APSTUDIO_INVOKED
155 GUIDELINES DESIGNINFO
156 BEGIN
157 IDD_ABOUTBOX, DIALOG
158 BEGIN
159 LEFTMARGIN, 16
160 RIGHTMARGIN, 160
161 TOPMARGIN, 7
162 BOTTOMMARGIN, 187
163 END
164
165 IDD_PREFDIALOG, DIALOG
166 BEGIN
167 LEFTMARGIN, 7
168 RIGHTMARGIN, 236
169 VERTGUIDE, 13
170 TOPMARGIN, 7
171 BOTTOMMARGIN, 167
172 END
173
174 IDD_FACTORYRESETDIALOG, DIALOG
175 BEGIN
176 LEFTMARGIN, 7
177 RIGHTMARGIN, 290
178 VERTGUIDE, 54
179 TOPMARGIN, 7
180 BOTTOMMARGIN, 69
181 END
182 END
183 #endif // APSTUDIO_INVOKED
184
185 #endif // Neutral resources
186 /////////////////////////////////////////////////////////////////////////////
187
188
189 /////////////////////////////////////////////////////////////////////////////
190 // German (Germany) resources
191
192 #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU)
193 #ifdef _WIN32
194 LANGUAGE LANG_GERMAN, SUBLANG_GERMAN
195 #pragma code_page(1252)
196 #endif //_WIN32
197
198 #ifdef APSTUDIO_INVOKED
199 /////////////////////////////////////////////////////////////////////////////
200 //
201 // TEXTINCLUDE
202 //
203
204 1 TEXTINCLUDE
205 BEGIN
206 "resource.h\0"
207 END
208
209 3 TEXTINCLUDE
210 BEGIN
211 "\r\0"
212 END
213
214 2 TEXTINCLUDE
215 BEGIN
216 "#include ""afxres.h""\r\0"
217 END
218
219 #endif // APSTUDIO_INVOKED
220
221 #endif // German (Germany) resources
222 /////////////////////////////////////////////////////////////////////////////
223
224
225
226 #ifndef APSTUDIO_INVOKED
227 /////////////////////////////////////////////////////////////////////////////
228 //
229 // Generated from the TEXTINCLUDE 3 resource.
230 //
231
232 /////////////////////////////////////////////////////////////////////////////
233 #endif // not APSTUDIO_INVOKED
234
+0
-67
windows/resources/resource.h less more
0 //{{NO_DEPENDENCIES}}
1 // Microsoft Visual C++ generated include file.
2 // Used by nzbget.rc
3 //
4 #define IDI_MAINICON 101
5 #define IDR_TRAYMENU 102
6 #define IDI_TRAYICON_IDLE 102
7 #define IDD_ABOUTBOX 103
8 #define IDI_TRAYICON_PAUSED 103
9 #define IDI_TRAYICON_WORKING 104
10 #define IDD_PREFDIALOG 105
11 #define IDD_RUNNINGDIALOG 106
12 #define IDD_FACTORYRESETDIALOG 107
13 #define IDC_ABOUT_ICON 1001
14 #define IDC_ABOUT_VERSION 1002
15 #define IDC_ABOUT_HOMEPAGE 1003
16 #define IDC_ABOUT_NAME 1004
17 #define IDC_PREF_AUTOSTART 1005
18 #define IDC_ABOUT_GPL 1005
19 #define IDC_PREF_CONSOLE 1006
20 #define IDC_PREF_TRAY 1007
21 #define IDC_PREF_WEBUI 1008
22 #define IDC_RUNNING_ICON 1009
23 #define IDC_RUNNING_TITLE 1010
24 #define IDC_RUNNING_TEXT 1011
25 #define IDC_QUIT 1013
26 #define IDC_RUNNING_QUIT 1013
27 #define IDC_RUNNING_PREFS 1014
28 #define IDC_RUNNING_WEBUI 1015
29 #define IDC_RUNNING_OK 1016
30 #define IDC_FACTORYRESET_CANCEL 1016
31 #define IDC_FACTORYRESET_RESET 1017
32 #define IDC_FACTORYRESET_TEXT 1018
33 #define IDC_FACTORYRESET_TITLE 1019
34 #define IDC_FACTORYRESET_ICON 1020
35 #define IDC_PREF_TRAYPAUSE 1021
36 #define IDC_PREF_TRAYWEBUI 1022
37 #define ID_SHOWWEBUI 40004
38 #define ID_ABOUT 40005
39 #define ID_EXIT 40006
40 #define ID_MENU_INFO 40007
41 #define ID_INFO_HOMEPAGE 40008
42 #define ID_INFO_DOWNLOADS 40009
43 #define ID_INFO_FORUM 40010
44 #define ID_Menu 40011
45 #define ID_PREFERENCES 40012
46 #define ID_SHOW_CONFIGFILE 40020
47 #define ID_SHOW_LOGFILE 40021
48 #define ID_SHOW_DESTDIR 40022
49 #define ID_SHOW_INTERDIR 40023
50 #define ID_SHOW_NZBDIR 40024
51 #define ID_SHOW_SCRIPTDIR 40025
52 #define ID_MENU_TROUBLESHOOTING 40026
53 #define ID_TROUBLESHOOTING_RESTART 40027
54 #define ID_TROUBLESHOOTING_OPENCONFIG 40032
55 #define ID_TROUBLESHOOTING_FACTORYRESET 40036
56
57 // Next default values for new objects
58 //
59 #ifdef APSTUDIO_INVOKED
60 #ifndef APSTUDIO_READONLY_SYMBOLS
61 #define _APS_NEXT_RESOURCE_VALUE 106
62 #define _APS_NEXT_COMMAND_VALUE 40037
63 #define _APS_NEXT_CONTROL_VALUE 1023
64 #define _APS_NEXT_SYMED_VALUE 101
65 #endif
66 #endif
windows/resources/trayicon_idle.ico less more
Binary diff not shown
windows/resources/trayicon_paused.ico less more
Binary diff not shown
windows/resources/trayicon_working.ico less more
Binary diff not shown
windows/setup/install.bmp less more
Binary diff not shown
+0
-265
windows/setup/nzbget-setup.nsi less more
0 /*
1 * This file is part of nzbget. See <http://nzbget.net>.
2 *
3 * Copyright (C) 2014-2016 Andrey Prygunkov <hugbug@users.sourceforge.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 ; This is setup script for NZBGet for Windows. To compile the script you need
20 ; NSIS (http://nsis.sourceforge.net). Moreover a special build of NSIS must be
21 ; installed over standard NSIS installation. This special build provides
22 ; extra logging required by the install script:
23 ; - Speical build with extra logging - http://nsis.sourceforge.net/Special%5FBuilds
24 ; The install script also requires additional plugins:
25 ; - NSIS Simple Service Plugin - http://nsis.sourceforge.net/NSIS_Simple_Service_Plugin
26 ; - AccessControl plug-in - http://nsis.sourceforge.net/AccessControl_plug-in
27
28
29 ;--------------------------------
30 ;Includes
31
32 !include "MUI2.nsh"
33 !include "FileFunc.nsh"
34 !include "LogicLib.nsh"
35 !include "WinVer.nsh"
36
37 ;--------------------------------
38 ;General
39
40 Name "NZBGet"
41 OutFile "..\nzbget-setup.exe"
42
43 ;Default installation folder
44 InstallDir "$PROGRAMFILES\NZBGet"
45
46 ;Get installation folder from registry if available
47 InstallDirRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\NZBGet" "InstallLocation"
48
49 !ifndef DEBUG_UI
50 ;Request application privileges for Windows Vista
51 RequestExecutionLevel admin
52 !endif
53
54 ;--------------------------------
55 ;Interface Settings
56
57 ; !define MUI_ABORTWARNING
58
59 !define MUI_ICON "..\resources\mainicon.ico"
60 !define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\orange-uninstall.ico"
61
62 !define MUI_WELCOMEFINISHPAGE_BITMAP "install.bmp"
63 !define MUI_UNWELCOMEFINISHPAGE_BITMAP "uninstall.bmp"
64
65 !define MUI_FINISHPAGE_RUN
66 !define MUI_FINISHPAGE_RUN_FUNCTION RunAction
67 !define MUI_FINISHPAGE_SHOWREADME ""
68 !define MUI_FINISHPAGE_SHOWREADME_NOTCHECKED
69 !define MUI_FINISHPAGE_SHOWREADME_TEXT "Create Desktop Shortcut"
70 !define MUI_FINISHPAGE_SHOWREADME_FUNCTION FinishPageAction
71
72 ;--------------------------------
73 ;Pages
74
75 !insertmacro MUI_PAGE_WELCOME
76 !insertmacro MUI_PAGE_LICENSE "..\NZBGet\COPYING"
77 !insertmacro MUI_PAGE_DIRECTORY
78 !insertmacro MUI_PAGE_INSTFILES
79 !define MUI_PAGE_CUSTOMFUNCTION_SHOW MyFinishShow
80 !define MUI_PAGE_CUSTOMFUNCTION_LEAVE MyFinishLeave
81 !insertmacro MUI_PAGE_FINISH
82
83 !insertmacro MUI_UNPAGE_WELCOME
84 !insertmacro MUI_UNPAGE_CONFIRM
85 !insertmacro MUI_UNPAGE_INSTFILES
86 !insertmacro MUI_UNPAGE_FINISH
87
88 ;--------------------------------
89 ;Languages
90
91 !insertmacro MUI_LANGUAGE "English"
92
93 ;--------------------------------
94 ;Installer Sections
95
96 Section "Main"
97
98 Delete "$INSTDIR\install.log"
99
100 ; Command "LogSet" requires a special build of NSIS supporting extended logging:
101 ; http://nsis.sourceforge.net/Special%5FBuilds
102 LogSet on
103
104 SetOutPath "$INSTDIR"
105
106 ; Stop NZBGet (if running)
107 ${If} ${FileExists} "$INSTDIR\nzbget.exe"
108 Delete "$INSTDIR\nzbget.exe"
109 ExecWait '"$INSTDIR\nzbget.exe" -Q' $R2
110 DetailPrint "Stopping NZBGet..."
111
112 try_delete:
113 ; Wait up to 10 seconds until stopped
114 StrCpy $R2 20
115 ${While} ${FileExists} "$INSTDIR\nzbget.exe"
116 ${If} $R2 = 0
117 ${Break}
118 ${EndIf}
119 Sleep 500
120 IntOp $R2 $R2 - 1
121 Delete "$INSTDIR\nzbget.exe"
122 ${EndWhile}
123
124 ${If} ${FileExists} "$INSTDIR\nzbget.exe"
125 MessageBox MB_RETRYCANCEL "NZBGet seems to be running right now. Please stop NZBGet and try again." \
126 IDRETRY try_delete IDCANCEL cancel
127 cancel:
128 abort
129 ${EndIf}
130 ${EndIf}
131
132 !ifndef DEBUG_UI
133
134 File "..\NZBGet\*"
135 SetOutPath "$INSTDIR\webui"
136 File /r "..\NZBGet\webui\*"
137
138 ${If} ${FileExists} "$INSTDIR\nzbget.conf"
139 ; When updating a portable installation install all scripts into exe-directory
140 SetOutPath "$INSTDIR\scripts"
141 ${Else}
142 ; In default mode install all scripts into app-data-directory
143 SetShellVarContext all
144 SetOutPath "$APPDATA\NZBGet\scripts"
145 # Make directory "$APPDATA\NZBGet" full access by all users
146 AccessControl::GrantOnFile "$APPDATA\NZBGet" "(BU)" "FullAccess"
147 Pop $0
148 SetShellVarContext current
149 ${EndIf}
150 File "..\NZBGet\scripts\*"
151
152 !endif
153
154 ; Create shortcuts
155 CreateDirectory "$SMPROGRAMS\NZBGet"
156 CreateShortCut "$SMPROGRAMS\NZBGet\NZBGet.lnk" "$INSTDIR\nzbget.exe"
157 CreateShortCut "$SMPROGRAMS\NZBGet\Uninstall.lnk" "$INSTDIR\Uninstall.exe"
158
159 ; Add control panel entry for Uninstall
160 WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\NZBGet" "DisplayName" "NZBGet"
161 WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\NZBGet" "UninstallString" "$\"$INSTDIR\uninstall.exe$\""
162 WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\NZBGet" "Publisher" "Andrey Prygunkov"
163 WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\NZBGet" "InstallLocation" "$INSTDIR"
164
165 ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2
166 IntFmt $0 "0x%08X" $0
167 WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\NZBGet" "EstimatedSize" "$0"
168
169 ; Create uninstaller
170 WriteUninstaller "$INSTDIR\Uninstall.exe"
171
172 SectionEnd
173
174
175 Function FinishPageAction
176
177 ; Create desktop shortcut
178 CreateShortcut "$DESKTOP\NZBGet.lnk" "$INSTDIR\nzbget.exe"
179
180 ; Refresh desktop window
181 System::Call 'Shell32::SHChangeNotify(i 0x8000000, i 0, i 0, i 0)'
182
183 FunctionEnd
184
185
186 Function RunAction
187
188 ${If} ${AtLeastWinVista}
189 ; Starting NZBGet with standard user privileges
190 Exec "runas /trustlevel:0x20000 $\"$INSTDIR\nzbget.exe$\""
191 ${Else}
192 ; Starting NZBGet with current privileges
193 Exec "$INSTDIR\nzbget.exe"
194 ${EndIf}
195
196 FunctionEnd
197
198
199 ; Add an extra checkbox for file association
200 var Checkbox
201 var Checkbox_State
202
203 Function MyFinishShow
204 ${NSD_CreateCheckbox} 120u 130u 100% 10u "Associate With NZB Files"
205 Pop $Checkbox
206 SetCtlColors $Checkbox "" "ffffff"
207 FunctionEnd
208
209 Function MyFinishLeave
210 ${NSD_GetState} $Checkbox $Checkbox_State
211 ${If} $Checkbox_State <> 0
212
213 WriteRegStr HKCR ".nzb" "" "NZBGet.NZBFile"
214 WriteRegStr HKCR "NZBGet.NZBFile" "" `NZB File`
215 WriteRegStr HKCR "NZBGet.NZBFile\DefaultIcon" "" `$INSTDIR\nzbget.exe,00`
216 WriteRegStr HKCR "NZBGet.NZBFile\shell" "" "open"
217 WriteRegStr HKCR "NZBGet.NZBFile\shell\open" "" `Open with NZBGet`
218 WriteRegStr HKCR "NZBGet.NZBFile\shell\open\command" "" `$INSTDIR\nzbget.exe -app -A $\"%1$\"`
219
220 System::Call 'Shell32::SHChangeNotify(i 0x8000000, i 0, i 0, i 0)'
221
222 ${EndIf}
223 FunctionEnd
224
225
226 ;--------------------------------
227 ;Uninstaller Section
228
229 Section "Uninstall"
230
231 ; Stop service (if installed)
232 SimpleSC::StopService "NZBGet" 1 30
233 Pop $0 ; returns an errorcode (<>0) otherwise success (0)
234
235 ; Remove a service
236 SimpleSC::RemoveService "NZBGet"
237 Pop $0 ; returns an errorcode (<>0) otherwise success (0)
238
239 try_delete:
240 Delete "$INSTDIR\nzbget.exe"
241 IfFileExists "$INSTDIR\nzbget.exe" 0 not_running
242 MessageBox MB_RETRYCANCEL "File nzbget.exe could not be deleted. Please make sure the program isn't running." \
243 IDRETRY try_delete IDCANCEL cancel
244 cancel:
245 quit
246 not_running:
247
248 RMDir /r "$INSTDIR"
249 RMDir /r "$SMPROGRAMS\NZBGet"
250 Delete "$DESKTOP\NZBGet.lnk"
251
252 DeleteRegKey HKCU "Software\NZBGet"
253 DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\NZBGet"
254
255 ReadRegStr $R0 HKCR ".nzb" ""
256 ${If} $R0 == "NZBGet.NZBFile"
257 DeleteRegKey HKCR `NZBGet.NZBFile`
258 DeleteRegValue HKCR ".nzb" ""
259 ${EndIf}
260
261 ; Refresh desktop window
262 System::Call 'Shell32::SHChangeNotify(i 0x8000000, i 0, i 0, i 0)'
263
264 SectionEnd
windows/setup/uninstall.bmp less more
Binary diff not shown