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()
@kepler
Copy link
Author

kepler commented Sep 2, 2011

Copy of SSHplus from Anil Gulecha, modified to support some very basic menu nesting.

@kepler
Copy link
Author

kepler commented Sep 2, 2011

Doesn't currently support importing nested menus from sshmenu configuration.

@WladyX
Copy link

WladyX commented Oct 6, 2011

Can you please update it for Ubuntu 11.10?
It doesn't show an icon in the notification area and it core dumps on refresh.
Thanks for youe effort.

@kepler
Copy link
Author

kepler commented Nov 9, 2011

It's working for me on Ubuntu 11.10 but using Gnome Shell, not Unity (so it's not the same notification area). Have you tried the lastest version from Anil's github repository (github.com/anilgulecha/misc)?

@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