diff --git a/briar-android/res/drawable-hdpi/content_attachment.png b/briar-android/res/drawable-hdpi/content_attachment.png new file mode 100644 index 0000000000000000000000000000000000000000..53b963d54106ff032f364ac815f513ab91e9bd23 Binary files /dev/null and b/briar-android/res/drawable-hdpi/content_attachment.png differ diff --git a/briar-android/res/drawable-mdpi/content_attachment.png b/briar-android/res/drawable-mdpi/content_attachment.png new file mode 100644 index 0000000000000000000000000000000000000000..38ff9f853ce781299b92b471da4cb9d587100a66 Binary files /dev/null and b/briar-android/res/drawable-mdpi/content_attachment.png differ diff --git a/briar-android/res/drawable-xhdpi/content_attachment.png b/briar-android/res/drawable-xhdpi/content_attachment.png new file mode 100644 index 0000000000000000000000000000000000000000..1cffb3fbf2f1149821435933ea6a236ff2663ed5 Binary files /dev/null and b/briar-android/res/drawable-xhdpi/content_attachment.png differ diff --git a/briar-android/src/net/sf/briar/android/messages/ConversationAdapter.java b/briar-android/src/net/sf/briar/android/messages/ConversationAdapter.java index 67c6c629b724593b71423efa56107ace831f40a3..31fdd1dcc84606d179b171ef7192393583a6f65a 100644 --- a/briar-android/src/net/sf/briar/android/messages/ConversationAdapter.java +++ b/briar-android/src/net/sf/briar/android/messages/ConversationAdapter.java @@ -45,6 +45,13 @@ implements OnItemClickListener { else star.setImageResource(R.drawable.rating_not_important); layout.addView(star); + if(!item.getContentType().equals("text/plain")) { + ImageView attachment = new ImageView(ctx); + attachment.setPadding(0, 5, 5, 5); + attachment.setImageResource(R.drawable.content_attachment); + layout.addView(attachment); + } + TextView subject = new TextView(ctx); // Give me all the unused width subject.setLayoutParams(new LayoutParams(WRAP_CONTENT, WRAP_CONTENT, diff --git a/briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java b/briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java index f09c7dabed6c714a23b804c9a0286079085d36e7..b54a41827e8eac042306b726b5c5e5c812924aee 100644 --- a/briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java +++ b/briar-android/src/net/sf/briar/android/messages/ConversationListActivity.java @@ -112,21 +112,21 @@ implements OnClickListener, DatabaseListener { ContactId contactId = db.addContact("Carol"); // Insert some fake messages to and from the contact Message m = messageFactory.createPrivateMessage(null, - "First message's subject is short", - "First message's body".getBytes("UTF-8")); + "text/plain", + "First message is short".getBytes("UTF-8")); db.addLocalPrivateMessage(m, contactId); db.setReadFlag(m.getId(), true); db.setStarredFlag(m.getId(), true); Thread.sleep(1000); m = messageFactory.createPrivateMessage(m.getId(), - "Second message's subject is also short", - "Second message's body".getBytes("UTF-8")); + "image/jpeg", new byte[1000]); db.receiveMessage(contactId, m); Thread.sleep(1000); m = messageFactory.createPrivateMessage(m.getId(), - "Third message's subject is quite long to test" - + " line wrapping and exciting stuff like that", - "Third message's body".getBytes("UTF-8")); + "text/plain", + ("Third message is quite long to test line" + + " wrapping and subject line extraction and" + + " all that fun stuff").getBytes("UTF-8")); db.addLocalPrivateMessage(m, contactId); db.setReadFlag(m.getId(), true); } diff --git a/briar-api/src/net/sf/briar/api/db/GroupMessageHeader.java b/briar-api/src/net/sf/briar/api/db/GroupMessageHeader.java index af8add02b337bac51c6ced34c8614dd34c8e4425..543f34a939b1eaed183c11b3efc9c26ddf0fb52e 100644 --- a/briar-api/src/net/sf/briar/api/db/GroupMessageHeader.java +++ b/briar-api/src/net/sf/briar/api/db/GroupMessageHeader.java @@ -9,10 +9,10 @@ public class GroupMessageHeader extends MessageHeader { private final GroupId groupId; private final Author author; - public GroupMessageHeader(MessageId id, MessageId parent, String subject, - long timestamp, boolean read, boolean starred, GroupId groupId, - Author author) { - super(id, parent, subject, timestamp, read, starred); + public GroupMessageHeader(MessageId id, MessageId parent, + String contentType, String subject, long timestamp, boolean read, + boolean starred, GroupId groupId, Author author) { + super(id, parent, contentType, subject, timestamp, read, starred); this.groupId = groupId; this.author = author; } diff --git a/briar-api/src/net/sf/briar/api/db/MessageHeader.java b/briar-api/src/net/sf/briar/api/db/MessageHeader.java index b1f11d1bd549b5add829b7dbd69af065b3121d24..2cbab3f51ce17268a48723f3ee44eefd757ef02f 100644 --- a/briar-api/src/net/sf/briar/api/db/MessageHeader.java +++ b/briar-api/src/net/sf/briar/api/db/MessageHeader.java @@ -5,14 +5,15 @@ import net.sf.briar.api.messaging.MessageId; public abstract class MessageHeader { private final MessageId id, parent; - private final String subject; + private final String contentType, subject; private final long timestamp; private final boolean read, starred; - protected MessageHeader(MessageId id, MessageId parent, String subject, - long timestamp, boolean read, boolean starred) { + protected MessageHeader(MessageId id, MessageId parent, String contentType, + String subject, long timestamp, boolean read, boolean starred) { this.id = id; this.parent = parent; + this.contentType = contentType; this.subject = subject; this.timestamp = timestamp; this.read = read; @@ -32,6 +33,11 @@ public abstract class MessageHeader { return parent; } + /** Returns the message's content type. */ + public String getContentType() { + return contentType; + } + /** Returns the message's subject line. */ public String getSubject() { return subject; diff --git a/briar-api/src/net/sf/briar/api/db/PrivateMessageHeader.java b/briar-api/src/net/sf/briar/api/db/PrivateMessageHeader.java index 900c2cb2a92fa2c43c196594694ed8659d8381a2..af55211c66fb691f233ce82816525d03fca2ff29 100644 --- a/briar-api/src/net/sf/briar/api/db/PrivateMessageHeader.java +++ b/briar-api/src/net/sf/briar/api/db/PrivateMessageHeader.java @@ -8,10 +8,10 @@ public class PrivateMessageHeader extends MessageHeader { private final ContactId contactId; private final boolean incoming; - public PrivateMessageHeader(MessageId id, MessageId parent, String subject, - long timestamp, boolean read, boolean starred, ContactId contactId, - boolean incoming) { - super(id, parent, subject, timestamp, read, starred); + public PrivateMessageHeader(MessageId id, MessageId parent, + String contentType, String subject, long timestamp, boolean read, + boolean starred, ContactId contactId, boolean incoming) { + super(id, parent, contentType, subject, timestamp, read, starred); this.contactId = contactId; this.incoming = incoming; } diff --git a/briar-api/src/net/sf/briar/api/messaging/Message.java b/briar-api/src/net/sf/briar/api/messaging/Message.java index f2aac57fba2adfc47b144e07a5954398075d780e..b48d54cc061380af1a8e9d4c5fdb7240a8e6847f 100644 --- a/briar-api/src/net/sf/briar/api/messaging/Message.java +++ b/briar-api/src/net/sf/briar/api/messaging/Message.java @@ -23,7 +23,14 @@ public interface Message { */ Author getAuthor(); - /** Returns the message's subject line. */ + /** Returns the message's content type. */ + String getContentType(); + + /** + * Returns the message's subject line, which is created from the first 50 + * bytes of the message body if the content type is text/plain, or is the + * empty string otherwise. + */ String getSubject(); /** Returns the timestamp created by the message's {@link Author}. */ diff --git a/briar-api/src/net/sf/briar/api/messaging/MessageFactory.java b/briar-api/src/net/sf/briar/api/messaging/MessageFactory.java index 25dee5e10c6b21e26a2fc4fc91679426bced186d..ade4acda4ed4040e5adedbb9592a5d4130719e47 100644 --- a/briar-api/src/net/sf/briar/api/messaging/MessageFactory.java +++ b/briar-api/src/net/sf/briar/api/messaging/MessageFactory.java @@ -7,27 +7,27 @@ import java.security.PrivateKey; public interface MessageFactory { /** Creates a private message. */ - Message createPrivateMessage(MessageId parent, String subject, byte[] body) - throws IOException, GeneralSecurityException; + Message createPrivateMessage(MessageId parent, String contentType, + byte[] body) throws IOException, GeneralSecurityException; /** Creates an anonymous message to an unrestricted group. */ Message createAnonymousGroupMessage(MessageId parent, Group group, - String subject, byte[] body) throws IOException, + String contentType, byte[] body) throws IOException, GeneralSecurityException; /** Creates an anonymous message to a restricted group. */ Message createAnonymousGroupMessage(MessageId parent, Group group, - PrivateKey groupKey, String subject, byte[] body) + PrivateKey groupKey, String contentType, byte[] body) throws IOException, GeneralSecurityException; /** Creates a pseudonymous message to an unrestricted group. */ Message createPseudonymousMessage(MessageId parent, Group group, - Author author, PrivateKey authorKey, String subject, byte[] body) - throws IOException, GeneralSecurityException; + Author author, PrivateKey authorKey, String contentType, + byte[] body) throws IOException, GeneralSecurityException; /** Creates a pseudonymous message to a restricted group. */ Message createPseudonymousMessage(MessageId parent, Group group, PrivateKey groupKey, Author author, PrivateKey authorKey, - String subject, byte[] body) throws IOException, + String contentType, byte[] body) throws IOException, GeneralSecurityException; } diff --git a/briar-api/src/net/sf/briar/api/messaging/MessagingConstants.java b/briar-api/src/net/sf/briar/api/messaging/MessagingConstants.java index 5f3f93ac28c2e8f1e7648791d801adeda74a0e79..4ddcedf2c5d6c87046b80ab78037f993e1470cc1 100644 --- a/briar-api/src/net/sf/briar/api/messaging/MessagingConstants.java +++ b/briar-api/src/net/sf/briar/api/messaging/MessagingConstants.java @@ -36,6 +36,9 @@ public interface MessagingConstants { */ int MAX_BODY_LENGTH = MAX_PACKET_LENGTH - 1024; + /** The maximum length of a message's content type in UTF-8 bytes. */ + int MAX_CONTENT_TYPE_LENGTH = 50; + /** The maximum length of a message's subject line in UTF-8 bytes. */ int MAX_SUBJECT_LENGTH = 100; diff --git a/briar-api/src/net/sf/briar/api/messaging/UnverifiedMessage.java b/briar-api/src/net/sf/briar/api/messaging/UnverifiedMessage.java index cf1fcf2ce4e6356fd228bb4788f233e93d9d0d76..83c81e55558b401053461987f7cd14eea8672a0c 100644 --- a/briar-api/src/net/sf/briar/api/messaging/UnverifiedMessage.java +++ b/briar-api/src/net/sf/briar/api/messaging/UnverifiedMessage.java @@ -6,18 +6,19 @@ public class UnverifiedMessage { private final MessageId parent; private final Group group; private final Author author; - private final String subject; + private final String contentType, subject; private final long timestamp; private final byte[] raw, authorSig, groupSig; private final int bodyStart, bodyLength, signedByAuthor, signedByGroup; public UnverifiedMessage(MessageId parent, Group group, Author author, - String subject, long timestamp, byte[] raw, byte[] authorSig, - byte[] groupSig, int bodyStart, int bodyLength, int signedByAuthor, - int signedByGroup) { + String contentType, String subject, long timestamp, byte[] raw, + byte[] authorSig, byte[] groupSig, int bodyStart, int bodyLength, + int signedByAuthor, int signedByGroup) { this.parent = parent; this.group = group; this.author = author; + this.contentType = contentType; this.subject = subject; this.timestamp = timestamp; this.raw = raw; @@ -53,7 +54,16 @@ public class UnverifiedMessage { return author; } - /** Returns the message's subject line. */ + /** Returns the message's content type. */ + public String getContentType() { + return contentType; + } + + /** + * Returns the message's subject line, which is created from the first 50 + * bytes of the message body if the content type is text/plain, or is the + * empty string otherwise. + */ public String getSubject() { return subject; } diff --git a/briar-core/src/net/sf/briar/db/DatabaseComponentImpl.java b/briar-core/src/net/sf/briar/db/DatabaseComponentImpl.java index 299f52bd4e425961973e452e606bd14baefc12c5..888acb4642c86c94319149d7d429314eb3b05f4a 100644 --- a/briar-core/src/net/sf/briar/db/DatabaseComponentImpl.java +++ b/briar-core/src/net/sf/briar/db/DatabaseComponentImpl.java @@ -472,7 +472,7 @@ DatabaseCleaner.Callback { if(m.getGroup() != null) throw new IllegalArgumentException(); if(m.getAuthor() != null) throw new IllegalArgumentException(); if(!db.addPrivateMessage(txn, m, c)) return false; - db.addStatus(txn, c, m.getId(), !incoming); + db.addStatus(txn, c, m.getId(), incoming); // Count the bytes stored synchronized(spaceLock) { bytesStoredSinceLastCheck += m.getSerialised().length; diff --git a/briar-core/src/net/sf/briar/db/JdbcDatabase.java b/briar-core/src/net/sf/briar/db/JdbcDatabase.java index 45ec3fd7f32854c477796ad9c9f3f7970e84907d..4836072a9e41bdda73903083f5fc671cc704a405 100644 --- a/briar-core/src/net/sf/briar/db/JdbcDatabase.java +++ b/briar-core/src/net/sf/briar/db/JdbcDatabase.java @@ -125,6 +125,7 @@ abstract class JdbcDatabase implements Database<Connection> { + " authorId HASH," // Null for private/anon messages + " authorName VARCHAR," // Null for private/anon messages + " authorKey VARCHAR," // Null for private/anon messages + + " contentType VARCHAR NOT NULL," + " subject VARCHAR NOT NULL," + " timestamp BIGINT NOT NULL," + " length INT NOT NULL," @@ -633,10 +634,10 @@ abstract class JdbcDatabase implements Database<Connection> { PreparedStatement ps = null; try { String sql = "INSERT INTO messages (messageId, parentId, groupId," - + " authorId, authorName, authorKey, subject, timestamp," - + " length, bodyStart, bodyLength, raw, sendability, read," - + " starred)" - + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ZERO()," + + " authorId, authorName, authorKey, contentType, subject," + + " timestamp, length, bodyStart, bodyLength, raw," + + " sendability, read, starred)" + + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ZERO()," + " FALSE, FALSE)"; ps = txn.prepareStatement(sql); ps.setBytes(1, m.getId().getBytes()); @@ -653,13 +654,14 @@ abstract class JdbcDatabase implements Database<Connection> { ps.setString(5, a.getName()); ps.setBytes(6, a.getPublicKey()); } - ps.setString(7, m.getSubject()); - ps.setLong(8, m.getTimestamp()); + ps.setString(7, m.getContentType()); + ps.setString(8, m.getSubject()); + ps.setLong(9, m.getTimestamp()); byte[] raw = m.getSerialised(); - ps.setInt(9, raw.length); - ps.setInt(10, m.getBodyStart()); - ps.setInt(11, m.getBodyLength()); - ps.setBytes(12, raw); + ps.setInt(10, raw.length); + ps.setInt(11, m.getBodyStart()); + ps.setInt(12, m.getBodyLength()); + ps.setBytes(13, raw); int affected = ps.executeUpdate(); if(affected != 1) throw new DbStateException(); ps.close(); @@ -707,22 +709,23 @@ abstract class JdbcDatabase implements Database<Connection> { if(containsMessage(txn, m.getId())) return false; PreparedStatement ps = null; try { - String sql = "INSERT INTO messages (messageId, parentId, subject," - + " timestamp, length, bodyStart, bodyLength, raw," - + " contactId, read, starred)" - + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, FALSE, FALSE)"; + String sql = "INSERT INTO messages (messageId, parentId," + + " contentType, subject, timestamp, length, bodyStart," + + " bodyLength, raw, contactId, read, starred)" + + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, FALSE, FALSE)"; ps = txn.prepareStatement(sql); ps.setBytes(1, m.getId().getBytes()); if(m.getParent() == null) ps.setNull(2, BINARY); else ps.setBytes(2, m.getParent().getBytes()); - ps.setString(3, m.getSubject()); - ps.setLong(4, m.getTimestamp()); + ps.setString(3, m.getContentType()); + ps.setString(4, m.getSubject()); + ps.setLong(5, m.getTimestamp()); byte[] raw = m.getSerialised(); - ps.setInt(5, raw.length); - ps.setInt(6, m.getBodyStart()); - ps.setInt(7, m.getBodyLength()); - ps.setBytes(8, raw); - ps.setInt(9, c.getInt()); + ps.setInt(6, raw.length); + ps.setInt(7, m.getBodyStart()); + ps.setInt(8, m.getBodyLength()); + ps.setBytes(9, raw); + ps.setInt(10, c.getInt()); int affected = ps.executeUpdate(); if(affected != 1) throw new DbStateException(); ps.close(); @@ -1226,7 +1229,8 @@ abstract class JdbcDatabase implements Database<Connection> { ResultSet rs = null; try { String sql = "SELECT messageId, parentId, authorId, authorName," - + " authorKey, subject, timestamp, read, starred" + + " authorKey, contentType, subject, timestamp, read," + + " starred" + " FROM messages" + " WHERE groupId = ?"; ps = txn.prepareStatement(sql); @@ -1246,12 +1250,13 @@ abstract class JdbcDatabase implements Database<Connection> { byte[] authorKey = rs.getBytes(5); author = new Author(authorId, authorName, authorKey); } - String subject = rs.getString(6); - long timestamp = rs.getLong(7); - boolean read = rs.getBoolean(8); - boolean starred = rs.getBoolean(9); - headers.add(new GroupMessageHeader(id, parent, subject, - timestamp, read, starred, g, author)); + String contentType = rs.getString(6); + String subject = rs.getString(7); + long timestamp = rs.getLong(8); + boolean read = rs.getBoolean(9); + boolean starred = rs.getBoolean(10); + headers.add(new GroupMessageHeader(id, parent, contentType, + subject, timestamp, read, starred, g, author)); } rs.close(); ps.close(); @@ -1268,8 +1273,8 @@ abstract class JdbcDatabase implements Database<Connection> { PreparedStatement ps = null; ResultSet rs = null; try { - String sql = "SELECT m.messageId, parentId, subject, timestamp," - + " m.contactId, read, starred, seen" + String sql = "SELECT m.messageId, parentId, contentType, subject," + + " timestamp, m.contactId, read, starred, seen" + " FROM messages AS m" + " JOIN statuses AS s" + " ON m.messageId = s.messageId" @@ -1283,14 +1288,15 @@ abstract class JdbcDatabase implements Database<Connection> { MessageId id = new MessageId(rs.getBytes(1)); byte[] b = rs.getBytes(2); MessageId parent = b == null ? null : new MessageId(b); - String subject = rs.getString(3); - long timestamp = rs.getLong(4); - ContactId contactId = new ContactId(rs.getInt(5)); - boolean read = rs.getBoolean(6); - boolean starred = rs.getBoolean(7); - boolean seen = rs.getBoolean(8); - headers.add(new PrivateMessageHeader(id, parent, subject, - timestamp, read, starred, contactId, !seen)); + String contentType = rs.getString(3); + String subject = rs.getString(4); + long timestamp = rs.getLong(5); + ContactId contactId = new ContactId(rs.getInt(6)); + boolean read = rs.getBoolean(7); + boolean starred = rs.getBoolean(8); + boolean seen = rs.getBoolean(9); + headers.add(new PrivateMessageHeader(id, parent, contentType, + subject, timestamp, read, starred, contactId, seen)); } rs.close(); ps.close(); @@ -1307,8 +1313,8 @@ abstract class JdbcDatabase implements Database<Connection> { PreparedStatement ps = null; ResultSet rs = null; try { - String sql = "SELECT m.messageId, parentId, subject, timestamp," - + " read, starred, seen" + String sql = "SELECT m.messageId, parentId, contentType, subject," + + " timestamp, read, starred, seen" + " FROM messages AS m" + " JOIN statuses AS s" + " ON m.messageId = s.messageId" @@ -1323,13 +1329,14 @@ abstract class JdbcDatabase implements Database<Connection> { MessageId id = new MessageId(rs.getBytes(1)); byte[] b = rs.getBytes(2); MessageId parent = b == null ? null : new MessageId(b); - String subject = rs.getString(3); - long timestamp = rs.getLong(4); - boolean read = rs.getBoolean(5); - boolean starred = rs.getBoolean(6); - boolean seen = rs.getBoolean(7); - headers.add(new PrivateMessageHeader(id, parent, subject, - timestamp, read, starred, c, !seen)); + String contentType = rs.getString(3); + String subject = rs.getString(4); + long timestamp = rs.getLong(5); + boolean read = rs.getBoolean(6); + boolean starred = rs.getBoolean(7); + boolean seen = rs.getBoolean(8); + headers.add(new PrivateMessageHeader(id, parent, contentType, + subject, timestamp, read, starred, c, seen)); } rs.close(); ps.close(); diff --git a/briar-core/src/net/sf/briar/messaging/MessageFactoryImpl.java b/briar-core/src/net/sf/briar/messaging/MessageFactoryImpl.java index 43d5f0f4b99a52e98f52e99f68f23402900199df..bf329c80c4621eab4a39d9ac420a72f28fcbd7a7 100644 --- a/briar-core/src/net/sf/briar/messaging/MessageFactoryImpl.java +++ b/briar-core/src/net/sf/briar/messaging/MessageFactoryImpl.java @@ -1,6 +1,7 @@ package net.sf.briar.messaging; import static net.sf.briar.api.messaging.MessagingConstants.MAX_BODY_LENGTH; +import static net.sf.briar.api.messaging.MessagingConstants.MAX_CONTENT_TYPE_LENGTH; import static net.sf.briar.api.messaging.MessagingConstants.MAX_PACKET_LENGTH; import static net.sf.briar.api.messaging.MessagingConstants.MAX_SIGNATURE_LENGTH; import static net.sf.briar.api.messaging.MessagingConstants.MAX_SUBJECT_LENGTH; @@ -11,6 +12,9 @@ import static net.sf.briar.api.messaging.Types.MESSAGE; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; import java.security.GeneralSecurityException; import java.security.PrivateKey; import java.security.SecureRandom; @@ -40,6 +44,7 @@ class MessageFactoryImpl implements MessageFactory { private final MessageDigest messageDigest; private final WriterFactory writerFactory; private final Clock clock; + private final CharsetDecoder decoder; @Inject MessageFactoryImpl(CryptoComponent crypto, WriterFactory writerFactory, @@ -50,44 +55,46 @@ class MessageFactoryImpl implements MessageFactory { messageDigest = crypto.getMessageDigest(); this.writerFactory = writerFactory; this.clock = clock; + decoder = Charset.forName("UTF-8").newDecoder(); } - public Message createPrivateMessage(MessageId parent, String subject, + public Message createPrivateMessage(MessageId parent, String contentType, byte[] body) throws IOException, GeneralSecurityException { - return createMessage(parent, null, null, null, null, subject, body); + return createMessage(parent, null, null, null, null, contentType, body); } public Message createAnonymousGroupMessage(MessageId parent, Group group, - String subject, byte[] body) throws IOException, + String contentType, byte[] body) throws IOException, GeneralSecurityException { - return createMessage(parent, group, null, null, null, subject, body); + return createMessage(parent, group, null, null, null, contentType, + body); } public Message createAnonymousGroupMessage(MessageId parent, Group group, - PrivateKey groupKey, String subject, byte[] body) + PrivateKey groupKey, String contentType, byte[] body) throws IOException, GeneralSecurityException { - return createMessage(parent, group, groupKey, null, null, subject, + return createMessage(parent, group, groupKey, null, null, contentType, body); } public Message createPseudonymousMessage(MessageId parent, Group group, - Author author, PrivateKey authorKey, String subject, byte[] body) + Author author, PrivateKey authorKey, String contentType, byte[] body) throws IOException, GeneralSecurityException { - return createMessage(parent, group, null, author, authorKey, subject, - body); + return createMessage(parent, group, null, author, authorKey, + contentType, body); } public Message createPseudonymousMessage(MessageId parent, Group group, PrivateKey groupKey, Author author, PrivateKey authorKey, - String subject, byte[] body) throws IOException, + String contentType, byte[] body) throws IOException, GeneralSecurityException { return createMessage(parent, group, groupKey, author, authorKey, - subject, body); + contentType, body); } private Message createMessage(MessageId parent, Group group, PrivateKey groupKey, Author author, PrivateKey authorKey, - String subject, byte[] body) throws IOException, + String contentType, byte[] body) throws IOException, GeneralSecurityException { // Validate the arguments if((author == null) != (authorKey == null)) @@ -95,7 +102,7 @@ class MessageFactoryImpl implements MessageFactory { if((group == null || group.getPublicKey() == null) != (groupKey == null)) throw new IllegalArgumentException(); - if(subject.getBytes("UTF-8").length > MAX_SUBJECT_LENGTH) + if(contentType.getBytes("UTF-8").length > MAX_CONTENT_TYPE_LENGTH) throw new IllegalArgumentException(); if(body.length > MAX_BODY_LENGTH) throw new IllegalArgumentException(); @@ -127,7 +134,7 @@ class MessageFactoryImpl implements MessageFactory { else writeGroup(w, group); if(author == null) w.writeNull(); else writeAuthor(w, author); - w.writeString(subject); + w.writeString(contentType); long timestamp = clock.currentTimeMillis(); w.writeInt64(timestamp); byte[] salt = new byte[SALT_LENGTH]; @@ -158,7 +165,17 @@ class MessageFactoryImpl implements MessageFactory { // Hash the message, including the signatures, to get the message ID w.removeConsumer(digestingConsumer); MessageId id = new MessageId(messageDigest.digest()); - return new MessageImpl(id, parent, group, author, subject, + // If the content type is text/plain, extract a subject line + String subject; + if(contentType.equals("text/plain")) { + byte[] start = new byte[Math.min(MAX_SUBJECT_LENGTH, body.length)]; + System.arraycopy(body, 0, start, 0, start.length); + decoder.reset(); + subject = decoder.decode(ByteBuffer.wrap(start)).toString(); + } else { + subject = ""; + } + return new MessageImpl(id, parent, group, author, contentType, subject, timestamp, out.toByteArray(), bodyStart, body.length); } diff --git a/briar-core/src/net/sf/briar/messaging/MessageImpl.java b/briar-core/src/net/sf/briar/messaging/MessageImpl.java index 3472613223a9090e575442c51979b25d1eae5edd..4ff50f31024ae6b4a78a821fc211949108132607 100644 --- a/briar-core/src/net/sf/briar/messaging/MessageImpl.java +++ b/briar-core/src/net/sf/briar/messaging/MessageImpl.java @@ -12,14 +12,14 @@ class MessageImpl implements Message { private final MessageId id, parent; private final Group group; private final Author author; - private final String subject; + private final String contentType, subject; private final long timestamp; private final byte[] raw; private final int bodyStart, bodyLength; public MessageImpl(MessageId id, MessageId parent, Group group, - Author author, String subject, long timestamp, byte[] raw, - int bodyStart, int bodyLength) { + Author author, String contentType, String subject, long timestamp, + byte[] raw, int bodyStart, int bodyLength) { if(bodyStart + bodyLength > raw.length) throw new IllegalArgumentException(); if(bodyLength > MAX_BODY_LENGTH) @@ -28,6 +28,7 @@ class MessageImpl implements Message { this.parent = parent; this.group = group; this.author = author; + this.contentType = contentType; this.subject = subject; this.timestamp = timestamp; this.raw = raw; @@ -51,6 +52,10 @@ class MessageImpl implements Message { return author; } + public String getContentType() { + return contentType; + } + public String getSubject() { return subject; } diff --git a/briar-core/src/net/sf/briar/messaging/MessageReader.java b/briar-core/src/net/sf/briar/messaging/MessageReader.java index 0345b70c6e34b3315ef0a53825a76c73a8d7f87f..de0bf74ac5b67b4087b27b2fdb04f165ddf1a504 100644 --- a/briar-core/src/net/sf/briar/messaging/MessageReader.java +++ b/briar-core/src/net/sf/briar/messaging/MessageReader.java @@ -1,6 +1,7 @@ package net.sf.briar.messaging; import static net.sf.briar.api.messaging.MessagingConstants.MAX_BODY_LENGTH; +import static net.sf.briar.api.messaging.MessagingConstants.MAX_CONTENT_TYPE_LENGTH; import static net.sf.briar.api.messaging.MessagingConstants.MAX_PACKET_LENGTH; import static net.sf.briar.api.messaging.MessagingConstants.MAX_SIGNATURE_LENGTH; import static net.sf.briar.api.messaging.MessagingConstants.MAX_SUBJECT_LENGTH; @@ -8,6 +9,9 @@ import static net.sf.briar.api.messaging.MessagingConstants.SALT_LENGTH; import static net.sf.briar.api.messaging.Types.MESSAGE; import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; import net.sf.briar.api.FormatException; import net.sf.briar.api.messaging.Author; @@ -24,11 +28,13 @@ class MessageReader implements StructReader<UnverifiedMessage> { private final StructReader<Group> groupReader; private final StructReader<Author> authorReader; + private final CharsetDecoder decoder; MessageReader(StructReader<Group> groupReader, StructReader<Author> authorReader) { this.groupReader = groupReader; this.authorReader = authorReader; + decoder = Charset.forName("UTF-8").newDecoder(); } public UnverifiedMessage readStruct(Reader r) throws IOException { @@ -55,8 +61,8 @@ class MessageReader implements StructReader<UnverifiedMessage> { Author author = null; if(r.hasNull()) r.readNull(); else author = authorReader.readStruct(r); - // Read the subject - String subject = r.readString(MAX_SUBJECT_LENGTH); + // Read the content type + String contentType = r.readString(MAX_CONTENT_TYPE_LENGTH); // Read the timestamp long timestamp = r.readInt64(); if(timestamp < 0) throw new FormatException(); @@ -65,6 +71,16 @@ class MessageReader implements StructReader<UnverifiedMessage> { if(salt.length < SALT_LENGTH) throw new FormatException(); // Read the message body byte[] body = r.readBytes(MAX_BODY_LENGTH); + // If the content type is text/plain, extract a subject line + String subject; + if(contentType.equals("text/plain")) { + byte[] start = new byte[Math.min(MAX_SUBJECT_LENGTH, body.length)]; + System.arraycopy(body, 0, start, 0, start.length); + decoder.reset(); + subject = decoder.decode(ByteBuffer.wrap(start)).toString(); + } else { + subject = ""; + } // Record the offset of the body within the message int bodyStart = (int) counting.getCount() - body.length; // Record the length of the data covered by the author's signature @@ -83,8 +99,8 @@ class MessageReader implements StructReader<UnverifiedMessage> { r.removeConsumer(counting); r.removeConsumer(copying); byte[] raw = copying.getCopy(); - return new UnverifiedMessage(parent, group, author, subject, timestamp, - raw, authorSig, groupSig, bodyStart, body.length, - signedByAuthor, signedByGroup); + return new UnverifiedMessage(parent, group, author, contentType, + subject, timestamp, raw, authorSig, groupSig, bodyStart, + body.length, signedByAuthor, signedByGroup); } } diff --git a/briar-core/src/net/sf/briar/messaging/MessageVerifierImpl.java b/briar-core/src/net/sf/briar/messaging/MessageVerifierImpl.java index e1dc4896e70b94ae2e22bb86692c2ee544451d0e..22abc26555f8a31628cbe869a13ef8997c93dbce 100644 --- a/briar-core/src/net/sf/briar/messaging/MessageVerifierImpl.java +++ b/briar-core/src/net/sf/briar/messaging/MessageVerifierImpl.java @@ -53,7 +53,8 @@ class MessageVerifierImpl implements MessageVerifier { if(!signature.verify(m.getGroupSignature())) throw new GeneralSecurityException(); } - return new MessageImpl(id, m.getParent(), group, author, m.getSubject(), - m.getTimestamp(), raw, m.getBodyStart(), m.getBodyLength()); + return new MessageImpl(id, m.getParent(), group, author, + m.getContentType(), m.getSubject(), m.getTimestamp(), raw, + m.getBodyStart(), m.getBodyLength()); } } diff --git a/briar-tests/src/net/sf/briar/ProtocolIntegrationTest.java b/briar-tests/src/net/sf/briar/ProtocolIntegrationTest.java index 18aff79214164200eafc3c062c6bedb18a2c6083..e838923c98893c968b8790a1b6bbfb8cfc889ffa 100644 --- a/briar-tests/src/net/sf/briar/ProtocolIntegrationTest.java +++ b/briar-tests/src/net/sf/briar/ProtocolIntegrationTest.java @@ -70,7 +70,7 @@ public class ProtocolIntegrationTest extends BriarTestCase { private final Group group, group1; private final Message message, message1, message2, message3; private final String authorName = "Alice"; - private final String subject = "Hello"; + private final String contentType = "text/plain"; private final String messageBody = "Hello world"; private final Collection<MessageId> messageIds; private final TransportId transportId; @@ -107,16 +107,16 @@ public class ProtocolIntegrationTest extends BriarTestCase { // Create two messages to each group: one anonymous, one pseudonymous MessageFactory messageFactory = i.getInstance(MessageFactory.class); message = messageFactory.createAnonymousGroupMessage(null, group, - subject, messageBody.getBytes("UTF-8")); + contentType, messageBody.getBytes("UTF-8")); message1 = messageFactory.createAnonymousGroupMessage(null, group1, - groupKeyPair.getPrivate(), subject, + groupKeyPair.getPrivate(), contentType, messageBody.getBytes("UTF-8")); message2 = messageFactory.createPseudonymousMessage(null, group, - author, authorKeyPair.getPrivate(), subject, + author, authorKeyPair.getPrivate(), contentType, messageBody.getBytes("UTF-8")); message3 = messageFactory.createPseudonymousMessage(null, group1, groupKeyPair.getPrivate(), author, authorKeyPair.getPrivate(), - subject, messageBody.getBytes("UTF-8")); + contentType, messageBody.getBytes("UTF-8")); messageIds = Arrays.asList(message.getId(), message1.getId(), message2.getId(), message3.getId()); // Create some transport properties diff --git a/briar-tests/src/net/sf/briar/TestMessage.java b/briar-tests/src/net/sf/briar/TestMessage.java index 0c4ae532a9e201036ec24d5901456b977d0b4389..9a8283505eb4c893b50e30bbdbfc8cea89cdc27b 100644 --- a/briar-tests/src/net/sf/briar/TestMessage.java +++ b/briar-tests/src/net/sf/briar/TestMessage.java @@ -13,23 +13,26 @@ public class TestMessage implements Message { private final MessageId id, parent; private final Group group; private final Author author; - private final String subject; + private final String contentType, subject; private final long timestamp; private final byte[] raw; private final int bodyStart, bodyLength; public TestMessage(MessageId id, MessageId parent, Group group, - Author author, String subject, long timestamp, byte[] raw) { - this(id, parent, group, author, subject, timestamp, raw, 0, raw.length); + Author author, String contentType, String subject, long timestamp, + byte[] raw) { + this(id, parent, group, author, contentType, subject, timestamp, raw, 0, + raw.length); } public TestMessage(MessageId id, MessageId parent, Group group, - Author author, String subject, long timestamp, byte[] raw, - int bodyStart, int bodyLength) { + Author author, String contentType, String subject, long timestamp, + byte[] raw, int bodyStart, int bodyLength) { this.id = id; this.parent = parent; this.group = group; this.author = author; + this.contentType = contentType; this.subject = subject; this.timestamp = timestamp; this.raw = raw; @@ -53,6 +56,10 @@ public class TestMessage implements Message { return author; } + public String getContentType() { + return contentType; + } + public String getSubject() { return subject; } diff --git a/briar-tests/src/net/sf/briar/db/DatabaseComponentTest.java b/briar-tests/src/net/sf/briar/db/DatabaseComponentTest.java index 1cf9044ffa54b389ef8759186aa3d3ac4b373d77..72958c9de3e0430e98de9794896500ce3e2b0e06 100644 --- a/briar-tests/src/net/sf/briar/db/DatabaseComponentTest.java +++ b/briar-tests/src/net/sf/briar/db/DatabaseComponentTest.java @@ -59,7 +59,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase { protected final AuthorId authorId; protected final Author author; protected final MessageId messageId, messageId1; - protected final String subject; + protected final String contentType, subject; protected final long timestamp; protected final int size; protected final byte[] raw; @@ -80,14 +80,15 @@ public abstract class DatabaseComponentTest extends BriarTestCase { author = new Author(authorId, "Alice", new byte[60]); messageId = new MessageId(TestUtils.getRandomId()); messageId1 = new MessageId(TestUtils.getRandomId()); + contentType = "text/plain"; subject = "Foo"; timestamp = System.currentTimeMillis(); size = 1234; raw = new byte[size]; - message = new TestMessage(messageId, null, group, author, subject, - timestamp, raw); - privateMessage = new TestMessage(messageId, null, null, null, subject, - timestamp, raw); + message = new TestMessage(messageId, null, group, author, contentType, + subject, timestamp, raw); + privateMessage = new TestMessage(messageId, null, null, null, + contentType, subject, timestamp, raw); transportId = new TransportId(TestUtils.getRandomId()); transportProperties = new TransportProperties(Collections.singletonMap( "foo", "bar")); diff --git a/briar-tests/src/net/sf/briar/db/H2DatabaseTest.java b/briar-tests/src/net/sf/briar/db/H2DatabaseTest.java index ec00dd3f61c2d5f858832727622e8ee0c94bdcd0..31262080834f69942f71c45b16a5da37354dddcf 100644 --- a/briar-tests/src/net/sf/briar/db/H2DatabaseTest.java +++ b/briar-tests/src/net/sf/briar/db/H2DatabaseTest.java @@ -56,7 +56,7 @@ public class H2DatabaseTest extends BriarTestCase { private final AuthorId authorId; private final Author author; private final MessageId messageId, messageId1; - private final String subject; + private final String contentType, subject; private final long timestamp; private final int size; private final byte[] raw; @@ -73,15 +73,16 @@ public class H2DatabaseTest extends BriarTestCase { author = new Author(authorId, "Alice", new byte[60]); messageId = new MessageId(TestUtils.getRandomId()); messageId1 = new MessageId(TestUtils.getRandomId()); + contentType = "text/plain"; subject = "Foo"; timestamp = System.currentTimeMillis(); size = 1234; raw = new byte[size]; random.nextBytes(raw); - message = new TestMessage(messageId, null, group, author, subject, - timestamp, raw); - privateMessage = new TestMessage(messageId1, null, null, null, + message = new TestMessage(messageId, null, group, author, contentType, subject, timestamp, raw); + privateMessage = new TestMessage(messageId1, null, null, null, + contentType, subject, timestamp, raw); transportId = new TransportId(TestUtils.getRandomId()); contactId = new ContactId(1); contactName = "Alice"; @@ -552,7 +553,7 @@ public class H2DatabaseTest extends BriarTestCase { Author author1 = new Author(authorId1, "Bob", new byte[60]); MessageId messageId1 = new MessageId(TestUtils.getRandomId()); Message message1 = new TestMessage(messageId1, null, group, author1, - subject, timestamp, raw); + contentType, subject, timestamp, raw); Database<Connection> db = open(false); Connection txn = db.startTransaction(); @@ -584,12 +585,12 @@ public class H2DatabaseTest extends BriarTestCase { GroupId groupId1 = new GroupId(TestUtils.getRandomId()); Group group1 = new Group(groupId1, "Group name", null); Message child1 = new TestMessage(childId1, messageId, group, author, - subject, timestamp, raw); + contentType, subject, timestamp, raw); Message child2 = new TestMessage(childId2, messageId, group, author, - subject, timestamp, raw); + contentType, subject, timestamp, raw); // The third child is in a different group Message child3 = new TestMessage(childId3, messageId, group1, author, - subject, timestamp, raw); + contentType, subject, timestamp, raw); Database<Connection> db = open(false); Connection txn = db.startTransaction(); @@ -620,7 +621,7 @@ public class H2DatabaseTest extends BriarTestCase { public void testGetOldMessages() throws Exception { MessageId messageId1 = new MessageId(TestUtils.getRandomId()); Message message1 = new TestMessage(messageId1, null, group, author, - subject, timestamp + 1000, raw); + contentType, subject, timestamp + 1000, raw); Database<Connection> db = open(false); Connection txn = db.startTransaction(); @@ -651,7 +652,7 @@ public class H2DatabaseTest extends BriarTestCase { byte[] largeBody = new byte[ONE_MEGABYTE]; for(int i = 0; i < largeBody.length; i++) largeBody[i] = (byte) i; Message message1 = new TestMessage(messageId, null, group, author, - subject, timestamp, largeBody); + contentType, subject, timestamp, largeBody); Database<Connection> db = open(false); // Sanity check: there should be enough space on disk for this test @@ -1130,8 +1131,8 @@ public class H2DatabaseTest extends BriarTestCase { // A message with no parent should return null MessageId childId = new MessageId(TestUtils.getRandomId()); - Message child = new TestMessage(childId, null, group, null, subject, - timestamp, raw); + Message child = new TestMessage(childId, null, group, null, contentType, + subject, timestamp, raw); db.addGroupMessage(txn, child); assertTrue(db.containsMessage(txn, childId)); assertNull(db.getGroupMessageParent(txn, childId)); @@ -1152,7 +1153,7 @@ public class H2DatabaseTest extends BriarTestCase { MessageId childId = new MessageId(TestUtils.getRandomId()); MessageId parentId = new MessageId(TestUtils.getRandomId()); Message child = new TestMessage(childId, parentId, group, null, - subject, timestamp, raw); + contentType, subject, timestamp, raw); db.addGroupMessage(txn, child); assertTrue(db.containsMessage(txn, childId)); assertFalse(db.containsMessage(txn, parentId)); @@ -1178,9 +1179,9 @@ public class H2DatabaseTest extends BriarTestCase { MessageId childId = new MessageId(TestUtils.getRandomId()); MessageId parentId = new MessageId(TestUtils.getRandomId()); Message child = new TestMessage(childId, parentId, group, null, - subject, timestamp, raw); + contentType, subject, timestamp, raw); Message parent = new TestMessage(parentId, null, group1, null, - subject, timestamp, raw); + contentType, subject, timestamp, raw); db.addGroupMessage(txn, child); db.addGroupMessage(txn, parent); assertTrue(db.containsMessage(txn, childId)); @@ -1203,7 +1204,7 @@ public class H2DatabaseTest extends BriarTestCase { // A message with a private parent should return null MessageId childId = new MessageId(TestUtils.getRandomId()); Message child = new TestMessage(childId, messageId1, group, null, - subject, timestamp, raw); + contentType, subject, timestamp, raw); db.addGroupMessage(txn, child); db.addPrivateMessage(txn, privateMessage, contactId); assertTrue(db.containsMessage(txn, childId)); @@ -1227,9 +1228,9 @@ public class H2DatabaseTest extends BriarTestCase { MessageId childId = new MessageId(TestUtils.getRandomId()); MessageId parentId = new MessageId(TestUtils.getRandomId()); Message child = new TestMessage(childId, parentId, group, null, - subject, timestamp, raw); - Message parent = new TestMessage(parentId, null, group, null, subject, - timestamp, raw); + contentType, subject, timestamp, raw); + Message parent = new TestMessage(parentId, null, group, null, + contentType, subject, timestamp, raw); db.addGroupMessage(txn, child); db.addGroupMessage(txn, parent); assertTrue(db.containsMessage(txn, childId)); @@ -1252,9 +1253,9 @@ public class H2DatabaseTest extends BriarTestCase { // Store a couple of messages int bodyLength = raw.length - 20; Message message1 = new TestMessage(messageId, null, group, null, - subject, timestamp, raw, 5, bodyLength); + contentType, subject, timestamp, raw, 5, bodyLength); Message privateMessage1 = new TestMessage(messageId1, null, null, - null, subject, timestamp, raw, 10, bodyLength); + null, contentType, subject, timestamp, raw, 10, bodyLength); db.addGroupMessage(txn, message1); db.addPrivateMessage(txn, privateMessage1, contactId); @@ -1294,7 +1295,7 @@ public class H2DatabaseTest extends BriarTestCase { MessageId parentId = new MessageId(TestUtils.getRandomId()); long timestamp1 = System.currentTimeMillis(); Message message1 = new TestMessage(messageId1, parentId, group, author, - subject, timestamp1, raw); + contentType, subject, timestamp1, raw); db.addGroupMessage(txn, message1); // Mark one of the messages read assertFalse(db.setReadFlag(txn, messageId, true)); @@ -1352,6 +1353,7 @@ public class H2DatabaseTest extends BriarTestCase { assertEquals(m.getGroup().getId(), h.getGroupId()); if(m.getAuthor() == null) assertNull(h.getAuthor()); else assertEquals(m.getAuthor(), h.getAuthor()); + assertEquals(m.getContentType(), h.getContentType()); assertEquals(m.getSubject(), h.getSubject()); assertEquals(m.getTimestamp(), h.getTimestamp()); } @@ -1423,13 +1425,13 @@ public class H2DatabaseTest extends BriarTestCase { db.addGroupMessage(txn, message); MessageId messageId1 = new MessageId(TestUtils.getRandomId()); Message message1 = new TestMessage(messageId1, null, group, author, - subject, timestamp, raw); + contentType, subject, timestamp, raw); db.addGroupMessage(txn, message1); // Store one message in the second group MessageId messageId2 = new MessageId(TestUtils.getRandomId()); Message message2 = new TestMessage(messageId2, null, group1, author, - subject, timestamp, raw); + contentType, subject, timestamp, raw); db.addGroupMessage(txn, message2); // Mark one of the messages in the first group read diff --git a/briar-tests/src/net/sf/briar/messaging/ConstantsTest.java b/briar-tests/src/net/sf/briar/messaging/ConstantsTest.java index f715b6f2c9995b8204cbe6a0c1b0c639abc1946e..76e4d6ccab4d30c30a1d38ba2f8a6f4b85f10496 100644 --- a/briar-tests/src/net/sf/briar/messaging/ConstantsTest.java +++ b/briar-tests/src/net/sf/briar/messaging/ConstantsTest.java @@ -8,7 +8,7 @@ import static net.sf.briar.api.messaging.MessagingConstants.MAX_PROPERTIES_PER_T import static net.sf.briar.api.messaging.MessagingConstants.MAX_PROPERTY_LENGTH; import static net.sf.briar.api.messaging.MessagingConstants.MAX_PUBLIC_KEY_LENGTH; import static net.sf.briar.api.messaging.MessagingConstants.MAX_SIGNATURE_LENGTH; -import static net.sf.briar.api.messaging.MessagingConstants.MAX_SUBJECT_LENGTH; +import static net.sf.briar.api.messaging.MessagingConstants.MAX_CONTENT_TYPE_LENGTH; import static net.sf.briar.api.messaging.MessagingConstants.MAX_SUBSCRIPTIONS; import java.io.ByteArrayOutputStream; @@ -123,15 +123,16 @@ public class ConstantsTest extends BriarTestCase { crypto.generateSignatureKeyPair().getPrivate(); PrivateKey authorPrivate = crypto.generateSignatureKeyPair().getPrivate(); - String subject = createRandomString(MAX_SUBJECT_LENGTH); + String contentType = createRandomString(MAX_CONTENT_TYPE_LENGTH); byte[] body = new byte[MAX_BODY_LENGTH]; Message message = messageFactory.createPseudonymousMessage(parent, - group, groupPrivate, author, authorPrivate, subject, body); + group, groupPrivate, author, authorPrivate, contentType, body); // Check the size of the serialised message int length = message.getSerialised().length; assertTrue(length > UniqueId.LENGTH + MAX_GROUP_NAME_LENGTH + MAX_PUBLIC_KEY_LENGTH + MAX_AUTHOR_NAME_LENGTH - + MAX_PUBLIC_KEY_LENGTH + MAX_BODY_LENGTH); + + MAX_PUBLIC_KEY_LENGTH + MAX_CONTENT_TYPE_LENGTH + + MAX_BODY_LENGTH); assertTrue(length <= MAX_PACKET_LENGTH); } diff --git a/briar-tests/src/net/sf/briar/messaging/simplex/SimplexMessagingIntegrationTest.java b/briar-tests/src/net/sf/briar/messaging/simplex/SimplexMessagingIntegrationTest.java index 1257c0eccd66e5d4ceb08c4ed49d93fbe8f83d35..105518b8f53537393fde5308e8a1f4115ea6e357 100644 --- a/briar-tests/src/net/sf/briar/messaging/simplex/SimplexMessagingIntegrationTest.java +++ b/briar-tests/src/net/sf/briar/messaging/simplex/SimplexMessagingIntegrationTest.java @@ -112,10 +112,10 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase { db.addEndpoint(ep); km.endpointAdded(ep, initialSecret.clone()); // Send Bob a message - String subject = "Hello"; + String contentType = "text/plain"; byte[] body = "Hi Bob!".getBytes("UTF-8"); MessageFactory messageFactory = alice.getInstance(MessageFactory.class); - Message message = messageFactory.createPrivateMessage(null, subject, + Message message = messageFactory.createPrivateMessage(null, contentType, body); db.addLocalPrivateMessage(message, contactId); // Create an outgoing simplex connection