#! /usr/bin/env python
# -*- coding: utf-8 -*-
#-----------------------------------------------------------------------------
# Name: rufus.py
# Purpose:
#
# Author: Jeremy Arendt
#
# Created: 2004/28/01
# RCS-ID: $Id: rufus.py,v 1.27 2005/11/30 00:58:00 inigo Exp $
# Copyright: (c) 2002
# Licence: See G3.LICENCE.TXT
#-----------------------------------------------------------------------------
import os
import wx
import time
import sys
if sys.platform == "win32":
win32_flag = True
else:
win32_flag = False
if win32_flag:
from webbrowser import open_new
else:
from leoxv import open_new
if not win32_flag:
oldStd = sys.stdout
oldStderr = sys.stderr
sys.stdout = open((os.path.expanduser('~/.Rufus/rufus.log')), "w")
sys.stderr = open((os.path.expanduser('~/.Rufus/error.log')), "w")
import shutil #used in killtorrent
from threading import Event,Thread,Lock
from os.path import dirname,join,split,splitext,exists,abspath,normpath
from traceback import print_exc
from btconfig import BTConfig
from images import Images
from g3widgets import *
from masterlist import MasterList
from graphpanel import GraphPanel
from detailspanel import DetailsPanel
from statuspanel import StatusPanel
from msgpanel import MessagePanel
from friendspanel import FriendsPanel
from searchpanel import SearchPopup
from g3taskbar import G3TaskBar
from BitTorrent import version
import friend
from g3peerid import CreatePeerId
from peerlistcache import PeerListCache
from g3rpcserver import G3RPCServer
from BitTorrent.bencode import bencode,bdecode
from btsession import BTSession
from g3rss import RSSPanel
from BitTorrent.encodedata import encodefile
import encodings
import gettext
import os.path
try:
import cjkcodecs.aliases
except:
pass
try:
import iconv_codec
except:
pass
if win32_flag:
from os import startfile
from webbrowser import open_new
else:
from leoxv import startfile,open_new,echo_browser_test,unparseloadurl
debug_flag = False
prog_name = " Rufus"
prog_name_ver = prog_name + ' v' + version + ' '
wxEVT_INVOKE = wx.NewEventType()
EVT_INVOKE = wx.PyEventBinder(wxEVT_INVOKE, 0)
class InvokeEvent(wx.PyEvent):
def __init__(self, func, args, kwargs):
wx.PyEvent.__init__(self)
self.SetEventType(wxEVT_INVOKE)
self.func = func
self.args = args
self.kwargs = kwargs
class RebaDropTarget(wx.FileDropTarget):
def __init__(self, window):
wx.FileDropTarget.__init__(self)
self.reba = window
def OnDropFiles(self, x, y, filenames):
for file in filenames:
self.reba.AddFromFile(file)
class Reba(wx.Frame, G3TaskBar):
def __init__(self, path, params):
wx.Frame.__init__(self, None, -1, prog_name_ver, size = wx.Size(666,480),
style = wx.DEFAULT_FRAME_STYLE)
G3TaskBar.__init__(self)
self.btsessions = []
self.sess_sort = {}
self.prgdlgs = {}
self.btsessions_lock = Lock()
self.uiflag = Event()
self.doneflag = Event()
self.last_update_time = 0
self.btconfig = BTConfig(path)
self.btconfig.LoadOptions()
self.cfg_visflag = Event()
self.srch_visflag = Event()
self.path = path
self.total_urate = 0
self.total_drate = 0
self.stotal = 0
self.ptotal = 0
self.showing_error = False
self.last_taskbar_update = 0
self.update_notified = False
# sets a minimum size for Rufus
self.SetMinSize((500,375))
self.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_MENU))
self.last_gui_update = 0
self.last_urate_throttle = 0
self.last_connect_friends = 0
self.last_broadcast = 0
self.last_tdirscan = 0
# initial GUI language is setup here
lang_pref = self.btconfig.Get('lang_pref')
gettext.install('rufus', './locale', unicode=True)
gettext.translation("rufus", './locale', languages=[lang_pref], fallback=True).install()
pos = self.btconfig.Get('clientpos')
size = self.btconfig.Get('clientsize')
if pos[0] > 0 and pos[1] > 0:
self.SetPosition(pos)
if size[0] > 100 and size[1] > 100:
self.SetSize(size)
if self.btconfig.Get('maximized'):
self.Maximize(True)
self.images = Images(path)
self.pl_dnsloop = PeerListCache(self.doneflag)
self.friends = friend.FriendList(self.btconfig)
self.friends.Load()
self.peer_id = CreatePeerId(self.btconfig.Get("nickname"))
##sets permenant taskbar icon
if win32_flag and self.btconfig.Get('fixedtrayicon'):
self.tbicon.SetIcon(self.images.GetImage('rufus.ico'))
wx.EVT_TASKBAR_LEFT_DCLICK(self.tbicon, self.OnTaskBarActivate)
wx.EVT_TASKBAR_RIGHT_DOWN(self.tbicon, self.OnTaskBarPopup)
# Set frame as drop target to accept files dropped from explorer, and url text
dt = RebaDropTarget(self)
self.SetDropTarget(dt)
try:
if self.btconfig['cust_title']:
self.SetTitle(prog_name_ver+self.btconfig['cust_title'])
except:
pass
# Tool Bar
self.MakeToolBar()
# Status Bar
self.statusbar = StatusBar_wImages(self, self.images)
self.SetStatusBar(self.statusbar)
# splitter window
splitter = wx.SplitterWindow(self, -1, style=wx.SP_NOBORDER)
splitter.SetMinimumPaneSize(120) # min size to avoid splitter loss
self.splitter = splitter
# Master List
self.list = MasterList(splitter,
self.UpdateGUI,
self.ResumeSelected,
self.PauseSelected,
self.StopSelected,
self.KillSelected,
self.MoveSessionUp,
self.MoveSessionDown,
self.CmdAnnounce,
self.ShowTorrentDlg,
self.DLOrderCatcher,
self.OpenFolderSelected,
self.TrackerMngr,
self.OnSelectInMasterList,
self.ChangeSessionCfg,
self.ScanOnDemand,
self.btconfig, bmps = self.images)
# Notebook
self.notebook = NoteBook(splitter, self.images, self.UpdateGUI, "MainNotebook", self.btconfig)
# Panels used in the notebook
self.status = StatusPanel(self.notebook, self.btconfig, self.images,
self.FriendCatcher, self.OnClickColInPeerlist, self.pl_dnsloop.GetPeerInfo)
self.details = DetailsPanel(self.notebook, self.btconfig, self.images)
self.graph = GraphPanel(self.notebook, self.btconfig, self.images)
self.friendsCtrl = FriendsPanel(self.notebook, self.btconfig,
self.friends, self.images)
self.msgpanel = MessagePanel(self.notebook, self.btconfig)
self.rsspanel = RSSPanel(self.notebook, self.btconfig, addfunc=self.AddFromURL)
self.notebook.Populate(self.status, self.details, self.graph,
self.friendsCtrl, self.msgpanel, self.rsspanel, self.statusbar)
# Set splitter
self.splitpos = self.btconfig.Get('splitterpos')
if self.btconfig.Get("splitter_style") == 0:
splitter.SplitHorizontally(self.list, self.notebook, self.splitpos)
else:
splitter.SplitVertically(self.list, self.notebook, self.splitpos)
if not self.btconfig['show_pane2']:
splitter.Unsplit(self.notebook)
wx.EVT_SPLITTER_DCLICK(self, -1, self.OnToggleSplitter)
border = wx.BoxSizer(wx.VERTICAL)
border.Add(self.toolbar, 0, wx.EXPAND|wx.BOTTOM, 3)
border.Add(splitter, 1, wx.EXPAND|wx.ALL)
self.SetSizer(border)
# Menu Bar
menuBar = wx.MenuBar()
menu1 = wx.Menu()
menu1.Append(201, _("&Add Torrent\tCtrl+O"), _("Open/Add torrent file"))
menu1.Append(210, _("Add Torrent (No &default save)\tCtrl+*"), _("Open/Add torrent file (No default save)"))
menu1.Append(214, _("Open Torrent For Seeding"), _("Open Torrent For Seeding"))
menu1.Append(202, _("Add Torrent From &URL\tIns"), _("Open/Add torrent file from url"))
menu1.AppendSeparator()
menu1.Append(211, _("&Create New Torrent\tCtrl+N"), _("Create New .torrent file"))
menu1.AppendSeparator()
menu1.Append(204, _("&Q&uit\tCtrl+Q"), _("I was afraid to go on..."))
menuBar.Append(menu1, _("&File"))
menu1 = wx.Menu()
menu1.Append(215, _("Stop Torrent(s)"), _("Stop selected torrent(s)"))
menu1.Append(216, _("Resume Torrent(s)"), _("Resume selected torrent(s)"))
menu1.AppendSeparator()
menu1.Append(217, _("Stop All"), _("Stop all torrents"))
menu1.Append(218, _("Resume All"), _("Resume all torrents"))
menu1.AppendSeparator()
menu1.Append(203, _("&Remove Torrent(s)\tCtrl+Del"), _("Remove selected torrent(s)"))
menuBar.Append(menu1, _("&Torrents"))
menu1 = wx.Menu()
menu1.Append(205, _("&Preferences\tCtrl+P"), _("Global Preferences"), False)
menu1.AppendSeparator()
menu1.Append(213, _("Toggle Tool&bar\tCtrl+B"), _("Show/Hide Toolbar"), True)
menu1.Append(212, _("&Toggle Tab Panel\tCtrl+T"), _("Show/Hide Panel 2: The hiding of Tab Panel"), True)
menu1.Append(209, _("Toggle &Splitter\tCtrl+S"), _("Toggle splitter"), True)
menu1.Append(206, _("&Error Popups"), _("Toggle warning messages"), True)
if self.btconfig.Get('popup_errors'):
menu1.Check(206, True)
if self.btconfig.Get('toggle_toolbar'):
menu1.Check(213, True)
if not self.btconfig.Get('show_pane2'):
menu1.Check(212, True)
menuBar.Append(menu1, _("&Options"))
self.options_menu = menu1
# complex language menu setup craziness... can probably be simplified
menu1 = wx.Menu()
self.lang = self.btconfig.GetLang()
lang_id = 400 #has to be a known value for use in self.SetLanguage
self.lang_codes = []
for i, j in self.lang.items():
menu1.Append(lang_id, j , _("Use %s for the GUI")%j, wx.ITEM_RADIO)
if self.btconfig.Get('lang_pref') == i:
menu1.Check(lang_id, True)
self.lang_codes.append(i)
wx.EVT_MENU(self, lang_id, self.SetLanguage)
lang_id = lang_id + 1
menuBar.Append(menu1, _("&Language"))
menu1 = wx.Menu()
menu1.Append(207, _("A&bout\tCtrl+A"), _("About"))
menu1.Append(208, _("Project &Homepage\tCtrl+H"), _("Project Homepage"))
menuBar.Append(menu1, _("&Help"))
self.SetMenuBar(menuBar)
wx.EVT_MENU(self, 201, self.NewTorrent_File)
wx.EVT_MENU(self, 210, self.NewTorrent_File)
wx.EVT_MENU(self, 214, self.NewTorrent_File)
wx.EVT_MENU(self, 202, self.NewTorrent_URL)
wx.EVT_MENU(self, 211, self.CreateTorrent)
wx.EVT_MENU(self, 204, self.OnClose)
wx.EVT_MENU(self, 205, self.OnPreferences)
wx.EVT_MENU(self, 209, self.OnToggleSplitter)
wx.EVT_MENU(self, 206, self.OnErrorPopupToggle)
wx.EVT_MENU(self, 207, self.OnAbout)
wx.EVT_MENU(self, 208, self.OnOpenHomePage)
wx.EVT_MENU(self, 212, self.OnToggleNotebook)
wx.EVT_MENU(self, 213, self.OnToggleToolbar)
wx.EVT_MENU(self, 215, self.StopSelected)
wx.EVT_MENU(self, 216, self.ResumeSelected)
wx.EVT_MENU(self, 217, self.StopAllFunc)
wx.EVT_MENU(self, 218, self.ResumeAllFunc)
wx.EVT_MENU(self, 203, self.KillSelected)
wx.EVT_SIZE(self, self.OnReSize)
wx.EVT_CLOSE(self, self.OnClose)
EVT_INVOKE(self, self.OnInvoke)
#wx.EVT_IDLE(self, self.OnIdle)
self.SetIcon(self.images.GetImage('rufus.ico'))
self.Show(True)
self.OnInit()
if self.btconfig.Get('ud_on_start'):
self.version_check()
try:
self.LoadWorkState()
if len(params) > 0:
self.AddFromFile(params[0])
except:
# send message here about error during startup
pass
def SetLanguage(self, event):
self.btconfig.Set('lang_pref', self.lang_codes[event.GetId()-400])
dlg = wx.MessageDialog(self, _("You will need to restart for the\nlanguage changes to take effect"),
_("Don't Panic!"), wx.OK | wx.ICON_INFORMATION)
dlg.ShowModal()
dlg.Destroy()
def MakeToolBar(self):
toolbar = wx.ToolBar(self, style=wx.TB_HORIZONTAL|wx.NO_BORDER|wx.TB_FLAT|wx.TB_TEXT)
self.toolbar = toolbar
toolbar.SetToolBitmapSize((24,24))
toolbar.AddTool(101, self.images.GetImage('btfile24.png'), wx.NullBitmap, False, "", _("Add From *.torrent"), _("Add new torrent from file"))
toolbar.AddTool(102, self.images.GetImage('bturl24.png'), wx.NullBitmap, False, "", _("Add From URL"), _("Add new torrent from url"))
toolbar.AddTool(111, self.images.GetImage('new24.png'), wx.NullBitmap, False, "", _("Create New Torrent"), _("Create New Torrent"))
toolbar.AddSeparator()
toolbar.AddTool(103, self.images.GetImage('remove24.png'), wx.NullBitmap, False, "", _("Remove"), _("Remove selected torrent"))
toolbar.AddTool(104, self.images.GetImage('resume24.png'), wx.NullBitmap, False, "", _("Resume/Start"), _("Resume/Start torrent"))
self.resumeall_butt = wx.BitmapButton(toolbar, -1, self.images.GetImage('smalldarrow.png'),style=wx.NO_BORDER, size=(8,-1))
toolbar.AddControl(self.resumeall_butt)
toolbar.AddTool(105, self.images.GetImage('pause24.png'), wx.NullBitmap, False, "", _("Pause/Requeue"), _("Pause/Requeue torrent"))
toolbar.AddTool(110, self.images.GetImage('stop24.png'), wx.NullBitmap, False, "", _("Stop"), _("Stop this torrent"))
self.stopall_butt = wx.BitmapButton(toolbar, -1, self.images.GetImage('smalldarrow.png'),style=wx.NO_BORDER, size=(8,-1))
toolbar.AddControl(self.stopall_butt)
toolbar.AddSeparator()
toolbar.AddTool(106, self.images.GetImage('upqueue24.png'), wx.NullBitmap, False, "", _("Move up in queue"), _("Move up in queue"))
toolbar.AddTool(107, self.images.GetImage('downqueue24.png'), wx.NullBitmap, False, "", _("Move down in queue"), _("Move down in queue"))
toolbar.AddSeparator()
toolbar.AddTool(112, self.images.GetImage('folder24.png'), wx.NullBitmap, False, "", _("Incoming Folder"), _("Incoming Folder"))
toolbar.AddSeparator()
toolbar.AddTool(108, self.images.GetImage('config24.png'), wx.NullBitmap, False, "", _("Preferences"), _("Preferences"))
toolbar.AddTool(109, self.images.GetImage('toggle24.png'), wx.NullBitmap, True, "", _("Toggle Splitter"), _("Toggle Splitter"))
toolbar.AddTool(113, self.images.GetImage('tab24.png'), wx.NullBitmap, False, "", _("Toggle Tab Panel"), _("Toggle Tab Panel"))
toolbar.AddSeparator()
toolbar.AddTool(114, self.images.GetImage('search24.png'), wx.NullBitmap, False, "", _("Torrent Search"), _("Search the web for a new torrent"))
if self.btconfig.Get('cust_img'):
cust_image = wx.Bitmap(join(self.path, normpath("images/%s" % self.btconfig.Get('cust_img'))))
#this is a spacer for the toolbar - needs to be long or errors in graphics can occur
self.tbspacer = wx.StaticBitmap(toolbar, -1, wx.NullBitmap, size=(500, -1))
toolbar.AddControl(self.tbspacer)
self.tblogo = wx.BitmapButton(toolbar, -1, cust_image, style=wx.SUNKEN_BORDER|wx.STATIC_BORDER|wx.NO_3D)
self.tblogo.SetCursor(wx.StockCursor(wx.CURSOR_HAND))
wx.EVT_COMMAND_LEFT_CLICK(self.tblogo, -1, self.CustURL) # wxMSW
wx.EVT_LEFT_UP(self.tblogo, self.CustURL) # wxGTK
toolbar.AddControl(self.tblogo)
wx.EVT_TOOL(self, 101, self.NewTorrent_File)
wx.EVT_TOOL(self, 102, self.NewTorrent_URL)
wx.EVT_TOOL(self, 111, self.CreateTorrent)
wx.EVT_TOOL(self, 103, self.KillSelected)
wx.EVT_TOOL(self, 104, self.ResumeSelected)
wx.EVT_TOOL(self, 105, self.PauseSelected)
wx.EVT_TOOL(self, 110, self.StopSelected)
wx.EVT_TOOL(self, 106, self.OnQueueUp)
wx.EVT_TOOL(self, 107, self.OnQueueDown)
wx.EVT_TOOL(self, 112, self.OpenIncomingFolder)
wx.EVT_TOOL(self, 108, self.OnPreferences)
wx.EVT_TOOL(self, 109, self.OnToggleSplitter)
wx.EVT_TOOL(self, 113, self.OnToggleNotebook)
wx.EVT_TOOL(self, 114, self.OnTorrentSearch)
wx.EVT_COMMAND_LEFT_CLICK(self.resumeall_butt, -1, self.OnResumeAll) # wxMSW
wx.EVT_LEFT_UP(self.resumeall_butt, self.OnResumeAll) # wxGTK
wx.EVT_COMMAND_LEFT_CLICK(self.stopall_butt, -1, self.OnStopAll) # wxMSW
wx.EVT_LEFT_UP(self.stopall_butt, self.OnStopAll) # wxGTK
toolbar.Realize()
def OnTorrentSearch(self, event):
if not self.srch_visflag.isSet():
popup = SearchPopup(self, self.btconfig, self.images, self.srch_visflag)
def CustURL (self, event):
if self.btconfig.Get('cust_home'):
Thread(target = self._OpenUrl, args = [self.btconfig.Get('cust_home')]).start()
event.Skip()
def _OpenUrl(self, url):
try:
open_new(url)
except:
pass
def OnToggleSplitter(self, event):
if self.splitter.GetSplitMode() == wx.SPLIT_HORIZONTAL:
self.splitter.SetSplitMode(wx.SPLIT_VERTICAL)
self.btconfig.Set('splitter_style', 1)
else:
self.splitter.SetSplitMode(wx.SPLIT_HORIZONTAL)
self.btconfig.Set('splitter_style', 0)
self.SetSize((self.GetSize()[0]+1, self.GetSize()[1]))
self.SetSize((self.GetSize()[0]-1, self.GetSize()[1]))
self.splitter.SetSashPosition(self.splitter.GetMinimumPaneSize()) #fullscreen splittertoggle bug fix
def Test(self, event):
print "test..."
def AntiFlicker(self, event):
pass
def OnUpdateUI(self, event):
print "updateui", time.time()
def OnToggleNotebook(self, event):
if self.notebook.IsShown():
self.splitter.Unsplit(self.notebook)
self.splitpos = self.splitter.GetSashPosition()
self.options_menu.Check(212, True)
self.btconfig['show_pane2'] = False
else:
self.notebook.Show(True)
if self.btconfig.Get("splitter_style") == 0:
self.splitter.SplitHorizontally(self.list, self.notebook, self.splitpos)
else:
self.splitter.SplitVertically(self.list, self.notebook, self.splitpos)
self.options_menu.Check(212, False)
self.btconfig['show_pane2'] = True
def OnToggleToolbar(self, event):
if self.toolbar.IsShown():
self.GetSizer().Hide(self.toolbar)
self.Layout()
self.btconfig.Set("toggle_toolbar", True)
else:
self.GetSizer().Show(self.toolbar)
self.Layout()
self.btconfig.Set("toggle_toolbar", False)
def OnAbout(self, event):
pos = self.ClientToScreen( (70,30) )
from optiondlg import About_Box
a = About_Box(self, self.btconfig, self.images, pos )
#self.notebook.SetSelection(5)
def OnOpenHomePage(self, event):
open_new("http://rufus.sourceforge.net/")
def OnErrorPopupToggle(self, event):
self.btconfig.Set('popup_errors', event.IsChecked())
self.SyncSessionOptions()
def ChangeSessionCfg(self, id, option_class):
""" Open DLG and change options for the session that matches this id """
if not self.cfg_visflag.isSet():
pos = self.ClientToScreen( (50,20) )
s = self.GetSession(id)
if s != None:
from optiondlg import SingleOption
option = SingleOption(self, pos, s.GetCfg(), option_class, self.images, self.cfg_visflag)
def OnPreferences(self, event):
""" Open preferences dialog """
if not self.cfg_visflag.isSet():
from optiondlg import Options
pos = self.ClientToScreen( (50,20) )
self.optionswin = Options(self, pos, self.btconfig, self.images,
self.cfg_visflag, syncfunc = self.SyncSessionOptions)
def OnReSize(self, event):
self.Layout()
if self.splitter.GetSashPosition() > 0:
self.splitter.SetSashPosition(self.splitter.GetSashPosition())
#does the layout for branding image on the right
if self.btconfig.Get('cust_img'):
slen = self.toolbar.GetSize()[0] - self.tblogo.GetSize()[0] - 3
if self.tbspacer.GetPosition()[0] < slen:
self.tblogo.SetPosition((slen,-1))
def OnInit(self):
# Threads ahoy
self.rpcserver = G3RPCServer(self.btconfig, self.AddStatMsg, self.FriendCatcher,
self.RemoteAddCatcher, self.btsessions, self.btsessions_lock, self.images)
self.rpcserver.Start()
self.mainloop = Thread(name="MainLoop", target = self.MainLoop)
self.mainloop.setDaemon(True)
self.mainloop.start()
self.pl_dnsloop.Start()
def OnStatMessage(self, name, msg, type=0):
self.msgpanel.AddMsg(name, msg, type)
self.statusbar.SetStatus(msg)
def OnError(self, sess_id, msg, type=-1, code=None):
if self.btconfig.Get('popup_errors') and not self.showing_error:
self.showing_error = True
dlg = wx.MessageDialog(self, message = msg,
caption = 'Download Error', style = wx.OK | wx.ICON_ERROR)
dlg.Fit()
dlg.Center()
dlg.ShowModal()
self.showing_error = False
dlg.Destroy()
trackerresponse = False
s = self.GetSession(sess_id)
if s != None and s.GetStaticData() != None:
filename = split(s.GetStaticData()['responsefile'])[1]
if code == 'tracker_response':
trackerresponse = True
if self.btconfig['dbg_tracker']:
self.msgpanel.AddMsg(filename, msg, type)
else:
self.msgpanel.AddMsg(filename, msg, type)
if code == 'tracker_bcool': # Tracker flunked. But the torrent is still going...
#Every body be cool! You, be cool!
pass
elif code == 'tracker_refuse': # Tracker refused announce attempt
s.error_count['tracker_refuse'] += 1
if 'blacklisted' in msg and s.error_count['tracker_refuse'] <= 2:
self.msgpanel.AddMsg(filename, "Reconfiguring settings to "
+ "use ports 50000-50099. Attempt #%d." % \
s.error_count['tracker_refuse'], type)
s.ChangePortRange(50000,50099)
elif s.error_count['tracker_refuse'] >= self.btconfig['max_trkrflunks']:
s.Stop()
self.msgpanel.AddMsg(filename, "Auto-Stopping this torrent. " \
"The tracker could not be contacted", type)
elif code == 'tracker_timeout': # Tracker announce Timed out
s.error_count['tracker_timeout'] += 1
if s.error_count['tracker_timeout'] >= self.btconfig['max_trkrflunks']:
s.error_count['tracker_timeout'] = 0
s.Pause()
self.msgpanel.AddMsg(filename, "Auto-Pausing this torrent. " \
"The tracker timed out after %d attempts" % \
s.error_count['tracker_timeout'], type)
elif code == 'tracker_404': # Could not connect to tracker
s.error_count['tracker_404'] += 1
if s.error_count['tracker_404'] >= self.btconfig['max_trkrflunks']:
self.msgpanel.AddMsg(filename, "Auto-Pausing this torrent. The tracker could not be contacted after %d attempts" % s.error_count['tracker_404'], type)
s.error_count['tracker_404'] = 0
s.Pause()
elif code == 'hash_flunked': # Hash flunked
try:
ip = msg.split(" ")[3]
if not s.error_count.has_key(ip):
s.error_count[ip] = 1
else:
s.error_count[ip] += 1
if s.error_count[ip] >= self.btconfig['max_hashflunks']:
self.FriendCatcher(ip, "Junker", friend.ADDFOETEMP, None)
s.ReChoke()
self.msgpanel.AddMsg(filename, "Temp banning %s. " \
"This peer sent %d invalid pieces." % \
(ip, s.error_count[ip]), type)
del s.error_count[ip]
except:
print_exc()
else:
rfilename = ''
if s != None and s.GetResponseFilename() != None:
rfilename = s.GetResponseFilename()
if code != None:
self.msgpanel.AddMsg(_("Error -")+rfilename, msg, code)
else:
self.msgpanel.AddMsg(_("Error -")+rfilename, msg, -2)
if not trackerresponse:
self.statusbar.SetStatus(_("An error has occured. Check message tab."))
def OnSessionUpdate(self, sess_id, d):
if d != None:
s = self.GetSession(sess_id)
if s != None:
s.SetStatusData(d)
def OnSessionStart(self, sess_id, d):
self.SaveWorkState()
if d != None:
s = self.GetSession(sess_id)
if s != None:
s.SetStaticData(d)
def OnInvoke(self, event):
if not self.uiflag.isSet() and not self.doneflag.isSet():
apply(event.func, event.args, event.kwargs)
def CmdAnnounce(self, id, url=None):
s = self.GetSession(id)
s.ReAnnounce(url)
def OnQueueUp(self, event=None):
try:
index = self.list.GetFirstSelected()
while index != -1:
id = self.list.GetItemData(index)
self.MoveSessionUp(id)
index = self.list.GetNextSelected(index)
self.UpdateGUI()
except:
print_exc()
def OnQueueDown(self, event=None):
try:
count = 0
index = self.list.GetFirstSelected()
while index != -1:
count +=1
index = self.list.GetNextSelected(index)
index = self.list.GetFirstSelected()
while index != -1:
id = self.list.GetItemData(index)
self.MoveSessionDown(id, count)
index = self.list.GetNextSelected(index)
self.UpdateGUI()
except:
print_exc()
def MoveSessionUp(self, id):
index = self.GetSessionIndex(id)
if index == None:
return
if index > 0:
session = self.btsessions.pop(index)
self.btsessions.insert(index-1, session)
def MoveSessionDown(self, id, nselected):
index = self.GetSessionIndex(id)
if index == None:
return
session = self.btsessions.pop(index)
self.btsessions.insert(index+nselected, session)
def MoveSessionToBack(self, id):
index = self.GetSessionIndex(id)
if index == None:
return
session = self.btsessions.pop(index)
self.btsessions.append(session)
def MoveSessionToFront(self, id):
index = self.GetSessionIndex(id)
if index == None:
return
session = self.btsessions.pop(index)
self.btsessions.insert(0, session)
def GetSessionIndex(self, id):
i = 0
for s in self.btsessions:
if s.GetId() == id:
return i
i += 1
return None
def InvokeLater(self, func, args = [], kwargs = {}):
if not self.uiflag.isSet() and not self.doneflag.isSet():
wx.PostEvent(self, InvokeEvent(func, args, kwargs))
def ScrapeCatcher(self, id, data):
def foo(self=self, id=id, data=data):
s = self.GetSession(id)
if s != None:
s.scrape_data = data
self.UpdateGUI()
self.InvokeLater(foo, [])
def FriendCatcher(self, ip, peerid, msgtype, data):
def foo(self=self):
self.friends.GotUpdate(ip, peerid, msgtype, data)
self.friendsCtrl.Update()
self.InvokeLater(foo, [])
def RemoteAddCatcher(self, params, referer="", type=0):
if type == 0:
if not self.btconfig.Get('tray_pass_enabled'):
self.OnTaskBarActivate()
self.InvokeLater(self.AddFromFile, [params])
elif type == 1:
if not self.btconfig.Get('show_add_URL') and not self.btconfig.Get('tray_pass_enabled'):
self.OnTaskBarActivate()
self.InvokeLater(self.AddFromURL, [params, referer])
def AddStatMsg(self, name, msg, type=0):
self.InvokeLater(self.OnStatMessage, [name, msg, type])
def ErrorCatcher(self, id, msg, code=None):
self.InvokeLater(self.OnError, [id, msg, -1, code])
def UpdateCatcher(self, id, d):
self.InvokeLater(self.OnSessionUpdate, [id, d])
def DNSCatcher(self, id, d):
self.InvokeLater(self.OnSessionUpdate, [id, d])
def StartCatcher(self, id, d):
self.InvokeLater(self.OnSessionStart, [id, d])
def DLOrderCatcher(self, id, manual=False):
self.InvokeLater(self.DLOrderMngrDlg, [id, manual])
# Alternative to the threaded MainLoop. Currently unused.
def OnIdle(self, event):
print 'on idle', time.time()
# UpdateGUI every 'gui_update_rate'
if self.last_gui_update + max(0.25, self.btconfig['gui_update_rate']) < time.time():
self.InvokeLater(self.UpdateGUI, [])
if not self.IsShown() and self.last_taskbar_update + 4 < time.time():
self.InvokeLater(self.UpdateIcon, [])
self.last_taskbar_update = time.time()
self.last_gui_update = time.time()
# Throttle urate every 1 sec
if self.last_urate_throttle + 1 < time.time():
self.InvokeLater(self.URateThrottle, [])
self.last_urate_throttle = time.time()
# ConnectFriends every 60 sec
if self.last_connect_friends + 60 < time.time():
self.InvokeLater(self.ConnectFriends, [])
self.last_connect_friends = time.time()
# Broadcast infohashes every 30 sec
if self.last_broadcast + 30 < time.time():
self.InvokeLater(self.Broadcast, [])
self.last_broadcast = time.time()
# Search torrent folder for new torrents every N mins
if self.btconfig['tdir_scan'] != 0 and self.btconfig['use_torrent_dir'] and self.btconfig['use_download_dir']:
if self.last_tdirscan + max(60, self.btconfig['tdir_scan']) < time.time():
self.InvokeLater(self.TorrentDirScan, [])
self.last_tdirscan = time.time()
def ScanOnDemand(self):
if self.btconfig['use_torrent_dir'] and self.btconfig['use_download_dir']:
self.InvokeLater(self.TorrentDirScan, [])
def MainLoop(self):
last_gui_update = 0
last_urate_throttle = 0
last_connect_friends = 0
last_broadcast = 0
last_tdirscan = 0
last_checked = time.time()
last_log = 0
while not self.doneflag.isSet():
# UpdateGUI every 'gui_update_rate'
if last_gui_update + max(0.25, self.btconfig['gui_update_rate']) < time.time():
if win32_flag:
self.InvokeLater(self.UpdateGUI, [])
if not self.IsShown() and self.last_taskbar_update + 4 < time.time():
self.InvokeLater(self.UpdateIcon, [])
self.last_taskbar_update = time.time()
else:
if not self.IsIconized(): # LeoXV
self.InvokeLater(self.UpdateGUI, [])
if self.IsIconized() and self.last_taskbar_update + 15 < time.time(): # LeoXV
self.InvokeLater(self.UpdateGUI, [])
self.InvokeLater(self.UpdateIcon, [])
self.last_taskbar_update = time.time()
last_gui_update = time.time()
# Throttle urate every 1 sec
if last_urate_throttle + 1 < time.time():
self.InvokeLater(self.URateThrottle, [])
last_urate_throttle = time.time()
# ConnectFriends every 60 sec
if last_connect_friends + 60 < time.time():
self.InvokeLater(self.ConnectFriends, [])
last_connect_friends = time.time()
# Broadcast infohashes every 30 sec
if last_broadcast + 30 < time.time():
self.InvokeLater(self.Broadcast, [])
last_broadcast = time.time()
# Search torrent folder for new torrents every N mins
if self.btconfig['tdir_scan'] != 0 and self.btconfig['use_torrent_dir'] and self.btconfig['use_download_dir']:
if last_tdirscan + max(60, self.btconfig['tdir_scan']) < time.time():
self.InvokeLater(self.TorrentDirScan, [])
last_tdirscan = time.time()
# Check for Rufus update every x hours
if self.btconfig['ud_hourly'] and not self.update_notified:
if last_checked + (self.btconfig['ud_rate'] * 3600) < time.time():
self.InvokeLater(self.version_check, [])
last_checked = time.time()
# Update log every x hours every 60 sec
if not win32_flag:
if last_log + 60 < time.time():
sys.stdout.flush()
sys.stderr.flush()
last_log = time.time()
self.doneflag.wait(0.2)
def TorrentDirScan(self):
torrentdir = self.btconfig['torrent_dir']
if not exists(torrentdir):
return
added_torrents = []
for s in self.btsessions:
if s.GetResponseFilename():
added_torrents.append( split(s.GetResponseFilename())[1] )
torrentfiles = os.listdir(torrentdir)
for torrent in torrentfiles:
responsefile = join(torrentdir, torrent)
if splitext(responsefile)[1] != ".torrent":
continue
try:
added_torrents.index(torrent)
except ValueError:
print 'Loading from file %s' % torrent
added_torrents.append(torrent)
self.AddFromFile(responsefile)
def ResetStatus(self, id):
self.status.peerlist.Reset()
self.status.pppgauge.SetValueUnknown()
def TrackerMngr(self, id):
s = self.GetSession(id)
if s != None and s.IsRunning():
from trackermngr import TrackerDlg
tmngr = TrackerDlg(self, id, self.btconfig, self.images,
s.download.SetAnnounceURLs, self.CmdAnnounce)
tmngr.Populate( s.download.GetAnnounceURLs() )
tmngr.Show()
def DLOrderMngrDlg(self, id, manual=False):
s = self.GetSession(id)
if s != None and (manual or self.btconfig['use_multimngr']) and self.IsShown():
from dlordermngr import DLOrderMngr
manager = DLOrderMngr(self, self.btconfig, self.images,
s.GetFileRanges(), s.IsDLOrderRandom(), s.SetPieceRanges)
def ShowTorrentDlg(self, id):
s = self.GetSession(id)
if not s.spew and s != None and s.GetStatusData() != None:
from btdownloadgui import DownloadInfoFrame
s.spew = True
self.prgdlgs[len(self.prgdlgs)] = DownloadInfoFrame(self, s, self.images,
self.pl_dnsloop.GetPeerInfo, self.FriendCatcher)
def UpdateGUI(self):
if not self.btsessions_lock.acquire(False):
return
selected_id = self.list.GetSelectedData()
selected = None
total_urate = 0.0
total_drate = 0.0
nActiveSessions = 0
nWaitingSessions = 0
nStoppedSessions = 0
nCheckingSessions = 0
for s in self.btsessions:
if not s.IsDone() and s.IsRunning():
if s.IsChecking():
nCheckingSessions += 1
nActiveSessions += 1
elif not s.IsDone() and s.IsPaused() and s.IsStopped():
nStoppedSessions += 1
elif not s.IsDone() and s.IsPaused() and not s.IsChecking():
nWaitingSessions += 1
stotal = 0.0
ptotal = 0.0
i = 0
while i < len(self.btsessions):
s = self.btsessions[i]
s.SetQRank(i)
if selected_id == s.GetId():
selected = s
# not FAILED or entered DONE state
if not s.IsDone():
# if in RUNNING state
if s.IsRunning() and s.GetStatusData() != None:
urate = s.GetStat('urate')
drate = s.GetStat('drate')
## print s.GetStat('dtotal')
## print s.GetStat('utotal')
stotal = stotal + s.GetStat('seeds')
ptotal = ptotal + s.GetStat('peers')
if urate:
total_urate += s.GetStat('urate')
if drate:
total_drate += s.GetStat('drate')
s.AppendRateRecord(drate, urate)
try:
self.list.AddSession(s)
except:
print_exc()
print 'ERROR: error appending master list'
#0: stop only queue>0, 1: stop on cust option, 2: keep sharing
if s.IsComplete():
cfg = s.GetCfg()
if cfg.Get('on_complete') == 0:
if nWaitingSessions > 0:
nWaitingSessions -= 1
s.Stop()
elif cfg.Get('on_complete') == 1:
if s.GetFilesize() and s.GetStat('utotal'):
dtotal = s.GetFilesize()
utotal = s.GetStat('utotal')
ratio = float(utotal) / dtotal
else:
ratio = 0
if cfg.Get('end_on_newrate'):
cfg.Set('use_global_urate', False)
cfg.Set('maxupspeed', cfg['end_newrate']/1024)
s.GetDownload().SetMaxUpSpeed(cfg['end_newrate'])
if cfg.Get('end_on_percent') and ratio >= cfg.Get('end_percent'):
s.Stop()
if cfg.Get('end_on_ratio') and ratio >= cfg.Get('end_ratio'):
s.Stop()
if cfg.Get('end_on_timelimit') and (s.GetFinTime() + cfg.Get('end_timelimit')) <= time.time():
s.Stop()
elif cfg.Get('on_complete') == 2:
pass # do nothing (keep sharing)
else:
pass # catch if greater than 2
# if in PAUSED state
elif s.IsPaused():
try:
if s.GetStatusData() != None:
self.list.AddSession(s)
else:
self.list.AddPlaceholder(s)
except:
print_exc()
print 'ERROR: error appending master list'
# try to start or unpause next session in queue, unless was paused manually
if nCheckingSessions < 1 and nActiveSessions < self.btconfig.Get('max_sessions') and not s.IsStopped() and not s.thread.isAlive():
print 'trying to resume ' + str(s.GetId())
s.Resume()
nActiveSessions += 1
nCheckingSessions += 1
# EXCEPTION/LIMBO STATE
else:
# stuff in the limbo state still needs to be displayed
try:
if s.GetStatusData() != None:
self.list.AddSession(s)
else:
self.list.AddPlaceholder(s)
except:
print_exc()
print 'ERROR: error appending master list'
i += 1
# DONE or FAILED state
else:
try:
self.InvokeLater(self.list.RemoveSession, [s])
self.btsessions.remove(s)
try:
if self.sess_sort[s]: #remove session sort info
del self.sess_sort[s]
except:
pass
s.Kill()
self.SaveWorkState()
except:
print str(s.GetId()) + ' ERROR: error removing from master list'
#end while
# enter data into graph every cycle
self.graph.Append_DRate(total_drate)
self.graph.Append_URate(total_urate)
self.total_urate = total_urate
self.total_drate = total_drate
self.stotal = stotal
self.ptotal = ptotal
self.UpdateStatusPanels(selected)
#update statusbar
self.statusbar.SetUpRate(total_urate/1024)
self.statusbar.SetDownRate(total_drate/1024)
self.statusbar.SetSeedsTotal(stotal, ptotal)
self.btsessions_lock.release()
def URateThrottle(self):
if not self.btconfig['use_global_urate']:
return
cur_total_urate = 0
n_sessions = 0
largest_urate = 0
for s in self.btsessions:
if s.IsRunning():
rate = s.GetStat('urate')
if rate != None and rate > 1:
n_sessions += 1
cur_total_urate += rate
if rate > largest_urate:
largest_urate = rate
if n_sessions <= 0:
return
max_urate = self.btconfig['total_max_uprate']
if max_urate == 1 or max_urate == 2:
max_urate = 0
self.btconfig.Set('total_max_uprate', 0)
if max_urate == 0:
rate = 0
else:
slack = max(0, max_urate - cur_total_urate)
rate = min(max_urate, int((max_urate / n_sessions) + slack))
for s in self.btsessions:
s_data = s.GetStatusData()
if not s.IsRunning() or s.IsChecking() or s_data == None:
continue
cfg = s.GetCfg()
if not cfg['use_global_urate']:
continue
target_peer_rate = 1024 * cfg['avg_peer_urate']
cur_rate = s_data['urate']
if cur_rate == None:
cur_rate = 0
if (cur_rate > rate or cfg['maxupspeed'] != int(rate/1024)) and \
(rate + cfg['maxupspeed']) != 0:
s.GetDownload().SetMaxUpSpeed(rate)
cfg['maxupspeed'] = int(rate/1024)
if rate > 0:
maxuploads = max(1, int(round(0.5 + float(rate) / max(1024, target_peer_rate))))
else:
maxuploads = max(4, int(round(0.5 + float(cur_rate) / max(1024, target_peer_rate))))
if largest_urate > target_peer_rate:
maxuploads += 1
elif largest_urate + 2048 < target_peer_rate and maxuploads > 1:
maxuploads -= 1
s.GetDownload().SetMaxUploads( maxuploads )
cfg['maxuploads'] = maxuploads
def UpdateStatusPanels(self, selected):
try:
# Display status on list selected item
if selected != None and self.IsShown():
d = selected.GetStatusData()
s = selected.GetStaticData()
if selected.IsStopped():
self.TogglePauseButton(True, True)
elif selected.IsPaused():
self.TogglePauseButton(False)
else:
self.TogglePauseButton(True)
# Status Panel
if self.notebook.GetSelection() == 0:
if selected.IsComplete():
self.status.pppgauge.SetValueFinished()
elif selected.IsStopped():
self.status.pppgauge.SetValueStopped()
self.status.peerlist.Reset()
elif selected.IsPaused():
self.status.pppgauge.SetValuePaused()
self.status.peerlist.Reset()
elif selected.HasFailed():
self.status.pppgauge.SetValueFailed()
elif d != None:
pppg_time = time.time()
self.status.pppgauge.SetValue(d['fractionDone'],
d['havelist'], d['availlist'])
if selected.IsRunning() and d != None and s != None:
pop_time = time.time()
self.status.peerlist.Populate(d['spew'], s['info_hash'], selected.ReChoke, selected.GetCfg())
else:
self.status.peerlist.Reset()
# Details Panel
elif self.notebook.GetSelection() == 1:
self.details.Update(selected)
# Friends Panel
elif self.notebook.GetSelection() == 3:
self.friendsCtrl.Update()
# Nothing selected
elif self.IsShown():
if self.notebook.GetSelection() == 0:
self.status.pppgauge.SetValueUnknown()
self.status.peerlist.Populate()
elif self.notebook.GetSelection() == 1:
self.details.Clear()
# Graph Panel section
if self.notebook.GetSelection() == 2:
if selected != None and selected.IsRunning() and \
selected.GetStatusData() != None:
self.graph.AttachSession(selected)
d = selected.GetStatusData()
self.graph.Append_Sel_DRate(d['drate'])
self.graph.Append_Sel_URate(d['urate'])
else:
self.graph.PushAsunder()
if self.IsShown():
self.graph.UpdateGraph()
else:
self.graph.PushAsunder()
else:
self.graph.PushAsunder()
# Main list
if self.IsShown():
self.list.Sort()
for s in self.btsessions:
if s is not selected and not s.spew:
s.ToggleSpew(False)
else:
s.ToggleSpew(True)
else:
for s in self.btsessions:
if not s.spew:
s.ToggleSpew(False)
else:
s.ToggleSpew(True)
except:
print_exc()
def ConnectFriends(self):
for s in self.btsessions:
xdata = s.GetStaticData()
if s.IsRunning() and xdata:
infohash = xdata['info_hash']
interested = self.friends.GetNeedsConnection(infohash)
for ip, port, peerid in interested:
s.StartConnection(ip, port, peerid)
def Broadcast(self):
live_files = []
for s in self.btsessions:
if s.IsRunning() and s.GetStaticData() != None:
live_files.append([ s.GetStaticData()['info_hash'],
s.GetStaticData()['listen_port'],
s.GetStaticData()['peer_id'] ])
self.friends.Broadcast(live_files)
self.last_friend_announce = time.time()
def OnClickColInPeerlist(self, col, ascending):
selected = self.GetSession(self.list.GetSelectedData())
if selected and col: #recalls last save
self.sess_sort[selected] = (col, ascending)
def OnSelectInMasterList(self, id):
selected = self.GetSession(id)
try:
if selected: #loads old sort value when switching between torrents
self.status.peerlist.SetColSort(self.sess_sort[selected])
except:
pass
#self.status.peerlist.Reset()
try:
self.UpdateGUI()
except:
print_exc()
def TogglePauseButton(self, status, both=False):
if both:
self.toolbar.EnableTool(104, status)
self.toolbar.EnableTool(105, status)
else:
self.toolbar.EnableTool(104, not status)
self.toolbar.EnableTool(105, status)
def OpenFolderSelected(self, event=None):
try:
index = self.list.GetFirstSelected()
while index != -1:
id = self.list.GetItemData(index)
self.OpenFolder(id)
index = self.list.GetNextSelected(index)
self.UpdateGUI()
except:
print_exc()
def PauseSelected(self, event=None):
try:
self.SavePeers()
index = self.list.GetFirstSelected()
while index != -1:
id = self.list.GetItemData(index)
self.PauseTorrent(id)
index = self.list.GetNextSelected(index)
self.UpdateGUI()
except:
print_exc()
def ResumeSelected(self, event=None):
try:
index = self.list.GetFirstSelected()
while index != -1:
id = self.list.GetItemData(index)
self.ResumeTorrent(id)
index = self.list.GetNextSelected(index)
self.UpdateGUI()
except:
print_exc()
def OnResumeAll(self, event):
pos = self.resumeall_butt.ClientToScreen((0,0))
butt_size = self.resumeall_butt.GetSize()
if not hasattr(self, "popupID1"):
self.popupID1 = wx.NewId()
wx.EVT_MENU(self, self.popupID1, self.ResumeAllFunc)
menu = wx.Menu()
menu.Append(self.popupID1, _("Resume All"), _("Resume All"), True)
self.PopupMenu(menu, self.ScreenToClient((pos[0]-butt_size.width, pos[1] + butt_size.height)))
menu.Destroy()
def ResumeAllFunc(self, event):
print "Resuming ALL torrents"
for s in self.btsessions:
s.Resume()
def StopSelected(self, event=None):
try:
index = self.list.GetFirstSelected()
while index != -1:
id = self.list.GetItemData(index)
self.StopTorrent(id)
index = self.list.GetNextSelected(index)
self.UpdateGUI()
self.SavePeers()
except:
print_exc()
def OnStopAll(self, event):
pos = self.stopall_butt.ClientToScreen((0,0))
butt_size = self.stopall_butt.GetSize()
if not hasattr(self, "popupID2"):
self.popupID2 = wx.NewId()
wx.EVT_MENU(self, self.popupID2, self.StopAllFunc)
menu = wx.Menu()
menu.Append(self.popupID2, _("Stop All"), _("Stop All"), True)
self.PopupMenu(menu, self.ScreenToClient((pos[0]-butt_size.width, pos[1] + butt_size.height)))
menu.Destroy()
def StopAllFunc(self, event):
print "Stopping ALL torrents"
for s in self.btsessions:
s.Stop()
def OpenIncomingFolder(self, id):
target_dl_dir = self.btconfig.Get("completed_dl_dir")
if os.path.exists(target_dl_dir):
startfile(target_dl_dir)
else:
self.msgpanel.AddMsg(_("Error"),(target_dl_dir,_(" not found. Check preferences.")), -1)
self.statusbar.SetStatus(_("Incoming Folder not found. Check message tab."))
def OpenFolder(self, id):
if id != None:
s = self.GetSession(id)
if s != None:
s.OpenDataFolder()
def StopTorrent(self, id):
if id != None:
s = self.GetSession(id)
if s != None:
s.Stop()
def PauseTorrent(self, id):
if id != None:
s = self.GetSession(id)
if s != None:
if not s.IsPaused():
s.Pause()
self.TogglePauseButton(True)
if not self.btconfig.Get('pause_move'):
self.MoveSessionToBack(id)
elif s.IsStopped():
s.Pause()
self.TogglePauseButton(True)
def ResumeTorrent(self, id):
if id != None:
s = self.GetSession(id)
if s != None:
s.Resume()
self.TogglePauseButton(False)
if not self.btconfig.Get('resume_move'):
self.MoveSessionToFront(id)
def NewSessionId(self):
if not hasattr(self, '_last_id'):
self._last_id = 100
else:
self._last_id += 1
return self._last_id
def AddTorrent(self, params = None, confirm_dir=False, btconfig=None):
self.AddStatMsg(_("General"), _("Adding Torrent"))
try:
id = self.NewSessionId()
if btconfig == None:
btconfig = self.btconfig.Clone()
print 'session ' + str(id) + ' Adding torrent'
session = BTSession(self, id, self.peer_id, self.InvokeLater,
self.UpdateCatcher, self.ErrorCatcher, self.StartCatcher,
self.friends.GetInterested, btconfig, self.images,
params, confirm_dir, self.AddStatMsg, self.DLOrderCatcher, self.path)
if not session.IsDone():
self.btsessions.append(session)
self.UpdateGUI()
else:
self.AddStatMsg(_("Error"), _("Could not start download"), -2)
print 'ERROR: Could not start download'
except:
print_exc()
def AddFromURL(self, url, referer=None):
url = url.encode('latin-1')
if not win32_flag:
url = unparseloadurl(url)
self.AddStatMsg(_("General"), _("Trying to load from URL %s") % url)
print "trying to load from URL %s" % url
if self.btconfig.Get('use_torrent_dir'):
path = self.btconfig.Get('torrent_dir')
else:
#need some temp place to put this
path = self.path
from urlfetch import T_FetchFile
geturl = T_FetchFile(self.InvokeLater, self.AddFromFile, url, path, referer)
geturl.start()
return True
def AddFromFile(self, responsefile, confirm_dir=False):
from BitTorrent.download import Download
# do checks then add
self.AddStatMsg(_("General"), _("Trying to load from file %s") % responsefile)
print "trying to load from responsefile"
d = Download()
## print responsefile
response = d.ParseResponseFile(responsefile)
if response == None:
self.AddStatMsg(_("Error"), _("Response file %s contains invalid data") % responsefile, -2)
print 'ERROR: responsefile contains invalid data'
return False
info = response['info']
if response.has_key('encoding'):
enc_type = response['encoding']
else:
enc_type = 'latin-1'
if info.has_key('name.utf-8'):
filename = info['name.utf-8'].decode('UTF-8')
else:
filename = info['name'].decode(enc_type)
# attept to see if this torrent is already added
for s in self.btsessions:
if s.GetResponseFilename() == None:
continue
if split(s.GetResponseFilename())[1] == encodefile(split(responsefile)[1]):
self.AddStatMsg(_("Error"), _("A response file named %s is already loaded - ignoring") % split(responsefile)[1], -2)
return True
if s.GetFilename() == filename:
# To do. make this optional via the preferences dialog
self.AddStatMsg(_("Error"), _("A file named %s is already loaded - ignoring") % filename, -2)
#self.AddTorrent( [responsefile], True )
return True
# check in the completed folder and retarget DL
dldir = self.btconfig['download_dir']
comp_dldir = self.btconfig['completed_dl_dir']
if self.btconfig['use_download_dir'] and exists(dldir) and exists(comp_dldir) and abspath(dldir) != abspath(comp_dldir):
files = os.listdir(comp_dldir)
for f in files:
if f == encodefile(filename):
# add confirmation here
print 'Found matching filename in completed folder'
startup_p = ["--responsefile", responsefile, "--saveas", join(comp_dldir, filename)]
btconfig = self.btconfig.Clone()
self.AddTorrent(startup_p, False, btconfig)
return True
self.AddTorrent( [responsefile], confirm_dir )
return True
def SaveWorkState(self):
import ConfigParser
print 'saving work state'
size = self.GetSize()
pos = self.GetPosition()
maximized = self.IsMaximized()
self.btconfig['maximized'] = maximized
if not maximized:
self.btconfig['clientpos'] = pos
self.btconfig['clientsize'] = size
splitpos = self.splitter.GetSashPosition()
if splitpos >= self.splitter.GetMinimumPaneSize():
self.btconfig['splitterpos'] = splitpos
self.btconfig.SaveOptions()
cp = ConfigParser.ConfigParser()
if win32_flag:
statefile = join(self.path, 'torrents.ini')
else:
statefile = join(os.path.expanduser('~/.Rufus'), 'torrents.ini')
print statefile
cp.add_section('TORRENTS')
ordered_sessions = [(s.GetQRank(), s) for s in self.btsessions]
ordered_sessions.sort()
for rank, s in ordered_sessions:
try:
params = s.GetSaveParams()
if len(params) > 0:
cp.set('TORRENTS', str(rank), str(params))
except:
print_exc()
print 'ERROR saving %s' % s.GetFilename()
file = open(statefile, 'w')
cp.write(file)
file.close()
def SavePeers(self):
all_peers = []
# save peers for
for s in self.btsessions:
if s.IsRunning() and s.GetStat('spew'):
rec = []
rec.append(s.GetFilename())
rec.append(s.GetSavePeers())
all_peers.append(rec)
all_peers = bencode(all_peers)
if win32_flag:
peerfile = join(self.path, 'peers.ben')
else:
peerfile = join(os.path.expanduser('~/.Rufus'), 'peers.ben')
file = open(peerfile, 'wb')
file.write(all_peers)
file.close()
def LoadWorkState(self):
import ConfigParser
self.AddStatMsg(_("General"), _("Loading work state"))
if win32_flag:
statefile = join(self.path, 'torrents.ini')
else:
statefile = join(os.path.expanduser('~/.Rufus'), 'torrents.ini')
print 'Loading work state:',statefile
if not exists(statefile):
return
torrentdir = self.btconfig.Get('torrent_dir')
completeddir = self.btconfig.Get('completed_tor_dir')
load_completed = self.btconfig.Get('load_completed')
# load what was saved in the ini file,
# except what is in completed dir if load_completed is False
cp = ConfigParser.ConfigParser()
try:
file = open(statefile, 'r')
cp.readfp(file)
file.close()
items = cp.items('TORRENTS')
cfg = {}
added_torrents = []
sorted_items = []
#for some lame reason, items is in an arbitrary order
for key, params in items:
sorted_items.append( (int(key), params) )
sorted_items.sort()
for key, params in sorted_items:
p = eval(params)
try:
responsefile = p[p.index("--responsefile") + 1]
saveas = p[p.index("--saveas") + 1]
cfg = p[p.index("--cfg") + 1]
up_total = p[p.index("--up_total") + 1]
down_total = p[p.index("--down_total") + 1]
check_hashes = p[p.index("--check_hashes") + 1]
except ValueError:
continue
if split(responsefile)[0] == completeddir and not load_completed:
continue
else:
# print 'from ini ' + split(responsefile)[1]
startup_p = []
startup_p.append( "--responsefile" )
startup_p.append( responsefile )
startup_p.append( "--saveas" )
startup_p.append( saveas )
startup_p.append( "--up_total" )
startup_p.append( up_total )
startup_p.append( "--down_total" )
startup_p.append( down_total )
if not self.btconfig['always_check_hashes']:
startup_p.append( "--check_hashes" )
startup_p.append( check_hashes )
added_torrents.append(split(responsefile)[1])
cfg = eval(cfg)
btconfig = self.btconfig.Clone()
btconfig.Inject(cfg)
self.AddTorrent(startup_p, False, btconfig)
except:
print_exc()
# load torrents in torrent folder, unless already loaded.
if not self.btconfig.Get('use_torrent_dir') or not exists(torrentdir):
return
torrentdir = unicode(torrentdir)
torrentfiles = os.listdir(torrentdir)
for torrent in torrentfiles:
## print "trying to load %s" % torrent
responsefile = join(torrentdir, torrent)
if splitext(responsefile)[1] != ".torrent":
continue
try:
added_torrents.index(torrent)
except ValueError:
## print 'Loading from file %s' % torrent
added_torrents.append(torrent)
self.AddFromFile(responsefile)
def version_check(self):
self.VersionCheck = Thread(target=self._ver_check)
self.VersionCheck.start()
def _ver_check(self):
from BitTorrent.zurllib import urlopen,Request
url="http://rufus.sourceforge.net/check.php"
new_version = 0
try:
h = urlopen(url)
new_version = h.read()
if new_version > version:
self.InvokeLater(self.OnNewVersion, [new_version])
except Exception, e:
print "Error checking for new version: " + str(e)
def OnNewVersion(self, new_version):
self.update_notified = True
from optiondlg import UpdateDlg
up_dlg = UpdateDlg(self, btconfig = BTConfig(), bmps=self.images, ver=version, new_ver=new_version)
up_mode = up_dlg.ShowModal()
if up_mode == wx.ID_OK:
open_new("http://rufus.sourceforge.net/downloads.php")
if up_dlg.DisableUpdate():
print "Disabling Auto-Update Permenantly"
self.btconfig.Set('ud_on_start', False)
self.btconfig.Set('ud_hourly', False)
up_dlg.Destroy()
def CreateTorrent(self, event):
from btcompletedirgui import CreateTorrentDlg
pos = self.ClientToScreen( (50,20) )
frame = CreateTorrentDlg(self, self.btconfig, pos, self.AddFromFile)
frame.Show(True)
def NewTorrent_File(self, event):
confirm_dir=False
msg = 'Select .torrent file(s) to add'
if event.GetId() == 210:
confirm_dir=True
msg += ' - Non default save'
elif event.GetId() == 214:
confirm_dir=True
msg = 'Select .torrent(s) to seed'
dlg = wx.FileDialog(self, msg, '', '', '*.torrent', wx.OPEN | wx.MULTIPLE | wx.CHANGE_DIR )
if dlg.ShowModal() != wx.ID_OK:
self.failed = True
return False
else:
responsefile = dlg.GetPaths()
for d in responsefile:
self.AddFromFile(d, confirm_dir)
dlg.Destroy()
def NewTorrent_URL(self, event):
from urlfetch import URLDialog
data = None
data = wx.TextDataObject()
wx.TheClipboard.Open()
success = wx.TheClipboard.GetData(data)
wx.TheClipboard.Close()
dlg = URLDialog(self)
if success and "torrent" in data.GetText() or "http" in data.GetText():
dlg.edit1.SetValue(data.GetText())
else:
dlg.edit1.SetValue("")
if dlg.ShowModal() == wx.ID_OK and dlg.edit1.GetValue() != "":
self.AddFromURL(dlg.edit1.GetValue(), dlg.edit2.GetValue())
dlg.Destroy()
def GetSession(self, id):
for s in self.btsessions:
if s.GetId() == id:
return s
return None
def SyncSessionOptions(self, dosync=False):
if dosync:
self.AddStatMsg(_("General"), _("Syncing options"))
for s in self.btsessions:
try:
cfg = s.GetCfg()
cfg.MirrorOptions(self.btconfig)
except:
print_exc()
else:
self.options_menu.Check(206, self.btconfig['popup_errors'])
def KillTorrent(self, id, death_mode=-1):
s = self.GetSession(id)
del_torrent = False
del_data = False
remove_dlg = None
if death_mode > -1:
apply2all = True
else:
apply2all = False
if death_mode == -1:
from optiondlg import RemoveTorrentDlg
remove_dlg = RemoveTorrentDlg(self, btconfig = BTConfig(), bmps=self.images)
death_mode = remove_dlg.ShowModal()
remove_dlg.Destroy()
if death_mode == wx.ID_CANCEL:
return None
if remove_dlg.Apply2All():
apply2all = True
if death_mode == 1:
del_torrent = True
elif death_mode == 2:
del_data = True
elif death_mode == 3:
del_torrent = True
del_data = True
responsefile = s.GetResponseFilename()
if s.GetDownload() and s.GetDownload().GetFiles():
datafiles = s.GetDownload().GetFiles()
else:
del_data = False
# delete torrent file
if del_torrent:
if responsefile != None:
try:
self.AddStatMsg(_("General"), _("Deleting torrent file %s") % responsefile, 0)
os.remove(responsefile)
except OSError:
self.AddStatMsg(_("Error"), _("Could not delete file %s") % responsefile, -2)
print "ERROR: could not delete file %s" % responsefile
else:
print split(responsefile)[0] , abspath(self.btconfig.Get('torrent_dir'))
if split(responsefile)[0] == abspath(self.btconfig.Get('torrent_dir')):
try:
os.rename(responsefile, responsefile+"_ABORTED")
except OSError:
pass
# delete data
if del_data:
if s != None:
s.Kill()
s.RemoveResumeData()
nfiles = 0
for filename, len in datafiles:
nfiles += 1
try:
filename = encodefile(filename)
if exists(filename):
self.AddStatMsg(_("General"), _("Deleting file %s") % filename, 0)
os.remove(filename)
except OSError:
print "ERROR: could not delete file %s" % filename
self.AddStatMsg(_("Error"), _("Could not delete file %s") % filename, -2)
if nfiles > 1:
for i in range(nfiles):
try:
#check to make sure it hasn't already been deleted by rmtree
if exists(dirname( datafiles[i][0] )):
self.AddStatMsg(_("General"), _("Deleting dir %s ") % dirname( datafiles[i][0] ), 0)
shutil.rmtree( dirname( datafiles[i][0] ) )
except:
self.AddStatMsg(_("Error"), _("Could not remove dir %s") % dirname( datafiles[i][0] ), -2)
##debug print_exc()
s = None
if s != None:
s.Kill()
s.RemoveResumeData()
self.UpdateGUI()
if apply2all:
return death_mode
return -1
def KillSelected(self, event):
self.AddStatMsg(_("General"), _("Killing selected torrent(s)"))
print 'Killing selected torrent(s)'
selected = []
index = self.list.GetFirstSelected()
while index != -1:
id = self.list.GetItemData(index)
selected.append(id)
index = self.list.GetNextSelected(index)
try:
death_mode = -1
for id in selected:
death_mode = self.KillTorrent(id, death_mode)
if death_mode == None:
break
except:
print_exc()
self.UpdateGUI()
def OnClose(self, event):
if not self.CheckPass("quit"):
return
# get confirmation before closing
if self.btconfig.Get('confirmexit'):
dlg = wx.MessageDialog(self, _("Do you really want to exit?"),
_("Confirmation"), wx.YES_NO | wx.ICON_INFORMATION)
dlgresult = dlg.ShowModal()
dlg.Destroy()
if dlgresult != wx.ID_YES:
return
try:
if self.cfg_visflag.isSet():
return
print 'On Close'
self.Show(False)
self.SaveWorkState()
self.SavePeers()
self.doneflag.set()
self.pl_dnsloop.Stop()
self.rpcserver.Stop()
# if not win32_flag: #(crashes on exit under win32)
# import socket
# socket.setdefaulttimeout(1) # LeoXV Destroy()
print 'Mainloop joining'
self.mainloop.join(1)
print 'Killing sessions ' + str(len(self.btsessions))
for s in self.btsessions:
s.Kill()
except:
print 'ERROR: Did not shut down correctly'
print_exc()
print 'Destroying all open/minimised torrent progress dialogs'
for f in self.prgdlgs:
try:
self.prgdlgs[f].KillDlg()
except:
pass
if win32_flag:
print 'Destroying main taskbar icon'
self.tbicon.Destroy()
print 'Destroying window'
## if not win32_flag:
## sys.stdout.flush()
## sys.stdout.close()
## sys.stdout = oldStd
##
## sys.stderr.flush()
## sys.stderr.close()
## sys.stderr = oldStderr
self.Destroy()
if not win32_flag: # (crash on exit under win32)
sys.exit(1) # http://ubuntuforums.org - jdong
class MyApp(wx.App):
def __init__(self, flag):
wx.App.__init__(self, flag)
wx.Log_SetActiveTarget(wx.LogStderr())
def OnInit(self):
path = dirname(sys.argv[0])
frame = Reba(path, sys.argv[1:])
self.SetTopWindow(frame)
return True
def popup_abort():
app = wx.PySimpleApp()
frame = wx.Frame(None, -1, '')
dlg = wx.MessageDialog(frame, "Another instance of %s is already running" % prog_name,
"Abort", wx.OK | wx.ICON_INFORMATION)
dlg.ShowModal()
dlg.Destroy()
frame.Destroy()
def run(params):
try:
app = MyApp(False)
app.MainLoop()
except:
print_exc()
if __name__ == '__main__':
print "Rufus requires wxwindows 2.5.2.8u"
print "Installed wx version: %s" % wx.VERSION_STRING
if not win32_flag:
echo_browser_test()
if debug_flag:
print 'debugging'
run(sys.argv[1:])
else:
checker = wx.SingleInstanceChecker( prog_name + '-' + wx.GetUserId() )
if checker.IsAnotherRunning() == False:
run(sys.argv[1:])
else:
print 'Another instance is already running'
if len(sys.argv[1:]) > 0:
from g3rpcclient import G3RPCCLient
rpc = G3RPCCLient(dirname(sys.argv[0]))
rpc.AddTorrent(sys.argv[1:][0])
else:
popup_abort()
|