From 706780f1b6239842176f418389d124dfa77d3446 Mon Sep 17 00:00:00 2001 From: Ramil Nugmanov Date: Sat, 24 Jan 2015 16:17:18 +0300 Subject: [PATCH 1/2] bugfix. for channel addresses added anonymous sending by using prefix "chan-" in toAddress field. --- bminterface.py | 148 ++++++++++++++++++++++++++++++------------------- outgoing.py | 4 +- 2 files changed, 92 insertions(+), 60 deletions(-) diff --git a/bminterface.py b/bminterface.py index 423af94..1fde95d 100644 --- a/bminterface.py +++ b/bminterface.py @@ -11,81 +11,97 @@ allMessages = [] currentAddress = None -def _getKeyLocation(): #make this not suck later + +def _getKeyLocation(): # make this not suck later return '~/.config/PyBitmessage/keys.dat' + def _getConfig(keys): return apiData() - #TODO make this work, so the above can be removed + # TODO make this work, so the above can be removed config = ConfigParser.SafeConfigParser() config.read(keys) try: - api_port = config.getint('bitmessagesettings', 'apiport') - api_iface = config.get('bitmessagesettings', 'apiinterface') - api_uname = config.get('bitmessagesettings', 'apiusername') - api_passwd = config.get('bitmessagesettings', 'apipassword') + api_port = config.getint('bitmessagesettings', 'apiport') + api_iface = config.get('bitmessagesettings', 'apiinterface') + api_uname = config.get('bitmessagesettings', 'apiusername') + api_passwd = config.get('bitmessagesettings', 'apipassword') except: logging.warning("Could not load keys.dat config") return 0 - return "http://"+api_uname+":"+api_passwd+"@"+api_iface+":"+str(api_port)+"/" + return "http://" + api_uname + ":" + api_passwd + "@" + api_iface + ":" + str(api_port) + "/" + def _makeApi(keys): return xmlrpclib.ServerProxy(_getConfig(keys)) - + + def _sendMessage(toAddress, fromAddress, subject, body): api = _makeApi(_getKeyLocation()) try: - return api.sendMessage(toAddress, fromAddress, subject, body) + return api.sendMessage(toAddress, fromAddress, subject, body) except: - return 0 - + return 0 + + def _sendBroadcast(fromAddress, subject, body): api = _makeApi(_getKeyLocation()) try: - return api.sendBroadcast(fromAddress, subject, body) + return api.sendBroadcast(fromAddress, subject, body) except: - return 0 - + return 0 + + def _stripAddress(address): if 'broadcast' in address.lower(): - return 'broadcast' + return 'broadcast', False + + if 'chan-' in address.lower()[:5]: + chan = True + else: + chan = False orig = address alphabet = '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ' retstring = '' while address: - if address[:3] == 'BM-': - retstring = 'BM-' - address = address[3:] - while address[0] in alphabet: - retstring += address[0] - address = address[1:] - else: - address = address[1:] + if address[:3] == 'BM-': + retstring = 'BM-' + address = address[3:] + while address[0] in alphabet: + retstring += address[0] + address = address[1:] + else: + address = address[1:] logging.info("converted address " + orig + " to " + retstring) - return retstring + return retstring, chan + def registerAddress(address): global currentAddress currentAddress = address logging.debug("Set current address to %s" % currentAddress) + def send(toAddress, fromAddress, subject, body): - toAddress = _stripAddress(toAddress) + toAddress, chan = _stripAddress(toAddress) fromAddress = _stripAddress(fromAddress) subject = subject.encode('base64') body = body.encode('base64') if toAddress == 'broadcast': - return _sendBroadcast(fromAddress, subject, body) + return _sendBroadcast(fromAddress, subject, body) + elif chan: + return _sendMessage(toAddress, toAddress, subject, body) else: - return _sendMessage(toAddress, fromAddress, subject, body) + return _sendMessage(toAddress, fromAddress, subject, body) + def _getAll(): global allMessages global currentAddress if not allMessages: - api = _makeApi(_getKeyLocation()) - allMessages = json.loads(api.getAllInboxMessages()) + api = _makeApi(_getKeyLocation()) + allMessages = json.loads(api.getAllInboxMessages()) logging.debug("current address is %s" % currentAddress) if currentAddress is not None: ret = [] @@ -95,70 +111,84 @@ def _getAll(): return dict(inboxMessages=ret) return allMessages + def get(msgID): inboxMessages = _getAll() - dateTime = email.utils.formatdate(time.mktime(datetime.datetime.fromtimestamp(float(inboxMessages['inboxMessages'][msgID]['receivedTime'])).timetuple())) + dateTime = email.utils.formatdate(time.mktime( + datetime.datetime.fromtimestamp(float(inboxMessages['inboxMessages'][msgID]['receivedTime'])).timetuple())) toAddress = inboxMessages['inboxMessages'][msgID]['toAddress'] + '@bm.addr' fromAddress = inboxMessages['inboxMessages'][msgID]['fromAddress'] + '@bm.addr' ##Disabled to support new chan format - #if 'Broadcast' in toAddress: + # if 'Broadcast' in toAddress: # toAddress = fromAddress + if toAddress == fromAddress: + toAddress = fromAddress = 'chan-' + fromAddress subject = inboxMessages['inboxMessages'][msgID]['subject'].decode('base64') body = inboxMessages['inboxMessages'][msgID]['message'].decode('base64') return dateTime, toAddress, fromAddress, subject, body - + + def listMsgs(): inboxMessages = _getAll() return len(inboxMessages['inboxMessages']) - + + def markForDelete(msgID): global purgeList inboxMessages = _getAll() msgRef = str(inboxMessages['inboxMessages'][msgID]['msgid']) purgeList.append(msgRef) return 0 - + + def cleanup(): global allMessages global purgeList while len(purgeList): - _deleteMessage(purgeList.pop()) + _deleteMessage(purgeList.pop()) allMessages = [] return 0 + def _deleteMessage(msgRef): api = _makeApi(_getKeyLocation()) - api.trashMessage(msgRef) #TODO uncomment this to allow deletion - return 0 - + api.trashMessage(msgRef) # TODO uncomment this to allow deletion + return 0 + + def getUIDLforAll(): api = _makeApi(_getKeyLocation()) inboxMessages = json.loads(api.getAllInboxMessages()) refdata = [] for msgID in range(len(inboxMessages['inboxMessages'])): - msgRef = inboxMessages['inboxMessages'][msgID]['msgid'] #gets the message Ref via the message index number - refdata.append(str(msgRef)) - return refdata #api.trashMessage(msgRef) #TODO uncomment this to allow deletion - + msgRef = inboxMessages['inboxMessages'][msgID]['msgid'] # gets the message Ref via the message index number + refdata.append(str(msgRef)) + return refdata # api.trashMessage(msgRef) #TODO uncomment this to allow deletion + + def getUIDLforSingle(msgID): api = _makeApi(_getKeyLocation()) inboxMessages = json.loads(api.getAllInboxMessages()) - msgRef = inboxMessages['inboxMessages'][msgID]['msgid'] #gets the message Ref via the message index number + msgRef = inboxMessages['inboxMessages'][msgID]['msgid'] # gets the message Ref via the message index number return [str(msgRef)] + ############################################################################## -def lookupAppdataFolder(): #gets the appropriate folders for the .dat files depending on the OS. Taken from bitmessagemain.py +def lookupAppdataFolder(): # gets the appropriate folders for the .dat files depending on the OS. Taken from bitmessagemain.py import sys + APPNAME = "PyBitmessage" from os import path, environ + if sys.platform == 'darwin': if "HOME" in environ: dataFolder = path.join(os.environ["HOME"], "Library/Application support/", APPNAME) + '/' else: - logging.warning('Could not find home folder, please report this message and your OS X version to the Daemon Github.') + logging.warning( + 'Could not find home folder, please report this message and your OS X version to the Daemon Github.') os.exit() elif 'win32' in sys.platform or 'win64' in sys.platform: @@ -166,26 +196,27 @@ def lookupAppdataFolder(): #gets the appropriate folders for the .dat files depe else: dataFolder = path.expanduser(path.join("~", "." + "config", APPNAME + "/")) return dataFolder - + + def apiData(): global keysPath - + config = ConfigParser.SafeConfigParser() keysPath = 'keys.dat' - config.read(keysPath) #First try to load the config file (the keys.dat file) from the program directory + config.read(keysPath) # First try to load the config file (the keys.dat file) from the program directory try: - config.get('bitmessagesettings','settingsversion') + config.get('bitmessagesettings', 'settingsversion') appDataFolder = '' except: - #Could not load the keys.dat file in the program directory. Perhaps it is in the appdata directory. + # Could not load the keys.dat file in the program directory. Perhaps it is in the appdata directory. appDataFolder = lookupAppdataFolder() keysPath = appDataFolder + 'keys.dat' config = ConfigParser.SafeConfigParser() config.read(keysPath) try: - config.get('bitmessagesettings','settingsversion') + config.get('bitmessagesettings', 'settingsversion') except: #keys.dat was not there either, something is wrong. print ' ' @@ -198,24 +229,25 @@ def apiData(): print ' ' try: - apiConfigured = config.getboolean('bitmessagesettings','apienabled') #Look for 'apienabled' + apiConfigured = config.getboolean('bitmessagesettings', 'apienabled') # Look for 'apienabled' apiEnabled = apiConfigured except: - apiConfigured = False #If not found, set to false since it still needs to be configured + apiConfigured = False # If not found, set to false since it still needs to be configured print "You need to edit your keys.dat file and enable bitmessage's API" print "See for more details: https://bitmessage.org/wiki/API" print "Will now crash..." raise - #if (apiConfigured == False):#If the apienabled == false or is not present in the keys.dat file, notify the user and set it up + # if (apiConfigured == False):#If the apienabled == false or is not present in the keys.dat file, notify the user and set it up #apiInit(apiEnabled) #Initalize the keys.dat file with API information - #keys.dat file was found or appropriately configured, allow information retrieval - apiEnabled = config.getboolean('bitmessagesettings','apienabled') + # keys.dat file was found or appropriately configured, allow information retrieval + apiEnabled = config.getboolean('bitmessagesettings', 'apienabled') apiPort = config.getint('bitmessagesettings', 'apiport') apiInterface = config.get('bitmessagesettings', 'apiinterface') apiUsername = config.get('bitmessagesettings', 'apiusername') apiPassword = config.get('bitmessagesettings', 'apipassword') - - return "http://" + apiUsername + ":" + apiPassword + "@" + apiInterface+ ":" + str(apiPort) + "/" #Build the api credentials + + return "http://" + apiUsername + ":" + apiPassword + "@" + apiInterface + ":" + str( + apiPort) + "/" #Build the api credentials diff --git a/outgoing.py b/outgoing.py index c2e787d..e3a2b0b 100644 --- a/outgoing.py +++ b/outgoing.py @@ -59,7 +59,7 @@ def _recurseParse(self, msg): image += '' elif 'multipart' in item['Content-Type']: firstTest_new, text_new, image_new = self._recurseParse(item) - text += firstText_new + text_new + text += firstTest_new + text_new image += image_new else: #Note that there's a chance we may die horribly if nothing returns. @@ -110,4 +110,4 @@ def run(): if __name__ == '__main__': - run() + run() From b5120a49d7aa1711373c176f202ad8bffc70134f Mon Sep 17 00:00:00 2001 From: Ramil Nugmanov Date: Fri, 20 Feb 2015 23:55:21 +0300 Subject: [PATCH 2/2] fix --- bminterface.py | 22 ++---- incoming.py | 187 +++++++++++++++++++++++++++---------------------- outgoing.py | 159 ++++++++++++++++++++--------------------- 3 files changed, 191 insertions(+), 177 deletions(-) diff --git a/bminterface.py b/bminterface.py index 1fde95d..e0be004 100644 --- a/bminterface.py +++ b/bminterface.py @@ -1,4 +1,5 @@ import ConfigParser +import re import xmlrpclib import json import datetime @@ -56,25 +57,16 @@ def _stripAddress(address): if 'broadcast' in address.lower(): return 'broadcast', False + orig = address + address = re.search('(chan-)?BM-[0-9a-zA-Z]+', address).group() if 'chan-' in address.lower()[:5]: chan = True + address = address[5:] else: chan = False - orig = address - alphabet = '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ' - retstring = '' - while address: - if address[:3] == 'BM-': - retstring = 'BM-' - address = address[3:] - while address[0] in alphabet: - retstring += address[0] - address = address[1:] - else: - address = address[1:] - logging.info("converted address " + orig + " to " + retstring) - return retstring, chan + logging.info("converted address " + orig + " to " + address) + return address, chan def registerAddress(address): @@ -85,7 +77,7 @@ def registerAddress(address): def send(toAddress, fromAddress, subject, body): toAddress, chan = _stripAddress(toAddress) - fromAddress = _stripAddress(fromAddress) + fromAddress = _stripAddress(fromAddress)[0] subject = subject.encode('base64') body = body.encode('base64') if toAddress == 'broadcast': diff --git a/incoming.py b/incoming.py index 7a8987a..6b29b07 100644 --- a/incoming.py +++ b/incoming.py @@ -12,28 +12,32 @@ class ChatterboxConnection(object): END = "\r\n" + def __init__(self, conn): - self.conn = conn + self.conn = conn + def __getattr__(self, name): - return getattr(self.conn, name) + return getattr(self.conn, name) + def sendall(self, data, END=END): - data += END - self.conn.sendall(data) + data += END + self.conn.sendall(data) + def recvall(self, END=END): - data = [] - while True: - chunk = self.conn.recv(4096) - if END in chunk: - data.append(chunk[:chunk.index(END)]) - break - data.append(chunk) - if len(data) > 1: - pair = data[-2] + data[-1] - if END in pair: - data[-2] = pair[:pair.index(END)] - data.pop() - break - return "".join(data) + data = [] + while True: + chunk = self.conn.recv(4096) + if END in chunk: + data.append(chunk[:chunk.index(END)]) + break + data.append(chunk) + if len(data) > 1: + pair = data[-2] + data[-1] + if END in pair: + data[-2] = pair[:pair.index(END)] + data.pop() + break + return "".join(data) def handleUser(data): @@ -48,28 +52,32 @@ def handleUser(data): bminterface.registerAddress(None) return "+OK user accepted" + def handlePass(data): return "+OK pass accepted" + def _getMsgSizes(): msgCount = bminterface.listMsgs() msgSizes = [] for msgID in range(msgCount): - logging.debug("Parsing msg %i of %i" % (msgID+1, msgCount)) - dateTime, toAddress, fromAddress, subject, body = bminterface.get(msgID) - msgSizes.append(len(makeEmail(dateTime, toAddress, fromAddress, subject, body))) + logging.debug("Parsing msg %i of %i" % (msgID + 1, msgCount)) + dateTime, toAddress, fromAddress, subject, body = bminterface.get(msgID) + msgSizes.append(len(makeEmail(dateTime, toAddress, fromAddress, subject, body))) return msgSizes + def handleStat(data): msgSizes = _getMsgSizes() msgCount = len(msgSizes) msgSizeTotal = 0 for msgSize in msgSizes: - msgSizeTotal += msgSize + msgSizeTotal += msgSize returnData = '+OK %i %i' % (msgCount, msgSizeTotal) logging.debug("Answering STAT: %i %i" % (msgCount, msgSizeTotal)) return returnData + def handleList(data): dataList = data.split() cmd = dataList[0] @@ -87,9 +95,9 @@ def handleList(data): returnDataPart2 = '' msgSizeTotal = 0 for msgSize in msgSizes: - msgSizeTotal += msgSize - msgCount += 1 - returnDataPart2 += '%i %i\r\n' % (msgCount, msgSize) + msgSizeTotal += msgSize + msgCount += 1 + returnDataPart2 += '%i %i\r\n' % (msgCount, msgSize) returnDataPart2 += '.' returnDataPart1 = '+OK %i messages (%i octets)\r\n' % (msgCount, msgSizeTotal) returnData = returnDataPart1 + returnDataPart2 @@ -97,39 +105,45 @@ def handleList(data): logging.debug(returnData) return returnData + def handleTop(data): msg = 'test' logging.debug(data.split()) cmd, msgID, lines = data.split() - msgID = int(msgID)-1 + msgID = int(msgID) - 1 lines = int(lines) logging.debug(lines) dateTime, toAddress, fromAddress, subject, body = bminterface.get(msgID) logging.debug(subject) msg = makeEmail(dateTime, toAddress, fromAddress, subject, body) top, bot = msg.split("\n\n", 1) - #text = top + "\r\n\r\n" + "\r\n".join(bot[:lines]) + # text = top + "\r\n\r\n" + "\r\n".join(bot[:lines]) return "+OK top of message follows\r\n%s\r\n." % top + def handleRetr(data): logging.debug(data.split()) - msgID = int(data.split()[1])-1 + msgID = int(data.split()[1]) - 1 dateTime, toAddress, fromAddress, subject, body = bminterface.get(msgID) msg = makeEmail(dateTime, toAddress, fromAddress, subject, body) return "+OK %i octets\r\n%s\r\n." % (len(msg), msg) + def handleDele(data): - msgID = int(data.split()[1])-1 + msgID = int(data.split()[1]) - 1 bminterface.markForDelete(msgID) return "+OK I'll try..." + def handleNoop(data): return "+OK" + def handleQuit(data): bminterface.cleanup() return "+OK just pretend I'm gone" + def handleCapa(data): returnData = "+OK List of capabilities follows\r\n" for k in dispatch: @@ -137,87 +151,91 @@ def handleCapa(data): returnData += "." return returnData + def handleUIDL(data): data = data.split() logging.debug(data) if len(data) == 1: - refdata = bminterface.getUIDLforAll() - logging.debug(refdata) - returnData = '+OK\r\n' - for msgID, d in enumerate(refdata): - returnData += "%s %s\r\n" % (msgID+1, d) - returnData += '.' + refdata = bminterface.getUIDLforAll() + logging.debug(refdata) + returnData = '+OK\r\n' + for msgID, d in enumerate(refdata): + returnData += "%s %s\r\n" % (msgID + 1, d) + returnData += '.' else: - refdata = bminterface.getUIDLforSingle(int(data[1])-1) - logging.debug(refdata) - returnData = '+OK ' + data[0] + str(refdata[0]) + refdata = bminterface.getUIDLforSingle(int(data[1]) - 1) + logging.debug(refdata) + returnData = '+OK ' + data[0] + str(refdata[0]) return returnData - + + def makeEmail(dateTime, toAddress, fromAddress, subject, body): body = parseBody(body) msgType = len(body) if msgType == 1: - msg = email.mime.text.MIMEText(body[0], 'plain', 'UTF-8') + msg = email.mime.text.MIMEText(body[0], 'plain', 'UTF-8') else: - msg = email.mime.multipart.MIMEMultipart('mixed') - bodyText = email.mime.text.MIMEText(body[0], 'plain', 'UTF-8') - body = body[1:] - msg.attach(bodyText) - for item in body: - img = 0 - itemType, itemData = [0], [0] - try: - itemType, itemData = item.split(';', 1) - itemType = itemType.split('/', 1) - except: - logging.warning("Could not parse message type") - pass - if itemType[0] == 'image': - try: - itemDataFinal = itemData.lstrip('base64,').strip(' ').strip('\n').decode('base64') - img = email.mime.image.MIMEImage(itemDataFinal) - except: - #Some images don't auto-detect type correctly with email.mime.image - #Namely, jpegs with embeded color profiles look problematic - #Trying to set it manually... + msg = email.mime.multipart.MIMEMultipart('mixed') + bodyText = email.mime.text.MIMEText(body[0], 'plain', 'UTF-8') + body = body[1:] + msg.attach(bodyText) + for item in body: + img = 0 + itemType, itemData = [0], [0] try: - itemDataFinal = itemData.lstrip('base64,').strip(' ').strip('\n').decode('base64') - img = email.mime.image.MIMEImage(itemDataFinal, _subtype=itemType[1]) + itemType, itemData = item.split(';', 1) + itemType = itemType.split('/', 1) except: - logging.warning("Failed to parse image data. This could be an image.") - logging.warning("This could be from an image tag filled with junk data.") - logging.warning("It could also be a python email.mime.image problem.") - if img: - img.add_header('Content-Disposition', 'attachment') - msg.attach(img) + logging.warning("Could not parse message type") + pass + if itemType[0] == 'image': + try: + itemDataFinal = itemData.lstrip('base64,').strip(' ').strip('\n').decode('base64') + img = email.mime.image.MIMEImage(itemDataFinal) + except: + # Some images don't auto-detect type correctly with email.mime.image + #Namely, jpegs with embeded color profiles look problematic + #Trying to set it manually... + try: + itemDataFinal = itemData.lstrip('base64,').strip(' ').strip('\n').decode('base64') + img = email.mime.image.MIMEImage(itemDataFinal, _subtype=itemType[1]) + except: + logging.warning("Failed to parse image data. This could be an image.") + logging.warning("This could be from an image tag filled with junk data.") + logging.warning("It could also be a python email.mime.image problem.") + if img: + img.add_header('Content-Disposition', 'attachment') + msg.attach(img) msg['To'] = toAddress msg['From'] = fromAddress msg['Subject'] = email.header.Header(subject, 'UTF-8') msg['Date'] = dateTime return msg.as_string() - + + def parseBody(body): returnData = [] text = '' searchString = ']*' attachment = re.search(searchString, body) while attachment: - imageCode = body[attachment.start():attachment.end()] - imageDataRange = re.search('src=[\"\'][^\"\']*[\"\']', imageCode) - imageData='' - if imageDataRange: - try: - imageData = imageCode[imageDataRange.start()+5:imageDataRange.end()-1].lstrip('data:') - except: - pass - if imageData: - returnData.append(imageData) - body = body[:attachment.start()] + body[attachment.end()+1:] - attachment = re.search(searchString, body) + imageCode = body[attachment.start():attachment.end()] + imageDataRange = re.search('src=[\"\'][^\"\']*[\"\']', imageCode) + imageData = '' + if imageDataRange: + try: + imageData = imageCode[imageDataRange.start() + 5:imageDataRange.end() - 1].lstrip('data:') + except: + pass + if imageData: + returnData.append(imageData) + body = body[:attachment.start()] + body[attachment.end() + 1:] + attachment = re.search(searchString, body) text = body returnData = [text] + returnData return returnData + dispatch = dict( USER=handleUser, PASS=handlePass, @@ -239,6 +257,7 @@ def incomingServer(host, port, run_event): popthread.start() return popthread + def incomingServer_main(host, port, run_event): sock = None try: @@ -274,9 +293,9 @@ def incomingServer_main(host, port, run_event): conn.close() except (SystemExit, KeyboardInterrupt): - pass + pass except Exception, ex: - raise + raise finally: if sock is not None: sock.close() diff --git a/outgoing.py b/outgoing.py index e3a2b0b..079803b 100644 --- a/outgoing.py +++ b/outgoing.py @@ -4,6 +4,7 @@ import bminterface import logging + class outgoingServer(SMTPServer): def process_message(self, peer, mailfrom, rcpttos, data): parser = email.parser.FeedParser() @@ -12,95 +13,97 @@ def process_message(self, peer, mailfrom, rcpttos, data): toAddress = msg['To'] fromAddress = msg['From'] - subject = u' '.join(unicode(t[0], t[1] or 'UTF-8') for t in email.header.decode_header(msg['Subject'])).encode('UTF-8') + subject = u' '.join(unicode(t[0], t[1] or 'UTF-8') for t in email.header.decode_header(msg['Subject'])).encode( + 'UTF-8') body = self._bmformat(msg) - - #Make sure we don't send an actually blank subject or body--this can cause problems. + + # Make sure we don't send an actually blank subject or body--this can cause problems. if not subject: - subject = ' ' + subject = ' ' if not body: - body = ' ' - + body = ' ' + if bminterface.send(toAddress, fromAddress, subject, body): - logging.info("Message queued for sending...") + logging.info("Message queued for sending...") else: - logging.info("There was an error trying to send the message...") - + logging.info("There was an error trying to send the message...") + return 0 - + def _bmformat(self, msg): - disclaimer = "\n\n\n" - imageNotice = "\n" - if not msg.is_multipart(): - #This is a single part message, so there's nothing to do. - #Will still parse, just to get rid of awkward quote '>' everywhere. - myText, oldText = self._parseQuoteText(msg.get_payload()) - return myText + oldText - else: - #This is a multipart message. - #Unfortunately, now we have to actually do work. - myText, oldText, image = self._recurseParse(msg) - return imageNotice + myText + oldText + disclaimer + image - - def _recurseParse(self, msg): - text = '' - image = '' - for item in msg.get_payload(): - if 'text/plain' in item['Content-Type']: - text += item.get_payload() - elif 'image' in item['Content-Type']: - [filetype, name] = item['Content-Type'].rstrip().split('\n') - name = name.replace('name', 'alt') - imageraw = item.get_payload().rstrip().split('\n') - imagedata = '' - for line in imageraw: - if not line[0] == '-': - imagedata += line - image += '' - elif 'multipart' in item['Content-Type']: - firstTest_new, text_new, image_new = self._recurseParse(item) - text += firstTest_new + text_new - image += image_new + disclaimer = "\n\n\n" + imageNotice = "\n" + if not msg.is_multipart(): + # This is a single part message, so there's nothing to do. + #Will still parse, just to get rid of awkward quote '>' everywhere. + myText, oldText = self._parseQuoteText(msg.get_payload()) + return myText + oldText else: - #Note that there's a chance we may die horribly if nothing returns. - pass - firstText, text = self._parseQuoteText(text) - return firstText, text, image + # This is a multipart message. + #Unfortunately, now we have to actually do work. + myText, oldText, image = self._recurseParse(msg) + return imageNotice + myText + oldText + disclaimer + image - def _parseQuoteText(self, text): - rawText = text.split('\n') - tempText = [] - text = '' - firstText = '' - n = 0 - while len(rawText): - for line in range(len(rawText)): - if rawText[line]: - if (rawText[line][0] == '>'): # and rawText[line].strip('>')[0] == ' '): - rawText[line] = rawText[line][1:] - if rawText[line]: - if rawText[line][0] == ' ': - rawText[line] = rawText[line][1:] - tempText.append(rawText[line]) - else: - if n == 0: - firstText += rawText[line]+'\n' - else: - text += rawText[line]+'\n' - else: - if n == 0: - firstText += '\n' + def _recurseParse(self, msg): + text = '' + image = '' + for item in msg.get_payload(): + if 'text/plain' in item['Content-Type']: + text += item.get_payload() + elif 'image' in item['Content-Type']: + [filetype, name] = item['Content-Type'].rstrip().split('\n') + name = name.replace('name', 'alt') + imageraw = item.get_payload().rstrip().split('\n') + imagedata = '' + for line in imageraw: + if not line[0] == '-': + imagedata += line + image += '' + elif 'multipart' in item['Content-Type']: + firstTest_new, text_new, image_new = self._recurseParse(item) + text += firstTest_new + text_new + image += image_new else: - text += '\n' - if len(tempText): - text += '\n\n------------------------------------------------------\n' - rawText = tempText + # Note that there's a chance we may die horribly if nothing returns. + pass + firstText, text = self._parseQuoteText(text) + return firstText, text, image + + def _parseQuoteText(self, text): + rawText = text.split('\n') tempText = [] - n += 1 - text = text.rstrip('\n') - firstText = firstText.rstrip('\n') - return firstText, text - + text = '' + firstText = '' + n = 0 + while len(rawText): + for line in range(len(rawText)): + if rawText[line]: + if (rawText[line][0] == '>'): # and rawText[line].strip('>')[0] == ' '): + rawText[line] = rawText[line][1:] + if rawText[line]: + if rawText[line][0] == ' ': + rawText[line] = rawText[line][1:] + tempText.append(rawText[line]) + else: + if n == 0: + firstText += rawText[line] + '\n' + else: + text += rawText[line] + '\n' + else: + if n == 0: + firstText += '\n' + else: + text += '\n' + if len(tempText): + text += '\n\n------------------------------------------------------\n' + rawText = tempText + tempText = [] + n += 1 + text = text.rstrip('\n') + firstText = firstText.rstrip('\n') + return firstText, text + + def run(): foo = outgoingServer(('localhost', 12345), None) try: