Change mail format to BMADDR@default. The word default can change. Also, get rid of the Bitmessage Mail tag in the subject line
This commit is contained in:
parent
1e3cd7fc88
commit
d8da925b8d
|
@ -199,26 +199,6 @@ def addBMIfNotPresent(address):
|
||||||
else:
|
else:
|
||||||
return address
|
return address
|
||||||
|
|
||||||
def getBase58Capitaliation(address):
|
|
||||||
if address[:3] == 'BM-':
|
|
||||||
address = address[3:]
|
|
||||||
i = []
|
|
||||||
for c in address:
|
|
||||||
i.append('1' if c.isupper() else '0')
|
|
||||||
return int(''.join(i), 2)
|
|
||||||
|
|
||||||
def applyBase58Capitalization(address, capitalization):
|
|
||||||
address = address.lower()
|
|
||||||
if address.startswith('bm-'):
|
|
||||||
address = address[3:]
|
|
||||||
n = []
|
|
||||||
for i, c in enumerate(address):
|
|
||||||
if (capitalization & (1 << (len(address)-i-1))) != 0:
|
|
||||||
n.append(c.upper())
|
|
||||||
else:
|
|
||||||
n.append(c)
|
|
||||||
return 'BM-' + ''.join(n)
|
|
||||||
|
|
||||||
def addressStream(address):
|
def addressStream(address):
|
||||||
#returns the stream number of an address or False if there is a problem with the address.
|
#returns the stream number of an address or False if there is a problem with the address.
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ class bitmessagePOP3Connection(asyncore.dispatcher):
|
||||||
v = (self.address,)
|
v = (self.address,)
|
||||||
shared.sqlLock.acquire()
|
shared.sqlLock.acquire()
|
||||||
# TODO LENGTH(message) needs to be the byte-length, not the character-length.
|
# 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('''SELECT msgid, fromaddress, subject, message FROM inbox WHERE folder='inbox' AND toAddress=?''')
|
||||||
shared.sqlSubmitQueue.put(v)
|
shared.sqlSubmitQueue.put(v)
|
||||||
queryreturn = shared.sqlReturnQueue.get()
|
queryreturn = shared.sqlReturnQueue.get()
|
||||||
shared.sqlLock.release()
|
shared.sqlLock.release()
|
||||||
|
@ -63,24 +63,25 @@ class bitmessagePOP3Connection(asyncore.dispatcher):
|
||||||
self.storage_size = 0
|
self.storage_size = 0
|
||||||
self.messages = []
|
self.messages = []
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
msgid, fromAddress, subject, size = row
|
msgid, fromAddress, subject, body = row
|
||||||
subject = shared.fixPotentiallyInvalidUTF8Data(subject)
|
subject = shared.fixPotentiallyInvalidUTF8Data(subject)
|
||||||
i = subject.find('<Bitmessage Mail: ')
|
body = shared.fixPotentiallyInvalidUTF8Data(body)
|
||||||
if i >= 0:
|
|
||||||
tmp = subject[i:]
|
message = parser.Parser().parsestr(body)
|
||||||
i = tmp.find('>')
|
if not ('Date' in message and 'From' in message and 'X-Bitmessage-Flags' in message):
|
||||||
if i >= 0:
|
continue
|
||||||
flags = tmp[i-21:i] # TODO - verify checksum?
|
|
||||||
|
flags = message['X-Bitmessage-Flags'] # TODO - verify checksum?
|
||||||
|
|
||||||
self.messages.append({
|
self.messages.append({
|
||||||
'msgid': msgid,
|
'msgid' : msgid,
|
||||||
'fromAddress': fromAddress,
|
'fromAddress': fromAddress,
|
||||||
'subject': subject,
|
'subject' : subject,
|
||||||
'size': size,
|
'size' : len(body),
|
||||||
|
'flags' : flags,
|
||||||
})
|
})
|
||||||
|
|
||||||
self.storage_size += size
|
self.storage_size += len(body)
|
||||||
|
|
||||||
|
|
||||||
def getMessageContent(self, msgid):
|
def getMessageContent(self, msgid):
|
||||||
if self.address is None:
|
if self.address is None:
|
||||||
|
@ -97,9 +98,9 @@ class bitmessagePOP3Connection(asyncore.dispatcher):
|
||||||
fromAddress, received, message, encodingtype = row
|
fromAddress, received, message, encodingtype = row
|
||||||
message = shared.fixPotentiallyInvalidUTF8Data(message)
|
message = shared.fixPotentiallyInvalidUTF8Data(message)
|
||||||
return {
|
return {
|
||||||
'fromAddress': fromAddress,
|
'fromAddress' : fromAddress,
|
||||||
'received': received,
|
'received' : received,
|
||||||
'message': message,
|
'message' : message,
|
||||||
'encodingtype': encodingtype
|
'encodingtype': encodingtype
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,13 +166,10 @@ class bitmessagePOP3Connection(asyncore.dispatcher):
|
||||||
if self.loggedin:
|
if self.loggedin:
|
||||||
raise Exception("Cannot login twice")
|
raise Exception("Cannot login twice")
|
||||||
|
|
||||||
if '@' not in data:
|
if '@' in data:
|
||||||
yield "-ERR access denied"
|
data, _ = data.split('@', 1)
|
||||||
return
|
|
||||||
|
|
||||||
capitalization, address = data.split('@', 1)
|
|
||||||
self.address = applyBase58Capitalization(address, int(capitalization))
|
|
||||||
|
|
||||||
|
self.address = data
|
||||||
status, addressVersionNumber, streamNumber, ripe = decodeAddress(self.address)
|
status, addressVersionNumber, streamNumber, ripe = decodeAddress(self.address)
|
||||||
if status != 'success':
|
if status != 'success':
|
||||||
with shared.printLock:
|
with shared.printLock:
|
||||||
|
@ -184,13 +182,6 @@ class bitmessagePOP3Connection(asyncore.dispatcher):
|
||||||
print 'Error: Address version number too high (or zero) in address: ' + self.address
|
print 'Error: Address version number too high (or zero) in address: ' + self.address
|
||||||
raise Exception("Invalid Bitmessage address: {}".format(self.address))
|
raise Exception("Invalid Bitmessage address: {}".format(self.address))
|
||||||
|
|
||||||
username = '{}@{}'.format(getBase58Capitaliation(self.address), self.address)
|
|
||||||
|
|
||||||
# Must login with the full E-mail address and capitalization
|
|
||||||
if data != username:
|
|
||||||
yield "-ERR access denied"
|
|
||||||
return
|
|
||||||
|
|
||||||
# Each identity must be enabled independly by setting the smtppop3password for the identity
|
# Each identity must be enabled independly by setting the smtppop3password for the identity
|
||||||
# If no password is set, then the identity is not available for SMTP/POP3 access.
|
# If no password is set, then the identity is not available for SMTP/POP3 access.
|
||||||
try:
|
try:
|
||||||
|
@ -295,6 +286,19 @@ class bitmessagePOP3Server(asyncore.dispatcher):
|
||||||
sock = ssl.wrap_socket(sock, server_side=True, certfile=self.certfile, keyfile=self.keyfile, ssl_version=ssl.PROTOCOL_SSLv23)
|
sock = ssl.wrap_socket(sock, server_side=True, certfile=self.certfile, keyfile=self.keyfile, ssl_version=ssl.PROTOCOL_SSLv23)
|
||||||
_ = bitmessagePOP3Connection(sock, peer_address, debug=self.debug)
|
_ = bitmessagePOP3Connection(sock, peer_address, debug=self.debug)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def addMailingListNameToSubject(subject, mailingListName):
|
||||||
|
withoutre = subject = subject.strip()
|
||||||
|
re = ''
|
||||||
|
if subject[:3] == 'Re:' or subject[:3] == 'RE:':
|
||||||
|
re = subject[:3] + ' '
|
||||||
|
withoutre = subject[3:].strip()
|
||||||
|
a = '[' + mailingListName + ']'
|
||||||
|
if withoutre.startswith(a):
|
||||||
|
return subject
|
||||||
|
else:
|
||||||
|
return re + a + ' ' + subject
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def reformatMessageForReceipt(toAddress, fromAddress, body, subject, broadcast=False):
|
def reformatMessageForReceipt(toAddress, fromAddress, body, subject, broadcast=False):
|
||||||
originalBody = body
|
originalBody = body
|
||||||
|
@ -332,23 +336,10 @@ class bitmessagePOP3Server(asyncore.dispatcher):
|
||||||
print(message)
|
print(message)
|
||||||
print '--------'
|
print '--------'
|
||||||
|
|
||||||
i = subject.find('<Bitmessage Mail: ')
|
flags = '0'
|
||||||
if i >= 0:
|
if 'X-Bitmessage-Flags' in message:
|
||||||
tmp = subject[i:]
|
flags = message['X-Bitmessage-Flags']
|
||||||
i = tmp.find('>')
|
del message['X-Bitmessage-Flags']
|
||||||
if i >= 0:
|
|
||||||
flags = tmp[i-21:i]
|
|
||||||
checksum = int(flags[-4:], 16)
|
|
||||||
|
|
||||||
# Checksum to make sure incoming message hasn't been tampered with
|
|
||||||
c = hashlib.sha256(body).digest()[:2]
|
|
||||||
#c = (ord(checksum[0]) << 8) | ord(checksum[1])
|
|
||||||
print(c, checksum)
|
|
||||||
|
|
||||||
# Valid Bitmessage subject line already
|
|
||||||
if c != checksum:
|
|
||||||
with shared.printLock:
|
|
||||||
print 'Got E-Mail formatted message with incorrect checksum...'
|
|
||||||
|
|
||||||
mailingListName = None
|
mailingListName = None
|
||||||
if broadcast:
|
if broadcast:
|
||||||
|
@ -366,14 +357,16 @@ class bitmessagePOP3Server(asyncore.dispatcher):
|
||||||
if not body_is_valid:
|
if not body_is_valid:
|
||||||
if broadcast:
|
if broadcast:
|
||||||
if ostensiblyFrom is not None:
|
if ostensiblyFrom is not None:
|
||||||
fromLabel = '{}@{}'.format(getBase58Capitaliation(ostensiblyFrom), ostensiblyFrom)
|
fromLabel = '{} <{}@default>'.format(ostensiblyFrom, ostensiblyFrom)
|
||||||
# TODO - check address book?
|
# TODO - check address book for label?
|
||||||
else:
|
else:
|
||||||
fromLabel = '{}@{}'.format(getBase58Capitaliation(fromAddress), fromAddress)
|
fromLabel = '{}@default'.format(fromAddress)
|
||||||
if mailingListName is not None:
|
if mailingListName is not None:
|
||||||
fromLabel = '{} <{}>'.format(mailingListName, fromLabel)
|
fromLabel = '{} <{}>'.format(mailingListName, fromLabel)
|
||||||
else:
|
else:
|
||||||
fromLabel = '{}@{}'.format(getBase58Capitaliation(fromAddress), fromAddress)
|
fromLabel = '{} <{}>'.format(fromAddress, fromLabel)
|
||||||
|
else:
|
||||||
|
fromLabel = '{}@default'.format(fromAddress)
|
||||||
|
|
||||||
with shared.sqlLock:
|
with shared.sqlLock:
|
||||||
t = (fromAddress,)
|
t = (fromAddress,)
|
||||||
|
@ -384,12 +377,12 @@ class bitmessagePOP3Server(asyncore.dispatcher):
|
||||||
for row in queryreturn:
|
for row in queryreturn:
|
||||||
fromLabel = '{} <{}>'.format(row[0], fromLabel)
|
fromLabel = '{} <{}>'.format(row[0], fromLabel)
|
||||||
break
|
break
|
||||||
|
else:
|
||||||
|
fromLabel = '{} <{}>'.format(fromAddress, fromLabel)
|
||||||
|
|
||||||
message['From'] = fromLabel
|
message['From'] = fromLabel
|
||||||
message['Date'] = utils.formatdate(localtime=False)
|
message['Date'] = utils.formatdate(localtime=False)
|
||||||
|
|
||||||
message['X-Bitmessage-Subject'] = subject
|
|
||||||
|
|
||||||
if 'Subject' in message:
|
if 'Subject' in message:
|
||||||
if mailingListName is not None:
|
if mailingListName is not None:
|
||||||
s = message['Subject']
|
s = message['Subject']
|
||||||
|
@ -400,17 +393,18 @@ class bitmessagePOP3Server(asyncore.dispatcher):
|
||||||
|
|
||||||
if broadcast:
|
if broadcast:
|
||||||
# The To: field on a broadcast is the mailing list, not you
|
# The To: field on a broadcast is the mailing list, not you
|
||||||
toLabel = '{}@{}'.format(getBase58Capitaliation(fromAddress), fromAddress)
|
toLabel = '{}@default'.format(fromAddress)
|
||||||
if mailingListName is not None:
|
if mailingListName is not None:
|
||||||
toLabel = '{} <{}>'.format(mailingListName, toLabel)
|
toLabel = '{} <{}>'.format(mailingListName, toLabel)
|
||||||
if 'To' in message:
|
if 'To' in message:
|
||||||
del message['To']
|
del message['To']
|
||||||
message['To'] = toLabel
|
message['To'] = toLabel
|
||||||
if 'Reply-To' not in message:
|
if 'Reply-To' in message:
|
||||||
del message['Reply-To']
|
del message['Reply-To']
|
||||||
message['Reply-To'] = toLabel
|
message['Reply-To'] = toLabel
|
||||||
elif 'To' not in message:
|
else:
|
||||||
toLabel = '{}@{}'.format(getBase58Capitaliation(toAddress), toAddress)
|
if 'To' not in message:
|
||||||
|
toLabel = '{}@default'.format(toAddress)
|
||||||
try:
|
try:
|
||||||
toLabel = '{} <{}>'.format(shared.config.get(toAddress, 'label'), toLabel)
|
toLabel = '{} <{}>'.format(shared.config.get(toAddress, 'label'), toLabel)
|
||||||
except:
|
except:
|
||||||
|
@ -419,103 +413,72 @@ class bitmessagePOP3Server(asyncore.dispatcher):
|
||||||
message['To'] = toLabel
|
message['To'] = toLabel
|
||||||
|
|
||||||
# Return-Path
|
# Return-Path
|
||||||
returnPath = "{}@{}".format(getBase58Capitaliation(fromAddress), fromAddress)
|
returnPath = "{}@default".format(fromAddress)
|
||||||
message['Return-Path'] = returnPath
|
message['Return-Path'] = returnPath
|
||||||
|
|
||||||
# X-Delivered-To
|
# X-Delivered-To
|
||||||
deliveredTo = "{}@{}".format(getBase58Capitaliation(toAddress), toAddress)
|
deliveredTo = "{}@default".format(toAddress)
|
||||||
message['X-Delivered-To'] = deliveredTo
|
message['X-Delivered-To'] = deliveredTo
|
||||||
|
|
||||||
# X-Bitmessage-Receiving-Version
|
# X-Bitmessage-Receiving-Version
|
||||||
message["X-Bitmessage-Receiving-Version"] = shared.softwareVersion
|
message["X-Bitmessage-Receiving-Version"] = shared.softwareVersion
|
||||||
|
|
||||||
|
# Others...
|
||||||
|
message['X-Bitmessage-Subject'] = subject
|
||||||
|
message['X-Bitmessage-Flags'] = flags
|
||||||
|
|
||||||
fp = StringIO()
|
fp = StringIO()
|
||||||
gen = generator.Generator(fp, mangle_from_=False, maxheaderlen=128)
|
gen = generator.Generator(fp, mangle_from_=False, maxheaderlen=128)
|
||||||
gen.flatten(message)
|
gen.flatten(message)
|
||||||
|
|
||||||
message_as_text = fp.getvalue()
|
message_as_text = fp.getvalue()
|
||||||
|
|
||||||
# Checksum to makesure incoming message hasn't been tampered with
|
|
||||||
# TODO - if subject_is_valid, then don't completely overwrite the subject, instead include all the data outside of <> too
|
|
||||||
checksum = hashlib.sha256(message_as_text).digest()[:2]
|
|
||||||
checksum = (ord(checksum[0]) << 8) | ord(checksum[1])
|
|
||||||
subject = "<Bitmessage Mail: 0000000000000000{:04x}>".format(checksum) # Reserved flags.
|
|
||||||
|
|
||||||
return message_as_text, subject
|
return message_as_text, subject
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def addMailingListNameToSubject(subject, mailingListName):
|
|
||||||
withoutre = subject = subject.strip()
|
|
||||||
re = ''
|
|
||||||
if subject[:3] == 'Re:' or subject[:3] == 'RE:':
|
|
||||||
re = subject[:3] + ' '
|
|
||||||
withoutre = subject[3:].strip()
|
|
||||||
a = '[' + mailingListName + ']'
|
|
||||||
if withoutre.startswith(a):
|
|
||||||
return subject
|
|
||||||
else:
|
|
||||||
return re + a + ' ' + subject
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def reformatMessageForMailingList(toAddress, fromAddress, body, subject, mailingListName):
|
def reformatMessageForMailingList(toAddress, fromAddress, body, subject, mailingListName):
|
||||||
message = parser.Parser().parsestr(body)
|
message = parser.Parser().parsestr(body)
|
||||||
with shared.printLock:
|
with shared.printLock:
|
||||||
print(message)
|
print(message)
|
||||||
|
|
||||||
subject_is_valid = False
|
flags = '0'
|
||||||
|
if 'X-Bitmessage-Flags' in message:
|
||||||
|
flags = message['X-Bitmessage-Flags']
|
||||||
|
del message['X-Bitmessage-Flags']
|
||||||
|
|
||||||
i = subject.find('<Bitmessage Mail: ')
|
# The mailing list code will override some headers, including Date and From
|
||||||
if i >= 0:
|
fromLabel = '{}@default'.format(fromAddress)
|
||||||
tmp = subject[i:]
|
|
||||||
i = tmp.find('>')
|
|
||||||
if i >= 0:
|
|
||||||
flags = tmp[i-21:i]
|
|
||||||
checksum = int(flags[-4:], 16)
|
|
||||||
|
|
||||||
# Checksum to make sure incoming message hasn't been tampered with
|
|
||||||
c = hashlib.sha256(body).digest()[:2]
|
|
||||||
c = (ord(checksum[0]) << 8) | ord(checksum[1])
|
|
||||||
|
|
||||||
# Valid Bitmessage subject line already
|
|
||||||
if c == checksum:
|
|
||||||
subject_is_valid = True
|
|
||||||
else:
|
|
||||||
with shared.printLock:
|
|
||||||
print 'Got E-Mail formatted message with incorrect checksum...'
|
|
||||||
|
|
||||||
# The mailing list code will override some headers, including Date and From, so
|
|
||||||
# that the trust can be moved from the original sender to the mailing list owner.
|
|
||||||
fromLabel = '{}@{}'.format(getBase58Capitaliation(fromAddress), fromAddress)
|
|
||||||
|
|
||||||
if 'From' in message:
|
if 'From' in message:
|
||||||
originalFrom = message['From']
|
originalFrom = message['From']
|
||||||
message['X-Original-From'] = originalFrom
|
message['X-Original-From'] = originalFrom
|
||||||
|
|
||||||
i = originalFrom.find('<' + fromLabel + '>')
|
i = originalFrom.find('<' + fromAddress + '@')
|
||||||
if i >= 0:
|
if i >= 0:
|
||||||
fromLabel = '{} <{}>'.format(originalFrom[:i].strip(), fromLabel)
|
fromLabel = '{} <{}>'.format(originalFrom[:i].strip(), fromLabel)
|
||||||
|
else:
|
||||||
|
fromLabel = '{} <{}>'.format(fromAddress, fromLabel)
|
||||||
|
|
||||||
|
del message['From']
|
||||||
|
|
||||||
message['From'] = fromLabel
|
message['From'] = fromLabel
|
||||||
message['Date'] = utils.formatdate()
|
|
||||||
|
if 'Date' in message:
|
||||||
|
del message['Date']
|
||||||
|
|
||||||
|
message['Date'] = utils.formatdate(localtime=False)
|
||||||
|
|
||||||
message['X-Bitmessage-Subject'] = subject
|
message['X-Bitmessage-Subject'] = subject
|
||||||
if 'Subject' not in message:
|
if 'Subject' not in message:
|
||||||
if not subject_is_valid:
|
|
||||||
message['Subject'] = bitmessagePOP3Server.addMailingListNameToSubject(subject, mailingListName)
|
message['Subject'] = bitmessagePOP3Server.addMailingListNameToSubject(subject, mailingListName)
|
||||||
else:
|
else:
|
||||||
# TODO - strip <Bitmessage Mail: ...> from bitmessage subject?
|
s = message['Subject']
|
||||||
message['Subject'] = bitmessagePOP3Server.addMailingListNameToSubject('', mailingListName)
|
del message['Subject']
|
||||||
else:
|
message['Subject'] = bitmessagePOP3Server.addMailingListNameToSubject(s, mailingListName)
|
||||||
message['Subject'] = bitmessagePOP3Server.addMailingListNameToSubject(message['Subject'], mailingListName)
|
|
||||||
|
|
||||||
toLabel = '{}@{}'.format(getBase58Capitaliation(toAddress), toAddress)
|
|
||||||
try:
|
|
||||||
toLabel = '{} <{}>'.format(shared.config.get(toAddress, 'label'), toLabel)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
toLabel = '"{}" <{}@default>'.format(mailingListName, toAddress)
|
||||||
if 'To' in message:
|
if 'To' in message:
|
||||||
message['X-Original-To'] = message['To']
|
message['X-Original-To'] = message['To']
|
||||||
|
del message['To']
|
||||||
message['To'] = toLabel
|
message['To'] = toLabel
|
||||||
|
|
||||||
# X-Bitmessage-MailingList-Name
|
# X-Bitmessage-MailingList-Name
|
||||||
|
@ -528,17 +491,12 @@ class bitmessagePOP3Server(asyncore.dispatcher):
|
||||||
# X-Bitmessage-MailingList-Version
|
# X-Bitmessage-MailingList-Version
|
||||||
message["X-Bitmessage-MailingList-Version"] = shared.softwareVersion
|
message["X-Bitmessage-MailingList-Version"] = shared.softwareVersion
|
||||||
|
|
||||||
|
message["X-Bitmessage-Flags"] = flags
|
||||||
|
|
||||||
fp = StringIO()
|
fp = StringIO()
|
||||||
gen = generator.Generator(fp, mangle_from_=False, maxheaderlen=128)
|
gen = generator.Generator(fp, mangle_from_=False, maxheaderlen=128)
|
||||||
gen.flatten(message)
|
gen.flatten(message)
|
||||||
|
|
||||||
message_as_text = fp.getvalue()
|
message_as_text = fp.getvalue()
|
||||||
|
|
||||||
# Checksum to makesure incoming message hasn't been tampered with
|
|
||||||
# TODO - if subject_is_valid, then don't completely overwrite the subject, instead include all the data outside of <> too
|
|
||||||
checksum = hashlib.sha256(message_as_text).digest()[:2]
|
|
||||||
checksum = (ord(checksum[0]) << 8) | ord(checksum[1])
|
|
||||||
subject = bitmessagePOP3Server.addMailingListNameToSubject("<Bitmessage Mail: 0000000000000000{:04x}>".format(checksum), mailingListAddress)
|
|
||||||
|
|
||||||
return message_as_text, subject
|
return message_as_text, subject
|
||||||
|
|
||||||
|
|
|
@ -172,13 +172,12 @@ class bitmessageSMTPChannel(asynchat.async_chat):
|
||||||
self.invalid_command('501 authorization not understood')
|
self.invalid_command('501 authorization not understood')
|
||||||
return
|
return
|
||||||
|
|
||||||
if '@' not in username:
|
if '@' in username:
|
||||||
self.invalid_command('530 Access denied.')
|
username, _ = username.split('@', 1)
|
||||||
return
|
|
||||||
|
|
||||||
capitalization, address = username.split('@', 1)
|
|
||||||
self.address = applyBase58Capitalization(address, int(capitalization))
|
|
||||||
|
|
||||||
|
self.address = username
|
||||||
|
with shared.printLock:
|
||||||
|
print 'Login request from {}'.format(self.address)
|
||||||
status, addressVersionNumber, streamNumber, ripe = decodeAddress(self.address)
|
status, addressVersionNumber, streamNumber, ripe = decodeAddress(self.address)
|
||||||
if status != 'success':
|
if status != 'success':
|
||||||
with shared.printLock:
|
with shared.printLock:
|
||||||
|
@ -191,13 +190,6 @@ class bitmessageSMTPChannel(asynchat.async_chat):
|
||||||
print 'Error: Address version number too high (or zero) in address: ' + self.address
|
print 'Error: Address version number too high (or zero) in address: ' + self.address
|
||||||
raise Exception("Invalid Bitmessage address: {}".format(self.address))
|
raise Exception("Invalid Bitmessage address: {}".format(self.address))
|
||||||
|
|
||||||
self.fullUsername = '{}@{}'.format(getBase58Capitaliation(self.address), address)
|
|
||||||
|
|
||||||
# Must match full email address with capitalization
|
|
||||||
if username != self.fullUsername:
|
|
||||||
self.invalid_command('530 Access denied.')
|
|
||||||
return
|
|
||||||
|
|
||||||
# Each identity must be enabled independly by setting the smtppop3password for the identity
|
# Each identity must be enabled independly by setting the smtppop3password for the identity
|
||||||
# If no password is set, then the identity is not available for SMTP/POP3 access.
|
# If no password is set, then the identity is not available for SMTP/POP3 access.
|
||||||
try:
|
try:
|
||||||
|
@ -242,7 +234,7 @@ class bitmessageSMTPChannel(asynchat.async_chat):
|
||||||
print >> smtpd.DEBUGSTREAM, '===> MAIL', arg
|
print >> smtpd.DEBUGSTREAM, '===> MAIL', arg
|
||||||
|
|
||||||
address = self.__getaddr('FROM:', arg) if arg else None
|
address = self.__getaddr('FROM:', arg) if arg else None
|
||||||
if not address:
|
if not address or '@' not in address:
|
||||||
self.invalid_command('501 Syntax: MAIL FROM: <address>')
|
self.invalid_command('501 Syntax: MAIL FROM: <address>')
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -254,7 +246,8 @@ class bitmessageSMTPChannel(asynchat.async_chat):
|
||||||
self.invalid_command('503 Not authenticated.')
|
self.invalid_command('503 Not authenticated.')
|
||||||
return
|
return
|
||||||
|
|
||||||
if address != self.fullUsername:
|
localPart, _ = address.split('@', 1)
|
||||||
|
if self.address != localPart:
|
||||||
self.invalid_command('530 Access denied: address must be the same as the authorized account')
|
self.invalid_command('530 Access denied: address must be the same as the authorized account')
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -278,12 +271,15 @@ class bitmessageSMTPChannel(asynchat.async_chat):
|
||||||
self.invalid_command('501 Syntax: RCPT TO: <user@address>')
|
self.invalid_command('501 Syntax: RCPT TO: <user@address>')
|
||||||
return
|
return
|
||||||
try:
|
try:
|
||||||
capitalization, address = address.split('@', 1)
|
localPart, dom = address.split('@', 1)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
self.invalid_command('501 Syntax: RCPT TO: <user@address>')
|
self.invalid_command('501 Syntax: RCPT TO: <user@address>')
|
||||||
return
|
return
|
||||||
realAddress = applyBase58Capitalization(address, int(capitalization))
|
status, addressVersionNumber, streamNumber, fromRipe = decodeAddress(localPart)
|
||||||
self.__rcpttos.append('{}@{}'.format(getBase58Capitaliation(realAddress), realAddress))
|
if status != 'success':
|
||||||
|
self.invalid_command('501 Bitmessage address is incorrect: {}'.format(status))
|
||||||
|
return
|
||||||
|
self.__rcpttos.append(address)
|
||||||
with shared.printLock:
|
with shared.printLock:
|
||||||
print >> smtpd.DEBUGSTREAM, 'recips:', self.__rcpttos
|
print >> smtpd.DEBUGSTREAM, 'recips:', self.__rcpttos
|
||||||
self.push('250 Ok')
|
self.push('250 Ok')
|
||||||
|
@ -341,17 +337,12 @@ class bitmessageSMTPServer(smtpd.SMTPServer):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def stripMessageHeaders(message):
|
def stripMessageHeaders(message):
|
||||||
# Convert Date header into GMT
|
# Always convert Date header into GMT
|
||||||
if 'Date' in message:
|
if 'Date' in message:
|
||||||
oldDate = message['Date']
|
oldDate = message['Date']
|
||||||
del message['Date']
|
del message['Date']
|
||||||
|
|
||||||
message['Date'] = utils.formatdate(utils.mktime_tz(utils.parsedate_tz(oldDate)), localtime=False)
|
message['Date'] = utils.formatdate(utils.mktime_tz(utils.parsedate_tz(oldDate)), localtime=False)
|
||||||
|
|
||||||
with shared.printLock:
|
|
||||||
print 'old date --', oldDate
|
|
||||||
print 'new date --', message['Date']
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if not shared.config.getboolean('bitmessagesettings', 'stripmessageheadersenable'):
|
if not shared.config.getboolean('bitmessagesettings', 'stripmessageheadersenable'):
|
||||||
return
|
return
|
||||||
|
@ -368,22 +359,24 @@ class bitmessageSMTPServer(smtpd.SMTPServer):
|
||||||
if h in message:
|
if h in message:
|
||||||
del message[h]
|
del message[h]
|
||||||
|
|
||||||
def process_message(self, peer, address, rcpttos, data):
|
def process_message(self, peer, fromAddress, rcpttos, data):
|
||||||
#print("Peer", peer)
|
#print("Peer", peer)
|
||||||
#print("Mail From", address)
|
#print("Mail From", fromAddress)
|
||||||
#print("Rcpt To", rcpttos)
|
#print("Rcpt To", rcpttos)
|
||||||
#print("Data")
|
#print("Data")
|
||||||
#print(data)
|
#print(data)
|
||||||
#print('--------')
|
#print('--------')
|
||||||
#print(type(address))
|
#print(type(fromAddress))
|
||||||
|
|
||||||
message = parser.Parser().parsestr(data)
|
message = parser.Parser().parsestr(data)
|
||||||
message['X-Bitmessage-Sending-Version'] = shared.softwareVersion
|
message['X-Bitmessage-Sending-Version'] = shared.softwareVersion
|
||||||
|
message['X-Bitmessage-Flags'] = '0'
|
||||||
|
|
||||||
bitmessageSMTPServer.stripMessageHeaders(message)
|
bitmessageSMTPServer.stripMessageHeaders(message)
|
||||||
fp = StringIO()
|
fp = StringIO()
|
||||||
gen = generator.Generator(fp, mangle_from_=False, maxheaderlen=128)
|
gen = generator.Generator(fp, mangle_from_=False, maxheaderlen=128)
|
||||||
gen.flatten(message)
|
gen.flatten(message)
|
||||||
|
|
||||||
message_as_text = fp.getvalue()
|
message_as_text = fp.getvalue()
|
||||||
with shared.printLock:
|
with shared.printLock:
|
||||||
print(message_as_text)
|
print(message_as_text)
|
||||||
|
@ -392,7 +385,6 @@ class bitmessageSMTPServer(smtpd.SMTPServer):
|
||||||
checksum = (ord(checksum[0]) << 8) | ord(checksum[1])
|
checksum = (ord(checksum[0]) << 8) | ord(checksum[1])
|
||||||
|
|
||||||
# Determine the fromAddress and make sure it's an owned identity
|
# Determine the fromAddress and make sure it's an owned identity
|
||||||
fromAddress = address
|
|
||||||
if not (fromAddress.startswith('BM-') and '.' not in fromAddress):
|
if not (fromAddress.startswith('BM-') and '.' not in fromAddress):
|
||||||
raise Exception("From Address must be a Bitmessage address.")
|
raise Exception("From Address must be a Bitmessage address.")
|
||||||
else:
|
else:
|
||||||
|
@ -421,7 +413,7 @@ class bitmessageSMTPServer(smtpd.SMTPServer):
|
||||||
raise Exception("The fromAddress is disabled: {}".format(fromAddress))
|
raise Exception("The fromAddress is disabled: {}".format(fromAddress))
|
||||||
|
|
||||||
for recipient in rcpttos:
|
for recipient in rcpttos:
|
||||||
_, toAddress = recipient.split('@', 1)
|
toAddress, _ = recipient.split('@', 1)
|
||||||
if not (toAddress.startswith('BM-') and '.' not in toAddress):
|
if not (toAddress.startswith('BM-') and '.' not in toAddress):
|
||||||
# TODO - deliver message to another SMTP server..
|
# TODO - deliver message to another SMTP server..
|
||||||
# I think this feature would urge adoption: the ability to use the same bitmessage address
|
# I think this feature would urge adoption: the ability to use the same bitmessage address
|
||||||
|
@ -461,7 +453,10 @@ class bitmessageSMTPServer(smtpd.SMTPServer):
|
||||||
# The subject is specially formatted to identify it from non-E-mail messages.
|
# The subject is specially formatted to identify it from non-E-mail messages.
|
||||||
# TODO - The bitfield will be used to convey things like external attachments, etc.
|
# TODO - The bitfield will be used to convey things like external attachments, etc.
|
||||||
# Last 2 bytes are two bytes of the sha256 checksum of message
|
# Last 2 bytes are two bytes of the sha256 checksum of message
|
||||||
subject = "<Bitmessage Mail: 0000000000000000{:04x}>".format(checksum) # Reserved flags.
|
if 'Subject' in message:
|
||||||
|
subject = message['Subject']
|
||||||
|
else:
|
||||||
|
subject = ''
|
||||||
|
|
||||||
ackdata = OpenSSL.rand(32)
|
ackdata = OpenSSL.rand(32)
|
||||||
t = ('', toAddress, toRipe, fromAddress, subject, message_as_text, ackdata, int(time.time()), 'msgqueued', 1, 1, 'sent', 2)
|
t = ('', toAddress, toRipe, fromAddress, subject, message_as_text, ackdata, int(time.time()), 'msgqueued', 1, 1, 'sent', 2)
|
||||||
|
|
Reference in New Issue
Block a user