import aprslib import logging logging.basicConfig( level=logging.DEBUG, format="%(asctime)s %(module)s -%(levelname)s- %(message)s" ) logger = logging.getLogger(__name__) """ Have a look at the incoming APRS message and check if it contains a message no which does not follow the APRS standard (see aprs101.pdf chapter 14) but rather follow the new format http://www.aprs.org/aprs11/replyacks.txt The following assumptions apply when handling APRS messages in general: Option 1: no message ID present: send no ACK outgoing messages have no msg number attachment Example data exchange 1: DF1JSL-4>APRS,TCPIP*,qAC,T2PRT::WXBOT :94043 WXBOT>APRS,qAS,KI6WJP::DF1JSL-4 :Mountain View CA. Today,Sunny High 60 Example data exchange 2: DF1JSL-4>APRS,TCPIP*,qAC,T2SPAIN::EMAIL-2 :jsl24469@gmail.com Hallo EMAIL-2>APJIE4,TCPIP*,qAC,AE5PL-JF::DF1JSL-4 :Email sent to jsl24469@gmail.com Option 2: old message number format is present: (example: msg{12345) Send ack with message number from original message (ack12345) All outgoing messages have trailing msg number ( {abcde ); can be numeric or slphanumeric counter. See aprs101.pdf chapter 14 Example data exchange 1: DF1JSL-4>APRS,TCPIP*,qAC,T2SP::EMAIL-2 :jsl24469@gmail.com Hallo{12345 EMAIL-2>APJIE4,TCPIP*,qAC,AE5PL-JF::DF1JSL-4 :ack12345 EMAIL-2>APJIE4,TCPIP*,qAC,AE5PL-JF::DF1JSL-4 :Email sent to jsl24469@gmail.com{891 DF1JSL-4>APOSB,TCPIP*,qAS,DF1JSL::EMAIL-2 :ack891 Example data exchange 2: DF1JSL-4>APRS,TCPIP*,qAC,T2CSNGRAD::EMAIL-2 :jsl24469@gmail.com{ABCDE EMAIL-2>APJIE4,TCPIP*,qAC,AE5PL-JF::DF1JSL-4 :ackABCDE EMAIL-2>APJIE4,TCPIP*,qAC,AE5PL-JF::DF1JSL-4 :Email sent to jsl24469@gmail.com{893 DF1JSL-4>APOSB,TCPIP*,qAS,DF1JSL::EMAIL-2 :ack893 Option 3: new messages with message ID but without trailing retry msg ids: msg{AB} Do NOT send extra ack All outgoing messages have 2-character msg id, followed by message ID from original message Example: User sends message "Hello{AB}" to MPAD MPAD responds "Message content line 1{DE}AB" to user MPAD responds "Message content line 2{DF}AB" to user AB -> original message DE, DF -> message IDs generated by MPAD Example data exchange 1: DF1JSL-4>APRS,TCPIP*,qAC,T2NUERNBG::WXBOT :99801{AB} WXBOT>APRS,qAS,KI6WJP::DF1JSL-4 :Lemon Creek AK. Today,Scattered Rain/Snow and Patchy Fog 50% High 4{QL}AB DF1JSL-4>APOSB,TCPIP*,qAS,DF1JSL::WXBOT :ackQL}AB WXBOT>APRS,qAS,KI6WJP::DF1JSL-4 :0{QM}AB DF1JSL-4>APOSB,TCPIP*,qAS,DF1JSL::WXBOT :ackQM}AB Example data exchange 2: DF1JSL-4>APRS,TCPIP*,qAC,T2SPAIN::EMAIL-2 :jsl24469@gmail.com Hallo{AB} EMAIL-2>APJIE4,TCPIP*,qAC,AE5PL-JF::DF1JSL-4 :Email sent to jsl24469@gmail.com{OQ}AB DF1JSL-4>APOSB,TCPIP*,qAS,DF1JSL::EMAIL-2 :ackOQ}AB Option 4: new messages with message ID and with trailing retry msg ids: msg{AB}CD We don't handle retries - therefore, apply option #3 for processing these the "CD" part gets omitted and is not used Example data exchange 1: DF1JSL-4>APRS,TCPIP*,qAC,T2CZECH::WXBOT :99801{LM}AA WXBOT>APRS,qAS,KI6WJP::DF1JSL-4 :Lemon Creek AK. Today,Scattered Rain/Snow and Patchy Fog 50% High 4{QP}LM DF1JSL-4>APOSB,TCPIP*,qAS,DF1JSL::WXBOT :ackQP}LM WXBOT>APRS,qAS,KI6WJP::DF1JSL-4 :0{QQ}LM DF1JSL-4>APOSB,TCPIP*,qAS,DF1JSL::WXBOT :ackQQ}LM Example data exchange 2: DF1JSL-4>APRS,TCPIP*,qAC,T2SP::EMAIL-2 :jsl24469@gmail.com Welt{DE}FG EMAIL-2>APJIE4,TCPIP*,qAC,AE5PL-JF::DF1JSL-4 :Email sent to jsl24469@gmail.com{OS}DE DF1JSL-4>APOSB,TCPIP*,qAS,DF1JSL::EMAIL-2 :ackOS}DE """ if __name__ == "__main__": # ack/rej assertion tests # erroneous rej packet = aprslib.parse("DF1JSL-4>APOSB,TCPIP*,qAS,DF1JSL::WXBOT :red12345") assert ("msgNo" not in packet) assert ("ackMsgNo" not in packet) assert ("message_text" in packet) assert (packet["format"] == "message") assert (packet["message_text"] == "red12345") # reject with "old" msgno packet = aprslib.parse("DF1JSL-4>APOSB,TCPIP*,qAS,DF1JSL::WXBOT :rej123") assert ("msgNo" in packet) assert ("ackMsgNo" not in packet) assert ("response" in packet) assert (packet["format"] == "message") assert ("message_text" not in packet) assert (packet["response"] == "rej") assert (packet["msgNo"] == "123") # ack with new msgNo but no ackMsgNo packet = aprslib.parse("DF1JSL-4>APOSB,TCPIP*,qAS,DF1JSL::WXBOT :ackAB}") assert ("msgNo" in packet) assert ("ackMsgNo" not in packet) assert ("response" in packet) assert (packet["format"] == "message") assert ("message_text" not in packet) assert (packet["response"] == "ack") assert (packet["msgNo"] == "AB") # ack with new msgNo and ackMsgNo packet = aprslib.parse("DF1JSL-4>APOSB,TCPIP*,qAS,DF1JSL::WXBOT :ackAB}CD") assert ("msgNo" in packet) assert ("ackMsgNo" in packet) assert ("response" in packet) assert (packet["format"] == "message") assert ("message_text" not in packet) assert (packet["response"] == "ack") assert (packet["msgNo"] == "AB") assert (packet["ackMsgNo"] == "CD") # message text body tests # message body without msg no packet = aprslib.parse("DF1JSL-4>APOSB,TCPIP*,qAS,DF1JSL::WXBOT :HelloWorld ") assert ("msgNo" not in packet) assert ("ackMsgNo" not in packet) assert ("message_text" in packet) assert (packet["format"] == "message") assert (packet["message_text"] == "HelloWorld") # message body with msg no - old format packet = aprslib.parse("DF1JSL-4>APOSB,TCPIP*,qAS,DF1JSL::WXBOT :HelloWorld {ABCDE") assert ("msgNo" in packet) assert ("ackMsgNo" not in packet) assert ("response" not in packet) assert (packet["format"] == "message") assert ("message_text" in packet) assert (packet["message_text"] == "HelloWorld") assert (packet["msgNo"] == "ABCDE") # message body with msgNo (new format) and ackMsgNo missing packet = aprslib.parse("DF1JSL-4>APOSB,TCPIP*,qAS,DF1JSL::WXBOT :HelloWorld {AB}") assert ("msgNo" in packet) assert ("ackMsgNo" not in packet) assert ("response" not in packet) assert (packet["format"] == "message") assert ("message_text" in packet) assert (packet["message_text"] == "HelloWorld") assert (packet["msgNo"] == "AB") # message body with msgNo and ackMsgNo (new format) packet = aprslib.parse("DF1JSL-4>APOSB,TCPIP*,qAS,DF1JSL::WXBOT :HelloWorld {AB}CD") assert ("msgNo" in packet) assert ("ackMsgNo" in packet) assert ("response" not in packet) assert (packet["format"] == "message") assert ("message_text" in packet) assert (packet["message_text"] == "HelloWorld") assert (packet["msgNo"] == "AB") assert (packet["ackMsgNo"] == "CD") # message body with really long message packet = aprslib.parse("DF1JSL-4>APOSB,TCPIP*,qAS,DF1JSL::WXBOT :00000000001111111111222222222233333333334444444444555555555566666666667777777777") assert ("msgNo" not in packet) assert ("ackMsgNo" not in packet) assert ("message_text" in packet) assert (packet["format"] == "message") assert (packet["message_text"] == "0000000000111111111122222222223333333333444444444455555555556666666")