#!/usr/bin/env python

# Free Open FTP Face (C)2006 Jeffrey Bakker
#
# FOFF is a graphical FTP client written in pyGTK.

# FOFF is compact, multiplatform (any system that supports GTK+ and python),
# has a simple and friendly interface, and has built-in convenience features
# including an image viewer, text viewer, one-click compress/decompress with
# gzip, and a mini console that takes both FTP commands and operating system
# commands.


# 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 2 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, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.


import ftplib
import time, datetime
import webbrowser
import pyDes

import gtk
import pango
import libglade

import foffplay as player
from foffutil import *
from foffwnds import *

import threading
import os, stat
import re

import locale
locale.setlocale(locale.LC_ALL,'')


# main window class from GladeWrapper ==========================================
class mainWnd(libglade.GladeWrapper):

	# grab widgets from xml ================================================
	def __init__(self, Filename, WindowName):
		libglade.GladeWrapper.__init__(self, Filename, WindowName)

		self.ftp = None
		self.cwd = os.getcwd()
		self.conncwd = ''
		self.account = ''

		self.showhidden = 1
		self.activeview = 1

		# OS Specific config dir
		if os.name == 'posix':
			self.rcdir = os.environ["HOME"] + "/.foffrc"
		else:
			self.rcdir = os.environ["HOMEDRIVE"] + os.environ["HOMEPATH"] + "\\foffrc"

		self.foffrc = os.path.join(self.rcdir, "foff.conf")

		"""
		try:
			self.toolbar2.set_icon_size(gtk.ICON_SIZE_SMALL_TOOLBAR)
			self.toolbar3.set_icon_size(gtk.ICON_SIZE_SMALL_TOOLBAR)
			self.toolbar2v.set_icon_size(gtk.ICON_SIZE_SMALL_TOOLBAR)
			self.toolbar3v.set_icon_size(gtk.ICON_SIZE_SMALL_TOOLBAR)
		except:
			pass
		"""

		# disable remote functions when not connected
		self.toolbar3.set_sensitive(False)
		self.toolbar3v.set_sensitive(False)
		self.remote1.set_sensitive(False)

		# ul/dl treeviews
		self.tvDl = gtk.TreeView()
		self.tvUl = gtk.TreeView()
		self.tvDl.set_headers_visible(True)
		self.tvUl.set_headers_visible(True)
		self.tvDl.show()
		self.tvUl.show()


		# download queue
		self.dl_model = gtk.ListStore(str, str, str, int, str, str)
		self.tvDl.set_model(self.dl_model)

		dir_column = gtk.TreeViewColumn("D", gtk.CellRendererPixbuf(), stock_id=0)
		files_column = gtk.TreeViewColumn("Filename", gtk.CellRendererText(), text=1)
		size_column = gtk.TreeViewColumn("Size (bytes)", gtk.CellRendererText(), text=2)
		time_column = gtk.TreeViewColumn("Download Progress", gtk.CellRendererProgress(), value=3)
		done_column = gtk.TreeViewColumn("Received (bytes)", gtk.CellRendererText(), text=4)
		stat_column = gtk.TreeViewColumn("Status", gtk.CellRendererPixbuf(), stock_id=5)

		self.tvDl.append_column(stat_column)
		self.tvDl.append_column(dir_column)
		self.tvDl.append_column(files_column)
		self.tvDl.append_column(size_column)
		self.tvDl.append_column(done_column)
		self.tvDl.append_column(time_column)

		self.tvDl.get_selection().set_mode(gtk.SELECTION_MULTIPLE)


		# upload queue
		self.ul_model = gtk.ListStore(str, str, str, str, str)
		self.tvUl.set_model(self.ul_model)

		dir_column = gtk.TreeViewColumn("D", gtk.CellRendererPixbuf(), stock_id=0)
		files_column = gtk.TreeViewColumn("Filename", gtk.CellRendererText(), text=1)
		size_column = gtk.TreeViewColumn("Size (bytes)", gtk.CellRendererText(), text=2)
		time_column = gtk.TreeViewColumn("Upload Progress", gtk.CellRendererProgress(), text=3)
		stat_column = gtk.TreeViewColumn("Status", gtk.CellRendererPixbuf(), stock_id=4)

		self.tvUl.append_column(stat_column)
		self.tvUl.append_column(dir_column)
		self.tvUl.append_column(files_column)
		self.tvUl.append_column(size_column)
		self.tvUl.append_column(time_column)

		self.tvUl.get_selection().set_mode(gtk.SELECTION_MULTIPLE)


		# messages and tranfer info notebook
		label1 = gtk.Label("Downloads")
		self.swDl = gtk.ScrolledWindow()
		self.swDl.add(self.tvDl)
		self.swDl.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
		self.swDl.show()
		self.notebook.append_page(self.swDl, label1)
		label1.show()

		label2 = gtk.Label("Uploads")
		self.swUl = gtk.ScrolledWindow()
		self.swUl.add(self.tvUl)
		self.swUl.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
		self.swUl.show()
		self.notebook.append_page(self.swUl, label2)
		label2.show()

		if player.SOUND_PLAYER == 1:
			self.sWnd = player.sndWnd("/usr/share/foff/foff-player.glade", "sndWnd")
			self.sWnd.sndWnd.remove(self.sWnd.vbPlayer)

			label3 = gtk.Label("Audio Player")
			self.notebook.append_page(self.sWnd.vbPlayer, label3)
			label3.show()

		else:
			self.audioplayer0.hide()
			self.audioplayer1.hide()
			"""
			xml = gtk.glade.XML("/usr/share/foff/foff-player.glade", root="vbPlayer")
			self.sWnd = xml.get_widget("vbPlayer")
			self.sWnd.set_sensitive(False)

			label3 = gtk.Label("Audio Player")
			self.notebook.append_page(self.sWnd, label3)
			label3.show()
			"""

		self.notebook.set_current_page(0)


		# local files list
		dir_column = gtk.TreeViewColumn("D", gtk.CellRendererPixbuf(), stock_id=0)
		files_column = gtk.TreeViewColumn("Filename", gtk.CellRendererText(), text=1)
		size_column = gtk.TreeViewColumn("Size (bytes)", gtk.CellRendererText(), text=2)
		time_column = gtk.TreeViewColumn("Last Modified", gtk.CellRendererText(), text=3)

		self.local_model = gtk.ListStore(str, str, str, str, str)
		self.tvLocalFiles.set_model(self.local_model)

		self.tvLocalFiles.append_column(dir_column)
		self.tvLocalFiles.append_column(files_column)
		self.tvLocalFiles.append_column(size_column)
		self.tvLocalFiles.append_column(time_column)

		self.tvLocalFiles.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
		self.tvLocalFiles.set_search_column(1)


		# remote files list
		dir_column = gtk.TreeViewColumn("D", gtk.CellRendererPixbuf(), stock_id=0)
		files_column = gtk.TreeViewColumn("Filename", gtk.CellRendererText(), text=1)
		size_column = gtk.TreeViewColumn("Size (bytes)", gtk.CellRendererText(), text=2)
		time_column = gtk.TreeViewColumn("Last Modified", gtk.CellRendererText(), text=3)

		self.remote_model = gtk.ListStore(str, str, str, str)
		self.tvRemoteFiles.set_model(self.remote_model)

		self.tvRemoteFiles.append_column(dir_column)
		self.tvRemoteFiles.append_column(files_column)
		self.tvRemoteFiles.append_column(size_column)
		self.tvRemoteFiles.append_column(time_column)

		self.tvRemoteFiles.get_selection().set_mode(gtk.SELECTION_MULTIPLE)
		self.tvRemoteFiles.set_search_column(1)

		# remote folder combo box
		self.cbRemoteDir.clear()

		self.cbmdl = gtk.ListStore(str)
		dircell = gtk.CellRendererPixbuf()
		txtcell = gtk.CellRendererText()
		dircell.set_property("stock-id", "gtk-directory")
		dircell.set_property("stock-size", gtk.ICON_SIZE_BUTTON)

		self.cbRemoteDir.pack_start(dircell, False)
		self.cbRemoteDir.pack_start(txtcell, True)
		self.cbRemoteDir.add_attribute(txtcell, 'text', 0)
		self.cbRemoteDir.set_model(self.cbmdl)

		# enter keypress for connection
		self.cbeServer.child.connect("key-press-event", self.connect_enter)
		self.entPort.connect("key-press-event", self.connect_enter)
		self.entUser.connect("key-press-event", self.connect_enter)
		self.entPass.connect("key-press-event", self.connect_enter)


		# command bar
		self.cbCommType.set_active(0)
		self.cbeCommand.child.connect("key-press-event", self.command_enter)
		self.cbRemoteDir.get_model().clear()

		self.txvMessages.set_left_margin(4)
		self.txvMessages.set_right_margin(4)
		self.txvMessages.modify_font(pango.FontDescription('monospace'))
		self.textbuff = self.txvMessages.get_buffer()

		img = gtk.gdk.pixbuf_new_from_file_at_size("/usr/share/foff/foff_logo00.png", 64,52)
		self.textbuff.insert_pixbuf(self.textbuff.get_end_iter(),img)
		self.textbuff.insert(self.textbuff.get_end_iter(),"Welcome to Free, Open FTP Face. =)\n")

		# initialize settings
		self.tbhidden1.set_active(True)
		self.options1.hide()

		if not os.path.exists(self.foffrc):

			if not os.path.exists(self.rcdir):

				os.mkdir(self.rcdir)
			else:

				mstr = "<b>New 'Bookmark' Format</b>\n"
				mstr += "If this is your first time running FOFF 0.99.4 or later, "
				mstr += "you must backup and remove the old .foff files in " + self.rcdir

				msg = gtk.MessageDialog(None,gtk.DIALOG_MODAL,gtk.MESSAGE_WARNING,gtk.BUTTONS_OK)
				msg.set_icon_name("gtk-dialog-warning")
				msg.set_title('First Run')
				msg.set_markup(mstr)

				response = msg.run()
				msg.destroy()

			self.save_preferences()
		else:
			self.load_preferences()


		# list saved sites
		self.read_servers_config()

		# load local directory contents
		self.load_local_dir(self.fcLocalDir.get_filename())

	# print to messages ====================================================
	def printm(self, message, stock_id="gtk-dialog-info"):

		img = self.txvMessages.render_icon(stock_id, gtk.ICON_SIZE_MENU)
		self.textbuff.insert_pixbuf(self.textbuff.get_end_iter(),img)
		self.textbuff.insert(self.textbuff.get_end_iter(), message)
		self.txvMessages.scroll_mark_onscreen(self.textbuff.get_insert())

		if stock_id == "gtk-dialog-error":

			self.notebook.set_current_page(0)

	# load settings ========================================================
	def load_preferences(self):

		try:
			rc = open(self.foffrc, "r")
		except:
			self.printm("Config file not found.\n", "gtk-dialog-error")

			return

		for line in rc.readlines():

			if len(line.split('=')) < 1:
				continue

			k,v = line.strip().split('=')
#			print k, v

			if k == 'MainToolbar':
				self.viewtoolbar1.set_active(int(v))

#			elif k == 'ConnectBar':
#				self.viewconnectbar1.set_active(int(v))

			elif k == 'CommandBar':
				self.viewcommandbar1.set_active(int(v))

			elif k == 'FoldersBar':

				v = int(v)

				if   v == 0:
					self.tbhidden1.set_active(True)
				elif v == 1:
					self.tbhorizontal1.set_active(True)
				elif v == 2:
					self.tbvertical1.set_active(True)

			elif k == 'ShowHidden':
				self.showhidden1.set_active(int(v))

	def save_preferences(self):

		try:
			rc = open(self.foffrc, "w")
		except:
			self.printm("Cannot write to config file.\n", "gtk-dialog-error")

			return

		prefs = {}

		prefs['MainToolbar'] = int(self.viewtoolbar1.get_active())
		prefs['ConnectBar'] = int(self.viewconnectbar1.get_active())
		prefs['CommandBar'] = int(self.viewcommandbar1.get_active())
		prefs['ShowHidden'] = int(self.showhidden1.get_active())

		if self.tbhidden1.get_active():
			prefs['FoldersBar'] = 0

		elif self.tbhorizontal1.get_active():
			prefs['FoldersBar'] = 1

		elif self.tbvertical1.get_active():
			prefs['FoldersBar'] = 2

		for k in prefs:

			rc.write(k + '=' + str(prefs[k]) + '\n')

		rc.close()

	def read_servers_config(self):

		config = []
		config = os.listdir(self.rcdir)

		self.cbeServer.get_model().clear()

		for filename in config:

			if not filename.endswith('.foff'):

				continue

			filename = filename.split('.foff')[0]
			self.cbeServer.append_text(filename)


	def load_server_config(self, widget):

		rcfile = self.cbeServer.get_active_text()
		rcfile = os.path.join(self.rcdir, rcfile + '.foff')

		if not os.path.exists(rcfile):

			return


		try:
			config = open(rcfile, 'r')

		except IOError:

			self.printm('Cannot open config file: ' + rcfile  + '\n', "gtk-dialog-error")

			return


		for line in config.readlines():

			if len(line.split('=')) < 1:
				continue

			k,v = line.strip().split('=')

			if   k == 'address':
				self.cbeServer.child.set_text(v)

			elif k == 'portnum':
				self.entPort.set_text(v)

			elif k == 'usrname':
				self.entUser.set_text(v)

			elif k == 'usrpass':

				try:
					des = pyDes.des("FOFFCRYP", pyDes.CBC, "\0\0\0\0\0\0\0\0")
					v = des.decrypt(v, '\0')
					v = v.decode('rot_13')

				except ValueError:

					self.printm("DES Crypt error. Password will not be loaded.\n", "gtk-dialog-error")

					v = ''

				self.entPass.set_text(v)
		
			elif k == 'account':

				self.account = v

			elif k == 'remotdr':

				self.conncwd = v

			elif k == 'localdr':

				self.fcLocalDir.set_filename(str(v))

		config.close()

	# save site info =======================================================
	def on_save_site(self, widget):

		svDlg = saveDlg("/usr/share/foff/foff.glade", "saveDlg")
		svDlg.saveDlg.hide()

		svDlg.entBookmark.set_text(self.cbeServer.child.get_text())
		response = svDlg.saveDlg.run()

		if response == gtk.RESPONSE_CANCEL:

			return

		fofffile = os.path.join(self.rcdir, svDlg.get_info())

		if not fofffile.endswith('.foff'):
			fofffile += '.foff'


		if os.path.exists(fofffile):

			msg = gtk.MessageDialog(None,gtk.DIALOG_MODAL,gtk.MESSAGE_QUESTION,gtk.BUTTONS_YES_NO)
			msg.set_icon_name("gtk-dialog-question")
			msg.set_title('Overwrite File')
			msg.set_markup("Do you want to overwrite the saved site '" + svDlg.get_info() + "'?")

			response = msg.run()
			msg.destroy()

			if response == gtk.RESPONSE_NO:
				return


		encpass = self.entPass.get_text()
		encpass = encpass.encode('rot_13')

		try:
			k = pyDes.des("FOFFCRYP", pyDes.CBC, "\0\0\0\0\0\0\0\0")
			encpass = k.encrypt(encpass, '\0')

		except ValueError:

			self.printm("DES Crypt error. Password will not be saved.\n", "gtk-dialog-error")
			encpass = ''

		bookmark = open(fofffile, "w")
		bookmark.write('address=' + self.cbeServer.child.get_text() + '\n')
		bookmark.write('portnum=' + self.entPort.get_text() + '\n')
		bookmark.write('usrname=' + self.entUser.get_text() + '\n')
		bookmark.write('usrpass=' + encpass + '\n')
		bookmark.write('account=' + '' + '\n')
		bookmark.write('localdr=' + str(self.fcLocalDir.get_filename()) + '\n')
		bookmark.write('remotdr=' + str(self.cbRemoteDir.get_active_text()) + '\n')
		bookmark.close()

		self.printm("Bookmark file '" + svDlg.get_info() + "' saved\n")
		self.read_servers_config()


	# local file folder refresh ============================================
	def on_local_refresh(self, widget):

		self.load_local_dir(self.fcLocalDir.get_filename())

	# open local files =====================================================
	def open_local(self):

		sel = self.tvLocalFiles.get_selection()
		count = sel.count_selected_rows()

		if count < 1:
			return

		elif count > 1:
			msg = gtk.MessageDialog(None,gtk.DIALOG_MODAL,gtk.MESSAGE_WARNING,gtk.BUTTONS_OK)
			msg.set_icon_name("gtk-dialog-warning")
			msg.set_title('Open Multiple Files')
			msg.set_markup('Cannot open multiple files at once.')

			response = msg.run()
			msg.destroy()
			return

		model, pathlist = sel.get_selected_rows()
		iter = model.get_iter(pathlist[0])

#		for path in pathlist:
#			trr = gtk.TreeRowReference(model, path)
#			iter = model.get_iter(path)

		match_song = re.compile(r".*\.(aac|ac3|mp3|ogg|wma)$", re.IGNORECASE)
		match_pics = re.compile(r".*\.(png|tiff|tif|jpg|jpeg|xpm|ico|bmp|gif|tga|pcx)$", re.IGNORECASE)
		match_blob = re.compile(r".*\.(avi|mpg|mpeg|mp3|ogg|mov|wma|wmv|zip|bin|iso|gz|bz2|z|tar|rar|psd|wav|aiff|exe|obj|class)$", re.IGNORECASE)

		if model.get_value(iter,0) == 'gtk-directory':

			dirch = model.get_value(iter, 1)
			self.load_local_dir(dirch)

			self.fcLocalDir.set_filename(os.getcwd())

		elif match_song.match(model.get_value(iter, 1)):

			if player.SOUND_PLAYER == 1:

				self.notebook.set_current_page(3)
				self.sWnd.enqueue(os.path.join(os.getcwd(),model.get_value(iter, 1)))

		elif model.get_value(iter, 1).endswith('.html') or model.get_value(iter, 1).endswith('.htm'):

			webbrowser.open_new(model.get_value(iter, 1))

		elif match_pics.match(model.get_value(iter, 1)):

			imgWnd = picWnd("/usr/share/foff/foff.glade", "picWnd", model.get_value(iter, 1))

		elif match_blob.match(model.get_value(iter, 1)):

			pass
		else:
			txtWnd = textWnd("/usr/share/foff/foff.glade", "textWnd", model.get_value(iter, 1))

	def on_local_open(self, widget):

		self.open_local()

	def on_localfile_activated(self, treeview, path, viewcol):

		self.open_local()


	# make local directory =================================================
	def on_local_mkdir(self, widget):

		mdDlg = mkdirDlg("/usr/share/foff/foff.glade", "mkdirDlg")
		mdDlg.mkdirDlg.set_title("Create Local Directory")

		response = mdDlg.mkdirDlg.run()

		if response == gtk.RESPONSE_CANCEL:

			return


		os.mkdir(mdDlg.get_info())
		self.load_local_dir(self.fcLocalDir.get_filename())

		self.printm('LOCAL: Created directory \'' + mdDlg.get_info() + '\'\n', "gtk-home")

	# rename local file ====================================================
	def on_local_rename(self, widget):

		sel = self.tvLocalFiles.get_selection()
		count = sel.count_selected_rows()

		if count < 1:
			return

		elif count > 1:
			msg = gtk.MessageDialog(None,gtk.DIALOG_MODAL,gtk.MESSAGE_WARNING,gtk.BUTTONS_OK)
			msg.set_icon_name("gtk-dialog-warning")
			msg.set_title('Rename Multiple Files')
			msg.set_markup('Cannot rename multiple files at once.')

			response = msg.run()
			msg.destroy()
			return

		model, pathlist = sel.get_selected_rows()
		iter = model.get_iter(pathlist[0])
		srcfile = model.get_value(iter, 1)

		rnDlg = renameDlg("/usr/share/foff/foff.glade", "renameDlg")
		rnDlg.renameDlg.set_title("Rename Local File")

		rnDlg.entRename.set_text(srcfile)
		response = rnDlg.renameDlg.run()

		if response == gtk.RESPONSE_CANCEL:

			return

		os.rename(srcfile, rnDlg.get_info())
		self.load_local_dir(self.fcLocalDir.get_filename())

		self.printm('LOCAL: Renamed \'' + srcfile + '\' to \'' + rnDlg.get_info() + '\'\n', "gtk-home")

	# delete local file ====================================================
	def on_local_delete(self, widget):

		sel = self.tvLocalFiles.get_selection()
		count = sel.count_selected_rows()

		if count < 1:
			return

		if count > 1:
			mstr = '<b>Delete local files</b>'
			mstr += '\nAre you sure you want to delete multiple files?'

			msg = gtk.MessageDialog(None,gtk.DIALOG_MODAL,gtk.MESSAGE_QUESTION,gtk.BUTTONS_YES_NO)
			msg.set_icon_name("gtk-dialog-question")
			msg.set_title('Delete Local Files')
			msg.set_markup(mstr)

			response = msg.run()
			msg.destroy()

			if response == gtk.RESPONSE_NO:
				return

		model, pathlist = sel.get_selected_rows()

# TODO: directory not empty message

		for path in pathlist:

			iter = model.get_iter(path)

			if count == 1:
				mstr = '<b>Delete local file</b>'
				mstr += '\nAre you sure you want to delete \'' + model.get_value(iter, 1) + '\'?'

				msg = gtk.MessageDialog(None,gtk.DIALOG_MODAL,gtk.MESSAGE_QUESTION,gtk.BUTTONS_YES_NO)
				msg.set_icon_name("gtk-dialog-question")
				msg.set_title('Delete Local File')
				msg.set_markup(mstr)

				response = msg.run()
				msg.destroy()

				if response == gtk.RESPONSE_NO:
					return

			if model.get_value(iter,0) == 'gtk-directory':

				mstr = '<b>Delete directory recursively</b>'
				mstr += '\nAre you sure you want to delete \'' + model.get_value(iter, 1) + '\' and all of its files and subfolders?'

				msg = gtk.MessageDialog(None,gtk.DIALOG_MODAL,gtk.MESSAGE_QUESTION,gtk.BUTTONS_YES_NO)
				msg.set_icon_name("gtk-dialog-question")
				msg.set_title('Delete Local Directory')
				msg.set_markup(mstr)

				response = msg.run()
				msg.destroy()

				if response == gtk.RESPONSE_NO:
					continue

				# walk directory branch and leafs
				for root, dirs, files in os.walk(model.get_value(iter, 1), topdown=False):

					for name in files:
						os.remove(os.path.join(root, name))
					for name in dirs:
						os.rmdir(os.path.join(root, name))

				os.rmdir(model.get_value(iter, 1))
			else:
				os.remove(model.get_value(iter, 1))

			self.printm('LOCAL: Deleted \'' + model.get_value(iter, 1) + '\'\n', "gtk-home")

		self.load_local_dir(self.fcLocalDir.get_filename())

	# local directory changing =============================================
	def on_localfolder_change(self, widget):

		self.load_local_dir(self.fcLocalDir.get_filename())


	def load_local_dir(self, pathname='.'):

		if pathname == '.':
			pathname = self.fcLocalDir.get_filename()

		try:
			os.chdir(pathname)

			dirlist = os.listdir(".")
			dirlist.sort()

			self.local_model.clear()
			dirlist.insert(0,"..")

		except:
			return

		for diritem in dirlist:

			file_stat = os.stat(diritem)

			mode = file_stat.st_mode
			size = file_stat.st_size
			mtime = file_stat.st_mtime

			if self.showhidden == 0:
				if diritem[0] == '.' and diritem != '..':
					continue

			if stat.S_ISDIR(mode):

				iter = self.local_model.append()
				self.local_model.set(iter,0,"gtk-directory")
				self.local_model.set(iter,1,diritem)
				self.local_model.set(iter,2,str(size))
				self.local_model.set(iter,3,str( datetime.datetime.fromtimestamp(mtime) ))


		for diritem in dirlist:

			file_stat = os.stat(diritem)

			mode = file_stat.st_mode
			size = file_stat.st_size
			mtime = file_stat.st_mtime

			if self.showhidden == 0:
				if diritem[0] == '.':
					continue

			if stat.S_ISREG(mode):

				iter = self.local_model.append()
				self.local_model.set(iter,0,"gtk-file")
				self.local_model.set(iter,1,diritem)
				self.local_model.set(iter,2,str(size))
				self.local_model.set(iter,3,str( datetime.datetime.fromtimestamp(mtime) ))


		self.tvLocalFiles.columns_autosize()

	# enter commands =======================================================
	def command_enter(self, widget, event, data=None):

		if 'Return' == gtk.gdk.keyval_name(event.keyval):
			self.on_enter_command(self.btnEntCommand)

	def on_enter_command(self, widget):

		if self.cbCommType.get_active() == 0:

			oscommand = self.cbeCommand.child.get_text().strip()

			if oscommand == '':
				return

			if oscommand == 'clear':

				self.textbuff.set_text('')
				self.cbeCommand.child.set_text('')
				return

			self.printm('LOCAL: Running command \'' + oscommand + '\'...\n', "gtk-execute")

			# change directory in gui
			words = oscommand.split()
			if words[0] == 'cd':

				self.load_local_dir(words[1])
				self.fcLocalDir.set_filename(os.getcwd())
			else:
				pulse = Pulse(self.progressbar)
				pulse.start()

				comm = Command(self.txvMessages, oscommand, pulse, self.load_local_dir)
				comm.start()

				self.notebook.set_current_page(0)

			self.cbeCommand.child.set_text('')
			self.cbeCommand.append_text(oscommand)

			return


		elif self.ftp != None:

			ftpcommand = self.cbeCommand.child.get_text().strip()

			if ftpcommand == '':
				return

			elif ftpcommand == 'clear':

				self.textbuff.set_text('')
				self.cbeCommand.child.set_text('')
				return

			self.printm('REMOTE: Running command \'' + ftpcommand + '\'...\n', "gtk-execute")

			if ftpcommand == "pwd" or ftpcommand == "PWD":

				self.printm(self.ftp.pwd() + "\n", "gtk-network")

			elif ftpcommand.startswith("list") or ftpcommand.startswith("LIST"):

				list = []
				list = ftpcommand.split(' ')

				if len(list) < 2:
					result = self.ftp.retrlines('LIST', self.cb_list)
				else:
					result = self.ftp.retrlines('LIST ' + list[1], self.cb_list)

			elif ftpcommand.startswith("cwd") or ftpcommand.startswith("CWD"):

				list = []
				list = ftpcommand.split(' ')

				if len(list) >= 2:

					self.cbRemoteDir.insert_text(0,list[1])
					self.cbRemoteDir.set_active(0)

			elif ftpcommand.startswith("mkd") or ftpcommand.startswith("MKD"):

				list = []
				list = ftpcommand.split(' ')

				if len(list) < 2:
					return

				self.ftp.mkd(list[1])
				self.printm('REMOTE: Created directory \'' + list[1] + '\'\n', "gtk-network")
				self.load_remote_dir()

			elif ftpcommand.startswith("dele") or ftpcommand.startswith("DELE"):

				list = []
				list = ftpcommand.split(' ')

				if len(list) < 2:
					return

				try:
					self.ftp.delete(list[1])
					self.printm('REMOTE: Deleted \'' + list[1] + '\'\n', "gtk-network")
					self.load_remote_dir()
				except:
					self.printm('REMOTE: Cannot delete \'' + list[1] + '\'\n', "gtk-dialog-error")

			elif ftpcommand.startswith("stor") or ftpcommand.startswith("STOR"):

				list = []
				list = ftpcommand.split(' ')

				if len(list) < 2:
					return

				for item in list:

					if item == "stor" or item == "STOR":
						continue

					if not os.path.exists(item):
						return

					file_stat = os.stat(item)
					lsize = str(file_stat.st_size) + ' bytes'

					self.notebook.set_current_page(2)

					uiter = self.ul_model.append()
					self.ul_model.set(uiter,0,"gtk-file")
					self.ul_model.set(uiter,1,item)
					self.ul_model.set(uiter,2,lsize)

				pulse = Pulse(self.progressbar)
				pulse.start()

				thr = Upload(self.ftp, self.ul_model, pulse, self.load_remote_dir)
				thr.start()

			elif ftpcommand.startswith("retr") or ftpcommand.startswith("RETR"):

				list = []
				list = ftpcommand.split(' ')

				if len(list) < 2:
					return

				for item in list:

					if item == "retr" or item == "RETR":
						continue

					rsize = str(self.ftp.size(item))

					diter = self.dl_model.append()
					self.dl_model.set(diter,0,"gtk-file")
					self.dl_model.set(diter,1,item)
					self.dl_model.set(diter,2,rsize)

				self.notebook.set_current_page(1)
				thr = Download(self.ftp, self.dl_model, self.load_local_dir)
				thr.start()

			else:
				# TODO: FIXME
				self.printm(self.ftp.sendcmd("\""+ftpcommand+"\""), "gtk-network")

			self.cbeCommand.child.set_text('')
			self.cbeCommand.append_text(ftpcommand)

	# create/verify md5 checksums ==========================================
	def on_create_checksum(self, widget):

		sel = self.tvLocalFiles.get_selection()
		count = sel.count_selected_rows()

		if count == 0:
			return

		model, pathlist = sel.get_selected_rows()

		for path in pathlist:

			iter = model.get_iter(path)
			filename = model.get_value(iter, 1)

			if model.get_value(iter, 0) == 'gtk-directory':

				pass

			pulse = Pulse(self.progressbar)
			pulse.start()

			md5c = CreateMD5(filename, pulse, self.load_local_dir)
			md5c.start()

		self.load_local_dir(self.fcLocalDir.get_filename())

	def on_verify_checksum(self, widget):

		sel = self.tvLocalFiles.get_selection()
		count = sel.count_selected_rows()

		if count == 0:
			return

		model, pathlist = sel.get_selected_rows()

		for path in pathlist:

			iter = model.get_iter(path)
			filename = model.get_value(iter, 1)

			if not filename.endswith('.md5'):

				if os.path.exists(filename + ".md5"):

					filename += ".md5"
				else:

					mess = "<b>No Checksum File</b>\n"
					mess += "There is no checksum file for '" + filename + "'\n"

					msg = gtk.MessageDialog(None,gtk.DIALOG_MODAL,gtk.MESSAGE_WARNING,gtk.BUTTONS_OK)
					msg.set_icon_name("gtk-dialog-warning")
					msg.set_title('Verify Checksum')
					msg.set_markup(mess)

					response = msg.run()
					msg.destroy()

					continue

			if model.get_value(iter, 0) == 'gtk-directory':

				continue

			datafilename = filename.split('.md5')[0]

			if not os.path.exists(datafilename):

				mess = "<b>File Not Found</b>\n"
				mess += "The file does not exist: '" + datafilename + "'\n"

				msg = gtk.MessageDialog(None,gtk.DIALOG_MODAL,gtk.MESSAGE_ERROR,gtk.BUTTONS_OK)
				msg.set_icon_name("gtk-dialog-error")
				msg.set_title('Verify Checksum')
				msg.set_markup(mess)

				response = msg.run()
				msg.destroy()

				continue

			file_stat = os.stat(datafilename)
			file_size = file_stat.st_size

			hashfile = open(filename, "r")
			filehash = hashfile.readline().split(' ')[0]
			hashfile.close()

			check = open(datafilename,"rb")


			i = 0
			m = md5.new()

			if file_size / 100000000 > 0:

				chunk_size = int(file_size * 0.0003)

			elif file_size / 1000000 > 0:

				chunk_size = int(file_size * 0.05)

			else:
				chunk_size = int(file_size * 0.10)

#			print "file size: " + str(file_size) + "\n"
#			print "chunk size: " + str(chunk_size) + "\n"

			while True:
				chunk = check.read(chunk_size)
				if not chunk:
					break

				i += 1

				if file_size / 100000000 > 0:
					if i % 10 == 0:
						self.progressbar.pulse()
						gtk.main_iteration(False)
				else:
					self.progressbar.pulse()
					gtk.main_iteration(False)

				m.update(chunk)

			check.close()
			conthash = m.hexdigest()
			self.progressbar.set_fraction(0.0)


			if conthash == filehash:

				mess = "'" + datafilename + "'\n\n"
				mess += '<span foreground="#00bb00" weight="bold">Checksum Verified</span>\n'
				mess += "Contents Hash: " + conthash + "\n"
				mess += "MD5 File Hash: " + filehash

				msg = gtk.MessageDialog(None,gtk.DIALOG_MODAL,gtk.MESSAGE_INFO,gtk.BUTTONS_OK)
				msg.set_icon_name("gtk-dialog-info")
				msg.set_title('Verify Checksum')
				msg.set_markup(mess)

				response = msg.run()
				msg.destroy()

			else:
				mess = "'" + datafilename + "'\n\n"
				mess += '<span foreground="#dd0000" weight="bold">Checksum Failed</span>\n'
				mess += "Contents Hash: " + conthash + "\n"
				mess += "MD5 File Hash: " + filehash

				msg = gtk.MessageDialog(None,gtk.DIALOG_MODAL,gtk.MESSAGE_WARNING,gtk.BUTTONS_OK)
				msg.set_icon_name("gtk-dialog-warning")
				msg.set_title('Verify Checksum')
				msg.set_markup(mess)

				response = msg.run()
				msg.destroy()

	# gzip/gunzip compression ==============================================
	def on_compress(self, widget):

		sel = self.tvLocalFiles.get_selection()
		count = sel.count_selected_rows()

		if count == 0:
			return

		model, pathlist = sel.get_selected_rows()

		for path in pathlist:

			iter = model.get_iter(path)
			filename = model.get_value(iter, 1)

			if model.get_value(iter, 0) == 'gtk-directory':

# TODO: ask to tar dirs and multiple files first

				msg = gtk.MessageDialog(None,gtk.DIALOG_MODAL,gtk.MESSAGE_WARNING,gtk.BUTTONS_OK)
				msg.set_icon_name("gtk-dialog-warning")
				msg.set_title('Compress File')
				msg.set_markup('Cannot gzip a directory. You must tar it first.')

				response = msg.run()
				msg.destroy()
				return

			pulse = Pulse(self.progressbar)
			pulse.start()

			compress = Compress(filename, pulse, self.load_local_dir)
			compress.start()

	def on_decompress(self, widget):

		sel = self.tvLocalFiles.get_selection()
		count = sel.count_selected_rows()

		if count == 0:
			return

		model, pathlist = sel.get_selected_rows()

		for path in pathlist:

			iter = model.get_iter(path)
			filename = model.get_value(iter, 1)

			if filename.endswith('.gz'):
				pass

			elif filename.endswith('.bz2'):
				pass

			elif filename.endswith('.zip'):
				pass

			elif filename.endswith('.tar'):
				pass

			else:
				continue


			pulse = Pulse(self.progressbar)
			pulse.start()

			decompress = Decompress(filename, pulse, self.load_local_dir, self.txvMessages)
			decompress.start()

	# connect to FTP server ================================================
	def connect_enter(self, widget, event, data=None):

		if 'Return' == gtk.gdk.keyval_name(event.keyval):
			self.btnConnect.set_active(True)

	def connect_toggled(self, widget):

		if widget == self.tbConnect:

			if self.tbConnect.get_active():

				self.tbConnect.set_stock_id("gtk-disconnect")
				self.btnConnect.set_active(True)
			else:
				self.tbConnect.set_stock_id("gtk-connect")
				self.btnConnect.set_active(False)

		elif widget == self.btnConnect:

			if self.btnConnect.get_active():

				if self.ftp == None:
					self.on_connect(self.btnConnect)

				img = gtk.Image()
				img.set_from_stock("gtk-disconnect",gtk.IMAGE_STOCK)
				self.btnConnect.set_image(img)

				self.tbConnect.set_active(True)
			else:
				self.on_disconnect(self.btnConnect)

				img = gtk.Image()
				img.set_from_stock("gtk-connect",gtk.IMAGE_STOCK)
				self.btnConnect.set_image(img)

				self.tbConnect.set_active(False)

	def on_connect(self, widget):

		if self.ftp != None:

			self.printm('You are still connected. Please disconnect first.\n', "gtk-dialog-error")

			return

		self.printm('Connecting to site ' + self.cbeServer.child.get_text() + '\n', "gtk-network")

		try:
			self.ftp = ftplib.FTP()
			self.ftp.connect(self.cbeServer.child.get_text(), self.entPort.get_text())
			self.ftp.login(self.entUser.get_text(), self.entPass.get_text(), self.account)

			self.printm(self.ftp.getwelcome() + '\n')
			self.notebook.set_current_page(0)

			if self.conncwd != '':

				self.ftp.cwd(self.conncwd)

			self.viewconnectbar1.set_active(False)

			# enable remote functions when connected
			self.toolbar3.set_sensitive(True)
			self.toolbar3v.set_sensitive(True)
			self.remote1.set_sensitive(True)
			self.btnConnect.set_active(True)

		except:

			# TODO: print error to messages
			self.printm('Could not connect to the server.\n', "gtk-dialog-error")

			del self.ftp
			self.ftp = None

#			self.btnConnect.set_active(False)

			return

		self.cbRemoteDir.get_model().clear()
		self.cbRemoteDir.append_text(self.ftp.pwd())
		self.cbRemoteDir.append_text("Other...")
		self.cbRemoteDir.set_active(0)


	# disconnect current connection ========================================
	def on_disconnect(self, widget):

		self.viewconnectbar1.set_active(True)

		if self.ftp != None:

			self.ftp.close()
			del self.ftp
			self.ftp = None

			# disable remote functions when not connected
			self.toolbar3.set_sensitive(False)
			self.toolbar3v.set_sensitive(False)
			self.remote1.set_sensitive(False)

			self.printm('Disconnected\n', "gtk-network")
			self.btnConnect.set_active(False)


	def cb_list(self, line):

		self.printm(line + '\n', "gtk-file")

	def cb_list_dirs(self, line):

		words = line.split()
		diritem = words[-1]

#		if diritem in ('.','..'):
#			continue

		if words[0][0] == 'd' or words[0][0] == 'l':

			size = words[4]
			mtime = words[5] + ' ' + words[6] + ' ' + words[7]

			iter = self.remote_model.append()
			self.remote_model.set(iter,0,"gtk-directory")
			self.remote_model.set(iter,1,diritem)
			self.remote_model.set(iter,2,str(size))
			self.remote_model.set(iter,3,str(mtime))

	def cb_list_files(self, line):

		words = line.split()
		diritem = words[-1]

		if words[0][0] != 'd' and words[0][0] != 'l':

			size = words[4]
			mtime = words[5] + ' ' + words[6] + ' ' + words[7]

			iter = self.remote_model.append()
			self.remote_model.set(iter,0,"gtk-file")
			self.remote_model.set(iter,1,diritem)
			self.remote_model.set(iter,2,str(size))
			self.remote_model.set(iter,3,str(mtime))


	# load remote dir
	def load_remote_dir(self):

		"""
		try:
			self.nlist = self.ftp.nlst()
			self.nlist.sort()
			self.nlist.insert(0,"..")

		except:
			return
		"""

		self.printm('REMOTE: LIST\n', "gtk-directory")

		self.remote_model.clear()

		iter = self.remote_model.append()
		self.remote_model.set(iter,0,"gtk-directory")
		self.remote_model.set(iter,1,'..')
		self.remote_model.set(iter,2,str(0))
		self.remote_model.set(iter,3,str(datetime.datetime.fromtimestamp(0)))

		result = self.ftp.retrlines('LIST', self.cb_list_dirs)
		result = self.ftp.retrlines('LIST', self.cb_list_files)


		self.tvRemoteFiles.columns_autosize()

		"""
		for diritem in self.nlist:

			isdir = 0


###

			try:
				size = self.ftp.size(diritem)
				mtime = self.ftp.sendcmd("MDTM " + diritem)

			except ftplib.error_perm:

				size = 0
				isdir = 1
				mtime = 0

###

			size = 0
			isdir = 1
			mtime = 0

#			if isdir == 1:

			iter = self.remote_model.append()
			self.remote_model.set(iter,0,"gtk-directory")
			self.remote_model.set(iter,1,diritem)
			self.remote_model.set(iter,2,str(size))
			self.remote_model.set(iter,3,str(mtime))


		for diritem in self.nlist:

			isdir = 0

			try:
				size = self.ftp.size(diritem)
				mtime = self.ftp.sendcmd("MDTM " + diritem)

			except ftplib.error_perm:

				size = 0
				isdir = 1
				mtime = 0

			if isdir == 0:

				iter = self.remote_model.append()
				self.remote_model.set(iter,1,diritem)
				self.remote_model.set(iter,2,str(size))
				self.remote_model.set(iter,3,str(mtime))
		"""

	# open local files =====================================================
	def open_remote(self):

		sel = self.tvRemoteFiles.get_selection()

		count = sel.count_selected_rows()

		if count < 1:
			return

		elif count > 1:
			msg = gtk.MessageDialog(None,gtk.DIALOG_MODAL,gtk.MESSAGE_WARNING,gtk.BUTTONS_OK)
			msg.set_icon_name("gtk-dialog-warning")
			msg.set_title('Open Multiple Files')
			msg.set_markup('Cannot open multiple files at once.')

			response = msg.run()
			msg.destroy()
			return

		model, pathlist = sel.get_selected_rows()
		iter = model.get_iter(pathlist[0])

		if model.get_value(iter,0) == 'gtk-directory':

			dirch = model.get_value(iter, 1)
			self.ftp.cwd(dirch)
			self.cbRemoteDir.prepend_text(self.ftp.pwd())
			self.cbRemoteDir.set_active(0)

#			self.fcLocalDir.set_filename(os.getcwd())

		else:
			self.on_remote_get(self.toolbutton15)


	def on_remote_open(self, widget):

# TODO: FIXME: downloads in thread and opens incomplete file while downloading
# pass open func
		self.open_remote()

		sel = self.tvRemoteFiles.get_selection()
		count = sel.count_selected_rows()

		if count != 1:
			return

		model, pathlist = sel.get_selected_rows()
		iter = model.get_iter(pathlist[0])

		match_pics = re.compile(r".*\.(png|tiff|tif|jpg|jpeg|xpm|ico|bmp|gif|tga|pcx)$", re.IGNORECASE)
		match_blob = re.compile(r".*\.(avi|mpg|mpeg|mp3|ogg|mov|wma|wmv|zip|bin|iso|gz|bz2|z|tar|rar|psd|wav|aiff|exe|obj|class)$", re.IGNORECASE)

		if match_pics.match(model.get_value(iter, 1)):

			imgWnd = picWnd("/usr/share/foff/foff.glade", "picWnd", model.get_value(iter, 1))

		elif match_blob.match(model.get_value(iter, 1)):

			pass
		else:
			txtWnd = textWnd("/usr/share/foff/foff.glade", "textWnd", model.get_value(iter, 1))


	def on_remotefile_activated(self, treeview, path, viewcol):

		self.open_remote()


	# handle downloading ===================================================
	def walk_remote(self, dir):

# TODO:

# split and rejoin paths in Download class
# check if file is in a directory and create
# local directories as needed

# create new ftp object while downloading
# to allow browsing of folders


#		print 'cwd:', self.ftp.pwd()
#		print 'list', dir

		list = []
		self.ftp.retrlines('LIST ' + dir, list.append)

		for line in list:

			words = line.split()

			if words[0][0] == 'd' or words[0][0] == 'l':

				dir = dir + '/' + words[-1]
				self.walk_remote(dir)

				dir = os.path.split(dir)[0]
			else:
				self.printm(dir + '/' + words[-1] + '\n', "gtk-file")

				iter = self.dl_model.append()
				self.dl_model.set(iter,0,"gtk-file")
				self.dl_model.set(iter,1,dir + '/' + words[-1])
				self.dl_model.set(iter,2,str(words[4]))

		dir = os.path.split(dir)[0]


	def on_remote_get(self, widget):

		sel = self.tvRemoteFiles.get_selection()
		count = sel.count_selected_rows()

		if count < 1:
			return

		if self.dl_model.get_iter_first() == None:

			start_queue = True
		else:
			start_queue = False

		model, pathlist = sel.get_selected_rows()

		for path in pathlist:

			iter = model.get_iter(path)
			dlfile = model.get_value(iter, 1)


			if os.path.exists(dlfile):

				rsize = str(model.get_value(iter, 2)) + ' bytes'
				rmtime = 'Modified on ' + str(model.get_value(iter, 3))


				file_stat = os.stat(dlfile)
				lsize = str(file_stat.st_size) + ' bytes'
				lmtime = 'Modified on ' + str(datetime.datetime.fromtimestamp(file_stat.st_mtime))

				mstr = '<b>Overwrite file?</b>\n'
				mstr += '\nReplace local file \'' + dlfile + '\'\n'
				mstr += lmtime + '\n' + lsize
				mstr += '\n\nWith remote file \'' + dlfile + '\'\n'
				mstr += rmtime + '\n' + rsize

				msg = gtk.MessageDialog(None,gtk.DIALOG_MODAL,gtk.MESSAGE_QUESTION,gtk.BUTTONS_YES_NO)
				msg.set_icon_name("gtk-dialog-question")
				msg.set_title('Overwrite File')
				msg.set_markup(mstr)

				response = msg.run()
				msg.destroy()

				if response == gtk.RESPONSE_NO:
					continue


			if model.get_value(iter, 0) == 'gtk-directory':

				self.walk_remote(dlfile)
#				start_queue = False
			else:
				diter = self.dl_model.append()
				self.dl_model.set(diter,0,model.get_value(iter, 0))
				self.dl_model.set(diter,1,model.get_value(iter, 1))
				self.dl_model.set(diter,2,model.get_value(iter, 2))

		self.notebook.set_current_page(1)

		if start_queue:

			thr = Download(self.ftp, self.dl_model, self.load_local_dir)
			thr.start()


	def on_remote_cwd(self, widget):

		self.cbRemoteDir.popdown()
		if self.cbRemoteDir.get_active_text() == "Other...":

			cDlg = cwdDlg("/usr/share/foff/foff.glade", "cwdDlg")

			response = cDlg.cwdDlg.run()

			if response == gtk.RESPONSE_CANCEL:

				self.cbRemoteDir.set_active(0)
				return

			self.cbRemoteDir.prepend_text(cDlg.get_info())
			self.cbRemoteDir.set_active(0)

			return

		self.ftp.cwd(self.cbRemoteDir.get_active_text())
		self.load_remote_dir()

	# make remote directory ================================================
	def on_remote_mkdir(self, widget):

		mdDlg = mkdirDlg("/usr/share/foff/foff.glade", "mkdirDlg")
		mdDlg.mkdirDlg.set_title("Create Remote Directory")

		response = mdDlg.mkdirDlg.run()

		if response == gtk.RESPONSE_CANCEL:

			return

		self.ftp.mkd(mdDlg.get_info())
		self.printm('REMOTE: Created directory \'' + mdDlg.get_info() + '\'\n', "gtk-network")
		self.load_remote_dir()

	# rename remote file ===================================================
	def on_remote_rename(self, widget):

		sel = self.tvRemoteFiles.get_selection()
		count = sel.count_selected_rows()

		if count < 1:
			return

		elif count > 1:
			msg = gtk.MessageDialog(None,gtk.DIALOG_MODAL,gtk.MESSAGE_WARNING,gtk.BUTTONS_OK)
			msg.set_icon_name("gtk-dialog-warning")
			msg.set_title('Rename Multiple Files')
			msg.set_markup('Cannot rename multiple files at once.')

			response = msg.run()
			msg.destroy()
			return

		model, pathlist = sel.get_selected_rows()
		iter = model.get_iter(pathlist[0])
		srcfile = model.get_value(iter, 1)

		rnDlg = renameDlg("/usr/share/foff/foff.glade", "renameDlg")
		rnDlg.renameDlg.set_title("Rename Remote File")

		rnDlg.entRename.set_text(srcfile)
		response = rnDlg.renameDlg.run()

		if response == gtk.RESPONSE_CANCEL:

			return

		self.ftp.rename(srcfile, rnDlg.get_info())
		self.printm('REMOTE: Renamed \'' + srcfile + '\' to \'' + rnDlg.get_info() + '\'\n', "gtk-network")
		self.load_remote_dir()


	# delete remote file ===================================================
	def on_remote_delete(self, widget):

# TODO: dir not empty error_perm 550

		sel = self.tvRemoteFiles.get_selection()
		count = sel.count_selected_rows()

		if count < 1:
			return

		if count > 1:
			mstr = '<b>Delete remote files</b>'
			mstr += '\nAre you sure you want to delete multiple files?'

			msg = gtk.MessageDialog(None,gtk.DIALOG_MODAL,gtk.MESSAGE_QUESTION,gtk.BUTTONS_YES_NO)
			msg.set_icon_name("gtk-dialog-question")
			msg.set_title('Delete Remote Files')
			msg.set_markup(mstr)

			response = msg.run()
			msg.destroy()

			if response == gtk.RESPONSE_NO:
				return

		model, pathlist = sel.get_selected_rows()

# TODO: directory not empty message

		for path in pathlist:

#			gtk.TreeRowReference(model,path).get_path()
			iter = model.get_iter(path)

			if count == 1:
				mstr = '<b>Delete remote file</b>'
				mstr += '\nAre you sure you want to delete \'' + model.get_value(iter, 1) + '\'?'

				msg = gtk.MessageDialog(None,gtk.DIALOG_MODAL,gtk.MESSAGE_QUESTION,gtk.BUTTONS_YES_NO)
				msg.set_icon_name("gtk-dialog-question")
				msg.set_title('Delete Remote File')
				msg.set_markup(mstr)

				response = msg.run()
				msg.destroy()

				if response == gtk.RESPONSE_NO:
					return

			if model.get_value(iter,0) == 'gtk-directory':

				self.ftp.rmd(model.get_value(iter, 1))

			else:
				self.ftp.delete(model.get_value(iter, 1))

		self.printm('REMOTE: Deleted \'' + model.get_value(iter, 1) + '\'\n', "gtk-network")
		self.load_remote_dir()

	# refresh remote dir ===================================================
	def on_remote_refresh(self, wdiget):

		self.load_remote_dir()

	# handle uploading =====================================================
	def check_upload_overwrite(self, model, path, iter, overwrite):

		if model.get_value(iter, 1) == overwrite[0]:

			overwrite[1] = True
			overwrite.append(model.get_value(iter, 2))
			overwrite.append(model.get_value(iter, 3))
			return True

	def on_local_store(self, widget):

		sel = self.tvLocalFiles.get_selection()
		count = sel.count_selected_rows()

		if count < 1:
			return

		if self.ul_model.get_iter_first() == None:

			start_queue = True
		else:
			start_queue = False

		model, pathlist = sel.get_selected_rows()

		for path in pathlist:

			iter = model.get_iter(path)
			filename = model.get_value(iter, 1)
			lsize = model.get_value(iter, 2)
			lmtime = str(model.get_value(iter, 3))

			overwrite = []
			overwrite.append(filename)
			overwrite.append(False)

			self.remote_model.foreach(self.check_upload_overwrite, overwrite)

			if overwrite[1]:

				mstr = '<b>Overwrite file?</b>\n'
				mstr += '\nReplace remote file \'' + filename + '\'\n'
				mstr += 'Modified on ' + overwrite[3] + '\n'
				mstr += overwrite[2] + ' bytes\n'
				mstr += '\nWith local file \'' + filename + '\'\n'
				mstr += 'Modified on ' + lmtime + '\n'
				mstr += lsize + ' bytes'

				msg = gtk.MessageDialog(None,gtk.DIALOG_MODAL,gtk.MESSAGE_QUESTION,gtk.BUTTONS_YES_NO)
				msg.set_icon_name("gtk-dialog-question")
				msg.set_title('Overwrite File')
				msg.set_markup(mstr)

				response = msg.run()
				msg.destroy()

				if response == gtk.RESPONSE_NO:
					return


			self.notebook.set_current_page(2)

			uiter = self.ul_model.append()
			self.ul_model.set(uiter,0,model.get_value(iter, 0))
			self.ul_model.set(uiter,1,model.get_value(iter, 1))
			self.ul_model.set(uiter,2,model.get_value(iter, 2))

		if start_queue:

			pulse = Pulse(self.progressbar)
			pulse.start()

			thr = Upload(self.ftp, self.ul_model, pulse, self.load_remote_dir)
			thr.start()


	def stop_transfer(self, widget):

		col = 0
		ico = ''
		sel = None
		page = self.notebook.get_current_page()

		if page == 0 or page == 3:
			return

		elif page == 1:
			sel = self.tvDl.get_selection()
			ico = 'gtk-go-down'
			col = 5

		elif page == 2:
			sel = self.tvUl.get_selection()
			ico = 'gtk-go-up'
			col = 4

		if sel == None:
			return

		count = sel.count_selected_rows()

		if count < 1:
			return

		model, pathlist = sel.get_selected_rows()

		for path in pathlist:

			iter = model.get_iter(path)

			if model.get_value(iter, col) == ico:

				model.set(iter,col,"gtk-stop")

				for i in range(6):
					time.sleep(0.2)
					self.progressbar.pulse()
					gtk.main_iteration(False)

				self.progressbar.set_fraction(0.0)
				self.ftp.abort()
			else:
				model.set(iter,col,"gtk-stop")

	def remove_from_queue(self, widget):

		sel = None
		page = self.notebook.get_current_page()

		if page == 0 or page == 3:
			return
		elif page == 1:
			sel = self.tvDl.get_selection()
		elif page == 2:
			sel = self.tvUl.get_selection()

		if sel == None:
			return

		count = sel.count_selected_rows()

		if count < 1:
			return

		if count >= 1:
			mstr = '<b>Cancel from queue?</b>'
			mstr += '\nAre you sure you want to cancel the selected file(s) from the queue?'

			msg = gtk.MessageDialog(None,gtk.DIALOG_MODAL,gtk.MESSAGE_QUESTION,gtk.BUTTONS_YES_NO)
			msg.set_icon_name("gtk-dialog-question")
			msg.set_title('Transfer Queue')
			msg.set_markup(mstr)

			response = msg.run()
			msg.destroy()

			if response == gtk.RESPONSE_NO:
				return

		model, pathlist = sel.get_selected_rows()

# TODO: this affects the iters

		for path in pathlist:

			iter = model.get_iter(path)
			model.remove(iter)

	# exit program =========================================================
	def on_quit(self, widget, data=None):

		self.save_preferences()

		if player.SOUND_PLAYER == 1:
			self.sWnd.sound_stop(self.sWnd.vbPlayer)

		gtk.main_quit()

	# view settings ========================================================
	def on_view_toolbar(self, widget):

		if self.viewtoolbar1.get_active():
			self.handlebox1.show()

		else:
			self.handlebox1.hide()

	def on_view_connect(self, widget):

		if self.viewconnectbar1.get_active():
			self.handlebox2.show()

		else:
			self.handlebox2.hide()

	def on_view_folderbars(self, widget):

		if self.viewfoldertoolbars1.get_active():
			self.toolbar2.show()
			self.toolbar3.show()

		else:
			self.toolbar2.hide()
			self.toolbar3.hide()

	def on_view_command(self, widget):

		if self.viewcommandbar1.get_active():
			self.hbox10.show()

		else:
			self.hbox10.hide()

	def on_show_hidden(self, widget):

		if self.showhidden1.get_active():
			self.showhidden = 1

		else:
			self.showhidden = 0

		self.load_local_dir(self.fcLocalDir.get_filename())

	def on_toolbars_horizontal(self, widget):

		if self.tbhorizontal1.get_active():

			self.toolbar2.show()
			self.toolbar3.show()
			self.toolbar2v.hide()
			self.toolbar3v.hide()

	def on_toolbars_vertical(self, widget):

		if self.tbvertical1.get_active():

			self.toolbar2v.show()
			self.toolbar3v.show()
			self.toolbar2.hide()
			self.toolbar3.hide()

	def on_toolbars_hidden(self, widget):

		if self.tbhidden1.get_active():

			self.toolbar2v.hide()
			self.toolbar3v.hide()
			self.toolbar2.hide()
			self.toolbar3.hide()

	def on_audio_player(self, widget):

		audioWnd = player.sndWnd("/usr/share/foff/foff-player.glade", "sndWnd")
		audioWnd.sndWnd.show()

	def on_image_viewer(self, widget):

		imgWnd = picWnd("/usr/share/foff/foff.glade", "picWnd")

	def on_text_viewer(self, widget):

		txtWnd = textWnd("/usr/share/foff/foff.glade", "textWnd")

	def on_site_manager(self, widget):

		siteWnd = bookWnd("/usr/share/foff/foff.glade", "bookWnd")

	def on_view_page(self, widget):

		if self.messages1.get_active():
			self.notebook.set_current_page(0)

		elif self.downloadqueue1.get_active():
			self.notebook.set_current_page(1)

		elif self.uploadqueue1.get_active():
			self.notebook.set_current_page(2)

		elif self.audioplayer1.get_active():
			self.notebook.set_current_page(3)

	def on_notebook_switch_page(self, notebook, page, page_num, data=None):

		number = self.notebook.page_num(self.notebook.get_nth_page(page_num))

		if number == 0:

			self.messages1.set_active(True)

		elif number == 1:

			self.downloadqueue1.set_active(True)

		elif number == 2:

			self.uploadqueue1.set_active(True)

		elif number == 3:

			self.audioplayer1.set_active(True)

	# local context menu ===================================================
	def local_context_menu(self, widget, event):

		if event.button == 3:

			popmenu = gtk.Menu()

			menu_item = gtk.ImageMenuItem("_Upload")
			menu_item.set_image(gtk.image_new_from_stock("gtk-go-up",gtk.ICON_SIZE_MENU))
			menu_item.connect("activate",self.on_local_store)
			menu_item.show()
			popmenu.append(menu_item)

			menu_item = gtk.ImageMenuItem("gtk-open")
			menu_item.connect("activate",self.on_local_open)
			menu_item.show()
			popmenu.append(menu_item)

			menu_item = gtk.SeparatorMenuItem()
			menu_item.show()
			popmenu.append(menu_item)

			menu_item = gtk.ImageMenuItem("_Create Directory")
			menu_item.set_image(gtk.image_new_from_stock("gtk-directory",gtk.ICON_SIZE_MENU))
			menu_item.connect("activate",self.on_local_mkdir)
			menu_item.show()
			popmenu.append(menu_item)

			menu_item = gtk.ImageMenuItem("Re_name")
			menu_item.set_image(gtk.image_new_from_stock("gtk-select-font",gtk.ICON_SIZE_MENU))
			menu_item.connect("activate",self.on_local_rename)
			menu_item.show()
			popmenu.append(menu_item)

			menu_item = gtk.ImageMenuItem("gtk-delete")
			menu_item.connect("activate",self.on_local_delete)
			menu_item.show()
			popmenu.append(menu_item)

			menu_item = gtk.SeparatorMenuItem()
			menu_item.show()
			popmenu.append(menu_item)

			menu_item = gtk.ImageMenuItem("gtk-refresh")
			menu_item.connect("activate",self.on_local_refresh)
			menu_item.show()
			popmenu.append(menu_item)

			menu_item = gtk.SeparatorMenuItem()
			menu_item.show()
			popmenu.append(menu_item)

			menu_item = gtk.ImageMenuItem("Compress (gzip)")
			menu_item.set_image(gtk.image_new_from_stock("gtk-sort-ascending",gtk.ICON_SIZE_MENU))
			menu_item.connect("activate",self.on_compress)
			menu_item.show()
			popmenu.append(menu_item)

			menu_item = gtk.ImageMenuItem("Decompress (bz2/gzip/zip)")
			menu_item.set_image(gtk.image_new_from_stock("gtk-sort-descending",gtk.ICON_SIZE_MENU))
			menu_item.connect("activate",self.on_decompress)
			menu_item.show()
			popmenu.append(menu_item)

			menu_item = gtk.SeparatorMenuItem()
			menu_item.show()
			popmenu.append(menu_item)

			menu_item = gtk.ImageMenuItem("Create Checksum (md5)")
			menu_item.set_image(gtk.image_new_from_stock("gtk-apply",gtk.ICON_SIZE_MENU))
			menu_item.connect("activate",self.on_create_checksum)
			menu_item.show()
			popmenu.append(menu_item)

			menu_item = gtk.ImageMenuItem("Verify Checksum (md5)")
			menu_item.set_image(gtk.image_new_from_stock("gtk-apply",gtk.ICON_SIZE_MENU))
			menu_item.connect("activate",self.on_verify_checksum)
			menu_item.show()
			popmenu.append(menu_item)


			popmenu.show()
			popmenu.popup(None, None, None, event.button, event.time)

	# remote context menu ==================================================
	def remote_context_menu(self, widget, event):

		if self.ftp == None:

			return

		if event.button == 3:

			popmenu = gtk.Menu()

			menu_item = gtk.ImageMenuItem("Down_load")
			menu_item.set_image(gtk.image_new_from_stock("gtk-go-down",gtk.ICON_SIZE_MENU))
			menu_item.connect("activate",self.on_remote_get)
			menu_item.show()
			popmenu.append(menu_item)

			menu_item = gtk.SeparatorMenuItem()
			menu_item.show()
			popmenu.append(menu_item)

			menu_item = gtk.ImageMenuItem("_Create Directory")
			menu_item.set_image(gtk.image_new_from_stock("gtk-directory",gtk.ICON_SIZE_MENU))
			menu_item.connect("activate",self.on_remote_mkdir)
			menu_item.show()
			popmenu.append(menu_item)

			menu_item = gtk.ImageMenuItem("Re_name")
			menu_item.set_image(gtk.image_new_from_stock("gtk-select-font",gtk.ICON_SIZE_MENU))
			menu_item.connect("activate",self.on_remote_rename)
			menu_item.show()
			popmenu.append(menu_item)

			menu_item = gtk.ImageMenuItem("gtk-delete")
			menu_item.connect("activate",self.on_remote_delete)
			menu_item.show()
			popmenu.append(menu_item)

			menu_item = gtk.SeparatorMenuItem()
			menu_item.show()
			popmenu.append(menu_item)

			menu_item = gtk.ImageMenuItem("gtk-refresh")
			menu_item.connect("activate",self.on_remote_refresh)
			menu_item.show()
			popmenu.append(menu_item)

			popmenu.show()
			popmenu.popup(None, None, None, event.button, event.time)

	# main toolbar common buttons ==========================================
	def tb_mkdir(self, widget):

		if self.activeview == 1:

			self.on_local_mkdir(self.tvLocalFiles)

		elif self.activeview == 2:

			self.on_remote_mkdir(self.tvRemoteFiles)

	def tb_rename(self, widget):

		if self.activeview == 1:

			self.on_local_rename(self.tvLocalFiles)

		elif self.activeview == 2:

			self.on_remote_rename(self.tvRemoteFiles)

	def tb_delete(self, widget):

		if self.activeview == 1:

			self.on_local_delete(self.tvLocalFiles)

		elif self.activeview == 2:

			self.on_remote_delete(self.tvRemoteFiles)

	def tb_refresh(self, widget):

		if self.activeview == 1:

			self.load_local_dir()

		elif self.activeview == 2:

			self.load_remote_dir()

	# track last used  folder view =========================================
	def focus_local(self, widget, event):

		self.activeview = 1

	def focus_remote(self, widget, event):

		self.activeview = 2

	# about ================================================================
	def goto_url(self, dialog, website, data=None):

		webbrowser.open_new(website)


	def on_about(self, widget):

		try:
			file = open(os.path.join(self.cwd,"Copying.txt"), "r")
			license = file.read()
			file.close()

		except IOError:
			self.printm('Cannot open license file for reading', "gtk-dialog-error")

			license = "GNU General Public License (GPL)"

		authors = ["Free Open FTP Face by Jeffrey Bakker",
				"GladeWrapper \"libglade.py\" by Padraig Brady",
				"Python DES implementation \"pyDes.py\" by Todd Whiteman"]

		about = gtk.AboutDialog()

		try:
			foff_logo = gtk.gdk.pixbuf_new_from_file("/usr/share/foff/foff_logo00.png")
			about.set_logo(foff_logo)
		except:
			pass

		gtk.about_dialog_set_url_hook(self.goto_url, "http://foff.sf.net")

		about.set_name("FOFF")
		about.set_version("0.99.5 very beta")
		about.set_copyright("(C)2006 Jeffrey Bakker")
		about.set_authors(authors)
		about.set_license(license)
		about.set_website("http://foff.sf.net")
		about.set_website_label("http://foff.sf.net")

		about.run()
		about.destroy()


# start the application ========================================================
gtk.gdk.threads_init()
gtk.threads_enter()
mWnd = mainWnd("/usr/share/foff/foff.glade", "mainWnd")

gtk.main()
gtk.threads_leave()
# end of program ===============================================================
