You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

111 lines
3.3 KiB

  1. # TODO add the license
  2. # I had to rewrite this class because the python MIME email.mime (version 2.5)
  3. # are buggy, they use \n instead \r\n for new line which is not compliant
  4. # to standard!
  5. # http://bugs.python.org/issue5525
  6. # TODO do not load all the message in memory stream it from the disk
  7. import re
  8. import random
  9. import sys
  10. # new line
  11. NL = '\r\n'
  12. _width = len(repr(sys.maxsize - 1))
  13. _fmt = '%%0%dd' % _width
  14. class MIMEMessage:
  15. def __init__(self):
  16. self._files = []
  17. self._xmlMessage = ""
  18. self._startCID = ""
  19. self._boundary = ""
  20. def makeBoundary(self):
  21. # create the boundary
  22. msgparts = []
  23. msgparts.append(self._xmlMessage)
  24. for i in self._files:
  25. msgparts.append(i.read())
  26. # this sucks, all in memory
  27. alltext = NL.join(msgparts)
  28. self._boundary = _make_boundary(alltext)
  29. # maybe I can save some memory
  30. del alltext
  31. del msgparts
  32. self._startCID = "<" + (_fmt % random.randrange(sys.maxsize)) \
  33. + (_fmt % random.randrange(sys.maxsize)) + ">"
  34. def toString(self):
  35. '''it return a string with the MIME message'''
  36. if len(self._boundary) == 0:
  37. # the makeBoundary hasn't been called yet
  38. self.makeBoundary()
  39. # ok we have everything let's start to spit the message out
  40. # first the XML
  41. returnstr = NL + "--" + self._boundary + NL
  42. returnstr += "Content-Type: text/xml; charset=\"us-ascii\"" + NL
  43. returnstr += "Content-Transfer-Encoding: 7bit" + NL
  44. returnstr += "Content-Id: " + self._startCID + NL + NL
  45. returnstr += self._xmlMessage + NL
  46. # then the files
  47. for file in self._files:
  48. returnstr += "--" + self._boundary + NL
  49. returnstr += "Content-Type: application/octet-stream" + NL
  50. returnstr += "Content-Transfer-Encoding: binary" + NL
  51. returnstr += "Content-Id: <" + str(id(file)) + ">" + NL + NL
  52. file.seek(0)
  53. returnstr += file.read() + NL
  54. # closing boundary
  55. returnstr += "--" + self._boundary + "--" + NL
  56. return returnstr
  57. def attachFile(self, file):
  58. '''
  59. it adds a file to this attachment
  60. '''
  61. self._files.append(file)
  62. def addXMLMessage(self, xmlMessage):
  63. '''
  64. it adds the XML message. we can have only one XML SOAP message
  65. '''
  66. self._xmlMessage = xmlMessage
  67. def getBoundary(self):
  68. '''
  69. this function returns the string used in the mime message as a
  70. boundary. First the write method as to be called
  71. '''
  72. return self._boundary
  73. def getStartCID(self):
  74. '''
  75. This function returns the CID of the XML message
  76. '''
  77. return self._startCID
  78. def _make_boundary(text=None):
  79. # some code taken from python stdlib
  80. # Craft a random boundary. If text is given, ensure that the chosen
  81. # boundary doesn't appear in the text.
  82. token = random.randrange(sys.maxsize)
  83. boundary = ('=' * 10) + (_fmt % token) + '=='
  84. if text is None:
  85. return boundary
  86. b = boundary
  87. counter = 0
  88. while True:
  89. cre = re.compile('^--' + re.escape(b) + '(--)?$', re.MULTILINE)
  90. if not cre.search(text):
  91. break
  92. b = boundary + '.' + str(counter)
  93. counter += 1
  94. return b