Author: dbkr
Date: 2006-08-04 16:29:28 +0000 (Fri, 04 Aug 2006)
New Revision: 9884
Modified:
trunk/apps/Freemail/src/freemail/AccountManager.java
trunk/apps/Freemail/src/freemail/InboundContact.java
trunk/apps/Freemail/src/freemail/MessageSender.java
trunk/apps/Freemail/src/freemail/OutboundContact.java
Log:
Fix stuff relating to ACKs, and fights between long addresses and short ones
for the same outbound contact.
Modified: trunk/apps/Freemail/src/freemail/AccountManager.java
===================================================================
--- trunk/apps/Freemail/src/freemail/AccountManager.java 2006-08-04
15:47:27 UTC (rev 9883)
+++ trunk/apps/Freemail/src/freemail/AccountManager.java 2006-08-04
16:29:28 UTC (rev 9884)
@@ -212,6 +212,8 @@
PropsFile accfile = getAccountFile(accountdir);
+ alias = alias.toLowerCase();
+
MailSite ms = new MailSite(accfile);
if (ms.insertAlias(alias)) {
Modified: trunk/apps/Freemail/src/freemail/InboundContact.java
===================================================================
--- trunk/apps/Freemail/src/freemail/InboundContact.java 2006-08-04
15:47:27 UTC (rev 9883)
+++ trunk/apps/Freemail/src/freemail/InboundContact.java 2006-08-04
16:29:28 UTC (rev 9884)
@@ -134,6 +134,13 @@
}
System.out.println("You've got mail!");
sm.slotUsed();
+ String ack_key = this.ibct_props.get("ackssk");
+ if (ack_key == null) {
+ System.out.println("Warning! Can't send message
acknowledgement - don't have an 'ackssk' entry! This message will eventually
bounce, even though you've received it.");
+ continue;
+ }
+ ack_key += "ack-"+id;
+ AckProcrastinator.put(ack_key);
}
}
Modified: trunk/apps/Freemail/src/freemail/MessageSender.java
===================================================================
--- trunk/apps/Freemail/src/freemail/MessageSender.java 2006-08-04 15:47:27 UTC
(rev 9883)
+++ trunk/apps/Freemail/src/freemail/MessageSender.java 2006-08-04 16:29:28 UTC
(rev 9884)
@@ -15,6 +15,7 @@
public static final String OUTBOX_DIR = "outbox";
private static final int MIN_RUN_TIME = 60000;
public static final String NIM_KEY_PREFIX = "KSK at freemail-nim-";
+ private static final int MAX_TRIES = 10;
private final File datadir;
private Thread senderthread;
@@ -35,7 +36,7 @@
this.senderthread.interrupt();
}
- private synchronized void copyToOutbox(File src, File outbox, String
to) throws IOException {
+ private void copyToOutbox(File src, File outbox, String to) throws
IOException {
File tempfile = File.createTempFile("fmail-msg-tmp", null,
Freemail.getTempDir());
FileOutputStream fos = new FileOutputStream(tempfile);
@@ -49,15 +50,22 @@
fis.close();
fos.close();
+ this.moveToOutbox(tempfile, 0, to, outbox);
+ }
+
+ // save a file to the outbox handling name collisions and atomicity
+ private void moveToOutbox(File f, int tries, String to, File outbox) {
File destfile;
int prefix = 1;
- do {
- String filename = prefix + ":" + to;
- destfile = new File(outbox, filename);
- prefix++;
- } while (destfile.exists());
+ synchronized (this.senderthread) {
+ do {
+ String filename = prefix + ":" + tries + ":" +
to;
+ destfile = new File(outbox, filename);
+ prefix++;
+ } while (destfile.exists());
- tempfile.renameTo(destfile);
+ f.renameTo(destfile);
+ }
}
public void run() {
@@ -100,12 +108,16 @@
}
private void sendSingle(File accdir, File msg) {
- String parts[] = msg.getName().split(":", 2);
+ String parts[] = msg.getName().split(":", 3);
EmailAddress addr;
- if (parts.length < 2) {
- addr = new EmailAddress(parts[0]);
+ int tries;
+ if (parts.length < 3) {
+ System.out.println("Warning invalid file in outbox -
deleting.");
+ msg.delete();
+ return;
} else {
- addr = new EmailAddress(parts[1]);
+ tries = Integer.parseInt(parts[1]);
+ addr = new EmailAddress(parts[2]);
}
if (addr.domain == null || addr.domain.length() == 0) {
@@ -122,6 +134,15 @@
} else {
if (this.sendSecure(accdir, addr, msg)) {
msg.delete();
+ } else {
+ tries++;
+ if (tries > MAX_TRIES) {
+ if (Postman.bounceMessage(msg, new
MessageBank(accdir.getName()), "Tried too many times to deliver this message,
but it doesn't apear that this address even exists. If you're sure that it
does, check your Freenet connection.")) {
+ msg.delete();
+ }
+ } else {
+ this.moveToOutbox(msg, tries, parts[2],
msg.getParentFile());
+ }
}
}
}
@@ -134,6 +155,13 @@
} catch (BadFreemailAddressException bfae) {
// bounce
return Postman.bounceMessage(msg, new
MessageBank(accdir.getName()), "The address that this message was destined for
("+addr+") is not a valid Freemail address.");
+ } catch (OutboundContactFatalException obfe) {
+ // bounce
+ return Postman.bounceMessage(msg, new
MessageBank(accdir.getName()), obfe.getMessage());
+ } catch (IOException ioe) {
+ // couldn't get the mailsite - try again if you're not
ready
+ //to give up yet
+ return false;
}
return ct.sendMessage(msg);
Modified: trunk/apps/Freemail/src/freemail/OutboundContact.java
===================================================================
--- trunk/apps/Freemail/src/freemail/OutboundContact.java 2006-08-04
15:47:27 UTC (rev 9883)
+++ trunk/apps/Freemail/src/freemail/OutboundContact.java 2006-08-04
16:29:28 UTC (rev 9884)
@@ -8,6 +8,7 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.FileNotFoundException;
+import java.net.MalformedURLException;
import java.math.BigInteger;
import java.security.SecureRandom;
@@ -52,10 +53,10 @@
private static final int AES_KEY_LENGTH = 256 / 8;
// this is defined in the AES standard (although the Rijndael
// algorithm does support other block sizes.
- // we read 128 bytes for our IV, so it needs to be constant.
+ // we read 128 bytes for our IV, so it needs to be constant.)
private static final int AES_BLOCK_LENGTH = 128 / 8;
- public OutboundContact(File accdir, EmailAddress a) throws
BadFreemailAddressException {
+ public OutboundContact(File accdir, EmailAddress a) throws
BadFreemailAddressException, IOException, OutboundContactFatalException {
this.address = a;
this.accdir = accdir;
@@ -72,8 +73,23 @@
if (!outbounddir.exists())
outbounddir.mkdir();
- File obctdir = new File(outbounddir,
this.address.getSubDomain());
+ if (!this.address.is_ssk_address()) {
+ String ssk_mailsite =
this.fetchKSKRedirect(this.address.getMailpageKey());
+
+ if (ssk_mailsite == null) throw new
IOException();
+
+ FreenetURI furi;
+ try {
+ furi = new FreenetURI(ssk_mailsite);
+ } catch (MalformedURLException mfue) {
+ throw new
OutboundContactFatalException("The Freemail address points to an invalid
redirect, and is therefore useless.");
+ }
+
+ this.address.domain =
Base32.encode(furi.getKeyBody().getBytes())+".freemail";
+ }
+ File obctdir = new File(outbounddir,
this.address.getSubDomain().toLowerCase());
+
if (!obctdir.exists())
obctdir.mkdir();
@@ -111,7 +127,7 @@
if (ctskey == null) {
this.init();
}
- ctskey += "ack";
+ ctskey += "cts";
HighLevelFCPClient fcpcli = new HighLevelFCPClient();
@@ -369,6 +385,43 @@
return true;
}
+ // fetch the redirect (assumes that this is a KSK address)
+ private String fetchKSKRedirect(String key) throws
OutboundContactFatalException {
+ HighLevelFCPClient cli = new HighLevelFCPClient();
+
+ System.out.println("Attempting to fetch mailsite redirect
"+key);
+ File result = cli.fetch(key);
+
+ if (result == null) {
+ System.out.println("Failed to retrieve mailsite
redirect "+key);
+ return null;
+ }
+
+ if (result.length() > 512) {
+ System.out.println("Fatal: mailsite redirect too long.
Ignoring.");
+ result.delete();
+ throw new OutboundContactFatalException("Mailsite
redirect too long.");
+ }
+
+ BufferedReader br = null;
+ try {
+ br = new BufferedReader(new FileReader(result));
+ } catch (FileNotFoundException fnfe) {
+ // impossible
+ }
+
+ String addr;
+ try {
+ addr = br.readLine();
+ br.close();
+ } catch (IOException ioe) {
+ System.out.println("Warning: IO exception whilst
reading mailsite redirect file: "+ioe.getMessage());
+ return null;
+ }
+ result.delete();
+ return addr;
+ }
+
private boolean fetchMailSite() throws OutboundContactFatalException {
HighLevelFCPClient cli = new HighLevelFCPClient();
@@ -380,36 +433,6 @@
return false;
}
- if (!this.address.is_ssk_address()) {
- // presumably a KSK 'redirect'. Follow it.
- BufferedReader br = null;
- try {
- br = new BufferedReader(new
FileReader(mailsite_file));
- } catch (FileNotFoundException fnfe) {
- // impossible
- }
-
- if (mailsite_file.length() > 512) {
- System.out.println("Fatal: mailsite redirect
too long. Ignoring.");
- throw new
OutboundContactFatalException("Mailsite redirect too long.");
- }
-
- String addr;
- try {
- addr = br.readLine();
- br.close();
- } catch (IOException ioe) {
- System.out.println("Warning: IO exception
whilst reading mailsite redirect file: "+ioe.getMessage());
- return false;
- }
- mailsite_file.delete();
- mailsite_file = cli.fetch(addr);
- if (mailsite_file == null) {
- System.out.println("Failed to retrieve
redirected mailsite "+addr);
- return false;
- }
- }
-
System.out.println("got mailsite");
PropsFile mailsite = new PropsFile(mailsite_file);
@@ -610,8 +633,10 @@
continue;
}
- key += msgs[i].uid;
+ key += "ack-"+msgs[i].uid;
+ System.out.println("Looking for message ack on "+key);
+
File ack = fcpcli.fetch(key);
if (ack != null) {
System.out.println("Ack received for message
"+msgs[i].uid+" on contact "+this.address.domain+". Now that's a job well
done.");
@@ -622,6 +647,7 @@
// delete inital slot for forward secrecy
this.contactfile.remove("initialslot");
} else {
+ System.out.println("Failed to receive ack on
"+key);
if (System.currentTimeMillis() >
msgs[i].first_send_time + FAIL_DELAY) {
// give up and bounce the message
File m = msgs[i].getMessageFile();