bitmessagecli.py.bak
1 #!/usr/bin/python2.7 2 # -*- coding: utf-8 -*- 3 # pylint: disable=too-many-lines,global-statement,too-many-branches,too-many-statements,inconsistent-return-statements 4 # pylint: disable=too-many-nested-blocks,too-many-locals,protected-access,too-many-arguments,too-many-function-args 5 # pylint: disable=no-member 6 """ 7 Created by Adam Melton (.dok) referenceing https://bitmessage.org/wiki/API_Reference for API documentation 8 Distributed under the MIT/X11 software license. See http://www.opensource.org/licenses/mit-license.php. 9 10 This is an example of a daemon client for PyBitmessage 0.6.2, by .dok (Version 0.3.1) , modified 11 12 TODO: fix the following (currently ignored) violations: 13 14 """ 15 16 import datetime 17 import imghdr 18 import json 19 import ntpath 20 import os 21 import socket 22 import sys 23 import time 24 25 from six.moves import input as raw_input 26 from six.moves import xmlrpc_client as xmlrpclib 27 28 from bmconfigparser import config 29 30 31 api = '' 32 keysName = 'keys.dat' 33 keysPath = 'keys.dat' 34 usrPrompt = 0 # 0 = First Start, 1 = prompt, 2 = no prompt if the program is starting up 35 knownAddresses = dict() 36 37 38 def userInput(message): 39 """Checks input for exit or quit. Also formats for input, etc""" 40 41 global usrPrompt 42 43 print('\n' + message) 44 uInput = raw_input('> ') 45 46 if uInput.lower() == 'exit': # Returns the user to the main menu 47 usrPrompt = 1 48 main() 49 50 elif uInput.lower() == 'quit': # Quits the program 51 print('\n Bye\n') 52 sys.exit(0) 53 54 else: 55 return uInput 56 57 58 def restartBmNotify(): 59 """Prompt the user to restart Bitmessage""" 60 print('\n *******************************************************************') 61 print(' WARNING: If Bitmessage is running locally, you must restart it now.') 62 print(' *******************************************************************\n') 63 64 65 # Begin keys.dat interactions 66 67 68 def lookupAppdataFolder(): 69 """gets the appropriate folders for the .dat files depending on the OS. Taken from bitmessagemain.py""" 70 71 APPNAME = "PyBitmessage" 72 if sys.platform == 'darwin': 73 if "HOME" in os.environ: 74 dataFolder = os.path.join(os.environ["HOME"], "Library/Application support/", APPNAME) + '/' 75 else: 76 print( 77 ' Could not find home folder, please report ' 78 'this message and your OS X version to the Daemon Github.') 79 sys.exit(1) 80 81 elif 'win32' in sys.platform or 'win64' in sys.platform: 82 dataFolder = os.path.join(os.environ['APPDATA'], APPNAME) + '\\' 83 else: 84 dataFolder = os.path.expanduser(os.path.join("~", ".config/" + APPNAME + "/")) 85 return dataFolder 86 87 88 def configInit(): 89 """Initialised the configuration""" 90 91 config.add_section('bitmessagesettings') 92 # Sets the bitmessage port to stop the warning about the api not properly 93 # being setup. This is in the event that the keys.dat is in a different 94 # directory or is created locally to connect to a machine remotely. 95 config.set('bitmessagesettings', 'port', '8444') 96 config.set('bitmessagesettings', 'apienabled', 'true') # Sets apienabled to true in keys.dat 97 98 with open(keysName, 'wb') as configfile: 99 config.write(configfile) 100 101 print('\n ' + str(keysName) + ' Initalized in the same directory as daemon.py') 102 print(' You will now need to configure the ' + str(keysName) + ' file.\n') 103 104 105 def apiInit(apiEnabled): 106 """Initialise the API""" 107 108 global usrPrompt 109 config.read(keysPath) 110 111 if apiEnabled is False: # API information there but the api is disabled. 112 uInput = userInput("The API is not enabled. Would you like to do that now, (Y)es or (N)o?").lower() 113 114 if uInput == "y": 115 config.set('bitmessagesettings', 'apienabled', 'true') # Sets apienabled to true in keys.dat 116 with open(keysPath, 'wb') as configfile: 117 config.write(configfile) 118 119 print('Done') 120 restartBmNotify() 121 return True 122 123 elif uInput == "n": 124 print(' \n************************************************************') 125 print(' Daemon will not work when the API is disabled. ') 126 print(' Please refer to the Bitmessage Wiki on how to setup the API.') 127 print(' ************************************************************\n') 128 usrPrompt = 1 129 main() 130 131 else: 132 print('\n Invalid Entry\n') 133 usrPrompt = 1 134 main() 135 136 elif apiEnabled: # API correctly setup 137 # Everything is as it should be 138 return True 139 140 else: # API information was not present. 141 print('\n ' + str(keysPath) + ' not properly configured!\n') 142 uInput = userInput("Would you like to do this now, (Y)es or (N)o?").lower() 143 144 if uInput == "y": # User said yes, initalize the api by writing these values to the keys.dat file 145 print(' ') 146 147 apiUsr = userInput("API Username") 148 apiPwd = userInput("API Password") 149 apiPort = userInput("API Port") 150 apiEnabled = userInput("API Enabled? (True) or (False)").lower() 151 daemon = userInput("Daemon mode Enabled? (True) or (False)").lower() 152 153 if (daemon != 'true' and daemon != 'false'): 154 print('\n Invalid Entry for Daemon.\n') 155 uInput = 1 156 main() 157 158 print(' -----------------------------------\n') 159 160 # sets the bitmessage port to stop the warning about the api not properly 161 # being setup. This is in the event that the keys.dat is in a different 162 # directory or is created locally to connect to a machine remotely. 163 config.set('bitmessagesettings', 'port', '8444') 164 config.set('bitmessagesettings', 'apienabled', 'true') 165 config.set('bitmessagesettings', 'apiport', apiPort) 166 config.set('bitmessagesettings', 'apiinterface', '127.0.0.1') 167 config.set('bitmessagesettings', 'apiusername', apiUsr) 168 config.set('bitmessagesettings', 'apipassword', apiPwd) 169 config.set('bitmessagesettings', 'daemon', daemon) 170 with open(keysPath, 'wb') as configfile: 171 config.write(configfile) 172 173 print('\n Finished configuring the keys.dat file with API information.\n') 174 restartBmNotify() 175 return True 176 177 elif uInput == "n": 178 print('\n ***********************************************************') 179 print(' Please refer to the Bitmessage Wiki on how to setup the API.') 180 print(' ***********************************************************\n') 181 usrPrompt = 1 182 main() 183 else: 184 print(' \nInvalid entry\n') 185 usrPrompt = 1 186 main() 187 188 189 def apiData(): 190 """TBC""" 191 192 global keysName 193 global keysPath 194 global usrPrompt 195 196 config.read(keysPath) # First try to load the config file (the keys.dat file) from the program directory 197 198 try: 199 config.get('bitmessagesettings', 'port') 200 appDataFolder = '' 201 except: # noqa:E722 202 # Could not load the keys.dat file in the program directory. Perhaps it is in the appdata directory. 203 appDataFolder = lookupAppdataFolder() 204 keysPath = appDataFolder + keysPath 205 config.read(keysPath) 206 207 try: 208 config.get('bitmessagesettings', 'port') 209 except: # noqa:E722 210 # keys.dat was not there either, something is wrong. 211 print('\n ******************************************************************') 212 print(' There was a problem trying to access the Bitmessage keys.dat file') 213 print(' or keys.dat is not set up correctly') 214 print(' Make sure that daemon is in the same directory as Bitmessage. ') 215 print(' ******************************************************************\n') 216 217 uInput = userInput("Would you like to create a keys.dat in the local directory, (Y)es or (N)o?").lower() 218 219 if uInput in ("y", "yes"): 220 configInit() 221 keysPath = keysName 222 usrPrompt = 0 223 main() 224 elif uInput in ("n", "no"): 225 print('\n Trying Again.\n') 226 usrPrompt = 0 227 main() 228 else: 229 print('\n Invalid Input.\n') 230 231 usrPrompt = 1 232 main() 233 234 try: # checks to make sure that everyting is configured correctly. Excluding apiEnabled, it is checked after 235 config.get('bitmessagesettings', 'apiport') 236 config.get('bitmessagesettings', 'apiinterface') 237 config.get('bitmessagesettings', 'apiusername') 238 config.get('bitmessagesettings', 'apipassword') 239 240 except: # noqa:E722 241 apiInit("") # Initalize the keys.dat file with API information 242 243 # keys.dat file was found or appropriately configured, allow information retrieval 244 # apiEnabled = 245 # apiInit(config.safeGetBoolean('bitmessagesettings','apienabled')) 246 # #if false it will prompt the user, if true it will return true 247 248 config.read(keysPath) # read again since changes have been made 249 apiPort = int(config.get('bitmessagesettings', 'apiport')) 250 apiInterface = config.get('bitmessagesettings', 'apiinterface') 251 apiUsername = config.get('bitmessagesettings', 'apiusername') 252 apiPassword = config.get('bitmessagesettings', 'apipassword') 253 254 print('\n API data successfully imported.\n') 255 256 # Build the api credentials 257 return "http://" + apiUsername + ":" + apiPassword + "@" + apiInterface + ":" + str(apiPort) + "/" 258 259 260 # End keys.dat interactions 261 262 263 def apiTest(): 264 """Tests the API connection to bitmessage. Returns true if it is connected.""" 265 266 try: 267 result = api.add(2, 3) 268 except: # noqa:E722 269 return False 270 271 return result == 5 272 273 274 def bmSettings(): 275 """Allows the viewing and modification of keys.dat settings.""" 276 277 global keysPath 278 global usrPrompt 279 280 keysPath = 'keys.dat' 281 282 config.read(keysPath) # Read the keys.dat 283 try: 284 port = config.get('bitmessagesettings', 'port') 285 except: # noqa:E722 286 print('\n File not found.\n') 287 usrPrompt = 0 288 main() 289 290 startonlogon = config.safeGetBoolean('bitmessagesettings', 'startonlogon') 291 minimizetotray = config.safeGetBoolean('bitmessagesettings', 'minimizetotray') 292 showtraynotifications = config.safeGetBoolean('bitmessagesettings', 'showtraynotifications') 293 startintray = config.safeGetBoolean('bitmessagesettings', 'startintray') 294 defaultnoncetrialsperbyte = config.get('bitmessagesettings', 'defaultnoncetrialsperbyte') 295 defaultpayloadlengthextrabytes = config.get('bitmessagesettings', 'defaultpayloadlengthextrabytes') 296 daemon = config.safeGetBoolean('bitmessagesettings', 'daemon') 297 298 socksproxytype = config.get('bitmessagesettings', 'socksproxytype') 299 sockshostname = config.get('bitmessagesettings', 'sockshostname') 300 socksport = config.get('bitmessagesettings', 'socksport') 301 socksauthentication = config.safeGetBoolean('bitmessagesettings', 'socksauthentication') 302 socksusername = config.get('bitmessagesettings', 'socksusername') 303 sockspassword = config.get('bitmessagesettings', 'sockspassword') 304 305 print('\n -----------------------------------') 306 print(' | Current Bitmessage Settings |') 307 print(' -----------------------------------') 308 print(' port = ' + port) 309 print(' startonlogon = ' + str(startonlogon)) 310 print(' minimizetotray = ' + str(minimizetotray)) 311 print(' showtraynotifications = ' + str(showtraynotifications)) 312 print(' startintray = ' + str(startintray)) 313 print(' defaultnoncetrialsperbyte = ' + defaultnoncetrialsperbyte) 314 print(' defaultpayloadlengthextrabytes = ' + defaultpayloadlengthextrabytes) 315 print(' daemon = ' + str(daemon)) 316 print('\n ------------------------------------') 317 print(' | Current Connection Settings |') 318 print(' -----------------------------------') 319 print(' socksproxytype = ' + socksproxytype) 320 print(' sockshostname = ' + sockshostname) 321 print(' socksport = ' + socksport) 322 print(' socksauthentication = ' + str(socksauthentication)) 323 print(' socksusername = ' + socksusername) 324 print(' sockspassword = ' + sockspassword) 325 print(' ') 326 327 uInput = userInput("Would you like to modify any of these settings, (Y)es or (N)o?").lower() 328 329 if uInput == "y": 330 while True: # loops if they mistype the setting name, they can exit the loop with 'exit' 331 invalidInput = False 332 uInput = userInput("What setting would you like to modify?").lower() 333 print(' ') 334 335 if uInput == "port": 336 print(' Current port number: ' + port) 337 uInput = userInput("Enter the new port number.") 338 config.set('bitmessagesettings', 'port', str(uInput)) 339 elif uInput == "startonlogon": 340 print(' Current status: ' + str(startonlogon)) 341 uInput = userInput("Enter the new status.") 342 config.set('bitmessagesettings', 'startonlogon', str(uInput)) 343 elif uInput == "minimizetotray": 344 print(' Current status: ' + str(minimizetotray)) 345 uInput = userInput("Enter the new status.") 346 config.set('bitmessagesettings', 'minimizetotray', str(uInput)) 347 elif uInput == "showtraynotifications": 348 print(' Current status: ' + str(showtraynotifications)) 349 uInput = userInput("Enter the new status.") 350 config.set('bitmessagesettings', 'showtraynotifications', str(uInput)) 351 elif uInput == "startintray": 352 print(' Current status: ' + str(startintray)) 353 uInput = userInput("Enter the new status.") 354 config.set('bitmessagesettings', 'startintray', str(uInput)) 355 elif uInput == "defaultnoncetrialsperbyte": 356 print(' Current default nonce trials per byte: ' + defaultnoncetrialsperbyte) 357 uInput = userInput("Enter the new defaultnoncetrialsperbyte.") 358 config.set('bitmessagesettings', 'defaultnoncetrialsperbyte', str(uInput)) 359 elif uInput == "defaultpayloadlengthextrabytes": 360 print(' Current default payload length extra bytes: ' + defaultpayloadlengthextrabytes) 361 uInput = userInput("Enter the new defaultpayloadlengthextrabytes.") 362 config.set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str(uInput)) 363 elif uInput == "daemon": 364 print(' Current status: ' + str(daemon)) 365 uInput = userInput("Enter the new status.").lower() 366 config.set('bitmessagesettings', 'daemon', str(uInput)) 367 elif uInput == "socksproxytype": 368 print(' Current socks proxy type: ' + socksproxytype) 369 print("Possibilities: 'none', 'SOCKS4a', 'SOCKS5'.") 370 uInput = userInput("Enter the new socksproxytype.") 371 config.set('bitmessagesettings', 'socksproxytype', str(uInput)) 372 elif uInput == "sockshostname": 373 print(' Current socks host name: ' + sockshostname) 374 uInput = userInput("Enter the new sockshostname.") 375 config.set('bitmessagesettings', 'sockshostname', str(uInput)) 376 elif uInput == "socksport": 377 print(' Current socks port number: ' + socksport) 378 uInput = userInput("Enter the new socksport.") 379 config.set('bitmessagesettings', 'socksport', str(uInput)) 380 elif uInput == "socksauthentication": 381 print(' Current status: ' + str(socksauthentication)) 382 uInput = userInput("Enter the new status.") 383 config.set('bitmessagesettings', 'socksauthentication', str(uInput)) 384 elif uInput == "socksusername": 385 print(' Current socks username: ' + socksusername) 386 uInput = userInput("Enter the new socksusername.") 387 config.set('bitmessagesettings', 'socksusername', str(uInput)) 388 elif uInput == "sockspassword": 389 print(' Current socks password: ' + sockspassword) 390 uInput = userInput("Enter the new password.") 391 config.set('bitmessagesettings', 'sockspassword', str(uInput)) 392 else: 393 print("\n Invalid input. Please try again.\n") 394 invalidInput = True 395 396 if invalidInput is not True: # don't prompt if they made a mistake. 397 uInput = userInput("Would you like to change another setting, (Y)es or (N)o?").lower() 398 399 if uInput != "y": 400 print('\n Changes Made.\n') 401 with open(keysPath, 'wb') as configfile: 402 config.write(configfile) 403 restartBmNotify() 404 break 405 406 elif uInput == "n": 407 usrPrompt = 1 408 main() 409 else: 410 print("Invalid input.") 411 usrPrompt = 1 412 main() 413 414 415 def validAddress(address): 416 """Predicate to test address validity""" 417 address_information = json.loads(api.decodeAddress(address)) 418 419 return 'success' in str(address_information['status']).lower() 420 421 422 def getAddress(passphrase, vNumber, sNumber): 423 """Get a deterministic address""" 424 passphrase = passphrase.encode('base64') # passphrase must be encoded 425 426 return api.getDeterministicAddress(passphrase, vNumber, sNumber) 427 428 429 def subscribe(): 430 """Subscribe to an address""" 431 global usrPrompt 432 433 while True: 434 address = userInput("What address would you like to subscribe to?") 435 436 if address == "c": 437 usrPrompt = 1 438 print(' ') 439 main() 440 elif validAddress(address) is False: 441 print('\n Invalid. "c" to cancel. Please try again.\n') 442 else: 443 break 444 445 label = userInput("Enter a label for this address.") 446 label = label.encode('base64') 447 448 api.addSubscription(address, label) 449 print('\n You are now subscribed to: ' + address + '\n') 450 451 452 def unsubscribe(): 453 """Unsusbcribe from an address""" 454 global usrPrompt 455 456 while True: 457 address = userInput("What address would you like to unsubscribe from?") 458 459 if address == "c": 460 usrPrompt = 1 461 print(' ') 462 main() 463 elif validAddress(address) is False: 464 print('\n Invalid. "c" to cancel. Please try again.\n') 465 else: 466 break 467 468 userInput("Are you sure, (Y)es or (N)o?").lower() # uInput = 469 470 api.deleteSubscription(address) 471 print('\n You are now unsubscribed from: ' + address + '\n') 472 473 474 def listSubscriptions(): 475 """List subscriptions""" 476 477 global usrPrompt 478 print('\nLabel, Address, Enabled\n') 479 try: 480 print(api.listSubscriptions()) 481 except: # noqa:E722 482 print('\n Connection Error\n') 483 usrPrompt = 0 484 main() 485 print(' ') 486 487 488 def createChan(): 489 """Create a channel""" 490 491 global usrPrompt 492 password = userInput("Enter channel name") 493 password = password.encode('base64') 494 try: 495 print(api.createChan(password)) 496 except: # noqa:E722 497 print('\n Connection Error\n') 498 usrPrompt = 0 499 main() 500 501 502 def joinChan(): 503 """Join a channel""" 504 505 global usrPrompt 506 while True: 507 address = userInput("Enter channel address") 508 509 if address == "c": 510 usrPrompt = 1 511 print(' ') 512 main() 513 elif validAddress(address) is False: 514 print('\n Invalid. "c" to cancel. Please try again.\n') 515 else: 516 break 517 518 password = userInput("Enter channel name") 519 password = password.encode('base64') 520 try: 521 print(api.joinChan(password, address)) 522 except: # noqa:E722 523 print('\n Connection Error\n') 524 usrPrompt = 0 525 main() 526 527 528 def leaveChan(): 529 """Leave a channel""" 530 531 global usrPrompt 532 while True: 533 address = userInput("Enter channel address") 534 535 if address == "c": 536 usrPrompt = 1 537 print(' ') 538 main() 539 elif validAddress(address) is False: 540 print('\n Invalid. "c" to cancel. Please try again.\n') 541 else: 542 break 543 544 try: 545 print(api.leaveChan(address)) 546 except: # noqa:E722 547 print('\n Connection Error\n') 548 usrPrompt = 0 549 main() 550 551 552 def listAdd(): 553 """List all of the addresses and their info""" 554 global usrPrompt 555 try: 556 jsonAddresses = json.loads(api.listAddresses()) 557 numAddresses = len(jsonAddresses['addresses']) # Number of addresses 558 except: # noqa:E722 559 print('\n Connection Error\n') 560 usrPrompt = 0 561 main() 562 563 # print('\nAddress Number,Label,Address,Stream,Enabled\n') 564 print('\n --------------------------------------------------------------------------') 565 print(' | # | Label | Address |S#|Enabled|') 566 print(' |---|-------------------|-------------------------------------|--|-------|') 567 for addNum in range(0, numAddresses): # processes all of the addresses and lists them out 568 label = (jsonAddresses['addresses'][addNum]['label']).encode( 569 'utf') # may still misdiplay in some consoles 570 address = str(jsonAddresses['addresses'][addNum]['address']) 571 stream = str(jsonAddresses['addresses'][addNum]['stream']) 572 enabled = str(jsonAddresses['addresses'][addNum]['enabled']) 573 574 if len(label) > 19: 575 label = label[:16] + '...' 576 577 print(''.join([ 578 ' |', 579 str(addNum).ljust(3), 580 '|', 581 label.ljust(19), 582 '|', 583 address.ljust(37), 584 '|', 585 stream.ljust(1), 586 '|', 587 enabled.ljust(7), 588 '|', 589 ])) 590 591 print(''.join([ 592 ' ', 593 74 * '-', 594 '\n', 595 ])) 596 597 598 def genAdd(lbl, deterministic, passphrase, numOfAdd, addVNum, streamNum, ripe): 599 """Generate address""" 600 601 global usrPrompt 602 603 if deterministic is False: # Generates a new address with the user defined label. non-deterministic 604 addressLabel = lbl.encode('base64') 605 try: 606 generatedAddress = api.createRandomAddress(addressLabel) 607 except: # noqa:E722 608 print('\n Connection Error\n') 609 usrPrompt = 0 610 main() 611 612 return generatedAddress 613 614 elif deterministic: # Generates a new deterministic address with the user inputs. 615 passphrase = passphrase.encode('base64') 616 try: 617 generatedAddress = api.createDeterministicAddresses(passphrase, numOfAdd, addVNum, streamNum, ripe) 618 except: # noqa:E722 619 print('\n Connection Error\n') 620 usrPrompt = 0 621 main() 622 return generatedAddress 623 624 return 'Entry Error' 625 626 627 def saveFile(fileName, fileData): 628 """Allows attachments and messages/broadcats to be saved""" 629 630 # This section finds all invalid characters and replaces them with ~ 631 fileName = fileName.replace(" ", "") 632 fileName = fileName.replace("/", "~") 633 # fileName = fileName.replace("\\", "~") How do I get this to work...? 634 fileName = fileName.replace(":", "~") 635 fileName = fileName.replace("*", "~") 636 fileName = fileName.replace("?", "~") 637 fileName = fileName.replace('"', "~") 638 fileName = fileName.replace("<", "~") 639 fileName = fileName.replace(">", "~") 640 fileName = fileName.replace("|", "~") 641 642 directory = os.path.abspath('attachments') 643 644 if not os.path.exists(directory): 645 os.makedirs(directory) 646 647 filePath = os.path.join(directory, fileName) 648 649 with open(filePath, 'wb+') as path_to_file: 650 path_to_file.write(fileData.decode("base64")) 651 print('\n Successfully saved ' + filePath + '\n') 652 653 654 def attachment(): 655 """Allows users to attach a file to their message or broadcast""" 656 657 theAttachmentS = '' 658 659 while True: 660 661 isImage = False 662 theAttachment = '' 663 664 while True: # loops until valid path is entered 665 filePath = userInput( 666 '\nPlease enter the path to the attachment or just the attachment name if in this folder.') 667 668 try: 669 with open(filePath): 670 break 671 except IOError: 672 print('\n %s was not found on your filesystem or can not be opened.\n' % filePath) 673 674 # print(filesize, and encoding estimate with confirmation if file is over X size(1mb?)) 675 invSize = os.path.getsize(filePath) 676 invSize = (invSize / 1024) # Converts to kilobytes 677 round(invSize, 2) # Rounds to two decimal places 678 679 if invSize > 500.0: # If over 500KB 680 print(''.join([ 681 '\n WARNING:The file that you are trying to attach is ', 682 invSize, 683 'KB and will take considerable time to send.\n' 684 ])) 685 uInput = userInput('Are you sure you still want to attach it, (Y)es or (N)o?').lower() 686 687 if uInput != "y": 688 print('\n Attachment discarded.\n') 689 return '' 690 elif invSize > 184320.0: # If larger than 180MB, discard. 691 print('\n Attachment too big, maximum allowed size:180MB\n') 692 main() 693 694 pathLen = len(str(ntpath.basename(filePath))) # Gets the length of the filepath excluding the filename 695 fileName = filePath[(len(str(filePath)) - pathLen):] # reads the filename 696 697 filetype = imghdr.what(filePath) # Tests if it is an image file 698 if filetype is not None: 699 print('\n ---------------------------------------------------') 700 print(' Attachment detected as an Image.') 701 print(' <img> tags will automatically be included,') 702 print(' allowing the recipient to view the image') 703 print(' using the "View HTML code..." option in Bitmessage.') 704 print(' ---------------------------------------------------\n') 705 isImage = True 706 time.sleep(2) 707 708 # Alert the user that the encoding process may take some time. 709 print('\n Encoding Attachment, Please Wait ...\n') 710 711 with open(filePath, 'rb') as f: # Begin the actual encoding 712 data = f.read(188743680) # Reads files up to 180MB, the maximum size for Bitmessage. 713 data = data.encode("base64") 714 715 if isImage: # If it is an image, include image tags in the message 716 theAttachment = """ 717 <!-- Note: Image attachment below. Please use the right click "View HTML code ..." option to view it. --> 718 <!-- Sent using Bitmessage Daemon. https://github.com/Dokument/PyBitmessage-Daemon --> 719 720 Filename:%s 721 Filesize:%sKB 722 Encoding:base64 723 724 <center> 725 <div id="image"> 726 <img alt = "%s" src='data:image/%s;base64, %s' /> 727 </div> 728 </center>""" % (fileName, invSize, fileName, filetype, data) 729 else: # Else it is not an image so do not include the embedded image code. 730 theAttachment = """ 731 <!-- Note: File attachment below. Please use a base64 decoder, or Daemon, to save it. --> 732 <!-- Sent using Bitmessage Daemon. https://github.com/Dokument/PyBitmessage-Daemon --> 733 734 Filename:%s 735 Filesize:%sKB 736 Encoding:base64 737 738 <attachment alt = "%s" src='data:file/%s;base64, %s' />""" % (fileName, invSize, fileName, fileName, data) 739 740 uInput = userInput('Would you like to add another attachment, (Y)es or (N)o?').lower() 741 742 if uInput in ('y', 'yes'): # Allows multiple attachments to be added to one message 743 theAttachmentS = str(theAttachmentS) + str(theAttachment) + '\n\n' 744 elif uInput in ('n', 'no'): 745 break 746 747 theAttachmentS = theAttachmentS + theAttachment 748 return theAttachmentS 749 750 751 def sendMsg(toAddress, fromAddress, subject, message): 752 """ 753 With no arguments sent, sendMsg fills in the blanks. 754 subject and message must be encoded before they are passed. 755 """ 756 757 global usrPrompt 758 if validAddress(toAddress) is False: 759 while True: 760 toAddress = userInput("What is the To Address?") 761 762 if toAddress == "c": 763 usrPrompt = 1 764 print(' ') 765 main() 766 elif validAddress(toAddress) is False: 767 print('\n Invalid Address. "c" to cancel. Please try again.\n') 768 else: 769 break 770 771 if validAddress(fromAddress) is False: 772 try: 773 jsonAddresses = json.loads(api.listAddresses()) 774 numAddresses = len(jsonAddresses['addresses']) # Number of addresses 775 except: # noqa:E722 776 print('\n Connection Error\n') 777 usrPrompt = 0 778 main() 779 780 if numAddresses > 1: # Ask what address to send from if multiple addresses 781 found = False 782 while True: 783 print(' ') 784 fromAddress = userInput("Enter an Address or Address Label to send from.") 785 786 if fromAddress == "exit": 787 usrPrompt = 1 788 main() 789 790 for addNum in range(0, numAddresses): # processes all of the addresses 791 label = jsonAddresses['addresses'][addNum]['label'] 792 address = jsonAddresses['addresses'][addNum]['address'] 793 if fromAddress == label: # address entered was a label and is found 794 fromAddress = address 795 found = True 796 break 797 798 if found is False: 799 if validAddress(fromAddress) is False: 800 print('\n Invalid Address. Please try again.\n') 801 802 else: 803 for addNum in range(0, numAddresses): # processes all of the addresses 804 address = jsonAddresses['addresses'][addNum]['address'] 805 if fromAddress == address: # address entered was a found in our addressbook. 806 found = True 807 break 808 809 if found is False: 810 print('\n The address entered is not one of yours. Please try again.\n') 811 812 if found: 813 break # Address was found 814 815 else: # Only one address in address book 816 print('\n Using the only address in the addressbook to send from.\n') 817 fromAddress = jsonAddresses['addresses'][0]['address'] 818 819 if not subject: 820 subject = userInput("Enter your Subject.") 821 subject = subject.encode('base64') 822 if not message: 823 message = userInput("Enter your Message.") 824 825 uInput = userInput('Would you like to add an attachment, (Y)es or (N)o?').lower() 826 if uInput == "y": 827 message = message + '\n\n' + attachment() 828 829 message = message.encode('base64') 830 831 try: 832 ackData = api.sendMessage(toAddress, fromAddress, subject, message) 833 print('\n Message Status:', api.getStatus(ackData), '\n') 834 except: # noqa:E722 835 print('\n Connection Error\n') 836 usrPrompt = 0 837 main() 838 839 840 def sendBrd(fromAddress, subject, message): 841 """Send a broadcast""" 842 843 global usrPrompt 844 if not fromAddress: 845 846 try: 847 jsonAddresses = json.loads(api.listAddresses()) 848 numAddresses = len(jsonAddresses['addresses']) # Number of addresses 849 except: # noqa:E722 850 print('\n Connection Error\n') 851 usrPrompt = 0 852 main() 853 854 if numAddresses > 1: # Ask what address to send from if multiple addresses 855 found = False 856 while True: 857 fromAddress = userInput("\nEnter an Address or Address Label to send from.") 858 859 if fromAddress == "exit": 860 usrPrompt = 1 861 main() 862 863 for addNum in range(0, numAddresses): # processes all of the addresses 864 label = jsonAddresses['addresses'][addNum]['label'] 865 address = jsonAddresses['addresses'][addNum]['address'] 866 if fromAddress == label: # address entered was a label and is found 867 fromAddress = address 868 found = True 869 break 870 871 if found is False: 872 if validAddress(fromAddress) is False: 873 print('\n Invalid Address. Please try again.\n') 874 875 else: 876 for addNum in range(0, numAddresses): # processes all of the addresses 877 address = jsonAddresses['addresses'][addNum]['address'] 878 if fromAddress == address: # address entered was a found in our addressbook. 879 found = True 880 break 881 882 if found is False: 883 print('\n The address entered is not one of yours. Please try again.\n') 884 885 if found: 886 break # Address was found 887 888 else: # Only one address in address book 889 print('\n Using the only address in the addressbook to send from.\n') 890 fromAddress = jsonAddresses['addresses'][0]['address'] 891 892 if not subject: 893 subject = userInput("Enter your Subject.") 894 subject = subject.encode('base64') 895 if not message: 896 message = userInput("Enter your Message.") 897 898 uInput = userInput('Would you like to add an attachment, (Y)es or (N)o?').lower() 899 if uInput == "y": 900 message = message + '\n\n' + attachment() 901 902 message = message.encode('base64') 903 904 try: 905 ackData = api.sendBroadcast(fromAddress, subject, message) 906 print('\n Message Status:', api.getStatus(ackData), '\n') 907 except: # noqa:E722 908 print('\n Connection Error\n') 909 usrPrompt = 0 910 main() 911 912 913 def inbox(unreadOnly=False): 914 """Lists the messages by: Message Number, To Address Label, From Address Label, Subject, Received Time)""" 915 916 global usrPrompt 917 try: 918 inboxMessages = json.loads(api.getAllInboxMessages()) 919 numMessages = len(inboxMessages['inboxMessages']) 920 except: # noqa:E722 921 print('\n Connection Error\n') 922 usrPrompt = 0 923 main() 924 925 messagesPrinted = 0 926 messagesUnread = 0 927 for msgNum in range(0, numMessages): # processes all of the messages in the inbox 928 message = inboxMessages['inboxMessages'][msgNum] 929 # if we are displaying all messages or if this message is unread then display it 930 if not unreadOnly or not message['read']: 931 print(' -----------------------------------\n') 932 print(' Message Number:', msgNum) # Message Number) 933 print(' To:', getLabelForAddress(message['toAddress'])) # Get the to address) 934 print(' From:', getLabelForAddress(message['fromAddress'])) # Get the from address) 935 print(' Subject:', message['subject'].decode('base64')) # Get the subject) 936 print(''.join([ 937 ' Received:', 938 datetime.datetime.fromtimestamp( 939 float(message['receivedTime'])).strftime('%Y-%m-%d %H:%M:%S'), 940 ])) 941 messagesPrinted += 1 942 if not message['read']: 943 messagesUnread += 1 944 945 if messagesPrinted % 20 == 0 and messagesPrinted != 0: 946 userInput('(Press Enter to continue or type (Exit) to return to the main menu.)').lower() # uInput = 947 948 print('\n -----------------------------------') 949 print(' There are %d unread messages of %d messages in the inbox.' % (messagesUnread, numMessages)) 950 print(' -----------------------------------\n') 951 952 953 def outbox(): 954 """TBC""" 955 956 global usrPrompt 957 try: 958 outboxMessages = json.loads(api.getAllSentMessages()) 959 numMessages = len(outboxMessages['sentMessages']) 960 except: # noqa:E722 961 print('\n Connection Error\n') 962 usrPrompt = 0 963 main() 964 965 for msgNum in range(0, numMessages): # processes all of the messages in the outbox 966 print('\n -----------------------------------\n') 967 print(' Message Number:', msgNum) # Message Number) 968 # print(' Message ID:', outboxMessages['sentMessages'][msgNum]['msgid']) 969 print(' To:', getLabelForAddress( 970 outboxMessages['sentMessages'][msgNum]['toAddress'] 971 )) # Get the to address) 972 # Get the from address 973 print(' From:', getLabelForAddress(outboxMessages['sentMessages'][msgNum]['fromAddress'])) 974 print(' Subject:', outboxMessages['sentMessages'][msgNum]['subject'].decode('base64')) # Get the subject) 975 print(' Status:', outboxMessages['sentMessages'][msgNum]['status']) # Get the subject) 976 977 # print(''.join([ 978 # ' Last Action Time:', 979 # datetime.datetime.fromtimestamp( 980 # float(outboxMessages['sentMessages'][msgNum]['lastActionTime'])).strftime('%Y-%m-%d %H:%M:%S'), 981 # ])) 982 print(''.join([ 983 ' Last Action Time:', 984 datetime.datetime.fromtimestamp( 985 float(outboxMessages['sentMessages'][msgNum]['lastActionTime'])).strftime('%Y-%m-%d %H:%M:%S'), 986 ])) 987 988 if msgNum % 20 == 0 and msgNum != 0: 989 userInput('(Press Enter to continue or type (Exit) to return to the main menu.)').lower() # uInput = 990 991 print('\n -----------------------------------') 992 print(' There are ', numMessages, ' messages in the outbox.') 993 print(' -----------------------------------\n') 994 995 996 def readSentMsg(msgNum): 997 """Opens a sent message for reading""" 998 999 global usrPrompt 1000 try: 1001 outboxMessages = json.loads(api.getAllSentMessages()) 1002 numMessages = len(outboxMessages['sentMessages']) 1003 except: # noqa:E722 1004 print('\n Connection Error\n') 1005 usrPrompt = 0 1006 main() 1007 1008 print(' ') 1009 1010 if msgNum >= numMessages: 1011 print('\n Invalid Message Number.\n') 1012 main() 1013 1014 # Begin attachment detection 1015 message = outboxMessages['sentMessages'][msgNum]['message'].decode('base64') 1016 1017 while True: # Allows multiple messages to be downloaded/saved 1018 if ';base64,' in message: # Found this text in the message, there is probably an attachment. 1019 attPos = message.index(";base64,") # Finds the attachment position 1020 attEndPos = message.index("' />") # Finds the end of the attachment 1021 # attLen = attEndPos - attPos #Finds the length of the message 1022 1023 if 'alt = "' in message: # We can get the filename too 1024 fnPos = message.index('alt = "') # Finds position of the filename 1025 fnEndPos = message.index('" src=') # Finds the end position 1026 # fnLen = fnEndPos - fnPos #Finds the length of the filename 1027 1028 fileName = message[fnPos + 7:fnEndPos] 1029 else: 1030 fnPos = attPos 1031 fileName = 'Attachment' 1032 1033 uInput = userInput( 1034 '\n Attachment Detected. Would you like to save the attachment, (Y)es or (N)o?').lower() 1035 if uInput in ("y", 'yes'): 1036 1037 this_attachment = message[attPos + 9:attEndPos] 1038 saveFile(fileName, this_attachment) 1039 1040 message = message[:fnPos] + '~<Attachment data removed for easier viewing>~' + message[(attEndPos + 4):] 1041 1042 else: 1043 break 1044 1045 # End attachment Detection 1046 1047 print('\n To:', getLabelForAddress(outboxMessages['sentMessages'][msgNum]['toAddress'])) # Get the to address) 1048 # Get the from address 1049 print(' From:', getLabelForAddress(outboxMessages['sentMessages'][msgNum]['fromAddress'])) 1050 print(' Subject:', outboxMessages['sentMessages'][msgNum]['subject'].decode('base64')) # Get the subject) 1051 print(' Status:', outboxMessages['sentMessages'][msgNum]['status']) # Get the subject) 1052 print(''.join([ 1053 ' Last Action Time:', 1054 datetime.datetime.fromtimestamp( 1055 float(outboxMessages['sentMessages'][msgNum]['lastActionTime'])).strftime('%Y-%m-%d %H:%M:%S'), 1056 ])) 1057 print(' Message:\n') 1058 print(message) # inboxMessages['inboxMessages'][msgNum]['message'].decode('base64')) 1059 print(' ') 1060 1061 1062 def readMsg(msgNum): 1063 """Open a message for reading""" 1064 global usrPrompt 1065 try: 1066 inboxMessages = json.loads(api.getAllInboxMessages()) 1067 numMessages = len(inboxMessages['inboxMessages']) 1068 except: # noqa:E722 1069 print('\n Connection Error\n') 1070 usrPrompt = 0 1071 main() 1072 1073 if msgNum >= numMessages: 1074 print('\n Invalid Message Number.\n') 1075 main() 1076 1077 # Begin attachment detection 1078 message = inboxMessages['inboxMessages'][msgNum]['message'].decode('base64') 1079 1080 while True: # Allows multiple messages to be downloaded/saved 1081 if ';base64,' in message: # Found this text in the message, there is probably an attachment. 1082 attPos = message.index(";base64,") # Finds the attachment position 1083 attEndPos = message.index("' />") # Finds the end of the attachment 1084 # attLen = attEndPos - attPos #Finds the length of the message 1085 1086 if 'alt = "' in message: # We can get the filename too 1087 fnPos = message.index('alt = "') # Finds position of the filename 1088 fnEndPos = message.index('" src=') # Finds the end position 1089 # fnLen = fnEndPos - fnPos #Finds the length of the filename 1090 1091 fileName = message[fnPos + 7:fnEndPos] 1092 else: 1093 fnPos = attPos 1094 fileName = 'Attachment' 1095 1096 uInput = userInput( 1097 '\n Attachment Detected. Would you like to save the attachment, (Y)es or (N)o?').lower() 1098 if uInput in ("y", 'yes'): 1099 1100 this_attachment = message[attPos + 9:attEndPos] 1101 saveFile(fileName, this_attachment) 1102 1103 message = message[:fnPos] + '~<Attachment data removed for easier viewing>~' + message[attEndPos + 4:] 1104 1105 else: 1106 break 1107 1108 # End attachment Detection 1109 print('\n To:', getLabelForAddress(inboxMessages['inboxMessages'][msgNum]['toAddress'])) # Get the to address) 1110 # Get the from address 1111 print(' From:', getLabelForAddress(inboxMessages['inboxMessages'][msgNum]['fromAddress'])) 1112 print(' Subject:', inboxMessages['inboxMessages'][msgNum]['subject'].decode('base64')) # Get the subject) 1113 print(''.join([ 1114 ' Received:', datetime.datetime.fromtimestamp( 1115 float(inboxMessages['inboxMessages'][msgNum]['receivedTime'])).strftime('%Y-%m-%d %H:%M:%S'), 1116 ])) 1117 print(' Message:\n') 1118 print(message) # inboxMessages['inboxMessages'][msgNum]['message'].decode('base64')) 1119 print(' ') 1120 return inboxMessages['inboxMessages'][msgNum]['msgid'] 1121 1122 1123 def replyMsg(msgNum, forwardORreply): 1124 """Allows you to reply to the message you are currently on. Saves typing in the addresses and subject.""" 1125 1126 global usrPrompt 1127 forwardORreply = forwardORreply.lower() # makes it lowercase 1128 try: 1129 inboxMessages = json.loads(api.getAllInboxMessages()) 1130 except: # noqa:E722 1131 print('\n Connection Error\n') 1132 usrPrompt = 0 1133 main() 1134 1135 fromAdd = inboxMessages['inboxMessages'][msgNum]['toAddress'] # Address it was sent To, now the From address 1136 message = inboxMessages['inboxMessages'][msgNum]['message'].decode('base64') # Message that you are replying too. 1137 1138 subject = inboxMessages['inboxMessages'][msgNum]['subject'] 1139 subject = subject.decode('base64') 1140 1141 if forwardORreply == 'reply': 1142 toAdd = inboxMessages['inboxMessages'][msgNum]['fromAddress'] # Address it was From, now the To address 1143 subject = "Re: " + subject 1144 1145 elif forwardORreply == 'forward': 1146 subject = "Fwd: " + subject 1147 1148 while True: 1149 toAdd = userInput("What is the To Address?") 1150 1151 if toAdd == "c": 1152 usrPrompt = 1 1153 print(' ') 1154 main() 1155 elif validAddress(toAdd) is False: 1156 print('\n Invalid Address. "c" to cancel. Please try again.\n') 1157 else: 1158 break 1159 else: 1160 print('\n Invalid Selection. Reply or Forward only') 1161 usrPrompt = 0 1162 main() 1163 1164 subject = subject.encode('base64') 1165 1166 newMessage = userInput("Enter your Message.") 1167 1168 uInput = userInput('Would you like to add an attachment, (Y)es or (N)o?').lower() 1169 if uInput == "y": 1170 newMessage = newMessage + '\n\n' + attachment() 1171 1172 newMessage = newMessage + '\n\n------------------------------------------------------\n' 1173 newMessage = newMessage + message 1174 newMessage = newMessage.encode('base64') 1175 1176 sendMsg(toAdd, fromAdd, subject, newMessage) 1177 1178 main() 1179 1180 1181 def delMsg(msgNum): 1182 """Deletes a specified message from the inbox""" 1183 1184 global usrPrompt 1185 try: 1186 inboxMessages = json.loads(api.getAllInboxMessages()) 1187 # gets the message ID via the message index number 1188 msgId = inboxMessages['inboxMessages'][int(msgNum)]['msgid'] 1189 1190 msgAck = api.trashMessage(msgId) 1191 except: # noqa:E722 1192 print('\n Connection Error\n') 1193 usrPrompt = 0 1194 main() 1195 1196 return msgAck 1197 1198 1199 def delSentMsg(msgNum): 1200 """Deletes a specified message from the outbox""" 1201 1202 global usrPrompt 1203 try: 1204 outboxMessages = json.loads(api.getAllSentMessages()) 1205 # gets the message ID via the message index number 1206 msgId = outboxMessages['sentMessages'][int(msgNum)]['msgid'] 1207 msgAck = api.trashSentMessage(msgId) 1208 except: # noqa:E722 1209 print('\n Connection Error\n') 1210 usrPrompt = 0 1211 main() 1212 1213 return msgAck 1214 1215 1216 def getLabelForAddress(address): 1217 """Get label for an address""" 1218 1219 if address in knownAddresses: 1220 return knownAddresses[address] 1221 else: 1222 buildKnownAddresses() 1223 if address in knownAddresses: 1224 return knownAddresses[address] 1225 1226 return address 1227 1228 1229 def buildKnownAddresses(): 1230 """Build known addresses""" 1231 1232 global usrPrompt 1233 1234 # add from address book 1235 try: 1236 response = api.listAddressBookEntries() 1237 # if api is too old then fail 1238 if "API Error 0020" in response: 1239 return 1240 addressBook = json.loads(response) 1241 for entry in addressBook['addresses']: 1242 if entry['address'] not in knownAddresses: 1243 knownAddresses[entry['address']] = "%s (%s)" % (entry['label'].decode('base64'), entry['address']) 1244 except: # noqa:E722 1245 print('\n Connection Error\n') 1246 usrPrompt = 0 1247 main() 1248 1249 # add from my addresses 1250 try: 1251 response = api.listAddresses2() 1252 # if api is too old just return then fail 1253 if "API Error 0020" in response: 1254 return 1255 addresses = json.loads(response) 1256 for entry in addresses['addresses']: 1257 if entry['address'] not in knownAddresses: 1258 knownAddresses[entry['address']] = "%s (%s)" % (entry['label'].decode('base64'), entry['address']) 1259 except: # noqa:E722 1260 print('\n Connection Error\n') 1261 usrPrompt = 0 1262 main() 1263 1264 1265 def listAddressBookEntries(): 1266 """List addressbook entries""" 1267 1268 global usrPrompt 1269 1270 try: 1271 response = api.listAddressBookEntries() 1272 if "API Error" in response: 1273 return getAPIErrorCode(response) 1274 addressBook = json.loads(response) 1275 print(' --------------------------------------------------------------') 1276 print(' | Label | Address |') 1277 print(' |--------------------|---------------------------------------|') 1278 for entry in addressBook['addresses']: 1279 label = entry['label'].decode('base64') 1280 address = entry['address'] 1281 if len(label) > 19: 1282 label = label[:16] + '...' 1283 print(' | ' + label.ljust(19) + '| ' + address.ljust(37) + ' |') 1284 print(' --------------------------------------------------------------') 1285 except: # noqa:E722 1286 print('\n Connection Error\n') 1287 usrPrompt = 0 1288 main() 1289 1290 1291 def addAddressToAddressBook(address, label): 1292 """Add an address to an addressbook""" 1293 1294 global usrPrompt 1295 1296 try: 1297 response = api.addAddressBookEntry(address, label.encode('base64')) 1298 if "API Error" in response: 1299 return getAPIErrorCode(response) 1300 except: # noqa:E722 1301 print('\n Connection Error\n') 1302 usrPrompt = 0 1303 main() 1304 1305 1306 def deleteAddressFromAddressBook(address): 1307 """Delete an address from an addressbook""" 1308 1309 global usrPrompt 1310 1311 try: 1312 response = api.deleteAddressBookEntry(address) 1313 if "API Error" in response: 1314 return getAPIErrorCode(response) 1315 except: # noqa:E722 1316 print('\n Connection Error\n') 1317 usrPrompt = 0 1318 main() 1319 1320 1321 def getAPIErrorCode(response): 1322 """Get API error code""" 1323 1324 if "API Error" in response: 1325 # if we got an API error return the number by getting the number 1326 # after the second space and removing the trailing colon 1327 return int(response.split()[2][:-1]) 1328 1329 1330 def markMessageRead(messageID): 1331 """Mark a message as read""" 1332 1333 global usrPrompt 1334 1335 try: 1336 response = api.getInboxMessageByID(messageID, True) 1337 if "API Error" in response: 1338 return getAPIErrorCode(response) 1339 except: # noqa:E722 1340 print('\n Connection Error\n') 1341 usrPrompt = 0 1342 main() 1343 1344 1345 def markMessageUnread(messageID): 1346 """Mark a mesasge as unread""" 1347 1348 global usrPrompt 1349 1350 try: 1351 response = api.getInboxMessageByID(messageID, False) 1352 if "API Error" in response: 1353 return getAPIErrorCode(response) 1354 except: # noqa:E722 1355 print('\n Connection Error\n') 1356 usrPrompt = 0 1357 main() 1358 1359 1360 def markAllMessagesRead(): 1361 """Mark all messages as read""" 1362 1363 global usrPrompt 1364 1365 try: 1366 inboxMessages = json.loads(api.getAllInboxMessages())['inboxMessages'] 1367 except: # noqa:E722 1368 print('\n Connection Error\n') 1369 usrPrompt = 0 1370 main() 1371 for message in inboxMessages: 1372 if not message['read']: 1373 markMessageRead(message['msgid']) 1374 1375 1376 def markAllMessagesUnread(): 1377 """Mark all messages as unread""" 1378 1379 global usrPrompt 1380 1381 try: 1382 inboxMessages = json.loads(api.getAllInboxMessages())['inboxMessages'] 1383 except: # noqa:E722 1384 print('\n Connection Error\n') 1385 usrPrompt = 0 1386 main() 1387 for message in inboxMessages: 1388 if message['read']: 1389 markMessageUnread(message['msgid']) 1390 1391 1392 def clientStatus(): 1393 """Print (the client status""" 1394 1395 global usrPrompt 1396 1397 try: 1398 client_status = json.loads(api.clientStatus()) 1399 except: # noqa:E722 1400 print('\n Connection Error\n') 1401 usrPrompt = 0 1402 main() 1403 1404 print("\nnetworkStatus: " + client_status['networkStatus'] + "\n") 1405 print("\nnetworkConnections: " + str(client_status['networkConnections']) + "\n") 1406 print("\nnumberOfPubkeysProcessed: " + str(client_status['numberOfPubkeysProcessed']) + "\n") 1407 print("\nnumberOfMessagesProcessed: " + str(client_status['numberOfMessagesProcessed']) + "\n") 1408 print("\nnumberOfBroadcastsProcessed: " + str(client_status['numberOfBroadcastsProcessed']) + "\n") 1409 1410 1411 def shutdown(): 1412 """Shutdown the API""" 1413 1414 try: 1415 api.shutdown() 1416 except socket.error: 1417 pass 1418 print("\nShutdown command relayed\n") 1419 1420 1421 def UI(usrInput): 1422 """Main user menu""" 1423 1424 global usrPrompt 1425 1426 if usrInput in ("help", "h", "?"): 1427 print(' ') 1428 print(' -------------------------------------------------------------------------') 1429 print(' | https://github.com/Dokument/PyBitmessage-Daemon |') 1430 print(' |-----------------------------------------------------------------------|') 1431 print(' | Command | Description |') 1432 print(' |------------------------|----------------------------------------------|') 1433 print(' | help | This help file. |') 1434 print(' | apiTest | Tests the API |') 1435 print(' | addInfo | Returns address information (If valid) |') 1436 print(' | bmSettings | BitMessage settings |') 1437 print(' | exit | Use anytime to return to main menu |') 1438 print(' | quit | Quits the program |') 1439 print(' |------------------------|----------------------------------------------|') 1440 print(' | listAddresses | Lists all of the users addresses |') 1441 print(' | generateAddress | Generates a new address |') 1442 print(' | getAddress | Get determinist address from passphrase |') 1443 print(' |------------------------|----------------------------------------------|') 1444 print(' | listAddressBookEntries | Lists entries from the Address Book |') 1445 print(' | addAddressBookEntry | Add address to the Address Book |') 1446 print(' | deleteAddressBookEntry | Deletes address from the Address Book |') 1447 print(' |------------------------|----------------------------------------------|') 1448 print(' | subscribe | Subscribes to an address |') 1449 print(' | unsubscribe | Unsubscribes from an address |') 1450 print(' |------------------------|----------------------------------------------|') 1451 print(' | create | Creates a channel |') 1452 print(' | join | Joins a channel |') 1453 print(' | leave | Leaves a channel |') 1454 print(' |------------------------|----------------------------------------------|') 1455 print(' | inbox | Lists the message information for the inbox |') 1456 print(' | outbox | Lists the message information for the outbox |') 1457 print(' | send | Send a new message or broadcast |') 1458 print(' | unread | Lists all unread inbox messages |') 1459 print(' | read | Reads a message from the inbox or outbox |') 1460 print(' | save | Saves message to text file |') 1461 print(' | delete | Deletes a message or all messages |') 1462 print(' -------------------------------------------------------------------------') 1463 print(' ') 1464 main() 1465 1466 elif usrInput == "apitest": # tests the API Connection. 1467 if apiTest(): 1468 print('\n API connection test has: PASSED\n') 1469 else: 1470 print('\n API connection test has: FAILED\n') 1471 main() 1472 1473 elif usrInput == "addinfo": 1474 tmp_address = userInput('\nEnter the Bitmessage Address.') 1475 address_information = json.loads(api.decodeAddress(tmp_address)) 1476 1477 print('\n------------------------------') 1478 1479 if 'success' in str(address_information['status']).lower(): 1480 print(' Valid Address') 1481 print(' Address Version: %s' % str(address_information['addressVersion'])) 1482 print(' Stream Number: %s' % str(address_information['streamNumber'])) 1483 else: 1484 print(' Invalid Address !') 1485 1486 print('------------------------------\n') 1487 main() 1488 1489 elif usrInput == "bmsettings": # tests the API Connection. 1490 bmSettings() 1491 print(' ') 1492 main() 1493 1494 elif usrInput == "quit": # Quits the application 1495 print('\n Bye\n') 1496 sys.exit(0) 1497 1498 elif usrInput == "listaddresses": # Lists all of the identities in the addressbook 1499 listAdd() 1500 main() 1501 1502 elif usrInput == "generateaddress": # Generates a new address 1503 uInput = userInput('\nWould you like to create a (D)eterministic or (R)andom address?').lower() 1504 1505 if uInput in ("d", "deterministic"): # Creates a deterministic address 1506 deterministic = True 1507 1508 lbl = '' 1509 passphrase = userInput('Enter the Passphrase.') # .encode('base64') 1510 numOfAdd = int(userInput('How many addresses would you like to generate?')) 1511 addVNum = 3 1512 streamNum = 1 1513 isRipe = userInput('Shorten the address, (Y)es or (N)o?').lower() 1514 1515 if isRipe == "y": 1516 ripe = True 1517 print(genAdd(lbl, deterministic, passphrase, numOfAdd, addVNum, streamNum, ripe)) 1518 main() 1519 elif isRipe == "n": 1520 ripe = False 1521 print(genAdd(lbl, deterministic, passphrase, numOfAdd, addVNum, streamNum, ripe)) 1522 main() 1523 elif isRipe == "exit": 1524 usrPrompt = 1 1525 main() 1526 else: 1527 print('\n Invalid input\n') 1528 main() 1529 1530 elif uInput == "r" or uInput == "random": # Creates a random address with user-defined label 1531 deterministic = False 1532 null = '' 1533 lbl = userInput('Enter the label for the new address.') 1534 1535 print(genAdd(lbl, deterministic, null, null, null, null, null)) 1536 main() 1537 1538 else: 1539 print('\n Invalid input\n') 1540 main() 1541 1542 elif usrInput == "getaddress": # Gets the address for/from a passphrase 1543 phrase = userInput("Enter the address passphrase.") 1544 print('\n Working...\n') 1545 address = getAddress(phrase, 4, 1) # ,vNumber,sNumber) 1546 print('\n Address: ' + address + '\n') 1547 usrPrompt = 1 1548 main() 1549 1550 elif usrInput == "subscribe": # Subsribe to an address 1551 subscribe() 1552 usrPrompt = 1 1553 main() 1554 1555 elif usrInput == "unsubscribe": # Unsubscribe from an address 1556 unsubscribe() 1557 usrPrompt = 1 1558 main() 1559 1560 elif usrInput == "listsubscriptions": # Unsubscribe from an address 1561 listSubscriptions() 1562 usrPrompt = 1 1563 main() 1564 1565 elif usrInput == "create": 1566 createChan() 1567 usrPrompt = 1 1568 main() 1569 1570 elif usrInput == "join": 1571 joinChan() 1572 usrPrompt = 1 1573 main() 1574 1575 elif usrInput == "leave": 1576 leaveChan() 1577 usrPrompt = 1 1578 main() 1579 1580 elif usrInput == "inbox": 1581 print('\n Loading...\n') 1582 inbox() 1583 main() 1584 1585 elif usrInput == "unread": 1586 print('\n Loading...\n') 1587 inbox(True) 1588 main() 1589 1590 elif usrInput == "outbox": 1591 print('\n Loading...\n') 1592 outbox() 1593 main() 1594 1595 elif usrInput == 'send': # Sends a message or broadcast 1596 uInput = userInput('Would you like to send a (M)essage or (B)roadcast?').lower() 1597 1598 if uInput in ('m', 'message'): 1599 null = '' 1600 sendMsg(null, null, null, null) 1601 main() 1602 elif uInput in ('b', 'broadcast'): 1603 null = '' 1604 sendBrd(null, null, null) 1605 main() 1606 1607 elif usrInput == "read": # Opens a message from the inbox for viewing. 1608 1609 uInput = userInput("Would you like to read a message from the (I)nbox or (O)utbox?").lower() 1610 1611 if uInput not in ('i', 'inbox', 'o', 'outbox'): 1612 print('\n Invalid Input.\n') 1613 usrPrompt = 1 1614 main() 1615 1616 msgNum = int(userInput("What is the number of the message you wish to open?")) 1617 1618 if uInput in ('i', 'inbox'): 1619 print('\n Loading...\n') 1620 messageID = readMsg(msgNum) 1621 1622 uInput = userInput("\nWould you like to keep this message unread, (Y)es or (N)o?").lower() 1623 1624 if uInput not in ('y', 'yes'): 1625 markMessageRead(messageID) 1626 usrPrompt = 1 1627 1628 uInput = userInput("\nWould you like to (D)elete, (F)orward, (R)eply to, or (Exit) this message?").lower() 1629 1630 if uInput in ('r', 'reply'): 1631 print('\n Loading...\n') 1632 print(' ') 1633 replyMsg(msgNum, 'reply') 1634 usrPrompt = 1 1635 1636 elif uInput in ('f', 'forward'): 1637 print('\n Loading...\n') 1638 print(' ') 1639 replyMsg(msgNum, 'forward') 1640 usrPrompt = 1 1641 1642 elif uInput in ("d", 'delete'): 1643 uInput = userInput("Are you sure, (Y)es or (N)o?").lower() # Prevent accidental deletion 1644 1645 if uInput == "y": 1646 delMsg(msgNum) 1647 print('\n Message Deleted.\n') 1648 usrPrompt = 1 1649 else: 1650 usrPrompt = 1 1651 else: 1652 print('\n Invalid entry\n') 1653 usrPrompt = 1 1654 1655 elif uInput in ('o', 'outbox'): 1656 readSentMsg(msgNum) 1657 1658 # Gives the user the option to delete the message 1659 uInput = userInput("Would you like to (D)elete, or (Exit) this message?").lower() 1660 1661 if uInput in ("d", 'delete'): 1662 uInput = userInput('Are you sure, (Y)es or (N)o?').lower() # Prevent accidental deletion 1663 1664 if uInput == "y": 1665 delSentMsg(msgNum) 1666 print('\n Message Deleted.\n') 1667 usrPrompt = 1 1668 else: 1669 usrPrompt = 1 1670 else: 1671 print('\n Invalid Entry\n') 1672 usrPrompt = 1 1673 1674 main() 1675 1676 elif usrInput == "save": 1677 1678 uInput = userInput("Would you like to save a message from the (I)nbox or (O)utbox?").lower() 1679 1680 if uInput not in ('i', 'inbox', 'o', 'outbox'): 1681 print('\n Invalid Input.\n') 1682 usrPrompt = 1 1683 main() 1684 1685 if uInput in ('i', 'inbox'): 1686 inboxMessages = json.loads(api.getAllInboxMessages()) 1687 numMessages = len(inboxMessages['inboxMessages']) 1688 1689 while True: 1690 msgNum = int(userInput("What is the number of the message you wish to save?")) 1691 1692 if msgNum >= numMessages: 1693 print('\n Invalid Message Number.\n') 1694 else: 1695 break 1696 1697 subject = inboxMessages['inboxMessages'][msgNum]['subject'].decode('base64') 1698 # Don't decode since it is done in the saveFile function 1699 message = inboxMessages['inboxMessages'][msgNum]['message'] 1700 1701 elif uInput == 'o' or uInput == 'outbox': 1702 outboxMessages = json.loads(api.getAllSentMessages()) 1703 numMessages = len(outboxMessages['sentMessages']) 1704 1705 while True: 1706 msgNum = int(userInput("What is the number of the message you wish to save?")) 1707 1708 if msgNum >= numMessages: 1709 print('\n Invalid Message Number.\n') 1710 else: 1711 break 1712 1713 subject = outboxMessages['sentMessages'][msgNum]['subject'].decode('base64') 1714 # Don't decode since it is done in the saveFile function 1715 message = outboxMessages['sentMessages'][msgNum]['message'] 1716 1717 subject = subject + '.txt' 1718 saveFile(subject, message) 1719 1720 usrPrompt = 1 1721 main() 1722 1723 elif usrInput == "delete": # will delete a message from the system, not reflected on the UI. 1724 1725 uInput = userInput("Would you like to delete a message from the (I)nbox or (O)utbox?").lower() 1726 1727 if uInput in ('i', 'inbox'): 1728 inboxMessages = json.loads(api.getAllInboxMessages()) 1729 numMessages = len(inboxMessages['inboxMessages']) 1730 1731 while True: 1732 msgNum = userInput( 1733 'Enter the number of the message you wish to delete or (A)ll to empty the inbox.').lower() 1734 1735 if msgNum == 'a' or msgNum == 'all': 1736 break 1737 elif int(msgNum) >= numMessages: 1738 print('\n Invalid Message Number.\n') 1739 else: 1740 break 1741 1742 uInput = userInput("Are you sure, (Y)es or (N)o?").lower() # Prevent accidental deletion 1743 1744 if uInput == "y": 1745 if msgNum in ('a', 'all'): 1746 print(' ') 1747 for msgNum in range(0, numMessages): # processes all of the messages in the inbox 1748 print(' Deleting message ', msgNum + 1, ' of ', numMessages) 1749 delMsg(0) 1750 1751 print('\n Inbox is empty.') 1752 usrPrompt = 1 1753 else: 1754 delMsg(int(msgNum)) 1755 1756 print('\n Notice: Message numbers may have changed.\n') 1757 main() 1758 else: 1759 usrPrompt = 1 1760 1761 elif uInput in ('o', 'outbox'): 1762 outboxMessages = json.loads(api.getAllSentMessages()) 1763 numMessages = len(outboxMessages['sentMessages']) 1764 1765 while True: 1766 msgNum = userInput( 1767 'Enter the number of the message you wish to delete or (A)ll to empty the inbox.').lower() 1768 1769 if msgNum in ('a', 'all'): 1770 break 1771 elif int(msgNum) >= numMessages: 1772 print('\n Invalid Message Number.\n') 1773 else: 1774 break 1775 1776 uInput = userInput("Are you sure, (Y)es or (N)o?").lower() # Prevent accidental deletion 1777 1778 if uInput == "y": 1779 if msgNum in ('a', 'all'): 1780 print(' ') 1781 for msgNum in range(0, numMessages): # processes all of the messages in the outbox 1782 print(' Deleting message ', msgNum + 1, ' of ', numMessages) 1783 delSentMsg(0) 1784 1785 print('\n Outbox is empty.') 1786 usrPrompt = 1 1787 else: 1788 delSentMsg(int(msgNum)) 1789 print('\n Notice: Message numbers may have changed.\n') 1790 main() 1791 else: 1792 usrPrompt = 1 1793 else: 1794 print('\n Invalid Entry.\n') 1795 usrPrompt = 1 1796 main() 1797 1798 elif usrInput == "exit": 1799 print('\n You are already at the main menu. Use "quit" to quit.\n') 1800 usrPrompt = 1 1801 main() 1802 1803 elif usrInput == "listaddressbookentries": 1804 res = listAddressBookEntries() 1805 if res == 20: 1806 print('\n Error: API function not supported.\n') 1807 usrPrompt = 1 1808 main() 1809 1810 elif usrInput == "addaddressbookentry": 1811 address = userInput('Enter address') 1812 label = userInput('Enter label') 1813 res = addAddressToAddressBook(address, label) 1814 if res == 16: 1815 print('\n Error: Address already exists in Address Book.\n') 1816 if res == 20: 1817 print('\n Error: API function not supported.\n') 1818 usrPrompt = 1 1819 main() 1820 1821 elif usrInput == "deleteaddressbookentry": 1822 address = userInput('Enter address') 1823 res = deleteAddressFromAddressBook(address) 1824 if res == 20: 1825 print('\n Error: API function not supported.\n') 1826 usrPrompt = 1 1827 main() 1828 1829 elif usrInput == "markallmessagesread": 1830 markAllMessagesRead() 1831 usrPrompt = 1 1832 main() 1833 1834 elif usrInput == "markallmessagesunread": 1835 markAllMessagesUnread() 1836 usrPrompt = 1 1837 main() 1838 1839 elif usrInput == "status": 1840 clientStatus() 1841 usrPrompt = 1 1842 main() 1843 1844 elif usrInput == "shutdown": 1845 shutdown() 1846 usrPrompt = 1 1847 main() 1848 1849 else: 1850 print('\n "', usrInput, '" is not a command.\n') 1851 usrPrompt = 1 1852 main() 1853 1854 1855 def main(): 1856 """Entrypoint for the CLI app""" 1857 1858 global api 1859 global usrPrompt 1860 1861 if usrPrompt == 0: 1862 print('\n ------------------------------') 1863 print(' | Bitmessage Daemon by .dok |') 1864 print(' | Version 0.3.1 for BM 0.6.2 |') 1865 print(' ------------------------------') 1866 api = xmlrpclib.ServerProxy(apiData()) # Connect to BitMessage using these api credentials 1867 1868 if apiTest() is False: 1869 print('\n ****************************************************************') 1870 print(' WARNING: You are not connected to the Bitmessage client.') 1871 print(' Either Bitmessage is not running or your settings are incorrect.') 1872 print(' Use the command "apiTest" or "bmSettings" to resolve this issue.') 1873 print(' ****************************************************************\n') 1874 1875 print('Type (H)elp for a list of commands.') # Startup message) 1876 usrPrompt = 2 1877 1878 elif usrPrompt == 1: 1879 print('\nType (H)elp for a list of commands.') # Startup message) 1880 usrPrompt = 2 1881 1882 try: 1883 UI((raw_input('>').lower()).replace(" ", "")) 1884 except EOFError: 1885 UI("quit") 1886 1887 1888 if __name__ == "__main__": 1889 main()