unity-scope-sshsearch-0.1daily13.06.05/0000755000015700001700000000000012153554005020443 5ustar pbuserpbgroup00000000000000unity-scope-sshsearch-0.1daily13.06.05/po/0000755000015700001700000000000012153554005021061 5ustar pbuserpbgroup00000000000000unity-scope-sshsearch-0.1daily13.06.05/po/unity-scope-sshsearch.pot0000644000015700001700000000220412153552723026050 0ustar pbuserpbgroup00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-03-18 18:23+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #: ../src/unity_sshsearch_daemon.py:34 msgid "Boxes" msgstr "" #: ../src/unity_sshsearch_daemon.py:36 msgid "Sorry, there are no available SSH connections that match your search." msgstr "" #: ../src/unity_sshsearch_daemon.py:37 msgid "Search for available SSH connections" msgstr "" #: ../data/sshsearch.scope.in.h:1 msgid "sshsearch;ssh;connections;" msgstr "" #: ../data/sshsearch.scope.in.h:2 msgid "Sshsearch" msgstr "" #: ../data/sshsearch.scope.in.h:3 msgid "Find Sshsearch items" msgstr "" #: ../data/sshsearch.scope.in.h:4 msgid "Search Sshsearch" msgstr "" unity-scope-sshsearch-0.1daily13.06.05/po/POTFILES.in0000644000015700001700000000013312153552723022640 0ustar pbuserpbgroup00000000000000[encoding: UTF-8] src/unity_sshsearch_daemon.py [type: gettext/ini]data/sshsearch.scope.in unity-scope-sshsearch-0.1daily13.06.05/MANIFEST.in0000644000015700001700000000007612153552723022211 0ustar pbuserpbgroup00000000000000include MANIFEST.in include src/* include data/* include po/* unity-scope-sshsearch-0.1daily13.06.05/tests/0000755000015700001700000000000012153554005021605 5ustar pbuserpbgroup00000000000000unity-scope-sshsearch-0.1daily13.06.05/tests/test_sshsearch.py0000644000015700001700000000360412153552723025211 0ustar pbuserpbgroup00000000000000# -*- coding: utf-8 -*- from gi.repository import Dee from unittest import TestCase, main from src import unity_sshsearch_daemon as scope d = scope.Daemon() searches = ['192'] mock_data = {'should_pass': 'tests/data/mock_sshsearch_pass', 'should_fail': 'tests/data/mock_sshsearch_fail'} class TestSshsearch(TestCase): def test_search(self): scope.KNOWN_HOSTS_EXPAND = mock_data['should_pass'] model = Dee.SequenceModel.new() model.set_schema('s', 's', 'u', 'u', 's', 's', 's', 's') model.set_column_names('uri', 'icon_hint', 'category', 'result_type', 'mimetype', 'title', 'comment', 'dnd_uri') scope.Daemon.update_results_model(d, searches[0], model) self.assertEqual(model[0][0], 'ssh://config//192.168.1.2') self.assertEqual(model[0][1], 'gnome-terminal') self.assertEqual(model[0][5], '192.168.1.2') self.assertEqual(model[0][6], '192.168.1.2') def test_failing_search(self): scope.KNOWN_HOSTS_EXPAND = mock_data['should_fail'] model = Dee.SequenceModel.new() model.set_schema('s', 's', 'u', 'u', 's', 's', 's', 's') model.set_column_names('uri', 'icon_hint', 'category', 'result_type', 'mimetype', 'title', 'comment', 'dnd_uri') scope.Daemon.update_results_model(d, searches[0], model) self.assertEqual(len(model), 0) def test_preview(self): scope.KNOWN_HOSTS_EXPAND = mock_data['should_pass'] preview = d.on_preview_uri(None, "ssh://config//192.168.1.2") self.assertEqual(preview.props.title, "192.168.1.2") self.assertNotEqual(preview.props.image, None) self.assertEqual(preview.props.image.get_names(), ['gnome-terminal']) if __name__ == '__main__': main() unity-scope-sshsearch-0.1daily13.06.05/tests/__init__.py0000644000015700001700000000000012153552723023711 0ustar pbuserpbgroup00000000000000unity-scope-sshsearch-0.1daily13.06.05/tests/data/0000755000015700001700000000000012153554005022516 5ustar pbuserpbgroup00000000000000unity-scope-sshsearch-0.1daily13.06.05/tests/data/mock_sshsearch_pass0000644000015700001700000000061112153552723026466 0ustar pbuserpbgroup00000000000000192.168.1.2 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCtw4xYQ2Rz0rDnywH7ChchcF3m29+zht5lhbHcuC1zXHC8nqDe9eAklrtbYt4E9CmTvCXg5nfgviQ+ACviCchCd+z46VdPoTZE21ac4gIN0nqnvNWEE6TfAw40//9e/+PleB+q1Mq31n53w28Kfuzj/D0EkV1/Im6mi17+XRGL56ZrveeerFTGIza/AB2AOJOZBE9cGqqbFaCmWf38u8+15QGCR17S+riWBnDYjnSYFSM/BkfLIbVdNoUToV0EjpxQ34NrvMscLJtd/5w7Skwmr8obOZsK6aEHDbRvacLi+RzdFTkMS3w6N59+nfmXglJuZ+PNKpsZQbeSanXZb/1/ unity-scope-sshsearch-0.1daily13.06.05/tests/data/mock_sshsearch_fail0000644000015700001700000000000612153552723026431 0ustar pbuserpbgroup00000000000000 unity-scope-sshsearch-0.1daily13.06.05/src/0000755000015700001700000000000012153554005021232 5ustar pbuserpbgroup00000000000000unity-scope-sshsearch-0.1daily13.06.05/src/unity_sshsearch_daemon.py0000755000015700001700000002077212153552723026362 0ustar pbuserpbgroup00000000000000#! /usr/bin/python # -*- coding: utf-8 -*- # Copyright(C) 2013 Mark Tully # Copyright(C) 2012 Bernd Schlapsi # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License version 3, as published # by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranties of # MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR # PURPOSE. See the GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . from gi.repository import GLib, Gio from gi.repository import Unity, UnityExtras import gettext import os.path import paramiko APP_NAME = 'unity-scope-sshsearch' LOCAL_PATH = '/usr/share/locale/' gettext.bindtextdomain(APP_NAME, LOCAL_PATH) gettext.textdomain(APP_NAME) _ = gettext.gettext BUS_NAME = 'com.canonical.Unity.Scope.Boxes.Sshsearch' BUS_PATH = '/com/canonical/unity/scope/boxes/sshsearch' SVG_DIR = '/usr/share/icons/unity-icon-theme/places/svg/' CAT_0_ICON = Gio.ThemedIcon.new(SVG_DIR + 'group-boxes.svg') CAT_0_TITLE = _('Boxes') NO_RESULTS_HINT = _('Sorry, there are no available SSH connections that match your search.') SEARCH_HINT = _('Search for available SSH connections') SSH_DEFAULT_PORT = '22' SSHCONFIG = os.path.join('~', '.ssh', 'config') SSHCONFIG_EXPAND = os.path.expanduser(SSHCONFIG) KNOWN_HOSTS = os.path.join('~', '.ssh', 'known_hosts') KNOWN_HOSTS_EXPAND = os.path.expanduser(KNOWN_HOSTS) TERMINAL_APP = 'gnome-terminal' TERMINAL_APP_MIMETYPE = 'application/x-desktop' class Daemon: def __init__(self): self.scope = Unity.DeprecatedScope.new(BUS_PATH, 'sshsearch') self.scope.props.search_hint = SEARCH_HINT self.scope.search_in_global = True cats = Unity.CategorySet.new() cats.add(Unity.Category.new(CAT_0_TITLE.lower(), CAT_0_TITLE, CAT_0_ICON, Unity.CategoryRenderer.VERTICAL_TILE)) self.scope.props.categories = cats self.preferences = Unity.PreferencesManager.get_default() self.preferences.connect('notify::remote-content-search', self._on_preference_changed) self.scope.connect('search-changed', self.on_search_changed) self.scope.connect("activate-uri", self.on_activate_uri) self.scope.connect("preview-uri", self.on_preview_uri) self.scope.export() def __read_config(self, filemonitor, file, other_file, event_type): if not file.query_exists(None): self._config_hosts = [] return if (event_type in (Gio.FileMonitorEvent.CREATED, Gio.FileMonitorEvent.CHANGED, Gio.FileMonitorEvent.CHANGES_DONE_HINT, Gio.FileMonitorEvent.ATTRIBUTE_CHANGED)): c = paramiko.SSHConfig() c.parse(open(file.get_path())) self._config_hosts = [h['host'].lower() for h in c._config if '*' not in h['host']] def __read_known_hosts(self, filemonitor, file, other_file, event_type): if not file.query_exists(None): self._known_hosts = [] return if (event_type in (Gio.FileMonitorEvent.CREATED, Gio.FileMonitorEvent.CHANGED, Gio.FileMonitorEvent.CHANGES_DONE_HINT, Gio.FileMonitorEvent.ATTRIBUTE_CHANGED)): h = paramiko.HostKeys(KNOWN_HOSTS_EXPAND) self._known_hosts = [host for host in h.keys() if len(host) != 60] def __parse_hoststring(self, hoststring, user): # assign host and port host = hoststring port = SSH_DEFAULT_PORT if hoststring.startswith('['): host, port = hoststring[1:].split(']:') # assign target target = host if user: target = '%s@%s' % (user, host) # assign connection-description conn_desc = target if port != SSH_DEFAULT_PORT: conn_desc = '%s:%s' % (target, port) return target, port, conn_desc def _on_preference_changed(self, *_): self.scope.queue_search_changed(Unity.SearchType.DEFAULT) def on_search_changed(self, scope, search, search_type, *_): model = search.props.results_model model.clear() if self.preferences.props.remote_content_search != Unity.PreferencesManagerRemoteContent.ALL: search.emit('finished') return search_string = search.props.search_string.strip() print('Search changed to \'%s\'' % search_string) self.update_results_model(search_string, model) search.set_reply_hint('no-results-hint', GLib.Variant.new_string(NO_RESULTS_HINT)) search.emit('finished') def update_results_model(self, search, results): # read/parse ssh-config file self._config_hosts = [] self._config_file = Gio.file_new_for_path(SSHCONFIG_EXPAND) self._config_monitor = self._config_file.monitor_file( flags=Gio.FileMonitorFlags.NONE, cancellable=None) self._config_monitor.connect('changed', self.__read_config) self.__read_config(None, self._config_file, None, Gio.FileMonitorEvent.CREATED) # read/parse ssh-known_hosts file self._known_hosts = [] self._knownhosts_file = Gio.file_new_for_path(KNOWN_HOSTS_EXPAND) self._knownhosts_monitor = self._knownhosts_file.monitor_file(flags=Gio.FileMonitorFlags.NONE, cancellable=None) self.__read_known_hosts(None, self._knownhosts_file, None, Gio.FileMonitorEvent.CREATED) searchparts = search.split('@') searchhost = searchparts[-1] searchuser = '' if len(searchparts) == 2: searchuser = searchparts[0] found = [host for host in self._config_hosts if host.find(searchhost) >= 0] for host in found: target, port, conn_desc = self.__parse_hoststring(host, searchuser) results.append(uri='ssh://config/%s/%s' % (searchuser, host), icon_hint=TERMINAL_APP, category=0, mimetype=TERMINAL_APP_MIMETYPE, title=conn_desc, comment=conn_desc, dnd_uri='', result_type=Unity.ResultType.DEFAULT) found = [host for host in self._known_hosts if host.find(searchhost) >= 0] for host in found: target, port, conn_desc = self.__parse_hoststring(host, searchuser) results.append(uri='ssh://config/%s/%s' % (searchuser, host), icon_hint=TERMINAL_APP, category=1, mimetype=TERMINAL_APP_MIMETYPE, title=conn_desc, comment=conn_desc, dnd_uri='', result_type=Unity.ResultType.DEFAULT) def on_activate_uri(self, scope, uri): uri_splitted = uri.split('/') hoststring = uri_splitted[-1] user = uri_splitted[-2] target, port, conn_desc = self.__parse_hoststring(hoststring, user) if port == SSH_DEFAULT_PORT: # don't call with the port option, because the host definition # could be from the ~/.ssh/config file GLib.spawn_command_line_async('%s -e "ssh %s"' % (TERMINAL_APP, target)) else: GLib.spawn_command_line_async('%s -e "ssh -p %s %s"' % (TERMINAL_APP, port, target)) return Unity.ActivationResponse(handled=Unity.HandledType.HIDE_DASH, goto_uri='') def on_preview_uri(self, scope, uri): uri_splitted = uri.split('/') hoststring = uri_splitted[-1] user = uri_splitted[-2] target, port, conn_desc = self.__parse_hoststring(hoststring, user) image = Gio.ThemedIcon.new(TERMINAL_APP) preview = Unity.GenericPreview.new(conn_desc, '', image) action = Unity.PreviewAction.new("open", _("Connect"), None) action.connect("activated", self.on_activate_uri) preview.add_action(action) return preview if __name__ == '__main__': daemon = UnityExtras.dbus_own_name(BUS_NAME, Daemon, None) if daemon: GLib.unix_signal_add(0, 2, lambda x: daemon.quit(), None) daemon.run([]) unity-scope-sshsearch-0.1daily13.06.05/src/__init__.py0000644000015700001700000000000012153552723023336 0ustar pbuserpbgroup00000000000000unity-scope-sshsearch-0.1daily13.06.05/setup.py0000644000015700001700000000114612153552723022164 0ustar pbuserpbgroup00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- from distutils.core import setup from DistUtilsExtra.command import * setup(name='unity-scope-sshsearch', version='0.1', author='Mark Tully', author_email='markjtully@gmail.com', url='http://launchpad.net/ubuntu-scopes', license='GNU General Public License (GPL)', data_files=[ ('share/dbus-1/services', ['data/unity-scope-sshsearch.service']), ('share/unity-scopes/sshsearch', ['src/unity_sshsearch_daemon.py']), ], cmdclass={'build': build_extra.build_extra, 'build_i18n': build_i18n.build_i18n,}) unity-scope-sshsearch-0.1daily13.06.05/setup.cfg0000644000015700001700000000021012153552723022262 0ustar pbuserpbgroup00000000000000[build] i18n=True [build_i18n] domain=unity-scope-sshsearch desktop_files=[('share/unity/scopes/boxes', ('data/sshsearch.scope.in',))] unity-scope-sshsearch-0.1daily13.06.05/data/0000755000015700001700000000000012153554005021354 5ustar pbuserpbgroup00000000000000unity-scope-sshsearch-0.1daily13.06.05/data/unity-scope-sshsearch.service0000644000015700001700000000020012153552723027173 0ustar pbuserpbgroup00000000000000[D-BUS Service] Name=com.canonical.Unity.Scope.Boxes.Sshsearch Exec=/usr/share/unity-scopes/sshsearch/unity_sshsearch_daemon.py unity-scope-sshsearch-0.1daily13.06.05/data/icons/0000755000015700001700000000000012153554005022467 5ustar pbuserpbgroup00000000000000unity-scope-sshsearch-0.1daily13.06.05/data/sshsearch.scope.in0000644000015700001700000000120312153552723025000 0ustar pbuserpbgroup00000000000000[Scope] DBusName=com.canonical.Unity.Scope.Boxes.Sshsearch DBusPath=/com/canonical/unity/scope/boxes/sshsearch Icon= Loader=/usr/share/unity-scopes/sshsearch/unity_sshsearch_daemon.py _Keywords=sshsearch;ssh;connections; RequiredMetadata= OptionalMetadata= RemoteContent=false Type=boxes _Name=Sshsearch _Description=This is an Ubuntu search plugin that enables information from SSH connections to be searched and displayed in the Dash underneath the Boxes header. If you do not wish to search this content source, you can disable this search plugin. _SearchHint=Search Sshsearch [Desktop Entry] X-Ubuntu-Gettext-Domain=unity-scope-sshsearch