Author: dbkr
Date: 2006-06-22 19:11:33 +0000 (Thu, 22 Jun 2006)
New Revision: 9354
Added:
trunk/apps/Freemail/src/freemail/BadFreemailAddressException.java
trunk/apps/Freemail/src/freemail/OutboundContact.java
trunk/apps/Freemail/src/freemail/OutboundContactFatalException.java
Modified:
trunk/apps/Freemail/build.xml
trunk/apps/Freemail/src/freemail/AccountManager.java
trunk/apps/Freemail/src/freemail/Freemail.java
trunk/apps/Freemail/src/freemail/MailFetcher.java
trunk/apps/Freemail/src/freemail/MailSite.java
trunk/apps/Freemail/src/freemail/MessageSender.java
trunk/apps/Freemail/src/freemail/SingleAccountWatcher.java
trunk/apps/Freemail/src/freemail/utils/EmailAddress.java
trunk/apps/Freemail/src/freemail/utils/PropsFile.java
Log:
Work towards sending the RTS message. Doesn't work just yet as the message is
bigger than an RSA block.
Modified: trunk/apps/Freemail/build.xml
===================================================================
--- trunk/apps/Freemail/build.xml 2006-06-22 18:39:47 UTC (rev 9353)
+++ trunk/apps/Freemail/build.xml 2006-06-22 19:11:33 UTC (rev 9354)
@@ -23,8 +23,8 @@
<target name="bouncycastle-compile" depends="bouncycastle-fetch"
unless="bouncycastle-bin.present">
<mkdir dir="build" />
- <javac srcdir="${deps}/${bcdist}/src" destdir="${build}"
debug="off" optimize="on" source="1.4" nowarn="true">
- <exclude name="**/test/*" />
+ <javac srcdir="${deps}/${bcdist}/src" destdir="${build}"
debug="on" optimize="on" source="1.4" nowarn="true">
+ <!--<exclude name="**/test/*" />-->
</javac>
</target>
Modified: trunk/apps/Freemail/src/freemail/AccountManager.java
===================================================================
--- trunk/apps/Freemail/src/freemail/AccountManager.java 2006-06-22
18:39:47 UTC (rev 9353)
+++ trunk/apps/Freemail/src/freemail/AccountManager.java 2006-06-22
19:11:33 UTC (rev 9354)
@@ -9,17 +9,18 @@
import java.util.Random;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
import java.math.BigInteger;
import org.bouncycastle.crypto.generators.RSAKeyPairGenerator;
import org.bouncycastle.crypto.params.RSAKeyGenerationParameters;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.params.RSAKeyParameters;
-import java.security.SecureRandom;
+import org.bouncycastle.util.encoders.Hex;
import freemail.fcp.HighLevelFCPClient;
import freemail.fcp.SSKKeyPair;
-import freemail.util.PropsFile;
+import freemail.utils.PropsFile;
public class AccountManager {
public static final String DATADIR = "data";
@@ -33,6 +34,8 @@
private static final BigInteger ASYM_KEY_EXPONENT = new
BigInteger("17", 10);
private static final int ASYM_KEY_CERTAINTY = 80;
+ public static final String MAILSITE_SUFFIX = "mailsite";
+
public static void Create(String username) throws IOException {
File datadir = new File(DATADIR);
@@ -42,6 +45,7 @@
File accountdir = new File(DATADIR, username);
if (!accountdir.mkdir()) throw new IOException("Failed to
create directory "+username+" in "+DATADIR);
+ getAccountFile(accountdir);
}
public static void setupNIM(String username) throws IOException {
@@ -52,7 +56,12 @@
if (!contacts_dir.mkdir()) throw new
IOException("Failed to create contacts directory");
}
- File nimdir = new File(contacts_dir, NIMDIR);
+ File inbound_dir = new File(contacts_dir,
SingleAccountWatcher.INBOUND_DIR);
+ if (!inbound_dir.exists()) {
+ if (!inbound_dir.mkdir()) throw new IOException("Failed
to create inbound contacts directory");
+ }
+
+ File nimdir = new File(inbound_dir, NIMDIR);
if (!nimdir.exists()) {
if (!nimdir.mkdir()) throw new IOException("Failed to
create nim directory");
}
@@ -81,7 +90,7 @@
PropsFile accfile = getAccountFile(accountdir);
byte[] md5passwd = md.digest(newpassword.getBytes());
- String strmd5 = bytestoHex(md5passwd);
+ String strmd5 = new String(Hex.encode(md5passwd));
accfile.put("md5passwd", strmd5);
}
@@ -96,6 +105,20 @@
return accfile;
}
+ public static RSAKeyParameters getPrivateKey(File accdir) {
+ PropsFile props = getAccountFile(accdir);
+
+ String mod_str = props.get("asymkey.modulus");
+ String privexp_str = props.get("asymkey.privexponent");
+
+ if (mod_str == null || privexp_str == null) {
+ System.out.println("Couldn't get private key - account
file corrupt?");
+ return null;
+ }
+
+ return new RSAKeyParameters(true, new BigInteger(mod_str, 10),
new BigInteger(privexp_str, 10));
+ }
+
private static void initAccFile(PropsFile accfile) {
try {
System.out.println("Generating mailsite keys...");
@@ -103,13 +126,18 @@
SSKKeyPair keypair = fcpcli.makeSSK();
+ if (keypair == null) {
+ System.out.println("Unable to connect to the
Freenet nodenode");
+ return;
+ }
+
// write private key
- if (!accfile.put("mailsite.privkey",
keypair.privkey+"mailsite")) {
+ if (!accfile.put("mailsite.privkey",
keypair.privkey+MAILSITE_SUFFIX)) {
throw new IOException("Unable to write account
file");
}
// write public key
- if (!accfile.put("mailsite.pubkey",
keypair.pubkey+"mailsite")) {
+ if (!accfile.put("mailsite.pubkey",
keypair.pubkey+MAILSITE_SUFFIX)) {
throw new IOException("Unable to write account
file");
}
@@ -175,7 +203,7 @@
}
byte[] givenmd5 = md.digest(password.getBytes());
- String givenmd5str = bytestoHex(givenmd5);
+ String givenmd5str = new String(Hex.encode(givenmd5));
if (realmd5str.equals(givenmd5str)) {
return true;
@@ -187,17 +215,4 @@
if (username.matches("[\\w_]*")) return true;
return false;
}
-
- public static String bytestoHex(byte[] bytes) {
- String retval = new String("");
-
- for (int i = 0; i < bytes.length; i++) {
- String b = Integer.toHexString((int)(bytes[i] & 0xFF));
- if (b.length() < 2) {
- b = "0" + b;
- }
- retval += b;
- }
- return retval;
- }
}
Added: trunk/apps/Freemail/src/freemail/BadFreemailAddressException.java
===================================================================
--- trunk/apps/Freemail/src/freemail/BadFreemailAddressException.java
2006-06-22 18:39:47 UTC (rev 9353)
+++ trunk/apps/Freemail/src/freemail/BadFreemailAddressException.java
2006-06-22 19:11:33 UTC (rev 9354)
@@ -0,0 +1,5 @@
+package freemail;
+
+public class BadFreemailAddressException extends Exception {
+
+}
Modified: trunk/apps/Freemail/src/freemail/Freemail.java
===================================================================
--- trunk/apps/Freemail/src/freemail/Freemail.java 2006-06-22 18:39:47 UTC
(rev 9353)
+++ trunk/apps/Freemail/src/freemail/Freemail.java 2006-06-22 19:11:33 UTC
(rev 9354)
@@ -26,36 +26,29 @@
String fcphost = "localhost";
int fcpport = 9481;
+ String action = "";
+ String account = null;
+ String newpasswd = null;
+
for (int i = 0; i < args.length; i++) {
if (args[i].equals("--newaccount")) {
+ action = args[i];
i++;
if (args.length - 1 < i) {
System.out.println("Usage: --newaccount
<account name>");
return;
}
- try {
- AccountManager.Create(args[i]);
- // for now
- AccountManager.setupNIM(args[i]);
- System.out.println("Account created for
"+args[i]+". You may now set a password with --passwd <password>");
- System.out.println("For the time being,
you address is "+args[i]+"@nim.freemail");
- } catch (IOException ioe) {
- System.out.println("Couldn't create
account. Please check write access to Freemail's working directory. Error:
"+ioe.getMessage());
- }
- return;
+
+ account = args[i];
} else if (args[i].equals("--passwd")) {
+ action = args[i];
i = i + 2;
if (args.length - 1 < i) {
System.out.println("Usage: --passwd
<account name> <password>");
return;
}
- try {
- AccountManager.ChangePassword(args[i -
1], args[i]);
- System.out.println("Password changed.");
- } catch (Exception e) {
- System.out.println("Couldn't change
password for "+args[i - 1]+". "+e.getMessage());
- }
- return;
+ account = args[i - 1];
+ newpasswd = args[i];
} else if (args[i].equals("-h")) {
i++;
if (args.length - 1 < i) {
@@ -84,6 +77,28 @@
fcpthread.setDaemon(true);
fcpthread.start();
+ if (action.equals("--newaccount")) {
+ try {
+ AccountManager.Create(account);
+ // for now
+ AccountManager.setupNIM(account);
+ System.out.println("Account created for
"+account+". You may now set a password with --passwd <password>");
+ System.out.println("For the time being, you
address is "+account+"@nim.freemail");
+ } catch (IOException ioe) {
+ System.out.println("Couldn't create account.
Please check write access to Freemail's working directory. Error:
"+ioe.getMessage());
+ }
+ return;
+ } else if (action.equals("--passwd")) {
+ try {
+ AccountManager.ChangePassword(account,
newpasswd);
+ System.out.println("Password changed.");
+ } catch (Exception e) {
+ System.out.println("Couldn't change password
for "+account+". "+e.getMessage());
+ e.printStackTrace();
+ }
+ return;
+ }
+
// start a SingleAccountWatcher for each account
Freemail.datadir = new File("data");
if (!Freemail.datadir.exists()) {
Modified: trunk/apps/Freemail/src/freemail/MailFetcher.java
===================================================================
--- trunk/apps/Freemail/src/freemail/MailFetcher.java 2006-06-22 18:39:47 UTC
(rev 9353)
+++ trunk/apps/Freemail/src/freemail/MailFetcher.java 2006-06-22 19:11:33 UTC
(rev 9354)
@@ -16,6 +16,8 @@
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
+import org.bouncycastle.util.encoders.Hex;
+
public class MailFetcher {
private final MessageBank mb;
private File contact_dir;
@@ -127,6 +129,6 @@
file.delete();
byte[] checksum = md.digest();
- return AccountManager.bytestoHex(checksum);
+ return new String(Hex.encode(checksum));
}
}
Modified: trunk/apps/Freemail/src/freemail/MailSite.java
===================================================================
--- trunk/apps/Freemail/src/freemail/MailSite.java 2006-06-22 18:39:47 UTC
(rev 9353)
+++ trunk/apps/Freemail/src/freemail/MailSite.java 2006-06-22 19:11:33 UTC
(rev 9354)
@@ -3,11 +3,12 @@
import java.io.ByteArrayInputStream;
import java.io.UnsupportedEncodingException;
-import freemail.util.PropsFile;
+import freemail.utils.PropsFile;
import freemail.fcp.HighLevelFCPClient;
public class MailSite {
private final PropsFile accprops;
+ public static final String MAILPAGE = "mailpage";
MailSite(PropsFile a) {
this.accprops = a;
@@ -67,7 +68,7 @@
minslot = 1;
}
- int actualslot = cli.SlotInsert(bis, key, 1, "/mailpage");
+ int actualslot = cli.SlotInsert(bis, key, 1, "/"+MAILPAGE);
this.accprops.put("mailsite.slot", new
Integer(actualslot).toString());
Modified: trunk/apps/Freemail/src/freemail/MessageSender.java
===================================================================
--- trunk/apps/Freemail/src/freemail/MessageSender.java 2006-06-22 18:39:47 UTC
(rev 9353)
+++ trunk/apps/Freemail/src/freemail/MessageSender.java 2006-06-22 19:11:33 UTC
(rev 9354)
@@ -16,7 +16,7 @@
public class MessageSender implements Runnable {
public static final String OUTBOX_DIR = "outbox";
- public static final int MIN_RUN_TIME = 60000;
+ private static final int MIN_RUN_TIME = 60000;
public static final String NIM_KEY_PREFIX = "KSK at freemail-nim-";
private final File datadir;
private Thread senderthread;
@@ -77,7 +77,7 @@
if (!outbox.exists())
outbox.mkdir();
- this.sendDir(outbox);
+ this.sendDir(files[i], outbox);
}
// don't spin around the loop if nothing's
// going on
@@ -92,17 +92,17 @@
}
}
- private void sendDir(File dir) {
+ private void sendDir(File accdir, File dir) {
File[] files = dir.listFiles();
for (int i = 0; i < files.length; i++) {
if (files[i].getName().startsWith("."))
continue;
- this.sendSingle(files[i]);
+ this.sendSingle(accdir, files[i]);
}
}
- private void sendSingle(File msg) {
+ private void sendSingle(File accdir, File msg) {
String parts[] = msg.getName().split(":", 2);
EmailAddress addr;
if (parts.length < 2) {
@@ -129,6 +129,39 @@
if (cli.SlotInsert(fis,
NIM_KEY_PREFIX+addr.user+"-"+DateStringFactory.getKeyString(), 1, "") > -1) {
msg.delete();
}
+ } else {
+ if (this.sendSecure(accdir, addr, msg)) {
+ msg.delete();
+ }
}
}
+
+ private boolean sendSecure(File accdir, EmailAddress addr, File msg) {
+ System.out.println("sending secure");
+ OutboundContact ct;
+ try {
+ ct = new OutboundContact(accdir, addr);
+ } catch (BadFreemailAddressException bfae) {
+ // TODO: bounce
+ return true;
+ }
+ boolean ready;
+ if (!ct.exists()) {
+ try {
+ System.out.println("initing outbound contact");
+ ready = ct.init();
+ } catch (OutboundContactFatalException fe) {
+ // will never succeed, so report success to
delete the message
+ // TODO: send a bounce message or something
+ return true;
+ }
+ } else {
+ System.out.println("ready");
+ ready = true;
+ }
+
+ if (!ready) return false;
+
+ return false;
+ }
}
Added: trunk/apps/Freemail/src/freemail/OutboundContact.java
===================================================================
--- trunk/apps/Freemail/src/freemail/OutboundContact.java 2006-06-22
18:39:47 UTC (rev 9353)
+++ trunk/apps/Freemail/src/freemail/OutboundContact.java 2006-06-22
19:11:33 UTC (rev 9354)
@@ -0,0 +1,176 @@
+package freemail;
+
+import java.io.File;
+import java.io.ByteArrayOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+import freemail.utils.EmailAddress;
+import freemail.utils.PropsFile;
+import freemail.utils.DateStringFactory;
+import freemail.fcp.HighLevelFCPClient;
+import freemail.fcp.SSKKeyPair;
+
+import org.bouncycastle.crypto.params.RSAKeyParameters;
+import org.bouncycastle.crypto.AsymmetricBlockCipher;
+import org.bouncycastle.crypto.engines.RSAEngine;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+
+public class OutboundContact {
+ private final PropsFile contactfile;
+ private final File accdir;
+ private final EmailAddress address;
+ private static final String OUTBOUND_DIR = "outbound";
+
+ public OutboundContact(File accdir, EmailAddress a) throws
BadFreemailAddressException {
+ this.address = a;
+
+ this.accdir = accdir;
+
+ if (this.address.getMailsiteKey() == null) {
+ this.contactfile = null;
+ throw new BadFreemailAddressException();
+ } else {
+ File contactsdir = new File(accdir,
SingleAccountWatcher.CONTACTS_DIR);
+ if (!contactsdir.exists())
+ contactsdir.mkdir();
+ File outbounddir = new File(contactsdir, OUTBOUND_DIR);
+
+ if (!outbounddir.exists())
+ outbounddir.mkdir();
+
+ this.contactfile = new PropsFile(new File(outbounddir,
this.address.getMailsiteKey()));
+ }
+ }
+
+ public boolean exists() {
+ return this.contactfile.exists();
+ }
+
+ /**
+ * Set up an outbound contact. Fetch the mailsite, generate a new SSK
keypair and post an RTS message to the appropriate KSK.
+ * Will block for mailsite retrieval and RTS insertion
+ *
+ * @return true for success
+ */
+ public boolean init() throws OutboundContactFatalException {
+ HighLevelFCPClient cli = new HighLevelFCPClient();
+
+ System.out.println("Attempting to fetch
"+this.getMailpageKey());
+ File mailsite_file = cli.fetch(this.getMailpageKey());
+
+ if (mailsite_file == null) {
+ // TODO: Give up for now, try later, count number of
and limit attempts
+ System.out.println("Failed to retrieve mailsite for
"+this.address);
+ return false;
+ }
+
+ System.out.println("got mailsite");
+
+ PropsFile mailsite = new PropsFile(mailsite_file);
+
+ String rtskey = mailsite.get("rtsksk");
+ String keymod_str = mailsite.get("asymkey.modulus");
+ String keyexp_str = mailsite.get("asymkey.pubexponent");
+
+ if (rtskey == null || keymod_str == null || keyexp_str == null)
{
+ // TODO: More failure mechanisms - this is fatal.
+ System.out.println("Mailsite for "+this.address+" does
not contain all necessary iformation!");
+ throw new OutboundContactFatalException("Mailsite for
"+this.address+" does not contain all necessary iformation!");
+ }
+ mailsite_file.delete();
+
+ SSKKeyPair ssk = cli.makeSSK();
+
+ StringBuffer rtsmessage = new StringBuffer();
+
+ rtsmessage.append("messagetype=rts\r\n");
+
+ // must include who this RTS is to, otherwise we're vulnerable
to surruptitious forwarding
+ rtsmessage.append("to="+this.address.getMailsiteKey()+"\r\n");
+
+ // get our mailsite URI
+ String our_mailsite_uri =
AccountManager.getAccountFile(this.accdir).get("mailsite.pubkey");
+
+ rtsmessage.append("mailsite="+our_mailsite_uri+"\r\n");
+
+ // the public part of the SSK keypair we generated
+ rtsmessage.append("commssk="+ssk.pubkey+"\r\n");
+
+ rtsmessage.append("\r\n");
+
+ // sign the message
+
+ MessageDigest md = null;
+ try {
+ md = MessageDigest.getInstance("SHA-256");
+ } catch (NoSuchAlgorithmException alge) {
+ System.out.println("No SHA 256 implementation available
- no mail can be sent!");
+ return false;
+ }
+
+ byte[] hash = md.digest(rtsmessage.toString().getBytes());
+
+ RSAKeyParameters our_priv_key =
AccountManager.getPrivateKey(this.accdir);
+
+ AsymmetricBlockCipher sigcipher = new RSAEngine();
+ sigcipher.init(true, our_priv_key);
+ byte[] sig = null;
+ try {
+ sig = sigcipher.processBlock(hash, 0, hash.length);
+ } catch (InvalidCipherTextException e) {
+ e.printStackTrace();
+ return false;
+ }
+
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+
+ try {
+ bos.write(rtsmessage.toString().getBytes());
+ bos.write(sig);
+ } catch(IOException ioe) {
+ ioe.printStackTrace();
+ return false;
+ }
+
+ // now encrypt it
+
+ BigInteger keymodulus = new BigInteger(keymod_str, 10);
+ BigInteger keyexponent = new BigInteger(keyexp_str, 10);
+
+ // is not private
+ RSAKeyParameters their_pub_key = new RSAKeyParameters(false,
keymodulus, keyexponent);
+
+ AsymmetricBlockCipher enccipher = new RSAEngine();
+ enccipher.init(true, their_pub_key);
+ byte[] encmsg = null;
+ try {
+ encmsg = sigcipher.processBlock(bos.toByteArray(), 0,
bos.toByteArray().length);
+ } catch (InvalidCipherTextException e) {
+ e.printStackTrace();
+ return false;
+ }
+
+ // insert it!
+ ByteArrayInputStream bis = new
ByteArrayInputStream(bos.toByteArray());
+
+ if (cli.SlotInsert(bis,
"KSK@"+rtskey+"-"+DateStringFactory.getKeyString(), 1, "") < 0) {
+ return false;
+ }
+
+ // now we can create a new outbound contact file
+ this.contactfile.put("rtskey", rtskey);
+ this.contactfile.put("asymkey.modulus", keymod_str);
+ this.contactfile.put("asymnkey.exponent", keyexp_str);
+ this.contactfile.put("commssk", ssk.privkey);
+
+ return true;
+ }
+
+ private String getMailpageKey() {
+ return
"USK@"+this.address.getMailsiteKey()+"/"+AccountManager.MAILSITE_SUFFIX+"/1/"+MailSite.MAILPAGE;
+ }
+}
Added: trunk/apps/Freemail/src/freemail/OutboundContactFatalException.java
===================================================================
--- trunk/apps/Freemail/src/freemail/OutboundContactFatalException.java
2006-06-22 18:39:47 UTC (rev 9353)
+++ trunk/apps/Freemail/src/freemail/OutboundContactFatalException.java
2006-06-22 19:11:33 UTC (rev 9354)
@@ -0,0 +1,7 @@
+package freemail;
+
+public class OutboundContactFatalException extends Exception {
+ public OutboundContactFatalException(String msg) {
+ super(msg);
+ }
+}
Modified: trunk/apps/Freemail/src/freemail/SingleAccountWatcher.java
===================================================================
--- trunk/apps/Freemail/src/freemail/SingleAccountWatcher.java 2006-06-22
18:39:47 UTC (rev 9353)
+++ trunk/apps/Freemail/src/freemail/SingleAccountWatcher.java 2006-06-22
19:11:33 UTC (rev 9354)
@@ -3,10 +3,11 @@
import java.io.File;
import java.lang.InterruptedException;
-import freemail.util.PropsFile;
+import freemail.utils.PropsFile;
public class SingleAccountWatcher implements Runnable {
public static final String CONTACTS_DIR = "contacts";
+ public static final String INBOUND_DIR = "inbound";
private static final int MIN_POLL_DURATION = 60000; // in milliseconds
private static final int MAILSITE_UPLOAD_INTERVAL = 60 * 60 * 1000;
private final MessageBank mb;
@@ -14,13 +15,15 @@
SingleAccountWatcher(File accdir) {
File contacts_dir = new File(accdir, CONTACTS_DIR);
+ File inbound_dir = new File(contacts_dir, INBOUND_DIR);
+ // TODO: do this in the loop, periodically
PropsFile accprops = AccountManager.getAccountFile(accdir);
MailSite ms = new MailSite(accprops);
ms.Publish();
this.mb = new MessageBank(accdir.getName());
- this.mf = new MailFetcher(this.mb, contacts_dir,
Freemail.getFCPConnection());
+ this.mf = new MailFetcher(this.mb, inbound_dir,
Freemail.getFCPConnection());
}
public void run() {
Modified: trunk/apps/Freemail/src/freemail/utils/EmailAddress.java
===================================================================
--- trunk/apps/Freemail/src/freemail/utils/EmailAddress.java 2006-06-22
18:39:47 UTC (rev 9353)
+++ trunk/apps/Freemail/src/freemail/utils/EmailAddress.java 2006-06-22
19:11:33 UTC (rev 9354)
@@ -1,5 +1,7 @@
package freemail.utils;
+import org.bouncycastle.util.encoders.Hex;
+
public class EmailAddress {
public String realname;
public String user;
@@ -47,6 +49,26 @@
public boolean is_freemail_address() {
if (this.domain == null) return false;
- return this.domain.equalsIgnoreCase("nim.freemail");
+ if (!this.domain.endsWith(".freemail")) return false;
+ if (this.getMailsiteKey() == null) return false;
+ return true;
}
+
+ public String getMailsiteKey() {
+ String[] domparts = this.domain.split("\\.", 2);
+
+ if (domparts.length < 2) return null;
+
+ try {
+ return new String (Hex.decode(domparts[0].getBytes()));
+ } catch (ArrayIndexOutOfBoundsException aiobe) {
+ // the Hex decoder just generates this exception if the
input is not hex
+ // (since it looks up a non-hex charecter in the
decoding table)
+ return null;
+ }
+ }
+
+ public String toString() {
+ return this.user+"@"+this.domain;
+ }
}
Modified: trunk/apps/Freemail/src/freemail/utils/PropsFile.java
===================================================================
--- trunk/apps/Freemail/src/freemail/utils/PropsFile.java 2006-06-22
18:39:47 UTC (rev 9353)
+++ trunk/apps/Freemail/src/freemail/utils/PropsFile.java 2006-06-22
19:11:33 UTC (rev 9354)
@@ -1,4 +1,4 @@
-package freemail.util;
+package freemail.utils;
import java.io.File;
import java.io.FileReader;