2015-06-05 13:43:56 +02:00
/ *
* Copyright 2015 Christian Basler
*
* Licensed under the Apache License , Version 2 . 0 ( the " License " ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an " AS IS " BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* /
2015-05-22 20:51:57 +02:00
package ch.dissem.bitmessage.demo ;
import ch.dissem.bitmessage.BitmessageContext ;
import ch.dissem.bitmessage.entity.BitmessageAddress ;
import ch.dissem.bitmessage.entity.Plaintext ;
import ch.dissem.bitmessage.entity.payload.Pubkey ;
2015-08-05 19:52:18 +02:00
import ch.dissem.bitmessage.networking.DefaultNetworkHandler ;
2015-08-28 13:48:01 +02:00
import ch.dissem.bitmessage.ports.MemoryNodeRegistry ;
2015-12-08 20:27:32 +01:00
import ch.dissem.bitmessage.repository.* ;
2016-01-10 13:38:32 +01:00
import ch.dissem.bitmessage.cryptography.bc.BouncyCryptography ;
2015-05-22 20:51:57 +02:00
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
import java.io.UnsupportedEncodingException ;
2016-01-21 20:32:23 +01:00
import java.net.InetAddress ;
2015-05-22 20:51:57 +02:00
import java.util.List ;
import java.util.Scanner ;
/ * *
* A simple command line Bitmessage application
* /
public class Application {
private final static Logger LOG = LoggerFactory . getLogger ( Application . class ) ;
private final Scanner scanner ;
private BitmessageContext ctx ;
2016-01-21 20:32:23 +01:00
public Application ( String syncServer , int syncPort ) {
2015-06-05 13:43:56 +02:00
JdbcConfig jdbcConfig = new JdbcConfig ( ) ;
2015-05-22 20:51:57 +02:00
ctx = new BitmessageContext . Builder ( )
2015-06-05 13:43:56 +02:00
. addressRepo ( new JdbcAddressRepository ( jdbcConfig ) )
. inventory ( new JdbcInventory ( jdbcConfig ) )
2015-07-01 06:57:30 +02:00
. nodeRegistry ( new MemoryNodeRegistry ( ) )
2015-06-05 13:43:56 +02:00
. messageRepo ( new JdbcMessageRepository ( jdbcConfig ) )
2015-12-08 20:27:32 +01:00
. powRepo ( new JdbcProofOfWorkRepository ( jdbcConfig ) )
2015-08-05 19:52:18 +02:00
. networkHandler ( new DefaultNetworkHandler ( ) )
2016-01-10 13:38:32 +01:00
. cryptography ( new BouncyCryptography ( ) )
2015-10-14 18:37:43 +02:00
. port ( 48444 )
2015-10-07 21:50:41 +02:00
. listener ( new BitmessageContext . Listener ( ) {
@Override
public void receive ( Plaintext plaintext ) {
try {
System . out . println ( new String ( plaintext . getMessage ( ) , " UTF-8 " ) ) ;
} catch ( UnsupportedEncodingException e ) {
LOG . error ( e . getMessage ( ) , e ) ;
}
}
} )
2015-05-22 20:51:57 +02:00
. build ( ) ;
2016-01-21 20:32:23 +01:00
if ( syncServer = = null ) {
ctx . startup ( ) ;
}
2015-05-22 20:51:57 +02:00
scanner = new Scanner ( System . in ) ;
String command ;
do {
System . out . println ( ) ;
System . out . println ( " available commands: " ) ;
System . out . println ( " i) identities " ) ;
System . out . println ( " c) contacts " ) ;
2015-06-09 22:45:24 +02:00
System . out . println ( " s) subscriptions " ) ;
2015-05-22 20:51:57 +02:00
System . out . println ( " m) messages " ) ;
2016-01-21 20:32:23 +01:00
if ( syncServer ! = null ) {
System . out . println ( " y) sync " ) ;
}
2015-06-16 06:41:59 +02:00
System . out . println ( " ?) info " ) ;
2015-06-05 13:43:56 +02:00
System . out . println ( " e) exit " ) ;
2015-05-22 20:51:57 +02:00
command = nextCommand ( ) ;
try {
switch ( command ) {
case " i " : {
identities ( ) ;
break ;
}
case " c " :
contacts ( ) ;
break ;
2015-06-09 22:45:24 +02:00
case " s " :
subscriptions ( ) ;
break ;
2015-05-22 20:51:57 +02:00
case " m " :
messages ( ) ;
break ;
2015-06-16 06:41:59 +02:00
case " ? " :
info ( ) ;
break ;
2015-05-22 20:51:57 +02:00
case " e " :
break ;
2016-01-21 20:32:23 +01:00
case " y " :
ctx . synchronize ( InetAddress . getByName ( syncServer ) , syncPort , 120 , true ) ;
break ;
2015-05-22 20:51:57 +02:00
default :
System . out . println ( " Unknown command. Please try again. " ) ;
}
} catch ( Exception e ) {
LOG . debug ( e . getMessage ( ) ) ;
}
} while ( ! " e " . equals ( command ) ) ;
LOG . info ( " Shutting down client " ) ;
2015-10-12 12:44:13 +02:00
ctx . cleanup ( ) ;
2015-05-22 20:51:57 +02:00
ctx . shutdown ( ) ;
}
2015-06-16 06:41:59 +02:00
private void info ( ) {
System . out . println ( ) ;
System . out . println ( ctx . status ( ) ) ;
}
2015-05-22 20:51:57 +02:00
private String nextCommand ( ) {
return scanner . nextLine ( ) . trim ( ) . toLowerCase ( ) ;
}
private void identities ( ) {
String command ;
List < BitmessageAddress > identities = ctx . addresses ( ) . getIdentities ( ) ;
do {
System . out . println ( ) ;
int i = 0 ;
for ( BitmessageAddress identity : identities ) {
i + + ;
System . out . print ( i + " ) " ) ;
if ( identity . getAlias ( ) ! = null ) {
System . out . println ( identity . getAlias ( ) + " ( " + identity . getAddress ( ) + " ) " ) ;
} else {
System . out . println ( identity . getAddress ( ) ) ;
}
}
if ( i = = 0 ) {
System . out . println ( " You have no identities yet. " ) ;
}
System . out . println ( " a) create identity " ) ;
System . out . println ( " b) back " ) ;
command = nextCommand ( ) ;
switch ( command ) {
case " a " :
addIdentity ( ) ;
2015-05-29 13:17:00 +02:00
identities = ctx . addresses ( ) . getIdentities ( ) ;
2015-05-22 20:51:57 +02:00
break ;
case " b " :
return ;
default :
try {
int index = Integer . parseInt ( command ) - 1 ;
address ( identities . get ( index ) ) ;
} catch ( NumberFormatException e ) {
System . out . println ( " Unknown command. Please try again. " ) ;
}
}
} while ( ! " b " . equals ( command ) ) ;
}
private void addIdentity ( ) {
System . out . println ( ) ;
BitmessageAddress identity = ctx . createIdentity ( yesNo ( " would you like a shorter address? This will take some time to calculate. " ) , Pubkey . Feature . DOES_ACK ) ;
System . out . println ( " Please enter an alias for this identity, or an empty string for none " ) ;
2015-06-11 21:02:01 +02:00
String alias = scanner . nextLine ( ) . trim ( ) ;
2015-05-22 20:51:57 +02:00
if ( alias . length ( ) > 0 ) {
identity . setAlias ( alias ) ;
}
ctx . addresses ( ) . save ( identity ) ;
}
private void contacts ( ) {
String command ;
List < BitmessageAddress > contacts = ctx . addresses ( ) . getContacts ( ) ;
do {
System . out . println ( ) ;
int i = 0 ;
for ( BitmessageAddress contact : contacts ) {
i + + ;
System . out . print ( i + " ) " ) ;
if ( contact . getAlias ( ) ! = null ) {
System . out . println ( contact . getAlias ( ) + " ( " + contact . getAddress ( ) + " ) " ) ;
} else {
System . out . println ( contact . getAddress ( ) ) ;
}
}
if ( i = = 0 ) {
System . out . println ( " You have no contacts yet. " ) ;
}
System . out . println ( ) ;
System . out . println ( " a) add contact " ) ;
System . out . println ( " b) back " ) ;
command = nextCommand ( ) ;
switch ( command ) {
case " a " :
2015-06-09 22:45:24 +02:00
addContact ( false ) ;
2015-05-29 13:17:00 +02:00
contacts = ctx . addresses ( ) . getContacts ( ) ;
2015-05-22 20:51:57 +02:00
break ;
case " b " :
return ;
default :
try {
int index = Integer . parseInt ( command ) - 1 ;
address ( contacts . get ( index ) ) ;
} catch ( NumberFormatException e ) {
System . out . println ( " Unknown command. Please try again. " ) ;
}
}
} while ( ! " b " . equals ( command ) ) ;
}
2015-06-09 22:45:24 +02:00
private void addContact ( boolean isSubscription ) {
2015-05-22 20:51:57 +02:00
System . out . println ( ) ;
System . out . println ( " Please enter the Bitmessage address you want to add " ) ;
try {
BitmessageAddress address = new BitmessageAddress ( scanner . nextLine ( ) . trim ( ) ) ;
System . out . println ( " Please enter an alias for this address, or an empty string for none " ) ;
String alias = scanner . nextLine ( ) . trim ( ) ;
if ( alias . length ( ) > 0 ) {
address . setAlias ( alias ) ;
}
2015-06-09 22:45:24 +02:00
if ( isSubscription ) {
ctx . addSubscribtion ( address ) ;
}
2015-05-22 20:51:57 +02:00
ctx . addContact ( address ) ;
} catch ( IllegalArgumentException e ) {
System . out . println ( e . getMessage ( ) ) ;
}
}
2015-06-09 22:45:24 +02:00
private void subscriptions ( ) {
String command ;
List < BitmessageAddress > subscriptions = ctx . addresses ( ) . getSubscriptions ( ) ;
do {
System . out . println ( ) ;
int i = 0 ;
for ( BitmessageAddress contact : subscriptions ) {
i + + ;
System . out . print ( i + " ) " ) ;
if ( contact . getAlias ( ) ! = null ) {
System . out . println ( contact . getAlias ( ) + " ( " + contact . getAddress ( ) + " ) " ) ;
} else {
System . out . println ( contact . getAddress ( ) ) ;
}
}
if ( i = = 0 ) {
System . out . println ( " You have no subscriptions yet. " ) ;
}
System . out . println ( ) ;
System . out . println ( " a) add subscription " ) ;
System . out . println ( " b) back " ) ;
command = nextCommand ( ) ;
switch ( command ) {
case " a " :
addContact ( true ) ;
subscriptions = ctx . addresses ( ) . getSubscriptions ( ) ;
break ;
case " b " :
return ;
default :
try {
int index = Integer . parseInt ( command ) - 1 ;
address ( subscriptions . get ( index ) ) ;
} catch ( NumberFormatException e ) {
System . out . println ( " Unknown command. Please try again. " ) ;
}
}
} while ( ! " b " . equals ( command ) ) ;
}
2015-05-22 20:51:57 +02:00
private void address ( BitmessageAddress address ) {
System . out . println ( ) ;
if ( address . getAlias ( ) ! = null )
System . out . println ( address . getAlias ( ) ) ;
System . out . println ( address . getAddress ( ) ) ;
System . out . println ( " Stream: " + address . getStream ( ) ) ;
System . out . println ( " Version: " + address . getVersion ( ) ) ;
2015-05-29 13:17:00 +02:00
if ( address . getPrivateKey ( ) = = null ) {
2016-02-26 14:34:08 +01:00
if ( address . getPubkey ( ) = = null ) {
2015-05-29 13:17:00 +02:00
System . out . println ( " Public key still missing " ) ;
2016-02-26 14:34:08 +01:00
} else {
System . out . println ( " Public key available " ) ;
2015-05-29 13:17:00 +02:00
}
}
2015-05-22 20:51:57 +02:00
}
private void messages ( ) {
String command ;
do {
2016-02-26 14:34:08 +01:00
List < Plaintext > messages = ctx . messages ( ) . findMessages ( Plaintext . Status . RECEIVED ) ;
2015-05-22 20:51:57 +02:00
System . out . println ( ) ;
int i = 0 ;
for ( Plaintext message : messages ) {
i + + ;
2015-05-23 16:01:18 +02:00
System . out . println ( i + " ) From: " + message . getFrom ( ) + " ; Subject: " + message . getSubject ( ) ) ;
2015-05-22 20:51:57 +02:00
}
if ( i = = 0 ) {
System . out . println ( " You have no messages. " ) ;
}
System . out . println ( ) ;
System . out . println ( " c) compose message " ) ;
2015-06-09 22:45:24 +02:00
System . out . println ( " s) compose broadcast " ) ;
2015-05-22 20:51:57 +02:00
System . out . println ( " b) back " ) ;
command = scanner . nextLine ( ) . trim ( ) ;
switch ( command ) {
case " c " :
2015-06-09 22:45:24 +02:00
compose ( false ) ;
break ;
case " s " :
compose ( true ) ;
2015-05-22 20:51:57 +02:00
break ;
case " b " :
return ;
default :
try {
2015-05-23 10:27:05 +02:00
int index = Integer . parseInt ( command ) - 1 ;
2015-05-22 20:51:57 +02:00
show ( messages . get ( index ) ) ;
} catch ( NumberFormatException | IndexOutOfBoundsException e ) {
System . out . println ( " Unknown command. Please try again. " ) ;
}
}
} while ( ! " b " . equalsIgnoreCase ( command ) ) ;
}
private void show ( Plaintext message ) {
System . out . println ( ) ;
System . out . println ( " From: " + message . getFrom ( ) ) ;
System . out . println ( " To: " + message . getTo ( ) ) ;
System . out . println ( " Subject: " + message . getSubject ( ) ) ;
System . out . println ( ) ;
System . out . println ( message . getText ( ) ) ;
System . out . println ( ) ;
2015-06-09 22:45:24 +02:00
System . out . println ( " Labels: " + message . getLabels ( ) ) ;
2015-05-29 13:17:00 +02:00
System . out . println ( ) ;
2015-05-22 20:51:57 +02:00
String command ;
do {
2015-05-23 10:27:05 +02:00
System . out . println ( " r) reply " ) ;
2015-05-22 20:51:57 +02:00
System . out . println ( " d) delete " ) ;
2015-05-23 10:27:05 +02:00
System . out . println ( " b) back " ) ;
2015-05-22 20:51:57 +02:00
command = nextCommand ( ) ;
switch ( command ) {
case " r " :
compose ( message . getTo ( ) , message . getFrom ( ) , " RE: " + message . getSubject ( ) ) ;
break ;
case " d " :
ctx . messages ( ) . remove ( message ) ;
case " b " :
return ;
default :
System . out . println ( " Unknown command. Please try again. " ) ;
}
} while ( ! " b " . equalsIgnoreCase ( command ) ) ;
}
2015-06-09 22:45:24 +02:00
private void compose ( boolean broadcast ) {
2015-05-22 20:51:57 +02:00
System . out . println ( ) ;
2015-05-29 13:17:00 +02:00
BitmessageAddress from = selectAddress ( true ) ;
2015-06-11 21:02:01 +02:00
if ( from = = null ) {
return ;
}
2015-06-09 22:45:24 +02:00
BitmessageAddress to = ( broadcast ? null : selectAddress ( false ) ) ;
2015-06-11 21:02:01 +02:00
if ( ! broadcast & & to = = null ) {
return ;
}
2015-05-29 13:17:00 +02:00
compose ( from , to , null ) ;
}
private BitmessageAddress selectAddress ( boolean id ) {
2015-06-11 21:02:01 +02:00
List < BitmessageAddress > addresses = ( id ? ctx . addresses ( ) . getIdentities ( ) : ctx . addresses ( ) . getContacts ( ) ) ;
while ( addresses . size ( ) = = 0 ) {
if ( id ) {
addIdentity ( ) ;
addresses = ctx . addresses ( ) . getIdentities ( ) ;
} else {
addContact ( false ) ;
addresses = ctx . addresses ( ) . getContacts ( ) ;
}
2015-05-29 13:17:00 +02:00
}
2015-06-11 21:02:01 +02:00
if ( addresses . size ( ) = = 1 ) {
return addresses . get ( 0 ) ;
2015-05-29 13:17:00 +02:00
}
String command ;
do {
System . out . println ( ) ;
if ( id ) {
System . out . println ( " From: " ) ;
} else {
System . out . println ( " To: " ) ;
}
int i = 0 ;
2015-06-11 21:02:01 +02:00
for ( BitmessageAddress identity : addresses ) {
2015-05-29 13:17:00 +02:00
i + + ;
System . out . print ( i + " ) " ) ;
if ( identity . getAlias ( ) ! = null ) {
System . out . println ( identity . getAlias ( ) + " ( " + identity . getAddress ( ) + " ) " ) ;
} else {
System . out . println ( identity . getAddress ( ) ) ;
}
}
System . out . println ( " b) back " ) ;
command = nextCommand ( ) ;
switch ( command ) {
case " b " :
return null ;
default :
try {
int index = Integer . parseInt ( command ) - 1 ;
2015-06-11 21:02:01 +02:00
if ( addresses . get ( index ) ! = null ) {
return addresses . get ( index ) ;
2015-05-29 13:17:00 +02:00
}
} catch ( NumberFormatException e ) {
System . out . println ( " Unknown command. Please try again. " ) ;
}
}
} while ( ! " b " . equals ( command ) ) ;
return null ;
2015-05-22 20:51:57 +02:00
}
private void compose ( BitmessageAddress from , BitmessageAddress to , String subject ) {
2015-06-09 22:45:24 +02:00
boolean broadcast = ( to = = null ) ;
2015-05-22 20:51:57 +02:00
System . out . println ( ) ;
2015-05-29 13:17:00 +02:00
System . out . println ( " From: " + from ) ;
2015-06-09 22:45:24 +02:00
if ( ! broadcast ) {
System . out . println ( " To: " + to ) ;
}
2015-05-29 13:17:00 +02:00
if ( subject ! = null ) {
System . out . println ( " Subject: " + subject ) ;
} else {
System . out . print ( " Subject: " ) ;
2015-06-11 21:02:01 +02:00
subject = scanner . nextLine ( ) . trim ( ) ;
2015-05-29 13:17:00 +02:00
}
System . out . println ( " Message: " ) ;
StringBuilder message = new StringBuilder ( ) ;
String line ;
do {
2015-06-11 21:02:01 +02:00
line = scanner . nextLine ( ) ;
2015-05-29 13:17:00 +02:00
message . append ( line ) . append ( '\n' ) ;
} while ( line . length ( ) > 0 | | ! yesNo ( " Send message? " ) ) ;
2015-06-09 22:45:24 +02:00
if ( broadcast ) {
ctx . broadcast ( from , subject , message . toString ( ) ) ;
} else {
ctx . send ( from , to , subject , message . toString ( ) ) ;
}
2015-05-22 20:51:57 +02:00
}
private boolean yesNo ( String question ) {
String answer ;
do {
System . out . println ( question + " (y/n) " ) ;
answer = scanner . nextLine ( ) ;
if ( " y " . equalsIgnoreCase ( answer ) ) return true ;
if ( " n " . equalsIgnoreCase ( answer ) ) return false ;
} while ( true ) ;
}
}