@ -26,7 +26,7 @@ from pyelliptic.openssl import OpenSSL
from struct import pack
# Classes
from helper_sql import sqlQuery , sqlExecute , SqlBulkExecute
from helper_sql import sqlQuery , sqlExecute , SqlBulkExecute , sqlStoredProcedure
from debug import logger
# Helper Functions
@ -149,16 +149,218 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
return ( status , addressVersionNumber , streamNumber , ripe )
#Request Handlers
def HandleListAddresses ( self , method ) :
data = ' { " addresses " :[ '
configSections = shared . config . sections ( )
for addressInKeysFile in configSections :
if addressInKeysFile != ' bitmessagesettings ' :
status , addressVersionNumber , streamNumber , hash01 = decodeAddress (
addressInKeysFile )
def _handle_request ( self , method , params ) :
if method == ' helloWorld ' :
( a , b ) = params
return a + ' - ' + b
elif method == ' add ' :
( a , b ) = params
return a + b
elif method == ' statusBar ' :
message , = params
shared . UISignalQueue . put ( ( ' updateStatusBar ' , message ) )
elif method == ' listAddresses ' or method == ' listAddresses2 ' :
data = ' { " addresses " :[ '
configSections = shared . config . sections ( )
for addressInKeysFile in configSections :
if addressInKeysFile != ' bitmessagesettings ' :
status , addressVersionNumber , streamNumber , hash01 = decodeAddress (
addressInKeysFile )
if len ( data ) > 20 :
data + = ' , '
if shared . config . has_option ( addressInKeysFile , ' chan ' ) :
chan = shared . config . getboolean ( addressInKeysFile , ' chan ' )
else :
chan = False
label = shared . config . get ( addressInKeysFile , ' label ' )
if method == ' listAddresses2 ' :
label = label . encode ( ' base64 ' )
data + = json . dumps ( { ' label ' : label , ' address ' : addressInKeysFile , ' stream ' :
streamNumber , ' enabled ' : shared . config . getboolean ( addressInKeysFile , ' enabled ' ) , ' chan ' : chan } , indent = 4 , separators = ( ' , ' , ' : ' ) )
data + = ' ]} '
return data
elif method == ' listAddressBookEntries ' or method == ' listAddressbook ' : # the listAddressbook alias should be removed eventually.
queryreturn = sqlQuery ( ''' SELECT label, address from addressbook ''' )
if len ( params ) == 1 :
label , = params
label = self . _decode ( label , " base64 " )
queryreturn = sqlQuery ( ''' SELECT label, address from addressbook WHERE label = ? ''' , label )
elif len ( params ) > 1 :
raise APIError ( 0 , " Too many paremeters, max 1 " )
data = ' { " addresses " :[ '
for row in queryreturn :
label , address = row
label = shared . fixPotentiallyInvalidUTF8Data ( label )
if len ( data ) > 20 :
data + = ' , '
data + = json . dumps ( { ' label ' : label . encode ( ' base64 ' ) , ' address ' : address } , indent = 4 , separators = ( ' , ' , ' : ' ) )
data + = ' ]} '
return data
elif method == ' getAddressBookEntry ' : # search by label
if len ( params ) != 1 :
raise APIError ( 0 , " I need a label " )
label , = params
label = self . _decode ( label , " base64 " )
queryreturn = sqlQuery ( ''' SELECT label, address from addressbook WHERE label = ? ''' , label )
data = ' { " address " :[ '
for row in queryreturn :
label , address = row
label = shared . fixPotentiallyInvalidUTF8Data ( label )
if len ( data ) > 20 :
data + = ' , '
data + = json . dumps ( { ' label ' : label . encode ( ' base64 ' ) , ' address ' : address } , indent = 4 , separators = ( ' , ' , ' : ' ) )
data + = ' ]} '
return data
elif method == ' addAddressBookEntry ' or method == ' addAddressbook ' : # the addAddressbook alias should be deleted eventually.
if len ( params ) != 2 :
raise APIError ( 0 , " I need label and address " )
address , label = params
label = self . _decode ( label , " base64 " )
address = addBMIfNotPresent ( address )
self . _verifyAddress ( address )
queryreturn = sqlQuery ( " SELECT address FROM addressbook WHERE address=? " , address )
if queryreturn != [ ] :
raise APIError ( 16 , ' You already have this address in your address book. ' )
sqlExecute ( " INSERT INTO addressbook VALUES(?,?) " , label , address )
shared . UISignalQueue . put ( ( ' rerenderInboxFromLabels ' , ' ' ) )
shared . UISignalQueue . put ( ( ' rerenderSentToLabels ' , ' ' ) )
shared . UISignalQueue . put ( ( ' rerenderAddressBook ' , ' ' ) )
return " Added address %s to address book " % address
elif method == ' deleteAddressBookEntry ' or method == ' deleteAddressbook ' : # The deleteAddressbook alias should be deleted eventually.
if len ( params ) != 1 :
raise APIError ( 0 , " I need an address " )
address , = params
address = addBMIfNotPresent ( address )
self . _verifyAddress ( address )
sqlExecute ( ' DELETE FROM addressbook WHERE address=? ' , address )
shared . UISignalQueue . put ( ( ' rerenderInboxFromLabels ' , ' ' ) )
shared . UISignalQueue . put ( ( ' rerenderSentToLabels ' , ' ' ) )
shared . UISignalQueue . put ( ( ' rerenderAddressBook ' , ' ' ) )
return " Deleted address book entry for %s if it existed " % address
elif method == ' createRandomAddress ' :
if len ( params ) == 0 :
raise APIError ( 0 , ' I need parameters! ' )
elif len ( params ) == 1 :
label , = params
eighteenByteRipe = False
nonceTrialsPerByte = shared . config . get (
' bitmessagesettings ' , ' defaultnoncetrialsperbyte ' )
payloadLengthExtraBytes = shared . config . get (
' bitmessagesettings ' , ' defaultpayloadlengthextrabytes ' )
elif len ( params ) == 2 :
label , eighteenByteRipe = params
nonceTrialsPerByte = shared . config . get (
' bitmessagesettings ' , ' defaultnoncetrialsperbyte ' )
payloadLengthExtraBytes = shared . config . get (
' bitmessagesettings ' , ' defaultpayloadlengthextrabytes ' )
elif len ( params ) == 3 :
label , eighteenByteRipe , totalDifficulty = params
nonceTrialsPerByte = int (
shared . networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty )
payloadLengthExtraBytes = shared . config . get (
' bitmessagesettings ' , ' defaultpayloadlengthextrabytes ' )
elif len ( params ) == 4 :
label , eighteenByteRipe , totalDifficulty , smallMessageDifficulty = params
nonceTrialsPerByte = int (
shared . networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty )
payloadLengthExtraBytes = int (
shared . networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty )
else :
raise APIError ( 0 , ' Too many parameters! ' )
label = self . _decode ( label , " base64 " )
try :
unicode ( label , ' utf-8 ' )
except :
raise APIError ( 17 , ' Label is not valid UTF-8 data. ' )
shared . apiAddressGeneratorReturnQueue . queue . clear ( )
streamNumberForAddress = 1
shared . addressGeneratorQueue . put ( (
' createRandomAddress ' , 4 , streamNumberForAddress , label , 1 , " " , eighteenByteRipe , nonceTrialsPerByte , payloadLengthExtraBytes ) )
return shared . apiAddressGeneratorReturnQueue . get ( )
elif method == ' createDeterministicAddresses ' :
if len ( params ) == 0 :
raise APIError ( 0 , ' I need parameters! ' )
elif len ( params ) == 1 :
passphrase , = params
numberOfAddresses = 1
addressVersionNumber = 0
streamNumber = 0
eighteenByteRipe = False
nonceTrialsPerByte = shared . config . get (
' bitmessagesettings ' , ' defaultnoncetrialsperbyte ' )
payloadLengthExtraBytes = shared . config . get (
' bitmessagesettings ' , ' defaultpayloadlengthextrabytes ' )
elif len ( params ) == 2 :
passphrase , numberOfAddresses = params
addressVersionNumber = 0
streamNumber = 0
eighteenByteRipe = False
nonceTrialsPerByte = shared . config . get (
' bitmessagesettings ' , ' defaultnoncetrialsperbyte ' )
payloadLengthExtraBytes = shared . config . get (
' bitmessagesettings ' , ' defaultpayloadlengthextrabytes ' )
elif len ( params ) == 3 :
passphrase , numberOfAddresses , addressVersionNumber = params
streamNumber = 0
eighteenByteRipe = False
nonceTrialsPerByte = shared . config . get (
' bitmessagesettings ' , ' defaultnoncetrialsperbyte ' )
payloadLengthExtraBytes = shared . config . get (
' bitmessagesettings ' , ' defaultpayloadlengthextrabytes ' )
elif len ( params ) == 4 :
passphrase , numberOfAddresses , addressVersionNumber , streamNumber = params
eighteenByteRipe = False
nonceTrialsPerByte = shared . config . get (
' bitmessagesettings ' , ' defaultnoncetrialsperbyte ' )
payloadLengthExtraBytes = shared . config . get (
' bitmessagesettings ' , ' defaultpayloadlengthextrabytes ' )
elif len ( params ) == 5 :
passphrase , numberOfAddresses , addressVersionNumber , streamNumber , eighteenByteRipe = params
nonceTrialsPerByte = shared . config . get (
' bitmessagesettings ' , ' defaultnoncetrialsperbyte ' )
payloadLengthExtraBytes = shared . config . get (
' bitmessagesettings ' , ' defaultpayloadlengthextrabytes ' )
elif len ( params ) == 6 :
passphrase , numberOfAddresses , addressVersionNumber , streamNumber , eighteenByteRipe , totalDifficulty = params
nonceTrialsPerByte = int (
shared . networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty )
payloadLengthExtraBytes = shared . config . get (
' bitmessagesettings ' , ' defaultpayloadlengthextrabytes ' )
elif len ( params ) == 7 :
passphrase , numberOfAddresses , addressVersionNumber , streamNumber , eighteenByteRipe , totalDifficulty , smallMessageDifficulty = params
nonceTrialsPerByte = int (
shared . networkDefaultProofOfWorkNonceTrialsPerByte * totalDifficulty )
payloadLengthExtraBytes = int (
shared . networkDefaultPayloadLengthExtraBytes * smallMessageDifficulty )
else :
raise APIError ( 0 , ' Too many parameters! ' )
if len ( passphrase ) == 0 :
raise APIError ( 1 , ' The specified passphrase is blank. ' )
if not isinstance ( eighteenByteRipe , bool ) :
raise APIError ( 23 , ' Bool expected in eighteenByteRipe, saw %s instead ' % type ( eighteenByteRipe ) )
passphrase = self . _decode ( passphrase , " base64 " )
if addressVersionNumber == 0 : # 0 means "just use the proper addressVersionNumber"
addressVersionNumber = 4
if addressVersionNumber != 3 and addressVersionNumber != 4 :
raise APIError ( 2 , ' The address version number currently must be 3, 4, or 0 (which means auto-select). ' + addressVersionNumber + ' isn \' t supported. ' )
if streamNumber == 0 : # 0 means "just use the most available stream"
streamNumber = 1
if streamNumber != 1 :
raise APIError ( 3 , ' The stream number must be 1 (or 0 which means auto-select). Others aren \' t supported. ' )
if numberOfAddresses == 0 :
raise APIError ( 4 , ' Why would you ask me to generate 0 addresses for you? ' )
if numberOfAddresses > 999 :
raise APIError ( 5 , ' You have (accidentally?) specified too many addresses to make. Maximum 999. This check only exists to prevent mischief; if you really want to create more addresses than this, contact the Bitmessage developers and we can modify the check or you can do it yourself by searching the source code for this message. ' )
shared . apiAddressGeneratorReturnQueue . queue . clear ( )
logger . debug ( ' Requesting that the addressGenerator create %s addresses. ' , numberOfAddresses )
shared . addressGeneratorQueue . put (
( ' createDeterministicAddresses ' , addressVersionNumber , streamNumber ,
' unused API address ' , numberOfAddresses , passphrase , eighteenByteRipe , nonceTrialsPerByte , payloadLengthExtraBytes ) )
data = ' { " addresses " :[ '
queueReturn = shared . apiAddressGeneratorReturnQueue . get ( )
for item in queueReturn :
if len ( data ) > 20 :
data + = ' , '
if shared . config . has_option ( addressInKeysFile , ' chan ' ) :
@ -908,108 +1110,73 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
''' SELECT hash, payload FROM inventory WHERE tag = ' ' and objecttype = 2 ; ''' )
with SqlBulkExecute ( ) as sql :
for row in queryreturn :
hash01 , payload = row
readPosition = 16 # Nonce length + time length
readPosition + = decodeVarint ( payload [ readPosition : readPosition + 10 ] ) [ 1 ] # Stream Number length
t = ( payload [ readPosition : readPosition + 32 ] , hash01 )
sql . execute ( ''' UPDATE inventory SET tag=? WHERE hash=?; ''' , * t )
queryreturn = sqlQuery ( ''' SELECT payload FROM inventory WHERE tag = ? ''' ,
requestedHash )
data = ' { " receivedMessageDatas " :[ '
for row in queryreturn :
payload , = row
if len ( data ) > 25 :
data + = ' , '
data + = json . dumps ( { ' data ' : payload . encode ( ' hex ' ) } , indent = 4 , separators = ( ' , ' , ' : ' ) )
data + = ' ]} '
return data
def HandleClientStatus ( self , params ) :
if len ( shared . connectedHostsList ) == 0 :
networkStatus = ' notConnected '
elif len ( shared . connectedHostsList ) > 0 and not shared . clientHasReceivedIncomingConnections :
networkStatus = ' connectedButHaveNotReceivedIncomingConnections '
else :
networkStatus = ' connectedAndReceivingIncomingConnections '
return json . dumps ( { ' networkConnections ' : len ( shared . connectedHostsList ) , ' numberOfMessagesProcessed ' : shared . numberOfMessagesProcessed , ' numberOfBroadcastsProcessed ' : shared . numberOfBroadcastsProcessed , ' numberOfPubkeysProcessed ' : shared . numberOfPubkeysProcessed , ' networkStatus ' : networkStatus , ' softwareName ' : ' PyBitmessage ' , ' softwareVersion ' : shared . softwareVersion } , indent = 4 , separators = ( ' , ' , ' : ' ) )
def HandleDecodeAddress ( self , params ) :
# Return a meaningful decoding of an address.
if len ( params ) != 1 :
raise APIError ( 0 , ' I need 1 parameter! ' )
address , = params
status , addressVersion , streamNumber , ripe = decodeAddress ( address )
return json . dumps ( { ' status ' : status , ' addressVersion ' : addressVersion ,
' streamNumber ' : streamNumber , ' ripe ' : ripe . encode ( ' base64 ' ) } , indent = 4 ,
separators = ( ' , ' , ' : ' ) )
def HandleHelloWorld ( self , params ) :
( a , b ) = params
return a + ' - ' + b
def HandleAdd ( self , params ) :
( a , b ) = params
return a + b
def HandleStatusBar ( self , params ) :
message , = params
shared . UISignalQueue . put ( ( ' updateStatusBar ' , message ) )
handlers = { }
handlers [ ' helloWorld ' ] = HandleHelloWorld
handlers [ ' add ' ] = HandleAdd
handlers [ ' statusBar ' ] = HandleStatusBar
handlers [ ' listAddresses ' ] = HandleListAddresses
handlers [ ' listAddressBookEntries ' ] = HandleListAddressBookEntries ;
handlers [ ' listAddressbook ' ] = HandleListAddressBookEntries # the listAddressbook alias should be removed eventually.
handlers [ ' addAddressBookEntry ' ] = HandleAddAddressBookEntry
handlers [ ' addAddressbook ' ] = HandleAddAddressBookEntry # the addAddressbook alias should be deleted eventually.
handlers [ ' deleteAddressBookEntry ' ] = HandleDeleteAddressBookEntry
handlers [ ' deleteAddressbook ' ] = HandleDeleteAddressBookEntry # The deleteAddressbook alias should be deleted eventually.
handlers [ ' createRandomAddress ' ] = HandleCreateRandomAddress
handlers [ ' createDeterministicAddresses ' ] = HandleCreateDeterministicAddresses
handlers [ ' getDeterministicAddress ' ] = HandleGetDeterministicAddress
handlers [ ' createChan ' ] = HandleCreateChan
handlers [ ' joinChan ' ] = HandleJoinChan
handlers [ ' leaveChan ' ] = HandleLeaveChan
handlers [ ' deleteAddress ' ] = HandleDeleteAddress
handlers [ ' getAllInboxMessages ' ] = HandleGetAllInboxMessages
handlers [ ' getAllInboxMessageIds ' ] = HandleGetAllInboxMessageIds
handlers [ ' getAllInboxMessageIDs ' ] = HandleGetAllInboxMessageIds
handlers [ ' getInboxMessageById ' ] = HandleGetInboxMessageById
handlers [ ' getInboxMessageByID ' ] = HandleGetInboxMessageById
handlers [ ' getAllSentMessages ' ] = HandleGetAllSentMessages
handlers [ ' getAllSentMessageIds ' ] = HandleGetAllSentMessageIds
handlers [ ' getAllSentMessageIDs ' ] = HandleGetAllSentMessageIds
handlers [ ' getInboxMessagesByReceiver ' ] = HandleInboxMessagesByReceiver
handlers [ ' getInboxMessagesByAddress ' ] = HandleInboxMessagesByReceiver #after some time getInboxMessagesByAddress should be removed
handlers [ ' getSentMessageById ' ] = HandleGetSentMessageById
handlers [ ' getSentMessageByID ' ] = HandleGetSentMessageById
handlers [ ' getSentMessagesByAddress ' ] = HandleGetSentMessagesByAddress
handlers [ ' getSentMessagesBySender ' ] = HandleGetSentMessagesByAddress
handlers [ ' getSentMessageByAckData ' ] = HandleGetSentMessagesByAckData
handlers [ ' trashMessage ' ] = HandleTrashMessage
handlers [ ' trashInboxMessage ' ] = HandleTrashInboxMessage
handlers [ ' trashSentMessage ' ] = HandleTrashSentMessage
handlers [ ' trashSentMessageByAckData ' ] = HandleTrashSentMessageByAckDAta
handlers [ ' sendMessage ' ] = HandleSendMessage
handlers [ ' sendBroadcast ' ] = HandleSendBroadcast
handlers [ ' getStatus ' ] = HandleGetStatus
handlers [ ' addSubscription ' ] = HandleAddSubscription
handlers [ ' deleteSubscription ' ] = HandleDeleteSubscription
handlers [ ' listSubscriptions ' ] = ListSubscriptions
handlers [ ' disseminatePreEncryptedMsg ' ] = HandleDisseminatePreEncryptedMsg
handlers [ ' disseminatePubkey ' ] = HandleDissimatePubKey
handlers [ ' getMessageDataByDestinationHash ' ] = HandleGetMessageDataByDestinationHash
handlers [ ' getMessageDataByDestinationTag ' ] = HandleGetMessageDataByDestinationHash
handlers [ ' clientStatus ' ] = HandleClientStatus
handlers [ ' decodeAddress ' ] = HandleDecodeAddress
def _handle_request ( self , method , params ) :
if ( self . handlers . has_key ( method ) ) :
return self . handlers [ method ] ( self , params )
transmitdata , = row
data + = json . dumps ( { ' data ' : transmitdata . encode ( ' hex ' ) } , indent = 4 , separators = ( ' , ' , ' : ' ) )
data + = ' ]} '
return data
elif method == ' clientStatus ' :
if len ( shared . connectedHostsList ) == 0 :
networkStatus = ' notConnected '
elif len ( shared . connectedHostsList ) > 0 and not shared . clientHasReceivedIncomingConnections :
networkStatus = ' connectedButHaveNotReceivedIncomingConnections '
else :
networkStatus = ' connectedAndReceivingIncomingConnections '
return json . dumps ( { ' networkConnections ' : len ( shared . connectedHostsList ) , ' numberOfMessagesProcessed ' : shared . numberOfMessagesProcessed , ' numberOfBroadcastsProcessed ' : shared . numberOfBroadcastsProcessed , ' numberOfPubkeysProcessed ' : shared . numberOfPubkeysProcessed , ' networkStatus ' : networkStatus , ' softwareName ' : ' PyBitmessage ' , ' softwareVersion ' : shared . softwareVersion } , indent = 4 , separators = ( ' , ' , ' : ' ) )
elif method == ' decodeAddress ' :
# Return a meaningful decoding of an address.
if len ( params ) != 1 :
raise APIError ( 0 , ' I need 1 parameter! ' )
address , = params
status , addressVersion , streamNumber , ripe = decodeAddress ( address )
return json . dumps ( { ' status ' : status , ' addressVersion ' : addressVersion ,
' streamNumber ' : streamNumber , ' ripe ' : ripe . encode ( ' base64 ' ) } , indent = 4 ,
separators = ( ' , ' , ' : ' ) )
elif method == ' getInboxCount ' :
#queryreturn = sqlQuery('''SELECT read, received < 'now' - 60 AS old, COUNT (*) AS cnt FROM inbox WHERE folder = 'inbox' GROUP BY read, old''')
ret = { }
queryreturn = sqlQuery ( ''' SELECT COUNT (*) AS cnt FROM inbox WHERE folder = ' inbox ' AND read = 0 AND received < ' now ' - 60 ''' )
for row in queryreturn :
count , = row
ret [ ' oldread ' ] = count
queryreturn = sqlQuery ( ''' SELECT COUNT (*) AS cnt FROM inbox WHERE folder = ' inbox ' AND read = 1 AND received < ' now ' - 60 ''' )
for row in queryreturn :
count , = row
ret [ ' oldunread ' ] = count
queryreturn = sqlQuery ( ''' SELECT COUNT (*) AS cnt FROM inbox WHERE folder = ' inbox ' AND read = 0 AND received >= ' now ' - 60 ''' )
for row in queryreturn :
count , = row
ret [ ' newread ' ] = count
queryreturn = sqlQuery ( ''' SELECT COUNT (*) AS cnt FROM inbox WHERE folder = ' inbox ' AND read = 1 AND received >= ' now ' - 60 ''' )
for row in queryreturn :
count , = row
ret [ ' newunread ' ] = count
data = ' { " inboxCount " : { '
for key in ret :
val = ret [ key ]
if len ( data ) > 16 :
data + = ' , '
data + = json . dumps ( { key : val } , indent = 4 , separators = ( ' , ' , ' : ' ) )
data + = ' }} '
elif method == ' getSentCount ' :
ret = { }
queryreturn = sqlQuery ( ''' SELECT COUNT (*) AS cnt FROM sent WHERE folder = ' sent ' AND status = ' msgqueued ' ''' )
for row in queryreturn :
count , = row
ret [ ' queued ' ] = count
queryreturn = sqlQuery ( ''' SELECT COUNT (*) AS cnt FROM sent WHERE folder = ' sent ' AND status = ' msgsent ' ''' )
for row in queryreturn :
count , = row
ret [ ' awaitingack ' ] = count
data = ' { " sentCount " : { '
for key in ret :
val = ret [ key ]
if len ( data ) > 15 :
data + = ' , '
data + = json . dumps ( { key : val } , indent = 4 , separators = ( ' , ' , ' : ' ) )
data + = ' }} '
elif method == ' deleteAndVacuum ' :
sqlStoredProcedure ( ' deleteandvacuume ' )
return ' done '
else :
raise APIError ( 20 , ' Invalid method: %s ' % method )