2014-04-18 07:48:42 +02:00
# Copyright (c) 2014 Luke Montalvo <lukemontalvo@gmail.com>
2014-04-29 07:10:33 +02:00
# This file adds a alternative commandline interface, feel free to critique and fork
2014-04-19 20:45:37 +02:00
#
2014-04-29 07:10:33 +02:00
# This has only been tested on Arch Linux
2014-04-19 20:45:37 +02:00
# Dependencies:
# * from python2-pip
# * python2-pythondialog
# * dialog
2014-04-18 07:48:42 +02:00
import os
import sys
import StringIO
2014-04-19 20:45:37 +02:00
import time
from time import strftime , localtime
from threading import Timer
import curses
import dialog
from dialog import Dialog
2014-04-29 07:10:33 +02:00
from helper_sql import *
2014-04-19 20:45:37 +02:00
import shared
import ConfigParser
2014-04-18 07:48:42 +02:00
from addresses import *
2014-04-29 07:10:33 +02:00
from pyelliptic . openssl import OpenSSL
2014-04-18 07:48:42 +02:00
quit = False
menutab = 1
menu = [ " Inbox " , " Send " , " Sent " , " Your Identities " , " Subscriptions " , " Address Book " , " Blacklist " , " Network Status " ]
2014-04-19 20:57:08 +02:00
naptime = 100
2014-04-18 07:48:42 +02:00
log = " "
2014-04-19 20:45:37 +02:00
logpad = None
inventorydata = 0
startuptime = time . time ( )
2014-04-29 07:10:33 +02:00
inbox = [ ]
inboxcur = 0
2014-04-30 04:45:41 +02:00
sentbox = [ ]
2014-04-29 07:10:33 +02:00
sentcur = 0
2014-04-18 07:48:42 +02:00
addresses = [ ]
addrcur = 0
2014-04-19 20:45:37 +02:00
addrcopy = 0
2014-04-29 07:10:33 +02:00
subscriptions = [ ]
subcur = 0
addrbook = [ ]
abookcur = 0
blacklist = [ ]
blackcur = 0
2014-04-30 04:45:41 +02:00
bwtype = " black "
2014-04-29 07:10:33 +02:00
BROADCAST_STR = " [Broadcast subscribers] "
2014-04-18 07:48:42 +02:00
class printLog :
def write ( self , output ) :
global log
log + = output
2014-04-19 20:45:37 +02:00
def flush ( self ) :
pass
class errLog :
def write ( self , output ) :
global log
log + = " ! " + output
def flush ( self ) :
pass
2014-04-18 07:48:42 +02:00
printlog = printLog ( )
2014-04-19 20:45:37 +02:00
errlog = errLog ( )
2014-04-18 07:48:42 +02:00
def cpair ( a ) :
r = curses . color_pair ( a )
if r not in range ( 1 , curses . COLOR_PAIRS - 1 ) :
r = curses . color_pair ( 0 )
return r
2014-04-29 07:10:33 +02:00
def ascii ( s ) :
r = " "
for c in s :
if ord ( c ) in range ( 128 ) :
r + = c
return r
2014-04-18 07:48:42 +02:00
def drawmenu ( stdscr ) :
menustr = " "
for i in range ( 0 , len ( menu ) ) :
if menutab == i + 1 :
menustr = menustr [ : - 1 ]
menustr + = " [ "
menustr + = str ( i + 1 ) + menu [ i ]
if menutab == i + 1 :
menustr + = " ] "
elif i != len ( menu ) - 1 :
menustr + = " "
stdscr . addstr ( 2 , 5 , menustr , curses . A_UNDERLINE )
2014-04-19 20:45:37 +02:00
def resetlookups ( ) :
2014-04-29 07:10:33 +02:00
global inventorydata
2014-04-19 20:45:37 +02:00
inventorydata = shared . numberOfInventoryLookupsPerformed
shared . numberOfInventoryLookupsPerformed = 0
2014-04-29 07:10:33 +02:00
Timer ( 1 , resetlookups , ( ) ) . start ( )
2014-04-18 07:48:42 +02:00
def drawtab ( stdscr ) :
2014-04-19 20:45:37 +02:00
if menutab in range ( 1 , len ( menu ) + 1 ) :
2014-04-18 07:48:42 +02:00
if menutab == 1 : # Inbox
2014-04-29 07:10:33 +02:00
stdscr . addstr ( 3 , 5 , " To " , curses . A_BOLD )
2014-04-30 04:45:41 +02:00
stdscr . addstr ( 3 , 40 , " From " , curses . A_BOLD )
stdscr . addstr ( 3 , 80 , " Subject " , curses . A_BOLD )
stdscr . addstr ( 3 , 120 , " Time Received " , curses . A_BOLD )
stdscr . hline ( 4 , 5 , ' - ' , 121 )
2014-04-29 07:10:33 +02:00
for i , item in enumerate ( inbox [ max ( min ( len ( inbox ) - curses . LINES + 6 , inboxcur - 5 ) , 0 ) : ] ) :
if 6 + i < curses . LINES :
a = 0
if i == inboxcur - max ( min ( len ( inbox ) - curses . LINES + 6 , inboxcur - 5 ) , 0 ) : # Highlight current address
a = a | curses . A_REVERSE
if item [ 7 ] == False : # If not read, highlight
a = a | curses . A_BOLD
2014-04-30 04:45:41 +02:00
stdscr . addstr ( 5 + i , 5 , item [ 1 ] [ : 34 ] , a )
stdscr . addstr ( 5 + i , 40 , item [ 3 ] [ : 39 ] , a )
stdscr . addstr ( 5 + i , 80 , item [ 5 ] [ : 39 ] , a )
stdscr . addstr ( 5 + i , 120 , item [ 6 ] [ : 39 ] , a )
2014-04-19 20:45:37 +02:00
elif menutab == 3 : # Sent
2014-04-30 04:45:41 +02:00
stdscr . addstr ( 3 , 5 , " To " , curses . A_BOLD )
stdscr . addstr ( 3 , 40 , " From " , curses . A_BOLD )
stdscr . addstr ( 3 , 80 , " Subject " , curses . A_BOLD )
stdscr . addstr ( 3 , 120 , " Status " , curses . A_BOLD )
stdscr . hline ( 4 , 5 , ' - ' , 121 )
for i , item in enumerate ( sentbox [ max ( min ( len ( sentbox ) - curses . LINES + 6 , sentcur - 5 ) , 0 ) : ] ) :
if 6 + i < curses . LINES :
a = 0
if i == sentcur - max ( min ( len ( sentbox ) - curses . LINES + 6 , sentcur - 5 ) , 0 ) : # Highlight current address
a = a | curses . A_REVERSE
stdscr . addstr ( 5 + i , 5 , item [ 0 ] [ : 34 ] , a )
stdscr . addstr ( 5 + i , 40 , item [ 2 ] [ : 39 ] , a )
stdscr . addstr ( 5 + i , 80 , item [ 4 ] [ : 39 ] , a )
stdscr . addstr ( 5 + i , 120 , item [ 5 ] [ : 39 ] , a )
2014-04-29 07:10:33 +02:00
elif menutab == 2 or menutab == 4 : # Send or Identities
2014-04-19 20:45:37 +02:00
stdscr . addstr ( 3 , 5 , " Label " , curses . A_BOLD )
2014-04-30 04:45:41 +02:00
stdscr . addstr ( 3 , 40 , " Address " , curses . A_BOLD )
stdscr . addstr ( 3 , 80 , " Stream " , curses . A_BOLD )
stdscr . hline ( 4 , 5 , ' - ' , 81 )
2014-04-29 07:10:33 +02:00
for i , item in enumerate ( addresses [ max ( min ( len ( addresses ) - curses . LINES + 6 , addrcur - 5 ) , 0 ) : ] ) :
2014-04-30 04:45:41 +02:00
if 6 + i < curses . LINES :
a = 0
if i == addrcur - max ( min ( len ( addresses ) - curses . LINES + 6 , addrcur - 5 ) , 0 ) : # Highlight current address
a = a | curses . A_REVERSE
if item [ 1 ] == True and item [ 3 ] not in [ 8 , 9 ] : # Embolden enabled, non-special addresses
a = a | curses . A_BOLD
stdscr . addstr ( 5 + i , 5 , item [ 0 ] [ : 34 ] , a )
stdscr . addstr ( 5 + i , 40 , item [ 2 ] [ : 39 ] , cpair ( item [ 3 ] ) | a )
stdscr . addstr ( 5 + i , 80 , str ( 1 ) [ : 39 ] , a )
2014-04-19 20:45:37 +02:00
elif menutab == 5 : # Subscriptions
2014-04-30 04:45:41 +02:00
stdscr . addstr ( 3 , 5 , " Label " , curses . A_BOLD )
stdscr . addstr ( 3 , 80 , " Address " , curses . A_BOLD )
stdscr . addstr ( 3 , 120 , " Enabled " , curses . A_BOLD )
stdscr . hline ( 4 , 5 , ' - ' , 121 )
for i , item in enumerate ( subscriptions [ max ( min ( len ( subscriptions ) - curses . LINES + 6 , subcur - 5 ) , 0 ) : ] ) :
if 6 + i < curses . LINES :
a = 0
if i == subcur - max ( min ( len ( subscriptions ) - curses . LINES + 6 , subcur - 5 ) , 0 ) : # Highlight current address
a = a | curses . A_REVERSE
if item [ 2 ] == True : # Embolden enabled subscriptions
a = a | curses . A_BOLD
stdscr . addstr ( 5 + i , 5 , item [ 0 ] [ : 74 ] , a )
stdscr . addstr ( 5 + i , 80 , item [ 1 ] [ : 39 ] , a )
stdscr . addstr ( 5 + i , 120 , str ( item [ 2 ] ) , a )
2014-04-19 20:45:37 +02:00
elif menutab == 6 : # Address book
2014-04-29 07:10:33 +02:00
stdscr . addstr ( 3 , 5 , " Label " , curses . A_BOLD )
2014-04-30 04:45:41 +02:00
stdscr . addstr ( 3 , 40 , " Address " , curses . A_BOLD )
stdscr . hline ( 4 , 5 , ' - ' , 41 )
2014-04-29 07:10:33 +02:00
for i , item in enumerate ( addrbook [ max ( min ( len ( addrbook ) - curses . LINES + 6 , abookcur - 5 ) , 0 ) : ] ) :
2014-04-30 04:45:41 +02:00
if 6 + i < curses . LINES :
a = 0
if i == abookcur - max ( min ( len ( addrbook ) - curses . LINES + 6 , abookcur - 5 ) , 0 ) : # Highlight current address
a = a | curses . A_REVERSE
stdscr . addstr ( 5 + i , 5 , item [ 0 ] [ : 34 ] , a )
stdscr . addstr ( 5 + i , 40 , item [ 1 ] [ : 39 ] , a )
2014-04-19 20:45:37 +02:00
elif menutab == 7 : # Blacklist
2014-04-30 04:45:41 +02:00
stdscr . addstr ( 3 , 5 , " Type: " + bwtype )
stdscr . addstr ( 4 , 5 , " Label " , curses . A_BOLD )
stdscr . addstr ( 4 , 80 , " Address " , curses . A_BOLD )
stdscr . addstr ( 4 , 120 , " Enabled " , curses . A_BOLD )
stdscr . hline ( 5 , 5 , ' - ' , 121 )
for i , item in enumerate ( blacklist [ max ( min ( len ( blacklist ) - curses . LINES + 6 , blackcur - 5 ) , 0 ) : ] ) :
if 7 + i < curses . LINES :
a = 0
if i == blackcur - max ( min ( len ( blacklist ) - curses . LINES + 6 , blackcur - 5 ) , 0 ) : # Highlight current address
a = a | curses . A_REVERSE
if item [ 2 ] == True : # Embolden enabled subscriptions
a = a | curses . A_BOLD
stdscr . addstr ( 6 + i , 5 , item [ 0 ] [ : 74 ] , a )
stdscr . addstr ( 6 + i , 80 , item [ 1 ] [ : 39 ] , a )
stdscr . addstr ( 6 + i , 120 , str ( item [ 2 ] ) , a )
2014-04-19 20:45:37 +02:00
elif menutab == 8 : # Network status
# Connection data
stdscr . addstr ( 4 , 5 , " Total Connections: " + str ( len ( shared . connectedHostsList ) ) . ljust ( 2 ) )
stdscr . addstr ( 6 , 6 , " Stream # " , curses . A_BOLD )
2014-04-19 20:57:08 +02:00
stdscr . addstr ( 6 , 18 , " Connections " , curses . A_BOLD )
stdscr . hline ( 7 , 6 , ' - ' , 23 )
2014-04-19 20:45:37 +02:00
streamcount = [ ]
for host , stream in shared . connectedHostsList . items ( ) :
if stream > = len ( streamcount ) :
streamcount . append ( 1 )
else :
streamcount [ stream ] + = 1
for i , item in enumerate ( streamcount ) :
2014-04-19 20:57:08 +02:00
if i < 4 :
2014-04-19 20:45:37 +02:00
if i == 0 :
2014-04-19 20:57:08 +02:00
stdscr . addstr ( 8 + i , 6 , " ? " )
2014-04-19 20:45:37 +02:00
else :
2014-04-19 20:57:08 +02:00
stdscr . addstr ( 8 + i , 6 , str ( i ) )
stdscr . addstr ( 8 + i , 18 , str ( item ) . ljust ( 2 ) )
2014-04-19 20:45:37 +02:00
# Uptime and processing data
stdscr . addstr ( 6 , 35 , " Since startup on " + unicode ( strftime ( shared . config . get ( ' bitmessagesettings ' , ' timeformat ' ) , localtime ( int ( startuptime ) ) ) ) )
stdscr . addstr ( 7 , 40 , " Processed " + str ( shared . numberOfMessagesProcessed ) . ljust ( 4 ) + " person-to-person messages. " )
stdscr . addstr ( 8 , 40 , " Processed " + str ( shared . numberOfBroadcastsProcessed ) . ljust ( 4 ) + " broadcast messages. " )
stdscr . addstr ( 9 , 40 , " Processed " + str ( shared . numberOfPubkeysProcessed ) . ljust ( 4 ) + " public keys. " )
# Inventory data
2014-04-29 07:10:33 +02:00
stdscr . addstr ( 11 , 35 , " Inventory lookups per second: " + str ( inventorydata ) . ljust ( 3 ) )
2014-04-19 20:45:37 +02:00
# Log
stdscr . addstr ( 13 , 6 , " Log " , curses . A_BOLD )
n = log . count ( ' \n ' )
if n > 0 :
l = log . split ( ' \n ' )
if n > 512 :
del l [ : ( n - 256 ) ]
logpad . erase ( )
n = len ( l )
for i , item in enumerate ( l ) :
a = 0
if len ( item ) > 0 and item [ 0 ] == ' ! ' :
a = curses . color_pair ( 1 )
item = item [ 1 : ]
logpad . addstr ( i , 0 , item , a )
logpad . refresh ( n - curses . LINES + 2 , 0 , 14 , 6 , curses . LINES - 2 , curses . COLS - 7 )
2014-04-18 07:48:42 +02:00
stdscr . refresh ( )
def redraw ( stdscr ) :
stdscr . erase ( )
stdscr . border ( )
drawmenu ( stdscr )
stdscr . refresh ( )
2014-04-19 20:45:37 +02:00
def dialogreset ( stdscr ) :
stdscr . clear ( )
stdscr . keypad ( 1 )
curses . curs_set ( 0 )
2014-04-18 07:48:42 +02:00
def handlech ( c , stdscr ) :
if c != curses . ERR :
if c in range ( 256 ) :
if chr ( c ) in ' 12345678 ' :
2014-04-29 07:10:33 +02:00
global menutab
2014-04-18 07:48:42 +02:00
menutab = int ( chr ( c ) )
elif chr ( c ) == ' q ' :
global quit
quit = True
2014-04-19 20:45:37 +02:00
elif chr ( c ) == ' \n ' :
2014-04-30 04:45:41 +02:00
curses . curs_set ( 1 )
d = Dialog ( dialog = " dialog " )
2014-04-29 07:10:33 +02:00
if menutab == 1 :
d . set_background_title ( " Inbox Message Dialog Box " )
r , t = d . menu ( " Do what with \" " + inbox [ inboxcur ] [ 5 ] + " \" from \" " + inbox [ inboxcur ] [ 3 ] + " \" ? " ,
choices = [ ( " 1 " , " View message " ) ,
( " 2 " , " Mark message as unread " ) ,
( " 3 " , " Reply " ) ,
( " 4 " , " Add sender to Address Book " ) ,
( " 5 " , " Save message as text file " ) ,
( " 6 " , " Move to trash " ) ] )
if r == d . DIALOG_OK :
if t == " 1 " : # View
d . set_background_title ( " \" " + inbox [ inboxcur ] [ 5 ] + " \" from \" " + inbox [ inboxcur ] [ 3 ] + " \" to \" " + inbox [ inboxcur ] [ 1 ] + " \" " )
msg = " "
ret = sqlQuery ( " SELECT message FROM inbox WHERE msgid=? " , inbox [ inboxcur ] [ 0 ] )
if ret != [ ] :
for row in ret :
msg , = row
msg = shared . fixPotentiallyInvalidUTF8Data ( msg )
d . scrollbox ( unicode ( ascii ( msg ) ) , 30 , 100 , exit_label = " Continue " )
sqlExecute ( " UPDATE inbox SET read=1 WHERE msgid=? " , inbox [ inboxcur ] [ 0 ] )
inbox [ inboxcur ] [ 7 ] = 1
else :
d . scrollbox ( unicode ( " Could not fetch message. " ) , exit_label = " Continue " )
elif t == " 2 " : # Mark unread
sqlExecute ( " UPDATE inbox SET read=0 WHERE msgid=? " , inbox [ inboxcur ] [ 0 ] )
inbox [ inboxcur ] [ 7 ] = 0
elif t == " 3 " : # Reply
curses . curs_set ( 1 )
m = inbox [ inboxcur ]
fromaddr = m [ 4 ]
ischan = False
for i , item in enumerate ( addresses ) :
if fromaddr == item [ 2 ] and item [ 3 ] != 0 :
ischan = True
break
if not addresses [ i ] [ 1 ] :
d . scrollbox ( unicode ( " Sending address disabled, please either enable it or choose a different address. " ) , exit_label = " Continue " )
return
toaddr = m [ 2 ]
if ischan :
toaddr = fromaddr
subject = m [ 5 ]
if not m [ 5 ] [ : 4 ] == " Re: " :
subject = " Re: " + m [ 5 ]
body = " "
ret = sqlQuery ( " SELECT message FROM inbox WHERE msgid=? " , m [ 0 ] )
if ret != [ ] :
body = " \n \n ------------------------------------------------------ \n "
for row in ret :
body , = row
2014-04-30 04:45:41 +02:00
sendMessage ( fromaddr , toaddr , ischan , subject , body , True )
2014-04-29 07:10:33 +02:00
dialogreset ( stdscr )
elif t == " 4 " : # Add to Address Book
addr = inbox [ inboxcur ] [ 4 ]
2014-04-30 04:45:41 +02:00
if addr not in [ item [ 1 ] for i , item in enumerate ( addrbook ) ] :
2014-04-29 07:10:33 +02:00
r , t = d . inputbox ( " Label for address \" " + addr + " \" " )
if r == d . DIALOG_OK :
sqlExecute ( " INSERT INTO addressbook VALUES (?,?) " , t , addr )
addrbook . reverse ( ) . append ( [ t , addr ] ) . reverse ( ) # Prepend new entry
else :
d . scrollbox ( unicode ( " The selected address is already in the Address Book. " ) , exit_label = " Continue " )
elif t == " 5 " : # Save message
d . set_background_title ( " Save \" " + inbox [ inboxcur ] [ 5 ] + " \" as text file " )
r , t = d . inputbox ( " Filename " , init = inbox [ inboxcur ] [ 5 ] + " .txt " )
if r == d . DIALOG_OK :
msg = " "
ret = sqlQuery ( " SELECT message FROM inbox WHERE msgid=? " , inbox [ inboxcur ] [ 0 ] )
if ret != [ ] :
for row in ret :
msg , = row
fh = open ( t , " a " ) # Open in append mode just in case
fh . write ( msg )
fh . close ( )
else :
d . scrollbox ( unicode ( " Could not fetch message. " ) , exit_label = " Continue " )
elif t == " 6 " : # Move to trash
sqlExecute ( " UPDATE inbox SET folder= ' trash ' WHERE msgid=? " , inbox [ inboxcur ] [ 0 ] )
del inbox [ inboxcur ]
2014-04-30 04:45:41 +02:00
d . scrollbox ( unicode ( " Message moved to trash. There is no interface to view your trash, \n but the message is still on disk if you are desperate to recover it. " ) ,
2014-04-29 07:10:33 +02:00
exit_label = " Continue " )
elif menutab == 2 :
sendMessage ( addresses [ addrcur ] [ 2 ] )
2014-04-30 04:45:41 +02:00
elif menutab == 3 :
d . set_background_title ( " Sent Messages Dialog Box " )
r , t = d . menu ( " Do what with \" " + sentbox [ sentcur ] [ 4 ] + " \" to \" " + sentbox [ sentcur ] [ 0 ] + " \" ? " ,
choices = [ ( " 1 " , " View message " ) ,
( " 2 " , " Move to trash " ) ] )
if r == d . DIALOG_OK :
if t == " 1 " : # View
d . set_background_title ( " \" " + sentbox [ sentcur ] [ 4 ] + " \" from \" " + sentbox [ sentcur ] [ 3 ] + " \" to \" " + sentbox [ sentcur ] [ 1 ] + " \" " )
msg = " "
ret = sqlQuery ( " SELECT message FROM sent WHERE subject=? AND ackdata=? " , sentbox [ sentcur ] [ 4 ] , sentbox [ sentcur ] [ 6 ] )
if ret != [ ] :
for row in ret :
msg , = row
msg = shared . fixPotentiallyInvalidUTF8Data ( msg )
d . scrollbox ( unicode ( ascii ( msg ) ) , 30 , 100 , exit_label = " Continue " )
else :
d . scrollbox ( unicode ( " Could not fetch message. " ) , exit_label = " Continue " )
elif t == " 2 " : # Move to trash
sqlExecute ( " UPDATE sent SET folder= ' trash ' WHERE subject=? AND ackdata=? " , sentbox [ sentcur ] [ 4 ] , sentbox [ sentcur ] [ 6 ] )
del sentbox [ sentcur ]
d . scrollbox ( unicode ( " Message moved to trash. There is no interface to view your trash, \n but the message is still on disk if you are desperate to recover it. " ) ,
exit_label = " Continue " )
2014-04-29 07:10:33 +02:00
elif menutab == 4 :
2014-04-19 20:45:37 +02:00
d . set_background_title ( " Your Identities Dialog Box " )
r , t = d . menu ( " Do what with \" " + addresses [ addrcur ] [ 0 ] + " \" : \" " + addresses [ addrcur ] [ 2 ] + " \" ? " ,
choices = [ ( " 1 " , " Create new address " ) ,
2014-04-30 04:45:41 +02:00
( " 2 " , " Send a message from this address " ) ,
2014-04-19 20:45:37 +02:00
( " 3 " , " Rename " ) ,
( " 4 " , " Enable " ) ,
( " 5 " , " Disable " ) ,
( " 6 " , " Delete " ) ,
( " 7 " , " Special address behavior " ) ] )
if r == d . DIALOG_OK :
if t == " 1 " : # Create new address
d . set_background_title ( " Create new address " )
d . scrollbox ( unicode ( " Here you may generate as many addresses as you like. \n "
" Indeed, creating and abandoning addresses is encouraged. \n "
" Deterministic addresses have several pros and cons: \n "
" \n Pros: \n "
" * You can recreate your addresses on any computer from memory \n "
" * You need not worry about backing up your keys.dat file as long as you \n can remember your passphrase \n "
" Cons: \n "
" * You must remember (or write down) your passphrase in order to recreate \n your keys if they are lost \n "
" * You must also remember the address version and stream numbers \n "
" * If you choose a weak passphrase someone may be able to brute-force it \n and then send and receive messages as you " ) ,
exit_label = " Continue " )
r , t = d . menu ( " Choose an address generation technique " ,
choices = [ ( " 1 " , " Use a random number generator " ) ,
( " 2 " , " Use a passphrase " ) ] )
if r == d . DIALOG_OK :
if t == " 1 " :
d . set_background_title ( " Randomly generate address " )
r , t = d . inputbox ( " Label (not shown to anyone except you) " )
label = " "
if r == d . DIALOG_OK and len ( t ) > 0 :
label = t
r , t = d . menu ( " Choose a stream " ,
choices = [ ( " 1 " , " Use the most available stream " ) , ( " " , " (Best if this is the first of many addresses you will create) " ) ,
( " 2 " , " Use the same stream as an existing address " ) , ( " " , " (Saves you some bandwidth and processing power) " ) ] )
if r == d . DIALOG_OK :
if t == " 1 " :
stream = 1
elif t == " 2 " :
addrs = [ ]
for i , item in enumerate ( addresses ) :
addrs . append ( [ str ( i ) , item [ 2 ] ] )
r , t = d . menu ( " Choose an existing address ' s stream " , choices = addrs )
if r == d . DIALOG_OK :
stream = decodeAddress ( addrs [ int ( t ) ] [ 1 ] ) [ 2 ]
shorten = False
r , t = d . checklist ( " Miscellaneous options " ,
choices = [ ( " 1 " , " Spend time shortening the address " , shorten ) ] )
if r == d . DIALOG_OK and " 1 " in t :
shorten = True
shared . addressGeneratorQueue . put ( ( " createRandomAddress " , 4 , stream , label , 1 , " " , shorten ) )
elif t == " 2 " :
d . set_background_title ( " Make deterministic addresses " )
r , t = d . passwordform ( " Enter passphrase " ,
[ ( " Passphrase " , 1 , 1 , " " , 2 , 1 , 64 , 128 ) ,
( " Confirm passphrase " , 3 , 1 , " " , 4 , 1 , 64 , 128 ) ] ,
form_height = 4 , insecure = True )
if r == d . DIALOG_OK :
if t [ 0 ] == t [ 1 ] :
passphrase = t [ 0 ]
r , t = d . rangebox ( " Number of addresses to generate " ,
width = 48 , min = 1 , max = 99 , init = 8 )
if r == d . DIALOG_OK :
number = t
stream = 1
shorten = False
r , t = d . checklist ( " Miscellaneous options " ,
choices = [ ( " 1 " , " Spend time shortening the address " , shorten ) ] )
if r == d . DIALOG_OK and " 1 " in t :
shorten = True
d . scrollbox ( unicode ( " In addition to your passphrase, be sure to remember the following numbers: \n "
" \n * Address version number: " + str ( 4 ) + " \n "
" * Stream number: " + str ( stream ) ) ,
exit_label = " Continue " )
shared . addressGeneratorQueue . put ( ( ' createDeterministicAddresses ' , 4 , stream , " unused deterministic address " , number , str ( passphrase ) , shorten ) )
else :
d . scrollbox ( unicode ( " Passphrases do not match " ) , exit_label = " Continue " )
2014-04-30 04:45:41 +02:00
elif t == " 2 " : # Send a message
sendMessage ( addresses [ addrcur ] [ 2 ] )
2014-04-19 20:45:37 +02:00
elif t == " 3 " : # Rename address label
a = addresses [ addrcur ] [ 2 ]
label = addresses [ addrcur ] [ 0 ]
r , t = d . inputbox ( " New address label " , init = label )
if r == d . DIALOG_OK :
label = t
shared . config . set ( a , " label " , label )
# Write config
with open ( shared . appdata + ' keys.dat ' , ' wb ' ) as configfile :
shared . config . write ( configfile )
addresses [ addrcur ] [ 0 ] = label
elif t == " 4 " : # Enable address
a = addresses [ addrcur ] [ 2 ]
shared . config . set ( a , " enabled " , " true " ) # Set config
# Write config
with open ( shared . appdata + ' keys.dat ' , ' wb ' ) as configfile :
shared . config . write ( configfile )
# Change color
if shared . safeConfigGetBoolean ( a , ' chan ' ) :
addresses [ addrcur ] [ 3 ] = 9 # orange
elif shared . safeConfigGetBoolean ( a , ' mailinglist ' ) :
addresses [ addrcur ] [ 3 ] = 5 # magenta
else :
addresses [ addrcur ] [ 3 ] = 0 # black
addresses [ addrcur ] [ 1 ] = True
shared . reloadMyAddressHashes ( ) # Reload address hashes
elif t == " 5 " : # Disable address
a = addresses [ addrcur ] [ 2 ]
shared . config . set ( a , " enabled " , " false " ) # Set config
addresses [ addrcur ] [ 3 ] = 8 # Set color to gray
# Write config
with open ( shared . appdata + ' keys.dat ' , ' wb ' ) as configfile :
shared . config . write ( configfile )
addresses [ addrcur ] [ 1 ] = False
shared . reloadMyAddressHashes ( ) # Reload address hashes
elif t == " 6 " : # Delete address
2014-04-30 04:45:41 +02:00
r , t = d . inputbox ( " Type in \" I want to delete this address \" " , width = 50 )
if r == d . DIALOG_OK and t == " I want to delete this address " :
shared . config . remove_section ( addresses [ addrcur ] [ 2 ] )
with open ( shared . appdata + ' keys.dat ' , ' wb ' ) as configfile :
shared . config . write ( configfile )
del addresses [ addrcur ]
2014-04-19 20:45:37 +02:00
elif t == " 7 " : # Special address behavior
a = addresses [ addrcur ] [ 2 ]
d . set_background_title ( " Special address behavior " )
if shared . safeConfigGetBoolean ( a , " chan " ) :
d . scrollbox ( unicode ( " This is a chan address. You cannot use it as a pseudo-mailing list. " ) , exit_label = " Continue " )
else :
m = shared . safeConfigGetBoolean ( a , " mailinglist " )
r , t = d . radiolist ( " Select address behavior " ,
2014-04-29 07:10:33 +02:00
choices = [ ( " 1 " , " Behave as a normal address " , not m ) ,
( " 2 " , " Behave as a pseudo-mailing-list address " , m ) ] )
2014-04-19 20:45:37 +02:00
if r == d . DIALOG_OK :
if t == " 1 " and m == True :
shared . config . set ( a , " mailinglist " , " false " )
if addresses [ addrcur ] [ 1 ] :
addresses [ addrcur ] [ 3 ] = 0 # Set color to black
else :
addresses [ addrcur ] [ 3 ] = 8 # Set color to gray
elif t == " 2 " and m == False :
try :
mn = shared . config . get ( a , " mailinglistname " )
except ConfigParser . NoOptionError :
mn = " "
r , t = d . inputbox ( " Mailing list name " , init = mn )
if r == d . DIALOG_OK :
mn = t
shared . config . set ( a , " mailinglist " , " true " )
shared . config . set ( a , " mailinglistname " , mn )
addresses [ addrcur ] [ 3 ] = 6 # Set color to magenta
# Write config
with open ( shared . appdata + ' keys.dat ' , ' wb ' ) as configfile :
shared . config . write ( configfile )
2014-04-30 04:45:41 +02:00
elif menutab == 5 :
d . set_background_title ( " Subscriptions Dialog Box " )
r , t = d . menu ( " Do what with subscription to \" " + subscriptions [ subcur ] [ 0 ] + " \" ? " ,
choices = [ ( " 1 " , " Add new subscription " ) ,
( " 2 " , " Delete this subscription " ) ,
( " 3 " , " Enable " ) ,
( " 4 " , " Disable " ) ] )
if r == d . DIALOG_OK :
if t == " 1 " :
r , t = d . inputbox ( " New subscription address " )
if r == d . DIALOG_OK :
addr = addBMIfNotPresent ( t )
if not shared . isAddressInMySubscriptionsList ( addr ) :
r , t = d . inputbox ( " New subscription label " )
if r == d . DIALOG_OK :
label = t
subscriptions . reverse ( ) . append ( label , addr , True ) . reverse ( )
sqlExecute ( " INSERT INTO subscriptions VALUES (?,?,?) " , label , address , True )
shared . reloadBroadcastSendersForWhichImWatching ( )
elif t == " 2 " :
r , t = d . inpuxbox ( " Type in \" I want to delete this subscription \" " )
if r == d . DIALOG_OK and t == " I want to delete this subscription " :
sqlExecute ( " DELETE FROM subscriptions WHERE label=? AND address=? " , subscriptions [ subcur ] [ 0 ] , subscriptions [ subcur ] [ 1 ] )
shared . reloadBroadcastSendersForWhichImWatching ( )
del subscriptions [ subcur ]
elif t == " 3 " :
sqlExecute ( " UPDATE subscriptions SET enabled=1 WHERE label=? AND address=? " , subscriptions [ subcur ] [ 0 ] , subscriptions [ subcur ] [ 1 ] )
shared . reloadBroadcastSendersForWhichImWatching ( )
subscriptions [ subcur ] [ 2 ] = True
elif t == " 4 " :
sqlExecute ( " UPDATE subscriptions SET enabled=0 WHERE label=? AND address=? " , subscriptions [ subcur ] [ 0 ] , subscriptions [ subcur ] [ 1 ] )
shared . reloadBroadcastSendersForWhichImWatching ( )
subscriptions [ subcur ] [ 2 ] = False
elif menutab == 6 :
d . set_background_title ( " Address Book Dialog Box " )
r , t = d . menu ( " Do what with \" " + addrbook [ abookcur ] [ 0 ] + " \" : \" " + addrbook [ abookcur ] [ 1 ] + " \" " ,
choices = [ ( " 1 " , " Send a message to this address " ) ,
( " 2 " , " Subscribe to this address " ) ,
( " 3 " , " Add new address to Address Book " ) ,
( " 4 " , " Delete this address " ) ] )
if r == d . DIALOG_OK :
if t == " 1 " :
sendMessage ( recv = addrbook [ abookcur ] [ 1 ] )
elif t == " 2 " :
r , t = d . inputbox ( " New subscription label " )
if r == d . DIALOG_OK :
label = t
subscriptions . reverse ( ) . append ( label , addr , True ) . reverse ( )
sqlExecute ( " INSERT INTO subscriptions VALUES (?,?,?) " , label , address , True )
shared . reloadBroadcastSendersForWhichImWatching ( )
elif t == " 3 " :
r , t = d . inputbox ( " Input new address " )
if r == d . DIALOG_OK :
addr = t
if addr not in [ item [ 1 ] for i , item in enumerate ( addrbook ) ] :
r , t = d . inputbox ( " Label for address \" " + addr + " \" " )
if r == d . DIALOG_OK :
sqlExecute ( " INSERT INTO addressbook VALUES (?,?) " , t , addr )
addrbook . reverse ( ) . append ( [ t , addr ] ) . reverse ( ) # Prepend new entry
else :
d . scrollbox ( unicode ( " The selected address is already in the Address Book. " ) , exit_label = " Continue " )
elif t == " 4 " :
r , t = d . inputbox ( " Type in \" I want to delete this Address Book entry \" " )
if r == d . DIALOG_OK and t == " I want to delete this Address Book entry " :
sqlExecute ( " DELETE FROM addressbook WHERE label=? AND address=? " , addrbook [ abookcur ] [ 0 ] , addrbook [ abookcur ] [ 1 ] )
del addrbook [ abookcur ]
elif menutab == 7 :
d . set_background_title ( " Blacklist Dialog Box " )
r , t = d . menu ( " Do what with \" " + blacklist [ blackcur ] [ 0 ] + " \" : \" " + blacklist [ blackcur ] [ 1 ] + " \" ? " ,
choices = [ ( " 1 " , " Delete " ) ,
( " 2 " , " Enable " ) ,
( " 3 " , " Disable " ) ] )
if r == d . DIALOG_OK :
if t == " 1 " :
r , t = d . inputbox ( " Type in \" I want to delete this Blacklist entry \" " )
if r == d . DIALOG_OK and t == " I want to delete this Blacklist entry " :
sqlExecute ( " DELETE FROM blacklist WHERE label=? AND address=? " , blacklist [ blackcur ] [ 0 ] , blacklist [ blackcur ] [ 1 ] )
del blacklist [ blackcur ]
elif t == " 2 " :
sqlExecute ( " UPDATE blacklist SET enabled=1 WHERE label=? AND address=? " , blacklist [ blackcur ] [ 0 ] , blacklist [ blackcur ] [ 1 ] )
blacklist [ blackcur ] [ 2 ] = True
elif t == " 3 " :
sqlExecute ( " UPDATE blacklist SET enabled=0 WHERE label=? AND address=? " , blacklist [ blackcur ] [ 0 ] , blacklist [ blackcur ] [ 1 ] )
blacklist [ blackcur ] [ 2 ] = False
dialogreset ( stdscr )
2014-04-18 07:48:42 +02:00
else :
2014-04-30 04:45:41 +02:00
global addrcur , inboxcur , sentcur , subcur , abookcur , blackcur
2014-04-18 07:48:42 +02:00
if c == curses . KEY_UP :
2014-04-29 07:10:33 +02:00
if menutab == 1 and inboxcur > 0 :
inboxcur - = 1
if ( menutab == 2 or menutab == 4 ) and addrcur > 0 :
2014-04-18 07:48:42 +02:00
addrcur - = 1
2014-04-30 04:45:41 +02:00
if menutab == 3 and sentcur > 0 :
sentcur - = 1
if menutab == 5 and subcur > 0 :
subcur - = 1
2014-04-29 07:10:33 +02:00
if menutab == 6 and abookcur > 0 :
abookcur - = 1
2014-04-30 04:45:41 +02:00
if menutab == 7 and blackcur > 0 :
blackcur - = 1
2014-04-18 07:48:42 +02:00
elif c == curses . KEY_DOWN :
2014-04-29 07:10:33 +02:00
if menutab == 1 and inboxcur < len ( inbox ) - 1 :
inboxcur + = 1
if ( menutab == 2 or menutab == 4 ) and addrcur < len ( addresses ) - 1 :
2014-04-18 07:48:42 +02:00
addrcur + = 1
2014-04-30 04:45:41 +02:00
if menutab == 3 and sentcur < len ( sentbox ) - 1 :
sentcur + = 1
if menutab == 5 and subcur < len ( subscriptions ) - 1 :
subcur + = 1
2014-04-29 07:10:33 +02:00
if menutab == 6 and abookcur < len ( addrbook ) - 1 :
abookcur + = 1
2014-04-30 04:45:41 +02:00
if menutab == 7 and blackcur < len ( blacklist ) - 1 :
blackcur + = 1
2014-04-29 07:10:33 +02:00
elif c == curses . KEY_HOME :
if menutab == 1 :
inboxcur = 0
if menutab == 2 or menutab == 4 :
addrcur = 0
2014-04-30 04:45:41 +02:00
if menutab == 3 :
sentcur = 0
if menutab == 5 :
subcur = 0
2014-04-29 07:10:33 +02:00
if menutab == 6 :
abookcur = 0
2014-04-30 04:45:41 +02:00
if menutab == 7 :
blackcur = 0
2014-04-29 07:10:33 +02:00
elif c == curses . KEY_END :
if menutab == 1 :
inboxcur = len ( inbox ) - 1
if menutab == 2 or menutab == 4 :
addrcur = len ( addresses ) - 1
2014-04-30 04:45:41 +02:00
if menutab == 3 :
sentcur = len ( sentbox ) - 1
if menutab == 5 :
subcur = len ( subscriptions ) - 1
2014-04-29 07:10:33 +02:00
if menutab == 6 :
abookcur = len ( addrbook ) - 1
2014-04-30 04:45:41 +02:00
if menutab == 7 :
blackcur = len ( blackcur ) - 1
2014-04-18 07:48:42 +02:00
redraw ( stdscr )
2014-04-30 04:45:41 +02:00
def sendMessage ( sender = " " , recv = " " , broadcast = None , subject = " " , body = " " , reply = False ) :
2014-04-29 07:10:33 +02:00
if sender == " " :
return
d = Dialog ( dialog = " dialog " )
d . set_background_title ( " Send a message " )
if recv == " " :
r , t = d . inputbox ( " Recipient address (Cancel to load from the Address Book or leave blank to broadcast) " , 10 , 60 )
if r != d . DIALOG_OK :
global menutab
menutab = 6
return
recv = t
if broadcast == None :
r , t = d . radiolist ( " How to send the message? " ,
choices = [ ( " 1 " , " Send to one or more specific people " , True ) ,
( " 2 " , " Broadcast to everyone who is subscribed to your address " , False ) ] )
if r != d . DIALOG_OK :
return
broadcast = False
if t == " 2 " : # Broadcast
broadcast = True
2014-04-30 04:45:41 +02:00
if subject == " " or reply :
r , t = d . inputbox ( " Message subject " , width = 60 , init = subject )
2014-04-29 07:10:33 +02:00
if r != d . DIALOG_OK :
return
subject = shared . fixPotentiallyInvalidUTF8Data ( t )
2014-04-30 04:45:41 +02:00
if body == " " or reply :
r , t = d . inputbox ( " Message body " , 10 , 80 , init = body )
2014-04-29 07:10:33 +02:00
if r != d . DIALOG_OK :
return
body = shared . fixPotentiallyInvalidUTF8Data ( t )
if not broadcast :
recvlist = [ ]
for i , item in enumerate ( recv . replace ( " , " , " ; " ) . split ( " ; " ) ) :
recvlist . append ( item . strip ( ) )
list ( set ( recvlist ) ) # Remove exact duplicates
for addr in recvlist :
if addr != " " :
status , version , stream , ripe = decodeAddress ( addr )
if status != " success " :
d . set_background_title ( " Recipient address error " )
err = " Could not decode " + addr + " : " + status + " \n \n "
if status == " missingbm " :
err + = " Bitmessage addresses should start with \" BM- \" . "
elif status == " checksumfailed " :
err + = " The address was not typed or copied correctly. "
elif status == " invalidcharacters " :
err + = " The address contains invalid characters. "
elif status == " versiontoohigh " :
err + = " The address version is too high. Either you need to upgrade your Bitmessage software or your acquaintance is doing something clever. "
elif status == " ripetooshort " :
err + = " Some data encoded in the address is too short. There might be something wrong with the software of your acquaintance. "
elif status == " ripetoolong " :
err + = " Some data encoded in the address is too long. There might be something wrong with the software of your acquaintance. "
else :
err + = " It is unknown what is wrong with the address. "
d . scrollbox ( unicode ( err ) , exit_label = " Continue " )
else :
addr = addBMIfNotPresent ( addr )
if version > 4 or version < = 1 :
d . set_background_title ( " Recipient address error " )
d . scrollbox ( unicode ( " Could not understand version number " + version + " of address " + addr + " . " ) ,
exit_label = " Continue " )
continue
if stream > 1 or stream == 0 :
d . set_background_title ( " Recipient address error " )
d . scrollbox ( unicode ( " Bitmessage currently only supports stream numbers of 1, unlike as requested for address " + addr + " . " ) ,
exit_label = " Continue " )
continue
if len ( shared . connectedHostsList ) == 0 :
d . set_background_title ( " Not connected warning " )
d . scrollbox ( unicode ( " Because you are not currently connected to the network, " ) ,
exit_label = " Continue " )