updated on Thu Jan 12 00:00:55 UTC 2012
[aur-mirror.git] / pysshfs / pysshfs.py
blob7f9f893dcc09f769248673a4419d213b22fbbd72
1 #!/usr/bin/python2
2 # -*- coding: utf-8 -*-
3 ##changing: - Add fusermount -z option
4 # - Add killall -KILL sshfs after fusermount to kill sshfs process when connection if turned off. unexpectedly (make file manager froze).
5 # - Removed mount point in home folder as the unique choice, we can choose whatever folder.
6 # - Empty fields as default (expect port)
7 # - "Open directory" box unchecked as default
8 # - Force mounting in a none empty folder (-o nonempty)
9 #To do: - Check/uncheck as default delete mount point when disconnect
10 # - Create a button to save profile
12 # Quick mount sshfs
14 # by ADcomp <david.madbox@gmail.com>
15 # http://www.ad-comp.be/
17 # This program is distributed under the terms of the GNU General Public License
18 # For more info see http://www.gnu.org/licenses/gpl.txt
21 import pexpect
22 import os
23 import gtk
25 VERSION = 0.2
26 ## print debug info ( True / False )
27 DEBUG = False
29 class Profil:
30 def __init__(self):
31 self.clear()
32 ## preremplissage des champs
33 def clear(self):
34 #self.user = os.getenv('USER')
35 self.user = ''
36 self.pwd = ''
37 self.host = ''
38 self.dir = ''
39 self.mountpoint = ''
40 self.port = '22'
42 def open(self, file):
43 self.clear()
44 home = os.environ['HOME']
45 file_src = "%s/.config/pysshfs/%s.profil" % (home, file)
46 if os.access(file_src, os.F_OK|os.R_OK):
47 f = open(file_src,'r')
48 for line in f:
49 if line == '\n' or line[0]=='#':
50 continue
51 try:
52 line = line.strip('\n')
53 key, value = line.split('=',1)
54 key = key.strip()
55 value = value.strip()
57 if key == 'user':
58 self.user = value
59 elif key == 'pwd':
60 self.pwd = value
61 elif key == 'host':
62 self.host = value
63 elif key == 'dir':
64 self.dir = value
65 elif key == 'mountpoint':
66 self.mountpoint = value
67 elif key == 'port':
68 self.port = value
69 except Exception, e:
70 print "EE : %s" % e
71 else:
72 print "can't access profil: %s" % profil
75 class UI:
76 def __init__(self):
77 # Create window
78 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
79 self.window.set_title("Mount sshFS")
80 self.window.set_position(gtk.WIN_POS_CENTER)
81 self.window.connect("destroy", self.quit)
83 if os.access('pysshfs.png', os.F_OK|os.R_OK):
84 self.window.set_icon_from_file('pysshfs.png')
85 else:
86 self.window.set_icon_from_file('/usr/share/pixmaps/pysshfs.png')
88 # Containers
89 BoxBase = gtk.VBox(False, 0)
90 BoxBase.set_spacing(10)
91 BoxBase.set_border_width(10)
93 BoxMain = gtk.HBox()
94 BoxMain.set_spacing(5)
95 BoxMain.set_border_width(5)
97 BoxControls = gtk.HButtonBox()
98 #~ BoxControls.set_spacing(2)
99 BoxControls.set_layout(gtk.BUTTONBOX_END)
101 # Exit
102 button_exit = gtk.Button(stock=gtk.STOCK_CLOSE)
103 button_exit.connect("clicked", self.quit)
104 BoxControls.pack_end(button_exit, False, False)
106 table = gtk.Table()
107 table.set_row_spacings(5)
108 table.set_col_spacings(5)
110 ## Combo Profil
111 self.profil_combo = gtk.combo_box_new_text()
112 self.profil_combo.append_text('New Connection')
114 home = os.environ['HOME']
116 if os.path.exists("%s/.config/pysshfs" % home):
117 listdir = os.listdir("%s/.config/pysshfs" % home)
118 for profil in listdir:
119 if '.profil' in profil:
120 self.profil_combo.append_text(profil[:-7])
122 self.profil_combo.set_active(0)
123 self.profil_combo.connect('changed', self.changed_profil)
125 table.attach(self.profil_combo, 0, 2, 0, 1)
127 ## User
128 self.User_entry = gtk.Entry()
130 label = gtk.Label('User :')
131 label.set_alignment(0, 1)
132 table.attach(label, 0, 1, 1, 2)
133 table.attach(self.User_entry, 1, 2, 1, 2)
135 ## Password
136 self.Password_entry = gtk.Entry()
137 self.Password_entry.set_visibility(False)
138 label = gtk.Label('Password :')
139 label.set_alignment(0, 1)
140 table.attach(label, 0, 1, 2, 3)
141 table.attach(self.Password_entry, 1, 2, 2, 3)
143 ## Host
144 self.Host_entry = gtk.Entry()
145 label = gtk.Label('Host :')
146 label.set_alignment(0, 1)
147 table.attach(label, 0, 1, 3, 4)
148 table.attach(self.Host_entry, 1, 2, 3, 4)
150 ## Dir
151 self.Dir_entry = gtk.Entry()
152 label = gtk.Label('Dir :')
153 label.set_alignment(0, 1)
154 table.attach(label, 0, 1, 4, 5)
155 table.attach(self.Dir_entry, 1, 2, 4, 5)
157 ## Mountpoint
158 self.Mountpoint_entry = gtk.Entry()
159 label = gtk.Label('Mountpoint :')
160 label.set_alignment(0, 1)
161 table.attach(label, 0, 1, 5, 6)
162 table.attach(self.Mountpoint_entry, 1, 2, 5, 6)
164 ## Port
165 self.Port_entry = gtk.Entry()
166 label = gtk.Label('Port :')
167 label.set_alignment(0, 1)
168 table.attach(label, 0, 1, 6, 7)
169 table.attach(self.Port_entry, 1, 2, 6, 7)
171 # Open directory
172 self.OpenDir_checkbox = gtk.CheckButton('Open directory')
173 ## cocher/decocher par defaut l'ouverture du dossier
174 self.OpenDir_checkbox.set_active(False)
175 table.attach(self.OpenDir_checkbox, 0, 1, 7, 8)
177 ## Connect
178 self.Connect_Bt = gtk.Button(stock=gtk.STOCK_CONNECT)
179 self.Connect_Bt.connect("clicked", self.mount_sshfs)
180 table.attach(self.Connect_Bt, 1, 2, 7, 8)
182 ## Separator
183 table.attach(gtk.HSeparator(), 0, 2, 8, 9)
185 ## Label
186 label = gtk.Label()
187 label.set_markup("<b>Mountpoint</b>")
188 label.set_alignment(0, 1)
189 table.attach(label, 0, 2, 9, 10)
191 ## Mounted_FS
192 self.Mounted_fs_combo = gtk.combo_box_new_text()
193 table.attach(self.Mounted_fs_combo, 0, 2, 10, 11)
195 ## Open / Umount
196 self.Open_Bt = gtk.Button(stock=gtk.STOCK_OPEN)
197 self.Open_Bt.connect("clicked", self.open_mountpoint)
198 table.attach(self.Open_Bt, 0, 1, 11, 12)
200 self.Umount_Bt = gtk.Button(stock=gtk.STOCK_DISCONNECT)
201 self.Umount_Bt.connect("clicked", self.umount_sshfs)
202 table.attach(self.Umount_Bt, 1, 2, 11, 12)
204 ## creation du bouton de sauvegarde de profil
205 #self.Umount_Bt = gtk.Button(stock=gtk.STOCK_SAVE)
206 #Self.Umount_Bt.connect("clicked", self.save_profile)
207 #table.attach(self.Umount_Bt, 0, 2, 16, 17)
209 ## Remove mountpoint
210 self.check_remove = gtk.CheckButton('delete mountpoint when disconnect')
211 table.attach(self.check_remove, 0, 2, 12, 13)
213 ## Separator
214 table.attach(gtk.HSeparator(), 0, 2, 13, 14)
216 #~ BoxMain.add(table)
217 BoxBase.pack_start(table, True)
218 BoxBase.pack_end(BoxControls, False)
220 self.window.add(BoxBase)
221 #turn off auto mountpoint
222 #self.User_entry.connect("changed", self.auto_mountpoint)
223 #self.Host_entry.connect("changed", self.auto_mountpoint)
225 self.update_mountedfs()
227 self.profil = Profil()
228 self.init_entry(self.profil)
230 #Show main window frame and all content
231 self.window.show_all()
233 def init_entry(self, profil):
234 self.User_entry.set_text(profil.user)
235 self.Password_entry.set_text(profil.pwd)
236 self.Host_entry.set_text(profil.host)
237 self.Dir_entry.set_text(profil.dir)
238 self.Mountpoint_entry.set_text(profil.mountpoint)
239 self.Port_entry.set_text(profil.port)
241 def changed_profil(self, combobox):
242 model = combobox.get_model()
243 index = combobox.get_active()
245 if index == 0:
246 self.profil.clear()
247 self.init_entry(self.profil)
248 elif index:
249 self.profil.open(model[index][0])
250 self.init_entry(self.profil)
252 return
254 def open_profil(self, profil):
255 print 'open_profil: %s' % profil
256 #desactive la creation auto du point de montage
257 # def auto_mountpoint(self, widget):
258 # User = self.User_entry.get_text()
259 # Host = self.Host_entry.get_text()
260 # self.Mountpoint_entry.set_text('%s@%s' % (User, Host))
262 def open_mountpoint(self, widget):
263 mount_point = self.Mounted_fs_combo.get_active()
264 if mount_point == 0 or mount_point == -1:
265 return
266 else:
267 os.system('xdg-open %s' % self.Mounted_fs_combo.get_active_text())
269 def umount_sshfs(self, widget):
270 mount_point = self.Mounted_fs_combo.get_active()
271 if mount_point == 0 or mount_point == -1:
272 return
273 else:
274 os.system('fusermount -u -z %s && killall -KILL sshfs' % self.Mounted_fs_combo.get_active_text())
275 if self.check_remove.get_active():
276 os.rmdir(self.Mounted_fs_combo.get_active_text())
277 self.update_mountedfs()
278 ## button ton save profile
279 #def save_profile(self, widget):
281 def update_mountedfs(self):
282 self.mounted_fs_tab = get_mounted_fs()
283 self.Mounted_fs_combo.get_model().clear()
284 self.Mounted_fs_combo.insert_text(0, 'Choose')
286 ind = 1
287 for mounted_fs in self.mounted_fs_tab:
288 self.Mounted_fs_combo.insert_text(ind, mounted_fs[1])
289 ind += 1
290 self.Mounted_fs_combo.set_active(0)
292 def mount_sshfs(self, widget):
293 User = self.User_entry.get_text()
294 Password = self.Password_entry.get_text()
295 Host = self.Host_entry.get_text()
296 Dir = self.Dir_entry.get_text()
298 Mountpoint = self.Mountpoint_entry.get_text()
299 #Mountpoint = os.getenv('HOME') + '/' + self.Mountpoint_entry.get_text()
301 if not os.path.exists(Mountpoint):
302 os.mkdir(Mountpoint)
304 Port = self.Port_entry.get_text()
306 if User == '' or Password == '' or Host == '' or Mountpoint =='' or Port =='':
307 #!FixME
308 debug_info('Error : please check your config')
309 show_msg('Error : please check your config')
310 return
312 sshfs = sshFs()
313 ret = sshfs.mount(User, Password, Host, Dir, Mountpoint, Port)
314 self.update_mountedfs()
316 if ret[0] == 0:
317 if self.OpenDir_checkbox.get_active():
318 os.system('xdg-open %s' % Mountpoint)
319 else:
320 show_msg(ret[1])
322 def run(self):
323 gtk.main()
325 def quit(self, widget=None, data=None):
326 gtk.main_quit()
328 ## Initialize the module.
329 class sshFs:
330 def __init__(self):
331 ## Three responses we might expect.
332 self.Initial_Responses = ['Are you sure you want to continue connecting (yes/no)?',
333 'password:', pexpect.EOF]
335 def mount(self, User="", Password="", Host="", Dir="", Mountpoint="", Port=22, Timeout=120):
337 Command = "sshfs -o allow_other -o nonempty -p %s %s@%s:%s %s" % (Port, User, Host, Dir, Mountpoint)
338 debug_info("Command : %s" % Command)
340 child = pexpect.spawn(Command)
342 ## Get the first response.
343 ret = child.expect (self.Initial_Responses, Timeout)
344 ## The first reponse is to accept the key.
345 if ret==0:
346 debug_info("The first reponse is to accept the key.")
347 #~ T = child.read(100)
348 child.sendline("yes")
349 child.expect('password:', Timeout)
350 child.sendline(Password)
351 ## The second response sends the password.
352 elif ret == 1:
353 debug_info("The second response sends the password.")
354 child.sendline(Password)
355 ## Otherwise, there is an error.
356 else:
357 debug_info("Otherwise, there is an error.")
358 return (-3, 'ERROR: Unknown: ' + str(child.before))
360 ## Get the next response.
361 Possible_Responses = ['password:', pexpect.EOF]
362 ret = child.expect (Possible_Responses, Timeout)
364 ## If it asks for a password, error.
365 if ret == 0:
366 debug_info("If it asks for a password, error.")
367 return (-4, 'ERROR: Incorrect password.')
368 elif ret == 1:
369 debug_info("Otherwise we are okay.")
370 return (0, str(child.after))
371 ## Otherwise we are okay.
372 else:
373 debug_info("Otherwise, there is an error.")
374 return (-3, 'ERROR: Unknown: ' + str(child.before))
376 def show_msg(msg=' .. '):
377 """ """
378 message = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_OK, msg)
379 resp = message.run()
380 message.destroy()
382 def get_mounted_fs():
383 """ get_mounted_fs() -> reads mtab and returns a list of mounted sshfs filesystems. """
384 try:
385 mounted_fs = []
386 lines = [line.strip("\n").split(" ") for line in open ("/etc/mtab", "r").readlines()]
387 for line in lines:
388 if line[2] == "fuse.sshfs" and "user=%s" % os.getenv('USER') in line[3]:
389 mounted_fs.append((line[0], line[1]))
390 return mounted_fs
391 except:
392 debug_info("Could not read mtab")
393 show_msg("Could not read mtab .. :(")
395 def debug_info(msg):
396 if DEBUG:
397 print "# %s" % msg
399 if __name__ == "__main__":
400 ui = UI()
401 ui.run()