Commit 72db56fd authored by Yann Leboulanger's avatar Yann Leboulanger
Browse files

remove not ported plugins

parent 3e7571db
from fshare import FileSharePlugin
<?xml version="1.0"?>
<interface>
<requires lib="gtk+" version="2.16"/>
<!-- interface-naming-policy toplevel-contextual -->
<object class="GtkWindow" id="window1">
<child>
<object class="GtkVBox" id="hbox111">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkHBox" id="hbox1">
<property name="visible">True</property>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Incoming folder:</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="dl_folder">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x25CF;</property>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="position">0</property>
</packing>
</child>
</object>
</child>
</object>
</interface>
import sqlite3
from common import app
import sys
import os
class FilesharingDatabase:
def __init__(self, plugin):
self.plugin = plugin
path_l = os.path.split(plugin.config.FILE_PATH)
path = os.path.join(path_l[0], 'shared_files.db')
db_exist = os.path.exists(path)
self.conn = sqlite3.connect(path)
# Enable foreign keys contraints
self.conn.cursor().execute("pragma foreign_keys = on")
if not db_exist:
self.create_database()
# NOTE: Make sure we are getting and setting the requester without its
# resource
def create_database(self):
c = self.conn.cursor()
# Create tables
c.execute("CREATE TABLE permissions" +
"(fid integer REFERENCES files(fid) ON DELETE CASCADE, " +
"account text, requester text)")
c.execute("CREATE TABLE files" +
"(fid INTEGER PRIMARY KEY AUTOINCREMENT," +
" file_path text, relative_path text, hash_sha1 text," +
"size numeric, description text, mod_date text, is_dir boolean)")
# Save (commit) the changes
self.conn.commit()
c.close()
def get_toplevel_files(self, account, requester):
c = self.conn.cursor()
data = (account, requester)
c.execute("SELECT relative_path, hash_sha1, size, description, " +
"mod_date, is_dir FROM (files JOIN permissions ON" +
" files.fid=permissions.fid) WHERE account=? AND requester=?" +
" AND relative_path NOT LIKE '%/%'", data)
result = c.fetchall()
c.close()
return result
def get_files_from_dir(self, account, requester, dir_):
c = self.conn.cursor()
data = (account, requester, dir_ + '/%')
c.execute("SELECT relative_path, hash_sha1, size, description, " +
"mod_date, is_dir FROM (files JOIN permissions ON" +
" files.fid=permissions.fid) WHERE account=? AND requester=?" +
" AND relative_path LIKE ?", data)
result = c.fetchall()
c.close()
fresult = []
for r in result:
name = r[0][len(dir_) + 1:]
if '/' not in name:
fresult.append(r)
return fresult
def get_files(self, account, requester):
"""
>>> file_ = ('file_path', 'relative_path', 'hash', 999, 'description', \
'date', False)
>>> foo = add_file('account@gajim', 'requester@jabber', file_)
>>> result = get_files('account@gajim', 'requester@jabber')
>>> len(result)
1
>>> _delete_file(1)
"""
c = self.conn.cursor()
data = (account, requester)
c.execute("SELECT relative_path, hash_sha1, size, description, " +
"mod_date, is_dir FROM (files JOIN permissions ON" +
" files.fid=permissions.fid) WHERE account=? AND requester=?", data)
result = c.fetchall()
c.close()
return result
def get_file(self, account, requester, hash_, name):
c = self.conn.cursor()
if hash_:
data = (account, requester, hash_)
sql = "SELECT relative_path, hash_sha1, size, description, " + \
"mod_date, file_path FROM (files JOIN permissions ON" + \
" files.fid=permissions.fid) WHERE account=? AND requester=?" +\
" AND hash_sha1=?"
else:
data = (account, requester, name)
sql = "SELECT relative_path, hash_sha1, size, description, " + \
"mod_date, file_path FROM (files JOIN permissions ON" + \
" files.fid=permissions.fid) WHERE account=? AND requester=?" +\
" AND relative_path=?"
c.execute(sql, data)
result = c.fetchall()
c.close()
if result == []:
return None
else:
return result[0]
def get_files_name(self, account, requester):
result = self.get_files(account, requester)
flist = []
for r in result:
flist.append(r[0])
return flist
def add_file(self, account, requester, file_):
"""
>>> file_ = ('file_path', 'relative_path', 'hash', 999, 'description', \
'date', False)
>>> add_file('account@gajim', 'requester@jabber', file_)
1
>>> _delete_file(1)
"""
self._check_duplicate(account, requester, file_)
requester = app.get_jid_without_resource(requester)
c = self.conn.cursor()
c.execute("INSERT INTO files (file_path, " +
"relative_path, hash_sha1, size, description, mod_date, " +
" is_dir) VALUES (?,?,?,?,?,?,?)", file_)
fid = c.lastrowid
permission_data = (fid, account, requester)
c.execute("INSERT INTO permissions VALUES (?,?,?)", permission_data)
self.conn.commit()
c.close()
return fid
def _check_duplicate(self, account, requester, file_):
c = self.conn.cursor()
data = (account, requester, file_[1])
c.execute("SELECT * FROM (files JOIN permissions ON" +
" files.fid=permissions.fid) WHERE account=? AND requester=?" +
" AND relative_path=? ", data)
result = c.fetchall()
if file_[2] != '':
data = (account, requester, file_[2])
c.execute("SELECT * FROM (files JOIN permissions ON" +
" files.fid=permissions.fid) WHERE account=? AND requester=?" +
" AND hash_sha1=?)", data)
result.extend(c.fetchall())
if len(result) > 0:
raise Exception('Duplicated entry')
c.close()
def _delete_file(self, fid):
c = self.conn.cursor()
data = (fid, )
c.execute("DELETE FROM files WHERE fid=?", data)
self.conn.commit()
c.close()
def _delete_dir(self, dir_, account, requester):
c = self.conn.cursor()
data = (account, requester, dir_, dir_ + '/%')
sql = "DELETE FROM files WHERE fid IN " + \
" (SELECT files.fid FROM files, permissions WHERE" + \
" files.fid=permissions.fid AND account=?"+ \
" AND requester=? AND (relative_path=? OR relative_path LIKE ?))"
c.execute(sql, data)
self.conn.commit()
c.close()
def delete(self, account, requester, relative_path):
c = self.conn.cursor()
data = (account, requester, relative_path)
c.execute("SELECT files.fid, is_dir FROM (files JOIN permissions ON" +
" files.fid=permissions.fid) WHERE account=? AND requester=? AND " +
"relative_path=? ", data)
result = c.fetchone()
c.close()
if result[1] == 0:
self._delete_file(result[0])
else:
self._delete_dir(relative_path, account, requester)
def delete_all(self, account, requester):
c = self.conn.cursor()
data = (account, requester)
sql = "DELETE FROM files WHERE fid IN (SELECT fid FROM permissions" + \
" WHERE account=? AND requester=?)"
c.execute(sql, data)
self.conn.commit()
c.close()
if __name__ == "__main__":
"""
DELETE DATABASE FILE BEFORE RUNNING TESTS
"""
import doctest
path = sys.path[0]
path = path + '/' + 'shared_files.db'
conn = sqlite3.connect(path)
# Enable foreign keys contraints
conn.cursor().execute("pragma foreign_keys = on")
FilesharingDatabase.create_database()
doctest.testmod()
import gtk
import gobject
from common import gajim
from common import helpers
from common.file_props import FilesProp
import fshare
import os
import fshare_protocol
class FileShareWindow(gtk.Window):
def __init__(self, plugin):
self.plugin = plugin
gtk.Window.__init__(self)
self.set_title('File Share')
self.connect('delete_event', self.delete_event)
self.set_position(gtk.WIN_POS_CENTER)
self.set_default_size(400, 400)
# Children
self.notebook = gtk.Notebook()
# Browse page
self.bt_search = gtk.Button('Search')
self.bt_search.connect('clicked', self.on_bt_search_clicked)
self.entry_search = gtk.Entry(max=0)
self.entry_search.set_size_request(300, -1)
self.exp_advance = gtk.Expander('Advance')
self.ts_search = gtk.TreeStore(gobject.TYPE_STRING)
self.tv_search = gtk.TreeView(self.ts_search)
self.tv_search.connect('row-expanded', self.row_expanded)
self.tv_search.connect('button-press-event',
self.on_treeview_button_press_event)
self.browse_popup = gtk.Menu()
mi_download = gtk.MenuItem('Download')
mi_property = gtk.MenuItem('Property')
mi_download.show()
mi_property.show()
mi_download.connect('activate', self.on_download_clicked)
self.browse_popup.append(mi_download)
self.browse_popup.append(mi_property)
self.browse_sw = gtk.ScrolledWindow()
self.browse_sw.add(self.tv_search)
self.tvcolumn_browse = gtk.TreeViewColumn('')
self.tv_search.append_column(self.tvcolumn_browse)
self.cell_browse = gtk.CellRendererText()
self.tvcolumn_browse.pack_start(self.cell_browse, True)
self.tvcolumn_browse.add_attribute(self.cell_browse, 'text', 0)
self.lbl_browse = gtk.Label('Browse')
self.browse_hbox = gtk.HBox()
self.browse_hbox2 = gtk.HBox()
self.browse_vbox = gtk.VBox()
self.browse_hbox.pack_start(self.entry_search, True, True, 10)
self.browse_hbox.pack_start(self.bt_search, False, False, 10)
self.browse_vbox.pack_start(self.browse_hbox, False, False, 10)
self.browse_vbox.pack_start(self.exp_advance, False, False, 10)
self.browse_vbox.pack_start(self.browse_sw, True, True, 10)
self.notebook.append_page(self.browse_vbox, self.lbl_browse)
# file references for tv_search
self.browse_fref = {}
# contact references for tv_search
self.browse_jid = {}
# Information of the files inserted in the treeview: name, size, etc
self.brw_file_info = {}
# dummy row children so that we can get expanders
self.empty_row_child = {}
# Manage page
self.bt_add_file = gtk.Button('Add file')
self.bt_add_file.connect('clicked', self.add_file)
self.bt_add_dir = gtk.Button('Add directory')
self.bt_add_dir.connect('clicked', self.add_directory)
self.bt_remove = gtk.Button('Remove')
self.bt_remove.connect('clicked', self.remove_file_clicked)
self.bt_remove_all = gtk.Button('Remove all')
self.bt_remove_all.connect('clicked', self.remove_all_clicked)
self.ts_contacts = gtk.TreeStore(gobject.TYPE_STRING)
self.cbb_contacts = gtk.ComboBoxEntry(self.ts_contacts)
self.cbb_contacts.connect('changed', self.__check_combo_edit)
cbb_entry = self.cbb_contacts.child
self.cbb_completion = gtk.EntryCompletion()
cbb_entry.set_completion(self.cbb_completion)
self.cbb_completion.set_model(self.ts_contacts)
self.cbb_completion.set_text_column(0)
self.bt_stophash = gtk.Button('Calculating hash')
self.lbl_manage = gtk.Label('Manage Shared Files')
self.ts_files = gtk.TreeStore(gobject.TYPE_STRING)
self.tv_files = gtk.TreeView(self.ts_files)
self.treeSelection_files = self.tv_files.get_selection()
self.treeSelection_files.connect('changed', self.row_selected)
self.manage_sw = gtk.ScrolledWindow()
self.manage_sw.add(self.tv_files)
self.tvcolumn = gtk.TreeViewColumn('')
self.tv_files.append_column(self.tvcolumn)
self.cell = gtk.CellRendererText()
self.tvcolumn.pack_start(self.cell, True)
self.tvcolumn.add_attribute(self.cell, 'text', 0)
self.pb_filehash = gtk.ProgressBar()
self.manage_hbox = gtk.HBox()
self.manage_hbox2 = gtk.HBox()
self.manage_vbox = gtk.VBox()
self.manage_vbox2 = gtk.VBox()
self.manage_hbox.pack_start(self.bt_stophash , False, False, 10)
self.manage_hbox.pack_start(self.pb_filehash, True, True, 10)
self.manage_hbox.set_sensitive(False)
self.manage_vbox.pack_start(self.cbb_contacts, False, False, 10)
self.manage_vbox.pack_start(self.manage_hbox, False, False, 10)
self.manage_hbox2.pack_start(self.manage_sw, True, True, 10)
self.manage_hbox2.pack_start(self.manage_vbox2, False, False, 10)
self.manage_vbox2.pack_start(self.bt_add_file, False, False, 10)
self.manage_vbox2.pack_start(self.bt_add_dir, False, False, 10)
self.manage_vbox2.pack_start(self.bt_remove, False, False, 10)
self.manage_vbox2.pack_start(self.bt_remove_all, False, False, 10)
self.manage_vbox2.set_sensitive(False)
self.manage_vbox.pack_start(self.manage_hbox2, True, True, 10)
self.notebook.append_page(self.manage_vbox, self.lbl_manage)
# Preferences page
self.lbl_pref = gtk.Label('Preferences')
self.entry_dir_pref = gtk.Entry(max=0)
self.entry_dir_pref.set_text(self.plugin.config['incoming_dir'])
self.bt_sel_dir_pref = gtk.Button('Select dir', gtk.STOCK_OPEN)
self.bt_sel_dir_pref.connect('clicked', self.on_bt_sel_dir_pref_clicked)
self.frm_dir_pref = gtk.Frame('Incoming files directory')
self.frm_dir_pref.set_shadow_type(gtk.SHADOW_IN)
self.pref_hbox = gtk.HBox()
self.pref_vbox = gtk.VBox()
self.pref_hbox.pack_start(self.entry_dir_pref, True, True, 10)
self.pref_hbox.pack_start(self.bt_sel_dir_pref, False, False, 10)
self.frm_dir_pref.add(self.pref_hbox)
self.pref_vbox.pack_start(self.frm_dir_pref, False, False, 10)
self.notebook.append_page(self.pref_vbox , self.lbl_pref)
self.add(self.notebook)
self.show_all()
def set_account(self, account):
self.account = account
# connect window to protocol
pro = fshare.FileSharePlugin.prohandler[self.account]
pro.set_window(self)
def add_file(self, widget):
dialog = gtk.FileChooserDialog('Add file to be shared', self,
gtk.FILE_CHOOSER_ACTION_OPEN,
(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN,
gtk.RESPONSE_OK)
)
dialog.set_select_multiple(True)
response = dialog.run()
if response == gtk.RESPONSE_OK:
file_list = dialog.get_filenames()
self.add_items_tvcontacts(file_list)
dialog.destroy()
def add_directory(self, widget):
dialog = gtk.FileChooserDialog('Add directory to be shared', self,
gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,
(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN,
gtk.RESPONSE_ACCEPT)
)
response = dialog.run()
if response == gtk.RESPONSE_ACCEPT:
file_list = []
file_list.append(dialog.get_filename())
self.add_items_tvcontacts(file_list)
dialog.destroy()
def add_file_list(self, flist, treestore, fref = {}, root = None):
# file references to their in the treeStore
for f in flist:
# keeps track of the relative dir path
tail = ''
# keeps track of the parent row
parent = None
dirpath = f.split('/')
if len(dirpath) == 1:
# Top level file, it doesnt have parent, add it right away
fref[dirpath[0]] = treestore.insert(root, 0, (dirpath[0],))
else:
for dir_ in dirpath:
if tail + dir_ not in fref:
fref[tail + dir_] = treestore.append(parent, (dir_,))
parent = fref[tail + dir_]
tail = tail + dir_ + '/'
return fref
def __convert_date(self, epoch):
# Converts date-time from seconds from epoch to iso 8601
import time, datetime
ts = time.gmtime(epoch)
dt = datetime.datetime(ts.tm_year, ts.tm_mon, ts.tm_mday, ts.tm_hour,
ts.tm_min, ts.tm_sec)
return dt.isoformat()
def add_items_tvcontacts(self, file_list, parentdir = None, parent = None):
# TODO: execute this method inside of a thread
for f in file_list:
# Relative name to be used internally in the shared folders
relative_name = f.split('/')[-1]
if parentdir:
relative_name = parentdir + '/' + relative_name
short_name = relative_name.split('/')[-1]
if short_name[0] == '.':
# Return if it is a hidden file
return
if parent:
row = self.ts_files.append(parent, (short_name,))
else:
row = self.ts_files.insert(None, 0, (short_name,))
# File info
size = os.path.getsize(f)
is_dir = os.path.isdir(f)
mod_date = os.path.getmtime(f)
mod_date = self.__convert_date(mod_date)
# TODO: add hash
file_ = (f, relative_name, '', size, '', mod_date, is_dir)
requester = self.cbb_contacts.get_active_text()
try:
fid = self.plugin.database.add_file(self.account, requester,
file_)
except Exception, e:
if e == 'Duplicated entry':
print 'Error: ' + e
continue
else:
raise Exception(e)
if is_dir:
tmpfl = os.listdir(f)
fl = []
for item in tmpfl:
fl.append(f + '/' + item)
self.add_items_tvcontacts(fl, relative_name, row)
def add_contact_browse(self, contact):
fjid = contact.get_full_jid()
jid = gajim.get_jid_without_resource(fjid)
contacts = gajim.contacts.get_contacts(self.account, jid)
for con in contacts:
if con.show in ('offline', 'error') and not \
con.supports(fshare_protocol.NS_FILE_SHARING):
break
cjid = con.get_full_jid()
r = self.ts_search.insert(None, 0, (cjid, ))
self.browse_jid[cjid] = r
pro = fshare.FileSharePlugin.prohandler[self.account]
# Request list of files from peer
stanza = pro.request(cjid)
if pro.conn.connection:
pro.conn.connection.send(stanza)
def add_contact_manage(self, contact):
self.contacts_rows = []
self.cbb_contacts.grab_focus()
for c in gajim.contacts.iter_contacts(self.account):
jid = gajim.get_jid_without_resource(c.get_full_jid())
r = self.ts_contacts.insert(None, len(self.ts_contacts), (jid, ))
if c.get_full_jid() == contact.get_full_jid():
self.cbb_contacts.set_active_iter(r)
self.contacts_rows.append(r)
self.manage_vbox2.set_sensitive(True)
self.bt_remove.set_sensitive(False)
self.add_file_list(self.plugin.database.get_files_name(self.account,
gajim.get_jid_without_resource(contact.get_full_jid())),
self.ts_files)
def delete_event(self, widget, data=None):
fshare.FileSharePlugin.filesharewindow = {}
return False
def __check_combo_edit(self, widget, data=None):
self.ts_files.clear()
entry = self.cbb_contacts.child
contact = entry.get_text()
self.manage_vbox2.set_sensitive(False)
for i in self.contacts_rows:
# If the contact in the comboboxentry is include inside of the
# combobox
if contact == self.ts_contacts.get_value(i, 0):
self.add_file_list(self.plugin.database.get_files_name(
self.account, contact), self.ts_files)
self.manage_vbox2.set_sensitive(True)
self.bt_remove.set_sensitive(False)
break
def remove_file_clicked(self, widget, data=None):
entry = self.cbb_contacts.child
contact = entry.get_text()
sel = self.treeSelection_files.get_selected()
relative_name = self.ts_files.get_value(sel[1], 0)
self.ts_files.remove(sel[1])
self.plugin.database.delete(self.account, contact, relative_name)
widget.set_sensitive(False)
def remove_all_clicked(self, widget, data=None):
entry = self.cbb_contacts.child
contact = entry.get_text()
self.plugin.database.delete_all(self.account, contact)
self.ts_files.clear()
def row_selected(self, widget, data=None):
# When row is selected in tv_files
sel = self.treeSelection_files.get_selected()
if not sel[1]:
return
depth = self.ts_files.iter_depth(sel[1])
# Don't remove file and dirs that aren't at the root level
if depth == 0:
self.bt_remove.set_sensitive(True)
else:
self.bt_remove.set_sensitive(False)
def row_expanded(self, widget, iter_, path, data=None):
name = None
for key in self.empty_row_child:
parent = self.ts_search.iter_parent(self.empty_row_child[key])
p = self.ts_search.get_path(parent)
if p == path:
name = key
break
if name:
# if we found that the expanded row is the parent of the empty row
# remove it from the treestore and empty_row dictionary. Then ask
# peer for list of files of that directory
i = self.empty_row_child[name]
pro = fshare.FileSharePlugin.prohandler[self.account]
contact = self.get_contact_from_iter(self.ts_search, i)
contact = gajim.contacts.get_contact_with_highest_priority(
self.account, contact)
stanza = pro.request(contact.get_full_jid(), name, isFile=False)
if pro.conn.connection:
pro.conn.connection.send(stanza)
self.ts_search.remove(i)
del self.empty_row_child[name]
def get_contact_from_iter(self, treestore, iter_):
toplevel = treestore.get_iter_root()
while toplevel:
if treestore.is_ancestor(toplevel, iter_):
return gajim.get_jid_without_resource(treestore.get_value(
toplevel, 0))
toplevel = treestore.iter_next(toplevel)
def on_treeview_button_press_event(self, treeview, event):
if event.button ==