28
28
from gi.repository import Unity
30
30
BUS_NAME = "net.launchpad.lens.sshsearch"
32
SSH_DEFAULT_PORT = '22'
31
33
SSHCONFIG = os.path.join('~', '.ssh', 'config')
32
34
SSHCONFIG_EXPAND = os.path.expanduser(SSHCONFIG)
33
35
KNOWN_HOSTS = os.path.join('~', '.ssh', 'known_hosts')
34
36
KNOWN_HOSTS_EXPAND = os.path.expanduser(KNOWN_HOSTS)
35
38
TERMINAL_APP = 'gnome-terminal'
36
39
TERMINAL_APP_MIMETYPE = 'application-x-desktop'
37
41
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
38
42
ICON_FILE = os.path.join(SCRIPT_DIR, 'unity-lens-sshsearch.png')
72
76
self._lens.add_local_scope (self._scope);
73
77
self._lens.export ()
75
self._config_hosts = self.__read_config()
76
self._known_hosts = self.__read_known_hosts()
77
print self._config_hosts
78
print self._known_hosts
80
def __read_config(self):
81
c = paramiko.SSHConfig()
82
c.parse(open(SSHCONFIG_EXPAND))
83
return [h['host'].lower() for h in c._config if h['host'] != '*']
85
def __read_known_hosts(self):
86
h = paramiko.HostKeys(KNOWN_HOSTS_EXPAND)
87
hosts = [host for host in h.keys() if len(host) != 60]
79
# read/parse ssh-config file
80
self._config_file = Gio.file_new_for_path(SSHCONFIG_EXPAND)
81
self._config_monitor = self._config_file.monitor_file(flags=Gio.FileMonitorFlags.NONE, cancellable=None)
82
self._config_monitor.connect('changed', self.__read_config)
83
self._config_hosts = self.__read_config(None, self._config_file, None, Gio.FileMonitorEvent.CREATED)
85
# read/parse ssh-known_hosts file
86
self._knownhosts_file = Gio.file_new_for_path(KNOWN_HOSTS_EXPAND)
87
self._knownhosts_monitor = self._knownhosts_file.monitor_file(flags=Gio.FileMonitorFlags.NONE, cancellable=None)
88
self._known_hosts = self.__read_known_hosts(None, self._knownhosts_file, None, Gio.FileMonitorEvent.CREATED)
90
def __read_config(self, filemonitor, file, other_file, event_type):
93
if not file.query_exists(None):
96
if (event_type in (Gio.FileMonitorEvent.CREATED,
97
Gio.FileMonitorEvent.CHANGED,
98
Gio.FileMonitorEvent.CHANGES_DONE_HINT)):
99
c = paramiko.SSHConfig()
100
c.parse(open(file.get_path()))
101
config_hosts = [h['host'].lower() for h in c._config if h['host'] != '*']
105
def __read_known_hosts(self, filemonitor, file, other_file, event_type):
107
if not file.query_exists(None):
110
if (event_type in (Gio.FileMonitorEvent.CREATED,
111
Gio.FileMonitorEvent.CHANGED,
112
Gio.FileMonitorEvent.CHANGES_DONE_HINT)):
113
h = paramiko.HostKeys(KNOWN_HOSTS_EXPAND)
114
known_hosts = [host for host in h.keys() if len(host) != 60]
90
118
def on_search_changed (self, entry, *args):
91
119
search = self._scope.props.active_search or None
105
133
results = self._scope.props.global_results_model
106
134
self.update_results_model(search_string, results)
136
def __parse_hoststring(self, hoststring, user):
137
# assign host and port
139
port = SSH_DEFAULT_PORT
140
if hoststring.startswith('['):
141
host, port = hoststring[1:].split(']:')
146
target = '%s@%s' % (user, host)
148
# assign connection-description
150
if port != SSH_DEFAULT_PORT:
151
conn_desc = '%s:%s' % (target, port)
153
return target, port, conn_desc
108
155
def update_results_model(self, search, model):
109
156
if search is None or search == '':
113
found = [host for host in self._config_hosts if host.find(search) >= 0]
160
searchparts = search.split('@')
161
searchhost = searchparts[-1]
163
if len(searchparts) == 2:
164
searchuser = searchparts[0]
166
found = [host for host in self._config_hosts if host.find(searchhost) >= 0]
114
167
for host in found:
115
model.append('ssh://config/%s' % host,
168
target, port, conn_desc = self.__parse_hoststring(host, searchuser)
169
model.append('ssh://config/%s/%s' % (searchuser, host),
118
172
TERMINAL_APP_MIMETYPE,
173
conn_desc, conn_desc, '')
121
found = [host for host in self._known_hosts if host.find(search) >= 0]
175
found = [host for host in self._known_hosts if host.find(searchhost) >= 0]
122
176
for host in found:
123
model.append('ssh://known_hosts/%s' % host,
177
target, port, conn_desc = self.__parse_hoststring(host, searchuser)
178
model.append('ssh://known_hosts/%s/%s' % (searchuser, host),
126
181
TERMINAL_APP_MIMETYPE,
129
def __parse_hoststring(self, hoststring):
130
if hoststring.startswith('['):
131
return hoststring[1:].split(']:')
132
return hoststring, 22
182
conn_desc, conn_desc, '')
134
184
def on_activate_uri (self, scope, uri):
135
hoststring = uri.split('/')[-1]
136
host, port = self.__parse_hoststring(hoststring)
185
uri_splitted = uri.split('/')
186
hoststring = uri_splitted[-1]
187
user = uri_splitted[-2]
188
target, port, conn_desc = self.__parse_hoststring(hoststring, user)
139
GLib.spawn_command_line_async('%s -e "ssh %s"' % (TERMINAL_APP, host))
190
if port == SSH_DEFAULT_PORT:
191
# don't call with the port option, because the host definition
192
# could be from the ~/.ssh/config file
193
GLib.spawn_command_line_async('%s -e "ssh %s"' % (TERMINAL_APP, target))
141
GLib.spawn_command_line_async('%s -e "ssh -p %s %s"' % (TERMINAL_APP, port, host))
195
GLib.spawn_command_line_async('%s -e "ssh -p %s %s"' % (TERMINAL_APP, port, target))
143
197
return Unity.ActivationResponse(handled=Unity.HandledType.HIDE_DASH, goto_uri='')