diff --git a/messaging/sms/deliver.py b/messaging/sms/deliver.py index 5a9ba6b..76709a3 100644 --- a/messaging/sms/deliver.py +++ b/messaging/sms/deliver.py @@ -21,6 +21,13 @@ def __init__(self, pdu, strict=True): self.mtype = None self.sr = None + #2bit SC to MS Message type + self.tp_mti = None + #Boolean, indicate if there is more message to send + self.tp_mms = None + #Boolean, indicate if udh presend + self.tp_udhi = None + self.pdu = pdu @property @@ -36,7 +43,7 @@ def data(self): 'dcs': self.dcs, 'csca': self.csca, 'number': self.number, - 'type': self.type, + 'type': self.tp_mti, 'date': self.date, 'fmt': self.fmt, 'sr': self.sr, @@ -79,23 +86,36 @@ def _set_pdu(self, pdu): else: self.csca = None - # 1 byte(octet) == 2 char - # Message type TP-MTI bits 0,1 - # More messages to send/deliver bit 2 - # Status report request indicated bit 5 - # User Data Header Indicator bit 6 - # Reply path set bit 7 + # 1 byte(octet) == 2 HEX char + # TP_MTI, Message type bits 0,1 + # TP_MMS, More messages to send/deliver bit 2 + # TP_SRI, Status report request indicated bit 5 + # TP_UHDI, User Data Header Indicator bit 6 + # TP_RP, Reply path set bit 7 try: self.mtype = data.pop(0) except TypeError: raise ValueError("Decoding this type of SMS is not supported yet") - mtype = self.mtype & 0x03 + #0 0 SC->MS SMS-DELIVER + #0 1 SC->MS SMS-SUBMIT-REPORT ( Not supported yet ) + #1 0 SC->MS SMS-STATUS-REPORT + #1 1 Any Reserved + self.tp_mti = self.mtype & 0b00000011 + + #TP-More-Messages-to-Send (TP-MMS) in SMS-DELIVER (0 = more messages) + self.tp_mms = False if self.mtype & 0b00000100 else True + + #Indicate if message has UDH + self.tp_udhi = True if self.mtype & 0b01000000 else False + + if self.tp_mti == 0b11: + raise ValueError("Decoding this type of SMS is not supported") - if mtype == 0x02: + if self.tp_mti == 0b10: return self._decode_status_report_pdu(data) - if mtype == 0x01: + if self.tp_mti == 0b01: raise ValueError("Cannot decode a SmsSubmitReport message yet") sndlen = data.pop(0) @@ -160,7 +180,7 @@ def _process_message(self, data): # check for header headlen = ud_len = 0 - if self.mtype & 0x40: # UDHI present + if self.tp_udhi: # UDHI present ud_len = data.pop(0) self.udh = UserDataHeader.from_bytes(data[:ud_len]) headlen = (ud_len + 1) * 8 @@ -183,7 +203,7 @@ def _process_message(self, data): elif self.fmt == 0x08: data = data[ud_len:].tolist() _bytes = [int("%02X%02X" % (data[i], data[i + 1]), 16) - for i in range(0, len(data), 2)] + for i in range(0, len(data), 2)] self.text = u''.join(list(map(unichr, _bytes))) pdu = property(lambda self: self._pdu, _set_pdu) @@ -203,26 +223,57 @@ def _decode_status_report_pdu(self, data): data = data[sndlen:] - date = swap(list(encode_bytes(data[:7]))) - try: - scts_str = "%s%s/%s%s/%s%s %s%s:%s%s:%s%s" % tuple(date[0:12]) - self.date = datetime.strptime(scts_str, "%y/%m/%d %H:%M:%S") - except (ValueError, TypeError): - scts_str = '' - debug('Could not decode scts: %s' % date) + datestr = '' + # Get date stamp (sender's local time) + date = list(encode_bytes(data[:6])) + for n in range(1, len(date), 2): + date[n - 1], date[n] = date[n], date[n - 1] - data = data[7:] + data = data[6:] - date = swap(list(encode_bytes(data[:7]))) - try: - dt_str = "%s%s/%s%s/%s%s %s%s:%s%s:%s%s" % tuple(date[0:12]) - dt = datetime.strptime(dt_str, "%y/%m/%d %H:%M:%S") - except (ValueError, TypeError): - dt_str = '' - dt = None - debug('Could not decode date: %s' % date) + # Get sender's offset from GMT (TS 23.040 TP-SCTS) + tz = data.pop(0) + + offset = ((tz & 0x07) * 10 + ((tz & 0xf0) >> 4)) * 15 + if (tz & 0x08): + offset = offset * -1 + + # 02/08/26 19:37:41 + datestr = "%s%s/%s%s/%s%s %s%s:%s%s:%s%s" % tuple(date) + outputfmt = '%y/%m/%d %H:%M:%S' + + sndlocaltime = datetime.strptime(datestr, outputfmt) + sndoffset = timedelta(minutes=offset) + # date as UTC + self.date = sndlocaltime - sndoffset + scts_str = datestr + + + datestr = '' + # Get date stamp (sender's local time) + date = list(encode_bytes(data[:6])) + for n in range(1, len(date), 2): + date[n - 1], date[n] = date[n], date[n - 1] + + data = data[6:] + + # Get sender's offset from GMT (TS 23.040 TP-SCTS) + tz = data.pop(0) + + offset = ((tz & 0x07) * 10 + ((tz & 0xf0) >> 4)) * 15 + if (tz & 0x08): + offset = offset * -1 + + # 02/08/26 19:37:41 + datestr = "%s%s/%s%s/%s%s %s%s:%s%s:%s%s" % tuple(date) + outputfmt = '%y/%m/%d %H:%M:%S' + + sndlocaltime = datetime.strptime(datestr, outputfmt) + sndoffset = timedelta(minutes=offset) + # date as UTC + dt = sndlocaltime - sndoffset + dt_str = datestr - data = data[7:] msg_l = [recipient, scts_str] try: @@ -253,7 +304,6 @@ def _decode_status_report_pdu(self, data): self.number = sender self.text = "|".join(msg_l) self.fmt = 0x08 # UCS2 - self.type = 0x03 # status report self.sr = { 'recipient': recipient, @@ -261,4 +311,3 @@ def _decode_status_report_pdu(self, data): 'dt': dt, 'status': _status } - diff --git a/messaging/test/test_sms.py b/messaging/test/test_sms.py index c3ff7b5..2da3e71 100644 --- a/messaging/test/test_sms.py +++ b/messaging/test/test_sms.py @@ -399,7 +399,7 @@ def test_decoding_number_alphanumeric(self): def test_decode_sms_confirmation(self): pdu = "07914306073011F006270B913426565711F7012081111345400120811174054043" csca = "+34607003110" - date = datetime(2010, 2, 18, 11, 31, 54) + date = datetime(2010, 2, 18, 10, 31, 54) number = "SR-UNKNOWN" # XXX: the number should be +344626575117, is the prefix flipped ? text = "+43626575117|10/02/18 11:31:54|" @@ -443,8 +443,8 @@ def test_decoding_delivery_status_report(self): pdu = "0791538375000075061805810531F1019082416500400190824165004000" sr = { 'status': 0, - 'scts': datetime(2010, 9, 28, 14, 56), - 'dt': datetime(2010, 9, 28, 14, 56), + 'scts': datetime(2010, 9, 28, 13, 56), + 'dt': datetime(2010, 9, 28, 13, 56), 'recipient': '50131' } @@ -458,8 +458,8 @@ def test_decoding_delivery_status_report_without_smsc_address(self): pdu = "00060505810531F1010150610000400101506100004000" sr = { 'status': 0, - 'scts': datetime(2010, 10, 5, 16, 0), - 'dt': datetime(2010, 10, 5, 16, 0), + 'scts': datetime(2010, 10, 5, 15, 0), + 'dt': datetime(2010, 10, 5, 15, 0), 'recipient': '50131' }