From fd7bb7c9173bc5997a0cbe68837d01879aa3026c Mon Sep 17 00:00:00 2001
From: peter-tank <30540412+peter-tank@users.noreply.github.com>
Date: Thu, 19 Jul 2018 00:03:23 +0800
Subject: [PATCH] * Refine atachment detect. * Fix duplicated sending msg.
Signed-off-by: peter-tank <30540412+peter-tank@users.noreply.github.com>
---
src/bitmessagecli.py | 104 +++++++++++++++++++++----------------------
1 file changed, 52 insertions(+), 52 deletions(-)
diff --git a/src/bitmessagecli.py b/src/bitmessagecli.py
index faa8c75a..16f86ce1 100644
--- a/src/bitmessagecli.py
+++ b/src/bitmessagecli.py
@@ -110,7 +110,6 @@ inputShorts = dict({
'yes': ['y', 'yes'],
'no': ['n', 'no'],
'exit': ['e', 'ex', 'exit'],
- 'save': ['save', 's', 'sv'],
'deterministic': ['d', 'dt'],
'random': ['r', 'rd', 'random'],
'message': ['m', 'msg', 'message'],
@@ -1087,7 +1086,9 @@ def genAdd(lbl, deterministic, passphrase, numOfAdd, addVNum, streamNum, ripe):
def getBase64Len(x=''):
- return int(len(x)*(3/4)) - 2 if x[-2:] == '==' else 1 if x[-1] == '=' else 0
+
+ strip = len(x) if len(x) < 4 else 2 if x[-2:] == '==' else 1 if x[-1] == '=' else 0
+ return int(len(x) * 3 /4) - strip
def dump2File(fileName, fileData, deCoded):
@@ -1122,7 +1123,7 @@ def dump2File(fileName, fileData, deCoded):
print '\n'.join([
' -----------------------------------',
' Contents seems not "BASE64" encoded. (base on length check)',
- ' Start[%d] ~ Ends[%d].' % (x[:3], x[-3:]),
+ ' Start[%s] ~ Ends[%s].' % (x[:3], x[-3:]),
' About: %d(bytes).' % getBase64Len(x),
' FileName: "%s"' % fileName,
])
@@ -1331,6 +1332,8 @@ def sendMsg(toAddress, fromAddress, subject=None, message=None):
uInput = userInput('Would you like to try again, (n)o or (Y)es?').lower()
if uInput in inputShorts['no']:
break
+ else:
+ break
if ackData['error'] == 0:
print ' Fetching send status...'
@@ -1418,6 +1421,8 @@ def sendBrd(fromAddress=None, subject=None, message=None):
uInput = userInput('Would you like to try again, no or (Y)es?').lower()
if uInput in inputShorts['no']:
break
+ else:
+ break
if ackData['error'] == 0:
print ' Fetching send status...'
@@ -1466,7 +1471,7 @@ def inbox(unreadOnly=False, pageNum=20):
print ' From:', getLabelForAddress(message['fromAddress']) # Get the from address
print ' Subject:', message['subject'].decode('base64') # Get the subject
print ' Received:', datetime.datetime.fromtimestamp(float(message['receivedTime'])).strftime('%Y-%m-%d %H:%M:%S')
- print ' Base64Len:', str(len(message['message']))
+ print ' Size: %d(bytes)' % getBase64Len(message['message'])
messagesPrinted += 1
if not message['read']:
messagesUnread += 1
@@ -1507,7 +1512,7 @@ def outbox(pageNum=20):
print ' Status:', message['status'] # Get the status
print ' Ack:', message['ackData'] # Get the ackData
print ' Last Action Time:', datetime.datetime.fromtimestamp(float(message['lastActionTime'])).strftime('%Y-%m-%d %H:%M:%S')
- print ' Base64Len:', str(len(message['message']))
+ print ' Size: %d(bytes)' % getBase64Len(message['message'])
if msgNum % pageNum == 0 and msgNum != 0:
uInput = userInput('Paused on %d/%d, next [%d],' % (msgNum, numMessages - 1, msgNum - pageNum if msgNum > pageNum else 0))
@@ -1524,56 +1529,47 @@ def attDetect(content=None, textmsg=None, attPrefix=None, askSave=True):
global inputShorts
attPos = msgPos = 0
+ counter = 0
+ prefixRe = re.compile(r'<(\w*)\s*[^<>]*src="[^"]*;base64,$')
+ suffixRe = re.compile(r'("\s*/?>)')
+ fnRe1 = re.compile(r'alt="([^"]*)"*\s*[^<>]*;base64,$') # alt= preferred for attachment filename
+ fnRe2 = re.compile(r'src="([^"]*)"*\s*[^<>]*;base64,$')
# Hard way search attachments
- for counter in range(1, 3): # Allows maximum 3 of attachments to be downloaded/saved
+ while counter < 4: # Allows maximum 3 of attachments to be downloaded/saved
try:
- attPos = content.index(';base64,', attPos) + 9 # Finds the attachment position
- attEndPos = content.index('/>', attPos) - 1 # Finds the end of the attachment
+ attEndPos = attPos = content.index(';base64,', attPos) + len(';base64,') # Finds the attachment position
+ hasEnd = suffixRe.search(content[attPos:])
+ if hasEnd:
+ attEndPos = attPos + hasEnd.start() + len(hasEnd.group(1))
+ else:
+ raise ValueError
- attPre = attPos - 9 # back for ;base64, | = (msgPos + 12):
- if '<' == content[attPre - 12]:
- pBack = 12
- elif attPre - msgPos + 5 >= 0:
- if '<' == content[attPre - 5]:
- pBack = 5
- attPre = attPre - pBack
+ prefix_max = attOffset if attOffset <= 180 else 180 # define max forward searching for base64 embedded codes '= 4: # too small not attachments, leave as is
+ havefn = fnRe1.search(prefixStr)
+ if not havefn:
+ havefn = fnRe2.search(prefixStr)
+ fn = '%s_%d_%s_%s' % (attPrefix, attPos, iscomplete.group(1), havefn.group(1) if havefn else 'notdetected')
+ attPre = attPos - prefix_max + iscomplete.start()
- try:
- fnPos = content.index('alt="', msgPos, attPos) + 5 # Finds position of the filename
- fnEndPos = content.index('" src=', msgPos, attPos) # Finds the end position
- # fnLen = fnEndPos - fnPos #Finds the length of the filename
- fn = content[fnPos:fnEndPos]
-
- attPre = fnPos - 5 # back for alt=" | = (msgPos + 12):
- if '<' == content[attPre - 12]:
- pBack = 12
- elif attPre - msgPos + 5 >= 0:
- if '<' == content[attPre - 5]:
- pBack = 5
- attPre = attPre - pBack
-
- except ValueError:
- fn = 'notdetected'
- fn = '%d_attachment_%d_%s' % (attPrefix, attPos, fn)
-
- this_attachment = content[attPos:attEndPos]
+ this_attachment = content[attPos:attPos + hasEnd.start()]
x = filter(lambda z: not re.match(r'^\s*$', z), this_attachment)
# x = x.replace('\n', '').strip()
trydecode = False
+ counter += 1
if len(x) % 4 == 0: # check by length before decode.
trydecode = True
else:
print '\n'.join([
' -----------------------------------',
' Embeded mesaage seems not "BASE64" encoded. (base on length check)',
- ' Offset: %d, about: %d(bytes).' % (attPos, (int(len(x)*3/4)) - 2 if x[-2:] == '==' else 1 if x[-1] == '=' else 0),
- ' Start[%d] ~ Ends[%d].' % (x[:3], x[-3:]),
+ ' Offset: %d, about: %d(bytes).' % (attPre, getBase64Len(x)),
+ ' Start[%s] ~ Ends[%s].' % (x[:3], x[-3:]),
' FileName: "%s"' % fn,
])
uInput = userInput('Try to decode anyway, (n)o or (Y)es?')
@@ -1583,31 +1579,32 @@ def attDetect(content=None, textmsg=None, attPrefix=None, askSave=True):
try:
y = x.decode('base64', 'strict')
if x == y.encode('base64').replace('\n', ''): # double check decoded string.
- print ' This embeded message decoded successfully:', fn
if askSave is True:
- uInput = userInput('Download the "decoded" attachment, (y)es or (No)?\nName(%d): %s,' % (counter, fn)).lower()
+ uInput = userInput('Download the "decoded" attachment, (y)es or (No)?\nNames[%d]: %s,' % (counter, fn)).lower()
if uInput in inputShorts['yes']:
src = dump2File(fn, y, True)
+ else:
+ src = ' Attachment skiped[%d] "%s".' % (counter, fn)
else:
src = dump2File(fn, y, True)
print src
attmsg = '\n'.join([
' -----------------------------------',
- ' Attachment: "%s"' % fn,
+ ' Attachment[%d]: "%s"' % (counter, fn),
' Size: %d(bytes)' % getBase64Len(x),
' -----------------------------------',
])
# remove base64 and '' stuff
textmsg = textmsg + content[msgPos:attPre] + attmsg
- attEndPos += 3
msgPos = attEndPos
else:
print '\n Failed on decode this embeded "BASE64" like message on re-encode check.\n'
except ValueError:
- pass
print '\n Failed on decode this emdeded "BASE64" encoded like message.\n'
+ except InputException:
+ raise
except Exception:
print '\n Unexpected error: %s.\n' % sys.exc_info()[0]
@@ -1621,7 +1618,10 @@ def attDetect(content=None, textmsg=None, attPrefix=None, askSave=True):
except ValueError:
textmsg = textmsg + content[msgPos:]
break
+ except InputException:
+ raise
except Exception:
+ traceback.print_exc()
print '\n Unexpected error: %s.\n' % sys.exc_info()[0]
return textmsg
@@ -1630,8 +1630,8 @@ def attDetect(content=None, textmsg=None, attPrefix=None, askSave=True):
def readSentMsg(cmd='read', msgNum=-1, messageID=None, trunck=380, withAtta=False):
"""Opens a sent message for reading"""
- print ' All outbox messages downloading...', str(msgNum)
- if messageID is None:
+ print ' All outbox messages downloading...', str(msgNum), messageID
+ if not messageID:
response = api.getAllSentMessages()
if response['error'] != 0:
return response['errormsg']
@@ -1667,7 +1667,7 @@ def readSentMsg(cmd='read', msgNum=-1, messageID=None, trunck=380, withAtta=Fals
print ' ', 74 * '-'
if cmd == 'save':
- ret = dump2File('outbox_' + subject, textmsg, withAtta)
+ ret = dump2File('outbox_' + subject, textmsg, True)
print ret
return ''
@@ -1703,7 +1703,7 @@ def readMsg(cmd='read', msgNum=-1, messageID=None, trunck=380, withAtta=False):
print ' ', 74 * '-'
if cmd == 'save':
- ret = dump2File('inbox_' + subject + str(full), textmsg, withAtta)
+ ret = dump2File('inbox_' + subject + str(full), textmsg, True)
print ret
return ''
@@ -1800,7 +1800,7 @@ def delMsg(msgNum=-1, messageID=None):
def delSentMsg(msgNum=-1, messageID=None):
"""Deletes a specified message from the outbox"""
- if messageID is None:
+ if not messageID:
print ' All outbox messages downloading...', str(msgNum)
response = api.getAllSentMessages()
if response['error'] != 0:
@@ -2374,7 +2374,7 @@ def UI(cmdInput=None):
elif cmdInput in cmdShorts['send']: # Sends a message or broadcast
uInput = userInput('Would you like to send a (b)roadcast or (M)essage?').lower()
- null = ''
+ null = None
if uInput in inputShorts['broadcast']:
src = sendBrd(null, null, null)
else: