Adding refactored changes

This commit is contained in:
Chuck 2013-07-03 22:06:37 +07:00
parent e404c262dd
commit f482a4bc4c
2 changed files with 2 additions and 369 deletions

View File

@ -25,6 +25,8 @@ from class_outgoingSynSender import *
from class_singleListener import * from class_singleListener import *
from class_addressGenerator import * from class_addressGenerator import *
from class_asyncoreThread import * from class_asyncoreThread import *
from class_smtpServer import *
from class_pop3Server import *
# Helper Functions # Helper Functions
import helper_startup import helper_startup

View File

@ -1,375 +1,6 @@
from collections import deque
from pyelliptic.openssl import OpenSSL
import asyncore import asyncore
import shared import shared
import smtpd
import socket
import sys
import threading import threading
import time
import traceback
from addresses import *
import helper_inbox
import helper_sent
class bitmessageSMTPServer(smtpd.SMTPServer):
def __init__(self):
# TODO - move to separate file/class
smtpport = shared.config.getint('bitmessagesettings', 'smtpport')
smtpd.SMTPServer.__init__(self, ('127.0.0.1', smtpport), None)
shared.printLock.acquire()
print "SMTP server started"
shared.printLock.release()
def process_message(self, peer, mailfrom, rcpttos, data):
#print("Peer", peer)
#print("Mail From", mailfrom)
#print("Rcpt To", rcpttos)
#print("Data")
#print(data)
#print('--------')
#print(type(mailfrom))
message = data
# Determine the fromAddress and make sure it's an owned identity
# TODO - determine the address from a SMTP authorization.
# TODO - use the mailfrom (a legitimate email address?) when delivering
# real e-mail.
_, fromAddress = mailfrom.split('@', 1)
if not (fromAddress.startswith('BM-') and '.' not in fromAddress):
raise Exception("From Address must be a Bitmessage address.")
else:
status, addressVersionNumber, streamNumber, fromRipe = decodeAddress(fromAddress)
if status != 'success':
shared.printLock.acquire()
print 'Error: Could not decode address: ' + fromAddress + ' : ' + status
if status == 'checksumfailed':
print 'Error: Checksum failed for address: ' + fromAddress
if status == 'invalidcharacters':
print 'Error: Invalid characters in address: ' + fromAddress
if status == 'versiontoohigh':
print 'Error: Address version number too high (or zero) in address: ' + fromAddress
shared.printLock.release()
raise Exception("Invalid Bitmessage address: {}".format(fromAddress))
#fromAddress = addBMIfNotPresent(fromAddress) # I know there's a BM-, because it's required when using SMTP
try:
fromAddressEnabled = shared.config.getboolean(fromAddress, 'enabled')
except:
shared.printLock.acquire()
print 'Error: Could not find your fromAddress in the keys.dat file.'
shared.printLock.release()
raise Exception("Could not find address in keys.dat: {}".format(fromAddress))
if not fromAddressEnabled:
shared.printLock.acquire()
print 'Error: Your fromAddress is disabled. Cannot send.'
shared.printLock.release()
raise Exception("The fromAddress is disabled: {}".format(fromAddress))
for recipient in rcpttos:
_, toAddress = recipient.split('@', 1)
if not (toAddress.startswith('BM-') and '.' not in toAddress):
# TODO - deliver message to another SMTP server.. ?
raise Exception("Cannot yet handle normal E-mail addresses.")
else:
# This is now the 3rd copy of this code. There's one in the API, there's another
# copy in __init__ for the UI. Yet another exists here. It needs to be refactored
# into a utility func!
status, addressVersionNumber, streamNumber, toRipe = decodeAddress(toAddress)
if status != 'success':
shared.printLock.acquire()
print 'Error: Could not decode address: ' + toAddress + ' : ' + status
if status == 'checksumfailed':
print 'Error: Checksum failed for address: ' + toAddress
if status == 'invalidcharacters':
print 'Error: Invalid characters in address: ' + toAddress
if status == 'versiontoohigh':
print 'Error: Address version number too high (or zero) in address: ' + toAddress
shared.printLock.release()
raise Exception("Invalid Bitmessage address: {}".format(toAddress))
#toAddress = addBMIfNotPresent(toAddress) # I know there's a BM-, because it's required when using SMTP
toAddressIsOK = False
try:
shared.config.get(toAddress, 'enabled')
# The toAddress is one owned by me. We cannot send
# messages to ourselves without significant changes
# to the codebase.
shared.printLock.acquire()
print "Error: One of the addresses to which you are sending a message, {}, is yours. Unfortunately the Bitmessage client cannot process its own messages. Please try running a second client on a different computer or within a VM.".format(toAddress)
shared.printLock.release()
except:
toAddressIsOK = True
if not toAddressIsOK:
raise Exception("Cannot send message to {}".format(toAddress))
# The subject is specially formatted to identify it from non-E-mail messages.
subject = "<Bitmessage Mail: 00000000000000000000>" # Reserved, flags.
ackdata = OpenSSL.rand(32)
t = ('', toAddress, toRipe, fromAddress, subject, message, ackdata, int(time.time()), 'msgqueued', 1, 1, 'sent', 2)
helper_sent.insert(t)
toLabel = ''
t = (toAddress,)
shared.sqlLock.acquire()
shared.sqlSubmitQueue.put('''select label from addressbook where address=?''')
shared.sqlSubmitQueue.put(t)
queryreturn = shared.sqlReturnQueue.get()
shared.sqlLock.release()
if queryreturn != []:
for row in queryreturn:
toLabel, = row
shared.UISignalQueue.put(('displayNewSentMessage', (toAddress, toLabel, fromAddress, subject, message, ackdata)))
shared.workerQueue.put(('sendmessage', toAddress))
# TODO - what should we do with ackdata.encode('hex') ?
class bitmessagePOP3Connection(asyncore.dispatcher):
END = b"\r\n"
def __init__(self, sock, peer_address, debug=False):
asyncore.dispatcher.__init__(self, sock)
self.peer_address = peer_address
self.data_buffer = []
self.commands = deque()
self.debug = debug
self.dispatch = dict(
USER=self.handleUser,
PASS=self.handlePass,
STAT=self.handleStat,
LIST=self.handleList,
#TOP=self.handleTop,
RETR=self.handleRetr,
DELE=self.handleDele,
NOOP=self.handleNoop,
QUIT=self.handleQuit,
)
#self.bitmessage = Bitmessage()
self.messages = None #TODO self.bitmessage.getInboxMessagesByAddress(BITMAIL_ADDRESS)
self.storage_size = 0
self.address = None
#for msg in self.messages:
# msg['message'] = base64.b64decode(msg['message'].encode('ascii'))
# msg['subject'] = base64.b64decode(msg['subject'].encode('ascii'))
# msg['size'] = len(msg['message'])
# self.storage_size += msg['size']
#print(self.messages)
self.sendline("+OK Bitmessage POP3 server ready")
def populateMessageIndex(self):
if self.address is None:
raise Exception("Invalid address: {}".format(self.address))
if self.messages is not None:
return
v = (self.address,)
shared.sqlLock.acquire()
# TODO LENGTH(message) needs to be the byte-length, not the character-length.
shared.sqlSubmitQueue.put('''SELECT msgid, fromaddress, subject, LENGTH(message) FROM inbox WHERE folder='inbox' AND toAddress=?''')
shared.sqlSubmitQueue.put(v)
queryreturn = shared.sqlReturnQueue.get()
shared.sqlLock.release()
self.storage_size = 0
self.messages = []
for row in queryreturn:
msgid, fromAddress, subject, size = row
subject = shared.fixPotentiallyInvalidUTF8Data(subject)
if subject.startswith("<Bitmessage Mail: ") and subject[-1] == '>':
subject = "<Bitmessage Mail: 00000000000000000000>" # Reserved, flags.
flags = subject[-21:-1]
# TODO - checksum?
self.messages.append({
'msgid': msgid,
'fromAddress': fromAddress,
'subject': subject,
'size': size,
})
self.storage_size += size
def getMessageContent(self, msgid):
if self.address is None:
raise Exception("Invalid address: {}".format(self.address))
v = (msgid,)
shared.sqlLock.acquire()
shared.sqlSubmitQueue.put('''SELECT fromaddress, received, message, encodingtype FROM inbox WHERE msgid=?''')
shared.sqlSubmitQueue.put(v)
queryreturn = shared.sqlReturnQueue.get()
shared.sqlLock.release()
for row in queryreturn:
fromAddress, received, message, encodingtype = row
message = shared.fixPotentiallyInvalidUTF8Data(message)
return {
'fromAddress': fromAddress,
'received': received,
'message': message,
'encodingtype': encodingtype
}
def trashMessage(self, msgid):
# TODO - how to determine if the update succeeded?
if not self.debug:
helper_inbox.trash(msgid)
return True
def sendline(self, data, END=END):
if self.debug:
shared.printLock.acquire()
sys.stdout.write("sending ")
sys.stdout.write(data)
sys.stdout.write("\n")
shared.printLock.release()
data = data + END
while len(data) > 4096:
self.send(data[:4096])
data = data[4096:]
if len(data):
self.send(data)
def handle_read(self):
chunk = self.recv(4096)
while bitmessagePOP3Connection.END in chunk:
# Join all the data up to the END and throw it in commands
command = b''.join(self.data_buffer) + chunk[:chunk.index(bitmessagePOP3Connection.END)]
chunk = chunk[chunk.index(bitmessagePOP3Connection.END)+2:]
self.data_buffer = []
self.commands.append(command)
if len(chunk):
self.data_buffer.append(chunk)
if self.debug:
shared.printLock.acquire()
print('data_buffer', self.data_buffer)
print('commands', self.commands)
print('-')
shared.printLock.release()
while len(self.commands):
line = self.commands.popleft()
if b' ' in line:
cmd, data = line.split(b' ', 1)
else:
cmd, data = line, b''
try:
cmd = self.dispatch[cmd.decode('ascii').upper()]
except KeyError:
self.sendline('-ERR unknown command')
continue
for response in cmd(data):
self.sendline(response)
if cmd is self.handleQuit:
self.close()
break
def handleUser(self, data):
self.address = data
status, addressVersionNumber, streamNumber, ripe = decodeAddress(self.address)
if status != 'success':
shared.printLock.acquire()
print 'Error: Could not decode address: ' + self.address + ' : ' + status
if status == 'checksumfailed':
print 'Error: Checksum failed for address: ' + self.address
if status == 'invalidcharacters':
print 'Error: Invalid characters in address: ' + self.address
if status == 'versiontoohigh':
print 'Error: Address version number too high (or zero) in address: ' + self.address
shared.printLock.release()
raise Exception("Invalid Bitmessage address: {}".format(self.address))
return ["+OK user accepted"]
def handlePass(self, data):
# TODO
return ["+OK pass accepted"]
def handleStat(self, data):
self.populateMessageIndex()
return ["+OK {} {}".format(len(self.messages), self.storage_size)]
def handleList(self, data):
self.populateMessageIndex()
yield "+OK {} messages ({} octets)".format(len(self.messages), self.storage_size)
for i, msg in enumerate(self.messages):
yield "{} {}".format(i + 1, msg['size'])
yield "."
#def handleTop(self, data):
# cmd, num, lines = data.split()
# assert num == "1", "unknown message number: {}".format(num)
# lines = int(lines)
# text = msg.top + "\r\n\r\n" + "\r\n".join(msg.bot[:lines])
# return "+OK top of message follows\r\n{}\r\n.".format(text)
def handleRetr(self, data):
index = int(data.decode('ascii')) - 1
assert index >= 0
self.populateMessageIndex()
msg = self.messages[index]
content = self.getMessageContent(msg['msgid'])
if self.debug:
shared.printLock.acquire()
sys.stdout.write(str(msg) + ": " + str(content))
shared.printLock.release()
yield "+OK {} octets".format(msg['size'])
yield content['message']
yield '.'
def handleDele(self, data):
index = int(data.decode('ascii')) - 1
assert index >= 0
self.populateMessageIndex()
msg = self.messages[index]
if self.trashMessage(msg['msgid']):
return ["+OK deleted"]
else:
return ["-ERR internal error"]
def handleNoop(self, data):
return ["+OK"]
def handleQuit(self, data):
return ["+OK Bitmessage POP3 server signing off"]
class bitmessagePOP3Server(asyncore.dispatcher):
def __init__(self, debug=False):
asyncore.dispatcher.__init__(self)
self.debug = debug
pop3port = shared.config.getint('bitmessagesettings', 'pop3port')
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.bind(('127.0.0.1', pop3port))
self.listen(10)
shared.printLock.acquire()
print "POP3 server started"
shared.printLock.release()
def handle_accept(self):
sock, peer_address = self.accept()
_ = bitmessagePOP3Connection(sock, peer_address, debug=self.debug)
class asyncoreThread(threading.Thread): class asyncoreThread(threading.Thread):