1
2
3
4
5
6
7
8
9
10 """ MMS Data Unit structure encoding and decoding classes """
11
12 import os, array
13 import wsp_pdu
14 import message
15 from iterator import PreviewIterator
16
18 fieldNames = {0x01 : ('Bcc', 'EncodedStringValue'),
19 0x02 : ('Cc', 'EncodedStringValue'),
20 0x03 : ('Content-Location', 'UriValue'),
21 0x04 : ('Content-Type','ContentTypeValue'),
22 0x05 : ('Date', 'DateValue'),
23 0x06 : ('Delivery-Report', 'BooleanValue'),
24 0x07 : ('Delivery-Time', None),
25 0x08 : ('Expiry', 'ExpiryValue'),
26 0x09 : ('From', 'FromValue'),
27 0x0a : ('Message-Class', 'MessageClassValue'),
28 0x0b : ('Message-ID', 'TextString'),
29 0x0c : ('Message-Type', 'MessageTypeValue'),
30 0x0d : ('MMS-Version', 'VersionValue'),
31 0x0e : ('Message-Size', 'LongInteger'),
32 0x0f : ('Priority', 'PriorityValue'),
33 0x10 : ('Read-Reply', 'BooleanValue'),
34 0x11 : ('Report-Allowed', 'BooleanValue'),
35 0x12 : ('Response-Status', 'ResponseStatusValue'),
36 0x13 : ('Response-Text', 'EncodedStringValue'),
37 0x14 : ('Sender-Visibility', 'SenderVisibilityValue'),
38 0x15 : ('Status', 'StatusValue'),
39 0x16 : ('Subject', 'EncodedStringValue'),
40 0x17 : ('To', 'EncodedStringValue'),
41 0x18 : ('Transaction-Id', 'TextString')}
42
43
45 """ A decoder for MMS messages """
47 """ @param filename: If specified, decode the content of the MMS
48 message file with this name
49 @type filename: str
50 """
51 self._mmsData = array.array('B')
52 self._mmsMessage = message.MMSMessage()
53 self._parts = []
54
56 """ Load the data contained in the specified file, and decode it.
57
58 @param filename: The name of the MMS message file to open
59 @type filename: str
60
61 @raises OSError: The filename is invalid
62
63 @return: The decoded MMS data
64 @rtype: MMSMessage
65 """
66 nBytes = os.stat(filename)[6]
67 data = array.array('B')
68 f = open(filename, 'rb')
69 data.fromfile(f, nBytes)
70 f.close()
71 return self.decodeData(data)
72
74 """ Decode the specified MMS message data
75
76 @param data: The MMS message data to decode
77 @type data: array.array('B')
78
79 @return: The decoded MMS data
80 @rtype: MMSMessage
81 """
82 self._mmsMessage = message.MMSMessage()
83 self._mmsData = data
84 bodyIter = self.decodeMessageHeader()
85 self.decodeMessageBody(bodyIter)
86 return self._mmsMessage
87
89 """ Decodes the (full) MMS header data
90
91 @note: This B{must} be called before C{_decodeBody()}, as it sets
92 certain internal variables relating to data lengths, etc.
93 """
94 dataIter = PreviewIterator(self._mmsData)
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110 contentTypeFound = False
111 while contentTypeFound == False:
112 header, value = self.decodeHeader(dataIter)
113 if header == MMSEncodingAssignments.fieldNames[0x04][0]:
114 contentTypeFound = True
115 else:
116 self._mmsMessage.headers[header] = value
117
118
119 cType = value[0]
120
121 params = value[1]
122
123
124
125 self._mmsMessage.headers[header] = (cType, params)
126 return dataIter
127
128
129 - def decodeMessageBody(self, dataIter):
130 """ Decodes the MMS message body
131
132 @param dataIter: an iterator over the sequence of bytes of the MMS
133 body
134 @type dataIter: iter
135 """
136
137
138 nEntries = self.decodeUintvar(dataIter)
139
140
141
142
143
144
145
146
147 for partNum in range(nEntries):
148
149 headersLen = self.decodeUintvar(dataIter)
150 dataLen = self.decodeUintvar(dataIter)
151
152
153 ctFieldBytes = []
154 for i in range(headersLen):
155 ctFieldBytes.append(dataIter.next())
156
157 ctIter = PreviewIterator(ctFieldBytes)
158
159 contentType, ctParameters = self.decodeContentTypeValue(ctIter)
160 headers = {'Content-Type' : (contentType, ctParameters)}
161
162
163
164
165
166 while True:
167 try:
168 hdr, value = self.decodeHeader(ctIter)
169 headers[hdr] = value
170
171 except StopIteration:
172 break
173
174
175
176 data = array.array('B')
177 for i in range(dataLen):
178 data.append(dataIter.next())
179
180 part = message.DataPart()
181 part.setData(data, contentType)
182 part.contentTypeParameters = ctParameters
183 part.headers = headers
184 self._mmsMessage.addDataPart(part)
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205 @staticmethod
207 """ Decodes a header entry from an MMS message, starting at the byte
208 pointed to by C{byteIter.next()}
209
210 From [4], section 7.1:
211 C{Header = MMS-header | Application-header}
212
213 @raise DecodeError: This uses C{decodeMMSHeader()} and
214 C{decodeApplicationHeader()}, and will raise this
215 exception under the same circumstances as
216 C{decodeApplicationHeader()}. C{byteIter} will
217 not be modified in this case.
218
219 @note: The return type of the "header value" depends on the header
220 itself; it is thus up to the function calling this to determine
221 what that type is (or at least compensate for possibly
222 different return value types).
223
224 @return: The decoded header entry from the MMS, in the format:
225 (<str:header name>, <str/int/float:header value>)
226 @rtype: tuple
227 """
228 header = ''
229 value = ''
230 try:
231 header, value = MMSDecoder.decodeMMSHeader(byteIter)
232 except wsp_pdu.DecodeError:
233 header, value = wsp_pdu.Decoder.decodeHeader(byteIter)
234 return (header, value)
235
236 @staticmethod
238 """ From [4], section 7.1:
239 MMS-header = MMS-field-name MMS-value
240 MMS-field-name = Short-integer
241 MMS-value = Bcc-value | Cc-value | Content-location-value | Content-type-value | etc
242
243 This method takes into account the assigned number values for MMS
244 field names, as specified in [4], section 7.3, table 8.
245
246 @raise wsp_pdu.DecodeError: The MMS field name could not be parsed.
247 C{byteIter} will not be modified in this case.
248
249 @return: The decoded MMS header, in the format:
250 (<str:MMS-field-name>, <str:MMS-value>)
251 @rtype: tuple
252 """
253
254 mmsFieldName = ''
255 byte = wsp_pdu.Decoder.decodeShortIntegerFromByte(byteIter.preview())
256
257 if byte in MMSEncodingAssignments.fieldNames:
258 byteIter.next()
259 mmsFieldName = MMSEncodingAssignments.fieldNames[byte][0]
260
261 else:
262 byteIter.resetPreview()
263 raise wsp_pdu.DecodeError, 'Invalid MMS Header: could not decode MMS field name'
264
265 mmsValue = ''
266 try:
267 exec 'mmsValue = MMSDecoder.decode%s(byteIter)' % MMSEncodingAssignments.fieldNames[byte][1]
268 except wsp_pdu.DecodeError, msg:
269 raise wsp_pdu.DecodeError, 'Invalid MMS Header: Could not decode MMS-value: %s' % msg
270 except:
271 print 'A fatal error occurred, probably due to an unimplemented decoding operation. Tried to decode header: %s' % mmsFieldName
272 raise
273 return (mmsFieldName, mmsValue)
274
275 @staticmethod
277 """ From [4], section 7.2.9:
278 C{Encoded-string-value = Text-string | Value-length Char-set Text-string}
279 The Char-set values are registered by IANA as MIBEnum value.
280
281 @note: This function is not fully implemented, in that it does not
282 have proper support for the Char-set values; it basically just
283 reads over that sequence of bytes, and ignores it (see code for
284 details) - any help with this will be greatly appreciated.
285
286 @return: The decoded text string
287 @rtype: str
288 """
289 decodedString = ''
290 try:
291
292 valueLength = wsp_pdu.Decoder.decodeValueLength(byteIter)
293
294 try:
295 charSetValue = wsp_pdu.Decoder.decodeWellKnownCharset(byteIter)
296 except wsp_pdu.DecodeError, msg:
297 raise Exception, 'EncodedStringValue decoding error: Could not decode Char-set value; %s' % msg
298 decodedString = wsp_pdu.Decoder.decodeTextString(byteIter)
299 except wsp_pdu.DecodeError:
300
301 decodedString = wsp_pdu.Decoder.decodeTextString(byteIter)
302 return decodedString
303
304
305 @staticmethod
307 """ From [4], section 7.2.6::
308 Delivery-report-value = Yes | No
309 Yes = <Octet 128>
310 No = <Octet 129>
311
312 A lot of other yes/no fields use this encoding (read-reply,
313 report-allowed, etc)
314
315 @raise wsp_pdu.DecodeError: The boolean value could not be parsed.
316 C{byteIter} will not be modified in this case.
317
318 @return: The value for the field: 'Yes' or 'No'
319 @rtype: str
320 """
321 value = ''
322
323
324 byte = byteIter.preview()
325 if byte not in (128, 129):
326 byteIter.resetPreview()
327 raise wsp_pdu.DecodeError, 'Error parsing boolean value for byte: %s' % hex(byte)
328 else:
329 byte = byteIter.next()
330 if byte == 128:
331 value = 'Yes'
332 elif byte == 129:
333 value = 'No'
334 return value
335
336 @staticmethod
338 """ From [4], section 7.2.11:
339 From-value = Value-length (Address-present-token Encoded-string-value | Insert-address-token )
340 Address-present-token = <Octet 128>
341 Insert-address-token = <Octet 129>
342
343 @return: The "From" address value
344 @rtype: str
345 """
346 fromValue = ''
347 valueLength = wsp_pdu.Decoder.decodeValueLength(byteIter)
348
349 byte = byteIter.next()
350 if byte == 129:
351 fromValue = '<not inserted>'
352 else:
353 fromValue = MMSDecoder.decodeEncodedStringValue(byteIter)
354 return fromValue
355
356 @staticmethod
358 """ From [4], section 7.2.12:
359 Message-class-value = Class-identifier | Token-text
360 Class-identifier = Personal | Advertisement | Informational | Auto
361 Personal = <Octet 128>
362 Advertisement = <Octet 129>
363 Informational = <Octet 130>
364 Auto = <Octet 131>
365 The token-text is an extension method to the message class.
366
367 @return: The decoded message class
368 @rtype: str
369 """
370 classIdentifiers = {128 : 'Personal',
371 129 : 'Advertisement',
372 130 : 'Informational',
373 131 : 'Auto'}
374 msgClass = ''
375
376
377 byte = byteIter.preview()
378 if byte in classIdentifiers:
379 byteIter.next()
380 msgClass = classIdentifiers[byte]
381 else:
382 byteIter.resetPreview()
383 msgClass = wsp_pdu.Decoder.decodeTokenText(byteIter)
384 return msgClass
385
386 @staticmethod
388 """ Defined in [4], section 7.2.14.
389
390 @return: The decoded message type, or '<unknown>'
391 @rtype: str
392 """
393 messageTypes = {0x80 : 'm-send-req',
394 0x81 : 'm-send-conf',
395 0x82 : 'm-notification-ind',
396 0x83 : 'm-notifyresp-ind',
397 0x84 : 'm-retrieve-conf',
398 0x85 : 'm-acknowledge-ind',
399 0x86 : 'm-delivery-ind'}
400 byte = byteIter.preview()
401 if byte in messageTypes:
402 byteIter.next()
403 return messageTypes[byte]
404 else:
405 byteIter.resetPreview()
406 return '<unknown>'
407
408 @staticmethod
410 """ Defined in [4], section 7.2.17
411
412 @raise wsp_pdu.DecodeError: The priority value could not be decoded;
413 C{byteIter} is not modified in this case.
414
415 @return: The decoded priority value
416 @rtype: str
417 """
418 priorities = {128 : 'Low',
419 129 : 'Normal',
420 130 : 'High'}
421
422 byte = byteIter.preview()
423 if byte in priorities:
424 byte = byteIter.next()
425 return priorities[byte]
426 else:
427 byteIter.resetPreview()
428 raise wsp_pdu.DecodeError, 'Error parsing Priority value for byte:',byte
429
430 @staticmethod
432 """ Defined in [4], section 7.2.22::
433 Sender-visibility-value = Hide | Show
434 Hide = <Octet 128>
435 Show = <Octet 129>
436
437 @raise wsp_pdu.DecodeError: The sender visibility value could not be
438 parsed.
439 C{byteIter} will not be modified in this case.
440
441 @return: The sender visibility: 'Hide' or 'Show'
442 @rtype: str
443 """
444 value = ''
445
446
447 byte = byteIter.preview()
448 if byte not in (128, 129):
449 byteIter.resetPreview()
450 raise wsp_pdu.DecodeError, 'Error parsing sender visibility value for byte: %s' % hex(byte)
451 else:
452 byte = byteIter.next()
453 if byte == 128:
454 value = 'Hide'
455 elif byte == 129:
456 value = 'Show'
457 return value
458
459 @staticmethod
461 """ Defined in [4], section 7.2.20
462
463 Used to decode the "Response Status" MMS header.
464
465 @raise wsp_pdu.DecodeError: The sender visibility value could not be
466 parsed.
467 C{byteIter} will not be modified in this case.
468
469 @return: The decoded Response-status-value
470 @rtype: str
471 """
472 responseStatusValues = {0x80 : 'Ok',
473 0x81 : 'Error-unspecified',
474 0x82 : 'Error-service-denied',
475 0x83 : 'Error-message-format-corrupt',
476 0x84 : 'Error-sending-address-unresolved',
477 0x85 : 'Error-message-not-found',
478 0x86 : 'Error-network-problem',
479 0x87 : 'Error-content-not-accepted',
480 0x88 : 'Error-unsupported-message'}
481 byte = byteIter.preview()
482 if byte in responseStatusValues:
483 byteIter.next()
484 return responseStatusValues[byte]
485 else:
486 byteIter.next()
487
488 return responseStatusValues[0x81]
489
490 @staticmethod
492 """ Defined in [4], section 7.2.23
493
494 Used to decode the "Status" MMS header.
495
496 @raise wsp_pdu.DecodeError: The sender visibility value could not be
497 parsed.
498 C{byteIter} will not be modified in this case.
499
500 @return: The decoded Status-value
501 @rtype: str
502 """
503
504 statusValues = {0x80 : 'Expired',
505 0x81 : 'Retrieved',
506 0x82 : 'Rejected',
507 0x83 : 'Deferred',
508 0x84 : 'Unrecognised'}
509
510 byte = byteIter.preview()
511 if byte in statusValues:
512 byteIter.next()
513 return statusValues[byte]
514 else:
515 byteIter.next()
516
517 return statusValues[0x84]
518
519
520 @staticmethod
522 """ Defined in [4], section 7.2.10
523
524 Used to decode the "Expiry" MMS header.
525
526 From [4], section 7.2.10:
527 Expiry-value = Value-length (Absolute-token Date-value | Relative-token Delta-seconds-value)
528 Absolute-token = <Octet 128>
529 Relative-token = <Octet 129>
530
531 @raise wsp_pdu.DecodeError: The Expiry-value could not be decoded
532
533 @return: The decoded Expiry-value, either as a date, or as a delta-seconds value
534 @rtype: str or int
535 """
536 valueLength = MMSDecoder.decodeValueLength(byteIter)
537 token = byteIter.next()
538
539 if token == 0x80:
540 data = MMSDecoder.decodeDateValue(byteIter)
541 elif token == 0x81:
542 data = MMSDecoder.decodeDeltaSecondsValue(byteIter)
543 else:
544 raise wsp_pdu.DecodeError, 'Unrecognized token value: %s' % hex(token)
545 return data
546
547
551
552 - def encode(self, mmsMessage):
553 """ Encodes the specified MMS message
554
555 @param mmsMessage: The MMS message to encode
556 @type mmsMessage: MMSMessage
557
558 @return: The binary-encoded MMS data, as a sequence of bytes
559 @rtype: array.array('B')
560 """
561 self._mmsMessage = mmsMessage
562 msgData = self.encodeMessageHeader()
563 msgData.extend(self.encodeMessageBody())
564 return msgData
565
567 """ Binary-encodes the MMS header data.
568
569 @note: The encoding used for the MMS header is specified in [4].
570 All "constant" encoded values found/used in this method
571 are also defined in [4]. For a good example, see [2].
572
573 @return: the MMS PDU header, as an array of bytes
574 @rtype: array.array('B')
575 """
576
577 fromTypes = {'Address-present-token' : 0x80,
578 'Insert-address-token' : 0x81}
579
580 contentTypes = {'application/vnd.wap.multipart.related' : 0xb3}
581
582
583 messageHeader = array.array('B')
584
585 headersToEncode = self._mmsMessage.headers
586
587
588 for hdr in ('X-Mms-Message-Type', 'X-Mms-Transaction-Id', 'X-Mms-Version'):
589 if hdr in headersToEncode:
590 if hdr == 'X-Mms-Version':
591 cleanHeader = 'MMS-Version'
592 else:
593 cleanHeader = hdr.replace('X-Mms-', '', 1)
594 headersToEncode[cleanHeader] = headersToEncode[hdr]
595 del headersToEncode[hdr]
596
597
598
599
600
601
602
603
604 if 'Message-Type' not in headersToEncode:
605
606
607 headersToEncode['Message-Type'] = 'm-retrieve-conf'
608
609
610
611
612
613
614 if headersToEncode['Message-Type'] == 'm-send-req':
615 foundDestAddress = False
616 for addressType in ('To', 'Cc', 'Bc'):
617 if addressType in headersToEncode:
618 foundDestAddress = True
619 break
620 if not foundDestAddress:
621 headersToEncode['Message-Type'] = 'm-retrieve-conf'
622
623
624
625 if 'Transaction-Id' not in headersToEncode:
626 import random
627 headersToEncode['Transaction-Id'] = str(random.randint(1000, 9999))
628
629
630
631 if 'MMS-Version' not in headersToEncode:
632 headersToEncode['MMS-Version'] = '1.0'
633
634
635 for hdr in ('Message-Type', 'Transaction-Id', 'MMS-Version'):
636 messageHeader.extend(MMSEncoder.encodeHeader(hdr, headersToEncode[hdr]))
637 del headersToEncode[hdr]
638
639
640
641 for hdr in headersToEncode:
642 if hdr == 'Content-Type':
643 continue
644 messageHeader.extend(MMSEncoder.encodeHeader(hdr, headersToEncode[hdr]))
645
646
647 ctType = headersToEncode['Content-Type'][0]
648 ctParameters = headersToEncode['Content-Type'][1]
649 messageHeader.extend(MMSEncoder.encodeMMSFieldName('Content-Type'))
650 messageHeader.extend(MMSEncoder.encodeContentTypeValue(ctType, ctParameters))
651
652 return messageHeader
653
655 """ Binary-encodes the MMS body data.
656
657 @note: The MMS body is of type C{application/vnd.wap.multipart}
658 (C{mixed} or C{related}).
659 As such, its structure is divided into a header, and the data entries/parts::
660
661 [ header ][ entries ]
662 ^^^^^^^^^^^^^^^^^^^^^
663 MMS Body
664
665 The MMS Body header consists of one entry[5]::
666 name type purpose
667 ------- ------- -----------
668 nEntries Uintvar number of entries in the multipart entity
669
670 The MMS body's multipart entries structure::
671 name type purpose
672 ------- ----- -----------
673 HeadersLen Uintvar length of the ContentType and
674 Headers fields combined
675 DataLen Uintvar length of the Data field
676 ContentType Multiple octets the content type of the data
677 Headers (<HeadersLen>
678 - length of
679 <ContentType>) octets the part's headers
680 Data <DataLen> octets the part's data
681
682 @note: The MMS body's header should not be confused with the actual
683 MMS header, as returned by C{_encodeHeader()}.
684
685 @note: The encoding used for the MMS body is specified in [5], section 8.5.
686 It is only referenced in [4], however [2] provides a good example of
687 how this ties in with the MMS header encoding.
688
689 @return: The binary-encoded MMS PDU body, as an array of bytes
690 @rtype: array.array('B')
691 """
692
693 messageBody = array.array('B')
694
695
696
697
698 nEntries = 1
699 for page in self._mmsMessage._pages:
700 nEntries += page.numberOfParts()
701 for dataPart in self._mmsMessage._dataParts:
702 nEntries += 1
703
704 messageBody.extend(self.encodeUintvar(nEntries))
705
706
707
708
709
710
711
712
713
714 smilPart = message.DataPart()
715 smil = self._mmsMessage.smil()
716 smilPart.setData(smil, 'application/smil')
717
718 smilPart.headers['Content-ID'] = '<0000>'
719 parts = [smilPart]
720 for slide in self._mmsMessage._pages:
721 for partTuple in (slide.image, slide.audio, slide.text):
722 if partTuple != None:
723 parts.append(partTuple[0])
724
725 for part in parts:
726 partContentType = self.encodeContentTypeValue(part.headers['Content-Type'][0], part.headers['Content-Type'][1])
727
728 encodedPartHeaders = []
729 for hdr in part.headers:
730 if hdr == 'Content-Type':
731 continue
732 encodedPartHeaders.extend(wsp_pdu.Encoder.encodeHeader(hdr, part.headers[hdr]))
733
734
735 headersLen = len(partContentType) + len(encodedPartHeaders)
736 messageBody.extend(self.encodeUintvar(headersLen))
737
738 messageBody.extend(self.encodeUintvar(len(part)))
739
740 messageBody.extend(partContentType)
741
742 messageBody.extend(encodedPartHeaders)
743
744 for char in part.data:
745 messageBody.append(ord(char))
746 return messageBody
747
748
749 @staticmethod
751 """ Encodes a header entry for an MMS message
752
753 From [4], section 7.1:
754 C{Header = MMS-header | Application-header}
755 C{MMS-header = MMS-field-name MMS-value}
756 C{MMS-field-name = Short-integer}
757 C{MMS-value = Bcc-value | Cc-value | Content-location-value | Content-type-value | etc}
758
759 @raise DecodeError: This uses C{decodeMMSHeader()} and
760 C{decodeApplicationHeader()}, and will raise this
761 exception under the same circumstances as
762 C{decodeApplicationHeader()}. C{byteIter} will
763 not be modified in this case.
764
765 @note: The return type of the "header value" depends on the header
766 itself; it is thus up to the function calling this to determine
767 what that type is (or at least compensate for possibly
768 different return value types).
769
770 @return: The decoded header entry from the MMS, in the format:
771 (<str:header name>, <str/int/float:header value>)
772 @rtype: tuple
773 """
774 encodedHeader = []
775
776 for assignedNumber in MMSEncodingAssignments.fieldNames:
777 if MMSEncodingAssignments.fieldNames[assignedNumber][0] == headerFieldName:
778 encodedHeader.extend(wsp_pdu.Encoder.encodeShortInteger(assignedNumber))
779
780 expectedType = MMSEncodingAssignments.fieldNames[assignedNumber][1]
781 try:
782 exec 'encodedHeader.extend(MMSEncoder.encode%s(headerValue))' % expectedType
783 except wsp_pdu.EncodeError, msg:
784 raise wsp_pdu.EncodeError, 'Error encoding parameter value: %s' % msg
785 except:
786 print 'A fatal error occurred, probably due to an unimplemented encoding operation'
787 raise
788 break
789
790 if len(encodedHeader) == 0:
791
792 encodedHeaderName = wsp_pdu.Encoder.encodeTokenText(headerFieldName)
793 encodedHeader.extend(encodedHeaderName)
794
795 encodedHeader.extend(wsp_pdu.Encoder.encodeTextString(headerValue))
796 return encodedHeader
797
798 @staticmethod
800 """ Encodes an MMS header field name, using the "assigned values" for
801 well-known MMS headers as specified in [4].
802
803 From [4], section 7.1:
804 C{MMS-field-name = Short-integer}
805
806 @raise EncodeError: The specified header field name is not a
807 well-known MMS header.
808
809 @param fieldName: The header field name to encode
810 @type fieldName: str
811
812 @return: The encoded header field name, as a sequence of bytes
813 @rtype: list
814 """
815 encodedMMSFieldName = []
816 for assignedNumber in MMSEncodingAssignments.fieldNames:
817 if MMSEncodingAssignments.fieldNames[assignedNumber][0] == fieldName:
818 encodedMMSFieldName.extend(wsp_pdu.Encoder.encodeShortInteger(assignedNumber))
819 break
820 if len(encodedMMSFieldName) == 0:
821 raise wsp_pdu.EncodeError, 'The specified header field name is not a well-known MMS header field name'
822 return encodedMMSFieldName
823
824 @staticmethod
826 """ From [4], section 7.2.11:
827 From-value = Value-length (Address-present-token Encoded-string-value | Insert-address-token )
828 Address-present-token = <Octet 128>
829 Insert-address-token = <Octet 129>
830
831 @param fromValue: The "originator" of the MMS message. This may be an
832 empty string, in which case a token will be encoded
833 informing the MMSC to insert the address of the
834 device that sent this message (default).
835 @type fromValue: str
836
837 @return: The encoded "From" address value, as a sequence of bytes
838 @rtype: list
839 """
840 encodedFromValue = []
841 if len(fromValue) == 0:
842 valueLength = wsp_pdu.Encoder.encodeValueLength(1)
843 encodedFromValue.extend(valueLength)
844 encodedFromValue.append(129)
845 else:
846 encodedAddress = MMSEncoder.encodeEncodedStringValue(fromValue)
847 length = len(encodedAddress) + 1
848 valueLength = wsp_pdu.Encoder.encodeValueLength(length)
849 encodedFromValue.extend(valueLength)
850 encodedFromValue.append(128)
851 encodedFromValue.extend(encodedAddress)
852 return encodedFromValue
853
854 @staticmethod
856 """ From [4], section 7.2.9:
857 C{Encoded-string-value = Text-string | Value-length Char-set Text-string}
858 The Char-set values are registered by IANA as MIBEnum value.
859
860 @param stringValue: The text string to encode
861 @type stringValue: str
862
863 @note: This function is currently a simple wrappper to
864 C{encodeTextString()}
865
866 @return: The encoded string value, as a sequence of bytes
867 @rtype: list
868 """
869 return wsp_pdu.Encoder.encodeTextString(stringValue)
870
871 @staticmethod
873 """ Defined in [4], section 7.2.14.
874
875 @note: Unknown message types are discarded; thus they will be encoded
876 as 0x80 ("m-send-req") by this function
877
878 @param messageType: The MMS message type to encode
879 @type messageType: str
880
881 @return: The encoded message type, as a sequence of bytes
882 @rtype: list
883 """
884 messageTypes = {'m-send-req' : 0x80,
885 'm-send-conf' : 0x81,
886 'm-notification-ind' : 0x81,
887 'm-notifyresp-ind' : 0x83,
888 'm-retrieve-conf' : 0x84,
889 'm-acknowledge-ind' : 0x85,
890 'm-delivery-ind' : 0x86}
891 if messageType in messageTypes:
892 return [messageTypes[messageType]]
893 else:
894 return [0x80]
895