hylaproto_t.py :  » Business-Application » hylaPEx » hylapex » library » ftp » 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 » Business Application » hylaPEx 
hylaPEx » hylapex » library » ftp » hylaproto_t.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# hylaPEx, an hylafax client written in python
#
# www.unipex.it/hylapex/
#
# License:
#         GNU General Public License (GPL)
#         For more info see LICENSE.txt and LICENSE-GPL.txt
#
# Copyright (C) 2004-2006  Unipex s.r.l.,  All Rights Reserved.
# Via Vittorio Veneto 83/A
# 33050 Gonars (UD) - Italy
# phone 0039 0432 931511 - fax 0039 0432 931378
# www.unipex.it - michele.petrazzo@unipex.it

#Twisted
from twisted.internet import reactor,threads
from myftp import FClient
from twisted.protocols import basic
from twisted.internet.protocol import Protocol,ClientCreator

#System
from cStringIO import StringIO
from datetime import datetime
from operator import itemgetter
from tempfile import mkstemp
import string , time, os, sys, pprint, copy, traceback

#Image
import hylaimage

#Key to hylafax (hfaxd) codes. See man hfaxd for more info
H_DONE_F = {'comp':'C','dial':'D','pri':'I','jtag':'J','stat':'a','num':'e','id':'j','own':'o',
            'last':'s','kill':'k','pag':'p','dat':'Y','rate':'E', 'tts':'z', 'loc': 'L', 
            'from_send': 'S', 'to_pers': 'R'}
H_RCV_F = {'err':'e', 'img':'f', 'pag':'p','snd':'s', 'dat':'t', 'err':'e'}
H_SEND_F = {'comp':'C','dial':'D','pri':'I','jtag':'J','stat':'a','num':'e','id':'j','own':'o',
            'last':'s','kill':'k','pag':'P','tts':'z', 'sched':'Z', 'rate':'E', 'loc': 'L', 
            'from_send': 'S', 'to_pers': 'R'}

#Formats
#DONE_FMT = "%j|%C|%L|%I|%o|%a|%D|%e|%P|%z|%s"
#SND_FMT = "%j|%C|%Y|%L|%o|%a|%e|%p|%I|%s"
#RCV_FMT = "%f|%p|%s|%t|%e"

#Orders
DONE_ORDER = ["id", "comp", "dat", "to_pers", "own", "stat", 'num', 'pag', 'pri', 'last']
SEND_ORDER = ["id", "comp", "to_pers", "pri", "own", "stat", 'dial', 'num', 'pag', 'tts', 'last']
RCV_ORDER = ["img", "pag", "snd", "dat", 'err']

RCV_FORMAT_DATE = "%d-%m-%y %H:%M"
DONE_FORMAT_DATE = "%d-%m-%y %H:%M"

#View
DONE_VIEW = 0
RCV_VIEW = 1
SEND_VIEW = 2

STATUS_VIEW = 100
ALL_VIEW = 101

LINE_SEP = "\r\n"

FILE_TYPE_PS = 0
FILE_TYPE_PDF = 1
FILE_TYPE_TIFF = 2

D_FYLE_TYPE = {FILE_TYPE_TIFF: ('.tif', ""), 
               FILE_TYPE_PDF: ('.pdf', "%PDF"), 
               FILE_TYPE_PS: ('.ps', "%!PS"), }

#Not want the tiff test
NUM_F_TYPE = len( D_FYLE_TYPE ) -1

class NotConnected(Exception):
    pass

class _BufferingProtocol(Protocol, basic.LineReceiver):
    """Simple utility class that holds all data written to it in a buffer."""
    def __init__(self):
        self._buffer = StringIO()

    def dataReceived(self, data):
        self._buffer.write(data)
    
    def GetBuffer(self):
        return self._buffer
    
    buffer = property(GetBuffer)

class SendFax(object):
    """ Class useful for send a fax
    """
    def __init__(self):
        """ Init the class and create default values
        """
        super(SendFax, self).__init__()
        def isdigit(value):
            if isinstance(value, basestring):
                return value.isdigit()
            else:
                return False
        
        #Don't call the __setattr__ funct
        self.__dict__["_startUp"] = 1

        #Parameters list, with value name, default value, possible values (or function to control it)
        self.paramtersList = {
                #"leave" as are, unless you know what are you doing
                "chopthreshold": ("3", True),                
                "pagechop": ("default", True),
                "pagelength": ("296", isdigit),
                "pagewidth": ("209", isdigit),
                "vres": ("196", isdigit),
                
                #user paramenters
                "dialstring": (None, True), # the fax number
                "fromuser": (None, True),   #the user that send the fax
                "notifyaddr": ("", False),  # email where send the notify
                "notify": ("done+requeue",  # and when notify it
                        ("done+requeue","done", "requeue", "none", True) ),
                "maxdials": ("10", isdigit),    #how many dials
                "lasttime": ("010000", isdigit), #when the tranmission will fail
                "tolocation": ("", False),      #location. I'm using it has subject
                "tocompany": ("", False),       #company where send the fax
                "schedpri": ("127", isdigit),  #fax priority 0<->255. 0 is high
                "sendtime": ("Now", True),      # when send the fax

                #Not directly fax parameters
                "file_list": ([], True),        #File list
                "convert": (True, False),       #Convert fax before send
                "gspath": ("", False),          #Gs path
                }

        for name, (val, _) in self.paramtersList.iteritems():
            #Set defaults values
            setattr(self, name, val)
        
        self._parametersAdded = {}
        self._always_skip = ["convert", "gspath"]
        self.__dict__["_startUp"] = 0
        
    def GetSendValues(self, skip_value=()):
        """ Send the fax with the paramters passed
        """
        d_ret = {}
        #Control the data and its default values
        for name, (value, default) in self.paramtersList.iteritems():
            
            #If a paremeter was added, fetch that value, otherwise fetch the defalut one
            if name in self._parametersAdded:
                value = self._parametersAdded[name]
            
            #Control the values
            
            if default in (None, False) or default == True and value:
                #If any value are accepted, skip the control
                pass
            elif callable(default):
                if not default(value):
                    raise ValueError, "Value incorrect for attribute: %s %s" % (name, value)
            elif isinstance( default, (list, tuple) ):
                if not value in default:
                    raise ValueError, ("Value not in list attribute list: %s %s" % 
                                        (value, default) )
            elif default == True and not value:
                raise ValueError, "Value not present for attribute: %s" % name
            else:
                raise ValueError, ("Default value %s not understood for attribute: %s" % 
                                        (default, name) )
            
            d_ret[name] = value
            
        d_ret.update( self._parametersAdded )
        
        #The caller not need a value, skip (k in skip_value)
        #If the value are empty, skip it. Hylfax not want empty parameters! (not v)
        
        return dict( [(k,v) for k, v in d_ret.iteritems()
                       if v and not k in skip_value and not k in self._always_skip] )
        
    def addParameter(self, name, value):
        """ Add a parameter to the send class
        """
        name, value = self._ctrlParameters(name, value)
        self._parametersAdded[name] = value
    
    def _ctrlParameters(self, name, value):
        """ Control how the user pass us the values
        """
        if name in ("dialstring", "file_list"):
            if not isinstance(value, (tuple, list)):
                value = [value]
        if name == "lasttime":
            value += (6 - len(value)) * "0"

        return name, value
    
    def __setattr__(self, name, value):
        """ Trickle that leave the user add a paramter directly
        """
        if not self._startUp:
            if isinstance( name, basestring ):
                name = name.lower()
            if name in self.paramtersList and not name.startswith("_"):
                self.addParameter(name, value)
        
        name, value = self._ctrlParameters(name, value)
        
        #print name, value
        self.__dict__[name] = value
    
    def __repr__(self):
        return ( "Fax instance.%s My values are: %s" % 
            ( super(SendFax, self).__repr__(),
              pprint.pformat(self.__dict__) ) ) 
        
    sendvalues = property(GetSendValues)
    
class HylafaxProto(object):
    """ Hylafax proto class made with twisted
    """
    chunk_size_send = 8192
    mText = "Modem"
    
    def __init__(self, host, user, passwd="", adminpasswd="",
                    passive=1, tzone=0,
                    callBackOnUpdate=None, callBackOnError=None, 
                    timeUpdate=30,
                    filterSend=None, filterDone=None, filterRcv=None,
                    orderSend=None, orderDone=None, orderRcv=None,
                    sortSend=None, sortDone=None, sortRcv=None, sortReverse=True,
                    callBackOnStatus=None,
                    mode="S", port=4559,
                    dateTimeRcv=None, dateTimeRcvUse=True,
                    filterSendActive=True, filterDoneActive=True, filterRcvActive=True,
                    advancedFilters=None,
                    fetch_view=None,
                    debug=0, debugFunct=None):
        
        """ Values to pass me:
            host: the host name
            user: user for login
            passwd: its password, if any. default null
            adminpasswd: the administratio password, if any. default null
            callBackOnUpdate: a callable called when an update are done
            callBackOnError: a callable called when an update are done
            timeUpdate: how many seconds wait for an update
            filterSend, filterDone, filterRcv = Filter the number of fax or filter by date. dict with "d" or "n" as key
            sortSend, sortDone, sortRcv = column where sort. Can be an integer or a the column string
            sortReverse = do a reverse sort? defalut true
            callBackOnStatus = callback when I receive the hylafax status info
            mode, port = ftp mode communication (string/image) as string and port integer
            dateTimeRcv, dateTimeRcvUse = Does I change the date representation for the received fax? If yes, 
                            passme a dict with the already seen fax
            filterSendActive, filterDoneActive, filterRcvActive = does I have to filter the data?
            advancedFilters = do advanced filtering. See filters.py
            fetch_view: if None I'll fetch all the three views, otherwise I'll *delete*, from my views that passed
            debug, debugFunct = debug and call the debugFunct with the parameters
        """
        
        self._startingUp = True
        
        #Setup debug
        self.debugFunct = debugFunct
        self._debug = debug
        self._init_debug()
        
        #Sorted columns
        self.sortSend = sortSend
        self.sortDone = sortDone
        self.sortRcv= sortRcv
        
        self.sortReverse = sortReverse

        #Filters
        self.filterDone = filterDone
        self.filterRcv = filterRcv
        self.filterSend = filterSend

        #Orders
        self.orderSend = orderSend
        self.orderDone = orderDone
        self.orderRcv = orderRcv
        
        #AdvancedFilters 
        self.advancedFilters = advancedFilters
                
        #Filters activation
        self.filterDoneActive = filterDoneActive
        self.filterRcvActive = filterRcvActive
        self.filterSendActive = filterSendActive
        
        #Internal buffers. Real (passed from the server) and with the order and filter Applied
        self._buff_status = []
        self._buff_sendR, self._buff_doneR, self._buff_recvR = (),(),()
        self._buff_sendA, self._buff_doneA, self._buff_recvA = (),(),()

        #self._orderSend = SEND_ORDER; self._orderDone = DONE_ORDER; self._orderRcv = RCV_ORDER
        #self._filterDone = {}; self._filterRcv = {}; self._filterSend = {}

        #Server info
        self.host = host; self.user = user; self.passwd = passwd; self.adminpasswd = adminpasswd
        self._port = port; self._passive = passive; self._mode = mode; self._tzone = tzone
        
        #Some other values
        self._callBackOnUpdate = callBackOnUpdate
        self._callBackOnError = callBackOnError
        self._callBackOnStatus = callBackOnStatus
        self._timeUpdate = timeUpdate
        self._dateTimeRcv = dateTimeRcv or {}
        self._dateTimeRcvUse = dateTimeRcvUse
        
        #sequence for call the fetch data
        self._lst_sequence_fetch_order = [STATUS_VIEW, SEND_VIEW, RCV_VIEW, DONE_VIEW, ALL_VIEW]
        
        if fetch_view is None:
            fetch_view = ()
        elif not isinstance(fetch_view, (list, tuple)):
            fetch_view = (fetch_view, )
        
        
        for view_del in fetch_view:
            self._lst_sequence_fetch_order.remove(view_del)
        

        self._lst_sequence_fetch = { STATUS_VIEW: (self._RetrStatus, self._RetStatus), 
                    SEND_VIEW: (self._RetrSend, self._RetSend), DONE_VIEW: (self._RetrDone, self._RetDone),
                    RCV_VIEW: (self._RetrRecvq, self._RetRecvq), ALL_VIEW: (self._RetrAll, ) }
        
        self._on_update = False
        self._current_fetch_idx = 0
        
        self._lstIdDateChanged = []
        self._delayCall = None
        
        #Are us connected?
        self._connected = 0
        self._mdtmCalled = 0
        
        #List where save the SendFax classes not already done
        self.queue_send = []
        
        #Only for multitasking tests
        if self._debug4:
            reactor.callLater(0.2, self._timePassed)
        
        self._startingUp = False
        self._hClient = None

        self._CreateFormats()
        self._SendStartupParameters()

    #
    # Init process
    #
    
    def _SendStartupParameters(self):
        """ Send login and other startup parameters
        """
        if self._startingUp: return

        #Reset the connection, if need
        if self._connected and self._hClient.connected:
            self._hClient.quit()
            self._connected = 0

        # Create the client
        creator = ClientCreator(reactor, FClient, self._user, self._passwd, 
                self._passive, self._loggedin, fail=self._Fail)
        #FTPClient.fail = self._Fail
        
        cre = creator.connectTCP(self._host, self._port)
        cre.addCallback(self._ConnectionMade)
        cre.addErrback(self._Fail)
    
    def _loggedin(self, res):
        """ Called when we are loggedin
        """
        if self._adminpasswd and self._connected:
            dadmin = self._hClient.queueStringCommand("ADMIN %s" % self._adminpasswd)
            dadmin.addErrback(self._Fail)
            if not self._connected: return
        
        #set mode and time zone
        if not self._connected: return
        d = self.SetMode()
        if not self._connected: return
        reactor.callLater(0.5, self.SetTzone)
        
        d.addErrback(self._Fail)
        
        #Load the first-time data
        if self._timeUpdate > 0:
            self._delayCall = reactor.callLater(self._timeUpdate, self._get_current_fetch())
            self._delayCall.delay(10)
            reactor.callLater(0, self._get_current_fetch())
        elif self._timeUpdate == 0:
            reactor.callLater(0, self._RetrStatus, onlyStatus=True)
        
    def _ConnectionMade(self, ftpClient):
        """
        """
        if self._debug1: self._Debug("HP:_ConnectionMade")
        self._hClient = ftpClient
        self._connected = 1
    
    #
    # Retrieve data
    #
    
    def _RetrStatus(self, *args, **kw):
        """ Retrieve the status 
        """
        if self._debug2: self._Debug("HP:start _RetrStatus")
        if self._on_update:
            if self._debug2: self._Debug("HP:We are already updating, skip")
            return 
        
        self._on_update = True
        
        if not self._hClient:
            self._Debug("HP:No connection on _RetrStatus. Why?")
            return

        proto = _BufferingProtocol()
        conn = self._hClient.list('status', proto)
        conn.addCallback(self._get_current_fetch_cb(), proto, *args, **kw)
        conn.addErrback(self._Fail)
        
    def _RetrSend(self):
        """ Retrieve the send queue
        """
        if self._debug2: self._Debug("HP:start _RetrSend")
        self._SetJFormat(SEND_VIEW)
        
        proto = _BufferingProtocol()
        conn = self._hClient.list('sendq', proto)
        conn.addCallbacks(self._get_current_fetch_cb(), self._Fail, callbackArgs=(proto,))
    
    def _RetrDone(self):
        """ Retrieve the done queue 
        """
        if self._debug2: self._Debug("HP:start _RetrDone")
        self._SetJFormat(DONE_VIEW)
        
        proto = _BufferingProtocol()
        conn = self._hClient.list('doneq', proto)
        conn.addCallbacks(self._get_current_fetch_cb(), self._Fail, callbackArgs=(proto,))

    def _RetrRecvq(self):
        """ Retrieve the recvq queue 
        """
        if self._debug2: self._Debug("HP:start _RetrRecvq")
        self._SetJFormat(RCV_VIEW)
        
        proto = _BufferingProtocol()
        conn = self._hClient.list('recvq', proto)
        conn.addCallbacks(self._get_current_fetch_cb(), self._Fail, callbackArgs=(proto,))
    
    
    def _RetrMDTM(self):
        """ Fetch the date for the receive fax, if need/want
        """
        if not ( self._dateTimeRcvUse and self._connected ): return
        
        posImg = self._orderRcv.index("img")
        
        sSrv = set( [ x[posImg] for x in self._buff_recvR ] )
        sDone = set( self._dateTimeRcv ) 
        numToRecon = sSrv - sDone
        
        #Clean the dict
        for k in sDone - sSrv: self._dateTimeRcv.pop(k)
        
        for numId in sorted( list( numToRecon ), reverse=True):
            if numId in self._dateTimeRcv: continue
            break
        else:
            return 

        if not self._hClient.connected:
            self._sendStartupParameters()
            return
        
        d = self._hClient.queueStringCommand("MDTM recvq/%s" % numId)
        d.addCallback(self._RetMDTM, numId, self._dateTimeRcv)
        d.addErrback(self._Fail)
    
    #
    # - Return functions from retrieve
    #
    
    def _RetStatus(self, result, b, *args, **kw):
        if self._debug2: self._Debug("HP:receved _RetStatus")
        
        buf = b.buffer.getvalue()
        
        #Keep only the lines that has some data
        self._buff_status = LINE_SEP.join( [ x for x in buf.split(LINE_SEP) if x.strip() ] )
        
        #If need, callit
        if callable(self._callBackOnStatus):
            reactor.callLater(0, self._callBackOnStatus)
        
        if kw.get("onlyStatus", None): return
        
        self._get_current_fetch()()
    
    def _RetSend(self, result, b):
        if self._debug2: self._Debug("HP:receved _RetSend")
        self._buff_sendR = self._CreateDataSets( b.buffer.getvalue() )
        self._get_current_fetch()()
    
    def _RetDone(self, result, b):
        if self._debug2: self._Debug("HP:receved _RetDone")
        buff = self._CreateDataSets( b.buffer.getvalue() )
        if buff != self._buff_doneR:
            self._lstIdDateChanged = []
            self._buff_doneR = buff
        self._get_current_fetch()()
    
    def _RetRecvq(self, result, b):
        if self._debug2: self._Debug("HP:receved _RetRecvq")
        self._buff_recvR = self._CreateDataSets( b.buffer.getvalue() )
        self._get_current_fetch()()
    
    def _RetrAll(self):
        """ We have done the update, so call sort, filter and restart the timer;
            at the end, call the parent update, if need
        """
        if self._debug2: self._Debug("HP:receved _RetAll")
        
        self._on_update = False
        
        self._current_fetch_idx = 0
        
        self._SetFiltersAndOrders()
        
        if self._delayCall and self._delayCall.active():
            self._delayCall.reset(self._timeUpdate)
        elif self._timeUpdate > 0:
            reactor.callLater(self._timeUpdate, self._get_current_fetch())
            
        if callable(self._callBackOnUpdate):
            reactor.callLater(0, self._callBackOnUpdate)
        
        if not self._mdtmCalled:
            reactor.callLater( 0.1, self._RetrMDTM )
            self._mdtmCalled = 1
        
    def _RetMDTM(self, ret, numId, d):
        """
        """
        if not (len(ret) > 0 and ret[0].startswith("213") ): 
            print "Error while retrieve date for file %s" % numId
            return
        mydate = ret[0].split(" ", 1)[1]
        
        lstSplit = (4,2,2,2,2,2)
        myIndex = 0
        lstOut = []
        for idx in lstSplit:
            lstOut.append( mydate[ myIndex : myIndex+idx ] )
            myIndex += idx
        dateOut = datetime(*map(int, lstOut)).timetuple()
        d[numId] = dateOut
        reactor.callLater( 0.3, self._RetrMDTM )
    
    def _RetRetrFile(self, result, proto, *args, **kw):
        """ Into kw passme: 
                callBack -> callable
                fileOut -> None
                createFileOut -> True
                returnBuffer -> False
        """
        
        if len(args) > 0: callBack = args[0]
        else: callBack = kw.get("callBack", None)
        
        if not callable(callBack):
            raise ValueError, "Pass me a valid callable at retrieve file"
        
        fileOut = kw.get("fileOut", None)
        createFileOut = kw.get("createFileOut", True)
        returnBuffer = kw.get("returnBuffer", False)
        
        #The buffer
        buff = proto.buffer.getvalue()
        
        #Control the header
        filetype = filter(lambda x: buff.startswith( D_FYLE_TYPE[x][1] ), 
                                range(NUM_F_TYPE) )
        
        if filetype: filetype = filetype[0]
        else: filetype = FILE_TYPE_TIFF
            
        #Have to create the file?
        if createFileOut: 
            if fileOut:
                f = open(fileOut, "wb")
            else:
                ext = D_FYLE_TYPE[filetype][0]
                fd, fileOut = mkstemp(prefix="hylapex_tmp_%s_" % self._user, suffix=ext)
                f = os.fdopen(fd, "wb")
            
            f.write( buff )
            f.close()
        
        par = {}
        #Paramenters
        par.update(kw)
        par["filetype"] = filetype
        
        if returnBuffer:
            par["returnBuffer"] = buff
        
        reactor.callLater(0, callBack, fileOut, **par)            
    
    def _Fail(self, response):
        """ Internal fail command
        """
        #FTP connection lost
        if hasattr( response, "getTraceback" ):
           resp = response.getTraceback()
        else:
           resp = "UnexpectedResponse"

        if ("FTP connection lost" in resp or 
                 ( hasattr( response, "type" ) and 
                   issubclass(response.type, NotConnected) )
            ) :
            #We lost connection, try to reconned silently!
            print "Error silently skipped:", resp
            self._SendStartupParameters()
            print response.stack
            if callable( self._callBackOnError ):
                self._callBackOnError( "Connection are lost, but I'll reconnect to the server" )
            return
        
        self._connected = 0
        
        #Delete the call, if need
        if self._delayCall and self._delayCall.active():
            self._delayCall.cancel()

        #Call error, if need
        if callable( self._callBackOnError ):
            self._callBackOnError( resp )
        
        if not self._connected:
            return
        
        self._hClient.quit()
    #
    # Interface methods
    #
    
    def Close(self):
        """ Close the connection and exit
        """
        self._hClient.quit()
        self._connected = 0
    
    def GetDataViewRaw(self, view):
        """ Get the buffer for the view passed
        """
        if view == DONE_VIEW:
            return self._buff_doneR
        elif view == RCV_VIEW:
            return self._buff_recvR
        elif view == SEND_VIEW:
            return self._buff_sendR
        else:
            raise ValueError

    def GetDataView(self, view):
        """ Get the buffer for the view passed
        """
        if view == DONE_VIEW:
            return self._buff_doneA
        elif view == RCV_VIEW:
            return self._buff_recvA
        elif view == SEND_VIEW:
            return self._buff_sendA
        else:
            raise ValueError
    
    def SetFilterView(self, f, view):
        """ Set the whole filter by the view
        """
        fi = self._getFilterDictByView(view)
        fi = f

    def SetFilterOptView(self, option, value, view):
        """ Set the filter option for the view.
            @see: __ChangeData
        """
        self._getFilterDictByView(view)[option] = value
    
    def SetFilterActiveView(self, value, view):
        """ Set filter activation by the view
        """
        if view == DONE_VIEW:
            self.filterDoneActive = value
        elif view == RCV_VIEW:
            self.filterRcvActive  = value
        elif view == SEND_VIEW:
            self.filterSendActive = value
        else:
            raise ValueError
        
    
    def RetrFile(self, fid, view, *args, **kw):
        """ Retrieve a file
            @par fid: File if
            @par view: My view
            @par kw: 
                callBack -> callable
                fileOut -> None
                createFileOut -> True
                returnBuffer -> False        
        """
        proto = _BufferingProtocol()
        
        if view == RCV_VIEW:
            conn = self._hClient.retrieveFile("recvq/" + fid, proto)
        else:
            raise NotImplementedError("Like now I can retrieve the files on recvq dir")
        
        conn.addCallback(self._RetRetrFile, proto, *args, **kw)
        conn.addErrback(self._Fail)
    
    def SendFax(self, fax, callback=None):
        """ Send the fax passed. fax must be a SendFax instance
            For make the work, we convert and stor the file into ftp server.
            @see: _SendFax_Conversion and the rest for more info
        """

        if not isinstance(fax, SendFax):
            raise ValueError, "The fax passed aren't a SendFax istance!"
        
        #create a copy for every destination and send them one at a time
        for fax_ds in fax.dialstring:
            
            fax_copied = copy.copy(fax)
            fax_copied.dialstring = fax_ds
                
            self.queue_send.append(fax_copied)
            
        self._on_sending = False
        
        #and call the process
        reactor.callLater(0.1, self._SendFax,callback)

    def SuspendJob(self, jobid):
        """ Suspend a job
        """
        self._sendCommandList( 'JOB %s' % jobid, 'JSUSP' )
        self._get_current_fetch()()
    
    def DeleteJob(self, jobid):
        """ Delete the job
        """
        cmdLst = []
        
        if jobid.startswith('fax'):
            cmdLst.append('DELE recvq/%s' % jobid)
        else:
            cmdLst.append('JOB %s' % jobid)
            cmdLst.append('JDELE')
        
        self._sendCommandList(cmdLst)
        self._get_current_fetch()()
    
    def AlterJob(self, jobid, paramters):
        """ Alter the job
        """
        self.SuspendJob(jobid)

        cmdList = list()
        cmdList.append('JOB %s' % jobid)
        
        for k, value in paramters.iteritems():
            cmdList.append( 'JPARM %s %s' % (k, value) )
        
        cmdList.append('JSUBM')
        
        self._sendCommandList(cmdList)

    def UpdateStatus(self):
        """ Call only the update of the status queue
        """
        self._get_current_fetch()(onlyStatus=True)

    def UpdateAll(self, resetTime=None):
        """ Force the update of the queue before the time has passed
        """
        if resetTime == None: resetTime = True
        
        if self._delayCall and self._delayCall.active() and resetTime:
            #Reset the timer, so it not will be call when I already receiving data
            self._delayCall.reset(self._timeUpdate)
        self._get_current_fetch()()
    
    def FakeUpdate(self):
        """ Call a not "true" update. Need when you want to say me to call the 
            update callbaack
        """
        self._RetrAll()
    
    #
    # Send fax helps
    #
    
    def _SendFax(self, callback):
        """ Internal send fax
        """
        if self._hClient.actionQueue or self._on_sending:
            #If there are other commands or other sending fax, wait for them
            reactor.callLater(0.1, self._SendFax, callback)
            return
        else:
            if not self.queue_send:
                if callable(callback):
                    reactor.callLater(0, callback)
                return
            
            self._on_sending = True
            
            #Return for see if all are end
            reactor.callLater(0.1, self._SendFax, callback)
            
            fax = self.queue_send.pop()
        
        if self._debug1: self._Debug("HP:Start send fax")
        if self._debug2: self._Debug(fax)

        if fax.convert:
           d = threads.deferToThread(self._SendFax_Conversion, fax)
           d.addCallback(self._SendFax_EndConversion, fax)
           d.addErrback(self._Fail)
        else:
           self._SendFax_EndConversion(fax.file_list[0], fax)


        

    def _SendFax_Conversion(self, fax):
        """ Start the file conversion
        """
        if self._debug1: self._Debug("HP:Start conversion")

        #Create a new hylaimage instance
        hi = hylaimage.Hylaimage(path_gs_exe=fax.gspath, 
             debug=self._debug, debug_funct=self.debugFunct)
        hi.DeleteFiles()

        #add the files
        hi.AddFile( fax.file_list )

        return hi.GetSingleImage()
    
    def _SendFax_EndConversion(self, filename, fax):
        """ Conversion are end. Say to hylafax that we want to 
            open a channel for send the file
        """
        if self._debug1: self._Debug("HP:End conversion. File path: ", filename)
            
        d_start, d_end = self._hClient.storeFileT()
        
        def create_store(channel):
            d_store = threads.deferToThread( self._SendFax_Store, channel, filename)
            d_store.addErrback(self._Fail)
        

        d_start.addCallback(create_store)
        d_start.addErrback(self._Fail)

        d_end.addCallback(self._SendFax_EndStore, fax)
        d_end.addErrback(self._Fail)
        
        return d_end
        
    def _SendFax_Store(self, channel, filename):
        """ Now store the file
        """
        if self._debug1: self._Debug("HP:Start store file (fax) to the server")
        
        f = open(filename, 'rb')
        
        while True:
            buff = f.read(self.chunk_size_send)
            if not buff: break
            channel.write(buff)
            if self._debug3: self._Debug("HP:i sent", self.chunk_size_send)
        
        channel.finish()
        
    def _SendFax_EndStore(self, ret, fax):
        """
        """
        try:
            start, end = ret[0][1][0][1]
            if not end.startswith('226'): raise
            filepath = start.split()[2]
        except:
            raise ValueError, "Response are not on the form that I expect: %s" % pprint.pformat(ret)
        
        if self._debug1: self._Debug("HP:Send the fax parameter to the server")
        
        cmds = ['JOB DEFAULT', 'JNEW']
        
        for k, v in fax.GetSendValues(("file_list", "dialstring")).iteritems():
            cmds.append("JPARM %s %s" % (k, v) )
            
            if self._debug2: self._Debug("HP:Parameter %s: %s" % (k, v))
        
        cmds.append('JPARM dialstring "%s"' % fax.dialstring[0])
        cmds.append('JPARM document %s' % filepath)
        cmds.append('JSUBM')
        
        self._sendCommandList(cmds)
        
        #End the process
        self._on_sending = False
        
        return "Done senfax"
    
    # -- Help methods
    def _CreateFormats(self, onlyFor=None):
        """ Create the formats string from the current order
        """
        if self._startingUp: return
        
        lstActions = list()
        D = self._CreateFDone; S = self._CreateFSend; R = self._CreateFRcv
        if onlyFor == None:
           lstActions = (D, S, R)
        elif onlyFor == DONE_VIEW: lstActions = (D,)
        elif onlyFor == RCV_VIEW: lstActions = (R,)
        elif onlyFor == SEND_VIEW: lstActions = (S,)
        else: raise ValueError

        for action in lstActions:
            action()
    
    #Create the parameters for send to the server
    def _CreateFDone(self):
        self._Fdone = "|".join( [ "%" + H_DONE_F[k] for k in self._orderDone ] )

    def _CreateFSend(self):
        self._Fsend = "|".join( [ "%" + H_SEND_F[k] for k in self._orderSend ] )

    def _CreateFRcv(self):
        self._Frcv = "|".join( [ "%" + H_RCV_F[k] for k in self._orderRcv ] )

    def __SortData(self, data, sortCol, order):
        """ Sort the data passed
        """
        if ( isinstance(sortCol, basestring) and 
                sortCol in order ):
            colOrder = order.index( sortCol )
        elif isinstance(self._sortDone, int):
            colOrder = sortCol
        else:
            raise ValueError, "I need string (that must be into the current order) or integer"
        
        if order[colOrder] == "id":
            def compare(x, y):
                if x.isdigit() and y.isdigit(): f_comp = int
                else: f_comp = str
                return cmp( f_comp(x or 0), f_comp(y or 0))
        else:
            compare = cmp
        
        return sorted(data, cmp=compare, key=itemgetter(colOrder), reverse=self.sortReverse)
    
    def __FilterData(self, data, dFilter, view=-1):
        """ Filter the data by the passed filter
        """
        #Type control
        if not isinstance(dFilter, dict):
            raise ValueError, "Filter must be a dict!"
        
        if "d" in dFilter and dFilter["d"] > 0:
            #control the filter by date
            if view == -1:
                raise ValueError("Date filter must have the view!")
            
            if view == DONE_VIEW and "dat" in DONE_ORDER:
                dat_pos = self._orderDone.index("dat")
            elif view == RCV_VIEW and "dat" in RCV_ORDER:
                dat_pos = self._orderRcv.index("dat")
            else:
                return data
            
            date_filter = time.time() - (dFilter["d"] *24*60*60)
            data_tmp = []
            
            #there is a data, work on it!
            for line in data:
                date_value = line[dat_pos]
                
                if (date_value.count("-") != 2 and date_value.count(":") != 1):
                    #I cannot control non valid data
                    data_tmp.append(line)
                    continue

                if not " " in date_value:
                    #skip strange values
                    data_tmp.append(line)
                    continue

                d_, h_ = date_value.split()
                d,m,y, h,mi = map(int, d_.split("-")  + h_.split(":"))
                sec_line = time.mktime( datetime(y,m,d, h,mi).timetuple() )
                if sec_line > date_filter:
                    data_tmp.append(line)
            
            data = data_tmp

        if "n" in dFilter and dFilter["n"] > 0:
            #Reverse the data. Here we have the old to new, but we
            #want the opposite.
            data.reverse()
            data = data[-dFilter["n"]:]
            
        return data

    def __ChangeData(self):
        """ Change data into the buffer due the specification
        """
        #Receive,  change date
        posId = self._orderRcv.index("img")
        posDate = self._orderRcv.index("dat")
        for data in self._buff_recvA:
            faxId = data[posId]
            if not faxId in self._dateTimeRcv: continue

            data[posDate] = time.strftime( RCV_FORMAT_DATE, self._dateTimeRcv[faxId] )
        
        #Done, change date and other
        posId = self._orderDone.index("id")
        posDate = self._orderDone.index("dat")
        for data in self._buff_doneA:
            if data[posId] in self._lstIdDateChanged: continue
            
            lstOut = []
            date, hour = data[posDate].split(" ", 1)
            
            for i in date.split("/", 2):
                lstOut.append(i)
            for i in hour.split(".", 2):
                lstOut.append(i)                
            
            dateOut = datetime(*map(int, lstOut)).timetuple()
            data[posDate] = time.strftime( RCV_FORMAT_DATE, dateOut )
            
            self._lstIdDateChanged.append( data[posId] )
        
        filterDoneOwn = self._filterDone.get("own", None)
        filterSendOwn = self._filterSend.get("own", None)
        
        #Control if we want to show only the user data
        if filterDoneOwn and "own" in DONE_ORDER:
            pos_own = DONE_ORDER.index("own")
            self._buff_doneA = filter(lambda row: row[pos_own] == self.user,self._buff_doneA)
        
        if filterSendOwn and "own" in SEND_ORDER:
            pos_own = SEND_ORDER.index("own")
            self._buff_sendA = filter(lambda row: row[pos_own] == self.user,self._buff_sendA)
        
        self.__DoAdvancedFilters()
    
    def __ControlStringInside(self, to_control, to_find, case_sensitive):
        """ Control if the string to_find are inside the string st_control
            Make the control lower case, if need
        """
        if not case_sensitive:
            to_find = to_find.lower()
        to_control = map(string.lower, to_control)
        
        for i in to_control:
            if i in to_find: return False
        else: 
            return True
        
    def __DoAdvancedFilters(self):
        """ Make advanced filters, so remove from buffer some data.
        """
        if not self.advancedFilters: return
        case_sensitive = self.advancedFilters.GetCaseSensitive()

        fnv = self.advancedFilters.GetFiltersNotView()
        fov = self.advancedFilters.GetFiltersOnlyView()

        #3 are the views
        for view in xrange(3):
            ov = fov[view]
            nv = fnv[view]
            if not (nv or ov): continue

            if view == DONE_VIEW:
                buff = self._buff_doneA
            elif view == SEND_VIEW:
                buff = self._buff_sendA
            elif view == RCV_VIEW:
                buff = self._buff_recvA

            #Control for the only view
            for col, strOV in ov.iteritems():
                if not strOV: continue
                buff = filter(lambda row:
                            not self.__ControlStringInside(strOV, row[col], case_sensitive),
                            buff)

            #Control for the not view
            for col, strNV in nv.iteritems():
                buff = filter(lambda row:
                            self.__ControlStringInside(strNV, row[col], case_sensitive),
                            buff)
            
            if view == DONE_VIEW:
                self._buff_doneA = buff
            elif view == SEND_VIEW:
                self._buff_sendA = buff
            elif view == RCV_VIEW:
                self._buff_recvA = buff
            
    def _SetFiltersAndOrders(self):
        """ Apply the the filters and the orders to the buffer
        """
        if self._startingUp: return

        if self._sortDone != -1:
            self._buff_doneA = self.__SortData(self._buff_doneR, self._sortDone, self._orderDone)
        else:
            self._buff_doneA = self._buff_doneR[:]
        
        if self._sortRcv != -1:
            self._buff_recvA = self.__SortData(self._buff_recvR, self._sortRcv, self._orderRcv)
        else:
            self._buff_recvA = self._buff_recvR[:]
        
        if self._sortSend != -1:
            self._buff_sendA = self.__SortData(self._buff_sendR, self._sortSend, self._orderSend)
        else:
            self._buff_sendA = self._buff_sendR[:]
        
        try:
            self.__ChangeData()
        except:
            print "Error on __ChangeData"
            traceback.print_exc()
        
        if self.filterDoneActive:
            self._buff_doneA = self.__FilterData(self._buff_doneA, self._filterDone, DONE_VIEW)
        if self.filterRcvActive:
            self._buff_recvA = self.__FilterData(self._buff_recvA, self._filterRcv, RCV_VIEW)
        
        
        
    def _CreateDataSets(self, data):
        """ Create, and return, data lines without separators
        """
        if "|" in data: 
            #Create the right data format
            d = [x.split("|") for x in data.split(LINE_SEP) if x.strip()]
            
        else: d = list()
        return d

    def _SetJFormat(self, view, frmt=None):
        """ Set the job format to the server
        """
        if view == RCV_VIEW: 
            cmd = 'RCVFMT '
            frmt = frmt or self._Frcv
        else: 
            cmd = 'JOBFMT '
            if view == DONE_VIEW:
                frmt = frmt or self._Fdone
            else:
                frmt = frmt or self._Fsend
        
        if not self._hClient.connected:
            self._sendStartupParameters()
            return
        
        return self._hClient.queueStringCommand(cmd + frmt)

    def _getFilterDictByView(self, view):
        """ Get the filter associated by the view
        """
        if view == DONE_VIEW:
            return self.filterDone
        elif view == RCV_VIEW:
            return self.filterRcv
        elif view == SEND_VIEW:
            return self.filterSend
        else:
            raise ValueError

    def _sendCommandList(self, cmdList, *args):
        """ Send command list and after add them the fail deferred
        """
        #Leave the user pass me strings or already tuple/list, but al least one value
        if isinstance(cmdList, basestring):
            cmdList = [cmdList]
        
        for arg in args:
            cmdList.append(arg)
        
        if not self._hClient.connected:
            self._sendStartupParameters()
            return
        
        deferreds = []
        for cmd in cmdList:
            if self._debug3: self._Debug("HP:Send command:", cmd)
            deferreds.append( self._hClient.queueStringCommand(cmd) )
        
        for deferred in deferreds:
            # If something goes wrong, call fail
            deferred.addErrback(self._Fail)
    
    def _get_current_fetch(self):
        """ Return the current fetch method
        """
        try:
            curr_view = self._lst_sequence_fetch_order[self._current_fetch_idx]
            return self._lst_sequence_fetch[curr_view] [0]
        except IndexError:
            #create a null function that do nothing
            def _f(*args, **kw):
                pass
            return _f
    
    def _get_current_fetch_cb(self, sum_=True):
        """ Return the current fetch method
        """
        try:
            curr_view = self._lst_sequence_fetch_order[self._current_fetch_idx]
            
            if sum_:
                self._current_fetch_idx += 1
            
            return self._lst_sequence_fetch[curr_view] [1]
        except:
            def null_funct(*args, **kw):
                pass
            return null_funct
        
    #
    # Debug
    #
    def _init_debug(self):
        """ Make the instance wide variables for debug
        """
        self._debug1 = self._debug > 0
        self._debug2 = self._debug > 1
        self._debug3 = self._debug > 2
        self._debug4 = self._debug > 3
        
    def _SetDebug(self, value):
        self._debug = value
        self._init_debug()
    def _GetDebug(self):
        return self._debug
        
    debug = property(_GetDebug, _SetDebug)

    def _Debug(self, *args, **kw):
        """ Unique debug function.
            If the instancer wants the debug messages, he have to 
            pass me a debug function, otherwise I'll print the message.
            If the debug value are more the 3, I'll print message in
            any case.
        """
        
        msg = ''
        
        for arg in args:
            arg = repr(arg)
            if not arg.endswith(" "): arg += " "
            msg += arg
        
        if kw: msg += pprint.pformat(kw)
            
        if callable(self.debugFunct):
            self.debugFunct(msg)
        
        if not callable(self.debugFunct) or self._debug4:
            print msg
        
    #
    # Properties
    #
    
    def SetMode(self, newMode=None):
        """
        """
        if not self._connected:return
        if newMode: self._mode = newMode
        
        if not self._hClient.connected:
            self._sendStartupParameters()
            return

        return self._hClient.queueStringCommand("MODE %s" % self._mode)
    
    def GetTzone(self):
        """
        """
        return self._tzone        
    
    def SetTzone(self, tzone=None):
        """
        """
        if tzone is not None: self._tzone = tzone
        if isinstance(self._tzone, basestring) and not self._tzone.isdigit():
             raise ValueError("Tzone value must be an integer 0|1")
        elif isinstance(self._tzone, basestring) and self._tzone.isdigit():
            self._tzone = int(self._tzone)

        if not self._tzone in (0,1):
            raise ValueError("Tzone value must be an integer 0|1")

        if not self._connected: return
        if self._tzone == 0: tzoneCmd = 'GMT'
        else: tzoneCmd = 'LOCAL'

        if not self._hClient.connected:
            self._sendStartupParameters()
            return

        return self._hClient.queueStringCommand("TZONE %s" % tzoneCmd)
        
    def GetModems(self):
        """ Return modem list
        """
        
        lstModems = list()
        
        for strModem in self._buff_status.split(LINE_SEP):
            #No modem found
            if not self.mText in strModem: continue
            
            lstM = strModem.split()
            lstModems.append( lstM[lstM.index(self.mText) +1].strip() )
        
        return lstModems
    
    # -- Queues
    def GetQStatus(self):
        """ Status property
        """
        return self._buff_status
    
    def GetQRcvd(self):
        """
        """
        return self._buff_recvA

    def GetQSend(self):
        """
        """
        return self._buff_sendA

    def GetQDone(self):
        """
        """
        return self._buff_doneA
    
    def GetDateTimeRcv(self):
        """
        """
        return self._dateTimeRcv

    # -- CallBacks
    def SetcallBackOnError(self, callBack):
        """
        """
        self._callBackOnError = callBack

    def SetcallBackOnUpdate(self, callBack):
        """
        """
        self._callBackOnUpdate = callBack
    
    def SetcallBackOnStatus(self, callBack):
        """
        """
        self._callBackOnStatus = callBack
    
    # -- Server info
    def GetHost(self):
        """
        """
        return self._host
    
    def SetHost(self, host):
        """
        """
        self._host = str(host)
        self._SendStartupParameters()
        
    def GetUser(self):
        """
        """
        return self._user
    
    def SetUser(self, user):
        """
        """
        self._user = str(user)
        self._SendStartupParameters()

    def GetPasswd(self):
        """
        """
        return self._user
    
    def SetPasswd(self, passwd):
        """
        """
        self._passwd = str(passwd)
        self._SendStartupParameters()

    def GetAdminPasswd(self):
        """
        """
        return self._user
    
    def SetAdminPasswd(self, adminpasswd):
        """
        """
        self._adminpasswd = str(adminpasswd)
        self._SendStartupParameters()
    
    def GetPassive(self):
        """
        """
        return self._passive
    
    def SetPassive(self, passive):
        """
        """
        self._passive = passive
        self._hClient.passive = passive
    
    def GetTimeUpdate(self):
        """ Return the update time
        """
        return self._timeUpdate
        
    def SetTimeUpdate(self, time_sec):
        """ Set the update time. If the time are < 0,
            stop immediatly the timer
        """
        self._timeUpdate = time_sec
        if self._timeUpdate < 0 and self._delayCall and self._delayCall.active():
            self._delayCall.reset(self._timeUpdate)
        elif self._timeUpdate > 0: 
            if self._delayCall and self._delayCall.active():
                #Only update the time, not need to recall
                #wait for the current update and, the next time, set the new seconds
                return
            
            self._delayCall = reactor.callLater(self._timeUpdate, self._get_current_fetch())
            self._delayCall.delay(10)
            reactor.callLater(0, self._get_current_fetch())


    # -- Filters
    def GetFilterDone(self):
        """
        """
        return self._filterDone
        
    def SetFilterDone(self, filterDone):
        """
        """
        self._filterDone = filterDone or {}
        self._SetFiltersAndOrders()
        
    def GetFilterRcv(self):
        """
        """
        return self._filterRcv
        
    def SetFilterRcv(self, filterRcv):
        """
        """
        self._filterRcv = filterRcv or {}
        self._SetFiltersAndOrders()
        
    def GetFilterSend(self):
        """
        """
        return self._filterSend
        
    def SetFilterSend(self, filterSend):
        """
        """
        self._filterSend = filterSend or {}
        self._SetFiltersAndOrders()
        
    # -- Filters
    def GetFilterDoneActive(self):
        """
        """
        return self._filterDoneActive
        
    def SetFilterDoneActive(self, filterDoneActive):
        """
        """
        self._filterDoneActive = filterDoneActive
        self._SetFiltersAndOrders()
        
    def GetFilterRcvActive(self):
        """
        """
        return self._filterRcvActive
        
    def SetFilterRcvActive(self, filterRcvActive):
        """
        """
        self._filterRcvActive = filterRcvActive
        self._SetFiltersAndOrders()
        
    def GetFilterSendActive(self):
        """
        """
        return self._filterSendActive
        
    def SetFilterSendActive(self, filterSendActive):
        """
        """
        self._filterSendActive = filterSendActive
        self._SetFiltersAndOrders()
        
    
    # -- Orders
    def GetOrderDone(self):
        """ Return the done order
        """
        return self._orderDone
        
    def SetOrderDone(self, orderDone):
        """ Set the done order
        """
        self._orderDone = orderDone or DONE_ORDER
        self._CreateFormats(DONE_VIEW)
        self._SetFiltersAndOrders()

    def GetOrderSend(self):
        """
        """
        return self._orderSend

    def SetOrderSend(self, orderSend):
        """
        """
        self._orderSend = orderSend or SEND_ORDER
        self._CreateFormats(SEND_VIEW)
        self._SetFiltersAndOrders()

    def GetOrderRcv(self):
        """
        """
        return self._orderRcv

    def SetOrderRcv(self, orderRcv):
        """
        """
        self._orderRcv = orderRcv or RCV_ORDER
        self._CreateFormats(RCV_VIEW)
        self._SetFiltersAndOrders()
        
    # -- Sort
    
    def GetSortDone(self):
        """
        """
        return self._sortDone
    
    def SetSortDone(self, sortDone):
        """
        """
        self._sortDone= sortDone or 0

    def GetSortRcv(self):
        """
        """
        return self._sortRcv
    
    def SetSortRcv(self, sortRcv):
        """
        """
        self._sortRcv = sortRcv or 0

    def GetSortSend(self):
        """
        """
        return self._sortSend
    
    def SetSortSend(self, sortSend):
        """
        """
        self._sortSend = sortSend or 0
    
    def GetHClient(self):
        """ Return the hylafax client connection
            Use it at your own risk!
        """
        return self._hClient
    #
    # Debug functions
    #

    def _timePassed(self):
        """
        """
        print "passed 0.2"
        reactor.callLater(0.2, self._timePassed)
    
    #
    # Property
    #
    
    host = property(GetHost, SetHost)
    user = property(GetUser, SetUser)
    passwd = property(GetPasswd, SetPasswd)
    adminpasswd = property(GetAdminPasswd, SetAdminPasswd)
    passive = property(GetPassive, SetPassive)
    tzone = property(GetTzone, SetTzone)
    
    status = property(GetQStatus)
    modems = property(GetModems)
    
    timeUpdate = property(GetTimeUpdate, SetTimeUpdate)
    
    qDone = property(GetQDone)
    qRcv = property(GetQRcvd)
    qSend = property(GetQSend)

    dateTimeRcv = property(GetDateTimeRcv)
    
    callBackOnUpdate = property(fset=SetcallBackOnUpdate)
    callBackOnError = property(fset=SetcallBackOnError)
    callBackOnStatus = property(fset=SetcallBackOnStatus)
    
    filterSend = property(GetFilterSend, SetFilterSend)
    filterDone = property(GetFilterDone, SetFilterDone)
    filterRcv = property(GetFilterRcv, SetFilterRcv)
    
    orderSend = property(GetOrderSend, SetOrderSend)
    orderDone = property(GetOrderDone, SetOrderDone)
    orderRcv = property(GetOrderRcv, SetOrderRcv)
    
    sortSend = property(GetSortSend, SetSortSend)
    sortDone = property(GetSortDone, SetSortDone)
    sortRcv = property(GetSortRcv, SetSortRcv)
    
    filterDoneActive = property(GetFilterDoneActive, SetFilterDoneActive)
    filterRcvActive = property(GetFilterRcvActive, SetFilterRcvActive)
    filterSendActive = property(GetFilterSendActive, SetFilterSendActive)

    hylafax_client = property(GetHClient)
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.