2018-05-15 17:15:44 +02:00
|
|
|
#!/usr/bin/python2.7
|
2017-12-26 14:17:37 +01:00
|
|
|
# -*- coding: utf-8 -*-
|
2018-05-15 17:15:44 +02:00
|
|
|
# pylint: disable=too-many-lines,global-statement,too-many-branches,too-many-statements,inconsistent-return-statements
|
|
|
|
# pylint: disable=too-many-nested-blocks,too-many-locals,protected-access,too-many-arguments,too-many-function-args
|
|
|
|
# pylint: disable=no-member
|
|
|
|
"""
|
|
|
|
Created by Adam Melton (.dok) referenceing https://bitmessage.org/wiki/API_Reference for API documentation
|
|
|
|
Distributed under the MIT/X11 software license. See http://www.opensource.org/licenses/mit-license.php.
|
2015-01-19 18:53:07 +01:00
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
This is an example of a daemon client for PyBitmessage 0.6.2, by .dok (Version 0.3.1) , modified
|
2015-01-19 18:53:07 +01:00
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
TODO: fix the following (currently ignored) violations:
|
|
|
|
|
|
|
|
"""
|
2015-01-19 18:53:07 +01:00
|
|
|
|
|
|
|
import xmlrpclib
|
|
|
|
import datetime
|
|
|
|
import imghdr
|
|
|
|
import ntpath
|
|
|
|
import json
|
2017-08-22 13:23:03 +02:00
|
|
|
import socket
|
2015-01-19 18:53:07 +01:00
|
|
|
import time
|
|
|
|
import sys
|
|
|
|
import os
|
|
|
|
|
2017-02-22 09:34:54 +01:00
|
|
|
from bmconfigparser import BMConfigParser
|
2016-12-06 10:47:39 +01:00
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
api = ''
|
|
|
|
keysName = 'keys.dat'
|
|
|
|
keysPath = 'keys.dat'
|
2018-05-15 17:15:44 +02:00
|
|
|
usrPrompt = 0 # 0 = First Start, 1 = prompt, 2 = no prompt if the program is starting up
|
2015-01-19 18:53:07 +01:00
|
|
|
knownAddresses = dict()
|
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
|
|
|
|
def userInput(message):
|
|
|
|
"""Checks input for exit or quit. Also formats for input, etc"""
|
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
global usrPrompt
|
2018-05-15 17:15:44 +02:00
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
print '\n' + message
|
|
|
|
uInput = raw_input('> ')
|
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
if uInput.lower() == 'exit': # Returns the user to the main menu
|
2015-01-19 18:53:07 +01:00
|
|
|
usrPrompt = 1
|
|
|
|
main()
|
2018-05-15 17:15:44 +02:00
|
|
|
|
|
|
|
elif uInput.lower() == 'quit': # Quits the program
|
2015-01-19 18:53:07 +01:00
|
|
|
print '\n Bye\n'
|
2018-05-15 17:15:44 +02:00
|
|
|
sys.exit(0)
|
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
else:
|
|
|
|
return uInput
|
2018-05-15 17:15:44 +02:00
|
|
|
|
|
|
|
|
|
|
|
def restartBmNotify():
|
|
|
|
"""Prompt the user to restart Bitmessage"""
|
2015-01-19 18:53:07 +01:00
|
|
|
print '\n *******************************************************************'
|
|
|
|
print ' WARNING: If Bitmessage is running locally, you must restart it now.'
|
|
|
|
print ' *******************************************************************\n'
|
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
|
|
|
|
# Begin keys.dat interactions
|
|
|
|
|
|
|
|
|
|
|
|
def lookupAppdataFolder():
|
|
|
|
"""gets the appropriate folders for the .dat files depending on the OS. Taken from bitmessagemain.py"""
|
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
APPNAME = "PyBitmessage"
|
|
|
|
if sys.platform == 'darwin':
|
2018-05-15 17:15:44 +02:00
|
|
|
if "HOME" in os.environ:
|
|
|
|
dataFolder = os.path.join(os.environ["HOME"], "Library/Application support/", APPNAME) + '/'
|
2015-01-19 18:53:07 +01:00
|
|
|
else:
|
2018-05-15 17:15:44 +02:00
|
|
|
print(
|
|
|
|
' Could not find home folder, please report '
|
|
|
|
'this message and your OS X version to the Daemon Github.')
|
|
|
|
sys.exit(1)
|
2015-01-19 18:53:07 +01:00
|
|
|
|
|
|
|
elif 'win32' in sys.platform or 'win64' in sys.platform:
|
2018-05-15 17:15:44 +02:00
|
|
|
dataFolder = os.path.join(os.environ['APPDATA'], APPNAME) + '\\'
|
2015-01-19 18:53:07 +01:00
|
|
|
else:
|
2018-05-15 17:15:44 +02:00
|
|
|
dataFolder = os.path.expanduser(os.path.join("~", ".config/" + APPNAME + "/"))
|
2015-01-19 18:53:07 +01:00
|
|
|
return dataFolder
|
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
def configInit():
|
2018-05-15 17:15:44 +02:00
|
|
|
"""Initialised the configuration"""
|
|
|
|
|
2017-01-11 14:27:19 +01:00
|
|
|
BMConfigParser().add_section('bitmessagesettings')
|
2018-05-15 17:15:44 +02:00
|
|
|
# Sets the bitmessage port to stop the warning about the api not properly
|
|
|
|
# being setup. This is in the event that the keys.dat is in a different
|
|
|
|
# directory or is created locally to connect to a machine remotely.
|
|
|
|
BMConfigParser().set('bitmessagesettings', 'port', '8444')
|
|
|
|
BMConfigParser().set('bitmessagesettings', 'apienabled', 'true') # Sets apienabled to true in keys.dat
|
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
with open(keysName, 'wb') as configfile:
|
2017-01-11 14:27:19 +01:00
|
|
|
BMConfigParser().write(configfile)
|
2015-01-19 18:53:07 +01:00
|
|
|
|
|
|
|
print '\n ' + str(keysName) + ' Initalized in the same directory as daemon.py'
|
|
|
|
print ' You will now need to configure the ' + str(keysName) + ' file.\n'
|
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
def apiInit(apiEnabled):
|
2018-05-15 17:15:44 +02:00
|
|
|
"""Initialise the API"""
|
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
global usrPrompt
|
2017-01-11 14:27:19 +01:00
|
|
|
BMConfigParser().read(keysPath)
|
2015-01-19 18:53:07 +01:00
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
if apiEnabled is False: # API information there but the api is disabled.
|
2015-01-19 18:53:07 +01:00
|
|
|
uInput = userInput("The API is not enabled. Would you like to do that now, (Y)es or (N)o?").lower()
|
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
if uInput == "y":
|
|
|
|
BMConfigParser().set('bitmessagesettings', 'apienabled', 'true') # Sets apienabled to true in keys.dat
|
2015-01-19 18:53:07 +01:00
|
|
|
with open(keysPath, 'wb') as configfile:
|
2017-01-11 14:27:19 +01:00
|
|
|
BMConfigParser().write(configfile)
|
2018-05-15 17:15:44 +02:00
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
print 'Done'
|
|
|
|
restartBmNotify()
|
|
|
|
return True
|
2018-05-15 17:15:44 +02:00
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
elif uInput == "n":
|
|
|
|
print ' \n************************************************************'
|
|
|
|
print ' Daemon will not work when the API is disabled. '
|
|
|
|
print ' Please refer to the Bitmessage Wiki on how to setup the API.'
|
|
|
|
print ' ************************************************************\n'
|
|
|
|
usrPrompt = 1
|
|
|
|
main()
|
2018-05-15 17:15:44 +02:00
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
else:
|
|
|
|
print '\n Invalid Entry\n'
|
|
|
|
usrPrompt = 1
|
|
|
|
main()
|
2018-05-15 17:15:44 +02:00
|
|
|
|
|
|
|
elif apiEnabled: # API correctly setup
|
|
|
|
# Everything is as it should be
|
2015-01-19 18:53:07 +01:00
|
|
|
return True
|
2018-05-15 17:15:44 +02:00
|
|
|
|
|
|
|
else: # API information was not present.
|
2015-01-19 18:53:07 +01:00
|
|
|
print '\n ' + str(keysPath) + ' not properly configured!\n'
|
|
|
|
uInput = userInput("Would you like to do this now, (Y)es or (N)o?").lower()
|
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
if uInput == "y": # User said yes, initalize the api by writing these values to the keys.dat file
|
2015-01-19 18:53:07 +01:00
|
|
|
print ' '
|
2018-05-15 17:15:44 +02:00
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
apiUsr = userInput("API Username")
|
|
|
|
apiPwd = userInput("API Password")
|
|
|
|
apiPort = userInput("API Port")
|
|
|
|
apiEnabled = userInput("API Enabled? (True) or (False)").lower()
|
|
|
|
daemon = userInput("Daemon mode Enabled? (True) or (False)").lower()
|
|
|
|
|
|
|
|
if (daemon != 'true' and daemon != 'false'):
|
|
|
|
print '\n Invalid Entry for Daemon.\n'
|
|
|
|
uInput = 1
|
|
|
|
main()
|
2018-05-15 17:15:44 +02:00
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
print ' -----------------------------------\n'
|
2018-05-15 17:15:44 +02:00
|
|
|
|
|
|
|
# sets the bitmessage port to stop the warning about the api not properly
|
|
|
|
# being setup. This is in the event that the keys.dat is in a different
|
|
|
|
# directory or is created locally to connect to a machine remotely.
|
|
|
|
BMConfigParser().set('bitmessagesettings', 'port', '8444')
|
|
|
|
BMConfigParser().set('bitmessagesettings', 'apienabled', 'true')
|
2017-01-11 14:27:19 +01:00
|
|
|
BMConfigParser().set('bitmessagesettings', 'apiport', apiPort)
|
|
|
|
BMConfigParser().set('bitmessagesettings', 'apiinterface', '127.0.0.1')
|
|
|
|
BMConfigParser().set('bitmessagesettings', 'apiusername', apiUsr)
|
|
|
|
BMConfigParser().set('bitmessagesettings', 'apipassword', apiPwd)
|
|
|
|
BMConfigParser().set('bitmessagesettings', 'daemon', daemon)
|
2015-01-19 18:53:07 +01:00
|
|
|
with open(keysPath, 'wb') as configfile:
|
2017-01-11 14:27:19 +01:00
|
|
|
BMConfigParser().write(configfile)
|
2018-05-15 17:15:44 +02:00
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
print '\n Finished configuring the keys.dat file with API information.\n'
|
|
|
|
restartBmNotify()
|
|
|
|
return True
|
2018-05-15 17:15:44 +02:00
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
elif uInput == "n":
|
|
|
|
print '\n ***********************************************************'
|
|
|
|
print ' Please refer to the Bitmessage Wiki on how to setup the API.'
|
|
|
|
print ' ***********************************************************\n'
|
|
|
|
usrPrompt = 1
|
|
|
|
main()
|
|
|
|
else:
|
|
|
|
print ' \nInvalid entry\n'
|
|
|
|
usrPrompt = 1
|
|
|
|
main()
|
|
|
|
|
|
|
|
|
|
|
|
def apiData():
|
2018-05-15 17:15:44 +02:00
|
|
|
"""TBC"""
|
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
global keysName
|
|
|
|
global keysPath
|
|
|
|
global usrPrompt
|
2018-05-15 17:15:44 +02:00
|
|
|
|
|
|
|
BMConfigParser().read(keysPath) # First try to load the config file (the keys.dat file) from the program directory
|
2015-01-19 18:53:07 +01:00
|
|
|
|
|
|
|
try:
|
2018-05-15 17:15:44 +02:00
|
|
|
BMConfigParser().get('bitmessagesettings', 'port')
|
2015-01-19 18:53:07 +01:00
|
|
|
appDataFolder = ''
|
|
|
|
except:
|
2018-05-15 17:15:44 +02:00
|
|
|
# Could not load the keys.dat file in the program directory. Perhaps it is in the appdata directory.
|
2015-01-19 18:53:07 +01:00
|
|
|
appDataFolder = lookupAppdataFolder()
|
|
|
|
keysPath = appDataFolder + keysPath
|
2017-01-11 14:27:19 +01:00
|
|
|
BMConfigParser().read(keysPath)
|
2015-01-19 18:53:07 +01:00
|
|
|
|
|
|
|
try:
|
2018-05-15 17:15:44 +02:00
|
|
|
BMConfigParser().get('bitmessagesettings', 'port')
|
2015-01-19 18:53:07 +01:00
|
|
|
except:
|
2018-05-15 17:15:44 +02:00
|
|
|
# keys.dat was not there either, something is wrong.
|
2015-01-19 18:53:07 +01:00
|
|
|
print '\n ******************************************************************'
|
|
|
|
print ' There was a problem trying to access the Bitmessage keys.dat file'
|
|
|
|
print ' or keys.dat is not set up correctly'
|
|
|
|
print ' Make sure that daemon is in the same directory as Bitmessage. '
|
|
|
|
print ' ******************************************************************\n'
|
|
|
|
|
|
|
|
uInput = userInput("Would you like to create a keys.dat in the local directory, (Y)es or (N)o?").lower()
|
2018-05-15 17:15:44 +02:00
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
if (uInput == "y" or uInput == "yes"):
|
|
|
|
configInit()
|
|
|
|
keysPath = keysName
|
|
|
|
usrPrompt = 0
|
|
|
|
main()
|
|
|
|
elif (uInput == "n" or uInput == "no"):
|
|
|
|
print '\n Trying Again.\n'
|
|
|
|
usrPrompt = 0
|
|
|
|
main()
|
|
|
|
else:
|
|
|
|
print '\n Invalid Input.\n'
|
|
|
|
|
|
|
|
usrPrompt = 1
|
|
|
|
main()
|
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
try: # checks to make sure that everyting is configured correctly. Excluding apiEnabled, it is checked after
|
2017-01-11 14:27:19 +01:00
|
|
|
BMConfigParser().get('bitmessagesettings', 'apiport')
|
|
|
|
BMConfigParser().get('bitmessagesettings', 'apiinterface')
|
|
|
|
BMConfigParser().get('bitmessagesettings', 'apiusername')
|
|
|
|
BMConfigParser().get('bitmessagesettings', 'apipassword')
|
2018-05-15 17:15:44 +02:00
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
except:
|
2018-05-15 17:15:44 +02:00
|
|
|
apiInit("") # Initalize the keys.dat file with API information
|
2015-01-19 18:53:07 +01:00
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
# keys.dat file was found or appropriately configured, allow information retrieval
|
|
|
|
# apiEnabled =
|
|
|
|
# apiInit(BMConfigParser().safeGetBoolean('bitmessagesettings','apienabled'))
|
|
|
|
# #if false it will prompt the user, if true it will return true
|
2015-01-19 18:53:07 +01:00
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
BMConfigParser().read(keysPath) # read again since changes have been made
|
2017-01-11 14:27:19 +01:00
|
|
|
apiPort = int(BMConfigParser().get('bitmessagesettings', 'apiport'))
|
|
|
|
apiInterface = BMConfigParser().get('bitmessagesettings', 'apiinterface')
|
|
|
|
apiUsername = BMConfigParser().get('bitmessagesettings', 'apiusername')
|
|
|
|
apiPassword = BMConfigParser().get('bitmessagesettings', 'apipassword')
|
2018-05-15 17:15:44 +02:00
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
print '\n API data successfully imported.\n'
|
2018-05-15 17:15:44 +02:00
|
|
|
|
|
|
|
# Build the api credentials
|
|
|
|
return "http://" + apiUsername + ":" + apiPassword + "@" + apiInterface + ":" + str(apiPort) + "/"
|
|
|
|
|
|
|
|
|
|
|
|
# End keys.dat interactions
|
2015-01-19 18:53:07 +01:00
|
|
|
|
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
def apiTest():
|
|
|
|
"""Tests the API connection to bitmessage. Returns true if it is connected."""
|
2015-01-19 18:53:07 +01:00
|
|
|
|
|
|
|
try:
|
2018-05-15 17:15:44 +02:00
|
|
|
result = api.add(2, 3)
|
2015-01-19 18:53:07 +01:00
|
|
|
except:
|
|
|
|
return False
|
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
return result == 5
|
|
|
|
|
|
|
|
|
|
|
|
def bmSettings():
|
|
|
|
"""Allows the viewing and modification of keys.dat settings."""
|
2015-01-19 18:53:07 +01:00
|
|
|
|
|
|
|
global keysPath
|
|
|
|
global usrPrompt
|
2018-05-15 17:15:44 +02:00
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
keysPath = 'keys.dat'
|
2018-05-15 17:15:44 +02:00
|
|
|
|
|
|
|
BMConfigParser().read(keysPath) # Read the keys.dat
|
2015-01-19 18:53:07 +01:00
|
|
|
try:
|
2017-01-11 14:27:19 +01:00
|
|
|
port = BMConfigParser().get('bitmessagesettings', 'port')
|
2015-01-19 18:53:07 +01:00
|
|
|
except:
|
|
|
|
print '\n File not found.\n'
|
|
|
|
usrPrompt = 0
|
|
|
|
main()
|
2018-05-15 17:15:44 +02:00
|
|
|
|
2017-01-11 14:27:19 +01:00
|
|
|
startonlogon = BMConfigParser().safeGetBoolean('bitmessagesettings', 'startonlogon')
|
|
|
|
minimizetotray = BMConfigParser().safeGetBoolean('bitmessagesettings', 'minimizetotray')
|
|
|
|
showtraynotifications = BMConfigParser().safeGetBoolean('bitmessagesettings', 'showtraynotifications')
|
|
|
|
startintray = BMConfigParser().safeGetBoolean('bitmessagesettings', 'startintray')
|
|
|
|
defaultnoncetrialsperbyte = BMConfigParser().get('bitmessagesettings', 'defaultnoncetrialsperbyte')
|
|
|
|
defaultpayloadlengthextrabytes = BMConfigParser().get('bitmessagesettings', 'defaultpayloadlengthextrabytes')
|
|
|
|
daemon = BMConfigParser().safeGetBoolean('bitmessagesettings', 'daemon')
|
|
|
|
|
|
|
|
socksproxytype = BMConfigParser().get('bitmessagesettings', 'socksproxytype')
|
|
|
|
sockshostname = BMConfigParser().get('bitmessagesettings', 'sockshostname')
|
|
|
|
socksport = BMConfigParser().get('bitmessagesettings', 'socksport')
|
|
|
|
socksauthentication = BMConfigParser().safeGetBoolean('bitmessagesettings', 'socksauthentication')
|
|
|
|
socksusername = BMConfigParser().get('bitmessagesettings', 'socksusername')
|
|
|
|
sockspassword = BMConfigParser().get('bitmessagesettings', 'sockspassword')
|
2015-01-19 18:53:07 +01:00
|
|
|
|
|
|
|
print '\n -----------------------------------'
|
|
|
|
print ' | Current Bitmessage Settings |'
|
|
|
|
print ' -----------------------------------'
|
|
|
|
print ' port = ' + port
|
|
|
|
print ' startonlogon = ' + str(startonlogon)
|
|
|
|
print ' minimizetotray = ' + str(minimizetotray)
|
|
|
|
print ' showtraynotifications = ' + str(showtraynotifications)
|
|
|
|
print ' startintray = ' + str(startintray)
|
|
|
|
print ' defaultnoncetrialsperbyte = ' + defaultnoncetrialsperbyte
|
|
|
|
print ' defaultpayloadlengthextrabytes = ' + defaultpayloadlengthextrabytes
|
|
|
|
print ' daemon = ' + str(daemon)
|
|
|
|
print '\n ------------------------------------'
|
|
|
|
print ' | Current Connection Settings |'
|
|
|
|
print ' -----------------------------------'
|
|
|
|
print ' socksproxytype = ' + socksproxytype
|
|
|
|
print ' sockshostname = ' + sockshostname
|
|
|
|
print ' socksport = ' + socksport
|
|
|
|
print ' socksauthentication = ' + str(socksauthentication)
|
|
|
|
print ' socksusername = ' + socksusername
|
|
|
|
print ' sockspassword = ' + sockspassword
|
|
|
|
print ' '
|
|
|
|
|
|
|
|
uInput = userInput("Would you like to modify any of these settings, (Y)es or (N)o?").lower()
|
2018-05-15 17:15:44 +02:00
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
if uInput == "y":
|
2018-05-15 17:15:44 +02:00
|
|
|
while True: # loops if they mistype the setting name, they can exit the loop with 'exit'
|
2015-01-19 18:53:07 +01:00
|
|
|
invalidInput = False
|
|
|
|
uInput = userInput("What setting would you like to modify?").lower()
|
|
|
|
print ' '
|
|
|
|
|
|
|
|
if uInput == "port":
|
|
|
|
print ' Current port number: ' + port
|
|
|
|
uInput = userInput("Enter the new port number.")
|
2017-01-11 14:27:19 +01:00
|
|
|
BMConfigParser().set('bitmessagesettings', 'port', str(uInput))
|
2015-01-19 18:53:07 +01:00
|
|
|
elif uInput == "startonlogon":
|
|
|
|
print ' Current status: ' + str(startonlogon)
|
|
|
|
uInput = userInput("Enter the new status.")
|
2017-01-11 14:27:19 +01:00
|
|
|
BMConfigParser().set('bitmessagesettings', 'startonlogon', str(uInput))
|
2015-01-19 18:53:07 +01:00
|
|
|
elif uInput == "minimizetotray":
|
|
|
|
print ' Current status: ' + str(minimizetotray)
|
|
|
|
uInput = userInput("Enter the new status.")
|
2017-01-11 14:27:19 +01:00
|
|
|
BMConfigParser().set('bitmessagesettings', 'minimizetotray', str(uInput))
|
2015-01-19 18:53:07 +01:00
|
|
|
elif uInput == "showtraynotifications":
|
|
|
|
print ' Current status: ' + str(showtraynotifications)
|
|
|
|
uInput = userInput("Enter the new status.")
|
2017-01-11 14:27:19 +01:00
|
|
|
BMConfigParser().set('bitmessagesettings', 'showtraynotifications', str(uInput))
|
2015-01-19 18:53:07 +01:00
|
|
|
elif uInput == "startintray":
|
|
|
|
print ' Current status: ' + str(startintray)
|
|
|
|
uInput = userInput("Enter the new status.")
|
2017-01-11 14:27:19 +01:00
|
|
|
BMConfigParser().set('bitmessagesettings', 'startintray', str(uInput))
|
2015-01-19 18:53:07 +01:00
|
|
|
elif uInput == "defaultnoncetrialsperbyte":
|
|
|
|
print ' Current default nonce trials per byte: ' + defaultnoncetrialsperbyte
|
|
|
|
uInput = userInput("Enter the new defaultnoncetrialsperbyte.")
|
2017-01-11 14:27:19 +01:00
|
|
|
BMConfigParser().set('bitmessagesettings', 'defaultnoncetrialsperbyte', str(uInput))
|
2015-01-19 18:53:07 +01:00
|
|
|
elif uInput == "defaultpayloadlengthextrabytes":
|
|
|
|
print ' Current default payload length extra bytes: ' + defaultpayloadlengthextrabytes
|
|
|
|
uInput = userInput("Enter the new defaultpayloadlengthextrabytes.")
|
2017-01-11 14:27:19 +01:00
|
|
|
BMConfigParser().set('bitmessagesettings', 'defaultpayloadlengthextrabytes', str(uInput))
|
2015-01-19 18:53:07 +01:00
|
|
|
elif uInput == "daemon":
|
|
|
|
print ' Current status: ' + str(daemon)
|
|
|
|
uInput = userInput("Enter the new status.").lower()
|
2017-01-11 14:27:19 +01:00
|
|
|
BMConfigParser().set('bitmessagesettings', 'daemon', str(uInput))
|
2015-01-19 18:53:07 +01:00
|
|
|
elif uInput == "socksproxytype":
|
|
|
|
print ' Current socks proxy type: ' + socksproxytype
|
|
|
|
print "Possibilities: 'none', 'SOCKS4a', 'SOCKS5'."
|
|
|
|
uInput = userInput("Enter the new socksproxytype.")
|
2017-01-11 14:27:19 +01:00
|
|
|
BMConfigParser().set('bitmessagesettings', 'socksproxytype', str(uInput))
|
2015-01-19 18:53:07 +01:00
|
|
|
elif uInput == "sockshostname":
|
|
|
|
print ' Current socks host name: ' + sockshostname
|
|
|
|
uInput = userInput("Enter the new sockshostname.")
|
2017-01-11 14:27:19 +01:00
|
|
|
BMConfigParser().set('bitmessagesettings', 'sockshostname', str(uInput))
|
2015-01-19 18:53:07 +01:00
|
|
|
elif uInput == "socksport":
|
|
|
|
print ' Current socks port number: ' + socksport
|
|
|
|
uInput = userInput("Enter the new socksport.")
|
2017-01-11 14:27:19 +01:00
|
|
|
BMConfigParser().set('bitmessagesettings', 'socksport', str(uInput))
|
2015-01-19 18:53:07 +01:00
|
|
|
elif uInput == "socksauthentication":
|
|
|
|
print ' Current status: ' + str(socksauthentication)
|
|
|
|
uInput = userInput("Enter the new status.")
|
2017-01-11 14:27:19 +01:00
|
|
|
BMConfigParser().set('bitmessagesettings', 'socksauthentication', str(uInput))
|
2015-01-19 18:53:07 +01:00
|
|
|
elif uInput == "socksusername":
|
|
|
|
print ' Current socks username: ' + socksusername
|
|
|
|
uInput = userInput("Enter the new socksusername.")
|
2017-01-11 14:27:19 +01:00
|
|
|
BMConfigParser().set('bitmessagesettings', 'socksusername', str(uInput))
|
2015-01-19 18:53:07 +01:00
|
|
|
elif uInput == "sockspassword":
|
|
|
|
print ' Current socks password: ' + sockspassword
|
|
|
|
uInput = userInput("Enter the new password.")
|
2017-01-11 14:27:19 +01:00
|
|
|
BMConfigParser().set('bitmessagesettings', 'sockspassword', str(uInput))
|
2015-01-19 18:53:07 +01:00
|
|
|
else:
|
|
|
|
print "\n Invalid input. Please try again.\n"
|
|
|
|
invalidInput = True
|
2018-05-15 17:15:44 +02:00
|
|
|
|
|
|
|
if invalidInput is not True: # don't prompt if they made a mistake.
|
2015-01-19 18:53:07 +01:00
|
|
|
uInput = userInput("Would you like to change another setting, (Y)es or (N)o?").lower()
|
|
|
|
|
|
|
|
if uInput != "y":
|
|
|
|
print '\n Changes Made.\n'
|
|
|
|
with open(keysPath, 'wb') as configfile:
|
2017-01-11 14:27:19 +01:00
|
|
|
BMConfigParser().write(configfile)
|
2015-01-19 18:53:07 +01:00
|
|
|
restartBmNotify()
|
|
|
|
break
|
2018-05-15 17:15:44 +02:00
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
elif uInput == "n":
|
|
|
|
usrPrompt = 1
|
|
|
|
main()
|
|
|
|
else:
|
|
|
|
print "Invalid input."
|
|
|
|
usrPrompt = 1
|
|
|
|
main()
|
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
def validAddress(address):
|
2018-05-15 17:15:44 +02:00
|
|
|
"""Predicate to test address validity"""
|
2018-02-18 20:14:21 +01:00
|
|
|
address_information = json.loads(api.decodeAddress(address))
|
2015-01-19 18:53:07 +01:00
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
return 'success' in str(address_information['status']).lower()
|
|
|
|
|
|
|
|
|
|
|
|
def getAddress(passphrase, vNumber, sNumber):
|
|
|
|
"""Get a deterministic address"""
|
|
|
|
passphrase = passphrase.encode('base64') # passphrase must be encoded
|
|
|
|
|
|
|
|
return api.getDeterministicAddress(passphrase, vNumber, sNumber)
|
2015-01-19 18:53:07 +01:00
|
|
|
|
|
|
|
|
|
|
|
def subscribe():
|
2018-05-15 17:15:44 +02:00
|
|
|
"""Subscribe to an address"""
|
2015-01-19 18:53:07 +01:00
|
|
|
global usrPrompt
|
|
|
|
|
|
|
|
while True:
|
|
|
|
address = userInput("What address would you like to subscribe to?")
|
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
if address == "c":
|
|
|
|
usrPrompt = 1
|
|
|
|
print ' '
|
|
|
|
main()
|
|
|
|
elif validAddress(address) is False:
|
2015-01-19 18:53:07 +01:00
|
|
|
print '\n Invalid. "c" to cancel. Please try again.\n'
|
|
|
|
else:
|
|
|
|
break
|
2018-05-15 17:15:44 +02:00
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
label = userInput("Enter a label for this address.")
|
|
|
|
label = label.encode('base64')
|
2018-05-15 17:15:44 +02:00
|
|
|
|
|
|
|
api.addSubscription(address, label)
|
|
|
|
print '\n You are now subscribed to: ' + address + '\n'
|
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
|
|
|
|
def unsubscribe():
|
2018-05-15 17:15:44 +02:00
|
|
|
"""Unsusbcribe from an address"""
|
2015-01-19 18:53:07 +01:00
|
|
|
global usrPrompt
|
2018-05-15 17:15:44 +02:00
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
while True:
|
|
|
|
address = userInput("What address would you like to unsubscribe from?")
|
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
if address == "c":
|
|
|
|
usrPrompt = 1
|
|
|
|
print ' '
|
|
|
|
main()
|
|
|
|
elif validAddress(address) is False:
|
2015-01-19 18:53:07 +01:00
|
|
|
print '\n Invalid. "c" to cancel. Please try again.\n'
|
|
|
|
else:
|
|
|
|
break
|
2018-05-15 17:15:44 +02:00
|
|
|
|
|
|
|
userInput("Are you sure, (Y)es or (N)o?").lower() # uInput =
|
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
api.deleteSubscription(address)
|
2018-05-15 17:15:44 +02:00
|
|
|
print '\n You are now unsubscribed from: ' + address + '\n'
|
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
|
|
|
|
def listSubscriptions():
|
2018-05-15 17:15:44 +02:00
|
|
|
"""List subscriptions"""
|
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
global usrPrompt
|
|
|
|
print '\nLabel, Address, Enabled\n'
|
|
|
|
try:
|
|
|
|
print api.listSubscriptions()
|
|
|
|
except:
|
|
|
|
print '\n Connection Error\n'
|
|
|
|
usrPrompt = 0
|
|
|
|
main()
|
|
|
|
print ' '
|
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
def createChan():
|
2018-05-15 17:15:44 +02:00
|
|
|
"""Create a channel"""
|
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
global usrPrompt
|
|
|
|
password = userInput("Enter channel name")
|
|
|
|
password = password.encode('base64')
|
|
|
|
try:
|
|
|
|
print api.createChan(password)
|
|
|
|
except:
|
|
|
|
print '\n Connection Error\n'
|
|
|
|
usrPrompt = 0
|
|
|
|
main()
|
|
|
|
|
|
|
|
|
|
|
|
def joinChan():
|
2018-05-15 17:15:44 +02:00
|
|
|
"""Join a channel"""
|
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
global usrPrompt
|
|
|
|
while True:
|
|
|
|
address = userInput("Enter channel address")
|
2018-05-15 17:15:44 +02:00
|
|
|
|
|
|
|
if address == "c":
|
|
|
|
usrPrompt = 1
|
|
|
|
print ' '
|
|
|
|
main()
|
|
|
|
elif validAddress(address) is False:
|
2015-01-19 18:53:07 +01:00
|
|
|
print '\n Invalid. "c" to cancel. Please try again.\n'
|
|
|
|
else:
|
|
|
|
break
|
2018-05-15 17:15:44 +02:00
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
password = userInput("Enter channel name")
|
|
|
|
password = password.encode('base64')
|
|
|
|
try:
|
2018-05-15 17:15:44 +02:00
|
|
|
print api.joinChan(password, address)
|
2015-01-19 18:53:07 +01:00
|
|
|
except:
|
|
|
|
print '\n Connection Error\n'
|
|
|
|
usrPrompt = 0
|
|
|
|
main()
|
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
def leaveChan():
|
2018-05-15 17:15:44 +02:00
|
|
|
"""Leave a channel"""
|
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
global usrPrompt
|
|
|
|
while True:
|
|
|
|
address = userInput("Enter channel address")
|
2018-05-15 17:15:44 +02:00
|
|
|
|
|
|
|
if address == "c":
|
|
|
|
usrPrompt = 1
|
|
|
|
print ' '
|
|
|
|
main()
|
|
|
|
elif validAddress(address) is False:
|
2015-01-19 18:53:07 +01:00
|
|
|
print '\n Invalid. "c" to cancel. Please try again.\n'
|
|
|
|
else:
|
|
|
|
break
|
2018-05-15 17:15:44 +02:00
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
try:
|
|
|
|
print api.leaveChan(address)
|
|
|
|
except:
|
|
|
|
print '\n Connection Error\n'
|
|
|
|
usrPrompt = 0
|
|
|
|
main()
|
|
|
|
|
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
def listAdd():
|
|
|
|
"""List all of the addresses and their info"""
|
2015-01-19 18:53:07 +01:00
|
|
|
global usrPrompt
|
|
|
|
try:
|
|
|
|
jsonAddresses = json.loads(api.listAddresses())
|
2018-05-15 17:15:44 +02:00
|
|
|
numAddresses = len(jsonAddresses['addresses']) # Number of addresses
|
2015-01-19 18:53:07 +01:00
|
|
|
except:
|
|
|
|
print '\n Connection Error\n'
|
|
|
|
usrPrompt = 0
|
|
|
|
main()
|
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
# print '\nAddress Number,Label,Address,Stream,Enabled\n'
|
2015-01-19 18:53:07 +01:00
|
|
|
print '\n --------------------------------------------------------------------------'
|
|
|
|
print ' | # | Label | Address |S#|Enabled|'
|
|
|
|
print ' |---|-------------------|-------------------------------------|--|-------|'
|
2018-05-15 17:15:44 +02:00
|
|
|
for addNum in range(0, numAddresses): # processes all of the addresses and lists them out
|
|
|
|
label = (jsonAddresses['addresses'][addNum]['label']).encode(
|
|
|
|
'utf') # may still misdiplay in some consoles
|
2015-01-19 18:53:07 +01:00
|
|
|
address = str(jsonAddresses['addresses'][addNum]['address'])
|
2018-05-15 17:15:44 +02:00
|
|
|
stream = str(jsonAddresses['addresses'][addNum]['stream'])
|
2015-01-19 18:53:07 +01:00
|
|
|
enabled = str(jsonAddresses['addresses'][addNum]['enabled'])
|
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
if len(label) > 19:
|
2015-01-19 18:53:07 +01:00
|
|
|
label = label[:16] + '...'
|
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
print ''.join(
|
|
|
|
' |',
|
|
|
|
str(addNum).ljust(3),
|
|
|
|
'|',
|
|
|
|
label.ljust(19),
|
|
|
|
'|',
|
|
|
|
address.ljust(37),
|
|
|
|
'|',
|
|
|
|
stream.ljust(1),
|
|
|
|
'|',
|
|
|
|
enabled.ljust(7),
|
|
|
|
'|',
|
|
|
|
)
|
|
|
|
|
|
|
|
print ''.join(
|
|
|
|
' ',
|
|
|
|
74 * '-',
|
|
|
|
'\n',
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def genAdd(lbl, deterministic, passphrase, numOfAdd, addVNum, streamNum, ripe):
|
|
|
|
"""Generate address"""
|
2015-01-19 18:53:07 +01:00
|
|
|
|
|
|
|
global usrPrompt
|
2018-05-15 17:15:44 +02:00
|
|
|
|
|
|
|
if deterministic is False: # Generates a new address with the user defined label. non-deterministic
|
2015-01-19 18:53:07 +01:00
|
|
|
addressLabel = lbl.encode('base64')
|
|
|
|
try:
|
|
|
|
generatedAddress = api.createRandomAddress(addressLabel)
|
|
|
|
except:
|
|
|
|
print '\n Connection Error\n'
|
|
|
|
usrPrompt = 0
|
|
|
|
main()
|
2018-05-15 17:15:44 +02:00
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
return generatedAddress
|
2018-05-15 17:15:44 +02:00
|
|
|
|
|
|
|
elif deterministic: # Generates a new deterministic address with the user inputs.
|
2015-01-19 18:53:07 +01:00
|
|
|
passphrase = passphrase.encode('base64')
|
|
|
|
try:
|
|
|
|
generatedAddress = api.createDeterministicAddresses(passphrase, numOfAdd, addVNum, streamNum, ripe)
|
|
|
|
except:
|
|
|
|
print '\n Connection Error\n'
|
|
|
|
usrPrompt = 0
|
|
|
|
main()
|
|
|
|
return generatedAddress
|
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
return 'Entry Error'
|
2015-06-20 09:54:15 +02:00
|
|
|
|
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
def saveFile(fileName, fileData):
|
|
|
|
"""Allows attachments and messages/broadcats to be saved"""
|
2015-01-19 18:53:07 +01:00
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
# This section finds all invalid characters and replaces them with ~
|
2015-01-19 18:53:07 +01:00
|
|
|
fileName = fileName.replace(" ", "")
|
|
|
|
fileName = fileName.replace("/", "~")
|
2018-05-15 17:15:44 +02:00
|
|
|
# fileName = fileName.replace("\\", "~") How do I get this to work...?
|
2015-01-19 18:53:07 +01:00
|
|
|
fileName = fileName.replace(":", "~")
|
|
|
|
fileName = fileName.replace("*", "~")
|
|
|
|
fileName = fileName.replace("?", "~")
|
|
|
|
fileName = fileName.replace('"', "~")
|
|
|
|
fileName = fileName.replace("<", "~")
|
|
|
|
fileName = fileName.replace(">", "~")
|
|
|
|
fileName = fileName.replace("|", "~")
|
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
directory = os.path.abspath('attachments')
|
2015-01-19 18:53:07 +01:00
|
|
|
|
|
|
|
if not os.path.exists(directory):
|
|
|
|
os.makedirs(directory)
|
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
filePath = os.path.join(directory, fileName)
|
2015-01-19 18:53:07 +01:00
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
with open(filePath, 'wb+') as path_to_file:
|
|
|
|
path_to_file.write(fileData.decode("base64"))
|
|
|
|
print '\n Successfully saved ' + filePath + '\n'
|
2015-01-19 18:53:07 +01:00
|
|
|
|
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
def attachment():
|
|
|
|
"""Allows users to attach a file to their message or broadcast"""
|
2015-01-19 18:53:07 +01:00
|
|
|
|
|
|
|
theAttachmentS = ''
|
2018-05-15 17:15:44 +02:00
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
while True:
|
|
|
|
|
|
|
|
isImage = False
|
|
|
|
theAttachment = ''
|
2018-05-15 17:15:44 +02:00
|
|
|
|
|
|
|
while True: # loops until valid path is entered
|
|
|
|
filePath = userInput(
|
|
|
|
'\nPlease enter the path to the attachment or just the attachment name if in this folder.')
|
2015-01-19 18:53:07 +01:00
|
|
|
|
|
|
|
try:
|
2018-05-15 17:15:44 +02:00
|
|
|
with open(filePath):
|
|
|
|
break
|
2015-01-19 18:53:07 +01:00
|
|
|
except IOError:
|
|
|
|
print '\n %s was not found on your filesystem or can not be opened.\n' % filePath
|
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
# print filesize, and encoding estimate with confirmation if file is over X size (1mb?)
|
2015-01-19 18:53:07 +01:00
|
|
|
invSize = os.path.getsize(filePath)
|
2018-05-15 17:15:44 +02:00
|
|
|
invSize = (invSize / 1024) # Converts to kilobytes
|
|
|
|
round(invSize, 2) # Rounds to two decimal places
|
|
|
|
|
|
|
|
if invSize > 500.0: # If over 500KB
|
|
|
|
print ''.join(
|
|
|
|
'\n WARNING:The file that you are trying to attach is ',
|
|
|
|
invSize,
|
|
|
|
'KB and will take considerable time to send.\n'
|
|
|
|
)
|
2015-01-19 18:53:07 +01:00
|
|
|
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 ''
|
2018-05-15 17:15:44 +02:00
|
|
|
elif invSize > 184320.0: # If larger than 180MB, discard.
|
2015-01-19 18:53:07 +01:00
|
|
|
print '\n Attachment too big, maximum allowed size:180MB\n'
|
|
|
|
main()
|
2018-05-15 17:15:44 +02:00
|
|
|
|
|
|
|
pathLen = len(str(ntpath.basename(filePath))) # Gets the length of the filepath excluding the filename
|
|
|
|
fileName = filePath[(len(str(filePath)) - pathLen):] # reads the filename
|
|
|
|
|
|
|
|
filetype = imghdr.what(filePath) # Tests if it is an image file
|
2015-01-19 18:53:07 +01:00
|
|
|
if filetype is not None:
|
|
|
|
print '\n ---------------------------------------------------'
|
|
|
|
print ' Attachment detected as an Image.'
|
|
|
|
print ' <img> tags will automatically be included,'
|
|
|
|
print ' allowing the recipient to view the image'
|
|
|
|
print ' using the "View HTML code..." option in Bitmessage.'
|
|
|
|
print ' ---------------------------------------------------\n'
|
|
|
|
isImage = True
|
|
|
|
time.sleep(2)
|
2018-05-15 17:15:44 +02:00
|
|
|
|
|
|
|
# Alert the user that the encoding process may take some time.
|
|
|
|
print '\n Encoding Attachment, Please Wait ...\n'
|
|
|
|
|
|
|
|
with open(filePath, 'rb') as f: # Begin the actual encoding
|
|
|
|
data = f.read(188743680) # Reads files up to 180MB, the maximum size for Bitmessage.
|
2015-01-19 18:53:07 +01:00
|
|
|
data = data.encode("base64")
|
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
if isImage: # If it is an image, include image tags in the message
|
2015-01-19 18:53:07 +01:00
|
|
|
theAttachment = """
|
|
|
|
<!-- Note: Image attachment below. Please use the right click "View HTML code ..." option to view it. -->
|
|
|
|
<!-- Sent using Bitmessage Daemon. https://github.com/Dokument/PyBitmessage-Daemon -->
|
2018-05-15 17:15:44 +02:00
|
|
|
|
|
|
|
Filename:%s
|
|
|
|
Filesize:%sKB
|
|
|
|
Encoding:base64
|
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
<center>
|
|
|
|
<div id="image">
|
|
|
|
<img alt = "%s" src='data:image/%s;base64, %s' />
|
|
|
|
</div>
|
2018-05-15 17:15:44 +02:00
|
|
|
</center>""" % (fileName, invSize, fileName, filetype, data)
|
|
|
|
else: # Else it is not an image so do not include the embedded image code.
|
2015-01-19 18:53:07 +01:00
|
|
|
theAttachment = """
|
|
|
|
<!-- Note: File attachment below. Please use a base64 decoder, or Daemon, to save it. -->
|
|
|
|
<!-- Sent using Bitmessage Daemon. https://github.com/Dokument/PyBitmessage-Daemon -->
|
2018-05-15 17:15:44 +02:00
|
|
|
|
|
|
|
Filename:%s
|
|
|
|
Filesize:%sKB
|
|
|
|
Encoding:base64
|
|
|
|
|
|
|
|
<attachment alt = "%s" src='data:file/%s;base64, %s' />""" % (fileName, invSize, fileName, fileName, data)
|
2015-01-19 18:53:07 +01:00
|
|
|
|
|
|
|
uInput = userInput('Would you like to add another attachment, (Y)es or (N)o?').lower()
|
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
if uInput == 'y' or uInput == 'yes': # Allows multiple attachments to be added to one message
|
|
|
|
theAttachmentS = str(theAttachmentS) + str(theAttachment) + '\n\n'
|
|
|
|
elif uInput == 'n' or uInput == 'no':
|
2015-01-19 18:53:07 +01:00
|
|
|
break
|
2018-05-15 17:15:44 +02:00
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
theAttachmentS = theAttachmentS + theAttachment
|
|
|
|
return theAttachmentS
|
|
|
|
|
2018-05-15 17:15:44 +02:00
|
|
|
|
|
|
|
def sendMsg(toAddress, fromAddress, subject, message):
|
|
|
|
"""
|
|
|
|
With no arguments sent, sendMsg fills in the blanks.
|
|
|
|
subject and message must be encoded before they are passed.
|
|
|
|
"""
|
|
|
|
|
2015-01-19 18:53:07 +01:00
|
|
|
global usrPrompt
|
2018-05-15 17:15:44 +02:00
|
|
|
if validAddress(toAddress) is False:
|
2015-01-19 18:53:07 +01:00
|
|
|
while True:
|
|
|
|
|