mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-18 13:49:53 +01:00
Removed subject line from wire format, added content type.
This commit is contained in:
BIN
briar-android/res/drawable-hdpi/content_attachment.png
Normal file
BIN
briar-android/res/drawable-hdpi/content_attachment.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
BIN
briar-android/res/drawable-mdpi/content_attachment.png
Normal file
BIN
briar-android/res/drawable-mdpi/content_attachment.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
BIN
briar-android/res/drawable-xhdpi/content_attachment.png
Normal file
BIN
briar-android/res/drawable-xhdpi/content_attachment.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
@@ -45,6 +45,13 @@ implements OnItemClickListener {
|
|||||||
else star.setImageResource(R.drawable.rating_not_important);
|
else star.setImageResource(R.drawable.rating_not_important);
|
||||||
layout.addView(star);
|
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);
|
TextView subject = new TextView(ctx);
|
||||||
// Give me all the unused width
|
// Give me all the unused width
|
||||||
subject.setLayoutParams(new LayoutParams(WRAP_CONTENT, WRAP_CONTENT,
|
subject.setLayoutParams(new LayoutParams(WRAP_CONTENT, WRAP_CONTENT,
|
||||||
|
|||||||
@@ -112,21 +112,21 @@ implements OnClickListener, DatabaseListener {
|
|||||||
ContactId contactId = db.addContact("Carol");
|
ContactId contactId = db.addContact("Carol");
|
||||||
// Insert some fake messages to and from the contact
|
// Insert some fake messages to and from the contact
|
||||||
Message m = messageFactory.createPrivateMessage(null,
|
Message m = messageFactory.createPrivateMessage(null,
|
||||||
"First message's subject is short",
|
"text/plain",
|
||||||
"First message's body".getBytes("UTF-8"));
|
"First message is short".getBytes("UTF-8"));
|
||||||
db.addLocalPrivateMessage(m, contactId);
|
db.addLocalPrivateMessage(m, contactId);
|
||||||
db.setReadFlag(m.getId(), true);
|
db.setReadFlag(m.getId(), true);
|
||||||
db.setStarredFlag(m.getId(), true);
|
db.setStarredFlag(m.getId(), true);
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
m = messageFactory.createPrivateMessage(m.getId(),
|
m = messageFactory.createPrivateMessage(m.getId(),
|
||||||
"Second message's subject is also short",
|
"image/jpeg", new byte[1000]);
|
||||||
"Second message's body".getBytes("UTF-8"));
|
|
||||||
db.receiveMessage(contactId, m);
|
db.receiveMessage(contactId, m);
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
m = messageFactory.createPrivateMessage(m.getId(),
|
m = messageFactory.createPrivateMessage(m.getId(),
|
||||||
"Third message's subject is quite long to test"
|
"text/plain",
|
||||||
+ " line wrapping and exciting stuff like that",
|
("Third message is quite long to test line"
|
||||||
"Third message's body".getBytes("UTF-8"));
|
+ " wrapping and subject line extraction and"
|
||||||
|
+ " all that fun stuff").getBytes("UTF-8"));
|
||||||
db.addLocalPrivateMessage(m, contactId);
|
db.addLocalPrivateMessage(m, contactId);
|
||||||
db.setReadFlag(m.getId(), true);
|
db.setReadFlag(m.getId(), true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ public class GroupMessageHeader extends MessageHeader {
|
|||||||
private final GroupId groupId;
|
private final GroupId groupId;
|
||||||
private final Author author;
|
private final Author author;
|
||||||
|
|
||||||
public GroupMessageHeader(MessageId id, MessageId parent, String subject,
|
public GroupMessageHeader(MessageId id, MessageId parent,
|
||||||
long timestamp, boolean read, boolean starred, GroupId groupId,
|
String contentType, String subject, long timestamp, boolean read,
|
||||||
Author author) {
|
boolean starred, GroupId groupId, Author author) {
|
||||||
super(id, parent, subject, timestamp, read, starred);
|
super(id, parent, contentType, subject, timestamp, read, starred);
|
||||||
this.groupId = groupId;
|
this.groupId = groupId;
|
||||||
this.author = author;
|
this.author = author;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,14 +5,15 @@ import net.sf.briar.api.messaging.MessageId;
|
|||||||
public abstract class MessageHeader {
|
public abstract class MessageHeader {
|
||||||
|
|
||||||
private final MessageId id, parent;
|
private final MessageId id, parent;
|
||||||
private final String subject;
|
private final String contentType, subject;
|
||||||
private final long timestamp;
|
private final long timestamp;
|
||||||
private final boolean read, starred;
|
private final boolean read, starred;
|
||||||
|
|
||||||
protected MessageHeader(MessageId id, MessageId parent, String subject,
|
protected MessageHeader(MessageId id, MessageId parent, String contentType,
|
||||||
long timestamp, boolean read, boolean starred) {
|
String subject, long timestamp, boolean read, boolean starred) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
|
this.contentType = contentType;
|
||||||
this.subject = subject;
|
this.subject = subject;
|
||||||
this.timestamp = timestamp;
|
this.timestamp = timestamp;
|
||||||
this.read = read;
|
this.read = read;
|
||||||
@@ -32,6 +33,11 @@ public abstract class MessageHeader {
|
|||||||
return parent;
|
return parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns the message's content type. */
|
||||||
|
public String getContentType() {
|
||||||
|
return contentType;
|
||||||
|
}
|
||||||
|
|
||||||
/** Returns the message's subject line. */
|
/** Returns the message's subject line. */
|
||||||
public String getSubject() {
|
public String getSubject() {
|
||||||
return subject;
|
return subject;
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ public class PrivateMessageHeader extends MessageHeader {
|
|||||||
private final ContactId contactId;
|
private final ContactId contactId;
|
||||||
private final boolean incoming;
|
private final boolean incoming;
|
||||||
|
|
||||||
public PrivateMessageHeader(MessageId id, MessageId parent, String subject,
|
public PrivateMessageHeader(MessageId id, MessageId parent,
|
||||||
long timestamp, boolean read, boolean starred, ContactId contactId,
|
String contentType, String subject, long timestamp, boolean read,
|
||||||
boolean incoming) {
|
boolean starred, ContactId contactId, boolean incoming) {
|
||||||
super(id, parent, subject, timestamp, read, starred);
|
super(id, parent, contentType, subject, timestamp, read, starred);
|
||||||
this.contactId = contactId;
|
this.contactId = contactId;
|
||||||
this.incoming = incoming;
|
this.incoming = incoming;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,14 @@ public interface Message {
|
|||||||
*/
|
*/
|
||||||
Author getAuthor();
|
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();
|
String getSubject();
|
||||||
|
|
||||||
/** Returns the timestamp created by the message's {@link Author}. */
|
/** Returns the timestamp created by the message's {@link Author}. */
|
||||||
|
|||||||
@@ -7,27 +7,27 @@ import java.security.PrivateKey;
|
|||||||
public interface MessageFactory {
|
public interface MessageFactory {
|
||||||
|
|
||||||
/** Creates a private message. */
|
/** Creates a private message. */
|
||||||
Message createPrivateMessage(MessageId parent, String subject, byte[] body)
|
Message createPrivateMessage(MessageId parent, String contentType,
|
||||||
throws IOException, GeneralSecurityException;
|
byte[] body) throws IOException, GeneralSecurityException;
|
||||||
|
|
||||||
/** Creates an anonymous message to an unrestricted group. */
|
/** Creates an anonymous message to an unrestricted group. */
|
||||||
Message createAnonymousGroupMessage(MessageId parent, Group group,
|
Message createAnonymousGroupMessage(MessageId parent, Group group,
|
||||||
String subject, byte[] body) throws IOException,
|
String contentType, byte[] body) throws IOException,
|
||||||
GeneralSecurityException;
|
GeneralSecurityException;
|
||||||
|
|
||||||
/** Creates an anonymous message to a restricted group. */
|
/** Creates an anonymous message to a restricted group. */
|
||||||
Message createAnonymousGroupMessage(MessageId parent, Group group,
|
Message createAnonymousGroupMessage(MessageId parent, Group group,
|
||||||
PrivateKey groupKey, String subject, byte[] body)
|
PrivateKey groupKey, String contentType, byte[] body)
|
||||||
throws IOException, GeneralSecurityException;
|
throws IOException, GeneralSecurityException;
|
||||||
|
|
||||||
/** Creates a pseudonymous message to an unrestricted group. */
|
/** Creates a pseudonymous message to an unrestricted group. */
|
||||||
Message createPseudonymousMessage(MessageId parent, Group group,
|
Message createPseudonymousMessage(MessageId parent, Group group,
|
||||||
Author author, PrivateKey authorKey, String subject, byte[] body)
|
Author author, PrivateKey authorKey, String contentType,
|
||||||
throws IOException, GeneralSecurityException;
|
byte[] body) throws IOException, GeneralSecurityException;
|
||||||
|
|
||||||
/** Creates a pseudonymous message to a restricted group. */
|
/** Creates a pseudonymous message to a restricted group. */
|
||||||
Message createPseudonymousMessage(MessageId parent, Group group,
|
Message createPseudonymousMessage(MessageId parent, Group group,
|
||||||
PrivateKey groupKey, Author author, PrivateKey authorKey,
|
PrivateKey groupKey, Author author, PrivateKey authorKey,
|
||||||
String subject, byte[] body) throws IOException,
|
String contentType, byte[] body) throws IOException,
|
||||||
GeneralSecurityException;
|
GeneralSecurityException;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,9 @@ public interface MessagingConstants {
|
|||||||
*/
|
*/
|
||||||
int MAX_BODY_LENGTH = MAX_PACKET_LENGTH - 1024;
|
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. */
|
/** The maximum length of a message's subject line in UTF-8 bytes. */
|
||||||
int MAX_SUBJECT_LENGTH = 100;
|
int MAX_SUBJECT_LENGTH = 100;
|
||||||
|
|
||||||
|
|||||||
@@ -6,18 +6,19 @@ public class UnverifiedMessage {
|
|||||||
private final MessageId parent;
|
private final MessageId parent;
|
||||||
private final Group group;
|
private final Group group;
|
||||||
private final Author author;
|
private final Author author;
|
||||||
private final String subject;
|
private final String contentType, subject;
|
||||||
private final long timestamp;
|
private final long timestamp;
|
||||||
private final byte[] raw, authorSig, groupSig;
|
private final byte[] raw, authorSig, groupSig;
|
||||||
private final int bodyStart, bodyLength, signedByAuthor, signedByGroup;
|
private final int bodyStart, bodyLength, signedByAuthor, signedByGroup;
|
||||||
|
|
||||||
public UnverifiedMessage(MessageId parent, Group group, Author author,
|
public UnverifiedMessage(MessageId parent, Group group, Author author,
|
||||||
String subject, long timestamp, byte[] raw, byte[] authorSig,
|
String contentType, String subject, long timestamp, byte[] raw,
|
||||||
byte[] groupSig, int bodyStart, int bodyLength, int signedByAuthor,
|
byte[] authorSig, byte[] groupSig, int bodyStart, int bodyLength,
|
||||||
int signedByGroup) {
|
int signedByAuthor, int signedByGroup) {
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.group = group;
|
this.group = group;
|
||||||
this.author = author;
|
this.author = author;
|
||||||
|
this.contentType = contentType;
|
||||||
this.subject = subject;
|
this.subject = subject;
|
||||||
this.timestamp = timestamp;
|
this.timestamp = timestamp;
|
||||||
this.raw = raw;
|
this.raw = raw;
|
||||||
@@ -53,7 +54,16 @@ public class UnverifiedMessage {
|
|||||||
return author;
|
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() {
|
public String getSubject() {
|
||||||
return subject;
|
return subject;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -472,7 +472,7 @@ DatabaseCleaner.Callback {
|
|||||||
if(m.getGroup() != null) throw new IllegalArgumentException();
|
if(m.getGroup() != null) throw new IllegalArgumentException();
|
||||||
if(m.getAuthor() != null) throw new IllegalArgumentException();
|
if(m.getAuthor() != null) throw new IllegalArgumentException();
|
||||||
if(!db.addPrivateMessage(txn, m, c)) return false;
|
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
|
// Count the bytes stored
|
||||||
synchronized(spaceLock) {
|
synchronized(spaceLock) {
|
||||||
bytesStoredSinceLastCheck += m.getSerialised().length;
|
bytesStoredSinceLastCheck += m.getSerialised().length;
|
||||||
|
|||||||
@@ -125,6 +125,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " authorId HASH," // Null for private/anon messages
|
+ " authorId HASH," // Null for private/anon messages
|
||||||
+ " authorName VARCHAR," // Null for private/anon messages
|
+ " authorName VARCHAR," // Null for private/anon messages
|
||||||
+ " authorKey VARCHAR," // Null for private/anon messages
|
+ " authorKey VARCHAR," // Null for private/anon messages
|
||||||
|
+ " contentType VARCHAR NOT NULL,"
|
||||||
+ " subject VARCHAR NOT NULL,"
|
+ " subject VARCHAR NOT NULL,"
|
||||||
+ " timestamp BIGINT NOT NULL,"
|
+ " timestamp BIGINT NOT NULL,"
|
||||||
+ " length INT NOT NULL,"
|
+ " length INT NOT NULL,"
|
||||||
@@ -633,10 +634,10 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
try {
|
try {
|
||||||
String sql = "INSERT INTO messages (messageId, parentId, groupId,"
|
String sql = "INSERT INTO messages (messageId, parentId, groupId,"
|
||||||
+ " authorId, authorName, authorKey, subject, timestamp,"
|
+ " authorId, authorName, authorKey, contentType, subject,"
|
||||||
+ " length, bodyStart, bodyLength, raw, sendability, read,"
|
+ " timestamp, length, bodyStart, bodyLength, raw,"
|
||||||
+ " starred)"
|
+ " sendability, read, starred)"
|
||||||
+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ZERO(),"
|
+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ZERO(),"
|
||||||
+ " FALSE, FALSE)";
|
+ " FALSE, FALSE)";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
ps.setBytes(1, m.getId().getBytes());
|
ps.setBytes(1, m.getId().getBytes());
|
||||||
@@ -653,13 +654,14 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
ps.setString(5, a.getName());
|
ps.setString(5, a.getName());
|
||||||
ps.setBytes(6, a.getPublicKey());
|
ps.setBytes(6, a.getPublicKey());
|
||||||
}
|
}
|
||||||
ps.setString(7, m.getSubject());
|
ps.setString(7, m.getContentType());
|
||||||
ps.setLong(8, m.getTimestamp());
|
ps.setString(8, m.getSubject());
|
||||||
|
ps.setLong(9, m.getTimestamp());
|
||||||
byte[] raw = m.getSerialised();
|
byte[] raw = m.getSerialised();
|
||||||
ps.setInt(9, raw.length);
|
ps.setInt(10, raw.length);
|
||||||
ps.setInt(10, m.getBodyStart());
|
ps.setInt(11, m.getBodyStart());
|
||||||
ps.setInt(11, m.getBodyLength());
|
ps.setInt(12, m.getBodyLength());
|
||||||
ps.setBytes(12, raw);
|
ps.setBytes(13, raw);
|
||||||
int affected = ps.executeUpdate();
|
int affected = ps.executeUpdate();
|
||||||
if(affected != 1) throw new DbStateException();
|
if(affected != 1) throw new DbStateException();
|
||||||
ps.close();
|
ps.close();
|
||||||
@@ -707,22 +709,23 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
if(containsMessage(txn, m.getId())) return false;
|
if(containsMessage(txn, m.getId())) return false;
|
||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
try {
|
try {
|
||||||
String sql = "INSERT INTO messages (messageId, parentId, subject,"
|
String sql = "INSERT INTO messages (messageId, parentId,"
|
||||||
+ " timestamp, length, bodyStart, bodyLength, raw,"
|
+ " contentType, subject, timestamp, length, bodyStart,"
|
||||||
+ " contactId, read, starred)"
|
+ " bodyLength, raw, contactId, read, starred)"
|
||||||
+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, FALSE, FALSE)";
|
+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, FALSE, FALSE)";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
ps.setBytes(1, m.getId().getBytes());
|
ps.setBytes(1, m.getId().getBytes());
|
||||||
if(m.getParent() == null) ps.setNull(2, BINARY);
|
if(m.getParent() == null) ps.setNull(2, BINARY);
|
||||||
else ps.setBytes(2, m.getParent().getBytes());
|
else ps.setBytes(2, m.getParent().getBytes());
|
||||||
ps.setString(3, m.getSubject());
|
ps.setString(3, m.getContentType());
|
||||||
ps.setLong(4, m.getTimestamp());
|
ps.setString(4, m.getSubject());
|
||||||
|
ps.setLong(5, m.getTimestamp());
|
||||||
byte[] raw = m.getSerialised();
|
byte[] raw = m.getSerialised();
|
||||||
ps.setInt(5, raw.length);
|
ps.setInt(6, raw.length);
|
||||||
ps.setInt(6, m.getBodyStart());
|
ps.setInt(7, m.getBodyStart());
|
||||||
ps.setInt(7, m.getBodyLength());
|
ps.setInt(8, m.getBodyLength());
|
||||||
ps.setBytes(8, raw);
|
ps.setBytes(9, raw);
|
||||||
ps.setInt(9, c.getInt());
|
ps.setInt(10, c.getInt());
|
||||||
int affected = ps.executeUpdate();
|
int affected = ps.executeUpdate();
|
||||||
if(affected != 1) throw new DbStateException();
|
if(affected != 1) throw new DbStateException();
|
||||||
ps.close();
|
ps.close();
|
||||||
@@ -1226,7 +1229,8 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
try {
|
try {
|
||||||
String sql = "SELECT messageId, parentId, authorId, authorName,"
|
String sql = "SELECT messageId, parentId, authorId, authorName,"
|
||||||
+ " authorKey, subject, timestamp, read, starred"
|
+ " authorKey, contentType, subject, timestamp, read,"
|
||||||
|
+ " starred"
|
||||||
+ " FROM messages"
|
+ " FROM messages"
|
||||||
+ " WHERE groupId = ?";
|
+ " WHERE groupId = ?";
|
||||||
ps = txn.prepareStatement(sql);
|
ps = txn.prepareStatement(sql);
|
||||||
@@ -1246,12 +1250,13 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
byte[] authorKey = rs.getBytes(5);
|
byte[] authorKey = rs.getBytes(5);
|
||||||
author = new Author(authorId, authorName, authorKey);
|
author = new Author(authorId, authorName, authorKey);
|
||||||
}
|
}
|
||||||
String subject = rs.getString(6);
|
String contentType = rs.getString(6);
|
||||||
long timestamp = rs.getLong(7);
|
String subject = rs.getString(7);
|
||||||
boolean read = rs.getBoolean(8);
|
long timestamp = rs.getLong(8);
|
||||||
boolean starred = rs.getBoolean(9);
|
boolean read = rs.getBoolean(9);
|
||||||
headers.add(new GroupMessageHeader(id, parent, subject,
|
boolean starred = rs.getBoolean(10);
|
||||||
timestamp, read, starred, g, author));
|
headers.add(new GroupMessageHeader(id, parent, contentType,
|
||||||
|
subject, timestamp, read, starred, g, author));
|
||||||
}
|
}
|
||||||
rs.close();
|
rs.close();
|
||||||
ps.close();
|
ps.close();
|
||||||
@@ -1268,8 +1273,8 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
try {
|
try {
|
||||||
String sql = "SELECT m.messageId, parentId, subject, timestamp,"
|
String sql = "SELECT m.messageId, parentId, contentType, subject,"
|
||||||
+ " m.contactId, read, starred, seen"
|
+ " timestamp, m.contactId, read, starred, seen"
|
||||||
+ " FROM messages AS m"
|
+ " FROM messages AS m"
|
||||||
+ " JOIN statuses AS s"
|
+ " JOIN statuses AS s"
|
||||||
+ " ON m.messageId = s.messageId"
|
+ " ON m.messageId = s.messageId"
|
||||||
@@ -1283,14 +1288,15 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
MessageId id = new MessageId(rs.getBytes(1));
|
MessageId id = new MessageId(rs.getBytes(1));
|
||||||
byte[] b = rs.getBytes(2);
|
byte[] b = rs.getBytes(2);
|
||||||
MessageId parent = b == null ? null : new MessageId(b);
|
MessageId parent = b == null ? null : new MessageId(b);
|
||||||
String subject = rs.getString(3);
|
String contentType = rs.getString(3);
|
||||||
long timestamp = rs.getLong(4);
|
String subject = rs.getString(4);
|
||||||
ContactId contactId = new ContactId(rs.getInt(5));
|
long timestamp = rs.getLong(5);
|
||||||
boolean read = rs.getBoolean(6);
|
ContactId contactId = new ContactId(rs.getInt(6));
|
||||||
boolean starred = rs.getBoolean(7);
|
boolean read = rs.getBoolean(7);
|
||||||
boolean seen = rs.getBoolean(8);
|
boolean starred = rs.getBoolean(8);
|
||||||
headers.add(new PrivateMessageHeader(id, parent, subject,
|
boolean seen = rs.getBoolean(9);
|
||||||
timestamp, read, starred, contactId, !seen));
|
headers.add(new PrivateMessageHeader(id, parent, contentType,
|
||||||
|
subject, timestamp, read, starred, contactId, seen));
|
||||||
}
|
}
|
||||||
rs.close();
|
rs.close();
|
||||||
ps.close();
|
ps.close();
|
||||||
@@ -1307,8 +1313,8 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
PreparedStatement ps = null;
|
PreparedStatement ps = null;
|
||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
try {
|
try {
|
||||||
String sql = "SELECT m.messageId, parentId, subject, timestamp,"
|
String sql = "SELECT m.messageId, parentId, contentType, subject,"
|
||||||
+ " read, starred, seen"
|
+ " timestamp, read, starred, seen"
|
||||||
+ " FROM messages AS m"
|
+ " FROM messages AS m"
|
||||||
+ " JOIN statuses AS s"
|
+ " JOIN statuses AS s"
|
||||||
+ " ON m.messageId = s.messageId"
|
+ " ON m.messageId = s.messageId"
|
||||||
@@ -1323,13 +1329,14 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
MessageId id = new MessageId(rs.getBytes(1));
|
MessageId id = new MessageId(rs.getBytes(1));
|
||||||
byte[] b = rs.getBytes(2);
|
byte[] b = rs.getBytes(2);
|
||||||
MessageId parent = b == null ? null : new MessageId(b);
|
MessageId parent = b == null ? null : new MessageId(b);
|
||||||
String subject = rs.getString(3);
|
String contentType = rs.getString(3);
|
||||||
long timestamp = rs.getLong(4);
|
String subject = rs.getString(4);
|
||||||
boolean read = rs.getBoolean(5);
|
long timestamp = rs.getLong(5);
|
||||||
boolean starred = rs.getBoolean(6);
|
boolean read = rs.getBoolean(6);
|
||||||
boolean seen = rs.getBoolean(7);
|
boolean starred = rs.getBoolean(7);
|
||||||
headers.add(new PrivateMessageHeader(id, parent, subject,
|
boolean seen = rs.getBoolean(8);
|
||||||
timestamp, read, starred, c, !seen));
|
headers.add(new PrivateMessageHeader(id, parent, contentType,
|
||||||
|
subject, timestamp, read, starred, c, seen));
|
||||||
}
|
}
|
||||||
rs.close();
|
rs.close();
|
||||||
ps.close();
|
ps.close();
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package net.sf.briar.messaging;
|
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_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_PACKET_LENGTH;
|
||||||
import static net.sf.briar.api.messaging.MessagingConstants.MAX_SIGNATURE_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_SUBJECT_LENGTH;
|
||||||
@@ -11,6 +12,9 @@ import static net.sf.briar.api.messaging.Types.MESSAGE;
|
|||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
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.GeneralSecurityException;
|
||||||
import java.security.PrivateKey;
|
import java.security.PrivateKey;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
@@ -40,6 +44,7 @@ class MessageFactoryImpl implements MessageFactory {
|
|||||||
private final MessageDigest messageDigest;
|
private final MessageDigest messageDigest;
|
||||||
private final WriterFactory writerFactory;
|
private final WriterFactory writerFactory;
|
||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
|
private final CharsetDecoder decoder;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
MessageFactoryImpl(CryptoComponent crypto, WriterFactory writerFactory,
|
MessageFactoryImpl(CryptoComponent crypto, WriterFactory writerFactory,
|
||||||
@@ -50,44 +55,46 @@ class MessageFactoryImpl implements MessageFactory {
|
|||||||
messageDigest = crypto.getMessageDigest();
|
messageDigest = crypto.getMessageDigest();
|
||||||
this.writerFactory = writerFactory;
|
this.writerFactory = writerFactory;
|
||||||
this.clock = clock;
|
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 {
|
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,
|
public Message createAnonymousGroupMessage(MessageId parent, Group group,
|
||||||
String subject, byte[] body) throws IOException,
|
String contentType, byte[] body) throws IOException,
|
||||||
GeneralSecurityException {
|
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,
|
public Message createAnonymousGroupMessage(MessageId parent, Group group,
|
||||||
PrivateKey groupKey, String subject, byte[] body)
|
PrivateKey groupKey, String contentType, byte[] body)
|
||||||
throws IOException, GeneralSecurityException {
|
throws IOException, GeneralSecurityException {
|
||||||
return createMessage(parent, group, groupKey, null, null, subject,
|
return createMessage(parent, group, groupKey, null, null, contentType,
|
||||||
body);
|
body);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Message createPseudonymousMessage(MessageId parent, Group group,
|
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 {
|
throws IOException, GeneralSecurityException {
|
||||||
return createMessage(parent, group, null, author, authorKey, subject,
|
return createMessage(parent, group, null, author, authorKey,
|
||||||
body);
|
contentType, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Message createPseudonymousMessage(MessageId parent, Group group,
|
public Message createPseudonymousMessage(MessageId parent, Group group,
|
||||||
PrivateKey groupKey, Author author, PrivateKey authorKey,
|
PrivateKey groupKey, Author author, PrivateKey authorKey,
|
||||||
String subject, byte[] body) throws IOException,
|
String contentType, byte[] body) throws IOException,
|
||||||
GeneralSecurityException {
|
GeneralSecurityException {
|
||||||
return createMessage(parent, group, groupKey, author, authorKey,
|
return createMessage(parent, group, groupKey, author, authorKey,
|
||||||
subject, body);
|
contentType, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Message createMessage(MessageId parent, Group group,
|
private Message createMessage(MessageId parent, Group group,
|
||||||
PrivateKey groupKey, Author author, PrivateKey authorKey,
|
PrivateKey groupKey, Author author, PrivateKey authorKey,
|
||||||
String subject, byte[] body) throws IOException,
|
String contentType, byte[] body) throws IOException,
|
||||||
GeneralSecurityException {
|
GeneralSecurityException {
|
||||||
// Validate the arguments
|
// Validate the arguments
|
||||||
if((author == null) != (authorKey == null))
|
if((author == null) != (authorKey == null))
|
||||||
@@ -95,7 +102,7 @@ class MessageFactoryImpl implements MessageFactory {
|
|||||||
if((group == null || group.getPublicKey() == null)
|
if((group == null || group.getPublicKey() == null)
|
||||||
!= (groupKey == null))
|
!= (groupKey == null))
|
||||||
throw new IllegalArgumentException();
|
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();
|
throw new IllegalArgumentException();
|
||||||
if(body.length > MAX_BODY_LENGTH)
|
if(body.length > MAX_BODY_LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
@@ -127,7 +134,7 @@ class MessageFactoryImpl implements MessageFactory {
|
|||||||
else writeGroup(w, group);
|
else writeGroup(w, group);
|
||||||
if(author == null) w.writeNull();
|
if(author == null) w.writeNull();
|
||||||
else writeAuthor(w, author);
|
else writeAuthor(w, author);
|
||||||
w.writeString(subject);
|
w.writeString(contentType);
|
||||||
long timestamp = clock.currentTimeMillis();
|
long timestamp = clock.currentTimeMillis();
|
||||||
w.writeInt64(timestamp);
|
w.writeInt64(timestamp);
|
||||||
byte[] salt = new byte[SALT_LENGTH];
|
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
|
// Hash the message, including the signatures, to get the message ID
|
||||||
w.removeConsumer(digestingConsumer);
|
w.removeConsumer(digestingConsumer);
|
||||||
MessageId id = new MessageId(messageDigest.digest());
|
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);
|
timestamp, out.toByteArray(), bodyStart, body.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,14 +12,14 @@ class MessageImpl implements Message {
|
|||||||
private final MessageId id, parent;
|
private final MessageId id, parent;
|
||||||
private final Group group;
|
private final Group group;
|
||||||
private final Author author;
|
private final Author author;
|
||||||
private final String subject;
|
private final String contentType, subject;
|
||||||
private final long timestamp;
|
private final long timestamp;
|
||||||
private final byte[] raw;
|
private final byte[] raw;
|
||||||
private final int bodyStart, bodyLength;
|
private final int bodyStart, bodyLength;
|
||||||
|
|
||||||
public MessageImpl(MessageId id, MessageId parent, Group group,
|
public MessageImpl(MessageId id, MessageId parent, Group group,
|
||||||
Author author, String subject, long timestamp, byte[] raw,
|
Author author, String contentType, String subject, long timestamp,
|
||||||
int bodyStart, int bodyLength) {
|
byte[] raw, int bodyStart, int bodyLength) {
|
||||||
if(bodyStart + bodyLength > raw.length)
|
if(bodyStart + bodyLength > raw.length)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
if(bodyLength > MAX_BODY_LENGTH)
|
if(bodyLength > MAX_BODY_LENGTH)
|
||||||
@@ -28,6 +28,7 @@ class MessageImpl implements Message {
|
|||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.group = group;
|
this.group = group;
|
||||||
this.author = author;
|
this.author = author;
|
||||||
|
this.contentType = contentType;
|
||||||
this.subject = subject;
|
this.subject = subject;
|
||||||
this.timestamp = timestamp;
|
this.timestamp = timestamp;
|
||||||
this.raw = raw;
|
this.raw = raw;
|
||||||
@@ -51,6 +52,10 @@ class MessageImpl implements Message {
|
|||||||
return author;
|
return author;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getContentType() {
|
||||||
|
return contentType;
|
||||||
|
}
|
||||||
|
|
||||||
public String getSubject() {
|
public String getSubject() {
|
||||||
return subject;
|
return subject;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package net.sf.briar.messaging;
|
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_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_PACKET_LENGTH;
|
||||||
import static net.sf.briar.api.messaging.MessagingConstants.MAX_SIGNATURE_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_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 static net.sf.briar.api.messaging.Types.MESSAGE;
|
||||||
|
|
||||||
import java.io.IOException;
|
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.FormatException;
|
||||||
import net.sf.briar.api.messaging.Author;
|
import net.sf.briar.api.messaging.Author;
|
||||||
@@ -24,11 +28,13 @@ class MessageReader implements StructReader<UnverifiedMessage> {
|
|||||||
|
|
||||||
private final StructReader<Group> groupReader;
|
private final StructReader<Group> groupReader;
|
||||||
private final StructReader<Author> authorReader;
|
private final StructReader<Author> authorReader;
|
||||||
|
private final CharsetDecoder decoder;
|
||||||
|
|
||||||
MessageReader(StructReader<Group> groupReader,
|
MessageReader(StructReader<Group> groupReader,
|
||||||
StructReader<Author> authorReader) {
|
StructReader<Author> authorReader) {
|
||||||
this.groupReader = groupReader;
|
this.groupReader = groupReader;
|
||||||
this.authorReader = authorReader;
|
this.authorReader = authorReader;
|
||||||
|
decoder = Charset.forName("UTF-8").newDecoder();
|
||||||
}
|
}
|
||||||
|
|
||||||
public UnverifiedMessage readStruct(Reader r) throws IOException {
|
public UnverifiedMessage readStruct(Reader r) throws IOException {
|
||||||
@@ -55,8 +61,8 @@ class MessageReader implements StructReader<UnverifiedMessage> {
|
|||||||
Author author = null;
|
Author author = null;
|
||||||
if(r.hasNull()) r.readNull();
|
if(r.hasNull()) r.readNull();
|
||||||
else author = authorReader.readStruct(r);
|
else author = authorReader.readStruct(r);
|
||||||
// Read the subject
|
// Read the content type
|
||||||
String subject = r.readString(MAX_SUBJECT_LENGTH);
|
String contentType = r.readString(MAX_CONTENT_TYPE_LENGTH);
|
||||||
// Read the timestamp
|
// Read the timestamp
|
||||||
long timestamp = r.readInt64();
|
long timestamp = r.readInt64();
|
||||||
if(timestamp < 0) throw new FormatException();
|
if(timestamp < 0) throw new FormatException();
|
||||||
@@ -65,6 +71,16 @@ class MessageReader implements StructReader<UnverifiedMessage> {
|
|||||||
if(salt.length < SALT_LENGTH) throw new FormatException();
|
if(salt.length < SALT_LENGTH) throw new FormatException();
|
||||||
// Read the message body
|
// Read the message body
|
||||||
byte[] body = r.readBytes(MAX_BODY_LENGTH);
|
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
|
// Record the offset of the body within the message
|
||||||
int bodyStart = (int) counting.getCount() - body.length;
|
int bodyStart = (int) counting.getCount() - body.length;
|
||||||
// Record the length of the data covered by the author's signature
|
// 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(counting);
|
||||||
r.removeConsumer(copying);
|
r.removeConsumer(copying);
|
||||||
byte[] raw = copying.getCopy();
|
byte[] raw = copying.getCopy();
|
||||||
return new UnverifiedMessage(parent, group, author, subject, timestamp,
|
return new UnverifiedMessage(parent, group, author, contentType,
|
||||||
raw, authorSig, groupSig, bodyStart, body.length,
|
subject, timestamp, raw, authorSig, groupSig, bodyStart,
|
||||||
signedByAuthor, signedByGroup);
|
body.length, signedByAuthor, signedByGroup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,8 @@ class MessageVerifierImpl implements MessageVerifier {
|
|||||||
if(!signature.verify(m.getGroupSignature()))
|
if(!signature.verify(m.getGroupSignature()))
|
||||||
throw new GeneralSecurityException();
|
throw new GeneralSecurityException();
|
||||||
}
|
}
|
||||||
return new MessageImpl(id, m.getParent(), group, author, m.getSubject(),
|
return new MessageImpl(id, m.getParent(), group, author,
|
||||||
m.getTimestamp(), raw, m.getBodyStart(), m.getBodyLength());
|
m.getContentType(), m.getSubject(), m.getTimestamp(), raw,
|
||||||
|
m.getBodyStart(), m.getBodyLength());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ public class ProtocolIntegrationTest extends BriarTestCase {
|
|||||||
private final Group group, group1;
|
private final Group group, group1;
|
||||||
private final Message message, message1, message2, message3;
|
private final Message message, message1, message2, message3;
|
||||||
private final String authorName = "Alice";
|
private final String authorName = "Alice";
|
||||||
private final String subject = "Hello";
|
private final String contentType = "text/plain";
|
||||||
private final String messageBody = "Hello world";
|
private final String messageBody = "Hello world";
|
||||||
private final Collection<MessageId> messageIds;
|
private final Collection<MessageId> messageIds;
|
||||||
private final TransportId transportId;
|
private final TransportId transportId;
|
||||||
@@ -107,16 +107,16 @@ public class ProtocolIntegrationTest extends BriarTestCase {
|
|||||||
// Create two messages to each group: one anonymous, one pseudonymous
|
// Create two messages to each group: one anonymous, one pseudonymous
|
||||||
MessageFactory messageFactory = i.getInstance(MessageFactory.class);
|
MessageFactory messageFactory = i.getInstance(MessageFactory.class);
|
||||||
message = messageFactory.createAnonymousGroupMessage(null, group,
|
message = messageFactory.createAnonymousGroupMessage(null, group,
|
||||||
subject, messageBody.getBytes("UTF-8"));
|
contentType, messageBody.getBytes("UTF-8"));
|
||||||
message1 = messageFactory.createAnonymousGroupMessage(null, group1,
|
message1 = messageFactory.createAnonymousGroupMessage(null, group1,
|
||||||
groupKeyPair.getPrivate(), subject,
|
groupKeyPair.getPrivate(), contentType,
|
||||||
messageBody.getBytes("UTF-8"));
|
messageBody.getBytes("UTF-8"));
|
||||||
message2 = messageFactory.createPseudonymousMessage(null, group,
|
message2 = messageFactory.createPseudonymousMessage(null, group,
|
||||||
author, authorKeyPair.getPrivate(), subject,
|
author, authorKeyPair.getPrivate(), contentType,
|
||||||
messageBody.getBytes("UTF-8"));
|
messageBody.getBytes("UTF-8"));
|
||||||
message3 = messageFactory.createPseudonymousMessage(null, group1,
|
message3 = messageFactory.createPseudonymousMessage(null, group1,
|
||||||
groupKeyPair.getPrivate(), author, authorKeyPair.getPrivate(),
|
groupKeyPair.getPrivate(), author, authorKeyPair.getPrivate(),
|
||||||
subject, messageBody.getBytes("UTF-8"));
|
contentType, messageBody.getBytes("UTF-8"));
|
||||||
messageIds = Arrays.asList(message.getId(), message1.getId(),
|
messageIds = Arrays.asList(message.getId(), message1.getId(),
|
||||||
message2.getId(), message3.getId());
|
message2.getId(), message3.getId());
|
||||||
// Create some transport properties
|
// Create some transport properties
|
||||||
|
|||||||
@@ -13,23 +13,26 @@ public class TestMessage implements Message {
|
|||||||
private final MessageId id, parent;
|
private final MessageId id, parent;
|
||||||
private final Group group;
|
private final Group group;
|
||||||
private final Author author;
|
private final Author author;
|
||||||
private final String subject;
|
private final String contentType, subject;
|
||||||
private final long timestamp;
|
private final long timestamp;
|
||||||
private final byte[] raw;
|
private final byte[] raw;
|
||||||
private final int bodyStart, bodyLength;
|
private final int bodyStart, bodyLength;
|
||||||
|
|
||||||
public TestMessage(MessageId id, MessageId parent, Group group,
|
public TestMessage(MessageId id, MessageId parent, Group group,
|
||||||
Author author, String subject, long timestamp, byte[] raw) {
|
Author author, String contentType, String subject, long timestamp,
|
||||||
this(id, parent, group, author, subject, timestamp, raw, 0, raw.length);
|
byte[] raw) {
|
||||||
|
this(id, parent, group, author, contentType, subject, timestamp, raw, 0,
|
||||||
|
raw.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TestMessage(MessageId id, MessageId parent, Group group,
|
public TestMessage(MessageId id, MessageId parent, Group group,
|
||||||
Author author, String subject, long timestamp, byte[] raw,
|
Author author, String contentType, String subject, long timestamp,
|
||||||
int bodyStart, int bodyLength) {
|
byte[] raw, int bodyStart, int bodyLength) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.group = group;
|
this.group = group;
|
||||||
this.author = author;
|
this.author = author;
|
||||||
|
this.contentType = contentType;
|
||||||
this.subject = subject;
|
this.subject = subject;
|
||||||
this.timestamp = timestamp;
|
this.timestamp = timestamp;
|
||||||
this.raw = raw;
|
this.raw = raw;
|
||||||
@@ -53,6 +56,10 @@ public class TestMessage implements Message {
|
|||||||
return author;
|
return author;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getContentType() {
|
||||||
|
return contentType;
|
||||||
|
}
|
||||||
|
|
||||||
public String getSubject() {
|
public String getSubject() {
|
||||||
return subject;
|
return subject;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
|
|||||||
protected final AuthorId authorId;
|
protected final AuthorId authorId;
|
||||||
protected final Author author;
|
protected final Author author;
|
||||||
protected final MessageId messageId, messageId1;
|
protected final MessageId messageId, messageId1;
|
||||||
protected final String subject;
|
protected final String contentType, subject;
|
||||||
protected final long timestamp;
|
protected final long timestamp;
|
||||||
protected final int size;
|
protected final int size;
|
||||||
protected final byte[] raw;
|
protected final byte[] raw;
|
||||||
@@ -80,14 +80,15 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
|
|||||||
author = new Author(authorId, "Alice", new byte[60]);
|
author = new Author(authorId, "Alice", new byte[60]);
|
||||||
messageId = new MessageId(TestUtils.getRandomId());
|
messageId = new MessageId(TestUtils.getRandomId());
|
||||||
messageId1 = new MessageId(TestUtils.getRandomId());
|
messageId1 = new MessageId(TestUtils.getRandomId());
|
||||||
|
contentType = "text/plain";
|
||||||
subject = "Foo";
|
subject = "Foo";
|
||||||
timestamp = System.currentTimeMillis();
|
timestamp = System.currentTimeMillis();
|
||||||
size = 1234;
|
size = 1234;
|
||||||
raw = new byte[size];
|
raw = new byte[size];
|
||||||
message = new TestMessage(messageId, null, group, author, subject,
|
message = new TestMessage(messageId, null, group, author, contentType,
|
||||||
timestamp, raw);
|
subject, timestamp, raw);
|
||||||
privateMessage = new TestMessage(messageId, null, null, null, subject,
|
privateMessage = new TestMessage(messageId, null, null, null,
|
||||||
timestamp, raw);
|
contentType, subject, timestamp, raw);
|
||||||
transportId = new TransportId(TestUtils.getRandomId());
|
transportId = new TransportId(TestUtils.getRandomId());
|
||||||
transportProperties = new TransportProperties(Collections.singletonMap(
|
transportProperties = new TransportProperties(Collections.singletonMap(
|
||||||
"foo", "bar"));
|
"foo", "bar"));
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
private final AuthorId authorId;
|
private final AuthorId authorId;
|
||||||
private final Author author;
|
private final Author author;
|
||||||
private final MessageId messageId, messageId1;
|
private final MessageId messageId, messageId1;
|
||||||
private final String subject;
|
private final String contentType, subject;
|
||||||
private final long timestamp;
|
private final long timestamp;
|
||||||
private final int size;
|
private final int size;
|
||||||
private final byte[] raw;
|
private final byte[] raw;
|
||||||
@@ -73,15 +73,16 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
author = new Author(authorId, "Alice", new byte[60]);
|
author = new Author(authorId, "Alice", new byte[60]);
|
||||||
messageId = new MessageId(TestUtils.getRandomId());
|
messageId = new MessageId(TestUtils.getRandomId());
|
||||||
messageId1 = new MessageId(TestUtils.getRandomId());
|
messageId1 = new MessageId(TestUtils.getRandomId());
|
||||||
|
contentType = "text/plain";
|
||||||
subject = "Foo";
|
subject = "Foo";
|
||||||
timestamp = System.currentTimeMillis();
|
timestamp = System.currentTimeMillis();
|
||||||
size = 1234;
|
size = 1234;
|
||||||
raw = new byte[size];
|
raw = new byte[size];
|
||||||
random.nextBytes(raw);
|
random.nextBytes(raw);
|
||||||
message = new TestMessage(messageId, null, group, author, subject,
|
message = new TestMessage(messageId, null, group, author, contentType,
|
||||||
timestamp, raw);
|
|
||||||
privateMessage = new TestMessage(messageId1, null, null, null,
|
|
||||||
subject, timestamp, raw);
|
subject, timestamp, raw);
|
||||||
|
privateMessage = new TestMessage(messageId1, null, null, null,
|
||||||
|
contentType, subject, timestamp, raw);
|
||||||
transportId = new TransportId(TestUtils.getRandomId());
|
transportId = new TransportId(TestUtils.getRandomId());
|
||||||
contactId = new ContactId(1);
|
contactId = new ContactId(1);
|
||||||
contactName = "Alice";
|
contactName = "Alice";
|
||||||
@@ -552,7 +553,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
Author author1 = new Author(authorId1, "Bob", new byte[60]);
|
Author author1 = new Author(authorId1, "Bob", new byte[60]);
|
||||||
MessageId messageId1 = new MessageId(TestUtils.getRandomId());
|
MessageId messageId1 = new MessageId(TestUtils.getRandomId());
|
||||||
Message message1 = new TestMessage(messageId1, null, group, author1,
|
Message message1 = new TestMessage(messageId1, null, group, author1,
|
||||||
subject, timestamp, raw);
|
contentType, subject, timestamp, raw);
|
||||||
Database<Connection> db = open(false);
|
Database<Connection> db = open(false);
|
||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
@@ -584,12 +585,12 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
GroupId groupId1 = new GroupId(TestUtils.getRandomId());
|
GroupId groupId1 = new GroupId(TestUtils.getRandomId());
|
||||||
Group group1 = new Group(groupId1, "Group name", null);
|
Group group1 = new Group(groupId1, "Group name", null);
|
||||||
Message child1 = new TestMessage(childId1, messageId, group, author,
|
Message child1 = new TestMessage(childId1, messageId, group, author,
|
||||||
subject, timestamp, raw);
|
contentType, subject, timestamp, raw);
|
||||||
Message child2 = new TestMessage(childId2, messageId, group, author,
|
Message child2 = new TestMessage(childId2, messageId, group, author,
|
||||||
subject, timestamp, raw);
|
contentType, subject, timestamp, raw);
|
||||||
// The third child is in a different group
|
// The third child is in a different group
|
||||||
Message child3 = new TestMessage(childId3, messageId, group1, author,
|
Message child3 = new TestMessage(childId3, messageId, group1, author,
|
||||||
subject, timestamp, raw);
|
contentType, subject, timestamp, raw);
|
||||||
Database<Connection> db = open(false);
|
Database<Connection> db = open(false);
|
||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
@@ -620,7 +621,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
public void testGetOldMessages() throws Exception {
|
public void testGetOldMessages() throws Exception {
|
||||||
MessageId messageId1 = new MessageId(TestUtils.getRandomId());
|
MessageId messageId1 = new MessageId(TestUtils.getRandomId());
|
||||||
Message message1 = new TestMessage(messageId1, null, group, author,
|
Message message1 = new TestMessage(messageId1, null, group, author,
|
||||||
subject, timestamp + 1000, raw);
|
contentType, subject, timestamp + 1000, raw);
|
||||||
Database<Connection> db = open(false);
|
Database<Connection> db = open(false);
|
||||||
Connection txn = db.startTransaction();
|
Connection txn = db.startTransaction();
|
||||||
|
|
||||||
@@ -651,7 +652,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
byte[] largeBody = new byte[ONE_MEGABYTE];
|
byte[] largeBody = new byte[ONE_MEGABYTE];
|
||||||
for(int i = 0; i < largeBody.length; i++) largeBody[i] = (byte) i;
|
for(int i = 0; i < largeBody.length; i++) largeBody[i] = (byte) i;
|
||||||
Message message1 = new TestMessage(messageId, null, group, author,
|
Message message1 = new TestMessage(messageId, null, group, author,
|
||||||
subject, timestamp, largeBody);
|
contentType, subject, timestamp, largeBody);
|
||||||
Database<Connection> db = open(false);
|
Database<Connection> db = open(false);
|
||||||
|
|
||||||
// Sanity check: there should be enough space on disk for this test
|
// 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
|
// A message with no parent should return null
|
||||||
MessageId childId = new MessageId(TestUtils.getRandomId());
|
MessageId childId = new MessageId(TestUtils.getRandomId());
|
||||||
Message child = new TestMessage(childId, null, group, null, subject,
|
Message child = new TestMessage(childId, null, group, null, contentType,
|
||||||
timestamp, raw);
|
subject, timestamp, raw);
|
||||||
db.addGroupMessage(txn, child);
|
db.addGroupMessage(txn, child);
|
||||||
assertTrue(db.containsMessage(txn, childId));
|
assertTrue(db.containsMessage(txn, childId));
|
||||||
assertNull(db.getGroupMessageParent(txn, childId));
|
assertNull(db.getGroupMessageParent(txn, childId));
|
||||||
@@ -1152,7 +1153,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
MessageId childId = new MessageId(TestUtils.getRandomId());
|
MessageId childId = new MessageId(TestUtils.getRandomId());
|
||||||
MessageId parentId = new MessageId(TestUtils.getRandomId());
|
MessageId parentId = new MessageId(TestUtils.getRandomId());
|
||||||
Message child = new TestMessage(childId, parentId, group, null,
|
Message child = new TestMessage(childId, parentId, group, null,
|
||||||
subject, timestamp, raw);
|
contentType, subject, timestamp, raw);
|
||||||
db.addGroupMessage(txn, child);
|
db.addGroupMessage(txn, child);
|
||||||
assertTrue(db.containsMessage(txn, childId));
|
assertTrue(db.containsMessage(txn, childId));
|
||||||
assertFalse(db.containsMessage(txn, parentId));
|
assertFalse(db.containsMessage(txn, parentId));
|
||||||
@@ -1178,9 +1179,9 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
MessageId childId = new MessageId(TestUtils.getRandomId());
|
MessageId childId = new MessageId(TestUtils.getRandomId());
|
||||||
MessageId parentId = new MessageId(TestUtils.getRandomId());
|
MessageId parentId = new MessageId(TestUtils.getRandomId());
|
||||||
Message child = new TestMessage(childId, parentId, group, null,
|
Message child = new TestMessage(childId, parentId, group, null,
|
||||||
subject, timestamp, raw);
|
contentType, subject, timestamp, raw);
|
||||||
Message parent = new TestMessage(parentId, null, group1, null,
|
Message parent = new TestMessage(parentId, null, group1, null,
|
||||||
subject, timestamp, raw);
|
contentType, subject, timestamp, raw);
|
||||||
db.addGroupMessage(txn, child);
|
db.addGroupMessage(txn, child);
|
||||||
db.addGroupMessage(txn, parent);
|
db.addGroupMessage(txn, parent);
|
||||||
assertTrue(db.containsMessage(txn, childId));
|
assertTrue(db.containsMessage(txn, childId));
|
||||||
@@ -1203,7 +1204,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
// A message with a private parent should return null
|
// A message with a private parent should return null
|
||||||
MessageId childId = new MessageId(TestUtils.getRandomId());
|
MessageId childId = new MessageId(TestUtils.getRandomId());
|
||||||
Message child = new TestMessage(childId, messageId1, group, null,
|
Message child = new TestMessage(childId, messageId1, group, null,
|
||||||
subject, timestamp, raw);
|
contentType, subject, timestamp, raw);
|
||||||
db.addGroupMessage(txn, child);
|
db.addGroupMessage(txn, child);
|
||||||
db.addPrivateMessage(txn, privateMessage, contactId);
|
db.addPrivateMessage(txn, privateMessage, contactId);
|
||||||
assertTrue(db.containsMessage(txn, childId));
|
assertTrue(db.containsMessage(txn, childId));
|
||||||
@@ -1227,9 +1228,9 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
MessageId childId = new MessageId(TestUtils.getRandomId());
|
MessageId childId = new MessageId(TestUtils.getRandomId());
|
||||||
MessageId parentId = new MessageId(TestUtils.getRandomId());
|
MessageId parentId = new MessageId(TestUtils.getRandomId());
|
||||||
Message child = new TestMessage(childId, parentId, group, null,
|
Message child = new TestMessage(childId, parentId, group, null,
|
||||||
subject, timestamp, raw);
|
contentType, subject, timestamp, raw);
|
||||||
Message parent = new TestMessage(parentId, null, group, null, subject,
|
Message parent = new TestMessage(parentId, null, group, null,
|
||||||
timestamp, raw);
|
contentType, subject, timestamp, raw);
|
||||||
db.addGroupMessage(txn, child);
|
db.addGroupMessage(txn, child);
|
||||||
db.addGroupMessage(txn, parent);
|
db.addGroupMessage(txn, parent);
|
||||||
assertTrue(db.containsMessage(txn, childId));
|
assertTrue(db.containsMessage(txn, childId));
|
||||||
@@ -1252,9 +1253,9 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
// Store a couple of messages
|
// Store a couple of messages
|
||||||
int bodyLength = raw.length - 20;
|
int bodyLength = raw.length - 20;
|
||||||
Message message1 = new TestMessage(messageId, null, group, null,
|
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,
|
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.addGroupMessage(txn, message1);
|
||||||
db.addPrivateMessage(txn, privateMessage1, contactId);
|
db.addPrivateMessage(txn, privateMessage1, contactId);
|
||||||
|
|
||||||
@@ -1294,7 +1295,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
MessageId parentId = new MessageId(TestUtils.getRandomId());
|
MessageId parentId = new MessageId(TestUtils.getRandomId());
|
||||||
long timestamp1 = System.currentTimeMillis();
|
long timestamp1 = System.currentTimeMillis();
|
||||||
Message message1 = new TestMessage(messageId1, parentId, group, author,
|
Message message1 = new TestMessage(messageId1, parentId, group, author,
|
||||||
subject, timestamp1, raw);
|
contentType, subject, timestamp1, raw);
|
||||||
db.addGroupMessage(txn, message1);
|
db.addGroupMessage(txn, message1);
|
||||||
// Mark one of the messages read
|
// Mark one of the messages read
|
||||||
assertFalse(db.setReadFlag(txn, messageId, true));
|
assertFalse(db.setReadFlag(txn, messageId, true));
|
||||||
@@ -1352,6 +1353,7 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
assertEquals(m.getGroup().getId(), h.getGroupId());
|
assertEquals(m.getGroup().getId(), h.getGroupId());
|
||||||
if(m.getAuthor() == null) assertNull(h.getAuthor());
|
if(m.getAuthor() == null) assertNull(h.getAuthor());
|
||||||
else assertEquals(m.getAuthor(), h.getAuthor());
|
else assertEquals(m.getAuthor(), h.getAuthor());
|
||||||
|
assertEquals(m.getContentType(), h.getContentType());
|
||||||
assertEquals(m.getSubject(), h.getSubject());
|
assertEquals(m.getSubject(), h.getSubject());
|
||||||
assertEquals(m.getTimestamp(), h.getTimestamp());
|
assertEquals(m.getTimestamp(), h.getTimestamp());
|
||||||
}
|
}
|
||||||
@@ -1423,13 +1425,13 @@ public class H2DatabaseTest extends BriarTestCase {
|
|||||||
db.addGroupMessage(txn, message);
|
db.addGroupMessage(txn, message);
|
||||||
MessageId messageId1 = new MessageId(TestUtils.getRandomId());
|
MessageId messageId1 = new MessageId(TestUtils.getRandomId());
|
||||||
Message message1 = new TestMessage(messageId1, null, group, author,
|
Message message1 = new TestMessage(messageId1, null, group, author,
|
||||||
subject, timestamp, raw);
|
contentType, subject, timestamp, raw);
|
||||||
db.addGroupMessage(txn, message1);
|
db.addGroupMessage(txn, message1);
|
||||||
|
|
||||||
// Store one message in the second group
|
// Store one message in the second group
|
||||||
MessageId messageId2 = new MessageId(TestUtils.getRandomId());
|
MessageId messageId2 = new MessageId(TestUtils.getRandomId());
|
||||||
Message message2 = new TestMessage(messageId2, null, group1, author,
|
Message message2 = new TestMessage(messageId2, null, group1, author,
|
||||||
subject, timestamp, raw);
|
contentType, subject, timestamp, raw);
|
||||||
db.addGroupMessage(txn, message2);
|
db.addGroupMessage(txn, message2);
|
||||||
|
|
||||||
// Mark one of the messages in the first group read
|
// Mark one of the messages in the first group read
|
||||||
|
|||||||
@@ -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_PROPERTY_LENGTH;
|
||||||
import static net.sf.briar.api.messaging.MessagingConstants.MAX_PUBLIC_KEY_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_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 static net.sf.briar.api.messaging.MessagingConstants.MAX_SUBSCRIPTIONS;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
@@ -123,15 +123,16 @@ public class ConstantsTest extends BriarTestCase {
|
|||||||
crypto.generateSignatureKeyPair().getPrivate();
|
crypto.generateSignatureKeyPair().getPrivate();
|
||||||
PrivateKey authorPrivate =
|
PrivateKey authorPrivate =
|
||||||
crypto.generateSignatureKeyPair().getPrivate();
|
crypto.generateSignatureKeyPair().getPrivate();
|
||||||
String subject = createRandomString(MAX_SUBJECT_LENGTH);
|
String contentType = createRandomString(MAX_CONTENT_TYPE_LENGTH);
|
||||||
byte[] body = new byte[MAX_BODY_LENGTH];
|
byte[] body = new byte[MAX_BODY_LENGTH];
|
||||||
Message message = messageFactory.createPseudonymousMessage(parent,
|
Message message = messageFactory.createPseudonymousMessage(parent,
|
||||||
group, groupPrivate, author, authorPrivate, subject, body);
|
group, groupPrivate, author, authorPrivate, contentType, body);
|
||||||
// Check the size of the serialised message
|
// Check the size of the serialised message
|
||||||
int length = message.getSerialised().length;
|
int length = message.getSerialised().length;
|
||||||
assertTrue(length > UniqueId.LENGTH + MAX_GROUP_NAME_LENGTH
|
assertTrue(length > UniqueId.LENGTH + MAX_GROUP_NAME_LENGTH
|
||||||
+ MAX_PUBLIC_KEY_LENGTH + MAX_AUTHOR_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);
|
assertTrue(length <= MAX_PACKET_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -112,10 +112,10 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase {
|
|||||||
db.addEndpoint(ep);
|
db.addEndpoint(ep);
|
||||||
km.endpointAdded(ep, initialSecret.clone());
|
km.endpointAdded(ep, initialSecret.clone());
|
||||||
// Send Bob a message
|
// Send Bob a message
|
||||||
String subject = "Hello";
|
String contentType = "text/plain";
|
||||||
byte[] body = "Hi Bob!".getBytes("UTF-8");
|
byte[] body = "Hi Bob!".getBytes("UTF-8");
|
||||||
MessageFactory messageFactory = alice.getInstance(MessageFactory.class);
|
MessageFactory messageFactory = alice.getInstance(MessageFactory.class);
|
||||||
Message message = messageFactory.createPrivateMessage(null, subject,
|
Message message = messageFactory.createPrivateMessage(null, contentType,
|
||||||
body);
|
body);
|
||||||
db.addLocalPrivateMessage(message, contactId);
|
db.addLocalPrivateMessage(message, contactId);
|
||||||
// Create an outgoing simplex connection
|
// Create an outgoing simplex connection
|
||||||
|
|||||||
Reference in New Issue
Block a user