str.join() only take exactly one argument, but xx given start from src. [python 2.7] #1288

Closed
opened 2018-06-28 12:16:21 +02:00 by peter-tank · 6 comments
peter-tank commented 2018-06-28 12:16:21 +02:00 (Migrated from github.com)

May we change the code ''.join(,,,) to '{}{}{}'.format(,,,)?
The error too many arguments given raised in src/bitmessagecli.py, runing from python2.7.

May we change the code `''.join(,,,)` to `'{}{}{}'.format(,,,)`? The error `too many arguments given` raised in `src/bitmessagecli.py`, runing from python2.7.
g1itch commented 2018-06-28 12:42:38 +02:00 (Migrated from github.com)

It's probably another untested change from @coffeedogs: e0d31d7 kiksed (:

Try this patch

diff --git a/src/bitmessagecli.py b/src/bitmessagecli.py
index 69d2484..02fed7e 100644
--- a/src/bitmessagecli.py
+++ b/src/bitmessagecli.py
@@ -572,7 +572,7 @@ def listAdd():
         if len(label) > 19:
             label = label[:16] + '...'
 
-        print ''.join(
+        print ''.join([
             '     |',
             str(addNum).ljust(3),
             '|',
@@ -584,13 +584,13 @@ def listAdd():
             '|',
             enabled.ljust(7),
             '|',
-        )
+        ])
 
-    print ''.join(
+    print ''.join([
         '     ',
         74 * '-',
         '\n',
-    )
+    ])
 
 
 def genAdd(lbl, deterministic, passphrase, numOfAdd, addVNum, streamNum, ripe):
@@ -675,11 +675,11 @@ def attachment():
         round(invSize, 2)  # Rounds to two decimal places
 
         if invSize > 500.0:  # If over 500KB
-            print ''.join(
+            print ''.join([
                 '\n     WARNING:The file that you are trying to attach is ',
                 invSize,
                 'KB and will take considerable time to send.\n'
-            )
+            ])
             uInput = userInput('Are you sure you still want to attach it, (Y)es or (N)o?').lower()
 
             if uInput != "y":
@@ -931,11 +931,11 @@ def inbox(unreadOnly=False):
             print '     To:', getLabelForAddress(message['toAddress'])  # Get the to address
             print '     From:', getLabelForAddress(message['fromAddress'])  # Get the from address
             print '     Subject:', message['subject'].decode('base64')  # Get the subject
-            print ''.join(
+            print ''.join([
                 '     Received:',
                 datetime.datetime.fromtimestamp(
                     float(message['receivedTime'])).strftime('%Y-%m-%d %H:%M:%S'),
-            )
+            ])
             messagesPrinted += 1
             if not message['read']:
                 messagesUnread += 1
@@ -970,11 +970,11 @@ def outbox():
         print '     Subject:', outboxMessages['sentMessages'][msgNum]['subject'].decode('base64')  # Get the subject
         print '     Status:', outboxMessages['sentMessages'][msgNum]['status']  # Get the subject
 
-        print ''.join(
+        print ''.join([
             '     Last Action Time:',
             datetime.datetime.fromtimestamp(
                 float(outboxMessages['sentMessages'][msgNum]['lastActionTime'])).strftime('%Y-%m-%d %H:%M:%S'),
-        )
+        ])
 
         if msgNum % 20 == 0 and msgNum != 0:
             userInput('(Press Enter to continue or type (Exit) to return to the main menu.)').lower()  # uInput =
@@ -1040,11 +1040,11 @@ def readSentMsg(msgNum):
     print '     From:', getLabelForAddress(outboxMessages['sentMessages'][msgNum]['fromAddress'])
     print '     Subject:', outboxMessages['sentMessages'][msgNum]['subject'].decode('base64')  # Get the subject
     print '     Status:', outboxMessages['sentMessages'][msgNum]['status']  # Get the subject
-    print ''.join(
+    print ''.join([
         '     Last Action Time:',
         datetime.datetime.fromtimestamp(
             float(outboxMessages['sentMessages'][msgNum]['lastActionTime'])).strftime('%Y-%m-%d %H:%M:%S'),
-    )
+    ])
     print '     Message:\n'
     print message  # inboxMessages['inboxMessages'][msgNum]['message'].decode('base64')
     print ' '
@@ -1101,10 +1101,10 @@ def readMsg(msgNum):
     # Get the from address
     print '     From:', getLabelForAddress(inboxMessages['inboxMessages'][msgNum]['fromAddress'])
     print '     Subject:', inboxMessages['inboxMessages'][msgNum]['subject'].decode('base64')  # Get the subject
-    print ''.join(
+    print ''.join([
         '     Received:', datetime.datetime.fromtimestamp(
             float(inboxMessages['inboxMessages'][msgNum]['receivedTime'])).strftime('%Y-%m-%d %H:%M:%S'),
-    )
+    ])
     print '     Message:\n'
     print message  # inboxMessages['inboxMessages'][msgNum]['message'].decode('base64')
     print ' '
It's probably another untested change from @coffeedogs: e0d31d7 kiksed (: Try this patch ```diff diff --git a/src/bitmessagecli.py b/src/bitmessagecli.py index 69d2484..02fed7e 100644 --- a/src/bitmessagecli.py +++ b/src/bitmessagecli.py @@ -572,7 +572,7 @@ def listAdd(): if len(label) > 19: label = label[:16] + '...' - print ''.join( + print ''.join([ ' |', str(addNum).ljust(3), '|', @@ -584,13 +584,13 @@ def listAdd(): '|', enabled.ljust(7), '|', - ) + ]) - print ''.join( + print ''.join([ ' ', 74 * '-', '\n', - ) + ]) def genAdd(lbl, deterministic, passphrase, numOfAdd, addVNum, streamNum, ripe): @@ -675,11 +675,11 @@ def attachment(): round(invSize, 2) # Rounds to two decimal places if invSize > 500.0: # If over 500KB - print ''.join( + print ''.join([ '\n WARNING:The file that you are trying to attach is ', invSize, 'KB and will take considerable time to send.\n' - ) + ]) uInput = userInput('Are you sure you still want to attach it, (Y)es or (N)o?').lower() if uInput != "y": @@ -931,11 +931,11 @@ def inbox(unreadOnly=False): print ' To:', getLabelForAddress(message['toAddress']) # Get the to address print ' From:', getLabelForAddress(message['fromAddress']) # Get the from address print ' Subject:', message['subject'].decode('base64') # Get the subject - print ''.join( + print ''.join([ ' Received:', datetime.datetime.fromtimestamp( float(message['receivedTime'])).strftime('%Y-%m-%d %H:%M:%S'), - ) + ]) messagesPrinted += 1 if not message['read']: messagesUnread += 1 @@ -970,11 +970,11 @@ def outbox(): print ' Subject:', outboxMessages['sentMessages'][msgNum]['subject'].decode('base64') # Get the subject print ' Status:', outboxMessages['sentMessages'][msgNum]['status'] # Get the subject - print ''.join( + print ''.join([ ' Last Action Time:', datetime.datetime.fromtimestamp( float(outboxMessages['sentMessages'][msgNum]['lastActionTime'])).strftime('%Y-%m-%d %H:%M:%S'), - ) + ]) if msgNum % 20 == 0 and msgNum != 0: userInput('(Press Enter to continue or type (Exit) to return to the main menu.)').lower() # uInput = @@ -1040,11 +1040,11 @@ def readSentMsg(msgNum): print ' From:', getLabelForAddress(outboxMessages['sentMessages'][msgNum]['fromAddress']) print ' Subject:', outboxMessages['sentMessages'][msgNum]['subject'].decode('base64') # Get the subject print ' Status:', outboxMessages['sentMessages'][msgNum]['status'] # Get the subject - print ''.join( + print ''.join([ ' Last Action Time:', datetime.datetime.fromtimestamp( float(outboxMessages['sentMessages'][msgNum]['lastActionTime'])).strftime('%Y-%m-%d %H:%M:%S'), - ) + ]) print ' Message:\n' print message # inboxMessages['inboxMessages'][msgNum]['message'].decode('base64') print ' ' @@ -1101,10 +1101,10 @@ def readMsg(msgNum): # Get the from address print ' From:', getLabelForAddress(inboxMessages['inboxMessages'][msgNum]['fromAddress']) print ' Subject:', inboxMessages['inboxMessages'][msgNum]['subject'].decode('base64') # Get the subject - print ''.join( + print ''.join([ ' Received:', datetime.datetime.fromtimestamp( float(inboxMessages['inboxMessages'][msgNum]['receivedTime'])).strftime('%Y-%m-%d %H:%M:%S'), - ) + ]) print ' Message:\n' print message # inboxMessages['inboxMessages'][msgNum]['message'].decode('base64') print ' ' ```
peter-tank commented 2018-06-28 13:09:59 +02:00 (Migrated from github.com)

That's lint, a little change appending:

@583
- stream.ljust(1),
+ steam.ljust(2),
That's lint, a little change appending: ``` @583 - stream.ljust(1), + steam.ljust(2), ```
coffeedogs commented 2018-06-28 13:20:07 +02:00 (Migrated from github.com)

Indeed, missing square brackets was not picked up by code review. As for tests, it remains a shame that we have no tests. I'm currently working on getting the QT app being driven by tests. I'll take a look at automating testing the CLI afterwards. @g1itch would you like me to submit a patch or are you already submitting the above diff?

I would really appreciate it, @g1itch, if you would stop blaming me for the decision to allocate my time towards code cleanup. I know exactly the problems that such an approach has, the types of bugs that arise, especially putting the new guy on it. However that risk was assessed and accepted by our respected team lead so please let's just deal with the consequences in a friendly manner. We should have the courage to change code. The v0.6 branch is not a release, it does not have to be perfect at all times.

Indeed, missing square brackets was not picked up by code review. As for tests, it remains a shame that we have no tests. I'm currently working on getting the QT app being driven by tests. I'll take a look at automating testing the CLI afterwards. @g1itch would you like me to submit a patch or are you already submitting the above diff? I would really appreciate it, @g1itch, if you would stop blaming me for the decision to allocate my time towards code cleanup. I know exactly the problems that such an approach has, the types of bugs that arise, especially putting the new guy on it. However that risk was assessed and accepted by our respected team lead so please let's just deal with the consequences in a friendly manner. We should have the courage to change code. The v0.6 branch is not a release, it does not have to be perfect at all times.
PeterSurda commented 2018-06-28 13:32:47 +02:00 (Migrated from github.com)

I'm afraid errors like this are inevitable if we're cleaning up the code. It would require extraordinary amount of resources to avoid these kind of problems at this stage of the project, which I don't have. For the time being, I'm ok with minor breakages as long as they are reported and fixed quickly.

I'm afraid errors like this are inevitable if we're cleaning up the code. It would require extraordinary amount of resources to avoid these kind of problems at this stage of the project, which I don't have. For the time being, I'm ok with minor breakages as long as they are reported and fixed quickly.
g1itch commented 2018-06-28 13:32:58 +02:00 (Migrated from github.com)

Please apply and submit it yourself. Maybe you'll find something more in bitmessagecli in process. The last comment is mysterious for me, @peter-tank what it means? Personally I don't care about bitmessagecli because I don't use it, don't understand, so cannot test locally if it works properly.

But maybe I will review PR's for such code which not concerns me, in order to spot such obvious mistakes.

Please apply and submit it yourself. Maybe you'll find something more in bitmessagecli in process. The last comment is mysterious for me, @peter-tank what it means? Personally I don't care about bitmessagecli because I don't use it, don't understand, so cannot test locally if it works properly. But maybe I will review PR's for such code which not concerns me, in order to spot such obvious mistakes.
peter-tank commented 2018-06-30 14:09:18 +02:00 (Migrated from github.com)

Sorry for confused @coffeedogs
Every one like GUI, except me... It's sad.
I made more changes on src/bitmessagecli.py, can you help to review and pull it?
These changes seems functionable, but for coder maybe it's too ugly.
As you can see but a new guy's trying.

  • Modifications:
    • Try save user's input on steps and replay(stack method works suck).
    • Add some input checking avoid error raise.
    • Update mail with attachment nowadays usage.
    • Original mail or header attached on Fw: and Re:, and multi-line mail allowed now.
    • Delete mails not simply follow by received order(pretty not sure if can use ackData in this way).
old mode 100644
new mode 100755
@@ -30,28 +30,57 @@ api = ''
 keysName = 'keys.dat'
 keysPath = 'keys.dat'
 usrPrompt = 0  # 0 = First Start, 1 = prompt, 2 = no prompt if the program is starting up
 knownAddresses = dict()
 
+import inspect
+cmdstr='help'
+inputs={}
 
 def userInput(message):
     """Checks input for exit or quit. Also formats for input, etc"""
 
-    global usrPrompt
-
-    print '\n' + message
+    global usrPrompt, cmdstr
+
+    stack = list(inspect.stack())
+    where = ''
+    #for item in stack:
+            #print item
+    where = ''.join([
+        str(stack[3][2]),
+        stack[3][3],
+        str(stack[2][2]),
+        stack[1][3],
+        str(stack[1][2]),
+        stack[3][3],
+        cmdstr
+        ])
+    last = '' if where not in inputs.keys() else inputs[where]
+    print ''.join([
+#        '\n',
+#        where,
+        '\n',
+        message,
+        '\nPress enter for input: [',
+        last,
+        ']',
+        ])
     uInput = raw_input('> ')
 
     if uInput.lower() == 'exit':  # Returns the user to the main menu
         usrPrompt = 1
         main()
 
     elif uInput.lower() == 'quit':  # Quits the program
         print '\n     Bye\n'
         sys.exit(0)
 
+    elif uInput == '':  # Return last value.
+        return last
+
     else:
+        inputs[where] = uInput
         return uInput
 
 
 def restartBmNotify():
     """Prompt the user to restart Bitmessage"""
@@ -247,14 +276,15 @@ def apiData():
     apiPort = int(BMConfigParser().get('bitmessagesettings', 'apiport'))
     apiInterface = BMConfigParser().get('bitmessagesettings', 'apiinterface')
     apiUsername = BMConfigParser().get('bitmessagesettings', 'apiusername')
     apiPassword = BMConfigParser().get('bitmessagesettings', 'apipassword')
 
-    print '\n     API data successfully imported.\n'
+    ret = "http://" + apiUsername + ":" + apiPassword + "@" + apiInterface + ":" + str(apiPort) + "/"
+    print '\n     API data successfully imported.\n     ' + ret
 
     # Build the api credentials
-    return "http://" + apiUsername + ":" + apiPassword + "@" + apiInterface + ":" + str(apiPort) + "/"
+    return ret
 
 
 # End keys.dat interactions
 
 
@@ -556,11 +586,11 @@ def listAdd():
     except:
         print '\n     Connection Error\n'
         usrPrompt = 0
         main()
 
-    # print '\nAddress Number,Label,Address,Stream,Enabled\n'
+    # print '\nAddress Index,Label,Address,Stream,Enabled\n'
     print '\n     --------------------------------------------------------------------------'
     print '     | # |       Label       |               Address               |S#|Enabled|'
     print '     |---|-------------------|-------------------------------------|--|-------|'
     for addNum in range(0, numAddresses):  # processes all of the addresses and lists them out
         label = (jsonAddresses['addresses'][addNum]['label']).encode(
@@ -570,29 +600,29 @@ def listAdd():
         enabled = str(jsonAddresses['addresses'][addNum]['enabled'])
 
         if len(label) > 19:
             label = label[:16] + '...'
 
-        print ''.join(
+        print ''.join([
             '     |',
             str(addNum).ljust(3),
             '|',
             label.ljust(19),
             '|',
             address.ljust(37),
             '|',
-            stream.ljust(1),
+            stream.ljust(2),
             '|',
             enabled.ljust(7),
             '|',
-        )
+        ])
 
-    print ''.join(
+    print ''.join([
         '     ',
         74 * '-',
         '\n',
-    )
+    ])
 
 
 def genAdd(lbl, deterministic, passphrase, numOfAdd, addVNum, streamNum, ripe):
     """Generate address"""
 
@@ -673,15 +703,15 @@ def attachment():
         invSize = os.path.getsize(filePath)
         invSize = (invSize / 1024)  # Converts to kilobytes
         round(invSize, 2)  # Rounds to two decimal places
 
         if invSize > 500.0:  # If over 500KB
-            print ''.join(
+            print ''.join([
                 '\n     WARNING:The file that you are trying to attach is ',
                 invSize,
                 'KB and will take considerable time to send.\n'
-            )
+            ])
             uInput = userInput('Are you sure you still want to attach it, (Y)es or (N)o?').lower()
 
             if uInput != "y":
                 print '\n     Attachment discarded.\n'
                 return ''
@@ -719,11 +749,11 @@ Filename:%s
 Filesize:%sKB
 Encoding:base64
 
 <center>
     <div id="image">
-        <img alt = "%s" src='data:image/%s;base64, %s' />
+        <img alt = "%s" src="data:image/%s;base64, %s"/>
     </div>
 </center>""" % (fileName, invSize, fileName, filetype, data)
         else:  # Else it is not an image so do not include the embedded image code.
             theAttachment = """
 <!-- Note: File attachment below. Please use a base64 decoder, or Daemon, to save it. -->
@@ -731,11 +761,11 @@ Encoding:base64
 
 Filename:%s
 Filesize:%sKB
 Encoding:base64
 
-<attachment alt = "%s" src='data:file/%s;base64, %s' />""" % (fileName, invSize, fileName, fileName, data)
+<attachment alt = "%s" src="data:file/%s;base64, %s"/>""" % (fileName, invSize, fileName, fileName, data)
 
         uInput = userInput('Would you like to add another attachment, (Y)es or (N)o?').lower()
 
         if uInput == 'y' or uInput == 'yes':  # Allows multiple attachments to be added to one message
             theAttachmentS = str(theAttachmentS) + str(theAttachment) + '\n\n'
@@ -815,12 +845,23 @@ def sendMsg(toAddress, fromAddress, subject, message):
             fromAddress = jsonAddresses['addresses'][0]['address']
 
     if subject == '':
         subject = userInput("Enter your Subject.")
         subject = subject.encode('base64')
+    elif subject == 'c':
+        usrPrompt = 1
+        print ' '
+        main()
     if message == '':
-        message = userInput("Enter your Message.")
+        while True:
+            try:
+                message += ''.join([
+                    '\n',
+                    userInput("Continue enter your Message line by line, end with <CTL-D>."),
+                    ])
+            except EOFError:
+                break
 
         uInput = userInput('Would you like to add an attachment, (Y)es or (N)o?').lower()
         if uInput == "y":
             message = message + '\n\n' + attachment()
 
@@ -889,11 +930,18 @@ def sendBrd(fromAddress, subject, message):
 
     if subject == '':
         subject = userInput("Enter your Subject.")
         subject = subject.encode('base64')
     if message == '':
-        message = userInput("Enter your Message.")
+        while True:
+            try:
+                message += ''.join([
+                    '\n',
+                    userInput("Continue enter your Message line by line, end with <CTL-D>."),
+                    ])
+            except EOFError:
+                break
 
         uInput = userInput('Would you like to add an attachment, (Y)es or (N)o?').lower()
         if uInput == "y":
             message = message + '\n\n' + attachment()
 
@@ -907,11 +955,11 @@ def sendBrd(fromAddress, subject, message):
         usrPrompt = 0
         main()
 
 
 def inbox(unreadOnly=False):
-    """Lists the messages by: Message Number, To Address Label, From Address Label, Subject, Received Time)"""
+    """Lists the messages by: message index, To Address Label, From Address Label, Subject, Received Time)"""
 
     global usrPrompt
     try:
         inboxMessages = json.loads(api.getAllInboxMessages())
         numMessages = len(inboxMessages['inboxMessages'])
@@ -925,19 +973,21 @@ def inbox(unreadOnly=False):
     for msgNum in range(0, numMessages):  # processes all of the messages in the inbox
         message = inboxMessages['inboxMessages'][msgNum]
         # if we are displaying all messages or if this message is unread then display it
         if not unreadOnly or not message['read']:
             print '     -----------------------------------\n'
-            print '     Message Number:', msgNum  # Message Number
+            print '     Message index:{}/{}'.format(msgNum, numMessages - 1)  # message index
+            print '     Message ID:', inboxMessages['inboxMessages'][msgNum]['msgid']
+            print '     Read:', inboxMessages['inboxMessages'][msgNum]['read']
             print '     To:', getLabelForAddress(message['toAddress'])  # Get the to address
             print '     From:', getLabelForAddress(message['fromAddress'])  # Get the from address
             print '     Subject:', message['subject'].decode('base64')  # Get the subject
-            print ''.join(
+            print ''.join([
                 '     Received:',
                 datetime.datetime.fromtimestamp(
                     float(message['receivedTime'])).strftime('%Y-%m-%d %H:%M:%S'),
-            )
+            ])
             messagesPrinted += 1
             if not message['read']:
                 messagesUnread += 1
 
         if messagesPrinted % 20 == 0 and messagesPrinted != 0:
@@ -960,23 +1010,24 @@ def outbox():
         usrPrompt = 0
         main()
 
     for msgNum in range(0, numMessages):  # processes all of the messages in the outbox
         print '\n     -----------------------------------\n'
-        print '     Message Number:', msgNum  # Message Number
-        # print '     Message ID:', outboxMessages['sentMessages'][msgNum]['msgid']
+        print '     Message index:{}/{}'.format(msgNum, numMessages - 1)  # message index
+        print '     Message ID:', outboxMessages['sentMessages'][msgNum]['msgid']
         print '     To:', getLabelForAddress(outboxMessages['sentMessages'][msgNum]['toAddress'])  # Get the to address
         # Get the from address
         print '     From:', getLabelForAddress(outboxMessages['sentMessages'][msgNum]['fromAddress'])
         print '     Subject:', outboxMessages['sentMessages'][msgNum]['subject'].decode('base64')  # Get the subject
-        print '     Status:', outboxMessages['sentMessages'][msgNum]['status']  # Get the subject
+        print '     Status:', outboxMessages['sentMessages'][msgNum]['status']  # Get the status
+        print '     Ack:', outboxMessages['sentMessages'][msgNum]['ackData']  # Get the ackData
 
-        print ''.join(
+        print ''.join([
             '     Last Action Time:',
             datetime.datetime.fromtimestamp(
                 float(outboxMessages['sentMessages'][msgNum]['lastActionTime'])).strftime('%Y-%m-%d %H:%M:%S'),
-        )
+        ])
 
         if msgNum % 20 == 0 and msgNum != 0:
             userInput('(Press Enter to continue or type (Exit) to return to the main menu.)').lower()  # uInput =
 
     print '\n     -----------------------------------'
@@ -997,20 +1048,20 @@ def readSentMsg(msgNum):
         main()
 
     print ' '
 
     if msgNum >= numMessages:
-        print '\n     Invalid Message Number.\n'
+        print '\n     Invalid message index.\n'
         main()
 
     # Begin attachment detection
     message = outboxMessages['sentMessages'][msgNum]['message'].decode('base64')
 
     while True:  # Allows multiple messages to be downloaded/saved
         if ';base64,' in message:  # Found this text in the message, there is probably an attachment.
             attPos = message.index(";base64,")  # Finds the attachment position
-            attEndPos = message.index("' />")  # Finds the end of the attachment
+            attEndPos = message.index('/>')  # Finds the end of the attachment
             # attLen = attEndPos - attPos #Finds the length of the message
 
             if 'alt = "' in message:  # We can get the filename too
                 fnPos = message.index('alt = "')  # Finds position of the filename
                 fnEndPos = message.index('" src=')  # Finds the end position
@@ -1032,24 +1083,28 @@ def readSentMsg(msgNum):
 
         else:
             break
 
     # End attachment Detection
-
-    print '\n     To:', getLabelForAddress(outboxMessages['sentMessages'][msgNum]['toAddress'])  # Get the to address
+    print '\n     Message index:{}/{}'.format(msgNum, numMessages - 1)  # message outdex
+    print '     Message ID:', outboxMessages['sentMessages'][msgNum]['msgid']
+    print '     To:', getLabelForAddress(outboxMessages['sentMessages'][msgNum]['toAddress'])  # Get the to address
     # Get the from address
     print '     From:', getLabelForAddress(outboxMessages['sentMessages'][msgNum]['fromAddress'])
     print '     Subject:', outboxMessages['sentMessages'][msgNum]['subject'].decode('base64')  # Get the subject
-    print '     Status:', outboxMessages['sentMessages'][msgNum]['status']  # Get the subject
-    print ''.join(
+    print '     Status:', outboxMessages['sentMessages'][msgNum]['status']  # Get the status
+    print '     Ack:', outboxMessages['sentMessages'][msgNum]['ackData']  # Get the ackData
+
+    print ''.join([
         '     Last Action Time:',
         datetime.datetime.fromtimestamp(
             float(outboxMessages['sentMessages'][msgNum]['lastActionTime'])).strftime('%Y-%m-%d %H:%M:%S'),
-    )
+    ])
     print '     Message:\n'
     print message  # inboxMessages['inboxMessages'][msgNum]['message'].decode('base64')
     print ' '
+    return outboxMessages['sentMessages'][msgNum]['msgid']
 
 
 def readMsg(msgNum):
     """Open a message for reading"""
     global usrPrompt
@@ -1060,20 +1115,20 @@ def readMsg(msgNum):
         print '\n     Connection Error\n'
         usrPrompt = 0
         main()
 
     if msgNum >= numMessages:
-        print '\n     Invalid Message Number.\n'
+        print '\n     Invalid message index.\n'
         main()
 
     # Begin attachment detection
     message = inboxMessages['inboxMessages'][msgNum]['message'].decode('base64')
 
     while True:  # Allows multiple messages to be downloaded/saved
         if ';base64,' in message:  # Found this text in the message, there is probably an attachment.
             attPos = message.index(";base64,")  # Finds the attachment position
-            attEndPos = message.index("' />")  # Finds the end of the attachment
+            attEndPos = message.index('/>')  # Finds the end of the attachment
             # attLen = attEndPos - attPos #Finds the length of the message
 
             if 'alt = "' in message:  # We can get the filename too
                 fnPos = message.index('alt = "')  # Finds position of the filename
                 fnEndPos = message.index('" src=')  # Finds the end position
@@ -1095,44 +1150,47 @@ def readMsg(msgNum):
 
         else:
             break
 
     # End attachment Detection
-    print '\n     To:', getLabelForAddress(inboxMessages['inboxMessages'][msgNum]['toAddress'])  # Get the to address
+    print '\n     Message index:{}/{}'.format(msgNum, numMessages - 1)  # message index
+    print '     Message ID:', inboxMessages['inboxMessages'][msgNum]['msgid']
+    print '     To:', getLabelForAddress(inboxMessages['inboxMessages'][msgNum]['toAddress'])  # Get the to address
     # Get the from address
     print '     From:', getLabelForAddress(inboxMessages['inboxMessages'][msgNum]['fromAddress'])
     print '     Subject:', inboxMessages['inboxMessages'][msgNum]['subject'].decode('base64')  # Get the subject
-    print ''.join(
+    print ''.join([
         '     Received:', datetime.datetime.fromtimestamp(
             float(inboxMessages['inboxMessages'][msgNum]['receivedTime'])).strftime('%Y-%m-%d %H:%M:%S'),
-    )
+    ])
     print '     Message:\n'
     print message  # inboxMessages['inboxMessages'][msgNum]['message'].decode('base64')
     print ' '
     return inboxMessages['inboxMessages'][msgNum]['msgid']
 
 
-def replyMsg(msgNum, forwardORreply):
+def replyMsg(messageID, forwardORreply):
     """Allows you to reply to the message you are currently on. Saves typing in the addresses and subject."""
 
     global usrPrompt
     forwardORreply = forwardORreply.lower()  # makes it lowercase
     try:
-        inboxMessages = json.loads(api.getAllInboxMessages())
+        inboxMessage = json.loads(api.getInboxMessageById(messageID))['inboxMessage']
     except:
         print '\n     Connection Error\n'
         usrPrompt = 0
         main()
 
-    fromAdd = inboxMessages['inboxMessages'][msgNum]['toAddress']  # Address it was sent To, now the From address
-    message = inboxMessages['inboxMessages'][msgNum]['message'].decode('base64')  # Message that you are replying too.
+    fromAdd = inboxMessage[0]['toAddress']  # Address it was sent To, now the From address
+    fwdFrom = inboxMessage[0]['fromAddress']  # Address it was sent To, will attached to fwd
+    message = inboxMessage[0]['message'].decode('base64')  # Message that you are replying too.
 
-    subject = inboxMessages['inboxMessages'][msgNum]['subject']
+    subject = inboxMessage[0]['subject']
     subject = subject.decode('base64')
 
     if forwardORreply == 'reply':
-        toAdd = inboxMessages['inboxMessages'][msgNum]['fromAddress']  # Address it was From, now the To address
+        toAdd = inboxMessage[0]['fromAddress']  # Address it was From, now the To address
         subject = "Re: " + subject
 
     elif forwardORreply == 'forward':
         subject = "Fwd: " + subject
 
@@ -1152,59 +1210,73 @@ def replyMsg(msgNum, forwardORreply):
         usrPrompt = 0
         main()
 
     subject = subject.encode('base64')
 
-    newMessage = userInput("Enter your Message.")
+    while True:
+        try:
+            newMessage = ''.join([
+                '\n',
+                userInput("Continue enter your Message line by line, end with <CTL-D>."),
+                ])
+        except EOFError:
+            break
 
     uInput = userInput('Would you like to add an attachment, (Y)es or (N)o?').lower()
     if uInput == "y":
         newMessage = newMessage + '\n\n' + attachment()
 
     newMessage = newMessage + '\n\n------------------------------------------------------\n'
-    newMessage = newMessage + message
+    attachMessage = ''
+    if forwardORreply == 'forward':
+        attachMessage = ''.join([
+            '>>To: ', fwdFrom,
+            '\n>>From: ', fromAdd,
+            '\n>>Subject: ', subject ,
+            '\n>>Message: ',
+            ])
+    for line in message.splitlines():
+        attachMessage = attachMessage + '>' + line + '\n'
+    newMessage = newMessage + attachMessage
     newMessage = newMessage.encode('base64')
 
     sendMsg(toAdd, fromAdd, subject, newMessage)
 
     main()
 
 
-def delMsg(msgNum):
+def delMsg(messageID):
     """Deletes a specified message from the inbox"""
 
     global usrPrompt
     try:
-        inboxMessages = json.loads(api.getAllInboxMessages())
-        # gets the message ID via the message index number
-        msgId = inboxMessages['inboxMessages'][int(msgNum)]['msgid']
-
-        msgAck = api.trashMessage(msgId)
+        msgAck = api.trashMessage(messageID)
+        return msgAck
     except:
         print '\n     Connection Error\n'
         usrPrompt = 0
         main()
 
-    return msgAck
-
 
-def delSentMsg(msgNum):
+def delSentMsg(msgNum, messageID=''):
     """Deletes a specified message from the outbox"""
 
     global usrPrompt
     try:
-        outboxMessages = json.loads(api.getAllSentMessages())
-        # gets the message ID via the message index number
-        msgId = outboxMessages['sentMessages'][int(msgNum)]['msgid']
-        msgAck = api.trashSentMessage(msgId)
+        if messageID == '':
+            outboxMessages = json.loads(api.getAllSentMessages())['sentMessages']
+            # gets the message actData via the message index number
+            ackData = outboxMessages[msgNum]['ackData']
+            msgAck = api.trashSentMessageByAckData(ackData)
+        else:
+            msgAck = api.trashSentMessage(messageID)
+        return msgAck
     except:
         print '\n     Connection Error\n'
         usrPrompt = 0
         main()
 
-    return msgAck
-
 
 def getLabelForAddress(address):
     """Get label for an address"""
 
     if address in knownAddresses:
@@ -1328,10 +1400,13 @@ def markMessageRead(messageID):
 
     try:
         response = api.getInboxMessageByID(messageID, True)
         if "API Error" in response:
             return getAPIErrorCode(response)
+        print '\n     TODO: need mark readMessage() API.\n'
+        #msgAck = api.readMessage(msgId)
+        #return msgAck
     except:
         print '\n     Connection Error\n'
         usrPrompt = 0
         main()
 
@@ -1343,46 +1418,46 @@ def markMessageUnread(messageID):
 
     try:
         response = api.getInboxMessageByID(messageID, False)
         if "API Error" in response:
             return getAPIErrorCode(response)
+        print '\n     TODO: need mark unReadMessage() API.\n'
+        #msgAck = api.unReadMessage(msgId)
+        #return msgAck
     except:
         print '\n     Connection Error\n'
         usrPrompt = 0
         main()
 
-
 def markAllMessagesRead():
     """Mark all messages as read"""
 
     global usrPrompt
 
     try:
-        inboxMessages = json.loads(api.getAllInboxMessages())['inboxMessages']
+        inboxMessagesIds = json.loads(api.getAllInboxMessageIDs())['inboxMessageIds']
     except:
         print '\n     Connection Error\n'
         usrPrompt = 0
         main()
-    for message in inboxMessages:
-        if not message['read']:
-            markMessageRead(message['msgid'])
+    for messageID in inboxMessagesIds:
+        markMessageRead(messageID)
 
 
 def markAllMessagesUnread():
     """Mark all messages as unread"""
 
     global usrPrompt
 
     try:
-        inboxMessages = json.loads(api.getAllInboxMessages())['inboxMessages']
+        inboxMessagesIds = json.loads(api.getAllInboxMessageIDs())['inboxMessageIds']
     except:
         print '\n     Connection Error\n'
         usrPrompt = 0
         main()
-    for message in inboxMessages:
-        if message['read']:
-            markMessageUnread(message['msgid'])
+    for messageID in inboxMessagesIds:
+        markMessageUnread(messageID)
 
 
 def clientStatus():
     """Print the client status"""
 
@@ -1605,61 +1680,75 @@ def UI(usrInput):
         if (uInput != 'i' and uInput != 'inbox' and uInput != 'o' and uInput != 'outbox'):
             print '\n     Invalid Input.\n'
             usrPrompt = 1
             main()
 
-        msgNum = int(userInput("What is the number of the message you wish to open?"))
+        while True:
+            cinput = userInput("What is the index of the message you wish to open??")
+            try:
+                if cinput in ['c']:
+                    cinput = -1
+                    break
+                elif int(cinput) < 0:
+                    print '\n     Invalid message index.\n'
+                else:
+                    break
+            except:
+                print '\n     Invalid input. "c" to cancel"\n'
+        if cinput < 0:
+            usrPrompt = 1
+            main()
+
+        msgNum = int(cinput)
 
         if (uInput == 'i' or uInput == 'inbox'):
             print '\n     Loading...\n'
             messageID = readMsg(msgNum)
 
             uInput = userInput("\nWould you like to keep this message unread, (Y)es or (N)o?").lower()
 
             if not (uInput == 'y' or uInput == 'yes'):
-                markMessageRead(messageID)
+                src = markMessageRead(messageID)
                 usrPrompt = 1
 
             uInput = userInput("\nWould you like to (D)elete, (F)orward, (R)eply to, or (Exit) this message?").lower()
 
             if uInput in ['r', 'reply']:
                 print '\n     Loading...\n'
                 print ' '
-                replyMsg(msgNum, 'reply')
+                src = replyMsg(messageID, 'reply')
                 usrPrompt = 1
 
             elif uInput == 'f' or uInput == 'forward':
                 print '\n     Loading...\n'
                 print ' '
-                replyMsg(msgNum, 'forward')
+                src = replyMsg(messageID, 'forward')
                 usrPrompt = 1
 
             elif uInput in ["d", 'delete']:
                 uInput = userInput("Are you sure, (Y)es or (N)o?").lower()  # Prevent accidental deletion
 
                 if uInput == "y":
-                    delMsg(msgNum)
-                    print '\n     Message Deleted.\n'
+                    src = delMsg(messageID)
                     usrPrompt = 1
                 else:
                     usrPrompt = 1
             else:
                 print '\n     Invalid entry\n'
                 usrPrompt = 1
 
         elif (uInput == 'o' or uInput == 'outbox'):
-            readSentMsg(msgNum)
+            messageID = readSentMsg(msgNum)
 
             # Gives the user the option to delete the message
             uInput = userInput("Would you like to (D)elete, or (Exit) this message?").lower()
 
             if (uInput == "d" or uInput == 'delete'):
                 uInput = userInput('Are you sure, (Y)es or (N)o?').lower()  # Prevent accidental deletion
 
                 if uInput == "y":
-                    delSentMsg(msgNum)
-                    print '\n     Message Deleted.\n'
+                    src = delSentMsg(msgNum, messageID)
                     usrPrompt = 1
                 else:
                     usrPrompt = 1
             else:
                 print '\n     Invalid Entry\n'
@@ -1677,35 +1766,61 @@ def UI(usrInput):
             main()
 
         if uInput in ['i', 'inbox']:
             inboxMessages = json.loads(api.getAllInboxMessages())
             numMessages = len(inboxMessages['inboxMessages'])
+            if numMessages < 1:
+                print '\n     Zero message in inbox.\n'
+                usrPrompt = 1
+                main()
 
             while True:
-                msgNum = int(userInput("What is the number of the message you wish to save?"))
-
-                if msgNum >= numMessages:
-                    print '\n     Invalid Message Number.\n'
-                else:
-                    break
+                cinput = userInput("What is the index of the message you wish to save[0-{}]?".format(numMessages - 1))
+                try:
+                    if cinput in ['c']:
+                        cinput = -1
+                        break
+                    elif int(cinput) >= numMessages:
+                        print '\n     Invalid message index.\n'
+                    else:
+                        break
+                except:
+                    print '\n     Invalid input. "c" to cancel"\n'
+            if cinput < 0:
+                usrPrompt = 1
+                main()
 
+            msgNum = int(cinput)
             subject = inboxMessages['inboxMessages'][msgNum]['subject'].decode('base64')
             # Don't decode since it is done in the saveFile function
             message = inboxMessages['inboxMessages'][msgNum]['message']
 
         elif uInput == 'o' or uInput == 'outbox':
             outboxMessages = json.loads(api.getAllSentMessages())
             numMessages = len(outboxMessages['sentMessages'])
+            if numMessages < 1:
+                print '\n     Zero message in outbox.\n'
+                usrPrompt = 1
+                main()
 
             while True:
-                msgNum = int(userInput("What is the number of the message you wish to save?"))
-
-                if msgNum >= numMessages:
-                    print '\n     Invalid Message Number.\n'
-                else:
-                    break
+                cinput = userInput("What is the index of the message you wish to save[0-{}]?".format(numMessages - 1))
+                try:
+                    if cinput in ['c']:
+                        cinput = - 1
+                        break
+                    elif int(cinput) >= numMessages:
+                        print '\n     Invalid message index.\n'
+                    else:
+                        break
+                except:
+                    print '\n     Invalid input. "c" to cancel"\n'
+            if cinput < 0:
+                usrPrompt = 1
+                main()
 
+            msgNum = int(cinput)
             subject = outboxMessages['sentMessages'][msgNum]['subject'].decode('base64')
             # Don't decode since it is done in the saveFile function
             message = outboxMessages['sentMessages'][msgNum]['message']
 
         subject = subject + '.txt'
@@ -1717,72 +1832,80 @@ def UI(usrInput):
     elif usrInput == "delete":  # will delete a message from the system, not reflected on the UI.
 
         uInput = userInput("Would you like to delete a message from the (I)nbox or (O)utbox?").lower()
 
         if uInput in ['i', 'inbox']:
-            inboxMessages = json.loads(api.getAllInboxMessages())
-            numMessages = len(inboxMessages['inboxMessages'])
+            inboxMessagesIds = json.loads(api.getAllInboxMessageIds())['inboxMessageIds']
+            numMessages = len(inboxMessagesIds)
+            if numMessages < 1:
+                print '\n     Zero message in inbox.\n'
+                usrPrompt = 1
+                main()
 
             while True:
                 msgNum = userInput(
-                    'Enter the number of the message you wish to delete or (A)ll to empty the inbox.').lower()
+                    'Enter the index of the message you wish to delete or (A)ll to empty the inbox. [0-{}]'.format(numMessages - 1) ).lower()
 
                 if msgNum == 'a' or msgNum == 'all':
                     break
                 elif int(msgNum) >= numMessages:
-                    print '\n     Invalid Message Number.\n'
+                    print '\n     Invalid message index.\n'
                 else:
                     break
 
             uInput = userInput("Are you sure, (Y)es or (N)o?").lower()  # Prevent accidental deletion
 
             if uInput == "y":
                 if msgNum in ['a', 'all']:
                     print ' '
                     for msgNum in range(0, numMessages):  # processes all of the messages in the inbox
                         print '     Deleting message ', msgNum + 1, ' of ', numMessages
-                        delMsg(0)
+                        delMsg(inboxMessagesIds[msgNum]['msgid'])
 
                     print '\n     Inbox is empty.'
                     usrPrompt = 1
                 else:
-                    delMsg(int(msgNum))
+                    delMsg(inboxMessagesIds[int(msgNum)]['msgid'])
 
-                print '\n     Notice: Message numbers may have changed.\n'
+                print '\n     Notice: Message indexs may have changed.\n'
                 main()
             else:
                 usrPrompt = 1
 
         elif uInput in ['o', 'outbox']:
-            outboxMessages = json.loads(api.getAllSentMessages())
-            numMessages = len(outboxMessages['sentMessages'])
+            outboxMessagesIds = json.loads(api.getAllSentMessageIds())['sentMessageIds']
+            numMessages = len(outboxMessagesIds)
+            if numMessages < 1:
+                print '\n     Zero message in outbox.\n'
+                usrPrompt = 1
+                main()
 
             while True:
                 msgNum = userInput(
-                    'Enter the number of the message you wish to delete or (A)ll to empty the inbox.').lower()
+                    'Enter the index of the message you wish to delete or (A)ll to empty the inbox. [0-{}'.format(numMessages - 1)).lower()
 
                 if msgNum in ['a', 'all']:
                     break
                 elif int(msgNum) >= numMessages:
-                    print '\n     Invalid Message Number.\n'
+                    print '\n     Invalid message index.\n'
                 else:
                     break
 
             uInput = userInput("Are you sure, (Y)es or (N)o?").lower()  # Prevent accidental deletion
 
             if uInput == "y":
                 if msgNum in ['a', 'all']:
                     print ' '
                     for msgNum in range(0, numMessages):  # processes all of the messages in the outbox
                         print '     Deleting message ', msgNum + 1, ' of ', numMessages
-                        delSentMsg(0)
+                        src = delSentMsg(msgNum, outboxMessagesIds[msgNum]['msgid'])
 
                     print '\n     Outbox is empty.'
                     usrPrompt = 1
                 else:
-                    delSentMsg(int(msgNum))
-                print '\n     Notice: Message numbers may have changed.\n'
+                    src = delSentMsg(int(msgNum), outboxMessagesIds[int(msgNum)]['msgid'])
+                print '\n     Notice: Message indexs may have changed.\n'
                 main()
             else:
                 usrPrompt = 1
         else:
             print '\n     Invalid Entry.\n'
@@ -1848,11 +1971,11 @@ def UI(usrInput):
 
 def main():
     """Entrypoint for the CLI app"""
 
     global api
-    global usrPrompt
+    global usrPrompt, cmdstr
 
     if usrPrompt == 0:
         print '\n     ------------------------------'
         print '     | Bitmessage Daemon by .dok  |'
         print '     | Version 0.3.1 for BM 0.6.2 |'
@@ -1864,19 +1987,29 @@ def main():
             print '        WARNING: You are not connected to the Bitmessage client.'
             print '     Either Bitmessage is not running or your settings are incorrect.'
             print '     Use the command "apiTest" or "bmSettings" to resolve this issue.'
             print '     ****************************************************************\n'
 
-        print 'Type (H)elp for a list of commands.'  # Startup message
+        print ''.join([
+            '\nType (H)elp for a list of commands.\nPress enter for cmd: [',
+            cmdstr,
+            ']',
+            ]) # Startup message
         usrPrompt = 2
 
     elif usrPrompt == 1:
-        print '\nType (H)elp for a list of commands.'  # Startup message
+        print ''.join([
+            '\nType (H)elp for a list of commands.\nPress enter for cmd: [',
+            cmdstr,
+            ']',
+            ]) # Startup message
         usrPrompt = 2
 
     try:
-        UI((raw_input('>').lower()).replace(" ", ""))
+        cmdInput = (raw_input('>').lower()).replace(" ", "")
+        if cmdInput != '': cmdstr = cmdInput
+        UI(cmdstr)
     except EOFError:
         UI("quit")
 
 
 if __name__ == "__main__":
Sorry for confused @coffeedogs Every one like GUI, except me... It's sad. I made more changes on `src/bitmessagecli.py`, can you help to review and pull it? These changes seems functionable, but for coder maybe it's too ugly. As you can see but a new guy's trying. * Modifications: + Try save user's input on steps and replay(stack method works suck). * Add some input checking avoid error raise. * Update mail with attachment nowadays usage. * Original mail or header attached on `Fw:` and `Re:`, and multi-line mail allowed now. * Delete mails not simply follow by received order(pretty not sure if can use `ackData` in this way). ```patch old mode 100644 new mode 100755 @@ -30,28 +30,57 @@ api = '' keysName = 'keys.dat' keysPath = 'keys.dat' usrPrompt = 0 # 0 = First Start, 1 = prompt, 2 = no prompt if the program is starting up knownAddresses = dict() +import inspect +cmdstr='help' +inputs={} def userInput(message): """Checks input for exit or quit. Also formats for input, etc""" - global usrPrompt - - print '\n' + message + global usrPrompt, cmdstr + + stack = list(inspect.stack()) + where = '' + #for item in stack: + #print item + where = ''.join([ + str(stack[3][2]), + stack[3][3], + str(stack[2][2]), + stack[1][3], + str(stack[1][2]), + stack[3][3], + cmdstr + ]) + last = '' if where not in inputs.keys() else inputs[where] + print ''.join([ +# '\n', +# where, + '\n', + message, + '\nPress enter for input: [', + last, + ']', + ]) uInput = raw_input('> ') if uInput.lower() == 'exit': # Returns the user to the main menu usrPrompt = 1 main() elif uInput.lower() == 'quit': # Quits the program print '\n Bye\n' sys.exit(0) + elif uInput == '': # Return last value. + return last + else: + inputs[where] = uInput return uInput def restartBmNotify(): """Prompt the user to restart Bitmessage""" @@ -247,14 +276,15 @@ def apiData(): apiPort = int(BMConfigParser().get('bitmessagesettings', 'apiport')) apiInterface = BMConfigParser().get('bitmessagesettings', 'apiinterface') apiUsername = BMConfigParser().get('bitmessagesettings', 'apiusername') apiPassword = BMConfigParser().get('bitmessagesettings', 'apipassword') - print '\n API data successfully imported.\n' + ret = "http://" + apiUsername + ":" + apiPassword + "@" + apiInterface + ":" + str(apiPort) + "/" + print '\n API data successfully imported.\n ' + ret # Build the api credentials - return "http://" + apiUsername + ":" + apiPassword + "@" + apiInterface + ":" + str(apiPort) + "/" + return ret # End keys.dat interactions @@ -556,11 +586,11 @@ def listAdd(): except: print '\n Connection Error\n' usrPrompt = 0 main() - # print '\nAddress Number,Label,Address,Stream,Enabled\n' + # print '\nAddress Index,Label,Address,Stream,Enabled\n' print '\n --------------------------------------------------------------------------' print ' | # | Label | Address |S#|Enabled|' print ' |---|-------------------|-------------------------------------|--|-------|' for addNum in range(0, numAddresses): # processes all of the addresses and lists them out label = (jsonAddresses['addresses'][addNum]['label']).encode( @@ -570,29 +600,29 @@ def listAdd(): enabled = str(jsonAddresses['addresses'][addNum]['enabled']) if len(label) > 19: label = label[:16] + '...' - print ''.join( + print ''.join([ ' |', str(addNum).ljust(3), '|', label.ljust(19), '|', address.ljust(37), '|', - stream.ljust(1), + stream.ljust(2), '|', enabled.ljust(7), '|', - ) + ]) - print ''.join( + print ''.join([ ' ', 74 * '-', '\n', - ) + ]) def genAdd(lbl, deterministic, passphrase, numOfAdd, addVNum, streamNum, ripe): """Generate address""" @@ -673,15 +703,15 @@ def attachment(): invSize = os.path.getsize(filePath) invSize = (invSize / 1024) # Converts to kilobytes round(invSize, 2) # Rounds to two decimal places if invSize > 500.0: # If over 500KB - print ''.join( + print ''.join([ '\n WARNING:The file that you are trying to attach is ', invSize, 'KB and will take considerable time to send.\n' - ) + ]) uInput = userInput('Are you sure you still want to attach it, (Y)es or (N)o?').lower() if uInput != "y": print '\n Attachment discarded.\n' return '' @@ -719,11 +749,11 @@ Filename:%s Filesize:%sKB Encoding:base64 <center> <div id="image"> - <img alt = "%s" src='data:image/%s;base64, %s' /> + <img alt = "%s" src="data:image/%s;base64, %s"/> </div> </center>""" % (fileName, invSize, fileName, filetype, data) else: # Else it is not an image so do not include the embedded image code. theAttachment = """ <!-- Note: File attachment below. Please use a base64 decoder, or Daemon, to save it. --> @@ -731,11 +761,11 @@ Encoding:base64 Filename:%s Filesize:%sKB Encoding:base64 -<attachment alt = "%s" src='data:file/%s;base64, %s' />""" % (fileName, invSize, fileName, fileName, data) +<attachment alt = "%s" src="data:file/%s;base64, %s"/>""" % (fileName, invSize, fileName, fileName, data) uInput = userInput('Would you like to add another attachment, (Y)es or (N)o?').lower() if uInput == 'y' or uInput == 'yes': # Allows multiple attachments to be added to one message theAttachmentS = str(theAttachmentS) + str(theAttachment) + '\n\n' @@ -815,12 +845,23 @@ def sendMsg(toAddress, fromAddress, subject, message): fromAddress = jsonAddresses['addresses'][0]['address'] if subject == '': subject = userInput("Enter your Subject.") subject = subject.encode('base64') + elif subject == 'c': + usrPrompt = 1 + print ' ' + main() if message == '': - message = userInput("Enter your Message.") + while True: + try: + message += ''.join([ + '\n', + userInput("Continue enter your Message line by line, end with <CTL-D>."), + ]) + except EOFError: + break uInput = userInput('Would you like to add an attachment, (Y)es or (N)o?').lower() if uInput == "y": message = message + '\n\n' + attachment() @@ -889,11 +930,18 @@ def sendBrd(fromAddress, subject, message): if subject == '': subject = userInput("Enter your Subject.") subject = subject.encode('base64') if message == '': - message = userInput("Enter your Message.") + while True: + try: + message += ''.join([ + '\n', + userInput("Continue enter your Message line by line, end with <CTL-D>."), + ]) + except EOFError: + break uInput = userInput('Would you like to add an attachment, (Y)es or (N)o?').lower() if uInput == "y": message = message + '\n\n' + attachment() @@ -907,11 +955,11 @@ def sendBrd(fromAddress, subject, message): usrPrompt = 0 main() def inbox(unreadOnly=False): - """Lists the messages by: Message Number, To Address Label, From Address Label, Subject, Received Time)""" + """Lists the messages by: message index, To Address Label, From Address Label, Subject, Received Time)""" global usrPrompt try: inboxMessages = json.loads(api.getAllInboxMessages()) numMessages = len(inboxMessages['inboxMessages']) @@ -925,19 +973,21 @@ def inbox(unreadOnly=False): for msgNum in range(0, numMessages): # processes all of the messages in the inbox message = inboxMessages['inboxMessages'][msgNum] # if we are displaying all messages or if this message is unread then display it if not unreadOnly or not message['read']: print ' -----------------------------------\n' - print ' Message Number:', msgNum # Message Number + print ' Message index:{}/{}'.format(msgNum, numMessages - 1) # message index + print ' Message ID:', inboxMessages['inboxMessages'][msgNum]['msgid'] + print ' Read:', inboxMessages['inboxMessages'][msgNum]['read'] print ' To:', getLabelForAddress(message['toAddress']) # Get the to address print ' From:', getLabelForAddress(message['fromAddress']) # Get the from address print ' Subject:', message['subject'].decode('base64') # Get the subject - print ''.join( + print ''.join([ ' Received:', datetime.datetime.fromtimestamp( float(message['receivedTime'])).strftime('%Y-%m-%d %H:%M:%S'), - ) + ]) messagesPrinted += 1 if not message['read']: messagesUnread += 1 if messagesPrinted % 20 == 0 and messagesPrinted != 0: @@ -960,23 +1010,24 @@ def outbox(): usrPrompt = 0 main() for msgNum in range(0, numMessages): # processes all of the messages in the outbox print '\n -----------------------------------\n' - print ' Message Number:', msgNum # Message Number - # print ' Message ID:', outboxMessages['sentMessages'][msgNum]['msgid'] + print ' Message index:{}/{}'.format(msgNum, numMessages - 1) # message index + print ' Message ID:', outboxMessages['sentMessages'][msgNum]['msgid'] print ' To:', getLabelForAddress(outboxMessages['sentMessages'][msgNum]['toAddress']) # Get the to address # Get the from address print ' From:', getLabelForAddress(outboxMessages['sentMessages'][msgNum]['fromAddress']) print ' Subject:', outboxMessages['sentMessages'][msgNum]['subject'].decode('base64') # Get the subject - print ' Status:', outboxMessages['sentMessages'][msgNum]['status'] # Get the subject + print ' Status:', outboxMessages['sentMessages'][msgNum]['status'] # Get the status + print ' Ack:', outboxMessages['sentMessages'][msgNum]['ackData'] # Get the ackData - print ''.join( + print ''.join([ ' Last Action Time:', datetime.datetime.fromtimestamp( float(outboxMessages['sentMessages'][msgNum]['lastActionTime'])).strftime('%Y-%m-%d %H:%M:%S'), - ) + ]) if msgNum % 20 == 0 and msgNum != 0: userInput('(Press Enter to continue or type (Exit) to return to the main menu.)').lower() # uInput = print '\n -----------------------------------' @@ -997,20 +1048,20 @@ def readSentMsg(msgNum): main() print ' ' if msgNum >= numMessages: - print '\n Invalid Message Number.\n' + print '\n Invalid message index.\n' main() # Begin attachment detection message = outboxMessages['sentMessages'][msgNum]['message'].decode('base64') while True: # Allows multiple messages to be downloaded/saved if ';base64,' in message: # Found this text in the message, there is probably an attachment. attPos = message.index(";base64,") # Finds the attachment position - attEndPos = message.index("' />") # Finds the end of the attachment + attEndPos = message.index('/>') # Finds the end of the attachment # attLen = attEndPos - attPos #Finds the length of the message if 'alt = "' in message: # We can get the filename too fnPos = message.index('alt = "') # Finds position of the filename fnEndPos = message.index('" src=') # Finds the end position @@ -1032,24 +1083,28 @@ def readSentMsg(msgNum): else: break # End attachment Detection - - print '\n To:', getLabelForAddress(outboxMessages['sentMessages'][msgNum]['toAddress']) # Get the to address + print '\n Message index:{}/{}'.format(msgNum, numMessages - 1) # message outdex + print ' Message ID:', outboxMessages['sentMessages'][msgNum]['msgid'] + print ' To:', getLabelForAddress(outboxMessages['sentMessages'][msgNum]['toAddress']) # Get the to address # Get the from address print ' From:', getLabelForAddress(outboxMessages['sentMessages'][msgNum]['fromAddress']) print ' Subject:', outboxMessages['sentMessages'][msgNum]['subject'].decode('base64') # Get the subject - print ' Status:', outboxMessages['sentMessages'][msgNum]['status'] # Get the subject - print ''.join( + print ' Status:', outboxMessages['sentMessages'][msgNum]['status'] # Get the status + print ' Ack:', outboxMessages['sentMessages'][msgNum]['ackData'] # Get the ackData + + print ''.join([ ' Last Action Time:', datetime.datetime.fromtimestamp( float(outboxMessages['sentMessages'][msgNum]['lastActionTime'])).strftime('%Y-%m-%d %H:%M:%S'), - ) + ]) print ' Message:\n' print message # inboxMessages['inboxMessages'][msgNum]['message'].decode('base64') print ' ' + return outboxMessages['sentMessages'][msgNum]['msgid'] def readMsg(msgNum): """Open a message for reading""" global usrPrompt @@ -1060,20 +1115,20 @@ def readMsg(msgNum): print '\n Connection Error\n' usrPrompt = 0 main() if msgNum >= numMessages: - print '\n Invalid Message Number.\n' + print '\n Invalid message index.\n' main() # Begin attachment detection message = inboxMessages['inboxMessages'][msgNum]['message'].decode('base64') while True: # Allows multiple messages to be downloaded/saved if ';base64,' in message: # Found this text in the message, there is probably an attachment. attPos = message.index(";base64,") # Finds the attachment position - attEndPos = message.index("' />") # Finds the end of the attachment + attEndPos = message.index('/>') # Finds the end of the attachment # attLen = attEndPos - attPos #Finds the length of the message if 'alt = "' in message: # We can get the filename too fnPos = message.index('alt = "') # Finds position of the filename fnEndPos = message.index('" src=') # Finds the end position @@ -1095,44 +1150,47 @@ def readMsg(msgNum): else: break # End attachment Detection - print '\n To:', getLabelForAddress(inboxMessages['inboxMessages'][msgNum]['toAddress']) # Get the to address + print '\n Message index:{}/{}'.format(msgNum, numMessages - 1) # message index + print ' Message ID:', inboxMessages['inboxMessages'][msgNum]['msgid'] + print ' To:', getLabelForAddress(inboxMessages['inboxMessages'][msgNum]['toAddress']) # Get the to address # Get the from address print ' From:', getLabelForAddress(inboxMessages['inboxMessages'][msgNum]['fromAddress']) print ' Subject:', inboxMessages['inboxMessages'][msgNum]['subject'].decode('base64') # Get the subject - print ''.join( + print ''.join([ ' Received:', datetime.datetime.fromtimestamp( float(inboxMessages['inboxMessages'][msgNum]['receivedTime'])).strftime('%Y-%m-%d %H:%M:%S'), - ) + ]) print ' Message:\n' print message # inboxMessages['inboxMessages'][msgNum]['message'].decode('base64') print ' ' return inboxMessages['inboxMessages'][msgNum]['msgid'] -def replyMsg(msgNum, forwardORreply): +def replyMsg(messageID, forwardORreply): """Allows you to reply to the message you are currently on. Saves typing in the addresses and subject.""" global usrPrompt forwardORreply = forwardORreply.lower() # makes it lowercase try: - inboxMessages = json.loads(api.getAllInboxMessages()) + inboxMessage = json.loads(api.getInboxMessageById(messageID))['inboxMessage'] except: print '\n Connection Error\n' usrPrompt = 0 main() - fromAdd = inboxMessages['inboxMessages'][msgNum]['toAddress'] # Address it was sent To, now the From address - message = inboxMessages['inboxMessages'][msgNum]['message'].decode('base64') # Message that you are replying too. + fromAdd = inboxMessage[0]['toAddress'] # Address it was sent To, now the From address + fwdFrom = inboxMessage[0]['fromAddress'] # Address it was sent To, will attached to fwd + message = inboxMessage[0]['message'].decode('base64') # Message that you are replying too. - subject = inboxMessages['inboxMessages'][msgNum]['subject'] + subject = inboxMessage[0]['subject'] subject = subject.decode('base64') if forwardORreply == 'reply': - toAdd = inboxMessages['inboxMessages'][msgNum]['fromAddress'] # Address it was From, now the To address + toAdd = inboxMessage[0]['fromAddress'] # Address it was From, now the To address subject = "Re: " + subject elif forwardORreply == 'forward': subject = "Fwd: " + subject @@ -1152,59 +1210,73 @@ def replyMsg(msgNum, forwardORreply): usrPrompt = 0 main() subject = subject.encode('base64') - newMessage = userInput("Enter your Message.") + while True: + try: + newMessage = ''.join([ + '\n', + userInput("Continue enter your Message line by line, end with <CTL-D>."), + ]) + except EOFError: + break uInput = userInput('Would you like to add an attachment, (Y)es or (N)o?').lower() if uInput == "y": newMessage = newMessage + '\n\n' + attachment() newMessage = newMessage + '\n\n------------------------------------------------------\n' - newMessage = newMessage + message + attachMessage = '' + if forwardORreply == 'forward': + attachMessage = ''.join([ + '>>To: ', fwdFrom, + '\n>>From: ', fromAdd, + '\n>>Subject: ', subject , + '\n>>Message: ', + ]) + for line in message.splitlines(): + attachMessage = attachMessage + '>' + line + '\n' + newMessage = newMessage + attachMessage newMessage = newMessage.encode('base64') sendMsg(toAdd, fromAdd, subject, newMessage) main() -def delMsg(msgNum): +def delMsg(messageID): """Deletes a specified message from the inbox""" global usrPrompt try: - inboxMessages = json.loads(api.getAllInboxMessages()) - # gets the message ID via the message index number - msgId = inboxMessages['inboxMessages'][int(msgNum)]['msgid'] - - msgAck = api.trashMessage(msgId) + msgAck = api.trashMessage(messageID) + return msgAck except: print '\n Connection Error\n' usrPrompt = 0 main() - return msgAck - -def delSentMsg(msgNum): +def delSentMsg(msgNum, messageID=''): """Deletes a specified message from the outbox""" global usrPrompt try: - outboxMessages = json.loads(api.getAllSentMessages()) - # gets the message ID via the message index number - msgId = outboxMessages['sentMessages'][int(msgNum)]['msgid'] - msgAck = api.trashSentMessage(msgId) + if messageID == '': + outboxMessages = json.loads(api.getAllSentMessages())['sentMessages'] + # gets the message actData via the message index number + ackData = outboxMessages[msgNum]['ackData'] + msgAck = api.trashSentMessageByAckData(ackData) + else: + msgAck = api.trashSentMessage(messageID) + return msgAck except: print '\n Connection Error\n' usrPrompt = 0 main() - return msgAck - def getLabelForAddress(address): """Get label for an address""" if address in knownAddresses: @@ -1328,10 +1400,13 @@ def markMessageRead(messageID): try: response = api.getInboxMessageByID(messageID, True) if "API Error" in response: return getAPIErrorCode(response) + print '\n TODO: need mark readMessage() API.\n' + #msgAck = api.readMessage(msgId) + #return msgAck except: print '\n Connection Error\n' usrPrompt = 0 main() @@ -1343,46 +1418,46 @@ def markMessageUnread(messageID): try: response = api.getInboxMessageByID(messageID, False) if "API Error" in response: return getAPIErrorCode(response) + print '\n TODO: need mark unReadMessage() API.\n' + #msgAck = api.unReadMessage(msgId) + #return msgAck except: print '\n Connection Error\n' usrPrompt = 0 main() - def markAllMessagesRead(): """Mark all messages as read""" global usrPrompt try: - inboxMessages = json.loads(api.getAllInboxMessages())['inboxMessages'] + inboxMessagesIds = json.loads(api.getAllInboxMessageIDs())['inboxMessageIds'] except: print '\n Connection Error\n' usrPrompt = 0 main() - for message in inboxMessages: - if not message['read']: - markMessageRead(message['msgid']) + for messageID in inboxMessagesIds: + markMessageRead(messageID) def markAllMessagesUnread(): """Mark all messages as unread""" global usrPrompt try: - inboxMessages = json.loads(api.getAllInboxMessages())['inboxMessages'] + inboxMessagesIds = json.loads(api.getAllInboxMessageIDs())['inboxMessageIds'] except: print '\n Connection Error\n' usrPrompt = 0 main() - for message in inboxMessages: - if message['read']: - markMessageUnread(message['msgid']) + for messageID in inboxMessagesIds: + markMessageUnread(messageID) def clientStatus(): """Print the client status""" @@ -1605,61 +1680,75 @@ def UI(usrInput): if (uInput != 'i' and uInput != 'inbox' and uInput != 'o' and uInput != 'outbox'): print '\n Invalid Input.\n' usrPrompt = 1 main() - msgNum = int(userInput("What is the number of the message you wish to open?")) + while True: + cinput = userInput("What is the index of the message you wish to open??") + try: + if cinput in ['c']: + cinput = -1 + break + elif int(cinput) < 0: + print '\n Invalid message index.\n' + else: + break + except: + print '\n Invalid input. "c" to cancel"\n' + if cinput < 0: + usrPrompt = 1 + main() + + msgNum = int(cinput) if (uInput == 'i' or uInput == 'inbox'): print '\n Loading...\n' messageID = readMsg(msgNum) uInput = userInput("\nWould you like to keep this message unread, (Y)es or (N)o?").lower() if not (uInput == 'y' or uInput == 'yes'): - markMessageRead(messageID) + src = markMessageRead(messageID) usrPrompt = 1 uInput = userInput("\nWould you like to (D)elete, (F)orward, (R)eply to, or (Exit) this message?").lower() if uInput in ['r', 'reply']: print '\n Loading...\n' print ' ' - replyMsg(msgNum, 'reply') + src = replyMsg(messageID, 'reply') usrPrompt = 1 elif uInput == 'f' or uInput == 'forward': print '\n Loading...\n' print ' ' - replyMsg(msgNum, 'forward') + src = replyMsg(messageID, 'forward') usrPrompt = 1 elif uInput in ["d", 'delete']: uInput = userInput("Are you sure, (Y)es or (N)o?").lower() # Prevent accidental deletion if uInput == "y": - delMsg(msgNum) - print '\n Message Deleted.\n' + src = delMsg(messageID) usrPrompt = 1 else: usrPrompt = 1 else: print '\n Invalid entry\n' usrPrompt = 1 elif (uInput == 'o' or uInput == 'outbox'): - readSentMsg(msgNum) + messageID = readSentMsg(msgNum) # Gives the user the option to delete the message uInput = userInput("Would you like to (D)elete, or (Exit) this message?").lower() if (uInput == "d" or uInput == 'delete'): uInput = userInput('Are you sure, (Y)es or (N)o?').lower() # Prevent accidental deletion if uInput == "y": - delSentMsg(msgNum) - print '\n Message Deleted.\n' + src = delSentMsg(msgNum, messageID) usrPrompt = 1 else: usrPrompt = 1 else: print '\n Invalid Entry\n' @@ -1677,35 +1766,61 @@ def UI(usrInput): main() if uInput in ['i', 'inbox']: inboxMessages = json.loads(api.getAllInboxMessages()) numMessages = len(inboxMessages['inboxMessages']) + if numMessages < 1: + print '\n Zero message in inbox.\n' + usrPrompt = 1 + main() while True: - msgNum = int(userInput("What is the number of the message you wish to save?")) - - if msgNum >= numMessages: - print '\n Invalid Message Number.\n' - else: - break + cinput = userInput("What is the index of the message you wish to save[0-{}]?".format(numMessages - 1)) + try: + if cinput in ['c']: + cinput = -1 + break + elif int(cinput) >= numMessages: + print '\n Invalid message index.\n' + else: + break + except: + print '\n Invalid input. "c" to cancel"\n' + if cinput < 0: + usrPrompt = 1 + main() + msgNum = int(cinput) subject = inboxMessages['inboxMessages'][msgNum]['subject'].decode('base64') # Don't decode since it is done in the saveFile function message = inboxMessages['inboxMessages'][msgNum]['message'] elif uInput == 'o' or uInput == 'outbox': outboxMessages = json.loads(api.getAllSentMessages()) numMessages = len(outboxMessages['sentMessages']) + if numMessages < 1: + print '\n Zero message in outbox.\n' + usrPrompt = 1 + main() while True: - msgNum = int(userInput("What is the number of the message you wish to save?")) - - if msgNum >= numMessages: - print '\n Invalid Message Number.\n' - else: - break + cinput = userInput("What is the index of the message you wish to save[0-{}]?".format(numMessages - 1)) + try: + if cinput in ['c']: + cinput = - 1 + break + elif int(cinput) >= numMessages: + print '\n Invalid message index.\n' + else: + break + except: + print '\n Invalid input. "c" to cancel"\n' + if cinput < 0: + usrPrompt = 1 + main() + msgNum = int(cinput) subject = outboxMessages['sentMessages'][msgNum]['subject'].decode('base64') # Don't decode since it is done in the saveFile function message = outboxMessages['sentMessages'][msgNum]['message'] subject = subject + '.txt' @@ -1717,72 +1832,80 @@ def UI(usrInput): elif usrInput == "delete": # will delete a message from the system, not reflected on the UI. uInput = userInput("Would you like to delete a message from the (I)nbox or (O)utbox?").lower() if uInput in ['i', 'inbox']: - inboxMessages = json.loads(api.getAllInboxMessages()) - numMessages = len(inboxMessages['inboxMessages']) + inboxMessagesIds = json.loads(api.getAllInboxMessageIds())['inboxMessageIds'] + numMessages = len(inboxMessagesIds) + if numMessages < 1: + print '\n Zero message in inbox.\n' + usrPrompt = 1 + main() while True: msgNum = userInput( - 'Enter the number of the message you wish to delete or (A)ll to empty the inbox.').lower() + 'Enter the index of the message you wish to delete or (A)ll to empty the inbox. [0-{}]'.format(numMessages - 1) ).lower() if msgNum == 'a' or msgNum == 'all': break elif int(msgNum) >= numMessages: - print '\n Invalid Message Number.\n' + print '\n Invalid message index.\n' else: break uInput = userInput("Are you sure, (Y)es or (N)o?").lower() # Prevent accidental deletion if uInput == "y": if msgNum in ['a', 'all']: print ' ' for msgNum in range(0, numMessages): # processes all of the messages in the inbox print ' Deleting message ', msgNum + 1, ' of ', numMessages - delMsg(0) + delMsg(inboxMessagesIds[msgNum]['msgid']) print '\n Inbox is empty.' usrPrompt = 1 else: - delMsg(int(msgNum)) + delMsg(inboxMessagesIds[int(msgNum)]['msgid']) - print '\n Notice: Message numbers may have changed.\n' + print '\n Notice: Message indexs may have changed.\n' main() else: usrPrompt = 1 elif uInput in ['o', 'outbox']: - outboxMessages = json.loads(api.getAllSentMessages()) - numMessages = len(outboxMessages['sentMessages']) + outboxMessagesIds = json.loads(api.getAllSentMessageIds())['sentMessageIds'] + numMessages = len(outboxMessagesIds) + if numMessages < 1: + print '\n Zero message in outbox.\n' + usrPrompt = 1 + main() while True: msgNum = userInput( - 'Enter the number of the message you wish to delete or (A)ll to empty the inbox.').lower() + 'Enter the index of the message you wish to delete or (A)ll to empty the inbox. [0-{}'.format(numMessages - 1)).lower() if msgNum in ['a', 'all']: break elif int(msgNum) >= numMessages: - print '\n Invalid Message Number.\n' + print '\n Invalid message index.\n' else: break uInput = userInput("Are you sure, (Y)es or (N)o?").lower() # Prevent accidental deletion if uInput == "y": if msgNum in ['a', 'all']: print ' ' for msgNum in range(0, numMessages): # processes all of the messages in the outbox print ' Deleting message ', msgNum + 1, ' of ', numMessages - delSentMsg(0) + src = delSentMsg(msgNum, outboxMessagesIds[msgNum]['msgid']) print '\n Outbox is empty.' usrPrompt = 1 else: - delSentMsg(int(msgNum)) - print '\n Notice: Message numbers may have changed.\n' + src = delSentMsg(int(msgNum), outboxMessagesIds[int(msgNum)]['msgid']) + print '\n Notice: Message indexs may have changed.\n' main() else: usrPrompt = 1 else: print '\n Invalid Entry.\n' @@ -1848,11 +1971,11 @@ def UI(usrInput): def main(): """Entrypoint for the CLI app""" global api - global usrPrompt + global usrPrompt, cmdstr if usrPrompt == 0: print '\n ------------------------------' print ' | Bitmessage Daemon by .dok |' print ' | Version 0.3.1 for BM 0.6.2 |' @@ -1864,19 +1987,29 @@ def main(): print ' WARNING: You are not connected to the Bitmessage client.' print ' Either Bitmessage is not running or your settings are incorrect.' print ' Use the command "apiTest" or "bmSettings" to resolve this issue.' print ' ****************************************************************\n' - print 'Type (H)elp for a list of commands.' # Startup message + print ''.join([ + '\nType (H)elp for a list of commands.\nPress enter for cmd: [', + cmdstr, + ']', + ]) # Startup message usrPrompt = 2 elif usrPrompt == 1: - print '\nType (H)elp for a list of commands.' # Startup message + print ''.join([ + '\nType (H)elp for a list of commands.\nPress enter for cmd: [', + cmdstr, + ']', + ]) # Startup message usrPrompt = 2 try: - UI((raw_input('>').lower()).replace(" ", "")) + cmdInput = (raw_input('>').lower()).replace(" ", "") + if cmdInput != '': cmdstr = cmdInput + UI(cmdstr) except EOFError: UI("quit") if __name__ == "__main__": ```
This repo is archived. You cannot comment on issues.
No Milestone
No project
No Assignees
1 Participants
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: Bitmessage/PyBitmessage-2024-08-21#1288
No description provided.