Mercurial > p > roundup > code
comparison roundup/mailgw.py @ 5418:55f09ca366c4
Python 3 preparation: StringIO.
This generally arranges for StringIO and cStringIO references to use
io.StringIO for Python 3 but io.BytesIO for Python 2, consistent with
the string representations generally used in Roundup. A special
FasterStringIO in the TAL code, which referenced internals of the old
Python 2 StringIO module, is cut down so it doesn't actually do
anything beyond the StringIO class it inherits from (it would also be
reasonable to remove FasterStringIO completely). One place in
roundup_server.py clearly needing binary I/O is made to use io.BytesIO
unconditionally.
| author | Joseph Myers <jsm@polyomino.org.uk> |
|---|---|
| date | Wed, 25 Jul 2018 09:08:29 +0000 |
| parents | 56c9bcdea47f |
| children | 86b6cea7a975 |
comparison
equal
deleted
inserted
replaced
| 5417:c749d6795bc2 | 5418:55f09ca366c4 |
|---|---|
| 93 explanatory message given in the exception. | 93 explanatory message given in the exception. |
| 94 """ | 94 """ |
| 95 from __future__ import print_function | 95 from __future__ import print_function |
| 96 __docformat__ = 'restructuredtext' | 96 __docformat__ = 'restructuredtext' |
| 97 | 97 |
| 98 import string, re, os, mimetools, cStringIO, smtplib, socket, binascii, quopri | 98 import string, re, os, mimetools, smtplib, socket, binascii, quopri |
| 99 import time, random, sys, logging | 99 import time, random, sys, logging |
| 100 import codecs | 100 import codecs |
| 101 import traceback | 101 import traceback |
| 102 import email.utils | 102 import email.utils |
| 103 | 103 |
| 106 | 106 |
| 107 from roundup import configuration, hyperdb, date, password, exceptions | 107 from roundup import configuration, hyperdb, date, password, exceptions |
| 108 from roundup.mailer import Mailer, MessageSendError | 108 from roundup.mailer import Mailer, MessageSendError |
| 109 from roundup.i18n import _ | 109 from roundup.i18n import _ |
| 110 from roundup.hyperdb import iter_roles | 110 from roundup.hyperdb import iter_roles |
| 111 from roundup.anypy.strings import StringIO | |
| 111 | 112 |
| 112 try: | 113 try: |
| 113 import pyme, pyme.core, pyme.constants, pyme.constants.sigsum | 114 import pyme, pyme.core, pyme.constants, pyme.constants.sigsum |
| 114 except ImportError: | 115 except ImportError: |
| 115 pyme = None | 116 pyme = None |
| 221 ''' Get a single part of a multipart message and return it as a new | 222 ''' Get a single part of a multipart message and return it as a new |
| 222 Message instance. | 223 Message instance. |
| 223 ''' | 224 ''' |
| 224 boundary = self.getparam('boundary') | 225 boundary = self.getparam('boundary') |
| 225 mid, end = '--'+boundary, '--'+boundary+'--' | 226 mid, end = '--'+boundary, '--'+boundary+'--' |
| 226 s = cStringIO.StringIO() | 227 s = StringIO() |
| 227 while 1: | 228 while 1: |
| 228 line = self.fp.readline() | 229 line = self.fp.readline() |
| 229 if not line: | 230 if not line: |
| 230 break | 231 break |
| 231 if line.strip() in (mid, end): | 232 if line.strip() in (mid, end): |
| 301 if self.gettype() == 'message/rfc822': | 302 if self.gettype() == 'message/rfc822': |
| 302 # handle message/rfc822 specially - the name should be | 303 # handle message/rfc822 specially - the name should be |
| 303 # the subject of the actual e-mail embedded here | 304 # the subject of the actual e-mail embedded here |
| 304 # we add a '.eml' extension like other email software does it | 305 # we add a '.eml' extension like other email software does it |
| 305 self.fp.seek(0) | 306 self.fp.seek(0) |
| 306 s = cStringIO.StringIO(self.getbody()) | 307 s = StringIO(self.getbody()) |
| 307 name = Message(s).getheader('subject') | 308 name = Message(s).getheader('subject') |
| 308 if name: | 309 if name: |
| 309 name = name + '.eml' | 310 name = name + '.eml' |
| 310 if not name: | 311 if not name: |
| 311 # try name on Content-Type | 312 # try name on Content-Type |
| 327 # BUG: is base64 really used for text encoding or | 328 # BUG: is base64 really used for text encoding or |
| 328 # are we inserting zip files here. | 329 # are we inserting zip files here. |
| 329 data = binascii.a2b_base64(self.fp.read()) | 330 data = binascii.a2b_base64(self.fp.read()) |
| 330 elif encoding == 'quoted-printable': | 331 elif encoding == 'quoted-printable': |
| 331 # the quopri module wants to work with files | 332 # the quopri module wants to work with files |
| 332 decoded = cStringIO.StringIO() | 333 decoded = StringIO() |
| 333 quopri.decode(self.fp, decoded) | 334 quopri.decode(self.fp, decoded) |
| 334 data = decoded.getvalue() | 335 data = decoded.getvalue() |
| 335 elif encoding == 'uuencoded': | 336 elif encoding == 'uuencoded': |
| 336 data = binascii.a2b_uu(self.fp.read()) | 337 data = binascii.a2b_uu(self.fp.read()) |
| 337 else: | 338 else: |
| 447 attachments.extend(new_attach) | 448 attachments.extend(new_attach) |
| 448 if ig and content_type == 'multipart/alternative' and content: | 449 if ig and content_type == 'multipart/alternative' and content: |
| 449 attachments = [] | 450 attachments = [] |
| 450 html_part = False | 451 html_part = False |
| 451 elif unpack_rfc822 and content_type == 'message/rfc822': | 452 elif unpack_rfc822 and content_type == 'message/rfc822': |
| 452 s = cStringIO.StringIO(self.getbody()) | 453 s = StringIO(self.getbody()) |
| 453 m = Message(s) | 454 m = Message(s) |
| 454 ig = ignore_alternatives and not content | 455 ig = ignore_alternatives and not content |
| 455 new_content, attachments, html_part = m.extract_content(m.gettype(), ig, | 456 new_content, attachments, html_part = m.extract_content(m.gettype(), ig, |
| 456 unpack_rfc822, html2text) | 457 unpack_rfc822, html2text) |
| 457 attachments.insert(0, m.text_as_attachment()) | 458 attachments.insert(0, m.text_as_attachment()) |
| 525 | 526 |
| 526 plaintext.seek(0,0) | 527 plaintext.seek(0,0) |
| 527 # pyme.core.Data implements a seek method with a different signature | 528 # pyme.core.Data implements a seek method with a different signature |
| 528 # than roundup can handle. So we'll put the data in a container that | 529 # than roundup can handle. So we'll put the data in a container that |
| 529 # the Message class can work with. | 530 # the Message class can work with. |
| 530 c = cStringIO.StringIO() | 531 c = StringIO() |
| 531 c.write(plaintext.read()) | 532 c.write(plaintext.read()) |
| 532 c.seek(0) | 533 c.seek(0) |
| 533 return Message(c) | 534 return Message(c) |
| 534 | 535 |
| 535 def verify_signature(self, author): | 536 def verify_signature(self, author): |
| 1326 Read into an internal structure that we can seek on (in case | 1327 Read into an internal structure that we can seek on (in case |
| 1327 there's an error). | 1328 there's an error). |
| 1328 | 1329 |
| 1329 XXX: we may want to read this into a temporary file instead... | 1330 XXX: we may want to read this into a temporary file instead... |
| 1330 """ | 1331 """ |
| 1331 s = cStringIO.StringIO() | 1332 s = StringIO() |
| 1332 s.write(sys.stdin.read()) | 1333 s.write(sys.stdin.read()) |
| 1333 s.seek(0) | 1334 s.seek(0) |
| 1334 self.main(s) | 1335 self.main(s) |
| 1335 return 0 | 1336 return 0 |
| 1336 | 1337 |
| 1422 | 1423 |
| 1423 # mark the message as deleted. | 1424 # mark the message as deleted. |
| 1424 server.store(str(i), '+FLAGS', r'(\Deleted)') | 1425 server.store(str(i), '+FLAGS', r'(\Deleted)') |
| 1425 | 1426 |
| 1426 # process the message | 1427 # process the message |
| 1427 s = cStringIO.StringIO(data[0][1]) | 1428 s = StringIO(data[0][1]) |
| 1428 s.seek(0) | 1429 s.seek(0) |
| 1429 self.handle_Message(Message(s)) | 1430 self.handle_Message(Message(s)) |
| 1430 server.close() | 1431 server.close() |
| 1431 finally: | 1432 finally: |
| 1432 try: | 1433 try: |
| 1491 # retr: returns | 1492 # retr: returns |
| 1492 # [ pop response e.g. '+OK 459 octets', | 1493 # [ pop response e.g. '+OK 459 octets', |
| 1493 # [ array of message lines ], | 1494 # [ array of message lines ], |
| 1494 # number of octets ] | 1495 # number of octets ] |
| 1495 lines = server.retr(i)[1] | 1496 lines = server.retr(i)[1] |
| 1496 s = cStringIO.StringIO('\n'.join(lines)) | 1497 s = StringIO('\n'.join(lines)) |
| 1497 s.seek(0) | 1498 s.seek(0) |
| 1498 self.handle_Message(Message(s)) | 1499 self.handle_Message(Message(s)) |
| 1499 # delete the message | 1500 # delete the message |
| 1500 server.dele(i) | 1501 server.dele(i) |
| 1501 | 1502 |
