New upstream version 19.1~r2031+dfsg
Andreas Moog
6 years ago
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 | # 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 | 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 | ||
0 | 4 | nzbget-19.0: |
1 | 5 | - unpack during downloading: |
2 | 6 | - downloaded files can now be unpacked as soon as every archive part is |
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 | } |
0 | 0 | #! /bin/sh |
1 | 1 | # 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. | |
3 | 3 | # |
4 | 4 | # Report bugs to <hugbug@users.sourceforge.net>. |
5 | 5 | # |
573 | 573 | # Identity of this package. |
574 | 574 | PACKAGE_NAME='nzbget' |
575 | 575 | 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' | |
578 | 578 | PACKAGE_BUGREPORT='hugbug@users.sourceforge.net' |
579 | 579 | |
580 | 580 | ac_unique_file="daemon/main/nzbget.cpp" |
1254 | 1254 | # Omit some internal or obsolete options to make the list less imposing. |
1255 | 1255 | # This message is too long to be a string in the A/UX 3.1 sh. |
1256 | 1256 | 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. | |
1258 | 1258 | |
1259 | 1259 | Usage: $0 [OPTION]... [VAR=VALUE]... |
1260 | 1260 | |
1325 | 1325 | |
1326 | 1326 | if test -n "$ac_init_help"; then |
1327 | 1327 | case $ac_init_help in |
1328 | short | recursive ) echo "Configuration of nzbget 19.0:";; | |
1328 | short | recursive ) echo "Configuration of nzbget 19.1-testing:";; | |
1329 | 1329 | esac |
1330 | 1330 | cat <<\_ACEOF |
1331 | 1331 | |
1476 | 1476 | test -n "$ac_init_help" && exit $ac_status |
1477 | 1477 | if $ac_init_version; then |
1478 | 1478 | cat <<\_ACEOF |
1479 | nzbget configure 19.0 | |
1479 | nzbget configure 19.1-testing | |
1480 | 1480 | generated by GNU Autoconf 2.61 |
1481 | 1481 | |
1482 | 1482 | Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, |
1490 | 1490 | This file contains any messages produced by compilers while |
1491 | 1491 | running configure, to aid debugging if configure makes a mistake. |
1492 | 1492 | |
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 | |
1494 | 1494 | generated by GNU Autoconf 2.61. Invocation command line was |
1495 | 1495 | |
1496 | 1496 | $ $0 $@ |
2286 | 2286 | |
2287 | 2287 | # Define the identity of the package. |
2288 | 2288 | PACKAGE='nzbget' |
2289 | VERSION='19.0' | |
2289 | VERSION='19.1-testing' | |
2290 | 2290 | |
2291 | 2291 | |
2292 | 2292 | cat >>confdefs.h <<_ACEOF |
12296 | 12296 | # report actual input values of CONFIG_FILES etc. instead of their |
12297 | 12297 | # values after options handling. |
12298 | 12298 | 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 | |
12300 | 12300 | generated by GNU Autoconf 2.61. Invocation command line was |
12301 | 12301 | |
12302 | 12302 | CONFIG_FILES = $CONFIG_FILES |
12349 | 12349 | _ACEOF |
12350 | 12350 | cat >>$CONFIG_STATUS <<_ACEOF |
12351 | 12351 | ac_cs_version="\\ |
12352 | nzbget config.status 19.0 | |
12352 | nzbget config.status 19.1-testing | |
12353 | 12353 | configured by $0, generated by GNU Autoconf 2.61, |
12354 | 12354 | with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" |
12355 | 12355 |
20 | 20 | # Process this file with autoconf to produce a configure script. |
21 | 21 | |
22 | 22 | 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) | |
24 | 24 | AC_CONFIG_AUX_DIR(posix) |
25 | 25 | AC_CANONICAL_TARGET |
26 | 26 | AM_INIT_AUTOMAKE([foreign]) |
421 | 421 | { |
422 | 422 | debug("WaitNextVolume for %s", filename); |
423 | 423 | |
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 | ||
424 | 436 | BString<1024> fullFilename("%s%c%s", *m_destDir, PATH_SEPARATOR, filename); |
425 | 437 | if (FileSystem::FileExists(fullFilename)) |
426 | 438 | { |
267 | 267 | uint16 size = ((uint16)buf[6] << 8) + buf[5]; |
268 | 268 | |
269 | 269 | uint32 blocksize = size; |
270 | if (m_encrypted) | |
271 | { | |
272 | // Align to 16 bytes | |
273 | blocksize = (blocksize + ((~blocksize + 1) & (16 - 1))); | |
274 | } | |
275 | ||
270 | 276 | block.trailsize = blocksize - sizeof(buf); |
271 | 277 | |
272 | 278 | uint8 addbuf[4]; |
223 | 223 | volume.GetVolumeNo() == lastVolume->GetVolumeNo() + 1 && |
224 | 224 | volume.GetVersion() == lastVolume->GetVersion() && |
225 | 225 | 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()))) | |
230 | 230 | { |
231 | 231 | debug(" adding %s", FileSystem::BaseFileName(volume.GetFilename())); |
232 | 232 | set.push_back(&volume); |
236 | 236 | } |
237 | 237 | } |
238 | 238 | |
239 | bool completed = !set.back()->GetHasNextVolume(); | |
239 | RarVolume* lastVolume = set.back(); | |
240 | bool completed = !lastVolume->GetHasNextVolume() && | |
241 | (lastVolume->GetFiles()->empty() || !lastVolume->GetFiles()->back().GetSplitAfter()); | |
240 | 242 | |
241 | 243 | return !completed; |
242 | 244 | }), |
102 | 102 | |
103 | 103 | if (m_hasRarFiles) |
104 | 104 | { |
105 | if (m_hasUnpackedRarFiles) | |
105 | if (m_hasNotUnpackedRarFiles || m_unpackDirCreated) | |
106 | 106 | { |
107 | 107 | if (m_postInfo->GetNzbInfo()->GetDirectUnpackStatus() == NzbInfo::nsSuccess) |
108 | 108 | { |
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 | } | |
110 | 117 | } |
118 | ||
119 | // Discard info about extracted archives to prevent reusing on next unpack attempt | |
120 | m_postInfo->GetExtractedArchives()->clear(); | |
121 | ||
111 | 122 | UnpackArchives(upUnrar, false); |
112 | 123 | } |
113 | 124 | else |
605 | 616 | const char* destDir = !m_finalDir.Empty() ? *m_finalDir : *m_destDir; |
606 | 617 | |
607 | 618 | m_unpackDir.Format("%s%c%s", destDir, PATH_SEPARATOR, "_unpack"); |
619 | m_unpackDirCreated = !FileSystem::DirectoryExists(m_unpackDir); | |
608 | 620 | |
609 | 621 | detail("Unpacking into %s", *m_unpackDir); |
610 | 622 | |
636 | 648 | if (regExRar.Match(filename)) |
637 | 649 | { |
638 | 650 | m_hasRarFiles = true; |
639 | m_hasUnpackedRarFiles |= std::find( | |
651 | m_hasNotUnpackedRarFiles |= std::find( | |
640 | 652 | m_postInfo->GetExtractedArchives()->begin(), |
641 | 653 | m_postInfo->GetExtractedArchives()->end(), |
642 | 654 | filename) == m_postInfo->GetExtractedArchives()->end(); |
72 | 72 | bool m_noFilesMessageReceived = false; |
73 | 73 | bool m_hasParFiles = false; |
74 | 74 | bool m_hasRarFiles = false; |
75 | bool m_hasUnpackedRarFiles = false; | |
75 | bool m_hasNotUnpackedRarFiles = false; | |
76 | 76 | bool m_hasRenamedArchiveFiles = false; |
77 | 77 | bool m_hasSevenZipFiles = false; |
78 | 78 | bool m_hasSevenZipMultiFiles = false; |
85 | 85 | bool m_cleanedUpDisk = false; |
86 | 86 | bool m_autoTerminated = false; |
87 | 87 | bool m_finalDirCreated = false; |
88 | bool m_unpackDirCreated = false; | |
88 | 89 | bool m_passListTried = false; |
89 | 90 | FileList m_joinedFiles; |
90 | 91 |
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 | /* | |
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 | /* | |
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 | /* | |
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 | /* | |
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 |
51 | 51 | <ClCompile> |
52 | 52 | <Optimization>Disabled</Optimization> |
53 | 53 | <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> | |
55 | 55 | <MinimalRebuild>false</MinimalRebuild> |
56 | 56 | <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> |
57 | 57 | <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> |
71 | 71 | <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> |
72 | 72 | <ClCompile> |
73 | 73 | <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> | |
75 | 75 | <ExceptionHandling>Sync</ExceptionHandling> |
76 | 76 | <RuntimeLibrary>MultiThreaded</RuntimeLibrary> |
77 | 77 | <PrecompiledHeader>Use</PrecompiledHeader> |
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 | /* | |
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 | /* | |
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 | /* | |
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 | /* | |
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 | <?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 | <?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 | // !$*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 | // | |
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 | // | |
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 | /* | |
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 | /* | |
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 | <?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 | /* | |
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 | /* | |
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 | {\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}}}⏎ |
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 | {\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 | 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 | 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 | 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 | /* | |
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 | /* | |
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 | /* | |
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 | /* | |
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 | <?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 | -----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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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=""', 'subject="') | |
16 | nzb_content = nzb_content.replace('" yEnc', '.dat yEnc') | |
17 | hist = nzbget.download_nzb('parchecker.subject.nzb', nzb_content) | |
18 | assert hist['Status'] == 'SUCCESS/PAR' |
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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | ===================================== | |
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 | @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 | @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 | { | |
1 | "update-info-link": "http://nzbget.net/info/nzbget-version-win32.json", | |
2 | "install-script": "install-update.bat" | |
3 | } |
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 | //{{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 |
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 |