Exemplo n.º 1
0
    def afterInit(self):
        self.messageIn = None  # Last AFTN message received
        self.messageOut = None # Last AFTN message sent
        self.fromDisk = True   # Changed to False for Service Message created on the fly
        self.filenameToSend = None  # Filename of the file we want to send or just sent
        self.filenameToErase = None # Path + filename of the file we want to erase (ack just received) 

        self.type = None       # Message type. Value must be in ['AFTN', 'SVC', 'RF', 'RQ', 'PRI_DESTADD_TEXT', None]
        self.header = None     # Message WMO Header
        self.priority = None   # Priority indicator (SS, DD, FF, GG or KK)
        self.destAddress = []  # 8-letter group, max. 21 addresses
        self.CSNJustReset = False 
        try:
            self.CSN = self.state.CSN
            self.logger.info("CSN (%s) has been taken from AFTN State" % self.CSN)
        except: 
            self.CSN = '0000'      # Channel sequence number, 4 digits (ex: 0003)
        self.filingTime = None # 6-digits DDHHMM (ex:140335) indicating date and time of filing the message for transmission.
        self.dateTime = None   # 8-digits DDHHMMSS (ex:14033608)
        self.readBuffer = ''   # Buffer where we put stuff read from the socket
        
        # Queueing Service Messages when waiting for an ack before sending
        self.serviceQueue = []

        # Big message support (sending)
        self.partsToSend = []                       # Text parts of the broken message
        self.numberOfParts = len(self.partsToSend)  # Number of parts in which a long message has been divided.
        self.nextPart = 0                           # Always 0 for message that are not bigger than the defined max. 

        # Big message support (receiving)
        self.receivedParts = []
        self.notCompletelyReceived = False
        self.generalPartsRegex = re.compile(r"//END PART \d\d//")
        self.lastPartRegex = re.compile(r"//END PART \d\d/\d\d//")

        # Ack support (ack we receive because of the message we have sent)
        try:
            self.lastAckReceived = self.state.lastAckReceived  
            self.logger.info("lastAckReceived (%s) has been taken from AFTN State" % self.lastAckReceived)

            self.waitingForAck = self.state.waitingForAck 
            self.logger.info("waitingForAck (%s) has been taken from AFTN State" % self.waitingForAck)
        except:
            self.lastAckReceived = None   # None or the transmitID
            self.waitingForAck = None     # None or the transmitID 

        self.sendingInfos = (0, None) # Number of times a message has been sent and the sending time.
        self.maxAckTime =  self.sourlient.maxAckTime  # Maximum time (in seconds) we wait for an ack, before resending.
        self.maxSending = 1   # Maximum number of sendings of a message
        self.ackUsed =  self.sourlient.ackUsed  # We can use ack or not (testing purposes only)
        self.totAck = 0       # Count the number of ack (testing purpose only)

        # CSN verification (receiving)
        try:
            self.waitedTID = self.state.waitedTID
        except:
            self.waitedTID = self.otherStationID + '0001'  # Initially (when the program start) we are not sure what TID is expected
            

        # Functionnality testing switches
        self.resendSameMessage = True

        # Read Buffer management
        self.unusedBuffer = ''        # Part of the buffer that was not used

        # Persistent state
        min = 60
        now = time.mktime(time.gmtime())

        if self.subscriber:
            try:
                lastUpdate = os.stat(AFTNPaths.STATE)[8]
                diff = now - lastUpdate
                if diff < 60 * min:
                    self.state = self.unarchiveObject(AFTNPaths.STATE)
                    self.updateFromState(self.state)
                else: 
                    self.logger.warning("Archive state not read because too old (%i minutes)" % int(diff/60))
                    raise
            except:
                self.state = StateAFTN()
                self.state.fill(self)
                self.archiveObject(AFTNPaths.STATE, self.state)
        else:
            try:
                self.state = self.unarchiveObject(AFTNPaths.STATE)
                self.updateFromState(self.state)
            except:
                self.state = StateAFTN()
                self.state.fill(self)
                self.archiveObject(AFTNPaths.STATE, self.state)
Exemplo n.º 2
0
    def afterInit(self):
        self.messageIn = None  # Last AFTN message received
        self.messageOut = None  # Last AFTN message sent
        self.fromDisk = True  # Changed to False for Service Message created on the fly
        self.filenameToSend = None  # Filename of the file we want to send or just sent
        self.filenameToErase = None  # Path + filename of the file we want to erase (ack just received)

        self.type = None  # Message type. Value must be in ['AFTN', 'SVC', 'RF', 'RQ', 'PRI_DESTADD_TEXT', None]
        self.header = None  # Message WMO Header
        self.priority = None  # Priority indicator (SS, DD, FF, GG or KK)
        self.destAddress = []  # 8-letter group, max. 21 addresses
        self.CSNJustReset = False
        try:
            self.CSN = self.state.CSN
            self.logger.info("CSN (%s) has been taken from AFTN State" %
                             self.CSN)
        except:
            self.CSN = '0000'  # Channel sequence number, 4 digits (ex: 0003)
        self.filingTime = None  # 6-digits DDHHMM (ex:140335) indicating date and time of filing the message for transmission.
        self.dateTime = None  # 8-digits DDHHMMSS (ex:14033608)
        self.readBuffer = ''  # Buffer where we put stuff read from the socket

        # Queueing Service Messages when waiting for an ack before sending
        self.serviceQueue = []

        # Big message support (sending)
        self.partsToSend = []  # Text parts of the broken message
        self.numberOfParts = len(
            self.partsToSend
        )  # Number of parts in which a long message has been divided.
        self.nextPart = 0  # Always 0 for message that are not bigger than the defined max.

        # Big message support (receiving)
        self.receivedParts = []
        self.notCompletelyReceived = False
        self.generalPartsRegex = re.compile(r"//END PART \d\d//")
        self.lastPartRegex = re.compile(r"//END PART \d\d/\d\d//")

        # Ack support (ack we receive because of the message we have sent)
        try:
            self.lastAckReceived = self.state.lastAckReceived
            self.logger.info(
                "lastAckReceived (%s) has been taken from AFTN State" %
                self.lastAckReceived)

            self.waitingForAck = self.state.waitingForAck
            self.logger.info(
                "waitingForAck (%s) has been taken from AFTN State" %
                self.waitingForAck)
        except:
            self.lastAckReceived = None  # None or the transmitID
            self.waitingForAck = None  # None or the transmitID

        self.sendingInfos = (
            0, None
        )  # Number of times a message has been sent and the sending time.
        self.maxAckTime = self.sourlient.maxAckTime  # Maximum time (in seconds) we wait for an ack, before resending.
        self.maxSending = 1  # Maximum number of sendings of a message
        self.ackUsed = self.sourlient.ackUsed  # We can use ack or not (testing purposes only)
        self.totAck = 0  # Count the number of ack (testing purpose only)

        # CSN verification (receiving)
        try:
            self.waitedTID = self.state.waitedTID
        except:
            self.waitedTID = self.otherStationID + '0001'  # Initially (when the program start) we are not sure what TID is expected

        # Functionnality testing switches
        self.resendSameMessage = True

        # Read Buffer management
        self.unusedBuffer = ''  # Part of the buffer that was not used

        # Persistent state
        min = 60
        now = time.mktime(time.gmtime())

        if self.subscriber:
            try:
                lastUpdate = os.stat(AFTNPaths.STATE)[8]
                diff = now - lastUpdate
                if diff < 60 * min:
                    self.state = self.unarchiveObject(AFTNPaths.STATE)
                    self.updateFromState(self.state)
                else:
                    self.logger.warning(
                        "Archive state not read because too old (%i minutes)" %
                        int(diff / 60))
                    raise
            except:
                self.state = StateAFTN()
                self.state.fill(self)
                self.archiveObject(AFTNPaths.STATE, self.state)
        else:
            try:
                self.state = self.unarchiveObject(AFTNPaths.STATE)
                self.updateFromState(self.state)
            except:
                self.state = StateAFTN()
                self.state.fill(self)
                self.archiveObject(AFTNPaths.STATE, self.state)
Exemplo n.º 3
0
class MessageManager:

    """
    A typical message:

    <SOH> ABC0003 14033608<CR><LF>                               <-- Heading line
    GG CYYCYFYX EGLLZRZX<CR><LF>                                 <-- Destination address line
    140335 CYEGYFYX<CR><LF>                                      <-- Origin address line

    <STX>040227 NOTAMN CYYC CALGARY INTL<CR><LF>                 <-- Start of text signal (<STX>)
    CYYC ILS 16 AND 34 U/S 0409141530<CR><LF>                    <-- Message text
    TIL 0409141800<CR><LF>

    <VT><ETX>                                                    <-- End of message signal

    """

    def __init__(self, logger=None, sourlient=None, reloadMode=False):
        
        AFTNPaths.normalPaths(sourlient.name)
        PXPaths.normalPaths()

        self.logger = logger         # Logger object
        self.sourlient = sourlient   # Sourlient object

        self.name = sourlient.name                       # Transceiver's name
        self.stationID = sourlient.stationID             # Value read from config. file
        self.otherStationID = sourlient.otherStationID   # Provider (MHS) Station ID
        self.address = sourlient.address                 # 8-letter group identifying the message originator (CYHQUSER)
        self.otherAddress = sourlient.otherAddress       # 8-letter group identifying the provider's address (CYHQMHSN)
        self.routingTable = sourlient.routingTable       # Routing table name
        self.subscriber = sourlient.subscriber           # Boolean indicating if this is a subscriber or a provider

        self.bullManager = bulletinManager(PXPaths.RXQ + self.name,
                                      self.logger,
                                      PXPaths.RXQ + self.name,
                                      9999,
                                      '\n',
                                      self.sourlient.extension,
                                      self.routingTable, 
                                      None,
                                      self.sourlient,
                                      True) 

        self.drp = self.bullManager.drp
        self.sp = StationParser(PXPaths.STATION_TABLE, logger)
        self.sp.parse()
        self.priorities = {'1':'FF', '2':'FF', '3':'GG', '4':'GG', '5':'GG'}

        if not reloadMode:
            self.afterInit()

    def afterInit(self):
        self.messageIn = None  # Last AFTN message received
        self.messageOut = None # Last AFTN message sent
        self.fromDisk = True   # Changed to False for Service Message created on the fly
        self.filenameToSend = None  # Filename of the file we want to send or just sent
        self.filenameToErase = None # Path + filename of the file we want to erase (ack just received) 

        self.type = None       # Message type. Value must be in ['AFTN', 'SVC', 'RF', 'RQ', 'PRI_DESTADD_TEXT', None]
        self.header = None     # Message WMO Header
        self.priority = None   # Priority indicator (SS, DD, FF, GG or KK)
        self.destAddress = []  # 8-letter group, max. 21 addresses
        self.CSNJustReset = False 
        try:
            self.CSN = self.state.CSN
            self.logger.info("CSN (%s) has been taken from AFTN State" % self.CSN)
        except: 
            self.CSN = '0000'      # Channel sequence number, 4 digits (ex: 0003)
        self.filingTime = None # 6-digits DDHHMM (ex:140335) indicating date and time of filing the message for transmission.
        self.dateTime = None   # 8-digits DDHHMMSS (ex:14033608)
        self.readBuffer = ''   # Buffer where we put stuff read from the socket
        
        # Queueing Service Messages when waiting for an ack before sending
        self.serviceQueue = []

        # Big message support (sending)
        self.partsToSend = []                       # Text parts of the broken message
        self.numberOfParts = len(self.partsToSend)  # Number of parts in which a long message has been divided.
        self.nextPart = 0                           # Always 0 for message that are not bigger than the defined max. 

        # Big message support (receiving)
        self.receivedParts = []
        self.notCompletelyReceived = False
        self.generalPartsRegex = re.compile(r"//END PART \d\d//")
        self.lastPartRegex = re.compile(r"//END PART \d\d/\d\d//")

        # Ack support (ack we receive because of the message we have sent)
        try:
            self.lastAckReceived = self.state.lastAckReceived  
            self.logger.info("lastAckReceived (%s) has been taken from AFTN State" % self.lastAckReceived)

            self.waitingForAck = self.state.waitingForAck 
            self.logger.info("waitingForAck (%s) has been taken from AFTN State" % self.waitingForAck)
        except:
            self.lastAckReceived = None   # None or the transmitID
            self.waitingForAck = None     # None or the transmitID 

        self.sendingInfos = (0, None) # Number of times a message has been sent and the sending time.
        self.maxAckTime =  self.sourlient.maxAckTime  # Maximum time (in seconds) we wait for an ack, before resending.
        self.maxSending = 1   # Maximum number of sendings of a message
        self.ackUsed =  self.sourlient.ackUsed  # We can use ack or not (testing purposes only)
        self.totAck = 0       # Count the number of ack (testing purpose only)

        # CSN verification (receiving)
        try:
            self.waitedTID = self.state.waitedTID
        except:
            self.waitedTID = self.otherStationID + '0001'  # Initially (when the program start) we are not sure what TID is expected
            

        # Functionnality testing switches
        self.resendSameMessage = True

        # Read Buffer management
        self.unusedBuffer = ''        # Part of the buffer that was not used

        # Persistent state
        min = 60
        now = time.mktime(time.gmtime())

        if self.subscriber:
            try:
                lastUpdate = os.stat(AFTNPaths.STATE)[8]
                diff = now - lastUpdate
                if diff < 60 * min:
                    self.state = self.unarchiveObject(AFTNPaths.STATE)
                    self.updateFromState(self.state)
                else: 
                    self.logger.warning("Archive state not read because too old (%i minutes)" % int(diff/60))
                    raise
            except:
                self.state = StateAFTN()
                self.state.fill(self)
                self.archiveObject(AFTNPaths.STATE, self.state)
        else:
            try:
                self.state = self.unarchiveObject(AFTNPaths.STATE)
                self.updateFromState(self.state)
            except:
                self.state = StateAFTN()
                self.state.fill(self)
                self.archiveObject(AFTNPaths.STATE, self.state)

    def resetCSN(self):
        hhmm = dateLib.getTodayFormatted('%H%M')
        hh = hhmm[:2]
        mm = hhmm[2:]

        if hh == '00' and mm <= '05' and not self.CSNJustReset:
            self.CSN = '0000'
            self.CSNJustReset = True
            self.logger.info('CSN has been reset to 0001')
        elif mm > '05':
            self.CSNJustReset = False
        
    def updateFromState(self, state):
        self.CSN = state.CSN
        self.waitedTID = state.waitedTID

        self.lastAckReceived = state.lastAckReceived
        self.waitingForAck = state.waitingForAck
    
    def ingest(self, bulletin):
        self.bullManager.writeBulletinToDisk(bulletin)

    def completeHeader(self, message):
        import dateLib
        wmoMessage = ''
        theHeader = ''
        allLines = []
        # We remove blank lines
        for  line in message.textLines:
            if line:
                allLines.append(line)
        
        # We don't have enough lines
        if len(allLines) < 2:
            return ['\n'.join(message.textLines) + '\n']

        messageType = allLines[0][:2]
        station = allLines[1].split()[0]

        headers = self.sp.headers.get(station, [])
        for header in headers:
            if header[:2] == messageType:
                theHeader = header

        if theHeader:
            BBB = ''
            firstLine = allLines[0].split()
            timestamp = firstLine[1]
            if len(firstLine) >= 3:
                BBB = firstLine[2]

            self.logger.debug("Type: %s, Station: %s, Headers: %s, TheHeader: %s, Timestamp: %s, BBB = %s" % (messageType, station, headers, theHeader, timestamp, BBB))
            allLines[0] = theHeader + ' ' + timestamp
            if BBB:
                allLines[0] += ' ' + BBB
            allLines.insert(1, 'AAXX ' + timestamp[:4] + '4')
        else:
            return ['\n'.join(message.textLines) + '\n']
            
        return ['\n'.join(allLines) + '\n']

    def addHeaderToMessage(self, message, textLines=None):
        """
        When no WMO header is present in the text part of an AFTN Message, we will create one 
        for each destination address in the message.
        ex: if self.drp.aftnMap['CWAOWXYZ'] == 'SACN32', the header will be 'SACN32 CWAO YYGGgg'
        where YY= day of the month, GG=hours and gg=minutes
        This method is only used at reception.

        textLines is not None for big messages (text is not in the message, but in a supplementary 
        variable.
        """
        import dateLib
        wmoMessages = []
        addresses = message.destAddress
        default = self.drp.aftnMap.get('DEFAULT')
        timestamp = dateLib.getYYGGgg()

        destLine = message.createDestinationAddressLine().strip() 
        originLine = message.createOriginAddressLine().strip() 

        destOriginLines = [destLine, originLine]

        self.logger.debug("Addresses: %s" % addresses)

        for address in addresses:
            header = self.drp.aftnMap.get(address, default) + " " + address[0:4] + " " + timestamp
            headerBlock = [header] + destOriginLines

            #self.logger.info("Header in addHeader: %s" % header)
            if textLines:
                wmoMessages.append('\n'.join(headerBlock + textLines) + '\n')
            else:
                wmoMessages.append('\n'.join(headerBlock + message.textLines) + '\n')
        return wmoMessages

    def doSpecialOrders(self, path):
        # Stop, restart, reload, deconnect, connect could be put here?
        reader = DiskReader(path)
        reader.read()
        dataFromFiles = reader.getFilenamesAndContent()
        for index in range(len(dataFromFiles)): 
            words = dataFromFiles[index][0].strip().split() 
            self.logger.info("Special Order: %s" % (dataFromFiles[index][0].strip()))

            if words[0] == 'outCSN':
                if words[1] == '+':
                    self.nextCSN()
                    self.logger.info("CSN = %s" % self.CSN)
                elif words[1] == '-':
                    # This case is only done for testing purpose. It is not complete and not correct when CSN 
                    # value is 0 or 1
                    self.nextCSN(str(int(self.CSN) - 2))
                    self.logger.info("CSN = %s" % self.CSN)
                elif words[1] == 'print':
                    self.logger.info("CSN = %s" % self.CSN)
                else:
                    # We suppose it's a number, we don't verify!!
                    self.nextCSN(words[1])
                    self.logger.info("CSN = %s" % self.CSN)

            elif words[0] == 'inCSN':
                if words[1] == '+':
                    self.calcWaitedTID(self.waitedTID)
                    self.logger.info("Waited TID = %s" % self.waitedTID)
                elif words[1] == '-':
                    # This case is only done for testing purpose. It is not complete and not correct when waited TID
                    # value is 0 or 1
                    self.calcWaitedTID(self.otherStationID + "%04d" % (int(self.waitedTID[3:]) - 2))
                    self.logger.info("Waited TID = %s" % self.waitedTID)
                elif words[1] == 'print':
                    self.logger.info("Waited TID = %s" % self.waitedTID)
                else:
                    # We suppose it's a number, we don't verify!!
                    self.calcWaitedTID(self.otherStationID + "%04d" % int(words[1]))
                    self.logger.info("Waited TID = %s" % self.waitedTID)

            elif words[0] == 'ackWaited':
                if words[1] == 'print':
                    self.logger.info("Waiting for ack: %s" % self.getWaitingForAck())
                else:
                    self.setWaitingForAck(words[1])
                    self.incrementSendingInfos()
            elif words[0] == 'ackNotWaited':
                self.setWaitingForAck(None)
                self.resetSendingInfos()
                self.updatePartsToSend()
            elif words[0] == 'ackUsed':
                self.ackUsed = words[1] == 'True' or words[1] == 'true'
            elif words[0] == 'printState':
                self.logger.info(self.state.infos()) 
            else:
                pass

            try:
                os.unlink(dataFromFiles[0][1])
                self.logger.debug("%s has been erased", os.path.basename(dataFromFiles[index][1]))
            except OSError, e:
                (type, value, tb) = sys.exc_info()
                self.logger.error("Unable to unlink %s ! Type: %s, Value: %s" % (dataFromFiles[index][1], type, value))
Exemplo n.º 4
0
class MessageManager:
    """
    A typical message:

    <SOH> ABC0003 14033608<CR><LF>                               <-- Heading line
    GG CYYCYFYX EGLLZRZX<CR><LF>                                 <-- Destination address line
    140335 CYEGYFYX<CR><LF>                                      <-- Origin address line

    <STX>040227 NOTAMN CYYC CALGARY INTL<CR><LF>                 <-- Start of text signal (<STX>)
    CYYC ILS 16 AND 34 U/S 0409141530<CR><LF>                    <-- Message text
    TIL 0409141800<CR><LF>

    <VT><ETX>                                                    <-- End of message signal

    """
    def __init__(self, logger=None, sourlient=None, reloadMode=False):

        AFTNPaths.normalPaths(sourlient.name)
        PXPaths.normalPaths()

        self.logger = logger  # Logger object
        self.sourlient = sourlient  # Sourlient object

        self.name = sourlient.name  # Transceiver's name
        self.stationID = sourlient.stationID  # Value read from config. file
        self.otherStationID = sourlient.otherStationID  # Provider (MHS) Station ID
        self.address = sourlient.address  # 8-letter group identifying the message originator (CYHQUSER)
        self.otherAddress = sourlient.otherAddress  # 8-letter group identifying the provider's address (CYHQMHSN)
        self.routingTable = sourlient.routingTable  # Routing table name
        self.subscriber = sourlient.subscriber  # Boolean indicating if this is a subscriber or a provider

        self.bullManager = bulletinManager(PXPaths.RXQ + self.name,
                                           self.logger,
                                           PXPaths.RXQ + self.name, 9999, '\n',
                                           self.sourlient.extension,
                                           self.routingTable, None,
                                           self.sourlient, True)

        self.drp = self.bullManager.drp
        self.sp = StationParser(PXPaths.STATION_TABLE, logger)
        self.sp.parse()
        self.priorities = {
            '1': 'FF',
            '2': 'FF',
            '3': 'GG',
            '4': 'GG',
            '5': 'GG'
        }

        if not reloadMode:
            self.afterInit()

    def afterInit(self):
        self.messageIn = None  # Last AFTN message received
        self.messageOut = None  # Last AFTN message sent
        self.fromDisk = True  # Changed to False for Service Message created on the fly
        self.filenameToSend = None  # Filename of the file we want to send or just sent
        self.filenameToErase = None  # Path + filename of the file we want to erase (ack just received)

        self.type = None  # Message type. Value must be in ['AFTN', 'SVC', 'RF', 'RQ', 'PRI_DESTADD_TEXT', None]
        self.header = None  # Message WMO Header
        self.priority = None  # Priority indicator (SS, DD, FF, GG or KK)
        self.destAddress = []  # 8-letter group, max. 21 addresses
        self.CSNJustReset = False
        try:
            self.CSN = self.state.CSN
            self.logger.info("CSN (%s) has been taken from AFTN State" %
                             self.CSN)
        except:
            self.CSN = '0000'  # Channel sequence number, 4 digits (ex: 0003)
        self.filingTime = None  # 6-digits DDHHMM (ex:140335) indicating date and time of filing the message for transmission.
        self.dateTime = None  # 8-digits DDHHMMSS (ex:14033608)
        self.readBuffer = ''  # Buffer where we put stuff read from the socket

        # Queueing Service Messages when waiting for an ack before sending
        self.serviceQueue = []

        # Big message support (sending)
        self.partsToSend = []  # Text parts of the broken message
        self.numberOfParts = len(
            self.partsToSend
        )  # Number of parts in which a long message has been divided.
        self.nextPart = 0  # Always 0 for message that are not bigger than the defined max.

        # Big message support (receiving)
        self.receivedParts = []
        self.notCompletelyReceived = False
        self.generalPartsRegex = re.compile(r"//END PART \d\d//")
        self.lastPartRegex = re.compile(r"//END PART \d\d/\d\d//")

        # Ack support (ack we receive because of the message we have sent)
        try:
            self.lastAckReceived = self.state.lastAckReceived
            self.logger.info(
                "lastAckReceived (%s) has been taken from AFTN State" %
                self.lastAckReceived)

            self.waitingForAck = self.state.waitingForAck
            self.logger.info(
                "waitingForAck (%s) has been taken from AFTN State" %
                self.waitingForAck)
        except:
            self.lastAckReceived = None  # None or the transmitID
            self.waitingForAck = None  # None or the transmitID

        self.sendingInfos = (
            0, None
        )  # Number of times a message has been sent and the sending time.
        self.maxAckTime = self.sourlient.maxAckTime  # Maximum time (in seconds) we wait for an ack, before resending.
        self.maxSending = 1  # Maximum number of sendings of a message
        self.ackUsed = self.sourlient.ackUsed  # We can use ack or not (testing purposes only)
        self.totAck = 0  # Count the number of ack (testing purpose only)

        # CSN verification (receiving)
        try:
            self.waitedTID = self.state.waitedTID
        except:
            self.waitedTID = self.otherStationID + '0001'  # Initially (when the program start) we are not sure what TID is expected

        # Functionnality testing switches
        self.resendSameMessage = True

        # Read Buffer management
        self.unusedBuffer = ''  # Part of the buffer that was not used

        # Persistent state
        min = 60
        now = time.mktime(time.gmtime())

        if self.subscriber:
            try:
                lastUpdate = os.stat(AFTNPaths.STATE)[8]
                diff = now - lastUpdate
                if diff < 60 * min:
                    self.state = self.unarchiveObject(AFTNPaths.STATE)
                    self.updateFromState(self.state)
                else:
                    self.logger.warning(
                        "Archive state not read because too old (%i minutes)" %
                        int(diff / 60))
                    raise
            except:
                self.state = StateAFTN()
                self.state.fill(self)
                self.archiveObject(AFTNPaths.STATE, self.state)
        else:
            try:
                self.state = self.unarchiveObject(AFTNPaths.STATE)
                self.updateFromState(self.state)
            except:
                self.state = StateAFTN()
                self.state.fill(self)
                self.archiveObject(AFTNPaths.STATE, self.state)

    def resetCSN(self):
        hhmm = dateLib.getTodayFormatted('%H%M')
        hh = hhmm[:2]
        mm = hhmm[2:]

        if hh == '00' and mm <= '05' and not self.CSNJustReset:
            self.CSN = '0000'
            self.CSNJustReset = True
            self.logger.info('CSN has been reset to 0001')
        elif mm > '05':
            self.CSNJustReset = False

    def updateFromState(self, state):
        self.CSN = state.CSN
        self.waitedTID = state.waitedTID

        self.lastAckReceived = state.lastAckReceived
        self.waitingForAck = state.waitingForAck

    def ingest(self, bulletin):
        self.bullManager.writeBulletinToDisk(bulletin)

    def completeHeader(self, message):
        import dateLib
        wmoMessage = ''
        theHeader = ''
        allLines = []
        # We remove blank lines
        for line in message.textLines:
            if line:
                allLines.append(line)

        # We don't have enough lines
        if len(allLines) < 2:
            return ['\n'.join(message.textLines) + '\n']

        messageType = allLines[0][:2]
        station = allLines[1].split()[0]

        headers = self.sp.headers.get(station, [])
        for header in headers:
            if header[:2] == messageType:
                theHeader = header

        if theHeader:
            BBB = ''
            firstLine = allLines[0].split()
            timestamp = firstLine[1]
            if len(firstLine) >= 3:
                BBB = firstLine[2]

            self.logger.debug(
                "Type: %s, Station: %s, Headers: %s, TheHeader: %s, Timestamp: %s, BBB = %s"
                % (messageType, station, headers, theHeader, timestamp, BBB))
            allLines[0] = theHeader + ' ' + timestamp
            if BBB:
                allLines[0] += ' ' + BBB
            allLines.insert(1, 'AAXX ' + timestamp[:4] + '4')
        else:
            return ['\n'.join(message.textLines) + '\n']

        return ['\n'.join(allLines) + '\n']

    def addHeaderToMessage(self, message, textLines=None):
        """
        When no WMO header is present in the text part of an AFTN Message, we will create one 
        for each destination address in the message.
        ex: if self.drp.aftnMap['CWAOWXYZ'] == 'SACN32', the header will be 'SACN32 CWAO YYGGgg'
        where YY= day of the month, GG=hours and gg=minutes
        This method is only used at reception.

        textLines is not None for big messages (text is not in the message, but in a supplementary 
        variable.
        """
        import dateLib
        wmoMessages = []
        addresses = message.destAddress
        default = self.drp.aftnMap.get('DEFAULT')
        timestamp = dateLib.getYYGGgg()

        destLine = message.createDestinationAddressLine().strip()
        originLine = message.createOriginAddressLine().strip()

        destOriginLines = [destLine, originLine]

        self.logger.debug("Addresses: %s" % addresses)

        for address in addresses:
            header = self.drp.aftnMap.get(
                address, default) + " " + address[0:4] + " " + timestamp
            headerBlock = [header] + destOriginLines

            #self.logger.info("Header in addHeader: %s" % header)
            if textLines:
                wmoMessages.append('\n'.join(headerBlock + textLines) + '\n')
            else:
                wmoMessages.append('\n'.join(headerBlock + message.textLines) +
                                   '\n')
        return wmoMessages

    def doSpecialOrders(self, path):
        # Stop, restart, reload, deconnect, connect could be put here?
        reader = DiskReader(path)
        reader.read()
        dataFromFiles = reader.getFilenamesAndContent()
        for index in range(len(dataFromFiles)):
            words = dataFromFiles[index][0].strip().split()
            self.logger.info("Special Order: %s" %
                             (dataFromFiles[index][0].strip()))

            if words[0] == 'outCSN':
                if words[1] == '+':
                    self.nextCSN()
                    self.logger.info("CSN = %s" % self.CSN)
                elif words[1] == '-':
                    # This case is only done for testing purpose. It is not complete and not correct when CSN
                    # value is 0 or 1
                    self.nextCSN(str(int(self.CSN) - 2))
                    self.logger.info("CSN = %s" % self.CSN)
                elif words[1] == 'print':
                    self.logger.info("CSN = %s" % self.CSN)
                else:
                    # We suppose it's a number, we don't verify!!
                    self.nextCSN(words[1])
                    self.logger.info("CSN = %s" % self.CSN)

            elif words[0] == 'inCSN':
                if words[1] == '+':
                    self.calcWaitedTID(self.waitedTID)
                    self.logger.info("Waited TID = %s" % self.waitedTID)
                elif words[1] == '-':
                    # This case is only done for testing purpose. It is not complete and not correct when waited TID
                    # value is 0 or 1
                    self.calcWaitedTID(self.otherStationID + "%04d" %
                                       (int(self.waitedTID[3:]) - 2))
                    self.logger.info("Waited TID = %s" % self.waitedTID)
                elif words[1] == 'print':
                    self.logger.info("Waited TID = %s" % self.waitedTID)
                else:
                    # We suppose it's a number, we don't verify!!
                    self.calcWaitedTID(self.otherStationID +
                                       "%04d" % int(words[1]))
                    self.logger.info("Waited TID = %s" % self.waitedTID)

            elif words[0] == 'ackWaited':
                if words[1] == 'print':
                    self.logger.info("Waiting for ack: %s" %
                                     self.getWaitingForAck())
                else:
                    self.setWaitingForAck(words[1])
                    self.incrementSendingInfos()
            elif words[0] == 'ackNotWaited':
                self.setWaitingForAck(None)
                self.resetSendingInfos()
                self.updatePartsToSend()
            elif words[0] == 'ackUsed':
                self.ackUsed = words[1] == 'True' or words[1] == 'true'
            elif words[0] == 'printState':
                self.logger.info(self.state.infos())
            else:
                pass

            try:
                os.unlink(dataFromFiles[0][1])
                self.logger.debug("%s has been erased",
                                  os.path.basename(dataFromFiles[index][1]))
            except OSError, e:
                (type, value, tb) = sys.exc_info()
                self.logger.error("Unable to unlink %s ! Type: %s, Value: %s" %
                                  (dataFromFiles[index][1], type, value))