I2P Address: [http://git.idk.i2p]

Skip to content
Snippets Groups Projects
Commit 66b19326 authored by zzz's avatar zzz
Browse files

Dropping apps/atalk demo, which was an awful example as it was apparently written

before streaming existed, so it's trying to do chat and file transfer
with datagrams and no error detection / correction.
parent 164f6603
No related branches found
No related tags found
No related merge requests found
package net.i2p.client;
/*
* free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain
* with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk.
*
*/
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;
import net.i2p.I2PAppContext;
import net.i2p.I2PException;
import net.i2p.data.DataFormatException;
import net.i2p.data.Destination;
import net.i2p.util.Clock;
import net.i2p.util.I2PThread;
import net.i2p.util.Log;
/**
* ATalk - anonymous talk, demonstrating a trivial I2P usage scenario.
* Run this class with no arguments for a manual.
*
* @author jrandom
*/
public class ATalk implements I2PSessionListener, Runnable {
/** logging hook - status messages are piped to this */
private final static Log _log = new Log(ATalk.class);
/** platform independent newline */
private final static String NL = System.getProperty("line.separator");
/** the current session */
private I2PSession _session;
/** who am i */
private Destination _myDestination;
/** who are you? */
private Destination _peerDestination;
/** location of my secret key file */
private String _myKeyFile;
/** location of their public key */
private String _theirDestinationFile;
/** where the application reads input from. currently set to standard input */
private BufferedReader _in;
/** where the application sends output to. currently set to standard output */
private BufferedWriter _out;
/** string that messages must begin with to be treated as files */
private final static String FILE_COMMAND = ".file: ";
/** the, erm, manual */
private final static String MANUAL = "ATalk: Anonymous Talk, a demo program for the Invisible Internet Project SDK"
+ NL
+ "To generate a new destination:"
+ NL
+ "\tATalk [fileToSavePrivateKeyIn] [fileToSavePublicKeyIn]"
+ NL
+ "To talk to another destination:"
+ NL
+ "\tATalk [myPrivateKeyFile] [peerPublicKey] [shouldLogToScreen]"
+ NL
+ "shouldLogToScreen is 'true' or 'false', depending on whether you want log info on the screen"
+ NL
+ "When talking to another destination, messages are sent after you hit return"
+ NL
+ "To send a file, send a message saying:"
+ NL
+ "\t"
+ FILE_COMMAND
+ "[filenameToSend]"
+ NL
+ "The peer will then recieve the file and be notified of where it has been saved"
+ NL
+ "To end the talk session, enter a period on a line by itself and hit return"
+ NL;
public final static String PROP_CONFIG_LOCATION = "configFile";
private static final SimpleDateFormat _fmt = new SimpleDateFormat("hh:mm:ss.SSS");
/** Construct the talk engine, but don't connect yet */
public ATalk(String myKeyFile, String theirDestFile) {
_myKeyFile = myKeyFile;
_theirDestinationFile = theirDestFile;
}
/** Actually start up the connection to the I2P network.
* Successful connect does not mean the peer is online or reachable.
*
* @throws IOException if there is a problem reading in the keys from the files specified
* @throws DataFormatException if the key files are not in the valid format
* @throws I2PSessionException if there is a problem contacting the I2P router
*/
public void connect() throws IOException, I2PSessionException, DataFormatException {
I2PClient client = I2PClientFactory.createClient();
File myFile = new File(_myKeyFile);
Properties props = new Properties();
String configLocation = System.getProperty(PROP_CONFIG_LOCATION, "atalk.config");
try {
props.load(new FileInputStream(configLocation));
} catch (FileNotFoundException fnfe) {
_log.warn("Unable to load up the ATalk config file " + configLocation);
}
// Provide any router or client API configuration here.
if (!props.containsKey(I2PClient.PROP_TCP_HOST))
props.setProperty(I2PClient.PROP_TCP_HOST, "localhost");
if (!props.containsKey(I2PClient.PROP_TCP_PORT))
props.setProperty(I2PClient.PROP_TCP_PORT, "7654");
if (!props.containsKey(I2PClient.PROP_RELIABILITY))
props.setProperty(I2PClient.PROP_RELIABILITY, I2PClient.PROP_RELIABILITY_BEST_EFFORT);
_session = client.createSession(new FileInputStream(myFile), props);
_session.setSessionListener(this);
_session.connect();
File peerDestFile = new File(_theirDestinationFile);
_peerDestination = new Destination();
_peerDestination.readBytes(new FileInputStream(peerDestFile));
return;
}
/** Actual bulk processing of the application, reading in user input,
* sending messages, and displaying results. When this function exits, the
* application is complete.
*
*/
public void run() {
try {
connect();
_in = new BufferedReader(new InputStreamReader(System.in));
_out = new BufferedWriter(new OutputStreamWriter(System.out));
_out.write("Starting up anonymous talk session" + NL);
while (true) {
String line = _in.readLine();
if ((line == null) || (line.trim().length() <= 0)) continue;
if (".".equals(line)) {
boolean ok = _session.sendMessage(_peerDestination, ("Peer disconnected at " + now()).getBytes());
// ignore ok, we're closing
break;
}
if (line.startsWith(FILE_COMMAND) && (line.trim().length() > FILE_COMMAND.length())) {
try {
String file = line.substring(FILE_COMMAND.length());
boolean sent = sendFile(file);
if (!sent) {
_out.write("Failed sending the file: " + file + NL);
}
} catch (IOException ioe) {
_out.write("Error sending the file: " + ioe.getMessage() + NL);
_log.error("Error sending the file", ioe);
}
} else {
boolean ok = _session.sendMessage(_peerDestination, ("[" + now() + "] " + line).getBytes());
if (!ok) {
_out.write("Failed sending message. Peer disconnected?" + NL);
}
}
}
} catch (IOException ioe) {
_log.error("Error running", ioe);
} catch (I2PSessionException ise) {
_log.error("Error communicating", ise);
} catch (DataFormatException dfe) {
_log.error("Peer destination file is not valid", dfe);
} finally {
try {
_log.debug("Exiting anonymous talk session");
if (_out != null) _out.write("Exiting anonymous talk session");
} catch (IOException ioe) {
// ignored
}
if (_session != null) {
try {
_session.destroySession();
} catch (I2PSessionException ise) {
// ignored
}
}
try {
Thread.sleep(5000);
} catch (InterruptedException ie) { // nop!
}
}
}
private String now() {
Date now = new Date(Clock.getInstance().now());
return _fmt.format(now);
}
/** Send the given file to the current peer. This works by sending a message
* saying ".file: filename\nbodyOfFile", where filename is the name of the file
* (which the recipient will be shown), and the bodyOfFile is the set of raw
* bytes in the file.
*
* @throws IOException if the file could not be found or read
* @return false if the file could not be sent to the peer
*/
private boolean sendFile(String filename) throws IOException, I2PSessionException {
_log.debug("Sending file [" + filename + "]");
ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
baos.write((FILE_COMMAND + filename + "\n").getBytes());
FileInputStream fin = new FileInputStream(filename);
byte buf[] = new byte[4096];
try {
while (true) {
int len = fin.read(buf);
if (len == -1) break;
baos.write(buf, 0, len);
}
} catch (IOException ioe) {
_log.debug("Failed reading the file", ioe);
return false;
}
baos.close();
byte val[] = baos.toByteArray();
_log.debug("Sending " + filename + " with a full payload of " + val.length);
try {
boolean rv = _session.sendMessage(_peerDestination, val);
_log.debug("Sending " + filename + " complete: rv = " + rv);
return rv;
} catch (Throwable t) {
_log.error("Error sending file", t);
return false;
}
}
/** I2PSessionListener.messageAvailable requires this method to be called whenever
* I2P wants to tell the session that a message is available. ATalk always grabs
* the message immediately and either processes it as a "send file" command (passing
* it off to handleRecieveFile(..) or simply displays the
* message to the user.
*
*/
public void messageAvailable(I2PSession session, int msgId, long size) {
_log.debug("Message available: id = " + msgId + " size = " + size);
try {
byte msg[] = session.receiveMessage(msgId);
// inefficient way to just read the first line of text, but its easy
BufferedReader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(msg)));
String line = reader.readLine();
if (line.startsWith(FILE_COMMAND)) {
handleRecieveFile(line, msg);
} else {
// not a file command, so just plop 'er out on the screen
_out.write(now() + " --> " + new String(msg));
_out.write(NL);
_out.flush();
}
} catch (I2PSessionException ise) {
_log.error("Error fetching available message", ise);
} catch (IOException ioe) {
_log.error("Error writing out the message", ioe);
}
}
/** React to a file being sent our way from the peer via {@link #sendFile sendFile}
* by saving the file to a temporary location and displaying where, what, and how large
* it is.
*
* @param firstline the first line of the message that, according to the sendFile
* implementation, contains the command and the filename that it was stored
* at on the peer's computer
* @param msg the entire message recieved, including the firstline
*/
private void handleRecieveFile(String firstline, byte msg[]) throws IOException {
_log.debug("handleRecieveFile called");
File f = File.createTempFile("recieve", ".dat", new File("."));
FileOutputStream fos = new FileOutputStream(f);
int lineLen = firstline.getBytes().length + "\n".getBytes().length;
int lenToCopy = msg.length - lineLen;
byte buf[] = new byte[lenToCopy];
System.arraycopy(msg, lineLen, buf, 0, lenToCopy);
fos.write(buf);
fos.close();
String name = firstline.substring(FILE_COMMAND.length());
_out.write("Recieved a file called [" + name + "] of size [" + lenToCopy + "] bytes, saved as ["
+ f.getAbsolutePath() + "]" + NL);
_out.flush();
}
/** driver */
public static void main(String args[]) {
I2PAppContext context = new I2PAppContext();
if (args.length == 2) {
String myKeyFile = args[0];
String myDestinationFile = args[1];
boolean success = generateKeys(myKeyFile, myDestinationFile);
if (success)
_log.debug("Keys generated (private key file: " + myKeyFile + " destination file: " + myDestinationFile
+ ")");
else
_log.debug("Keys generation failed");
try {
Thread.sleep(5000);
} catch (InterruptedException ie) { // nop
}
} else if (args.length == 3) {
_log.debug("Starting chat");
String myKeyfile = args[0];
String peerDestFile = args[1];
String shouldLog = args[2];
if (Boolean.TRUE.toString().equalsIgnoreCase(shouldLog))
context.logManager().setDisplayOnScreen(true);
else
context.logManager().setDisplayOnScreen(false);
String logFile = args[2];
Thread talkThread = new I2PThread(new ATalk(myKeyfile, peerDestFile));
talkThread.start();
} else {
System.out.println(MANUAL);
try {
Thread.sleep(5000);
} catch (InterruptedException ie) { // nop
}
System.exit(-1);
}
}
/** Generate a new Destination, saving that destination and the associated
* private keys in the privKeyFile, and also saving the destination without
* any private keys to destinationFile.
*
* @param privKeyFile private key file, including the destination and the various
* private keys, as defined by {@link I2PClient#createDestination I2PClient.createDestination}
* @param destinationFile file in which the Destination is serialized in
*/
private static boolean generateKeys(String privKeyFile, String destinationFile) {
try {
Destination d = I2PClientFactory.createClient().createDestination(new FileOutputStream(privKeyFile));
FileOutputStream fos = new FileOutputStream(destinationFile);
d.writeBytes(fos);
fos.flush();
fos.close();
return true;
} catch (IOException ioe) {
_log.error("Error generating keys", ioe);
} catch (I2PException ipe) {
_log.error("Error generating keys", ipe);
}
return false;
}
/** required by {@link I2PSessionListener I2PSessionListener} to notify of disconnect */
public void disconnected(I2PSession session) {
_log.debug("Disconnected");
}
/** required by {@link I2PSessionListener I2PSessionListener} to notify of error */
public void errorOccurred(I2PSession session, String message, Throwable error) {
_log.debug("Error occurred: " + message, error);
}
/** required by {@link I2PSessionListener I2PSessionListener} to notify of abuse */
public void reportAbuse(I2PSession session, int severity) {
_log.debug("Abuse reported of severity " + severity);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment