| 
							跨平台简化客户端
							为了支持各种Linux Unix Mac Windows等多种桌面,我们使用Python3 + 
							wxPython4 
							编写了这个跨平台桌面客户端,功能进行了大幅度缩减,但是一般的桌面点播和检索功能都已经做进去,这个程序只是我们提供的一个额外的开源框架客户端,主要是为了方便用户在此基础上开发自己想要的功能,但是对我们来说,它只是个备胎客户端; 因为各种平台Python运行的方式都不同 
							, 例如在windows环境下,您可以在命令行下,使用 python 
							xftp.py来运行这个客户端,也可以写个批处理然后放个快捷方式到桌面上. 
							或者直接双击xftp.py也可以运行这个程序,但是需要注意的是,为了运行本程序,必须在您的电脑上安装python3
							
							https://www.python.org/  , 此外还需要安装wxpython
							
							https://www.wxpython.org   
							2025.09.01补充,目前全新版本的XFile已经升级到4.xx,与旧版本的python可能存在兼容性,但是有了全新的点播客户端XFileM,
							请参考这里   支持的功能: 
							md5登录/加密md5登录XFile服务器 (并支持手动启用SHA256加密口令以支持未来版本) 
							新版本已经使用SHA256加密加盐登录协议 文件列表 切换 检索 点播 
							(新版本强制使用Http流映射功能)     源代码下载:
							
							 点击这里  
							(windows等平台下可直接双击运行xftp.py] 运行效果图: 
							     
							下面是初始版本源代码,但是注意,由于编辑器自动将缩进给吃掉了,所以你不能直接拷贝下面的内容到编辑器,仅供参考 # -*- coding: utf-8 -*-
							
 ###########################################################################
 ## 程序设计 danscort yu (c)2018
 ##
 ##
 ##
 ###########################################################################
 ###########################################################################
 ## 本代码使用wxPython + ftplib 编写 注意 
							只能在python版本高于3的环境下执行,不支持python2
 ## 专门适应XFile家庭文件服务器软件的跨平台运行播放客户端
 ## 
							代码里硬代码支持中文和英文,当然你也可以扩展支持各种其他语言,外挂也可以,但是我不想在细节上花费太多时间,因为windows平台已经有专用客户端,主要是支持Linux/unix平台用
 ## 注意 如果要使用标准FTP服务器软件 则必须注销掉SLST HTTP等扩展指令 
							并且换用不安全的明文口令,
 ## XFile服务器软件下载 https://www.phoenixp2p.com
 ## List列表指令采用XFile专用的简化格式列表 去掉SLST 可以切换回标准FTP列表
 ## 事实上XFile可以支持 例如 http映射,这样可以让网络播放更流畅 
							我保留了http选择项,用于将来的扩展
 ## 我们支持XFile加密口令 [加盐md5口令],这里我们套用了移动端验证口令 两种方式 
							都是加盐的验证 可以抗破解
 ## 因为各种限制 ,只做了检索支持
 ## python 和wxPython我都是第一次使用, 不熟悉,项目比较粗糙,无法象native 
							c++开发界面那样精确
 ## 执行方式 命令行下 输入 python xftp.py 或者建立一个批处理的快捷方式放到桌面上
 ## 目录下的xftpset文件是外部播放器程序的播放指令等信息 
							您应该根据你播放器的实际安装目录进行修改
 ## 在windows端支持 vlc mpv kodi 等主流播放器
 ## Player_cmd=H:\VLC\vlc.exe "$url"
 ## Player_cmdunix=vlc.exe "$url"
 ## 前一个Player_cmd用于windows环境 ,后一个用于非windows环境 
							,请根据实际进行修改 $url代表ftp实际连接
 ## 为了运行本程序,必须在您的电脑上安装python3 https://www.python.org/ 
							, 此外还需要安装wxpython https://www.wxpython.org
 ## 如果是正式版本,请将全局变量_debugmode 设置为False
 ##
 ##
 ##
 ##
 ##
 ##
 ##
 ##
 ##
 ## 您可以任意修改本代码 但是请保留本说明部分
 ## 作者: danscort@phoenixp2p.com
 ##
 ###########################################################################
 import wx
 import sys
 import time
 import wx.xrc
 import socket
 import os
 import ftplib
 from ftplib import FTP
 from ftplib import FTP_TLS
 import configparser
 import hashlib
 #from StringIO import StringIO
 #import images
 
 ###########################################################################
 ## Class MyFrameMain
 ###########################################################################
 #global m_ftp
 #global m_ftps
 #global mb_con
 ##以下是全局变量部分
 _ftp=FTP( )
 _ftps=FTP_TLS( )
 _mbcon=True
 _mbssl=False
 _httpport=0
 _debugmode=True
 # 如果是正式发行版本 请修改为 _debugmode=False
 _curworkdir="/"
 _chineseversion=True
 _timersec=0
 #播放调用程序 默认是vlc.exe 我们从配置文件读这个播放接口 这里只是预配置
 _playercmd='vlc.exe "$url"'
 #配置文件
 _configfile="xftpset.ini"
 _dlgitemfile="dlgitem.ini"
 #随机数 XFile专用的随机数字符串
 _srandomcode="0"
 #全局登录口令 是二次MD5, 但是注意 这个全局字符串有时间限制 可能在服务器某次刷新后就发生变动
 _sglobalpass=""
 
 
 class MyFrameMain ( wx.Frame ):
 
 def __init__( self, parent ):
 global _chineseversion
 #reload(sys)
 #sys.setdefaultencoding('utf-8')
 wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, 
							title = "XFtp", pos = wx.DefaultPosition, size = 
							wx.Size( 800,530 ), style = 
							wx.CAPTION|wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
 
 self.SetSizeHints( wx.DefaultSize, wx.DefaultSize )
 
 bSizer3 = wx.BoxSizer( wx.VERTICAL )
 
 bSizer1 = wx.BoxSizer( wx.HORIZONTAL )
 bSizer2 = wx.BoxSizer( wx.HORIZONTAL )
 
 bSizer1.SetMinSize( wx.Size( 600,20 ) )
 bSizer2.SetMinSize( wx.Size( 600,20 ) )
 if(_chineseversion):
 self.m_staticText1 = wx.StaticText( self, wx.ID_ANY, 
							"服务器地址 ", wx.DefaultPosition, wx.Size( 60,15 ), 0 )
 else:
 self.m_staticText1 = wx.StaticText( self, wx.ID_ANY, 
							"Server ", wx.DefaultPosition, wx.Size( 60,15 ), 0 )
 
 self.m_staticText1.Wrap( -1 )
 
 bSizer1.Add( self.m_staticText1, 0, wx.ALL, 5 )
 
 if(_chineseversion):
 self.m_textCtrlServer = wx.TextCtrl( self, 
							wx.ID_ANY, "127.0.0.1", wx.DefaultPosition, wx.Size( 
							100,15 ), 0 )
 
 else:
 self.m_textCtrlServer = wx.TextCtrl( self, 
							wx.ID_ANY, "127.0.0.1", wx.DefaultPosition, wx.Size( 
							100,15 ), 0 )
 
 #self.m_textCtrlServer = wx.TextCtrl( self, 
							wx.ID_ANY, "127.0.0.1", wx.DefaultPosition, wx.Size( 
							100,15 ), 0 )
 bSizer1.Add( self.m_textCtrlServer, 0, wx.ALL, 5 )
 
 if(_chineseversion):
 self.m_staticText2 = wx.StaticText( self, wx.ID_ANY, 
							"端口", wx.DefaultPosition, wx.Size( 30,15 ), 0 )
 
 else:
 self.m_staticText2 = wx.StaticText( self, wx.ID_ANY, 
							"Port", wx.DefaultPosition, wx.Size( 30,15 ), 0 )
 
 #self.m_staticText2 = wx.StaticText( self, 
							wx.ID_ANY, u"Port", wx.DefaultPosition, wx.Size( 
							30,15 ), 0 )
 self.m_staticText2.Wrap( -1 )
 
 bSizer1.Add( self.m_staticText2, 0, wx.ALL, 5 )
 
 self.m_textCtrlPort = wx.TextCtrl( self, wx.ID_ANY, 
							"21", wx.DefaultPosition, wx.Size( 45,15 ), 0 )
 bSizer1.Add( self.m_textCtrlPort, 0, wx.ALL, 5 )
 
 if(_chineseversion):
 self.m_staticText3 = wx.StaticText( self, wx.ID_ANY, 
							"用户名", wx.DefaultPosition, wx.Size( 50,15 ), 0 )
 
 else:
 self.m_staticText3 = wx.StaticText( self, wx.ID_ANY, 
							"User", wx.DefaultPosition, wx.Size( 50,15 ), 0 )
 
 
 #self.m_staticText3 = wx.StaticText( self, 
							wx.ID_ANY, "User", wx.DefaultPosition, wx.Size( 
							50,15 ), 0 )
 self.m_staticText3.Wrap( -1 )
 
 bSizer1.Add( self.m_staticText3, 0, wx.ALL, 5 )
 
 self.m_textCtrlUsername = wx.TextCtrl( self, 
							wx.ID_ANY, "admin", wx.DefaultPosition, wx.Size( 
							80,15 ), 0 )
 bSizer1.Add( self.m_textCtrlUsername, 0, wx.ALL, 5 )
 
 if(_chineseversion):
 self.m_staticText4 = wx.StaticText( self, wx.ID_ANY, 
							"口令", wx.DefaultPosition, wx.Size( 50,15 ), 0 )
 
 else:
 self.m_staticText4 = wx.StaticText( self, wx.ID_ANY, 
							"Password", wx.DefaultPosition, wx.Size( 50,15 ), 0 
							)
 
 #self.m_staticText4 = wx.StaticText( self, 
							wx.ID_ANY, "Password", wx.DefaultPosition, wx.Size( 
							50,15 ), 0 )
 self.m_staticText4.Wrap( -1 )
 
 bSizer1.Add( self.m_staticText4, 0, wx.ALL, 5 )
 
 self.m_textCtrlPassword = wx.TextCtrl( self, 
							wx.ID_ANY, "88888888", wx.DefaultPosition, wx.Size( 
							70,15 ), style=wx.TE_PASSWORD )
 #这里加入 设置textctrl 是口令模式
 
 bSizer1.Add( self.m_textCtrlPassword, 0, wx.ALL, 5 )
 
 if(_chineseversion):
 self.m_checkBoxHttp = wx.CheckBox( self, wx.ID_ANY, 
							"Http流优先", wx.DefaultPosition, wx.Size( 80,15 ), 0 )
 
 else:
 self.m_checkBoxHttp = wx.CheckBox( self, wx.ID_ANY, 
							"Http stream", wx.DefaultPosition, wx.Size( 80,15 ), 
							0 )
 
 #self.m_checkBoxHttp = wx.CheckBox( self, wx.ID_ANY, 
							u"Http stream", wx.DefaultPosition, wx.Size( 65,15 
							), 0 )
 bSizer1.Add( self.m_checkBoxHttp, 0, wx.ALL, 5 )
 
 if(_chineseversion):
 self.m_checkBoxSsl = wx.CheckBox( self, wx.ID_ANY, 
							"SSL加密", wx.DefaultPosition, wx.Size( 60,15 ), 0 )
 
 else:
 self.m_checkBoxSsl = wx.CheckBox( self, wx.ID_ANY, 
							"TLS/SSL", wx.DefaultPosition, wx.Size( 60,15 ), 0 )
 
 
 #self.m_checkBoxSsl = wx.CheckBox( self, wx.ID_ANY, 
							"SSL", wx.DefaultPosition, wx.Size( 45,15 ), 0 )
 bSizer1.Add( self.m_checkBoxSsl, 0, wx.ALL, 5 )
 
 if(_chineseversion):
 self.m_buttonLogin = wx.Button( self, wx.ID_ANY, 
							"连接", wx.DefaultPosition, wx.DefaultSize, 0 )
 
 else:
 self.m_buttonLogin = wx.Button( self, wx.ID_ANY, 
							"Connect", wx.DefaultPosition, wx.DefaultSize, 0 )
 
 #self.m_buttonLogin = wx.Button( self, wx.ID_ANY, 
							"Connect", wx.DefaultPosition, wx.DefaultSize, 0 )
 bSizer1.Add( self.m_buttonLogin, 0, wx.ALL, 5 )
 
 #这里我决定添加检索功能
 self.m_staticinfo=wx.StaticText( self, wx.ID_ANY, 
							"/", wx.DefaultPosition, wx.Size( 220,18 ), 
							wx.ALIGN_LEFT )
 self.m_staticinfo.Wrap( -1 )
 bSizer2.Add(self.m_staticinfo)
 if(_chineseversion):
 self.m_staticsearch=wx.StaticText( self, wx.ID_ANY, 
							"关键词:", wx.DefaultPosition, wx.Size( 80,18 ), 
							wx.ALIGN_LEFT )
 
 else:
 self.m_staticsearch=wx.StaticText( self, wx.ID_ANY, 
							"Keywords:", wx.DefaultPosition, wx.Size( 80,18 ), 
							wx.ALIGN_LEFT )
 
 #self.m_staticsearch=wx.StaticText( self, wx.ID_ANY, 
							"Keywords:", wx.DefaultPosition, wx.Size( 80,18 ), 
							wx.ALIGN_LEFT )
 self.m_staticsearch.Wrap( -1 )
 bSizer2.Add(self.m_staticsearch)
 self.m_textsearch = wx.TextCtrl( self, wx.ID_ANY, 
							".mkv", wx.DefaultPosition, wx.Size( 120,18 ), 
							wx.ALIGN_LEFT )
 bSizer2.Add( self.m_textsearch, 0, wx.ALL, 5 )
 if(_chineseversion):
 self.m_buttonSearch = wx.Button( self, wx.ID_ANY, 
							"检索", wx.DefaultPosition, wx.DefaultSize, 
							wx.ALIGN_RIGHT )
 
 else:
 self.m_buttonSearch = wx.Button( self, wx.ID_ANY, 
							"Search", wx.DefaultPosition, wx.DefaultSize, 
							wx.ALIGN_RIGHT )
 
 #self.m_buttonSearch = wx.Button( self, wx.ID_ANY, 
							"Search", wx.DefaultPosition, wx.DefaultSize, 
							wx.ALIGN_RIGHT )
 bSizer2.Add( self.m_buttonSearch, 0, wx.ALL, 5 )
 
 bSizer3.Add( bSizer1, 1, 
							wx.ALIGN_TOP|wx.FIXED_MINSIZE|wx.LEFT, 5 )
 bSizer3.Add( bSizer2, 1, 
							wx.ALIGN_TOP|wx.FIXED_MINSIZE|wx.LEFT, 5 )
 bSizerList = wx.BoxSizer( wx.VERTICAL )
 
 self.il = wx.ImageList(16, 16)
 #self.idx1 = self.il.Add(images.Smiles.GetBitmap())
 #self.sm_up = 
							self.il.Add(images.SmallUpArrow.GetBitmap())
 #self.sm_dn = 
							self.il.Add(images.SmallDnArrow.GetBitmap())
 self.m_listCtrlFtp = wx.ListCtrl( self, wx.ID_ANY, 
							wx.DefaultPosition, wx.Size( 800,500 ), 
							wx.LC_REPORT)
 self.m_listCtrlFtp.SetImageList(self.il, 
							wx.IMAGE_LIST_SMALL)
 bSizerList.Add( self.m_listCtrlFtp, 0, wx.ALL, 5 )
 bSizer3.Add( bSizerList, 1, wx.EXPAND, 5 )
 
 
 self.SetSizer( bSizer3 )
 self.Layout()
 
 self.Centre( wx.BOTH )
 
 # Connect Events
 self.Bind( wx.EVT_CLOSE, self.OnMyClose )
 self.m_buttonLogin.Bind( wx.EVT_BUTTON, 
							self.OnMyButtonClick )
 self.m_buttonSearch.Bind( wx.EVT_BUTTON, 
							self.OnMySearchButtonClick )
 self.m_listCtrlFtp.Bind( wx.EVT_LIST_COL_CLICK, 
							self.OnMyListColClick )
 self.m_listCtrlFtp.Bind( wx.EVT_LIST_ITEM_ACTIVATED, 
							self.OnMyListItemActivated )
 self.m_listCtrlFtp.Bind( 
							wx.EVT_LIST_ITEM_RIGHT_CLICK, 
							self.OnMyListItemRightClick )
 #self.m_listCtrlFtp.Bind( 
							wx.EVT_LIST_COL_RIGHT_CLICK, self.OnMyRightClick)
 # for wxMSW
 self.m_listCtrlFtp.Bind(wx.EVT_COMMAND_RIGHT_CLICK, 
							self.OnMyRightClick)
 
 # for wxGTK
 self.m_listCtrlFtp.Bind(wx.EVT_RIGHT_UP, 
							self.OnMyRightClick)
 
 #insert list columns num attr size filename
 #self.m_listCtrlFtp.InsertColumn(0,"Num")
 #self.m_listCtrlFtp.InsertColumn(1,"Type")
 #self.m_listCtrlFtp.InsertColumn(2,"Size")
 #self.m_listCtrlFtp.InsertColumn(3,"Name")
 #we need to insert images for list
 info = wx.ListItem()
 info.Mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE | 
							wx.LIST_MASK_FORMAT
 info.Image = -1
 info.Align = 0
 if(_chineseversion):
 info.Text = "编号"
 else:
 info.Text = "Num"
 #info.Text = u"Num"
 self.m_listCtrlFtp.InsertColumn(0, info)
 
 info = wx.ListItem()
 info.Mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_FORMAT
 #info.Image = -1
 info.Align = 0
 if(_chineseversion):
 info.Text = "类型"
 else:
 info.Text = "Type"
 #info.Text = u"Type"
 self.m_listCtrlFtp.InsertColumn(1, info)
 
 info = wx.ListItem()
 info.Mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_FORMAT
 #info.Image = -1
 info.Align = 0
 info.SetWidth(120)
 if(_chineseversion):
 info.Text = "大小"
 else:
 info.Text = "Size"
 #info.Text = "Size"
 self.m_listCtrlFtp.InsertColumn(2, info)
 
 info = wx.ListItem()
 info.Mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_FORMAT
 #info.Image = -1
 info.Align = 0
 if(_chineseversion):
 info.Text = "名称"
 else:
 info.Text = "Name"
 #info.Text = "Name"
 info.SetWidth(480)
 self.m_listCtrlFtp.InsertColumn(3, info)
 # Bind all EVT_TIMER events to self.OnTest1Timer
 #设置定时器 主要是用来支持定时发送NOOP指令 防止服务器断开连接
 self.timer1 = wx.Timer(self,8801)
 #必须指定只处理timer1事件
 self.Bind(wx.EVT_TIMER, 
							self.OnMyTimerMsg,self.timer1)
 #注意 绑定是在这里
 
 self.FuncChangeButton( )
 #Load dlg item strings
 self.FuncLoadDlgItem( )
 
 def __del__( self ):
 pass
 
 
 # Virtual event handlers, overide them in your 
							derived class
 def OnMyClose( self, event ):
 #event.Skip()
 global _mbcon
 global _ftp
 global _ftps
 global _mbssl
 if(_mbcon):
 pass
 else:
 try:
 if(mbssl):
 _ftps.close( )
 else:
 _ftp.close( )
 except:
 pass
 self.FuncSaveDlgItem()
 event.Skip( )
 
 def FuncSaveDlgItem(self):
 #在退出的时候保存参数
 global _dlgitemfile
 global _debugmode
 if(_debugmode):
 print("Now will save dlg string to file")
 cf=configparser.RawConfigParser()
 cf.add_section('Dlgitem')
 cf.set('Dlgitem', 'server_addr', 
							self.m_textCtrlServer.GetLineText(0))
 cf.set('Dlgitem', 'server_port', 
							self.m_textCtrlPort.GetLineText(0))
 cf.set('Dlgitem', 'server_username', 
							self.m_textCtrlUsername.GetLineText(0))
 cf.set('Dlgitem', 'server_password', 
							self.m_textCtrlPassword.GetLineText(0))
 str1='0'
 if(self.m_checkBoxSsl.GetValue()):
 str1='1'
 cf.set('Dlgitem', 'server_ssl', str1)
 str1='0'
 if(self.m_checkBoxHttp.GetValue()):
 str1='1'
 cf.set('Dlgitem', 'server_http', str1)
 #cf.set('Dlgitem', 'server_addr', 
							self.m_textCtrlServer.GetLineText(0))
 #cf.set('Dlgitem', 'server_addr', 
							self.m_textCtrlServer.GetLineText(0))
 with open(_dlgitemfile, 'wt') as configfile:
 cf.write(configfile)
 
 return
 
 
 
 
 def FuncLoadDlgItem(self):
 #读取主界面的部分参数
 global _dlgitemfile
 global _debugmode
 cf=configparser.ConfigParser()
 try:
 cf.read(_dlgitemfile)
 except IOError as e:
 if(_debugmode):
 print("Failed to load string file")
 return
 except :
 if(_debugmode):
 print("Unknwon error to load string file")
 return
 #现在保证已经正常打开配置文件 那么尝试读取吧
 str1=''
 try:
 str1=cf.get("Dlgitem","server_addr")
 if(len(str1)>=1):
 self.m_textCtrlServer.SetLabelText(str1)
 str1=''
 str1=cf.get("Dlgitem","server_port")
 if(len(str1)>=1):
 self.m_textCtrlPort.SetLabelText(str1)
 str1=''
 str1=cf.get("Dlgitem","server_username")
 if(len(str1)>=1):
 self.m_textCtrlUsername.SetLabelText(str1)
 str1=''
 str1=cf.get("Dlgitem","server_password")
 if(len(str1)>=1):
 self.m_textCtrlPassword.SetLabelText(str1)
 if(cf.get("Dlgitem","server_ssl")=='1'):
 self.m_checkBoxSsl.SetValue(True)
 if(cf.get("Dlgitem","server_http")=='1'):
 self.m_checkBoxHttp.SetValue(True)
 
 except (configparser.MissingSectionHeaderError,
 configparser.NoSectionError,
 configparser.NoOptionError) as e:
 if(_debugmode):
 print("Read string section error")
 return
 except :
 if(_debugmode):
 print("Read string section unknown error")
 return
 return
 
 def FuncLoadConfigFile(self):
 #读取配置文件
 #默认是当前目录下的xftp.ini
 #如果你要支持多国家语言 事实上也可以在这里进行
 #我是贪图方便 只做了英文和简体中文 硬编码 当然用c++的客户端我是采用的配置文件实现多国语言支持
 global _configfile
 global _playercmd
 global _debugmode
 cf=configparser.ConfigParser()
 #cf=configparser.RawConfigParser( )
 try:
 #cf.read(_configfile,'utf-8')
 #with open(_configfile, 'rb') as f:
 # content = 
							f.read().decode('utf-8-sig').encode('utf8')
 # cf.readfp(StringIO(content))
 cf.read(_configfile)
 
 
 except IOError as e:
 if(_debugmode):
 print("Failed to load config file")
 return
 
 except:
 if(_debugmode):
 print("Unknwon error to load config file")
 return
 str1=''
 try:
 #这里根据不同的操作系统读取不同的执行命令
 if(os.name=='nt'):
 str1=cf.get("XFtp_Set","Player_cmd")
 else:
 str1=cf.get("XFtp_Set","Player_cmdunix")
 except (configparser.MissingSectionHeaderError,
 configparser.NoSectionError,
 configparser.NoOptionError) as e:
 if(_debugmode):
 print("Read section error")
 return
 except:
 if(_debugmode):
 print("Unknown error to read section")
 str1=''
 if(len(str1)<=0):
 _playercmd='vlc.exe "$url"'
 else:
 _playercmd=str1
 if(_debugmode):
 print(_playercmd)
 return
 
 
 
 
 def OnMySearchButtonClick(self, event):
 #如果用户按了检索按钮
 global _mbcon
 global _mbssl
 global _ftp
 global _ftps
 #str6=""
 if(_mbcon):
 return
 str5=self.m_textsearch.GetLineText(0)
 if(len(str5)<=1):
 return
 str5="SKEY "+str5
 if(_mbssl):
 try:
 _ftps.sendcmd(str5)
 except (socket.error, socket.gaierror):
 self.FuncDisconnect( )
 return
 except ftplib.error_perm:
 return
 except:
 self.FuncDisconnect( )
 return
 else:
 try:
 _ftp.sendcmd(str5)
 except (socket.error, socket.gaierror):
 self.FuncDisconnect( )
 return
 except ftplib.error_perm:
 return
 except:
 self.FuncDisconnect( )
 return
 
 if(self.FuncGetList()==0):
 self.FuncDisconnect()
 return
 
 return
 
 def FuncGetList(self):
 #如果连接失败 则返回0 如果目录不存在等 则返回 -1
 global _chineseversion
 global _timersec
 data=[]
 if(_debugmode):
 print("Func getlist is called")
 _timersec=0
 #这里需要加入获取当前目录的操作函数
 
 if(_mbssl):
 try:
 #如果需要使用加密获取目录列表 那么每次都要重新发送prot_p
 #我这里直接采用明文,因为并不是什么机密内容 单纯将登录过程进行保密已经足够了
 _ftps.retrlines('LIST',data.append)
 except (socket.error, socket.gaierror):
 return 0
 except ftplib.error_perm:
 return -1
 except:
 return 0
 else:
 pass
 else:
 try:
 _ftp.retrlines('LIST',data.append)
 except (socket.error, socket.gaierror):
 return 0
 except ftplib.error_perm:
 return -1
 except:
 return 0
 #现在可以保证已经获取到了数据
 # 我们的目标服务器是XFile服务器 因此提供的是XFile标准扩展格式
 # 格式如下
 # 现在处理data数据
 # filesie 1/0 modtime |filename or dirname
 # filesize=64bit long int
 arr1=[]
 iline=0
 filesize=0
 modtime=0
 isdir=0
 self.m_listCtrlFtp.DeleteAllItems( )
 iline=self.m_listCtrlFtp.InsertItem(self.m_listCtrlFtp.GetItemCount( 
							),"",-1)
 self.m_listCtrlFtp.SetItem(iline,0,str(iline))
 if(_chineseversion):
 self.m_listCtrlFtp.SetItem(iline,1,"目录")
 else:
 self.m_listCtrlFtp.SetItem(iline,1,"Dir")
 
 #self.m_listCtrlFtp.SetItem(iline,1,"Dir")
 self.m_listCtrlFtp.SetItem(iline,2,"0")
 self.m_listCtrlFtp.SetItem(iline,3,"..")
 
 for str2 in data :
 if(_debugmode):
 print(str2)
 
 if(len(str2)<5):
 continue
 #spilit line by |
 i2=str2.find('|')
 if(i2<=3 or i2>=len(str2)):
 continue
 else:
 str3=str(str2[i2+1: ])
 str3.strip('\n')
 str3.strip('\r')
 str3.strip(' ')
 #文件名提取成功 下面提取文件长度等信息
 arr1=str2.split()
 if(len(arr1)<3):
 continue;
 #执行数字转换吧
 # 注意格式
 filesize=int(arr1[0],16)
 isdir=not int(arr1[1])
 modtime=int(arr1[2],16)
 #完成转换 现在执行插入操作
 iline=self.m_listCtrlFtp.InsertItem(self.m_listCtrlFtp.GetItemCount( 
							),"",-1)
 self.m_listCtrlFtp.SetItem(iline,0,str(iline))
 if(isdir):
 if(_chineseversion):
 self.m_listCtrlFtp.SetItem(iline,1,"目录")
 else:
 self.m_listCtrlFtp.SetItem(iline,1,"Dir")
 #self.m_listCtrlFtp.SetItem(iline,1,"Dir")
 self.m_listCtrlFtp.SetItem(iline,2,"0")
 else:
 if(_chineseversion):
 self.m_listCtrlFtp.SetItem(iline,1,"文件")
 else:
 self.m_listCtrlFtp.SetItem(iline,1,"File")
 #self.m_listCtrlFtp.SetItem(iline,1,"File")
 self.m_listCtrlFtp.SetItem(iline,2,str(filesize))
 self.m_listCtrlFtp.SetItem(iline,3,str3)
 #定时器
 #self.timer1 = wx.Timer(self)
 return 1
 
 def FuncGetRandomCode(self):
 global _ftp
 global _ftps
 global _srandomcode
 global _mbssl
 global _debugmode
 
 str5=""
 try:
 if(_mbssl):
 str5=_ftps.sendcmd("MKEY")
 else:
 str5=_ftp.sendcmd("MKEY")
 except (socket.error, socket.gaierror):
 return False
 
 except ftplib.error_perm:
 if(_debugmode):
 print("Error: server do not support MKEY")
 return False
 except:
 return False
 #现在分解返回的参数吧
 arr2=[ ]
 arr2=str5.split(' ')
 if(len(arr2)<3):
 if(_debugmode):
 print("Error: bad response from server of MKEY")
 
 return False
 if(_debugmode):
 print(str5)
 print(arr2[1])
 _srandomcode=arr2[1]
 return True
 
 
 
 
 
 
 
 def FunXFileExtend(self):
 global _mbcon
 global _debugmode
 global _mbssl
 global _ftp
 global _ftps
 global _httpport
 global _sglobalpass
 
 _sglobalpass=self.m_textCtrlPassword.GetLineText(0)
 
 if(_debugmode):
 print("XFileExteng function is called")
 str3="SLST 0"
 str4=""
 _httpport=0
 if(_mbssl):
 _ftps.set_pasv(True)
 try:
 str4=_ftps.sendcmd(str3)
 except (socket.error, socket.gaierror):
 return 0
 
 except ftplib.error_perm:
 if(_debugmode):
 print("Reponse error for SLST command")
 return 0
 except:
 return 0
 #https模式 需要新加入是采用p或者c模式支持
 try:
 #改用明文模式
 _ftps.prot_c()
 #_ftps.prot_p( )
 #_ftps._prot_p=True
 
 except (socket.error, socket.gaierror):
 return 0
 except ftplib.error_perm:
 if(_debugmode):
 print("Reponse error for PROT command")
 return 0
 except:
 return 0
 #发送SALT指令获取全局随机数
 str3="SALT"
 try:
 str4=_ftps.sendcmd(str3)
 except ftplib.error_perm:
 return 0
 except:
 return 0
 #提取服务器的回答
 arr8=[]
 arr8=str4.split(' ')
 if(len(arr8)>=2):
 str4=arr8[1]
 if(_debugmode):
 print(str4)
 #执行清理
 str4.strip(' ')
 str4.strip('\n')
 str4.strip('\r')
 #这里可以生成全局的登录口令了
 strnew=str4
 strnew+=self.m_textCtrlPassword.GetLineText(0)
 strnew+=str4;
 strnew+="()"
 if(_debugmode):
 print(strnew)
 md55=hashlib.md5()
 md55.update(strnew.encode(encoding='utf-8'))
 strnew=md55.hexdigest( )
 if(_debugmode):
 print(strnew)
 str3=strnew[0:2]
 str3+="_"
 str3+=strnew[3:]
 strnew=str4
 strnew+="<>"
 strnew+=str3
 #再次生成MD5加密口令
 if(_debugmode):
 print(strnew)
 md55=hashlib.md5()
 md55.update(strnew.encode(encoding='utf-8'))
 strnew=md55.hexdigest( )
 str3=strnew[0:2]
 str3+="_"
 str3+=strnew[3:]
 if(_debugmode):
 print(str3)
 _sglobalpass=str3
 
 
 #发送http指令获取服务端口
 #if(_debugmode):
 #print(str4)
 
 str3="HTTP 0"
 try:
 str4=_ftps.sendcmd(str3)
 except ftplib.error_perm:
 return 1
 except:
 return 0
 
 else:
 _ftp.set_pasv(True)
 try:
 str4=_ftp.sendcmd(str3)
 except (socket.error, socket.gaierror):
 return 0
 except ftplib.error_perm:
 return 0
 except :
 return 0
 if(_debugmode):
 print(str4)
 
 str3="SALT"
 try:
 str4=_ftp.sendcmd(str3)
 except ftplib.error_perm:
 return 0
 except:
 return 0
 #提取服务器的回答
 arr8=[]
 arr8=str4.split(' ')
 if(len(arr8)>=2):
 str4=arr8[1]
 if(_debugmode):
 print(str4)
 str4.strip(' ')
 str4.strip('\n')
 str4.strip('\r')
 #这里可以生成全局的登录口令了
 #
 #
 strnew=str4
 strnew+=self.m_textCtrlPassword.GetLineText(0)
 strnew+=str4;
 strnew+="()"
 if(_debugmode):
 print(strnew)
 md55=hashlib.md5()
 md55.update(strnew.encode(encoding='utf-8'))
 strnew=md55.hexdigest( )
 if(_debugmode):
 print(strnew)
 str3=strnew[0:2]
 str3+="_"
 str3+=strnew[3:]
 strnew=str4
 strnew+="<>"
 strnew+=str3
 if(_debugmode):
 print(strnew)
 #再次生成MD5加密口令
 md55=hashlib.md5()
 md55.update(strnew.encode(encoding='utf-8'))
 strnew=md55.hexdigest( )
 str3=strnew[0:2]
 str3+="_"
 str3+=strnew[3:]
 if(_debugmode):
 print(str3)
 _sglobalpass=str3
 #完成第三方登录口令的制作 可以防止破解
 
 
 #
 
 str3="HTTP 0"
 try:
 str4=_ftp.sendcmd(str3)
 except (socket.error, socket.gaierror):
 return 0
 except ftplib.error_perm:
 return 1
 except :
 return 0
 
 #对str4 进行分解 提取http端口号
 # 返回 200 端口号 无用的0
 if(_debugmode):
 print(str4)
 arr5=[]
 arr5=str4.split(' ')
 if(len(arr5)>=2):
 _httpport=int(arr5[1],10)
 else:
 _httpport=0
 #完成分解操作 无论用户是否钩选优先使用Http 都会执行一次 我是简化代码 
							当然如果你有兴趣可以加入判断来减少执行
 #
 
 #如果成功设置了简化模式输出 那么就返回成功 虽然我们有更多的方法来验证服务器是XFile服务器
 # 但是用这个指令的方法更简单
 # 将来如果有需要 可以将口令采用加盐Hash方式进行验证 这样更不容易被破解
 #
 if(_debugmode):
 print("Success get http number="+str(_httpport))
 
 return 1
 
 def FuncChangeButton(self):
 global _mbcon
 global _chineseversion
 if(_mbcon):
 if(_chineseversion):
 self.m_buttonLogin.SetLabelText("连接")
 else:
 self.m_buttonLogin.SetLabelText("Connect")
 self.m_listCtrlFtp.DeleteAllItems( )
 self.m_staticinfo.SetLabelText("/")
 self.m_buttonSearch.Disable( )
 self.m_textsearch.Disable( )
 self.m_textCtrlPassword.Enable( )
 self.m_textCtrlPort.Enable( )
 self.m_textCtrlServer.Enable( )
 self.m_textCtrlUsername.Enable( )
 self.m_checkBoxSsl.Enable( )
 self.m_checkBoxHttp.Enable( )
 
 else:
 if(_chineseversion):
 self.m_buttonLogin.SetLabelText("中断")
 else:
 self.m_buttonLogin.SetLabelText("Disconnect")
 self.m_buttonSearch.Enable( )
 self.m_textsearch.Enable( )
 self.m_textCtrlPassword.Disable( )
 self.m_textCtrlPort.Disable( )
 self.m_textCtrlServer.Disable( )
 self.m_textCtrlUsername.Disable( )
 self.m_checkBoxSsl.Disable( )
 self.m_checkBoxHttp.Disable( )
 
 
 def OnMyButtonClick( self, event ):
 global _mbcon
 global _ftp
 global _ftps
 global _debugmode
 global _mbssl
 global _srandomcode
 str7=""
 
 
 if(_mbcon):
 #load player file again
 self.FuncLoadConfigFile()
 #connect the server
 strserver=self.m_textCtrlServer.GetLineText(0)
 strusername=self.m_textCtrlUsername.GetLineText(0)
 strpassword=self.m_textCtrlPassword.GetLineText(0)
 iportnum=int(self.m_textCtrlPort.GetLineText(0))
 if(_debugmode):
 print(strserver)
 print(strusername)
 print(strpassword)
 print("portnum="+str(iportnum))
 if(self.m_checkBoxSsl.GetValue()):
 if(_debugmode):
 print("Now will in TLS-SSL connection mode")
 _mbssl=True
 _ftps.encoding='utf-8'
 else:
 if(_debugmode):
 print("Now will in Standard connection mode")
 _mbssl=False
 _ftp.encoding='utf-8'
 if(len(strserver)<=0 or len(strusername)<=0 or 
							len(strpassword)<=0 or iportnum<=0 or 
							iportnum>=65535):
 #pop dialog , parameters error
 dlg=wx.MessageDialog(self,"Bad parameters 
							found","Error",wx.OK | wx.ICON_INFORMATION)
 dlg.ShowModal( )
 dlg.Destroy( )
 return
 else:
 if(_debugmode):
 print("Debug: now will try to connect remote 
							server")
 if(_mbssl):
 try:
 str7=_ftps.connect(host=strserver,port=iportnum,timeout=23)
 except (socket.error, socket.gaierror):
 dlg=wx.MessageDialog(self,"Failed to connect server 
							with ftp ssl","Error",wx.OK | wx.ICON_INFORMATION)
 dlg.ShowModal( )
 dlg.Destroy( )
 return
 except:
 dlg=wx.MessageDialog(self,"Failed to connect server 
							with ftp ssl 2","Error",wx.OK | wx.ICON_INFORMATION)
 dlg.ShowModal( )
 dlg.Destroy( )
 return
 if(_debugmode):
 print(str7)
 if(self.FuncGetRandomCode()==False):
 dlg=wx.MessageDialog(self,"Bad server type, only 
							support XFile(www.phoenixp2p.com)","Error",wx.OK | 
							wx.ICON_INFORMATION)
 dlg.ShowModal( )
 dlg.Destroy( )
 return
 #这里添加转换 因为明文不安全 这里转换成md5模式的口令
 # 注意 这是XFile服务器才支持的格式 普通FTP服务器是不支持的
 
 strpassword=_srandomcode+strpassword
 if(_debugmode):
 print(strpassword)
 
 #生成MD5加密口令
 mhash=hashlib.md5(strpassword.encode(encoding='UTF-8'))
 str7=mhash.hexdigest()
 
 if(_debugmode):
 print(str7)
 strpassword="__"+str7
 try:
 _ftps.login(strusername,strpassword)
 except ftplib.error_perm:
 _ftps.close()
 dlg=wx.MessageDialog(self,"Failed to login server, 
							check your username and password","Error",wx.OK | 
							wx.ICON_INFORMATION)
 dlg.ShowModal( )
 dlg.Destroy( )
 return
 except:
 _ftps.close( )
 dlg=wx.MessageDialog(self,"Failed to login server, 
							check your username and password 2","Error",wx.OK | 
							wx.ICON_INFORMATION)
 dlg.ShowModal()
 dlg.Destroy( )
 
 return
 #现在可以保证已经登录到服务器了 那么尝试获取列表吧 是否加密呢 这是个问题
 #乱用SSL会导致性能问题
 #注意上面不能用quit 因为quit遇到特殊的服务器回答 会引发投递异常
 
 
 else:
 try:
 str7=_ftp.connect(host=strserver,port=iportnum,timeout=15)
 except (socket.error, socket.gaierror):
 dlg=wx.MessageDialog(self,"Failed to connect server 
							with ftp","Error",wx.OK | wx.ICON_INFORMATION)
 dlg.ShowModal()
 dlg.Destroy( )
 return
 except:
 dlg=wx.MessageDialog(self,"Failed to connect server 
							with ftp 2","Error",wx.OK | wx.ICON_INFORMATION)
 dlg.ShowModal( )
 dlg.Destroy( )
 return
 if(_debugmode):
 print(str7)
 if(self.FuncGetRandomCode()==False):
 dlg=wx.MessageDialog(self,"Bad server type, only 
							support XFile(www.phoenixp2p.com)","Error",wx.OK | 
							wx.ICON_INFORMATION)
 dlg.ShowModal( )
 dlg.Destroy( )
 return
 
 strpassword=_srandomcode+strpassword
 if(_debugmode):
 print(strpassword)
 
 #生成MD5加密口令
 mhash=hashlib.md5(strpassword.encode(encoding='UTF-8'))
 str7=mhash.hexdigest()
 
 
 if(_debugmode):
 print(str7)
 
 strpassword="__"+str7
 
 try:
 _ftp.login(strusername,strpassword)
 except ftplib.error_perm:
 _ftp.close()
 dlg=wx.MessageDialog(self,"Failed to login server, 
							check your username and password","Error",wx.OK | 
							wx.ICON_INFORMATION)
 dlg.ShowModal( )
 dlg.Destroy()
 return
 except (socket.error, socket.gaierror):
 _ftp.close()
 dlg=wx.MessageDialog(self,"Disconnected by 
							server","Error",wx.OK | wx.ICON_INFORMATION)
 dlg.ShowModal()
 dlg.Destroy()
 return
 except:
 _ftp.close()
 dlg=wx.MessageDialog(self,"Disconnected by server 
							2","Error",wx.OK | wx.ICON_INFORMATION)
 dlg.ShowModal( )
 dlg.Destroy( )
 return
 if(self.FunXFileExtend( )==0):
 dlg=wx.MessageDialog(self,"Server does not support 
							XFILE command","Error",wx.OK | wx.ICON_INFORMATION)
 dlg.ShowModal()
 dlg.Destroy()
 if(_mbssl):
 try:
 _ftps.close()
 except (socket.error, socket.gaierror):
 return
 except:
 return
 
 
 else:
 try:
 _ftp.close( )
 except (socket.error, socket.gaierror):
 return
 except:
 return
 
 return
 #直接失败 返回吧 事实上上面的close也可能抛出异常 因为概率太小 我直接忽略了
 #如果成功了 那么调用列表函数进行刷新操作吧
 # 并修改当前目录
 #连接成功
 _mbcon=False
 self.FuncGetList( )
 
 if(_mbcon==False):
 #self.timer1.SetOwner(None,8801)
 self.timer1.Start(10000)
 #每10秒触发一次
 
 #连接成功
 #_mbcon=False
 self.FuncChangeButton( )
 else:
 if(_mbssl):
 try:
 _ftps.close( )
 except (socket.error, socket.gaierror):
 pass
 except:
 pass
 else:
 try:
 _ftp.close( )
 except (socket.error, socket.gaierror):
 pass
 except:
 pass
 self.timer1.Stop()
 _mbcon=True
 self.FuncChangeButton( )
 
 #关闭定时器
 event.Skip()
 
 def OnMyListColClick( self, event ):
 event.Skip()
 
 def OnMyListItemActivated( self, event ):
 global _debugmode
 global _mbcon
 global _mbssl
 global _ftp
 global _ftps
 global _httpport
 global _curworkdir
 global _playercmd
 global _sglobalpass
 if(_debugmode):
 print("List item actived called")
 itnum=self.m_listCtrlFtp.GetFirstSelected( )
 if(itnum==-1):
 return
 if(_mbcon):
 return
 if(itnum==0):
 #返回上级目录
 #
 self.OnPopupRoot(event)
 return
 else:
 #注意 有可能是检索得到的结果
 # 也就是带目录的完整结果
 str1=self.m_listCtrlFtp.GetItemText(itnum,3)
 str2=self.m_listCtrlFtp.GetItemText(itnum,1)
 if(_debugmode):
 print(str1)
 print(str2)
 if(len(str2)<1):
 return
 if(len(str1)<=0):
 return
 #根据目录或者文件分别处理
 if(str2=="File" or str2=="文件"):
 #这是文件
 if(_debugmode):
 print("Found it is file or 文件")
 if(str1.find("/")>=0):
 #这是完整的带目录文件
 if(_debugmode):
 print("Found file is abs dir + file")
 pass
 else:
 #这是普通的文件
 # 需要添加当前目录
 str1=_curworkdir+"/"+str1
 #然后根据os 分别处理播放
 # 是否支持http映射呢 这以后进行扩展吧 注意http 也有可能是tls/ssl
 #///////这里先注销掉http 流播放模式
 ##if(self.m_checkBoxHttp.IsChecked() and 
							_httpport!=0):
 #如果是http模式
 #
 ##else:
 #按标准FTP进行播放
 if(_debugmode):
 print(str1)
 if(True):
 
 strurl="ftp://"
 
 strurl+=self.m_textCtrlUsername.GetLineText(0)
 strurl+=":"
 #strurl+=self.m_textCtrlPassword.GetLineText(0)
 strurl+=_sglobalpass
 strurl+="@"
 strserver=self.m_textCtrlServer.GetLineText(0)
 if(strserver.find(':')>=0 and 
							strserver.find('[')<0):
 #如果是ipv6地址 并且简单的判断没有加入[]
 strserver='['+strserver
 strserver+=']'
 
 #如果端口号不是21 应该加上端口号
 strurl+=strserver
 #加入服务器地址
 #请注意 ipv6地址加入端口号,在某些移动平台的播放器,会解析失败 
							不过原因是那些播放器软件本身解析的问题
 strurl+=":"
 strurl+=self.m_textCtrlPort.GetLineText(0)
 strurl+=str1
 #由于windows 目录文件可能有空格 这里使用双引号
 #strurl='"'+strurl
 #strurl+='"'
 
 #到这里完成了完整的ftp url 构成
 if(_debugmode):
 print(strurl)
 #根据os的不同进行调用吧
 #mpv 有py_mpv , 可以直接在python里非常简单的调用播放器
 #但是由于升级很频繁 我们还是建议你调用外部播放器方式来实现
 #虽然
 if(os.name=='nt'):
 # 这是windows 操作系统
 #如果存在mpv 那么使用mpv 进行播放
 #如果存在vlc 那么使用vlc 进行播放
 str10=_playercmd
 str10=str10.replace('$url',strurl)
 if(_debugmode):
 print(str10)
 #os.system(str10)
 os.popen(str10)
 #if(_debugmode):
 #print()
 else:
 #按Linux进行处理 posix
 str10=_playercmd
 str10=str10.replace('$url',strurl,1)
 if(_debugmode):
 print(str10)
 #os.system(str10)
 os.popen(str10)
 
 else:
 #这是目录 注意可能是完整目录
 if(_debugmode):
 print("this is dir")
 #if(str1.find("/")>=0):
 # #这是绝对目录
 # pass
 #else:
 # #这是相对目录
 # # 调用切换目录函数
 # pass
 if(self.FuncChangeDir(str1)==False):
 self.FuncDisconnect( )
 else:
 if(self.FuncGetWorkDir( )==False):
 self.FuncDisconnect( )
 if(_debugmode):
 print("change dir done")
 
 #event.Skip()
 
 def FuncGetWorkDir(self):
 global _mbssl
 global _ftp
 global _ftps
 global _curworkdir
 global _debugmode
 global _timersec
 strres=""
 _timersec=0
 if(_debugmode):
 print("FuncGetWorkDir funciton is called")
 if(_mbssl):
 try:
 strres=_ftps.sendcmd("PWD")
 except (socket.error, socket.gaierror):
 return False
 except ftplib.error_perm:
 return False
 except:
 return False
 else:
 try:
 strres=_ftp.sendcmd("PWD")
 except (socket.error, socket.gaierror):
 return False
 except ftplib.error_perm:
 return False
 except:
 return False
 #分解服务器应答
 #
 #
 #需要提取出"""内容
 if(_debugmode):
 print(strres)
 print("Now will change work dir")
 arr6=[]
 arr6=strres.split('"')
 if(len(arr6)<3):
 return False
 _curworkdir=arr6[1]
 if(_debugmode):
 print(_curworkdir)
 print("Success get cur workdir")
 self.m_staticinfo.SetLabelText(_curworkdir)
 return True
 
 def FuncDisconnect(self):
 #中断连接
 global _ftp
 global _ftps
 global _mbcon
 global _mbssl
 if(_mbcon):
 return
 if(_mbssl):
 try:
 _ftps.close( )
 except:
 pass
 else:
 try:
 _ftp.close( )
 except:
 pass
 _mbcon=True
 self.m_listCtrlFtp.DeleteAllItems( )
 self.m_staticinfo.SetLabelText("/")
 self.timer1.Stop( )
 self.FuncChangeButton( )
 
 
 
 
 
 
 def FuncChangeDir(self,sdir):
 #切换目录 同时已经刷新了列表
 global _ftp
 global _ftps
 global _mbssl
 global _curworkdir
 if(len(sdir)<=0):
 sdir="/"
 scmd="CWD "
 scmd+=sdir
 bsucc=True
 #切换目录
 if(_mbssl):
 #ssl
 try:
 _ftps.sendcmd(scmd)
 except (socket.error, socket.gaierror):
 #_ftps.close( )
 return False
 except ftplib.error_perm:
 bsucc=False
 
 else:
 try:
 _ftp.sendcmd(scmd)
 except (socket.error, socket.gaierror):
 #_ftp.close( )
 return False
 except ftplib.error_perm:
 bsucc=False
 #可能目录切换失败 那么切换到根目录吧
 if(bsucc==False):
 sdir="/"
 scmd="CWD /"
 if(_mbssl):
 try:
 _ftps.sendcmd(scmd)
 except (socket.error, socket.gaierror):
 #_ftps.close( )
 return False
 except ftplib.error_perm:
 #_ftps.close( )
 return False
 else:
 try:
 _ftp.sendcmd(scmd)
 except (socket.error, socket.gaierror):
 #_ftps.close( )
 return False
 except ftplib.error_perm:
 #_ftps.close( )
 return False
 #现在可以保证已经成功了 那么执行列表操作吧
 #
 if(self.FuncGetList( )==0):
 return False
 #_curworkdir=sdir
 #self.m_staticinfo.SetLabelText(sdir)
 return True
 #完成操作
 
 
 
 def OnMyRightClick(self, event):
 global _chineseversion
 if not hasattr(self, "popupIDRoot"):
 self.popupIDRoot = wx.NewIdRef()
 self.popupIDUp = wx.NewIdRef()
 self.popupIDList = wx.NewIdRef()
 self.popupIDPlay = wx.NewIdRef()
 self.popupIDRefresh = wx.NewIdRef()
 self.Bind(wx.EVT_MENU, self.OnPopupRoot, 
							id=self.popupIDRoot)
 self.Bind(wx.EVT_MENU, self.OnPopupUp, 
							id=self.popupIDUp)
 self.Bind(wx.EVT_MENU, self.OnPopupRefresh, 
							id=self.popupIDRefresh)
 self.Bind(wx.EVT_MENU, self.OnPopupPlay, 
							id=self.popupIDPlay)
 self.Bind(wx.EVT_MENU, self.OnPopupList, 
							id=self.popupIDList)
 # pop menu
 menu = wx.Menu()
 # add some items
 if(_chineseversion):
 #如果是中文版本
 menu.Append(self.popupIDRoot, "根目录")
 menu.Append(self.popupIDUp, "上级目录")
 menu.Append(self.popupIDList, "列表")
 menu.Append(self.popupIDPlay, "播放")
 menu.Append(self.popupIDRefresh, "刷新")
 else:
 #英文版本
 menu.Append(self.popupIDRoot, "Root")
 menu.Append(self.popupIDUp, "Upgread")
 menu.Append(self.popupIDList, "List")
 menu.Append(self.popupIDPlay, "Play")
 menu.Append(self.popupIDRefresh, "Refresh")
 
 # Popup the menu. If an item is selected then its 
							handler
 # will be called before PopupMenu returns.
 self.PopupMenu(menu)
 menu.Destroy()
 
 def OnMyListItemRightClick( self, event ):
 #event.Skip( )
 global _debugmode
 if(_debugmode):
 print("OnMyListItemRightClick function")
 event.Skip( )
 
 def OnPopupRoot(self, event):
 #event.Skip( )
 global _mbcon
 global _timersec
 if(_mbcon):
 return
 #修改定时器计数为0
 _timersec=0
 if(self.FuncChangeDir("/")==False):
 self.FuncDisconnect( )
 return
 else:
 if(self.FuncGetWorkDir()==False):
 self.FuncDisconnect()
 
 
 return
 
 def OnPopupUp(self, event):
 #event.Skip( )
 global _mbcon
 global _timersec
 if(_mbcon):
 return
 _timersec=0
 if(self.FuncChangeDir("..")==False):
 self.FuncDisconnect( )
 return
 
 
 
 def OnPopupList(self, event):
 #event.Skip( )
 global _mbcon
 global _timersec
 
 i3=self.m_listCtrlFtp.GetFirstSelected( )
 if(i3==-1):
 return
 if(_mbcon):
 return
 
 str22=self.m_listCtrlFtp.GetItemText(i3,1)
 if(str22=='File' or str22=='文件'):
 return
 _timersec=0
 self.OnMyListItemActivated(event)
 
 def OnPopupPlay(self, event):
 #event.Skip( )
 global _mbcon
 global _timersec
 
 i3=self.m_listCtrlFtp.GetFirstSelected( )
 if(i3==-1):
 return
 if(_mbcon):
 return
 str22=self.m_listCtrlFtp.GetItemText(i3,1)
 if(str22=='Dir' or str22=='目录'):
 return
 _timersec=0
 self.OnMyListItemActivated(event)
 
 def OnPopupRefresh(self, event):
 #event.Skip( )
 global _mbcon
 global _timersec
 if(_mbcon):
 return
 _timersec=0
 if(self.FuncGetList()==0):
 self.FuncDisconnect( )
 return
 
 def OnMyTimerMsg(self,event):
 global _mbcon
 global _debugmode
 global _timersec
 if(_debugmode):
 print("OnTimer msg")
 if(_mbcon):
 #连接已经中断 那么直接断开吧 是否需要使用锁定?
 return
 _timersec+=1
 if(_timersec>=6):
 #发送Noop指令给服务器吧
 _timersec=0
 if(self.FuncSendRawCmd("NOOP")==False):
 self.FuncDisconnect( )
 
 event.Skip( )
 
 def FuncSendRawCmd(self,scmd):
 global _mbcon
 global _debugmode
 global _ftp
 global _ftps
 global _mbssl
 if(_debugmode):
 print("Found timer to send noop command now")
 if(len(scmd)<=0):
 scmd="NOOP"
 try:
 if(_mbssl):
 _ftps.sendcmd(scmd)
 else:
 _ftp.sendcmd(scmd)
 except (socket.error, socket.gaierror):
 return False
 except ftplib.error_perm:
 return True
 except :
 return False
 return True
 
 
 
 
 
 
 
 
 if __name__ == '__main__':
 # When this module is run (not imported) then create 
							the app, the
 # frame, show it, and start the event loop.
 app = wx.App()
 frm = MyFrameMain(None)
 frm.Show()
 app.MainLoop()
 
                                         | 
							  |