diff --git a/bminterface.py b/bminterface.py index 423af94..1560e7c 100644 --- a/bminterface.py +++ b/bminterface.py @@ -1,11 +1,16 @@ -import ConfigParser -import xmlrpclib -import json +from six.moves import configparser +from six.moves import xmlrpc_client import datetime import time import email.utils import os import logging +from codecs import encode, decode + +try: + SafeConfigParser = configparser.SafeConfigParser +except AttributeError: + SafeConfigParser = configparser.ConfigParser purgeList = [] allMessages = [] @@ -17,7 +22,7 @@ def _getKeyLocation(): #make this not suck later def _getConfig(keys): return apiData() #TODO make this work, so the above can be removed - config = ConfigParser.SafeConfigParser() + config = SafeConfigParser() config.read(keys) try: api_port = config.getint('bitmessagesettings', 'apiport') @@ -30,7 +35,7 @@ def _getConfig(keys): return "http://"+api_uname+":"+api_passwd+"@"+api_iface+":"+str(api_port)+"/" def _makeApi(keys): - return xmlrpclib.ServerProxy(_getConfig(keys)) + return xmlrpc_client.ServerProxy(_getConfig(keys)) def _sendMessage(toAddress, fromAddress, subject, body): api = _makeApi(_getKeyLocation()) @@ -73,8 +78,8 @@ def registerAddress(address): def send(toAddress, fromAddress, subject, body): toAddress = _stripAddress(toAddress) fromAddress = _stripAddress(fromAddress) - subject = subject.encode('base64') - body = body.encode('base64') + subject = encode(subject.encode("utf-8", "replace"), 'base64').decode("utf-8", "replace") + body = encode(body.encode("utf-8", "replace"), 'base64').decode("utf-8", "replace") if toAddress == 'broadcast': return _sendBroadcast(fromAddress, subject, body) else: @@ -85,12 +90,13 @@ def _getAll(): global currentAddress if not allMessages: api = _makeApi(_getKeyLocation()) - allMessages = json.loads(api.getAllInboxMessages()) + allMessages = api.getAllInboxMessages() logging.debug("current address is %s" % currentAddress) if currentAddress is not None: ret = [] + cur_addr = currentAddress.decode("utf-8", "replace") for msg in allMessages['inboxMessages']: - if msg['toAddress'] == currentAddress: + if msg['toAddress'] == cur_addr: ret.append(msg) return dict(inboxMessages=ret) return allMessages @@ -105,8 +111,8 @@ def get(msgID): #if 'Broadcast' in toAddress: # toAddress = fromAddress - subject = inboxMessages['inboxMessages'][msgID]['subject'].decode('base64') - body = inboxMessages['inboxMessages'][msgID]['message'].decode('base64') + subject = decode(inboxMessages['inboxMessages'][msgID]['subject'].encode("utf-8", "replace"), 'base64') + body = decode(inboxMessages['inboxMessages'][msgID]['message'].encode("utf-8", "replace"), 'base64') return dateTime, toAddress, fromAddress, subject, body def listMsgs(): @@ -135,7 +141,7 @@ def _deleteMessage(msgRef): def getUIDLforAll(): api = _makeApi(_getKeyLocation()) - inboxMessages = json.loads(api.getAllInboxMessages()) + inboxMessages = _getAll() refdata = [] for msgID in range(len(inboxMessages['inboxMessages'])): msgRef = inboxMessages['inboxMessages'][msgID]['msgid'] #gets the message Ref via the message index number @@ -144,7 +150,7 @@ def getUIDLforAll(): def getUIDLforSingle(msgID): api = _makeApi(_getKeyLocation()) - inboxMessages = json.loads(api.getAllInboxMessages()) + inboxMessages = _getAll() msgRef = inboxMessages['inboxMessages'][msgID]['msgid'] #gets the message Ref via the message index number return [str(msgRef)] @@ -170,7 +176,7 @@ def lookupAppdataFolder(): #gets the appropriate folders for the .dat files depe def apiData(): global keysPath - config = ConfigParser.SafeConfigParser() + config = SafeConfigParser() keysPath = 'keys.dat' config.read(keysPath) #First try to load the config file (the keys.dat file) from the program directory @@ -181,30 +187,30 @@ def apiData(): #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 = SafeConfigParser() config.read(keysPath) try: config.get('bitmessagesettings','settingsversion') except: #keys.dat was not there either, something is wrong. - print ' ' - print '******************************************************************' - print 'There was a problem trying to access the Bitmessage keys.dat file.' - print 'Make sure that daemon is in the same directory as Bitmessage.' - print '******************************************************************' - print ' ' - print config - print ' ' + print(' ') + print('******************************************************************') + print('There was a problem trying to access the Bitmessage keys.dat file.') + print('Make sure that daemon is in the same directory as Bitmessage.') + print('******************************************************************') + print(' ') + print(config) + print(' ') try: 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 - 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..." + 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 diff --git a/incoming.py b/incoming.py index 7a8987a..045a276 100644 --- a/incoming.py +++ b/incoming.py @@ -11,7 +11,7 @@ class ChatterboxConnection(object): - END = "\r\n" + END = b"\r\n" def __init__(self, conn): self.conn = conn def __getattr__(self, name): @@ -33,23 +33,23 @@ def recvall(self, END=END): data[-2] = pair[:pair.index(END)] data.pop() break - return "".join(data) + return b"".join(data) def handleUser(data): d = data.split() logging.debug("data:%s" % d) username = d[-1] - if username[:3] == 'BM-': + if username[:3] == b'BM-': logging.debug("Only showing messages for %s" % username) bminterface.registerAddress(username) else: logging.debug("Showing all messages in the inbox") bminterface.registerAddress(None) - return "+OK user accepted" + return b"+OK user accepted" def handlePass(data): - return "+OK pass accepted" + return b"+OK pass accepted" def _getMsgSizes(): msgCount = bminterface.listMsgs() @@ -66,7 +66,7 @@ def handleStat(data): msgSizeTotal = 0 for msgSize in msgSizes: msgSizeTotal += msgSize - returnData = '+OK %i %i' % (msgCount, msgSizeTotal) + returnData = b'+OK %i %i' % (msgCount, msgSizeTotal) logging.debug("Answering STAT: %i %i" % (msgCount, msgSizeTotal)) return returnData @@ -79,26 +79,26 @@ def handleList(data): # means the server wants a single message response i = int(msgId) - 1 if i >= len(msgSizes): - return "-ERR no such message" + return b"-ERR no such message" else: msgSize = msgSizes[i] - return "+OK %s %s" % (msgId, msgSize) + return b"+OK %i %i" % (msgId, msgSize) msgCount = 0 - returnDataPart2 = '' + returnDataPart2 = b'' msgSizeTotal = 0 for msgSize in msgSizes: msgSizeTotal += msgSize msgCount += 1 - returnDataPart2 += '%i %i\r\n' % (msgCount, msgSize) - returnDataPart2 += '.' - returnDataPart1 = '+OK %i messages (%i octets)\r\n' % (msgCount, msgSizeTotal) + returnDataPart2 += b'%i %i\r\n' % (msgCount, msgSize) + returnDataPart2 += b'.' + returnDataPart1 = b'+OK %i messages (%i octets)\r\n' % (msgCount, msgSizeTotal) returnData = returnDataPart1 + returnDataPart2 logging.debug("Answering LIST: %i %i" % (msgCount, msgSizeTotal)) logging.debug(returnData) return returnData def handleTop(data): - msg = 'test' + msg = b'test' logging.debug(data.split()) cmd, msgID, lines = data.split() msgID = int(msgID)-1 @@ -107,34 +107,37 @@ def handleTop(data): 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]) - return "+OK top of message follows\r\n%s\r\n." % top + top, bot = msg.split(b"\n\n", 1) + #text = top + b"\r\n\r\n" + b"\r\n".join(bot[:lines]) + return b"+OK top of message follows\r\n%s\r\n." % top def handleRetr(data): logging.debug(data.split()) msgID = int(data.split()[1])-1 + msgCount = bminterface.listMsgs() + if msgID >= msgCount: + return b"-ERR no such message" 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) + return b"+OK %i octets\r\n%b\r\n." % (len(msg), msg.encode("utf-8", "replace")) def handleDele(data): msgID = int(data.split()[1])-1 bminterface.markForDelete(msgID) - return "+OK I'll try..." + return b"+OK I'll try..." def handleNoop(data): - return "+OK" + return b"+OK" def handleQuit(data): bminterface.cleanup() - return "+OK just pretend I'm gone" + return b"+OK just pretend I'm gone" def handleCapa(data): - returnData = "+OK List of capabilities follows\r\n" + returnData = b"+OK List of capabilities follows\r\n" for k in dispatch: - returnData += "%s\r\n" % k - returnData += "." + returnData += b"%b\r\n" % k.encode("utf-8", "replace") + returnData += b"." return returnData def handleUIDL(data): @@ -143,14 +146,14 @@ def handleUIDL(data): if len(data) == 1: refdata = bminterface.getUIDLforAll() logging.debug(refdata) - returnData = '+OK\r\n' + returnData = b'+OK\r\n' for msgID, d in enumerate(refdata): - returnData += "%s %s\r\n" % (msgID+1, d) - returnData += '.' + returnData += b"%i %b\r\n" % (msgID+1, d.encode("utf-8", "replace")) + returnData += b'.' else: refdata = bminterface.getUIDLforSingle(int(data[1])-1) logging.debug(refdata) - returnData = '+OK ' + data[0] + str(refdata[0]) + returnData = b'+OK ' + data[0] + refdata[0] return returnData def makeEmail(dateTime, toAddress, fromAddress, subject, body): @@ -198,16 +201,16 @@ def makeEmail(dateTime, toAddress, fromAddress, subject, body): def parseBody(body): returnData = [] - text = '' - searchString = ']*' + text = b'' + searchString = b']*' attachment = re.search(searchString, body) while attachment: imageCode = body[attachment.start():attachment.end()] - imageDataRange = re.search('src=[\"\'][^\"\']*[\"\']', imageCode) + imageDataRange = re.search(b'src=[\"\'][^\"\']*[\"\']', imageCode) imageData='' if imageDataRange: try: - imageData = imageCode[imageDataRange.start()+5:imageDataRange.end()-1].lstrip('data:') + imageData = imageCode[imageDataRange.start()+5:imageDataRange.end()-1].lstrip(b'data:') except: pass if imageData: @@ -257,15 +260,15 @@ def incomingServer_main(host, port, run_event): sock = None try: conn = ChatterboxConnection(conn) - conn.sendall("+OK server ready") + conn.sendall(b"+OK server ready") while run_event.is_set(): data = conn.recvall() logging.debug("Answering %s" % data) - command = data.split(None, 1)[0] + command = data.split(None, 1)[0].decode("utf-8", "replace") try: cmd = dispatch[command] except KeyError: - conn.sendall("-ERR unknown command") + conn.sendall(b"-ERR unknown command") else: conn.sendall(cmd(data)) if cmd is handleQuit: @@ -275,7 +278,7 @@ def incomingServer_main(host, port, run_event): except (SystemExit, KeyboardInterrupt): pass - except Exception, ex: + except Exception as ex: raise finally: if sock is not None: diff --git a/outgoing.py b/outgoing.py index c2e787d..8b24cb6 100644 --- a/outgoing.py +++ b/outgoing.py @@ -5,14 +5,14 @@ import logging class outgoingServer(SMTPServer): - def process_message(self, peer, mailfrom, rcpttos, data): + def process_message(self, peer, mailfrom, rcpttos, data, mail_options=[], rcpt_options=[]): parser = email.parser.FeedParser() - parser.feed(data) + parser.feed(data.decode("utf-8", "replace")) msg = parser.close() 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 = ' '.join(t[0] for t in email.header.decode_header(msg['Subject'])) body = self._bmformat(msg) #Make sure we don't send an actually blank subject or body--this can cause problems. @@ -49,7 +49,7 @@ def _recurseParse(self, msg): 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') + filetype, name = item['Content-Type'].rstrip().split(' ') name = name.replace('name', 'alt') imageraw = item.get_payload().rstrip().split('\n') imagedata = ''