@ -20,6 +20,7 @@
# SOFTWARE.
import base64
import httplib
import json
import socket
import sys
@ -28,6 +29,11 @@ import os
import shared
import tr # translate
# FIXME: from debug import logger crashes PyBitmessage due to a circular
# dependency. The debug module will also override/disable logging.getLogger()
# loggers so module level logging functions are used instead
import logging as logger
configSection = " bitmessagesettings "
# Error thrown when the RPC call returns an error.
@ -36,6 +42,9 @@ class RPCError (Exception):
def __init__ ( self , data ) :
self . error = data
def __str__ ( self ) :
return ' {0} : {1} ' . format ( type ( self ) . __name__ , self . error )
# This class handles the Namecoin identity integration.
class namecoinConnection ( object ) :
@ -46,6 +55,7 @@ class namecoinConnection (object):
nmctype = None
bufsize = 4096
queryid = 1
con = None
# Initialise. If options are given, take the connection settings from
# them instead of loading from the configs. This can be used to test
@ -55,18 +65,20 @@ class namecoinConnection (object):
if options is None :
self . nmctype = shared . config . get ( configSection , " namecoinrpctype " )
self . host = shared . config . get ( configSection , " namecoinrpchost " )
self . port = shared . config . get ( configSection , " namecoinrpcport " )
self . port = int ( shared . config . get ( configSection , " namecoinrpcport " ) )
self . user = shared . config . get ( configSection , " namecoinrpcuser " )
self . password = shared . config . get ( configSection ,
" namecoinrpcpassword " )
else :
self . nmctype = options [ " type " ]
self . host = options [ " host " ]
self . port = options [ " port " ]
self . port = int ( options [ " port " ] )
self . user = options [ " user " ]
self . password = options [ " password " ]
assert self . nmctype == " namecoind " or self . nmctype == " nmcontrol "
if self . nmctype == " namecoind " :
self . con = httplib . HTTPConnection ( self . host , self . port , timeout = 3 )
# Query for the bitmessage address corresponding to the given identity
# string. If it doesn't contain a slash, id/ is prepended. We return
@ -85,21 +97,24 @@ class namecoinConnection (object):
res = self . callRPC ( " data " , [ " getValue " , string ] )
res = res [ " reply " ]
if res == False :
r aise RPCError ( { " code " : - 4 } )
r eturn ( tr . _translate ( " MainWindow " , ' The name % 1 was not found. ' ) . arg ( unicode ( string ) ) , None )
else :
assert False
except RPCError as exc :
if exc . error [ " code " ] == - 4 :
return ( tr . _translate ( " MainWindow " , ' The name % 1 was not found. ' ) . arg ( unicode ( string ) ) , None )
logger . exception ( " Namecoin query RPC exception " )
if isinstance ( exc . error , dict ) :
errmsg = exc . error [ " message " ]
else :
return ( tr . _translate ( " MainWindow " , ' The namecoin query failed ( % 1) ' ) . arg ( unicode ( exc . error [ " message " ] ) ) , None )
errmsg = exc . error
return ( tr . _translate ( " MainWindow " , ' The namecoin query failed ( % 1) ' ) . arg ( unicode ( errmsg ) ) , None )
except Exception as exc :
print " Namecoin query exception: %s " % str ( exc )
logger . exception ( " Namecoin query exception " )
return ( tr . _translate ( " MainWindow " , ' The namecoin query failed. ' ) , None )
try :
val = json . loads ( res )
except :
logger . exception ( " Namecoin query json exception " )
return ( tr . _translate ( " MainWindow " , ' The name % 1 has no valid JSON data. ' ) . arg ( unicode ( string ) ) , None )
if " bitmessage " in val :
@ -132,14 +147,14 @@ class namecoinConnection (object):
if ( " reply " in res ) and res [ " reply " ] [ : len ( prefix ) ] == prefix :
return ( ' success ' , tr . _translate ( " MainWindow " , ' Success! NMControll is up and running. ' ) )
print " Unexpected nmcontrol reply: %s " % res
logger . error ( " Unexpected nmcontrol reply: %s " , res )
return ( ' failed ' , tr . _translate ( " MainWindow " , ' Couldn \' t understand NMControl. ' ) )
else :
assert False
except Exception as exc :
print " Namecoin connection test: %s " % str ( exc )
except Exception :
logger . exception ( " Namecoin connection test failure " )
return ( ' failed ' , " The connection to namecoin failed. " )
# Helper routine that actually performs an JSON RPC call.
@ -155,35 +170,43 @@ class namecoinConnection (object):
if val [ " id " ] != self . queryid :
raise Exception ( " ID mismatch in JSON RPC answer. " )
self . queryid = self . queryid + 1
if self . nmctype == " namecoind " :
self . queryid = self . queryid + 1
if val [ " error " ] is not None :
raise RPCError ( val [ " error " ] )
error = val [ " error " ]
if error is None :
return val [ " result " ]
return val [ " result " ]
if isinstance ( error , bool ) :
raise RPCError ( val [ " result " ] )
raise RPCError ( error )
# Query the server via HTTP.
def queryHTTP ( self , data ) :
header = " POST / HTTP/1.1 \n "
header + = " User-Agent: bitmessage \n "
header + = " Host: %s \n " % self . host
header + = " Content-Type: application/json \n "
header + = " Content-Length: %d \n " % len ( data )
header + = " Accept: application/json \n "
authstr = " %s : %s " % ( self . user , self . password )
header + = " Authorization: Basic %s \n " % base64 . b64encode ( authstr )
resp = self . queryServer ( " %s \n %s " % ( header , data ) )
lines = resp . split ( " \r \n " )
result = None
body = False
for line in lines :
if line == " " and not body :
body = True
elif body :
if result is not None :
raise Exception ( " Expected a single line in HTTP response. " )
result = line
try :
self . con . putrequest ( " POST " , " / " )
self . con . putheader ( " Connection " , " Keep-Alive " )
self . con . putheader ( " User-Agent " , " bitmessage " )
self . con . putheader ( " Host " , self . host )
self . con . putheader ( " Content-Type " , " application/json " )
self . con . putheader ( " Content-Length " , str ( len ( data ) ) )
self . con . putheader ( " Accept " , " application/json " )
authstr = " %s : %s " % ( self . user , self . password )
self . con . putheader ( " Authorization " , " Basic %s " % base64 . b64encode ( authstr ) )
self . con . endheaders ( )
self . con . send ( data )
try :
resp = self . con . getresponse ( )
result = resp . read ( )
if resp . status != 200 :
raise Exception ( " Namecoin returned status %i : %s " , resp . status , resp . reason )
except :
logger . error ( " HTTP receive error " )
except :
logger . error ( " HTTP connection error " )
return result
@ -193,7 +216,7 @@ class namecoinConnection (object):
s = socket . socket ( socket . AF_INET , socket . SOCK_STREAM )
s . setsockopt ( socket . SOL_SOCKET , socket . SO_REUSEADDR , 1 )
s . settimeout ( 3 )
s . connect ( ( self . host , int ( self . port ) ) )
s . connect ( ( self . host , self . port ) )
s . sendall ( data )
result = " "
@ -270,7 +293,7 @@ def ensureNamecoinOptions ():
nmc . close ( )
except Exception as exc :
print " Could not read the Namecoin config file probably because you don ' t have Namecoin installed. That ' s ok; we don ' t really need it. Detailed error message: %s " % str ( exc )
logger . warning ( " Error processing namecoin.conf " , exc_info = True )
# If still nothing found, set empty at least.
if ( not hasUser ) :