def _get_inhibitor(self):
        log.info(LOGRPEFIX + "Windows OS check: %s" % windows_check())

        if windows_check():
            try:
                return WindowsInhibitor()
            except Exception, e:
                log.debug(LOGRPEFIX + "Could not initialise the windows inhibitor: %s" % e)
Example #2
0
    def enable(self):
        log.debug("[AutoShutDown] Enabling plugin...")
        if osx_check():
            log.error("[AutoShutDown] OSX not currently supported")
            #Using subprocess could call osascript
            #subprocess.call(['osascript', '-e', 'tell app "System Events" to shut down'])
            self.disable()

        if not windows_check():
            self.bus_name = UPOWER
            bus_path = UPOWER_PATH
            try:
                bus = dbus.SystemBus()
                self.bus_obj = bus.get_object(self.bus_name, bus_path)
            except:
                log.debug("[AutoShutDown] Fallback to older dbus PowerManagement")
                self.bus_name = POWERMAN
                bus_path = POWERMAN_PATH
                bus = dbus.Bus(dbus.Bus.TYPE_SESSION)
                self.bus_obj = bus.get_object(self.bus_name, bus_path)

            self.bus_iface = dbus.Interface(self.bus_obj, self.bus_name)
            self.bus_iface_props = dbus.Interface(self.bus_obj, 'org.freedesktop.DBus.Properties')

        self.config = deluge.configmanager.ConfigManager("autoshutdown.conf", DEFAULT_PREFS)
        self.check_suspend_hibernate_flags()

        component.get("EventManager").register_event_handler("TorrentFinishedEvent", self.on_event_torrent_finished)
Example #3
0
    def shutdown(self):
        if windows_check():
            import win32api

            win32api.CloseHandle(self.mutex)
        if self.listener:
            return self.listener.stopListening()
Example #4
0
class DaemonSecurityTestCase(BaseTestCase, DaemonBase, SecurityBaseTestCase):

    if windows_check():
        skip = 'windows can\'t start_core not enough arguments for format string'

    def __init__(self, testname):
        super(DaemonSecurityTestCase, self).__init__(testname)
        DaemonBase.__init__(self)
        SecurityBaseTestCase.__init__(self)

    def setUp(self):
        skip = False
        for not_http_test in ('breach', 'headers', 'ticketbleed'):
            if not_http_test in self.id().split('.')[-1]:
                self.skipTest(SecurityBaseTestCase.http_err)
                skip = True
        if not skip:
            super(DaemonSecurityTestCase, self).setUp()

    def set_up(self):
        d = self.common_set_up()
        self.port = self.listen_port
        d.addCallback(self.start_core)
        d.addErrback(self.terminate_core)
        return d

    def tear_down(self):
        d = component.shutdown()
        d.addCallback(self.terminate_core)
        return d
Example #5
0
    def add_process_arg_group(self):
        """Adds a grouping of common process args to control a daemon to the parser"""

        self.process_arg_group = True
        self.group = self.add_argument_group(_('Process Control Options'))
        self.group.add_argument('-P',
                                '--pidfile',
                                metavar='<pidfile>',
                                action='store',
                                help=_('Pidfile to store the process id'))
        if not common.windows_check():
            self.group.add_argument(
                '-d',
                '--do-not-daemonize',
                dest='donotdaemonize',
                action='store_true',
                help=_('Do not daemonize (fork) this process'))
            self.group.add_argument('-f',
                                    '--fork',
                                    dest='donotdaemonize',
                                    action='store_false',
                                    help=argparse.SUPPRESS)  # Deprecated arg
            self.group.add_argument(
                '-U',
                '--user',
                metavar='<user>',
                action='store',
                help=_('Change to this user on startup (Requires root)'))
            self.group.add_argument(
                '-g',
                '--group',
                metavar='<group>',
                action='store',
                help=_('Change to this group on startup (Requires root)'))
Example #6
0
    def _get_inhibitor(self):
        if windows_check():
            try:
                log.debug('Creating Windows inhibitor')
                return WindowsInhibitor()
            except Exception as e:
                log.debug('Could not initialise the Windows inhibitor: %s' % e)
        else:
            try:
                log.debug('Creating Gnome session inhibitor')
                return GnomeSessionInhibitor()
            except Exception as e:
                log.debug(
                    'Could not initialise the Gnome session inhibitor: %s' % e)

            try:
                log.debug('Creating Freedesktop inhibitor')
                return DBusInhibitor(
                    'org.freedesktop.PowerManagement',
                    '/org/freedesktop/PowerManagement/Inhibit',
                    'org.freedesktop.PowerManagement.Inhibit')
            except Exception as e:
                log.debug(
                    'Could not initialise the Freedesktop inhibitor: %s' % e)

            try:
                log.debug('Creating Gnome inhibitor')
                return DBusInhibitor('org.gnome.PowerManager',
                                     '/org/gnome/PowerManager',
                                     'org.gnome.PowerManager')
            except Exception as e:
                log.debug('Could not initialise the gnome inhibitor: %s' % e)

        log.error('Could not initialize any inhibitor')
        return None
Example #7
0
class ConsoleScriptEntryWithDaemonTestCase(
    BaseTestCase, ConsoleUIWithDaemonBaseTestCase
):

    if windows_check():
        skip = 'cannot test console ui on windows'

    def __init__(self, testname):
        super(ConsoleScriptEntryWithDaemonTestCase, self).__init__(testname)
        ConsoleUIWithDaemonBaseTestCase.__init__(self)
        self.var['cmd_name'] = 'deluge-console'
        self.var['sys_arg_cmd'] = ['./deluge-console']

    def set_up(self):
        from deluge.ui.console.console import Console

        def start_console():
            return Console().start()

        self.patch(deluge.ui.console, 'start', start_console)
        self.var['start_cmd'] = deluge.ui.console.start

        return ConsoleUIWithDaemonBaseTestCase.set_up(self)

    def tear_down(self):
        return ConsoleUIWithDaemonBaseTestCase.tear_down(self)
Example #8
0
    def test_files_tab5(self):
        if windows_check():
            raise unittest.SkipTest('on windows \\ != / for path names')
        self.filestab.files_list[self.t_id] = (
            {
                'index': 0,
                'path': '1/test_10.txt',
                'offset': 0,
                'size': 13
            },
            {
                'index': 1,
                'path': '2/test_100.txt',
                'offset': 13,
                'size': 14
            },
        )
        self.filestab.update_files()
        self.filestab._on_torrentfilerenamed_event(self.t_id, self.index,
                                                   '1/test_100.txt')

        ret = self.verify_treestore(
            self.filestab.treestore,
            [['1/', [['test_100.txt'], ['test_10.txt']]]])
        if not ret:
            self.print_treestore('Treestore not expected:',
                                 self.filestab.treestore)
        self.assertTrue(ret)
Example #9
0
    def enable(self):
        log.debug("[AutoShutDown] Enabling plugin...")
        if osx_check():
            log.error("[AutoShutDown] OSX not currently supported")
            #Using subprocess could call osascript
            #subprocess.call(['osascript', '-e', 'tell app "System Events" to shut down'])
            self.disable()

        if not windows_check():
            try:
                bus = dbus.SystemBus()
                try:
                    self.bus_name = LOGIN1
                    self.bus_obj = bus.get_object(self.bus_name, LOGIN1_PATH)
                    self.bus_iface = dbus.Interface(self.bus_obj,
                                                    self.bus_name + '.Manager')
                except DBusException:
                    self.bus_name = UPOWER
                    self.bus_obj = bus.get_object(self.bus_name, UPOWER_PATH)
                    self.bus_iface = dbus.Interface(self.bus_obj,
                                                    self.bus_name)
            except:
                log.debug(
                    "[AutoShutDown] Fallback to older dbus PowerManagement")
                bus = dbus.Bus(dbus.Bus.TYPE_SESSION)
                self.bus_name = POWERMAN
                self.bus_obj = bus.get_object(self.bus_name, POWERMAN_PATH)
                self.bus_iface = dbus.Interface(self.bus_obj, self.bus_name)

        self.config = deluge.configmanager.ConfigManager(
            "autoshutdown.conf", DEFAULT_PREFS)
        self.check_suspend_hibernate_flags()

        component.get("EventManager").register_event_handler(
            "TorrentFinishedEvent", self.on_event_torrent_finished)
Example #10
0
def setup_logger(level='error', filename=None, filemode='w', logrotate=None,
                 output_stream=sys.stdout, twisted_observer=True):
    """
    Sets up the basic logger and if `:param:filename` is set, then it will log
    to that file instead of stdout.

    Args:
        level (str): The log level to use (Default: 'error')
        filename (str, optional): The log filename. Default is None meaning log
                                  to terminal
        filemode (str): The filemode to use when opening the log file
        logrotate (int, optional): The size of the logfile in bytes when enabling
                                   log rotation (Default is None meaning disabled)
        output_stream (file descriptor): File descriptor to log to if not logging to file
        twisted_observer (bool): Whether to setup the custom twisted logging observer.
    """
    if logging.getLoggerClass() is not Logging:
        logging.setLoggerClass(Logging)
        logging.addLevelName(5, 'TRACE')
        logging.addLevelName(1, 'GARBAGE')

    level = levels.get(level, logging.ERROR)

    root_logger = logging.getLogger()

    if filename and logrotate:
        handler = logging.handlers.RotatingFileHandler(
            filename, maxBytes=logrotate,
            backupCount=5, encoding='utf-8'
        )
    elif filename and filemode == 'w':
        handler_cls = logging.FileHandler
        if not common.windows_check():
            handler_cls = getattr(logging.handlers, 'WatchedFileHandler', logging.FileHandler)
        handler = handler_cls(filename, mode=filemode, encoding='utf-8')
    else:
        handler = logging.StreamHandler(stream=output_stream)

    handler.setLevel(level)

    formatter = logging.Formatter(
        DEFAULT_LOGGING_FORMAT % MAX_LOGGER_NAME_LENGTH,
        datefmt='%H:%M:%S'
    )

    handler.setFormatter(formatter)

    # Check for existing handler to prevent duplicate logging.
    if root_logger.handlers:
        for handle in root_logger.handlers:
            if not isinstance(handle, type(handler)):
                root_logger.addHandler(handler)
    else:
        root_logger.addHandler(handler)
    root_logger.setLevel(level)

    if twisted_observer:
        twisted_logging = TwistedLoggingObserver()
        twisted_logging.start()
Example #11
0
    def __init__(self,
                 listen_interface=None,
                 interface=None,
                 port=None,
                 standalone=False,
                 read_only_config_keys=None):
        """
        Args:
            listen_interface (str, optional): The IP address to listen to bittorrent connections on.
            interface (str, optional): The IP address the daemon will listen for UI connections on.
            port (int, optional): The port the daemon will listen for UI connections on.
            standalone (bool, optional): If True the client is in Standalone mode otherwise, if
                False, start the daemon as separate process.
            read_only_config_keys (list of str, optional): A list of config keys that will not be
                altered by core.set_config() RPC method.
        """
        self.standalone = standalone
        self.pid_file = get_config_dir('deluged.pid')
        log.info('Deluge daemon %s', get_version())
        if is_daemon_running(self.pid_file):
            raise DaemonRunningError(
                'Deluge daemon already running with this config directory!')

        # Twisted catches signals to terminate, so just have it call the shutdown method.
        reactor.addSystemEventTrigger('before', 'shutdown', self._shutdown)

        # Catch some Windows specific signals
        if windows_check():

            def win_handler(ctrl_type):
                """Handle the Windows shutdown or close events."""
                log.debug('windows handler ctrl_type: %s', ctrl_type)
                if ctrl_type == CTRL_CLOSE_EVENT or ctrl_type == CTRL_SHUTDOWN_EVENT:
                    self._shutdown()
                    return 1

            SetConsoleCtrlHandler(win_handler)

        # Start the core as a thread and join it until it's done
        self.core = Core(listen_interface=listen_interface,
                         read_only_config_keys=read_only_config_keys)

        if port is None:
            port = self.core.config['daemon_port']
        self.port = port

        if interface and not is_ip(interface):
            log.error('Invalid UI interface (must be IP Address): %s',
                      interface)
            interface = None

        self.rpcserver = RPCServer(
            port=port,
            allow_remote=self.core.config['allow_remote'],
            listen=not standalone,
            interface=interface)

        log.debug('Listening to UI on: %s:%s and bittorrent on: %s', interface,
                  port, listen_interface)
Example #12
0
 def split(self, text):
     if windows_check():
         text = text.replace('\\', '\\\\')
     result = shlex.split(text)
     for i, s in enumerate(result):
         result[i] = s.replace(r'\ ', ' ')
     result = [s for s in result if s != '']
     return result
Example #13
0
 def split(self, text):
     if windows_check():
         text = text.replace('\\', '\\\\')
     result = shlex.split(text)
     for i, s in enumerate(result):
         result[i] = s.replace(r'\ ', ' ')
     result = [s for s in result if s != '']
     return result
Example #14
0
 def adjust_windows_shutdown_privileges(self):
     if not windows_check():
         log.error("Only usable on Windows platform")
         return
     flags = TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY
     htoken = OpenProcessToken(GetCurrentProcess(), flags)
     id = LookupPrivilegeValue(None, SE_SHUTDOWN_NAME)
     newPrivileges = [(id, SE_PRIVILEGE_ENABLED)]
     AdjustTokenPrivileges(htoken, 0, newPrivileges)
Example #15
0
 def adjust_windows_shutdown_privileges(self):
     if not windows_check():
         log.error("Only usable on Windows platform")
         return
     flags = TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY
     htoken = OpenProcessToken(GetCurrentProcess(), flags)
     id = LookupPrivilegeValue(None, SE_SHUTDOWN_NAME)
     newPrivileges = [(id, SE_PRIVILEGE_ENABLED)]
     AdjustTokenPrivileges(htoken, 0, newPrivileges)
Example #16
0
 def os_hibernate(self):
     log.info("[AutoShutDown] Hibernating...")
     if windows_check():
         bForceClose = False
         hibernate = True
         self.adjust_windows_shutdown_privileges()
         thread.start_new_thread(ctypes.windll.Powrprof.SetSuspendState,
                                 (hibernate, bForceClose, False))
     else:
         self.bus_iface.Hibernate(False)
Example #17
0
 def os_shutdown(self):
     log.info("[AutoShutDown] Shutting down...")
     if windows_check():
         timeout = 10
         message = "Deluge AutoShutdown Plugin shutting down the system after %s secs.\
                 This can be cancelled by entering 'shutdown -a' in the Run box\
             " % timeout
         self.adjust_windows_shutdown_privileges()
         InitiateSystemShutdown(None, message, timeout, 1, 0)
     else:
         self.bus_iface.Shutdown(False)
Example #18
0
    def enable(self):
        """Enables the system tray icon."""
        self.builder = Builder()
        self.builder.add_from_file(resource_filename('deluge.ui.gtkui', os.path.join(
            'glade', 'tray_menu.ui')))

        self.builder.connect_signals(self)

        self.tray_menu = self.builder.get_object('tray_menu')

        if appindicator and self.config['enable_appindicator']:
            log.debug('Enabling the Application Indicator...')
            self.indicator = appindicator.Indicator('deluge', 'deluge',
                                                    appindicator.CATEGORY_APPLICATION_STATUS)
            try:
                self.indicator.set_property('title', _('Deluge'))
            except TypeError:
                # Catch 'title' property error for previous appindicator versions
                pass
            # Pass the menu to the Application Indicator
            self.indicator.set_menu(self.tray_menu)

            # Make sure the status of the Show Window MenuItem is correct
            self._sig_win_hide = self.mainwindow.window.connect('hide', self._on_window_hide)
            self._sig_win_show = self.mainwindow.window.connect('show', self._on_window_show)
            if self.mainwindow.visible():
                self.builder.get_object('menuitem_show_deluge').set_active(True)
            else:
                self.builder.get_object('menuitem_show_deluge').set_active(False)

            # Show the Application Indicator
            self.indicator.set_status(appindicator.STATUS_ACTIVE)

        else:
            log.debug('Enabling the system tray icon..')
            if windows_check():
                self.tray = status_icon_new_from_pixbuf(get_logo(32))
            else:
                self.tray = status_icon_new_from_icon_name('deluge')

            self.tray.connect('activate', self.on_tray_clicked)
            self.tray.connect('popup-menu', self.on_tray_popup)

        self.builder.get_object('download-limit-image').set_from_file(get_pixmap('downloading16.png'))
        self.builder.get_object('upload-limit-image').set_from_file(get_pixmap('seeding16.png'))

        client.register_event_handler('ConfigValueChangedEvent', self.config_value_changed)
        if client.connected():
            # We're connected so we need to get some values from the core
            self.__start()
        else:
            # Hide menu widgets because we're not connected to a host.
            for widget in self.hide_widget_list:
                self.builder.get_object(widget).hide()
Example #19
0
 def os_hibernate(self):
         log.info("[AutoShutDown] Hibernating...")
         if windows_check():
             bForceClose=False
             hibernate = True
             self.adjust_windows_shutdown_privileges()
             thread.start_new_thread(
                 ctypes.windll.Powrprof.SetSuspendState, (hibernate, bForceClose, False)
             )
         else:
             self.bus_iface.Hibernate()
Example #20
0
 def os_shutdown(self):
         log.info("[AutoShutDown] Shutting down...")
         if windows_check():
             timeout = 10
             message = "Deluge AutoShutdown Plugin shutting down the system after %s secs.\
                 This can be cancelled by entering 'shutdown -a' in the Run box\
             " % timeout
             self.adjust_windows_shutdown_privileges()
             InitiateSystemShutdown(None, message, timeout, 1, 0)
         else:
             self.bus_iface.Shutdown()
Example #21
0
    def test_download_with_rename_sanitised(self):

        if windows_check():
            raise unittest.SkipTest('on windows \\  != / for path names')

        url = self.get_url('rename?filename=/etc/passwd')
        d = download_file(url, fname('original'))
        d.addCallback(self.assertEqual, fname('passwd'))
        d.addCallback(self.assertContains,
                      'This file should be called /etc/passwd')
        return d
Example #22
0
 def check_suspend_hibernate_flags(self):
     self.config["can_hibernate"] = False
     self.config["can_suspend"] = False
     if windows_check():
         pwr_states = GetPwrCapabilities()
         try:
             if pwr_states['HiberFilePresent'] and pwr_states['SystemS4']:
                 self.config["can_hibernate"] = True
             if pwr_states['SystemS1'] | pwr_states['SystemS2'] | pwr_states['SystemS3']:
                 self.config["can_suspend"] = True
         except KeyError, e:
             log.error("[AutoShutdown] Error reading system power capabilities: %s", e)
Example #23
0
    def test_open_state_from_python2(self):
        """Open a Python2 state with a UTF-8 encoded torrent filename."""
        shutil.copy(
            common.get_test_data_file('utf8_filename_torrents.state'),
            os.path.join(self.config_dir, 'state', 'torrents.state'),
        )
        if windows_check():
            raise unittest.SkipTest(
                'Windows ModuleNotFoundError due to Linux line ending')

        state = self.tm.open_state()
        self.assertEqual(len(state.torrents), 1)
Example #24
0
    def test_download_with_rename_exists(self):

        if windows_check():
            raise unittest.SkipTest('on windows \\  != / for path names')

        open(fname('renamed'), 'w').close()
        url = self.get_url('rename?filename=renamed')
        d = download_file(url, fname('original'))
        d.addCallback(self.assertEqual, fname('renamed-1'))
        d.addCallback(self.assertContains,
                      'This file should be called renamed')
        return d
Example #25
0
File: core.py Project: zluca/deluge
    def execute_commands(self, torrent_id, event, *arg):
        if event == 'added' and arg[0]:
            # No futher action as from_state (arg[0]) is True
            return
        elif event == 'removed':
            torrent_id, torrent_name, download_location = self.preremoved_cache.pop(
                torrent_id)
        else:
            torrent = component.get('TorrentManager').torrents[torrent_id]
            info = torrent.get_status(['name', 'download_location'])
            # Grab the torrent name and download location
            # getProcessOutputAndValue requires args to be str
            torrent_name = info['name']
            download_location = info['download_location']

        log.debug('Running commands for %s', event)

        def log_error(result, command):
            (stdout, stderr, exit_code) = result
            if exit_code:
                log.warning('Command "%s" failed with exit code %d', command,
                            exit_code)
                if stdout:
                    log.warning('stdout: %s', stdout)
                if stderr:
                    log.warning('stderr: %s', stderr)

        # Go through and execute all the commands
        for command in self.config['commands']:
            if command[EXECUTE_EVENT] == event:
                command = os.path.expandvars(command[EXECUTE_COMMAND])
                command = os.path.expanduser(command)

                cmd_args = [
                    torrent_id.encode('utf8'),
                    torrent_name.encode('utf8'),
                    download_location.encode('utf8'),
                ]
                if windows_check():
                    # Escape ampersand on windows (see #2784)
                    cmd_args = [
                        cmd_arg.replace('&', '^^^&') for cmd_arg in cmd_args
                    ]

                if os.path.isfile(command) and os.access(command, os.X_OK):
                    log.debug('Running %s with args: %s', command, cmd_args)
                    d = getProcessOutputAndValue(command,
                                                 cmd_args,
                                                 env=os.environ)
                    d.addCallback(log_error, command)
                else:
                    log.error('Execute script not found or not executable')
Example #26
0
def get_logo(size):
    """A Deluge logo.

    Params:
        size (int): Size of logo in pixels

    Returns:
        gtk.gdk.Pixbuf: deluge logo
    """
    filename = 'deluge.svg'
    if windows_check():
        filename = 'deluge.png'
    return get_pixbuf_at_size(filename, size)
Example #27
0
def get_logo(size):
    """A Deluge logo.

    Params:
        size (int): Size of logo in pixels

    Returns:
        gtk.gdk.Pixbuf: deluge logo
    """
    filename = 'deluge.svg'
    if windows_check():
        filename = 'deluge.png'
    return get_pixbuf_at_size(filename, size)
Example #28
0
class TrackerIconsTestCase(BaseTestCase):

    if windows_check():
        skip = 'cannot use os.path.samefile to compair on windows(unix only)'

    def set_up(self):
        # Disable resizing with Pillow for consistency.
        self.patch(deluge.ui.tracker_icons, 'Image', None)
        self.icons = TrackerIcons()

    def tear_down(self):
        return component.shutdown()

    def test_get_deluge_png(self):
        # Deluge has a png favicon link
        icon = TrackerIcon(common.get_test_data_file('deluge.png'))
        d = self.icons.fetch('deluge-torrent.org')
        d.addCallback(self.assertNotIdentical, None)
        d.addCallback(self.assertEqual, icon)
        return d

    def test_get_google_ico(self):
        # Google doesn't have any icon links
        # So instead we'll grab its favicon.ico
        icon = TrackerIcon(common.get_test_data_file('google.ico'))
        d = self.icons.fetch('www.google.com')
        d.addCallback(self.assertNotIdentical, None)
        d.addCallback(self.assertEqual, icon)
        return d

    def test_get_google_ico_with_redirect(self):
        # google.com redirects to www.google.com
        icon = TrackerIcon(common.get_test_data_file('google.ico'))
        d = self.icons.fetch('google.com')
        d.addCallback(self.assertNotIdentical, None)
        d.addCallback(self.assertEqual, icon)
        return d

    def test_get_seo_ico_with_sni(self):
        # seo using certificates with SNI support only
        raise SkipTest('Site certificate expired')
        icon = TrackerIcon(common.get_test_data_file('seo.ico'))
        d = self.icons.fetch('www.seo.com')
        d.addCallback(self.assertNotIdentical, None)
        d.addCallback(self.assertEqual, icon)
        return d

    def test_get_empty_string_tracker(self):
        d = self.icons.fetch('')
        d.addCallback(self.assertIdentical, None)
        return d
Example #29
0
    def __init__(self, listen_interface=None, interface=None, port=None, standalone=False,
                 read_only_config_keys=None):
        """
        Args:
            listen_interface (str, optional): The IP address to listen to bittorrent connections on.
            interface (str, optional): The IP address the daemon will listen for UI connections on.
            port (int, optional): The port the daemon will listen for UI connections on.
            standalone (bool, optional): If True the client is in Standalone mode otherwise, if
                False, start the daemon as separate process.
            read_only_config_keys (list of str, optional): A list of config keys that will not be
                altered by core.set_config() RPC method.
        """
        self.standalone = standalone
        self.pid_file = get_config_dir('deluged.pid')
        log.info('Deluge daemon %s', get_version())
        if is_daemon_running(self.pid_file):
            raise DaemonRunningError('Deluge daemon already running with this config directory!')

        # Twisted catches signals to terminate, so just have it call the shutdown method.
        reactor.addSystemEventTrigger('before', 'shutdown', self._shutdown)

        # Catch some Windows specific signals
        if windows_check():
            def win_handler(ctrl_type):
                """Handle the Windows shutdown or close events."""
                log.debug('windows handler ctrl_type: %s', ctrl_type)
                if ctrl_type == CTRL_CLOSE_EVENT or ctrl_type == CTRL_SHUTDOWN_EVENT:
                    self._shutdown()
                    return 1
            SetConsoleCtrlHandler(win_handler)

        # Start the core as a thread and join it until it's done
        self.core = Core(listen_interface=listen_interface,
                         read_only_config_keys=read_only_config_keys)

        if port is None:
            port = self.core.config['daemon_port']
        self.port = port

        if interface and not is_ip(interface):
            log.error('Invalid UI interface (must be IP Address): %s', interface)
            interface = None

        self.rpcserver = RPCServer(
            port=port,
            allow_remote=self.core.config['allow_remote'],
            listen=not standalone,
            interface=interface
        )

        log.debug('Listening to UI on: %s:%s and bittorrent on: %s', interface, port, listen_interface)
Example #30
0
    def on_tray_popup(self, status_icon, button, activate_time):
        """Called when the tray icon is right clicked."""
        self.blink(False)

        if self.mainwindow.visible():
            self.builder.get_object('menuitem_show_deluge').set_active(True)
        else:
            self.builder.get_object('menuitem_show_deluge').set_active(False)

        popup_function = status_icon_position_menu
        if windows_check() or osx_check():
            popup_function = None
            button = 0
        self.tray_menu.popup(None, None, popup_function, button, activate_time, status_icon)
Example #31
0
    def __init__(self, header, text, icon, buttons, parent=None):
        """
        :param header: str, the header portion of the dialog
        :param text: str, the text body of the dialog
        :param icon: gtk Stock ID, a stock id for the gtk icon to display
        :param buttons: tuple, of gtk stock ids and responses
        :param parent: gtkWindow, the parent window, if None it will default to the
            MainWindow
        """
        super(BaseDialog, self).__init__(
            title=header,
            parent=parent if parent else component.get('MainWindow').window,
            flags=gtk.DIALOG_MODAL
            | gtk.DIALOG_DESTROY_WITH_PARENT
            | gtk.DIALOG_NO_SEPARATOR,
            buttons=buttons,
        )

        self.set_icon(get_deluge_icon())

        self.connect('delete-event', self._on_delete_event)
        self.connect('response', self._on_response)

        # Setup all the formatting and such to make our dialog look pretty
        self.set_border_width(5)
        self.set_default_size(200, 100)
        hbox = gtk.HBox(spacing=5)
        image = gtk.Image()
        if not gtk.stock_lookup(icon) and (
            icon.endswith('.svg') or icon.endswith('.png')
        ):
            # Hack for Windows since it doesn't support svg
            if icon.endswith('.svg') and windows_check():
                icon = icon.rpartition('.svg')[0] + '16.png'
            image.set_from_pixbuf(get_pixbuf_at_size(icon, 32))
        else:
            image.set_from_stock(icon, gtk.ICON_SIZE_DIALOG)
        image.set_alignment(0.5, 0.0)
        hbox.pack_start(image, False, False, 0)
        vbox = gtk.VBox(spacing=5)
        tlabel = gtk.Label(text)
        tlabel.set_use_markup(True)
        tlabel.set_line_wrap(True)
        tlabel.set_alignment(0.0, 0.5)
        vbox.pack_start(tlabel, False, False, 0)
        hbox.pack_start(vbox, False, False, 0)
        self.vbox.pack_start(hbox, False, False, 0)
        self.vbox.set_spacing(5)
        self.vbox.show_all()
Example #32
0
    def test_save_singlefile(self):
        if windows_check():
            raise unittest.SkipTest('on windows \\ != / for path names')
        tmp_path = tempfile.mkstemp('testdata')[1]
        with open(tmp_path, 'wb') as tmp_file:
            tmp_file.write(b'a' * (2314 * 1024))

        tmp_fd, tmp_file = tempfile.mkstemp('.torrent')
        metafile.make_meta_file(tmp_path, '', 32768, target=tmp_file)

        check_torrent(tmp_file)

        os.remove(tmp_path)
        os.close(tmp_fd)
        os.remove(tmp_file)
Example #33
0
    def on_tray_popup(self, status_icon, button, activate_time):
        """Called when the tray icon is right clicked."""
        self.blink(False)

        if self.mainwindow.visible():
            self.builder.get_object('menuitem_show_deluge').set_active(True)
        else:
            self.builder.get_object('menuitem_show_deluge').set_active(False)

        popup_function = StatusIcon.position_menu
        if windows_check() or osx_check():
            popup_function = None
            button = 0
        self.tray_menu.popup(None, None, popup_function, status_icon, button,
                             activate_time)
Example #34
0
 def check_suspend_hibernate_flags(self):
     self.config["can_hibernate"] = False
     self.config["can_suspend"] = False
     if windows_check():
         pwr_states = GetPwrCapabilities()
         try:
             if pwr_states['HiberFilePresent'] and pwr_states['SystemS4']:
                 self.config["can_hibernate"] = True
             if pwr_states['SystemS1'] | pwr_states[
                     'SystemS2'] | pwr_states['SystemS3']:
                 self.config["can_suspend"] = True
         except KeyError, e:
             log.error(
                 "[AutoShutdown] Error reading system power capabilities: %s",
                 e)
Example #35
0
    def test_utf8_encoded_paths2(self):
        if windows_check():
            raise unittest.SkipTest('on windows KeyError: unicode_filenames')
        filename = common.get_test_data_file('unicode_filenames.torrent')
        filepath1 = '\u30c6\u30af\u30b9\u30fb\u30c6\u30af\u30b5\u30f3.mkv'
        filepath2 = ('\u041c\u0438\u0445\u0430\u0438\u043b \u0413\u043e'
                     '\u0440\u0431\u0430\u0447\u0451\u0432.mkv')
        filepath3 = "Alisher ibn G'iyosiddin Navoiy.mkv"
        filepath4 = 'Ascii title.mkv'
        filepath5 = '\u09b8\u09c1\u0995\u09c1\u09ae\u09be\u09b0 \u09b0\u09be\u09df.mkv'

        ti = TorrentInfo(filename)
        files_tree = ti.files_tree['unicode_filenames']
        self.assertIn(filepath1, files_tree)
        self.assertIn(filepath2, files_tree)
        self.assertIn(filepath3, files_tree)
        self.assertIn(filepath4, files_tree)
        self.assertIn(filepath5, files_tree)

        result_files = [
            {
                'download': True,
                'path': 'unicode_filenames/' + filepath3,
                'size': 126158658,
            },
            {
                'download': True,
                'path': 'unicode_filenames/' + filepath4,
                'size': 189321363,
            },
            {
                'download': True,
                'path': 'unicode_filenames/' + filepath2,
                'size': 106649699,
            },
            {
                'download': True,
                'path': 'unicode_filenames/' + filepath5,
                'size': 21590269,
            },
            {
                'download': True,
                'path': 'unicode_filenames/' + filepath1,
                'size': 1771
            },
        ]

        assertCountEqual(self, ti.files, result_files)
Example #36
0
    def add_process_arg_group(self):
        """Adds a grouping of common process args to control a daemon to the parser"""

        self.process_arg_group = True
        self.group = self.add_argument_group(_('Process Control Options'))
        self.group.add_argument('-P', '--pidfile', metavar='<pidfile>', action='store',
                                help=_('Pidfile to store the process id'))
        if not common.windows_check():
            self.group.add_argument('-d', '--do-not-daemonize', dest='donotdaemonize', action='store_true',
                                    help=_('Do not daemonize (fork) this process'))
            self.group.add_argument('-f', '--fork', dest='donotdaemonize', action='store_false',
                                    help=argparse.SUPPRESS)  # Deprecated arg
            self.group.add_argument('-U', '--user', metavar='<user>', action='store',
                                    help=_('Change to this user on startup (Requires root)'))
            self.group.add_argument('-g', '--group', metavar='<group>', action='store',
                                    help=_('Change to this group on startup (Requires root)'))
Example #37
0
    def test_save_singlefile(self):
        if windows_check():
            raise unittest.SkipTest('on windows file not released')
        tmp_data = tempfile.mkstemp('testdata')[1]
        with open(tmp_data, 'wb') as _file:
            _file.write(b'a' * (2314 * 1024))
        t = maketorrent.TorrentMetadata()
        t.data_path = tmp_data
        tmp_fd, tmp_file = tempfile.mkstemp('.torrent')
        t.save(tmp_file)

        check_torrent(tmp_file)

        os.remove(tmp_data)
        os.close(tmp_fd)
        os.remove(tmp_file)
Example #38
0
    def test_text_input(self):
        def move_func(self, r, c):
            self._cursor_row = r
            self._cursor_col = c

        t = TextInput(
            self.parent,
            'name',
            'message',
            move_func,
            20,
            '/text/field/file/path',
            complete=False,
        )
        self.assertTrue(t)
        if not windows_check():
            self.assertTrue(t.handle_read(33))
Example #39
0
class ConsoleScriptEntryTestCase(BaseTestCase, ConsoleUIBaseTestCase):

    if windows_check():
        skip = 'Console ui test on Windows broken due to sys args issue'

    def __init__(self, testname):
        super(ConsoleScriptEntryTestCase, self).__init__(testname)
        ConsoleUIBaseTestCase.__init__(self)
        self.var['cmd_name'] = 'deluge-console'
        self.var['start_cmd'] = deluge.ui.console.start
        self.var['sys_arg_cmd'] = ['./deluge-console']

    def set_up(self):
        return ConsoleUIBaseTestCase.set_up(self)

    def tear_down(self):
        return ConsoleUIBaseTestCase.tear_down(self)
Example #40
0
    def install_signal_handlers(self):
        # Since twisted assigns itself all the signals may as well make
        # use of it.
        reactor.addSystemEventTrigger("after", "shutdown", self.shutdown)

        # Twisted doesn't handle windows specific signals so we still
        # need to attach to those to handle the close correctly.
        if common.windows_check():
            from win32api import SetConsoleCtrlHandler
            from win32con import CTRL_CLOSE_EVENT, CTRL_SHUTDOWN_EVENT
            def win_handler(ctrl_type):
                log.debug("ctrl type: %s", ctrl_type)
                if ctrl_type == CTRL_CLOSE_EVENT or \
                   ctrl_type == CTRL_SHUTDOWN_EVENT:
                    self.shutdown()
                    return 1
            SetConsoleCtrlHandler(win_handler)
Example #41
0
class ConsoleDelugeScriptEntryTestCase(BaseTestCase, ConsoleUIBaseTestCase):

    if windows_check():
        skip = 'cannot test console ui on windows'

    def __init__(self, testname):
        super(ConsoleDelugeScriptEntryTestCase, self).__init__(testname)
        ConsoleUIBaseTestCase.__init__(self)
        self.var['cmd_name'] = 'deluge console'
        self.var['start_cmd'] = ui_entry.start_ui
        self.var['sys_arg_cmd'] = ['./deluge', 'console']

    def set_up(self):
        return ConsoleUIBaseTestCase.set_up(self)

    def tear_down(self):
        return ConsoleUIBaseTestCase.tear_down(self)
Example #42
0
class WebUIDelugeScriptEntryTestCase(BaseTestCase, WebUIBaseTestCase):

    if windows_check():
        skip = 'cannot test console ui on windows'

    def __init__(self, testname):
        super(WebUIDelugeScriptEntryTestCase, self).__init__(testname)
        WebUIBaseTestCase.__init__(self)
        self.var['cmd_name'] = 'deluge web'
        self.var['start_cmd'] = ui_entry.start_ui
        self.var['sys_arg_cmd'] = ['./deluge', 'web', '--do-not-daemonize']

    def set_up(self):
        return WebUIBaseTestCase.set_up(self)

    def tear_down(self):
        return WebUIBaseTestCase.tear_down(self)
Example #43
0
def get_deluge_icon():
    """The deluge icon for use in dialogs.

    It will first attempt to get the icon from the theme and will fallback to using an image
    that is distributed with the package.

    Returns:
        gtk.gdk.Pixbuf: the deluge icon
    """
    if windows_check():
        return get_logo(32)
    else:
        try:
            icon_theme = icon_theme_get_default()
            return icon_theme.load_icon('deluge', 64, 0)
        except GError:
            return get_logo(64)
Example #44
0
    def install_signal_handlers(self):
        # Since twisted assigns itself all the signals may as well make
        # use of it.
        reactor.addSystemEventTrigger("after", "shutdown", self.shutdown)

        # Twisted doesn't handle windows specific signals so we still
        # need to attach to those to handle the close correctly.
        if common.windows_check():
            from win32api import SetConsoleCtrlHandler
            from win32con import CTRL_CLOSE_EVENT, CTRL_SHUTDOWN_EVENT
            def win_handler(ctrl_type):
                log.debug("ctrl type: %s", ctrl_type)
                if ctrl_type == CTRL_CLOSE_EVENT or \
                   ctrl_type == CTRL_SHUTDOWN_EVENT:
                    self.shutdown()
                    return 1
            SetConsoleCtrlHandler(win_handler)
Example #45
0
def get_deluge_icon():
    """The deluge icon for use in dialogs.

    It will first attempt to get the icon from the theme and will fallback to using an image
    that is distributed with the package.

    Returns:
        gtk.gdk.Pixbuf: the deluge icon
    """
    if windows_check():
        return get_logo(32)
    else:
        try:
            icon_theme = icon_theme_get_default()
            return icon_theme.load_icon('deluge', 64, 0)
        except GError:
            return get_logo(64)
Example #46
0
    def execute_commands(self, torrent_id, event, *arg):
        if event == 'added' and arg[0]:
            # No futher action as from_state (arg[0]) is True
            return
        elif event == 'removed':
            torrent_id, torrent_name, download_location = self.preremoved_cache.pop(torrent_id)
        else:
            torrent = component.get('TorrentManager').torrents[torrent_id]
            info = torrent.get_status(['name', 'download_location'])
            # Grab the torrent name and download location
            # getProcessOutputAndValue requires args to be str
            torrent_name = info['name']
            download_location = info['download_location']

        log.debug('Running commands for %s', event)

        def log_error(result, command):
            (stdout, stderr, exit_code) = result
            if exit_code:
                log.warn('Command "%s" failed with exit code %d', command, exit_code)
                if stdout:
                    log.warn('stdout: %s', stdout)
                if stderr:
                    log.warn('stderr: %s', stderr)

        # Go through and execute all the commands
        for command in self.config['commands']:
            if command[EXECUTE_EVENT] == event:
                command = os.path.expandvars(command[EXECUTE_COMMAND])
                command = os.path.expanduser(command)

                cmd_args = [torrent_id.encode('utf8'), torrent_name.encode('utf8'),
                            download_location.encode('utf8')]
                if windows_check():
                    # Escape ampersand on windows (see #2784)
                    cmd_args = [cmd_arg.replace('&', '^^^&') for cmd_arg in cmd_args]

                if os.path.isfile(command) and os.access(command, os.X_OK):
                    log.debug('Running %s with args: %s', command, cmd_args)
                    d = getProcessOutputAndValue(command, cmd_args, env=os.environ)
                    d.addCallback(log_error, command)
                else:
                    log.error('Execute script not found or not executable')
Example #47
0
    def _handle_ui_options(self, options):
        """Handle UI common and process group options.

        Args:
            options (argparse.Namespace): The parsed options.

        Returns:
            argparse.Namespace: The parsed options.

        """
        if not self.common_setup:
            self.common_setup = True

            # Setup the logger
            if options.quiet:
                options.loglevel = 'none'
            if options.loglevel:
                options.loglevel = options.loglevel.lower()

            logfile_mode = 'w'
            logrotate = options.logrotate
            if options.logrotate:
                logfile_mode = 'a'
                logrotate = common.parse_human_size(options.logrotate)

            # Setup the logger
            deluge.log.setup_logger(level=options.loglevel, filename=options.logfile, filemode=logfile_mode,
                                    logrotate=logrotate, output_stream=self.log_stream)

            if options.config:
                if not set_config_dir(options.config):
                    log = logging.getLogger(__name__)
                    log.error('There was an error setting the config dir! Exiting..')
                    sys.exit(1)
            else:
                if not os.path.exists(common.get_default_config_dir()):
                    os.makedirs(common.get_default_config_dir())

        if self.process_arg_group:
            self.process_arg_group = False
            # If donotdaemonize is set, skip process forking.
            if not (common.windows_check() or options.donotdaemonize):
                if os.fork():
                    os._exit(0)
                os.setsid()
                # Do second fork
                if os.fork():
                    os._exit(0)
                # Ensure process doesn't keep any directory in use that may prevent a filesystem unmount.
                os.chdir(get_config_dir())

            # Write pid file before chuid
            if options.pidfile:
                with open(options.pidfile, 'wb') as _file:
                    _file.write('%d\n' % os.getpid())

            if not common.windows_check():
                if options.user:
                    if not options.user.isdigit():
                        import pwd
                        options.user = pwd.getpwnam(options.user)[2]
                    os.setuid(options.user)
                if options.group:
                    if not options.group.isdigit():
                        import grp
                        options.group = grp.getgrnam(options.group)[2]
                    os.setuid(options.group)

        return options
Example #48
0
from deluge.plugins.pluginbase import CorePluginBase
import deluge.component as component
import deluge.configmanager
from deluge.core.rpcserver import export
from deluge.common import windows_check
from extractor.which import which

log = logging.getLogger(__name__)

DEFAULT_PREFS = {
    "extract_path": "",
    "use_name_folder": True
}

if windows_check():
    win_7z_exes = [
        '7z.exe',
        'C:\\Program Files\\7-Zip\\7z.exe',
        'C:\\Program Files (x86)\\7-Zip\\7z.exe',
    ]
    switch_7z = "x -y"
    ## Future suport:
    ## 7-zip cannot extract tar.* with single command.
    #    ".tar.gz", ".tgz",
    #    ".tar.bz2", ".tbz",
    #    ".tar.lzma", ".tlz",
    #    ".tar.xz", ".txz",
    exts_7z = [
        ".rar", ".zip", ".tar",
        ".7z", ".xz", ".lzma",
Example #49
0
def associate_magnet_links(overwrite=False):
    """
    Associates magnet links to Deluge.

    Params:
        overwrite (bool): if this is True, the current setting will be overwritten

    Returns:
        bool: True if association was set
    """

    if windows_check():
        try:
            import winreg
        except ImportError:
            import _winreg as winreg  # For Python 2.

        try:
            hkey = winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, 'Magnet')
        except WindowsError:
            overwrite = True
        else:
            winreg.CloseKey(hkey)

        if overwrite:
            deluge_exe = os.path.join(os.path.dirname(sys.executable), 'deluge.exe')
            try:
                magnet_key = winreg.CreateKey(winreg.HKEY_CLASSES_ROOT, 'Magnet')
            except WindowsError:
                # Could not create for all users, falling back to current user
                magnet_key = winreg.CreateKey(winreg.HKEY_CURRENT_USER, 'Software\\Classes\\Magnet')

            winreg.SetValue(magnet_key, '', winreg.REG_SZ, 'URL:Magnet Protocol')
            winreg.SetValueEx(magnet_key, 'URL Protocol', 0, winreg.REG_SZ, '')
            winreg.SetValueEx(magnet_key, 'BrowserFlags', 0, winreg.REG_DWORD, 0x8)
            winreg.SetValue(magnet_key, 'DefaultIcon', winreg.REG_SZ, '{},0'.format(deluge_exe))
            winreg.SetValue(magnet_key, r'shell\open\command', winreg.REG_SZ, '"{}" "%1"'.format(deluge_exe))
            winreg.CloseKey(magnet_key)

    # Don't try associate magnet on OSX see: #2420
    elif not osx_check():
        # gconf method is only available in a GNOME environment
        try:
            import gconf
        except ImportError:
            log.debug('gconf not available, so will not attempt to register magnet uri handler')
            return False
        else:
            key = '/desktop/gnome/url-handlers/magnet/command'
            gconf_client = gconf.client_get_default()
            if (gconf_client.get(key) and overwrite) or not gconf_client.get(key):
                # We are either going to overwrite the key, or do it if it hasn't been set yet
                if gconf_client.set_string(key, 'deluge "%s"'):
                    gconf_client.set_bool('/desktop/gnome/url-handlers/magnet/needs_terminal', False)
                    gconf_client.set_bool('/desktop/gnome/url-handlers/magnet/enabled', True)
                    log.info('Deluge registered as default magnet uri handler!')
                    return True
                else:
                    log.error('Unable to register Deluge as default magnet uri handler.')
                    return False
    return False
Example #50
0
    def __init__(self):
        self.about = gtk.AboutDialog()
        self.about.set_transient_for(component.get('MainWindow').window)
        self.about.set_position(gtk.WIN_POS_CENTER)
        self.about.set_program_name(_('Deluge'))
        if windows_check():
            def url_hook(dialog, url):
                """Url hook for Windows OS which has no default browser."""
                open_url_in_browser(url)
                return True
            self.about.connect('activate-link', url_hook)

        version = get_version()

        self.about.set_copyright(
            _('Copyright %(year_start)s-%(year_end)s Deluge Team') % {'year_start': 2007, 'year_end': 2015})
        self.about.set_comments(
            _('A peer-to-peer file sharing program\nutilizing the BitTorrent protocol.') +
            '\n\n' + _('Client:') + ' %s\n' % version)
        self.about.set_version(version)
        self.about.set_authors([
            _('Current Developers:'), 'Andrew Resch', 'Damien Churchill',
            'John Garland', 'Calum Lind', '', 'libtorrent (libtorrent.org):',
            'Arvid Norberg', '', _('Past Developers or Contributors:'),
            'Zach Tibbitts', 'Alon Zakai', 'Marcos Mobley', 'Alex Dedul',
            'Sadrul Habib Chowdhury', 'Ido Abramovich', 'Martijn Voncken'
        ])
        self.about.set_artists(['Andrew Wedderburn', 'Andrew Resch'])
        self.about.set_translator_credits('\n'.join([
            'Aaron Wang Shi', 'abbigss', 'ABCdatos', 'Abcx', 'Actam', 'Adam',
            'adaminikisi', 'adi_oporanu', 'Adrian Goll', 'afby', 'Ahmades',
            'Ahmad Farghal', 'Ahmad Gharbeia أحمد غربية', 'akira', 'Aki Sivula',
            'Alan Pepelko', 'Alberto', 'Alberto Ferrer', 'alcatr4z', 'AlckO',
            'Aleksej Korgenkov', 'Alessio Treglia', 'Alexander Ilyashov',
            'Alexander Matveev', 'Alexander Saltykov', 'Alexander Taubenkorb',
            'Alexander Telenga', 'Alexander Yurtsev', 'Alexandre Martani',
            'Alexandre Rosenfeld', 'Alexandre Sapata Carbonell',
            'Alexey Osipov', 'Alin Claudiu Radut', 'allah', 'AlSim',
            'Alvaro Carrillanca P.', 'A.Matveev', 'Andras Hipsag',
            'András Kárász', 'Andrea Ratto', 'Andreas Johansson', 'Andreas Str',
            'André F. Oliveira', 'AndreiF', 'andrewh', 'Angel Guzman Maeso',
            'Aníbal Deboni Neto', 'animarval', 'Antonio Cono', 'antoniojreyes',
            'Anton Shestakov', 'Anton Yakutovich', 'antou',
            'Arkadiusz Kalinowski', 'Artin', 'artir', 'Astur',
            'Athanasios Lefteris', 'Athmane MOKRAOUI (ButterflyOfFire)',
            'Augusta Carla Klug', 'Avoledo Marco', 'axaard', 'AxelRafn',
            'Axezium', 'Ayont', 'b3rx', 'Bae Taegil', 'Bajusz Tamás',
            "Balaam's Miracle", 'Ballestein', 'Bent Ole Fosse', 'berto89',
            'bigx', 'Bjorn Inge Berg', 'blackbird', 'Blackeyed', 'blackmx',
            'BlueSky', 'Blutheo', 'bmhm', 'bob00work', 'boenki',
            'Bogdan Bădic-Spătariu', 'bonpu', 'Boone', 'boss01',
            'Branislav Jovanović', 'bronze', 'brownie', 'Brus46', 'bumper',
            'butely', 'BXCracer', 'c0nfidencal', 'Can Kaya',
            'Carlos Alexandro Becker', 'cassianoleal', 'Cédric.h',
            'César Rubén', 'chaoswizard', 'Chen Tao', 'chicha',
            'Chien Cheng Wei', 'Christian Kopac', 'Christian Widell',
            'Christoffer Brodd-Reijer', 'christooss', 'CityAceE', 'Clopy',
            'Clusty', 'cnu', 'Commandant', 'Constantinos Koniaris', 'Coolmax',
            'cosmix', 'Costin Chirvasuta', 'CoVaLiDiTy', 'cow_2001',
            'Crispin Kirchner', 'crom', 'Cruster', 'Cybolic', 'Dan Bishop',
            'Danek', 'Dani', 'Daniel Demarco', 'Daniel Ferreira',
            'Daniel Frank', 'Daniel Holm', 'Daniel Høyer Iversen',
            'Daniel Marynicz', 'Daniel Nylander', 'Daniel Patriche',
            'Daniel Schildt', 'Daniil Sorokin', 'Dante Díaz', 'Daria Michalska',
            'DarkenCZ', 'Darren', 'Daspah', 'David Eurenius', 'davidhjelm',
            'David Machakhelidze', 'Dawid Dziurdzia', 'Daya Adianto ', 'dcruz',
            'Deady', 'Dereck Wonnacott', 'Devgru', 'Devid Antonio Filoni'
            'DevilDogTG', 'di0rz`', 'Dialecti Valsamou', 'Diego Medeiros',
            'Dkzoffy', 'Dmitrij D. Czarkoff', 'Dmitriy Geels',
            'Dmitry Olyenyov', 'Dominik Kozaczko', 'Dominik Lübben', 'doomster',
            'Dorota Król', 'Doyen Philippe', 'Dread Knight', 'DreamSonic',
            'duan', 'Duong Thanh An', 'DvoglavaZver', 'dwori', 'dylansmrjones',
            'Ebuntor', 'Edgar Alejandro Jarquin Flores', 'Eetu', 'ekerazha',
            'Elias Julkunen', 'elparia', 'Emberke', 'Emiliano Goday Caneda',
            'EndelWar', 'eng.essam', 'enubuntu', 'ercangun', 'Erdal Ronahi',
            'ergin üresin', 'Eric', 'Éric Lassauge', 'Erlend Finvåg', 'Errdil',
            'ethan shalev', 'Evgeni Spasov', 'ezekielnin', 'Fabian Ordelmans',
            'Fabio Mazanatti', 'Fábio Nogueira', 'FaCuZ', 'Felipe Lerena',
            'Fernando Pereira', 'fjetland', 'Florian Schäfer', 'FoBoS', 'Folke',
            'Force', 'fosk', 'fragarray', 'freddeg', 'Frédéric Perrin',
            'Fredrik Kilegran', 'FreeAtMind', 'Fulvio Ciucci', 'Gabor Kelemen',
            'Galatsanos Panagiotis', 'Gaussian', 'gdevitis', 'Georg Brzyk',
            'George Dumitrescu', 'Georgi Arabadjiev', 'Georg Sieber',
            'Gerd Radecke', 'Germán Heusdens', 'Gianni Vialetto',
            'Gigih Aji Ibrahim', 'Giorgio Wicklein', 'Giovanni Rapagnani',
            'Giuseppe', 'gl', 'glen', 'granjerox', 'Green Fish', 'greentea',
            'Greyhound', 'G. U.', 'Guillaume BENOIT', 'Guillaume Pelletier',
            'Gustavo Henrique Klug', 'gutocarvalho', 'Guybrush88',
            'Hans Rødtang', 'HardDisk', 'Hargas Gábor',
            'Heitor Thury Barreiros Barbosa', 'helios91940', 'helix84',
            'Helton Rodrigues', 'Hendrik Luup', 'Henrique Ferreiro',
            'Henry Goury-Laffont', 'Hezy Amiel', 'hidro', 'hoball', 'hokten',
            'Holmsss', 'hristo.num', 'Hubert Życiński', 'Hyo', 'Iarwain', 'ibe',
            'ibear', 'Id2ndR', 'Igor Zubarev', 'IKON (Ion)', 'imen',
            'Ionuț Jula', 'Isabelle STEVANT', 'István Nyitrai', 'Ivan Petrovic',
            'Ivan Prignano', 'IvaSerge', 'jackmc', 'Jacks0nxD', 'Jack Shen',
            'Jacky Yeung', 'Jacques Stadler', 'Janek Thomaschewski', 'Jan Kaláb',
            'Jan Niklas Hasse', 'Jasper Groenewegen', 'Javi Rodríguez',
            'Jayasimha (ಜಯಸಿಂಹ)', 'jeannich', 'Jeff Bailes', 'Jesse Zilstorff',
            'Joan Duran', 'João Santos', 'Joar Bagge', 'Joe Anderson',
            'Joel Calado', 'Johan Linde', 'John Garland', 'Jojan', 'jollyr0ger',
            'Jonas Bo Grimsgaard', 'Jonas Granqvist', 'Jonas Slivka',
            'Jonathan Zeppettini', 'Jørgen', 'Jørgen Tellnes', 'josé',
            'José Geraldo Gouvêa', 'José Iván León Islas', 'José Lou C.',
            'Jose Sun', 'Jr.', 'Jukka Kauppinen', 'Julián Alarcón',
            'julietgolf', 'Jusic', 'Justzupi', 'Kaarel', 'Kai Thomsen',
            'Kalman Tarnay', 'Kamil Páral', 'Kane_F', '*****@*****.**',
            'Kateikyoushii', 'kaxhinaz', 'Kazuhiro NISHIYAMA', 'Kerberos',
            'Keresztes Ákos', 'kevintyk', 'kiersie', 'Kimbo^', 'Kim Lübbe',
            'kitzOgen', 'Kjetil Rydland', 'kluon', 'kmikz', 'Knedlyk',
            'koleoptero', 'Kőrösi Krisztián', 'Kouta', 'Krakatos',
            'Krešo Kunjas', 'kripken', 'Kristaps', 'Kristian Øllegaard',
            'Kristoffer Egil Bonarjee', 'Krzysztof Janowski',
            'Krzysztof Zawada', 'Larry Wei Liu', 'laughterwym', 'Laur Mõtus',
            'lazka', 'leandrud', 'lê bình', 'Le Coz Florent', 'Leo', 'liorda',
            'LKRaider', 'LoLo_SaG', 'Long Tran', 'Lorenz', 'Low Kian Seong',
            'Luca Andrea Rossi', 'Luca Ferretti', 'Lucky LIX', 'Luis Gomes',
            'Luis Reis', 'Łukasz Wyszyński', 'luojie-dune', 'maaark',
            'Maciej Chojnacki', 'Maciej Meller', 'Mads Peter Rommedahl',
            'Major Kong', 'Malaki', 'malde', 'Malte Lenz', 'Mantas Kriaučiūnas',
            'Mara Sorella', 'Marcin', 'Marcin Falkiewicz', 'marcobra',
            'Marco da Silva', 'Marco de Moulin', 'Marco Rodrigues', 'Marcos',
            'Marcos Escalier', 'Marcos Mobley', 'Marcus Ekstrom',
            'Marek Dębowski', 'Mário Buči', 'Mario Munda', 'Marius Andersen',
            'Marius Hudea', 'Marius Mihai', 'Mariusz Cielecki',
            'Mark Krapivner', 'marko-markovic', 'Markus Brummer',
            'Markus Sutter', 'Martin', 'Martin Dybdal', 'Martin Iglesias',
            'Martin Lettner', 'Martin Pihl', 'Masoud Kalali', 'mat02',
            'Matej Urbančič', 'Mathias-K', 'Mathieu Arès',
            'Mathieu D. (MatToufoutu)', 'Mathijs', 'Matrik', 'Matteo Renzulli',
            'Matteo Settenvini', 'Matthew Gadd', 'Matthias Benkard',
            'Matthias Mailänder', 'Mattias Ohlsson', 'Mauro de Carvalho',
            'Max Molchanov', 'Me', 'MercuryCC', 'Mert Bozkurt', 'Mert Dirik',
            'MFX', 'mhietar', 'mibtha', 'Michael Budde', 'Michael Kaliszka',
            'Michalis Makaronides', 'Michał Tokarczyk', 'Miguel Pires da Rosa',
            'Mihai Capotă', 'Miika Metsälä', 'Mikael Fernblad', 'Mike Sierra',
            'mikhalek', 'Milan Prvulović', 'Milo Casagrande', 'Mindaugas',
            'Miroslav Matejaš', 'misel', 'mithras', 'Mitja Pagon', 'M.Kitchen',
            'Mohamed Magdy', 'moonkey', 'MrBlonde', 'muczy', 'Münir Ekinci',
            'Mustafa Temizel', 'mvoncken', 'Mytonn', 'NagyMarton', 'neaion',
            'Neil Lin', 'Nemo', 'Nerijus Arlauskas', 'Nicklas Larsson',
            'Nicolaj Wyke', 'Nicola Piovesan', 'Nicolas Sabatier',
            'Nicolas Velin', 'Nightfall', 'NiKoB', 'Nikolai M. Riabov',
            'Niko_Thien', 'niska', 'Nithir', 'noisemonkey', 'nomemohes',
            'nosense', 'null', 'Nuno Estêvão', 'Nuno Santos', 'nxxs', 'nyo',
            'obo', 'Ojan', 'Olav Andreas Lindekleiv', 'oldbeggar',
            'Olivier FAURAX', 'orphe', 'osantana', 'Osman Tosun', 'OssiR',
            'otypoks', 'ounn', 'Oz123', 'Özgür BASKIN', 'Pablo Carmona A.',
            'Pablo Ledesma', 'Pablo Navarro Castillo', 'Paco Molinero',
            'Pål-Eivind Johnsen', 'pano', 'Paolo Naldini', 'Paracelsus',
            'Patryk13_03', 'Patryk Skorupa', 'PattogoTehen', 'Paul Lange',
            'Pavcio', 'Paweł Wysocki', 'Pedro Brites Moita',
            'Pedro Clemente Pereira Neto', 'Pekka "PEXI" Niemistö', 'Penegal',
            'Penzo', 'perdido', 'Peter Kotrcka', 'Peter Skov',
            'Peter Van den Bosch', 'Petter Eklund', 'Petter Viklund',
            'phatsphere', 'Phenomen', 'Philipi', 'Philippides Homer', 'phoenix',
            'pidi', 'Pierre Quillery', 'Pierre Rudloff', 'Pierre Slamich',
            'Pietrao', 'Piotr Strębski', 'Piotr Wicijowski', 'Pittmann Tamás',
            'Playmolas', 'Prescott', 'Prescott_SK', 'pronull',
            'Przemysław Kulczycki', 'Pumy', 'pushpika', 'PY', 'qubicllj',
            'r21vo', 'Rafał Barański', 'rainofchaos', 'Rajbir', 'ras0ir', 'Rat',
            'rd1381', 'Renato', 'Rene Hennig', 'Rene Pärts', 'Ricardo Duarte',
            'Richard', 'Robert Hrovat', 'Roberth Sjonøy', 'Robert Lundmark',
            'Robin Jakobsson', 'Robin Kåveland', 'Rodrigo Donado',
            'Roel Groeneveld', 'rohmaru', 'Rolf Christensen', 'Rolf Leggewie',
            'Roni Kantis', 'Ronmi', 'Rostislav Raykov', 'royto', 'RuiAmaro',
            'Rui Araújo', 'Rui Moura', 'Rune Svendsen', 'Rusna', 'Rytis',
            'Sabirov Mikhail', 'salseeg', 'Sami Koskinen', 'Samir van de Sand',
            'Samuel Arroyo Acuña', 'Samuel R. C. Vale', 'Sanel', 'Santi',
            'Santi Martínez Cantelli', 'Sardan', 'Sargate Kanogan',
            'Sarmad Jari', 'Saša Bodiroža', 'sat0shi', 'Saulius Pranckevičius',
            'Savvas Radevic', 'Sebastian Krauß', 'Sebastián Porta', 'Sedir',
            'Sefa Denizoğlu', 'sekolands', 'Selim Suerkan', 'semsomi',
            'Sergii Golovatiuk', 'setarcos', 'Sheki', 'Shironeko', 'Shlomil',
            'silfiriel', 'Simone Tolotti', 'Simone Vendemia', 'sirkubador',
            'Sławomir Więch', 'slip', 'slyon', 'smoke', 'Sonja', 'spectral',
            'spin_555', 'spitf1r3', 'Spiziuz', 'Spyros Theodoritsis', 'SqUe',
            'Squigly', 'srtck', 'Stefan Horning', 'Stefano Maggiolo',
            'Stefano Roberto Soleti', 'steinberger', 'Stéphane Travostino',
            'Stephan Klein', 'Steven De Winter', 'Stevie', 'Stian24', 'stylius',
            'Sukarn Maini', 'Sunjae Park', 'Susana Pereira', 'szymon siglowy',
            'takercena', 'TAS', 'Taygeto', 'temy4', 'texxxxxx', 'thamood',
            'Thanos Chatziathanassiou', 'Tharawut Paripaiboon', 'Theodoor',
            'Théophane Anestis', 'Thor Marius K. Høgås', 'Tiago Silva',
            'Tiago Sousa', 'Tikkel', 'tim__b', 'Tim Bordemann', 'Tim Fuchs',
            'Tim Kornhammar', 'Timo', 'Timo Jyrinki', 'Timothy Babych',
            'TitkosRejtozo', 'Tom', 'Tomas Gustavsson', 'Tomas Valentukevičius',
            'Tomasz Dominikowski', 'Tomislav Plavčić', 'Tom Mannerhagen',
            'Tommy Mikkelsen', 'Tom Verdaat', 'Tony Manco',
            'Tor Erling H. Opsahl', 'Toudi', 'tqm_z', 'Trapanator', 'Tribaal',
            'Triton', 'TuniX12', 'Tuomo Sipola', 'turbojugend_gr', 'Turtle.net',
            'twilight', 'tymmej', 'Ulrik', 'Umarzuki Mochlis', 'unikob',
            'Vadim Gusev', 'Vagi', 'Valentin Bora', 'Valmantas Palikša',
            'VASKITTU', 'Vassilis Skoullis', 'vetal17', 'vicedo', 'viki',
            'villads hamann', 'Vincent Garibal', 'Vincent Ortalda', 'vinchi007',
            'Vinícius de Figueiredo Silva', 'Vinzenz Vietzke', 'virtoo',
            'virtual_spirit', 'Vitor Caike', 'Vitor Lamas Gatti',
            'Vladimir Lazic', 'Vladimir Sharshov', 'Wanderlust', 'Wander Nauta',
            'Ward De Ridder', 'WebCrusader', 'webdr', 'Wentao Tang', 'wilana',
            'Wilfredo Ernesto Guerrero Campos', 'Wim Champagne', 'World Sucks',
            'Xabi Ezpeleta', 'Xavi de Moner', 'XavierToo', 'XChesser',
            'Xiaodong Xu', 'xyb', 'Yaron', 'Yasen Pramatarov', 'YesPoX',
            'Yuren Ju', 'Yves MATHIEU', 'zekopeko', 'zhuqin', 'Zissan',
            'Γιάννης Κατσαμπίρης', 'Артём Попов', 'Миша', 'Шаймарданов Максим',
            '蔡查理'
        ]))
        self.about.set_wrap_license(True)
        self.about.set_license(_(
            'This program is free software; you can redistribute it and/or '
            'modify it under the terms of the GNU General Public License as '
            'published by the Free Software Foundation; either version 3 of '
            'the License, or (at your option) any later version. \n\n'
            'This program '
            'is distributed in the hope that it will be useful, but WITHOUT '
            'ANY WARRANTY; without even the implied warranty of '
            'MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU '
            'General Public License for more details. \n\n'
            'You should have received '
            'a copy of the GNU General Public License along with this program; '
            'if not, see <http://www.gnu.org/licenses>. \n\n'
            'In addition, as a '
            'special exception, the copyright holders give permission to link '
            'the code of portions of this program with the OpenSSL library. '
            'You must obey the GNU General Public License in all respects for '
            'all of the code used other than OpenSSL. \n\n'
            'If you modify file(s) '
            'with this exception, you may extend this exception to your '
            'version of the file(s), but you are not obligated to do so. If '
            'you do not wish to do so, delete this exception statement from '
            'your version. If you delete this exception statement from all '
            'source files in the program, then also delete it here.'
        ))
        self.about.set_website('http://deluge-torrent.org')
        self.about.set_website_label('deluge-torrent.org')

        self.about.set_icon(get_deluge_icon())
        self.about.set_logo(get_pixbuf('deluge-about.png'))

        if client.connected():
            if not client.is_standalone():
                self.about.set_comments(
                    self.about.get_comments() + _('Server:') + ' %coreversion%\n')

            self.about.set_comments(
                self.about.get_comments() + '\n' + _('libtorrent:') + ' %ltversion%\n')

            def on_lt_version(result):
                c = self.about.get_comments()
                c = c.replace('%ltversion%', result)
                self.about.set_comments(c)

            def on_info(result):
                c = self.about.get_comments()
                c = c.replace('%coreversion%', result)
                self.about.set_comments(c)
                client.core.get_libtorrent_version().addCallback(on_lt_version)

            if not client.is_standalone():
                client.daemon.info().addCallback(on_info)
            else:
                client.core.get_libtorrent_version().addCallback(on_lt_version)
    def show(self):
        """Show the ConnectionManager dialog."""
        self.builder = gtk.Builder()
        self.builder.add_from_file(resource_filename(
            'deluge.ui.gtkui', os.path.join('glade', 'connection_manager.ui')))
        self.connection_manager = self.builder.get_object('connection_manager')
        self.connection_manager.set_transient_for(component.get('MainWindow').window)

        # Create status pixbufs
        if not HOSTLIST_PIXBUFS:
            for stock_id in (gtk.STOCK_NO, gtk.STOCK_YES, gtk.STOCK_CONNECT):
                HOSTLIST_PIXBUFS.append(
                    self.connection_manager.render_icon(stock_id, gtk.ICON_SIZE_MENU))

        # Setup the hostlist liststore and treeview
        self.treeview = self.builder.get_object('treeview_hostlist')
        self.liststore = self.builder.get_object('liststore_hostlist')

        render = gtk.CellRendererPixbuf()
        column = gtk.TreeViewColumn(_('Status'), render)
        column.set_cell_data_func(render, cell_render_status, HOSTLIST_COL_STATUS)
        self.treeview.append_column(column)

        render = gtk.CellRendererText()
        column = gtk.TreeViewColumn(_('Host'), render, text=HOSTLIST_COL_HOST)
        host_data = (HOSTLIST_COL_HOST, HOSTLIST_COL_PORT, HOSTLIST_COL_USER)
        column.set_cell_data_func(render, cell_render_host, host_data)
        column.set_expand(True)
        self.treeview.append_column(column)

        column = gtk.TreeViewColumn(_('Version'), gtk.CellRendererText(), text=HOSTLIST_COL_VERSION)
        self.treeview.append_column(column)

        # Load any saved host entries
        self._load_liststore()
        # Set widgets to values from gtkui config.
        self._load_widget_config()
        self._update_widget_buttons()

        # Connect the signals to the handlers
        self.builder.connect_signals(self)
        self.treeview.get_selection().connect('changed', self.on_hostlist_selection_changed)

        # Set running True before update status call.
        self.running = True

        if windows_check():
            # Call to simulate() required to workaround showing daemon status (see #2813)
            reactor.simulate()
        self._update_host_status()

        # Trigger the on_selection_changed code and select the first host if possible
        self.treeview.get_selection().unselect_all()
        if len(self.liststore):
            self.treeview.get_selection().select_path(0)

        # Run the dialog
        self.connection_manager.run()

        # Dialog closed so cleanup.
        self.running = False
        self.connection_manager.destroy()
        del self.builder
        del self.connection_manager
        del self.liststore
        del self.treeview
Example #52
0
    def __init__(self, args):
        # Setup gtkbuilder/glade translation
        setup_translations(setup_gettext=False, setup_pygtk=True)

        # Setup signals
        def on_die(*args):
            log.debug('OS signal "die" caught with args: %s', args)
            reactor.stop()

        if windows_check():
            from win32api import SetConsoleCtrlHandler
            SetConsoleCtrlHandler(on_die, True)
            log.debug('Win32 "die" handler registered')
        elif osx_check() and WINDOWING == 'quartz':
            import gtkosx_application
            self.osxapp = gtkosx_application.gtkosx_application_get()
            self.osxapp.connect('NSApplicationWillTerminate', on_die)
            log.debug('OSX quartz "die" handler registered')

        # Set process name again to fix gtk issue
        setproctitle(getproctitle())

        # Attempt to register a magnet URI handler with gconf, but do not overwrite
        # if already set by another program.
        associate_magnet_links(False)

        # Make sure gtkui.conf has at least the defaults set
        self.config = ConfigManager('gtkui.conf', DEFAULT_PREFS)

        # Make sure the gtkui state folder has been created
        if not os.path.exists(os.path.join(get_config_dir(), 'gtkui_state')):
            os.makedirs(os.path.join(get_config_dir(), 'gtkui_state'))

        # Set language
        if self.config['language'] is not None:
            set_language(self.config['language'])

        # Start the IPC Interface before anything else.. Just in case we are
        # already running.
        self.queuedtorrents = QueuedTorrents()
        self.ipcinterface = IPCInterface(args.torrents)

        # Initialize gdk threading
        threads_init()

        # We make sure that the UI components start once we get a core URI
        client.set_disconnect_callback(self.__on_disconnect)

        self.trackericons = TrackerIcons()
        self.sessionproxy = SessionProxy()
        # Initialize various components of the gtkui
        self.mainwindow = MainWindow()
        self.menubar = MenuBar()
        self.toolbar = ToolBar()
        self.torrentview = TorrentView()
        self.torrentdetails = TorrentDetails()
        self.sidebar = SideBar()
        self.filtertreeview = FilterTreeView()
        self.preferences = Preferences()
        self.systemtray = SystemTray()
        self.statusbar = StatusBar()
        self.addtorrentdialog = AddTorrentDialog()

        if osx_check() and WINDOWING == 'quartz':
            def nsapp_open_file(osxapp, filename):
                # Ignore command name which is raised at app launch (python opening main script).
                if filename == sys.argv[0]:
                    return True
                process_args([filename])
            self.osxapp.connect('NSApplicationOpenFile', nsapp_open_file)
            from deluge.ui.gtkui.menubar_osx import menubar_osx
            menubar_osx(self, self.osxapp)
            self.osxapp.ready()

        # Initalize the plugins
        self.plugins = PluginManager()

        # Show the connection manager
        self.connectionmanager = ConnectionManager()

        # Setup RPC stats logging
        # daemon_bps: time, bytes_sent, bytes_recv
        self.daemon_bps = (0, 0, 0)
        self.rpc_stats = LoopingCall(self.log_rpc_stats)
        self.closing = False

        # Twisted catches signals to terminate, so have it call a pre_shutdown method.
        reactor.addSystemEventTrigger('before', 'gtkui_close', self.close)

        def gtkui_sigint_handler(num, frame):
            log.debug('SIGINT signal caught, firing event: gtkui_close')
            reactor.callLater(0, reactor.fireSystemEvent, 'gtkui_close')

        signal.signal(signal.SIGINT, gtkui_sigint_handler)