Skip to content

Instantly share code, notes, and snippets.

@kepler
Created September 2, 2011 18:03
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save kepler/1189327 to your computer and use it in GitHub Desktop.
Save kepler/1189327 to your computer and use it in GitHub Desktop.
SSHplus
#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# SSHplus
# A remote connect utlity, sshmenu compatible clone, and application starter.
#
# (C) 2011 Anil Gulecha
# Based on sshlist, incorporating changes by Benjamin Heil's simplestarter
#
# 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.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Instructions
#
# 1. Copy file sshplus.py (this file) to /usr/local/bin
# 2. Edit file .sshplus in your home directory to add menu entries, each
# line in the format NAME|COMMAND|ARGS
# 3. Launch sshplus.py
# 4. Or better yet, add it to gnome startup programs list so it's run on login.
import gobject
import gtk
import appindicator
import os
import pynotify
import sys
import shlex
_VERSION = "1.0"
_SETTINGS_FILE = os.getenv("HOME") + "/.sshplus"
_SSHMENU_FILE = os.getenv("HOME") + "/.sshmenu"
_ABOUT_TXT = """A simple application starter as appindicator.
To add items to the menu, edit the file <i>.sshplus</i> in your home directory. Each entry must be on a new line in this format:
<tt>NAME|COMMAND|ARGS</tt>
If the item is clicked in the menu, COMMAND with arguments ARGS will be executed. ARGS can be empty. To insert a separator, add a line which only contains "sep". Lines starting with "#" will be ignored. You can set an unclickable label with the prefix "label:". Items from sshmenu configuration will be automatically added (except nested items). To insert a nested menu, use the prefix "folder:menu name". Subsequent items will be inserted in this menu, until a line containing an empty folder name is found: "folder:". After that, subsequent items get inserted in the parent menu. That means that more than one level of nested menus can be created.
Example file:
<tt><small>
Show top|gnome-terminal|-x top
sep
# this is a comment
label:SSH connections
# create a folder named "Home"
folder:Home
SSH Ex|gnome-terminal|-x ssh user@1.2.3.4
# to mark the end of items inside "Home", specify and empty folder:
folder:
# this item appears in the main menu
SSH Ex|gnome-terminal|-x ssh user@1.2.3.4
label:RDP connections
RDP Ex|rdesktop|-T "RDP-Server" -r sound:local 1.2.3.4
</small></tt>
Copyright 2011 Anil Gulecha
Incorporating changes from simplestarter, Benjamin Heil, http://www.bheil.net
Released under GPL3, http://www.gnu.org/licenses/gpl-3.0.html"""
def menuitem_response(w, item):
if item == '_about':
show_help_dlg(_ABOUT_TXT)
elif item == '_refresh':
newmenu = build_menu()
ind.set_menu(newmenu)
pynotify.Notification("SSHplus refreshed", "Menu list was refreshed from %s" % _SETTINGS_FILE).show()
elif item == '_quit':
sys.exit(0)
elif item == 'folder':
pass
else:
print item
os.spawnvp(os.P_NOWAIT, item['cmd'], [item['cmd']] + item['args'])
os.wait3(os.WNOHANG)
def show_help_dlg(msg, error=False):
if error:
dlg_icon = gtk.MESSAGE_ERROR
else:
dlg_icon = gtk.MESSAGE_INFO
md = gtk.MessageDialog(None, 0, dlg_icon, gtk.BUTTONS_OK)
try:
md.set_markup("<b>SSHplus %s</b>" % _VERSION)
md.format_secondary_markup(msg)
md.run()
finally:
md.destroy()
def add_separator(menu):
separator = gtk.SeparatorMenuItem()
separator.show()
menu.append(separator)
def add_menu_item(menu, caption, item=None):
menu_item = gtk.MenuItem(caption)
if item:
menu_item.connect("activate", menuitem_response, item)
else:
menu_item.set_sensitive(False)
menu_item.show()
menu.append(menu_item)
return menu_item
def get_sshmenuconfig():
if not os.path.exists(_SSHMENU_FILE):
return None
hostlist=open(os.getenv("HOME")+"/.sshmenu","r").read()
smenutitle=[]
smenuparams=[]
try:
for line in hostlist.split("\n"):
if line[2:7] == "title":
smenutitle.append(line.split(":")[1])
if line[2:11] == "sshparams":
smenuparams.append(line.split(":")[1])
if len(smenutitle) == len(smenuparams):
if len(smenutitle) != 0:
return (smenutitle,smenuparams)
else:
if len(smenuparams) != 0:
return (smenuparams,smenuparams)
return None
except:
return None
def get_sshplusconfig():
if not os.path.exists(_SETTINGS_FILE):
return []
app_list = []
f = open(_SETTINGS_FILE, "r")
try:
for line in f.readlines():
line = line.rstrip()
if not line or line.startswith('#'):
continue
elif line == "sep":
app_list.append('sep')
elif line.startswith('label:'):
app_list.append({
'name': 'LABEL',
'cmd': line[6:],
'args': ''
})
elif line.startswith('folder:'):
app_list.append({
'name': 'FOLDER',
'cmd': line[7:],
'args': ''
})
else:
try:
name, cmd, args = line.split('|', 2)
app_list.append({
'name': name,
'cmd': cmd,
'args': [n.replace("\n", "") for n in shlex.split(args)],
})
except ValueError:
print "The following line has errors and will be ignored:\n%s" % line
finally:
f.close()
return app_list
def build_menu():
if not os.path.exists(_SETTINGS_FILE) and not os.path.exists(_SSHMENU_FILE) :
show_help_dlg("<b>ERROR: No .sshmenu or .sshplus file found in home directory</b>\n\n%s" % \
_ABOUT_TXT, error=True)
sys.exit(1)
app_list = get_sshplusconfig()
#Add sshmenu config items if any
sshmenuitems = get_sshmenuconfig()
if sshmenuitems != None:
app_list.append("sep")
app_list.append({
'name': 'LABEL',
'cmd': "SSHmenu",
'args': ''
})
titles=sshmenuitems[0]
sshparams=sshmenuitems[1]
for i in range(len(titles)):
app_list.append({
'name': titles[i],
'cmd': "gnome-terminal",
'args': [n.replace("\n", "") for n in shlex.split("-x ssh " + sshparams[i])],
})
menu = gtk.Menu()
menus = [menu]
for app in app_list:
if app == "sep":
add_separator(menus[-1])
elif app['name'] == "FOLDER" and not app['cmd']:
if len(menus) > 1:
menus.pop()
elif app['name'] == "FOLDER":
menu_item = add_menu_item(menus[-1], app['cmd'], 'folder')
menus.append(gtk.Menu())
menu_item.set_submenu(menus[-1])
elif app['name'] == "LABEL":
add_menu_item(menus[-1], app['cmd'], None)
else:
add_menu_item(menus[-1], app['name'], app)
add_separator(menu)
add_menu_item(menu, 'Refresh', '_refresh')
add_menu_item(menu, 'About', '_about')
add_separator(menu)
add_menu_item(menu, 'Quit', '_quit')
return menu
if __name__ == "__main__":
ind = appindicator.Indicator("sshplus", "stock_connect",
appindicator.CATEGORY_APPLICATION_STATUS)
#ind.set_label("Launch")
ind.set_status(appindicator.STATUS_ACTIVE)
appmenu = build_menu()
ind.set_menu(appmenu)
gtk.main()
@WladyX
Copy link

WladyX commented Nov 10, 2011

Yes, the latest version from Anil is working,
Thanks.

@rnijenhu
Copy link

Link update: https://github.com/anilgulecha/misc

works on ubuntu 16.04

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment