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 ;
2016-02-28 23:03:00 +01:00
import ch.dissem.bitmessage.cryptography.bc.BouncyCryptography ;
2015-05-22 20:51:57 +02:00
import ch.dissem.bitmessage.entity.BitmessageAddress ;
import ch.dissem.bitmessage.entity.Plaintext ;
import ch.dissem.bitmessage.entity.payload.Pubkey ;
2016-04-11 15:10:59 +02:00
import ch.dissem.bitmessage.entity.valueobject.Label ;
2016-07-25 07:52:27 +02:00
import ch.dissem.bitmessage.networking.nio.NioNetworkHandler ;
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-04-25 08:13:46 +02:00
import org.apache.commons.lang3.text.WordUtils ;
2015-05-22 20:51:57 +02:00
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
2016-01-21 20:32:23 +01:00
import java.net.InetAddress ;
2015-05-22 20:51:57 +02:00
import java.util.List ;
2016-04-11 15:10:59 +02:00
import java.util.stream.Collectors ;
2016-02-28 23:03:00 +01:00
import static ch.dissem.bitmessage.demo.CommandLine.COMMAND_BACK ;
import static ch.dissem.bitmessage.demo.CommandLine.ERROR_UNKNOWN_COMMAND ;
2015-05-22 20:51:57 +02:00
/ * *
* A simple command line Bitmessage application
* /
public class Application {
private final static Logger LOG = LoggerFactory . getLogger ( Application . class ) ;
2016-02-28 23:03:00 +01:00
private final CommandLine commandLine ;
2015-05-22 20:51:57 +02:00
private BitmessageContext ctx ;
2016-02-28 23:03:00 +01:00
public Application ( InetAddress 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 ) )
2016-07-25 07:52:27 +02:00
. networkHandler ( new NioNetworkHandler ( ) )
2016-01-10 13:38:32 +01:00
. cryptography ( new BouncyCryptography ( ) )
2015-10-14 18:37:43 +02:00
. port ( 48444 )
2016-04-25 08:13:46 +02:00
. listener ( plaintext - > System . out . println ( " New Message from " + plaintext . getFrom ( ) + " : " + plaintext . getSubject ( ) ) )
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
2016-02-28 23:03:00 +01:00
commandLine = new CommandLine ( ) ;
2015-05-22 20:51:57 +02:00
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
2016-02-28 23:03:00 +01:00
command = commandLine . nextCommand ( ) ;
2015-05-22 20:51:57 +02:00
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 " :
2016-04-15 17:18:11 +02:00
labels ( ) ;
2015-05-22 20:51:57 +02:00
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 " :
2016-02-28 23:03:00 +01:00
if ( syncServer ! = null ) {
ctx . synchronize ( syncServer , syncPort , 120 , true ) ;
}
2016-01-21 20:32:23 +01:00
break ;
2015-05-22 20:51:57 +02:00
default :
2016-02-28 23:03:00 +01:00
System . out . println ( ERROR_UNKNOWN_COMMAND ) ;
2015-05-22 20:51:57 +02:00
}
} 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 ( ) {
2016-05-24 17:19:29 +02:00
String command ;
do {
System . out . println ( ) ;
System . out . println ( ctx . status ( ) ) ;
System . out . println ( ) ;
System . out . println ( " c) cleanup inventory " ) ;
System . out . println ( " r) resend unacknowledged messages " ) ;
System . out . println ( COMMAND_BACK ) ;
command = commandLine . nextCommand ( ) ;
switch ( command ) {
case " c " :
ctx . cleanup ( ) ;
break ;
case " r " :
ctx . resendUnacknowledgedMessages ( ) ;
break ;
case " b " :
return ;
}
} while ( ! " b " . equals ( command ) ) ;
2015-06-16 06:41:59 +02:00
}
2015-05-22 20:51:57 +02:00
private void identities ( ) {
String command ;
List < BitmessageAddress > identities = ctx . addresses ( ) . getIdentities ( ) ;
do {
System . out . println ( ) ;
2016-02-28 23:03:00 +01:00
commandLine . listAddresses ( identities , " identities " ) ;
2015-05-22 20:51:57 +02:00
System . out . println ( " a) create identity " ) ;
2016-04-07 17:24:56 +02:00
System . out . println ( " c) join chan " ) ;
2016-02-28 23:03:00 +01:00
System . out . println ( COMMAND_BACK ) ;
2015-05-22 20:51:57 +02:00
2016-02-28 23:03:00 +01:00
command = commandLine . nextCommand ( ) ;
2015-05-22 20:51:57 +02:00
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 ;
2016-04-07 17:24:56 +02:00
case " c " :
joinChan ( ) ;
identities = ctx . addresses ( ) . getIdentities ( ) ;
break ;
2015-05-22 20:51:57 +02:00
case " b " :
return ;
default :
try {
int index = Integer . parseInt ( command ) - 1 ;
address ( identities . get ( index ) ) ;
} catch ( NumberFormatException e ) {
2016-02-28 23:03:00 +01:00
System . out . println ( ERROR_UNKNOWN_COMMAND ) ;
2015-05-22 20:51:57 +02:00
}
}
} while ( ! " b " . equals ( command ) ) ;
}
private void addIdentity ( ) {
System . out . println ( ) ;
2016-02-28 23:03:00 +01:00
BitmessageAddress identity = ctx . createIdentity ( commandLine . yesNo ( " would you like a shorter address? This will take some time to calculate. " ) , Pubkey . Feature . DOES_ACK ) ;
2015-05-22 20:51:57 +02:00
System . out . println ( " Please enter an alias for this identity, or an empty string for none " ) ;
2016-02-28 23:03:00 +01:00
String alias = commandLine . nextLineTrimmed ( ) ;
2015-05-22 20:51:57 +02:00
if ( alias . length ( ) > 0 ) {
identity . setAlias ( alias ) ;
}
ctx . addresses ( ) . save ( identity ) ;
}
2016-04-07 17:24:56 +02:00
private void joinChan ( ) {
System . out . println ( ) ;
System . out . print ( " Passphrase: " ) ;
String passphrase = commandLine . nextLine ( ) ;
System . out . print ( " Address: " ) ;
String address = commandLine . nextLineTrimmed ( ) ;
ctx . joinChan ( passphrase , address ) ;
}
2015-05-22 20:51:57 +02:00
private void contacts ( ) {
String command ;
List < BitmessageAddress > contacts = ctx . addresses ( ) . getContacts ( ) ;
do {
System . out . println ( ) ;
2016-02-28 23:03:00 +01:00
commandLine . listAddresses ( contacts , " contacts " ) ;
2015-05-22 20:51:57 +02:00
System . out . println ( ) ;
System . out . println ( " a) add contact " ) ;
2016-02-28 23:03:00 +01:00
System . out . println ( COMMAND_BACK ) ;
2015-05-22 20:51:57 +02:00
2016-02-28 23:03:00 +01:00
command = commandLine . nextCommand ( ) ;
2015-05-22 20:51:57 +02:00
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 ) {
2016-02-28 23:03:00 +01:00
System . out . println ( ERROR_UNKNOWN_COMMAND ) ;
2015-05-22 20:51:57 +02:00
}
}
} 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 {
2016-02-28 23:03:00 +01:00
BitmessageAddress address = new BitmessageAddress ( commandLine . nextLineTrimmed ( ) ) ;
2015-05-22 20:51:57 +02:00
System . out . println ( " Please enter an alias for this address, or an empty string for none " ) ;
2016-02-28 23:03:00 +01:00
String alias = commandLine . nextLineTrimmed ( ) ;
2015-05-22 20:51:57 +02:00
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 ( ) ;
2016-02-28 23:03:00 +01:00
commandLine . listAddresses ( subscriptions , " subscriptions " ) ;
2015-06-09 22:45:24 +02:00
System . out . println ( ) ;
System . out . println ( " a) add subscription " ) ;
2016-02-28 23:03:00 +01:00
System . out . println ( COMMAND_BACK ) ;
2015-06-09 22:45:24 +02:00
2016-02-28 23:03:00 +01:00
command = commandLine . nextCommand ( ) ;
2015-06-09 22:45:24 +02:00
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 ) {
2016-02-28 23:03:00 +01:00
System . out . println ( ERROR_UNKNOWN_COMMAND ) ;
2015-06-09 22:45:24 +02:00
}
}
} 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
}
2016-04-07 17:24:56 +02:00
} else {
if ( address . isChan ( ) ) {
System . out . println ( " Chan " ) ;
} else {
System . out . println ( " Identity " ) ;
}
2015-05-29 13:17:00 +02:00
}
2015-05-22 20:51:57 +02:00
}
2016-04-15 17:18:11 +02:00
private void labels ( ) {
List < Label > labels = ctx . messages ( ) . getLabels ( ) ;
2015-05-22 20:51:57 +02:00
String command ;
do {
2016-04-15 17:18:11 +02:00
System . out . println ( ) ;
int i = 0 ;
for ( Label label : labels ) {
i + + ;
2016-04-25 08:13:46 +02:00
System . out . print ( i + " ) " + label ) ;
int unread = ctx . messages ( ) . countUnread ( label ) ;
if ( unread > 0 ) {
System . out . println ( " [ " + unread + " ] " ) ;
} else {
System . out . println ( ) ;
}
2016-04-15 17:18:11 +02:00
}
System . out . println ( " a) Archive " ) ;
System . out . println ( ) ;
System . out . println ( " c) compose message " ) ;
System . out . println ( " s) compose broadcast " ) ;
System . out . println ( COMMAND_BACK ) ;
command = commandLine . nextCommand ( ) ;
switch ( command ) {
case " a " :
messages ( null ) ;
break ;
case " c " :
compose ( false ) ;
break ;
case " s " :
compose ( true ) ;
break ;
case " b " :
return ;
default :
try {
int index = Integer . parseInt ( command ) - 1 ;
messages ( labels . get ( index ) ) ;
} catch ( NumberFormatException | IndexOutOfBoundsException e ) {
System . out . println ( ERROR_UNKNOWN_COMMAND ) ;
}
}
} while ( ! " b " . equalsIgnoreCase ( command ) ) ;
}
private void messages ( Label label ) {
String command ;
do {
List < Plaintext > messages = ctx . messages ( ) . findMessages ( label ) ;
2015-05-22 20:51:57 +02:00
System . out . println ( ) ;
int i = 0 ;
for ( Plaintext message : messages ) {
i + + ;
2016-04-15 17:18:11 +02:00
System . out . println ( i + ( message . isUnread ( ) ? " > " : " ) " ) + " From: " + message . getFrom ( ) + " ; Subject: " + message . getSubject ( ) ) ;
2015-05-22 20:51:57 +02:00
}
if ( i = = 0 ) {
2016-04-15 17:18:11 +02:00
System . out . println ( " There are no messages. " ) ;
2015-05-22 20:51:57 +02:00
}
System . out . println ( ) ;
System . out . println ( " c) compose message " ) ;
2015-06-09 22:45:24 +02:00
System . out . println ( " s) compose broadcast " ) ;
2016-04-15 17:18:11 +02:00
if ( label . getType ( ) = = Label . Type . TRASH ) {
System . out . println ( " e) empty trash " ) ;
}
2016-02-28 23:03:00 +01:00
System . out . println ( COMMAND_BACK ) ;
2015-05-22 20:51:57 +02:00
2016-02-28 23:03:00 +01:00
command = commandLine . nextCommand ( ) ;
2015-05-22 20:51:57 +02:00
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 ;
2016-04-15 17:18:11 +02:00
case " e " :
messages . forEach ( ctx . messages ( ) : : remove ) ;
2015-05-22 20:51:57 +02:00
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 ) {
2016-02-28 23:03:00 +01:00
System . out . println ( ERROR_UNKNOWN_COMMAND ) ;
2015-05-22 20:51:57 +02:00
}
}
} 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 ( ) ;
2016-04-25 08:13:46 +02:00
System . out . println ( WordUtils . wrap ( message . getText ( ) , 120 ) ) ;
2015-05-22 20:51:57 +02:00
System . out . println ( ) ;
2016-04-11 15:10:59 +02:00
System . out . println ( message . getLabels ( ) . stream ( ) . map ( Label : : toString ) . collect (
2016-04-15 17:18:11 +02:00
Collectors . joining ( " , " , " Labels: " , " " ) ) ) ;
2015-05-29 13:17:00 +02:00
System . out . println ( ) ;
2016-04-11 15:10:59 +02:00
ctx . labeler ( ) . markAsRead ( message ) ;
2016-04-15 17:18:11 +02:00
ctx . messages ( ) . save ( message ) ;
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 " ) ;
2016-04-15 17:18:11 +02:00
System . out . println ( " a) archive " ) ;
2016-02-28 23:03:00 +01:00
System . out . println ( COMMAND_BACK ) ;
command = commandLine . nextCommand ( ) ;
2015-05-22 20:51:57 +02:00
switch ( command ) {
case " r " :
compose ( message . getTo ( ) , message . getFrom ( ) , " RE: " + message . getSubject ( ) ) ;
break ;
case " d " :
2016-04-15 17:18:11 +02:00
ctx . labeler ( ) . delete ( message ) ;
ctx . messages ( ) . save ( message ) ;
return ;
case " a " :
ctx . labeler ( ) . archive ( message ) ;
ctx . messages ( ) . save ( message ) ;
return ;
2015-05-22 20:51:57 +02:00
case " b " :
return ;
default :
2016-02-28 23:03:00 +01:00
System . out . println ( ERROR_UNKNOWN_COMMAND ) ;
2015-05-22 20:51:57 +02:00
}
} 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 ( ) ;
2016-02-28 23:03:00 +01:00
BitmessageAddress from = selectIdentity ( ) ;
2015-06-11 21:02:01 +02:00
if ( from = = null ) {
return ;
}
2016-02-28 23:03:00 +01:00
BitmessageAddress to = ( broadcast ? null : selectContact ( ) ) ;
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 ) ;
}
2016-02-28 23:03:00 +01:00
private BitmessageAddress selectIdentity ( ) {
List < BitmessageAddress > addresses = ctx . addresses ( ) . getIdentities ( ) ;
2015-06-11 21:02:01 +02:00
while ( addresses . size ( ) = = 0 ) {
2016-02-28 23:03:00 +01:00
addIdentity ( ) ;
addresses = ctx . addresses ( ) . getIdentities ( ) ;
2015-05-29 13:17:00 +02:00
}
2016-02-28 23:03:00 +01:00
return commandLine . selectAddress ( addresses , " From: " ) ;
}
2015-05-29 13:17:00 +02:00
2016-02-28 23:03:00 +01:00
private BitmessageAddress selectContact ( ) {
List < BitmessageAddress > addresses = ctx . addresses ( ) . getContacts ( ) ;
while ( addresses . size ( ) = = 0 ) {
addContact ( false ) ;
addresses = ctx . addresses ( ) . getContacts ( ) ;
}
return commandLine . selectAddress ( addresses , " To: " ) ;
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: " ) ;
2016-02-28 23:03:00 +01:00
subject = commandLine . nextLineTrimmed ( ) ;
2015-05-29 13:17:00 +02:00
}
System . out . println ( " Message: " ) ;
StringBuilder message = new StringBuilder ( ) ;
String line ;
do {
2016-02-28 23:03:00 +01:00
line = commandLine . nextLine ( ) ;
2015-05-29 13:17:00 +02:00
message . append ( line ) . append ( '\n' ) ;
2016-02-28 23:03:00 +01:00
} while ( line . length ( ) > 0 | | ! commandLine . 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
}
}