2
* Copyright (C) 2011 Antono Vasiljev <self@antono.info>
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation; either version 3 of the License, or
7
* (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
* Authored by Antono Vasiljev <self@antono.info>
26
public class SshPlugin: Object, Activatable, ItemProvider
28
public bool enabled { get; set; default = true; }
29
private HashMap<string, SshHost> hosts;
31
protected File config_file;
32
protected FileMonitor monitor;
41
hosts = new HashMap<string, SshHost> ();
44
public void activate ()
46
this.config_file = File.new_for_path (Environment.get_home_dir () + "/.ssh/config");
48
parse_ssh_config.begin ();
51
this.monitor = config_file.monitor_file (FileMonitorFlags.NONE);
52
this.monitor.changed.connect (this.handle_ssh_config_update);
56
Utils.Logger.warning (this, "Failed to start monitoring changes of ssh client config file");
60
public void deactivate () {}
62
static void register_plugin ()
64
DataSink.PluginRegistry.get_default ().register_plugin (
66
"SSH", // Plugin title
67
_ ("Connect to host with SSH"), // description
68
"terminal", // icon name
69
register_plugin, // reference to this function
70
// true if user's system has all required components which the plugin needs
71
(Environment.find_program_in_path ("ssh") != null),
72
_ ("ssh is not installed") // error message
76
private async void parse_ssh_config ()
82
var dis = new DataInputStream (config_file.read ());
84
// TODO: match key boundary
85
Regex host_key_re = new Regex ("(host\\s)", RegexCompileFlags.OPTIMIZE | RegexCompileFlags.CASELESS);
86
Regex comment_re = new Regex ("#.*$", RegexCompileFlags.OPTIMIZE);
87
Regex ws_re = new Regex ("[\\s]+", RegexCompileFlags.OPTIMIZE);
91
while ((line = yield dis.read_line_async (Priority.DEFAULT)) != null)
94
line = comment_re.replace (line, -1, 0, "");
95
if (host_key_re.match (line))
97
/* remove "Host" key */
98
line = host_key_re.replace (line, -1, 0, "");
99
/* Replace multiple whitespaces with a single space char */
100
line = ws_re.replace (line, -1, 0, " ").strip ();
101
/* split to find multiple host definition */
102
foreach (var host in line.split (" "))
104
string host_stripped = host.strip ();
105
if (host_stripped != "" && host_stripped.index_of ("*") == -1 && host_stripped.index_of ("?") == -1)
107
Utils.Logger.debug (this, "host added: %s\n", host_stripped);
108
hosts.set (host_stripped, new SshHost (host_stripped));
116
Utils.Logger.warning (this, "%s: %s", config_file.get_path (), e.message);
120
public void handle_ssh_config_update (FileMonitor monitor,
123
FileMonitorEvent event_type)
125
if (event_type == FileMonitorEvent.CHANGES_DONE_HINT)
127
Utils.Logger.log (this, "ssh_config is changed, reparsing");
128
parse_ssh_config.begin ();
132
public bool handles_query (Query query)
134
return hosts.size > 0 &&
135
( QueryFlags.ACTIONS in query.query_type ||
136
QueryFlags.INTERNET in query.query_type);
139
public async ResultSet? search (Query q) throws SearchError
141
Idle.add (search.callback);
143
q.check_cancellable ();
145
var results = new ResultSet ();
147
var matchers = Query.get_matchers_for_query (q.query_string, 0,
148
RegexCompileFlags.OPTIMIZE | RegexCompileFlags.CASELESS);
150
foreach (var host in hosts.values) //workaround for missing HashMap.iterator() method
152
foreach (var matcher in matchers)
154
if (matcher.key.match (host.host_query))
156
results.add (host, matcher.value - Match.Score.INCREMENT_SMALL);
162
q.check_cancellable ();
167
private class SshHost : Object, Match
169
public string title { get; construct set; }
170
public string description { get; set; }
171
public string icon_name { get; construct set; }
172
public bool has_thumbnail { get; construct set; }
173
public string thumbnail_path { get; construct set; }
174
public string host_query { get; construct set; }
175
public MatchType match_type { get; construct set; }
177
public void execute (Match? match)
181
AppInfo ai = AppInfo.create_from_commandline (
182
"ssh %s".printf (this.title),
183
"ssh", AppInfoCreateFlags.NEEDS_TERMINAL);
184
ai.launch (null, new Gdk.AppLaunchContext ());
188
warning ("%s", err.message);
192
public SshHost (string host_name)
195
match_type: MatchType.ACTION,
197
description: _("Connect with SSH"),
198
has_thumbnail: false,
199
icon_name: "terminal",
200
host_query: host_name
208
// vim: expandtab softtabstop tabstop=2