rufus.py :  » Network » Rufus-BitTorrent-Client » Rufus_0.7.0_src » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Network » Rufus BitTorrent Client 
Rufus BitTorrent Client » Rufus_0.7.0_src » rufus.py
#! /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()
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.