diff --git a/src/org/thoughtcrime/securesms/PassphraseCreateActivity.java b/src/org/thoughtcrime/securesms/PassphraseCreateActivity.java index 981ee0a93f..379f589589 100644 --- a/src/org/thoughtcrime/securesms/PassphraseCreateActivity.java +++ b/src/org/thoughtcrime/securesms/PassphraseCreateActivity.java @@ -36,14 +36,15 @@ import org.thoughtcrime.securesms.util.MemoryCleaner; * * @author Moxie Marlinspike */ + public class PassphraseCreateActivity extends PassphraseActivity { - private EditText passphraseEdit; - private EditText passphraseRepeatEdit; - private Button okButton; - private Button cancelButton; + private EditText passphraseEdit; + private EditText passphraseRepeatEdit; + private Button okButton; + private Button cancelButton; - public PassphraseCreateActivity() { } + public PassphraseCreateActivity() { } @Override public void onCreate(Bundle savedInstanceState) { diff --git a/src/org/thoughtcrime/securesms/ReviewIdentitiesActivity.java b/src/org/thoughtcrime/securesms/ReviewIdentitiesActivity.java index 43ed03ffd8..3df1c65fd7 100644 --- a/src/org/thoughtcrime/securesms/ReviewIdentitiesActivity.java +++ b/src/org/thoughtcrime/securesms/ReviewIdentitiesActivity.java @@ -177,11 +177,11 @@ public class ReviewIdentitiesActivity extends SherlockListActivity { boolean valid; String identityKeyString = cursor.getString(cursor.getColumnIndexOrThrow(IdentityDatabase.IDENTITY_KEY)); - String identityName = cursor.getString(cursor.getColumnIndexOrThrow(IdentityDatabase.IDENTITY_NAME)); + String identityName = cursor.getString(cursor.getColumnIndexOrThrow(IdentityDatabase.IDENTITY_NAME)); try { String mac = cursor.getString(cursor.getColumnIndexOrThrow(IdentityDatabase.MAC)); - valid = masterCipher.verifyMacFor(identityName + identityKeyString, Base64.decode(mac)); + valid = masterCipher.verifyMacFor(identityName + identityKeyString, Base64.decode(mac)); identityKey = new IdentityKey(Base64.decode(identityKeyString), 0); } catch (InvalidKeyException ike) { Log.w("ReviewIdentitiesActivity",ike); diff --git a/src/org/thoughtcrime/securesms/database/CanonicalAddressDatabase.java b/src/org/thoughtcrime/securesms/database/CanonicalAddressDatabase.java index 8293079287..623b85c80d 100644 --- a/src/org/thoughtcrime/securesms/database/CanonicalAddressDatabase.java +++ b/src/org/thoughtcrime/securesms/database/CanonicalAddressDatabase.java @@ -86,7 +86,7 @@ public class CanonicalAddressDatabase { } } finally { if (cursor != null) - cursor.close(); + cursor.close(); } } @@ -154,12 +154,12 @@ public class CanonicalAddressDatabase { } @Override - public void onCreate(SQLiteDatabase db) { + public void onCreate(SQLiteDatabase db) { db.execSQL(DATABASE_CREATE); } @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } } diff --git a/src/org/thoughtcrime/securesms/database/ContentValuesBuilder.java b/src/org/thoughtcrime/securesms/database/ContentValuesBuilder.java index 04f17cd96c..3d4ba41f14 100644 --- a/src/org/thoughtcrime/securesms/database/ContentValuesBuilder.java +++ b/src/org/thoughtcrime/securesms/database/ContentValuesBuilder.java @@ -1,6 +1,6 @@ -/** +/** * Copyright (C) 2011 Whisper Systems - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -10,40 +10,41 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package org.thoughtcrime.securesms.database; -import java.io.UnsupportedEncodingException; +import android.content.ContentValues; +import android.util.Log; import ws.com.google.android.mms.pdu.CharacterSets; import ws.com.google.android.mms.pdu.EncodedStringValue; -import android.content.ContentValues; -import android.util.Log; + +import java.io.UnsupportedEncodingException; public class ContentValuesBuilder { private final ContentValues contentValues; - + public ContentValuesBuilder(ContentValues contentValues) { this.contentValues = contentValues; } - + public void add(String key, String charsetKey, EncodedStringValue value) { if (value != null) { contentValues.put(key, toIsoString(value.getTextString())); contentValues.put(charsetKey, value.getCharacterSet()); } } - + public void add(String contentKey, byte[] value) { if (value != null) { contentValues.put(contentKey, toIsoString(value)); } } - + public void add(String contentKey, int b) { if (b != 0) contentValues.put(contentKey, b); @@ -53,11 +54,11 @@ public class ContentValuesBuilder { if (value != -1L) contentValues.put(contentKey, value); } - + public ContentValues getContentValues() { return contentValues; } - + private String toIsoString(byte[] bytes) { try { return new String(bytes, CharacterSets.MIMENAME_ISO_8859_1); diff --git a/src/org/thoughtcrime/securesms/database/Database.java b/src/org/thoughtcrime/securesms/database/Database.java index 10f07d4262..463b901d21 100644 --- a/src/org/thoughtcrime/securesms/database/Database.java +++ b/src/org/thoughtcrime/securesms/database/Database.java @@ -1,6 +1,6 @@ -/** +/** * Copyright (C) 2011 Whisper Systems - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -10,50 +10,50 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package org.thoughtcrime.securesms.database; -import java.util.Set; - import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteOpenHelper; import android.net.Uri; +import java.util.Set; + public abstract class Database { protected static final String ID_WHERE = "_id = ?"; private static final String CONVERSATION_URI = "content://textsecure/thread/"; private static final String CONVERSATION_LIST_URI = "content://textsecure/conversation-list"; - + protected final SQLiteOpenHelper databaseHelper; protected final Context context; - + public Database(Context context, SQLiteOpenHelper databaseHelper) { this.context = context; this.databaseHelper = databaseHelper; } - + protected void notifyConversationListeners(Set threadIds) { for (long threadId : threadIds) notifyConversationListeners(threadId); } - + protected void notifyConversationListeners(long threadId) { context.getContentResolver().notifyChange(Uri.parse(CONVERSATION_URI + threadId), null); } - + protected void notifyConversationListListeners() { context.getContentResolver().notifyChange(Uri.parse(CONVERSATION_LIST_URI), null); } - + protected void setNotifyConverationListeners(Cursor cursor, long threadId) { cursor.setNotificationUri(context.getContentResolver(), Uri.parse(CONVERSATION_URI + threadId)); } - + protected void setNotifyConverationListListeners(Cursor cursor) { cursor.setNotificationUri(context.getContentResolver(), Uri.parse(CONVERSATION_LIST_URI)); } diff --git a/src/org/thoughtcrime/securesms/database/DatabaseFactory.java b/src/org/thoughtcrime/securesms/database/DatabaseFactory.java index 007f4a1d4f..80ba841fd2 100644 --- a/src/org/thoughtcrime/securesms/database/DatabaseFactory.java +++ b/src/org/thoughtcrime/securesms/database/DatabaseFactory.java @@ -1,6 +1,6 @@ -/** +/** * Copyright (C) 2011 Whisper Systems - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -10,30 +10,31 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package org.thoughtcrime.securesms.database; -import org.thoughtcrime.securesms.crypto.MasterSecret; - import android.content.Context; import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteDatabase.CursorFactory; +import android.database.sqlite.SQLiteOpenHelper; + +import org.thoughtcrime.securesms.crypto.MasterSecret; public class DatabaseFactory { - - private static final int INTRODUCED_IDENTITIES_VERSION = 2; - private static final int DATABASE_VERSION = 2; + + private static final int INTRODUCED_IDENTITIES_VERSION = 2; + private static final int DATABASE_VERSION = 2; + private static final String DATABASE_NAME = "messages.db"; private static final Object lock = new Object(); - + private static DatabaseFactory instance; private static EncryptingMmsDatabase encryptingMmsInstance; private static EncryptingPartDatabase encryptingPartInstance; - + private final DatabaseHelper databaseHelper; private final SmsDatabase sms; @@ -45,70 +46,70 @@ public class DatabaseFactory { private final MmsAddressDatabase mmsAddress; private final MmsSmsDatabase mmsSmsDatabase; private final IdentityDatabase identityDatabase; - + public static DatabaseFactory getInstance(Context context) { synchronized (lock) { if (instance == null) instance = new DatabaseFactory(context); - + return instance; } } - + public static MmsSmsDatabase getMmsSmsDatabase(Context context) { return getInstance(context).mmsSmsDatabase; } - + public static ThreadDatabase getThreadDatabase(Context context) { return getInstance(context).thread; } - + public static SmsDatabase getSmsDatabase(Context context) { return getInstance(context).sms; } - + public static MmsDatabase getMmsDatabase(Context context) { return getInstance(context).mms; } - + public static CanonicalAddressDatabase getAddressDatabase(Context context) { return getInstance(context).address; } - + public static EncryptingSmsDatabase getEncryptingSmsDatabase(Context context) { return getInstance(context).encryptingSms; } - + public static EncryptingMmsDatabase getEncryptingMmsDatabase(Context context, MasterSecret masterSecret) { synchronized (lock) { if (encryptingMmsInstance == null) { DatabaseFactory factory = getInstance(context); encryptingMmsInstance = new EncryptingMmsDatabase(context, factory.databaseHelper, masterSecret); } - + return encryptingMmsInstance; } } - + public static PartDatabase getPartDatabase(Context context) { return getInstance(context).part; } - + public static EncryptingPartDatabase getEncryptingPartDatabase(Context context, MasterSecret masterSecret) { synchronized (lock) { if (encryptingPartInstance == null) { DatabaseFactory factory = getInstance(context); - encryptingPartInstance = new EncryptingPartDatabase(context, factory.databaseHelper, masterSecret); + encryptingPartInstance = new EncryptingPartDatabase(context, factory.databaseHelper, masterSecret); } - + return encryptingPartInstance; } } - + public static MmsAddressDatabase getMmsAddressDatabase(Context context) { return getInstance(context).mmsAddress; } - + public static IdentityDatabase getIdentityDatabase(Context context) { return getInstance(context).identityDatabase; } @@ -125,13 +126,13 @@ public class DatabaseFactory { this.mmsSmsDatabase = new MmsSmsDatabase(context, databaseHelper); this.identityDatabase = new IdentityDatabase(context, databaseHelper); } - + public void close() { databaseHelper.close(); address.close(); instance = null; } - + private static class DatabaseHelper extends SQLiteOpenHelper { public DatabaseHelper(Context context, String name, CursorFactory factory, int version) { @@ -146,14 +147,13 @@ public class DatabaseFactory { db.execSQL(ThreadDatabase.CREATE_TABLE); db.execSQL(MmsAddressDatabase.CREATE_TABLE); db.execSQL(IdentityDatabase.CREATE_TABLE); - // db.execSQL(CanonicalAddress.CREATE_TABLE); + // db.execSQL(CanonicalAddress.CREATE_TABLE); } @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - if (oldVersion < INTRODUCED_IDENTITIES_VERSION) - db.execSQL(IdentityDatabase.CREATE_TABLE); + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + if (oldVersion < INTRODUCED_IDENTITIES_VERSION) + db.execSQL(IdentityDatabase.CREATE_TABLE); } - } } diff --git a/src/org/thoughtcrime/securesms/database/EncryptingMmsDatabase.java b/src/org/thoughtcrime/securesms/database/EncryptingMmsDatabase.java index 054bc45205..2054f8304a 100644 --- a/src/org/thoughtcrime/securesms/database/EncryptingMmsDatabase.java +++ b/src/org/thoughtcrime/securesms/database/EncryptingMmsDatabase.java @@ -1,6 +1,6 @@ -/** +/** * Copyright (C) 2011 Whisper Systems - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -10,28 +10,28 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package org.thoughtcrime.securesms.database; -import org.thoughtcrime.securesms.crypto.MasterSecret; - import android.content.Context; import android.database.sqlite.SQLiteOpenHelper; +import org.thoughtcrime.securesms.crypto.MasterSecret; + public class EncryptingMmsDatabase extends MmsDatabase { private final MasterSecret masterSecret; - + public EncryptingMmsDatabase(Context context, SQLiteOpenHelper databaseHelper, MasterSecret masterSecret) { super(context, databaseHelper); this.masterSecret = masterSecret; } - + @Override - protected PartDatabase getPartDatabase() { + protected PartDatabase getPartDatabase() { return DatabaseFactory.getEncryptingPartDatabase(context, masterSecret); } diff --git a/src/org/thoughtcrime/securesms/database/EncryptingPartDatabase.java b/src/org/thoughtcrime/securesms/database/EncryptingPartDatabase.java index 5476c3e5b4..948d66dde6 100644 --- a/src/org/thoughtcrime/securesms/database/EncryptingPartDatabase.java +++ b/src/org/thoughtcrime/securesms/database/EncryptingPartDatabase.java @@ -1,6 +1,6 @@ -/** +/** * Copyright (C) 2011 Whisper Systems - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -10,30 +10,31 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package org.thoughtcrime.securesms.database; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; +import android.content.Context; +import android.database.sqlite.SQLiteOpenHelper; +import android.util.Log; import org.thoughtcrime.securesms.crypto.DecryptingPartInputStream; import org.thoughtcrime.securesms.crypto.EncryptingPartOutputStream; import org.thoughtcrime.securesms.crypto.MasterSecret; import ws.com.google.android.mms.pdu.PduPart; -import android.content.Context; -import android.database.sqlite.SQLiteOpenHelper; -import android.util.Log; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; public class EncryptingPartDatabase extends PartDatabase { private final MasterSecret masterSecret; - + public EncryptingPartDatabase(Context context, SQLiteOpenHelper databaseHelper, MasterSecret masterSecret) { super(context, databaseHelper); this.masterSecret = masterSecret; @@ -44,14 +45,14 @@ public class EncryptingPartDatabase extends PartDatabase { Log.w("EncryptingPartDatabase", "Getting part at: " + path.getAbsolutePath()); if (!part.getEncrypted()) return super.getPartInputStream(path, part); - + return new DecryptingPartInputStream(path, masterSecret); } - + @Override protected FileOutputStream getPartOutputStream(File path, PduPart part) throws FileNotFoundException { Log.w("EncryptingPartDatabase", "Writing part to: " + path.getAbsolutePath()); part.setEncrypted(true); return new EncryptingPartOutputStream(path, masterSecret); - } + } } diff --git a/src/org/thoughtcrime/securesms/database/EncryptingSmsDatabase.java b/src/org/thoughtcrime/securesms/database/EncryptingSmsDatabase.java index ea0d7f1495..a5a1396370 100644 --- a/src/org/thoughtcrime/securesms/database/EncryptingSmsDatabase.java +++ b/src/org/thoughtcrime/securesms/database/EncryptingSmsDatabase.java @@ -1,6 +1,6 @@ -/** +/** * Copyright (C) 2011 Whisper Systems - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -10,66 +10,66 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package org.thoughtcrime.securesms.database; +import android.content.Context; +import android.database.sqlite.SQLiteOpenHelper; +import android.telephony.SmsMessage; + import org.thoughtcrime.securesms.crypto.AsymmetricMasterCipher; import org.thoughtcrime.securesms.crypto.AsymmetricMasterSecret; import org.thoughtcrime.securesms.crypto.MasterCipher; import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.protocol.Prefix; -import android.content.Context; -import android.database.sqlite.SQLiteOpenHelper; -import android.telephony.SmsMessage; - public class EncryptingSmsDatabase extends SmsDatabase { public EncryptingSmsDatabase(Context context, SQLiteOpenHelper databaseHelper) { super(context, databaseHelper); - } + } private String getAsymmetricEncryptedBody(AsymmetricMasterSecret masterSecret, String body) { AsymmetricMasterCipher bodyCipher = new AsymmetricMasterCipher(masterSecret); return Prefix.ASYMMETRIC_LOCAL_ENCRYPT + bodyCipher.encryptBody(body); } - + private String getEncryptedBody(MasterSecret masterSecret, String body) { MasterCipher bodyCipher = new MasterCipher(masterSecret); - return Prefix.SYMMETRIC_ENCRYPT + bodyCipher.encryptBody(body); + return Prefix.SYMMETRIC_ENCRYPT + bodyCipher.encryptBody(body); } private long insertMessageSent(MasterSecret masterSecret, String address, long threadId, String body, long date, int type) { String encryptedBody = getEncryptedBody(masterSecret, body); - return insertMessageSent(address, threadId, encryptedBody, date, type); + return insertMessageSent(address, threadId, encryptedBody, date, type); } public void updateSecureMessageBody(MasterSecret masterSecret, long messageId, String body) { String encryptedBody = getEncryptedBody(masterSecret, body); updateMessageBodyAndType(messageId, encryptedBody, Types.SECURE_RECEIVED_TYPE); } - + public void updateMessageBody(MasterSecret masterSecret, long messageId, String body) { String encryptedBody = getEncryptedBody(masterSecret, body); updateMessageBodyAndType(messageId, encryptedBody, Types.INBOX_TYPE); } - + public long insertMessageSent(MasterSecret masterSecret, String address, long threadId, String body, long date) { return insertMessageSent(masterSecret, address, threadId, body, date, Types.ENCRYPTED_OUTBOX_TYPE); } - + public long insertSecureMessageSent(MasterSecret masterSecret, String address, long threadId, String body, long date) { return insertMessageSent(masterSecret, address, threadId, body, date, Types.ENCRYPTING_TYPE); } - + public long insertMessageReceived(MasterSecret masterSecret, SmsMessage message, String body) { String encryptedBody = getEncryptedBody(masterSecret, body); return insertMessageReceived(message, encryptedBody); } - + public long insertMessageReceived(AsymmetricMasterSecret masterSecret, SmsMessage message, String body) { String encryptedBody = getAsymmetricEncryptedBody(masterSecret, body); return insertSecureMessageReceived(message, encryptedBody); diff --git a/src/org/thoughtcrime/securesms/database/MessageRecord.java b/src/org/thoughtcrime/securesms/database/MessageRecord.java index 3532482691..a73488f8ed 100644 --- a/src/org/thoughtcrime/securesms/database/MessageRecord.java +++ b/src/org/thoughtcrime/securesms/database/MessageRecord.java @@ -1,6 +1,6 @@ -/** +/** * Copyright (C) 2011 Whisper Systems - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -10,7 +10,7 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ @@ -21,7 +21,7 @@ import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.recipients.Recipients; public class MessageRecord { - + private long id; private long threadId; private Recipient messageRecipient; @@ -35,7 +35,7 @@ public class MessageRecord { private boolean keyExchange; private boolean processedKeyExchange; private boolean staleKeyExchange; - + public MessageRecord(MessageRecord copy) { this.id = copy.id; this.threadId = copy.threadId; @@ -50,7 +50,7 @@ public class MessageRecord { this.keyExchange = copy.keyExchange; this.processedKeyExchange = copy.processedKeyExchange; } - + public MessageRecord(long id, Recipients recipients, long date, long type, long threadId) { this.id = id; this.date = date; @@ -58,7 +58,7 @@ public class MessageRecord { this.recipients = recipients; this.threadId = threadId; } - + public MessageRecord(long id, Recipients recipients, long date, long count, boolean read, long threadId) { this.id = id; this.threadId = threadId; @@ -67,115 +67,115 @@ public class MessageRecord { this.count = count; this.read = read; } - + public void setOnConversationItem(ConversationItem item) { item.setMessageRecord(this); } - + public boolean isMms() { return false; } - + public long getType() { return type; } - + public void setMessageRecipient(Recipient recipient) { this.messageRecipient = recipient; } - + public Recipient getMessageRecipient() { return this.messageRecipient; } - + public void setEmphasis(boolean emphasis) { this.emphasis = emphasis; } - + public boolean getEmphasis() { return this.emphasis; } - + public void setId(long id) { this.id = id; } - + public void setBody(String body) { this.body = body; } - + public long getThreadId() { return threadId; } - + public long getId() { return id; } - + public Recipients getRecipients() { return recipients; } - + public String getBody() { return body; } - + public long getDate() { return date; } - + public long getCount() { return count; } - + public boolean getRead() { return read; } - + public boolean isStaleKeyExchange() { return this.staleKeyExchange; } - + public void setStaleKeyExchange(boolean staleKeyExchange) { this.staleKeyExchange = staleKeyExchange; } - + public boolean isProcessedKeyExchange() { return processedKeyExchange; } - + public void setProcessedKeyExchange(boolean processedKeyExchange) { this.processedKeyExchange = processedKeyExchange; } - + public boolean isKeyExchange() { return keyExchange || processedKeyExchange || staleKeyExchange; } - + public void setKeyExchange(boolean keyExchange) { this.keyExchange = keyExchange; } - + public boolean isFailedDecryptType() { return type == SmsDatabase.Types.FAILED_DECRYPT_TYPE; } - + public boolean isFailed() { return SmsDatabase.Types.isFailedMessageType(type); } - + public boolean isOutgoing() { return SmsDatabase.Types.isOutgoingMessageType(type); } - + public boolean isPending() { return SmsDatabase.Types.isPendingMessageType(type); } - + public boolean isSecure() { return SmsDatabase.Types.isSecureType(type); } - - + + } diff --git a/src/org/thoughtcrime/securesms/database/MmsAddressDatabase.java b/src/org/thoughtcrime/securesms/database/MmsAddressDatabase.java index f6c2a22e62..cf3fdef44d 100644 --- a/src/org/thoughtcrime/securesms/database/MmsAddressDatabase.java +++ b/src/org/thoughtcrime/securesms/database/MmsAddressDatabase.java @@ -1,6 +1,6 @@ -/** +/** * Copyright (C) 2011 Whisper Systems - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -10,17 +10,12 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package org.thoughtcrime.securesms.database; -import java.io.UnsupportedEncodingException; - -import ws.com.google.android.mms.pdu.CharacterSets; -import ws.com.google.android.mms.pdu.EncodedStringValue; -import ws.com.google.android.mms.pdu.PduHeaders; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; @@ -28,17 +23,23 @@ import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.util.Log; +import ws.com.google.android.mms.pdu.CharacterSets; +import ws.com.google.android.mms.pdu.EncodedStringValue; +import ws.com.google.android.mms.pdu.PduHeaders; + +import java.io.UnsupportedEncodingException; + public class MmsAddressDatabase extends Database { - - private static final String TABLE_NAME = "mms_addresses"; + + private static final String TABLE_NAME = "mms_addresses"; private static final String ID = "_id"; private static final String MMS_ID = "mms_id"; private static final String TYPE = "type"; - private static final String ADDRESS = "address"; + private static final String ADDRESS = "address"; private static final String ADDRESS_CHARSET = "address_charset"; - - public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ID + " INTEGER PRIMARY KEY, " + - MMS_ID + " INTEGER, " + TYPE + " INTEGER, " + ADDRESS + " TEXT, " + + + public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ID + " INTEGER PRIMARY KEY, " + + MMS_ID + " INTEGER, " + TYPE + " INTEGER, " + ADDRESS + " TEXT, " + ADDRESS_CHARSET + " INTEGER);"; public MmsAddressDatabase(Context context, SQLiteOpenHelper databaseHelper) { @@ -56,7 +57,7 @@ public class MmsAddressDatabase extends Database { database.insert(TABLE_NAME, null, contentValues); } } - + private void insertAddress(long messageId, int type, EncodedStringValue[] addresses) { if (addresses != null) { for (int i=0;i. */ package org.thoughtcrime.securesms.database; -import java.util.HashSet; -import java.util.Set; - import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; @@ -26,54 +23,57 @@ import android.database.sqlite.SQLiteOpenHelper; import android.database.sqlite.SQLiteQueryBuilder; import android.util.Log; +import java.util.HashSet; +import java.util.Set; + public class MmsSmsDatabase extends Database { - + public static final String TRANSPORT = "transport_type"; public MmsSmsDatabase(Context context, SQLiteOpenHelper databaseHelper) { super(context, databaseHelper); } - + public Cursor getConversation(long threadId) { String[] projection = {"_id", "body", "type", "address", "subject", "normalized_date AS date", "m_type", "msg_box", "transport_type"}; String order = "normalized_date ASC"; String selection = "thread_id = " + threadId; - + Cursor cursor = queryTables(projection, selection, order, null); setNotifyConverationListeners(cursor, threadId); return cursor; } - + public Cursor getConversationSnippet(long threadId) { String[] projection = {"_id", "body", "type", "address", "subject", "normalized_date AS date", "m_type", "msg_box", "transport_type"}; String order = "normalized_date DESC"; String selection = "thread_id = " + threadId; - + Cursor cursor = queryTables(projection, selection, order, "1"); return cursor; } - + public Cursor getUnread() { String[] projection = {"_id", "body", "read", "type", "address", "subject", "thread_id", "normalized_date AS date", "m_type", "msg_box", "transport_type"}; String order = "normalized_date ASC"; String selection = "read = 0"; - + Cursor cursor = queryTables(projection, selection, order, null); - return cursor; + return cursor; } - + public int getConversationCount(long threadId) { int count = DatabaseFactory.getSmsDatabase(context).getMessageCountForThread(threadId); count += DatabaseFactory.getMmsDatabase(context).getMessageCountForThread(threadId); - + return count; } private Cursor queryTables(String[] projection, String selection, String order, String limit) { String[] mmsProjection = {"date * 1000 AS normalized_date", "_id", "body", "read", "thread_id", "type", "address", "subject", "date", "m_type", "msg_box", "transport_type"}; String[] smsProjection = {"date * 1 AS normalized_date", "_id", "body", "read", "thread_id", "type", "address", "subject", "date", "m_type", "msg_box", "transport_type"}; - + SQLiteQueryBuilder mmsQueryBuilder = new SQLiteQueryBuilder(); SQLiteQueryBuilder smsQueryBuilder = new SQLiteQueryBuilder(); @@ -82,7 +82,7 @@ public class MmsSmsDatabase extends Database { mmsQueryBuilder.setTables(MmsDatabase.TABLE_NAME); smsQueryBuilder.setTables(SmsDatabase.TABLE_NAME); - + Set mmsColumnsPresent = new HashSet(); mmsColumnsPresent.add("_id"); mmsColumnsPresent.add("m_type"); @@ -90,7 +90,7 @@ public class MmsSmsDatabase extends Database { mmsColumnsPresent.add("date"); mmsColumnsPresent.add("read"); mmsColumnsPresent.add("thread_id"); - + Set smsColumnsPresent = new HashSet(); smsColumnsPresent.add("_id"); smsColumnsPresent.add("body"); @@ -104,19 +104,19 @@ public class MmsSmsDatabase extends Database { String mmsSubQuery = mmsQueryBuilder.buildUnionSubQuery("transport_type", mmsProjection, mmsColumnsPresent, 0, "mms", selection, null, null, null); String smsSubQuery = smsQueryBuilder.buildUnionSubQuery("transport_type", smsProjection, smsColumnsPresent, 0, "sms", selection, null, null, null); - SQLiteQueryBuilder unionQueryBuilder = new SQLiteQueryBuilder(); + SQLiteQueryBuilder unionQueryBuilder = new SQLiteQueryBuilder(); String unionQuery = unionQueryBuilder.buildUnionQuery(new String[] {smsSubQuery, mmsSubQuery}, order, null); SQLiteQueryBuilder outerQueryBuilder = new SQLiteQueryBuilder(); outerQueryBuilder.setTables("(" + unionQuery + ")"); - - String query = outerQueryBuilder.buildQuery(projection, null, null, null, null, null, limit); - + + String query = outerQueryBuilder.buildQuery(projection, null, null, null, null, null, limit); + Log.w("MmsSmsDatabase", "Executing query: " + query); SQLiteDatabase db = databaseHelper.getReadableDatabase(); Cursor cursor = db.rawQuery(query, null); return cursor; - + } - + } diff --git a/src/org/thoughtcrime/securesms/database/PartDatabase.java b/src/org/thoughtcrime/securesms/database/PartDatabase.java index 6c0bd630ea..0ccb434ad5 100644 --- a/src/org/thoughtcrime/securesms/database/PartDatabase.java +++ b/src/org/thoughtcrime/securesms/database/PartDatabase.java @@ -1,6 +1,6 @@ -/** +/** * Copyright (C) 2011 Whisper Systems - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -10,12 +10,28 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package org.thoughtcrime.securesms.database; +import android.content.ContentUris; +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.util.Log; + +import org.thoughtcrime.securesms.providers.PartProvider; + +import ws.com.google.android.mms.ContentType; +import ws.com.google.android.mms.MmsException; +import ws.com.google.android.mms.pdu.CharacterSets; +import ws.com.google.android.mms.pdu.PduBody; +import ws.com.google.android.mms.pdu.PduPart; + import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; @@ -25,21 +41,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; -import org.thoughtcrime.securesms.providers.PartProvider; - -import ws.com.google.android.mms.ContentType; -import ws.com.google.android.mms.MmsException; -import ws.com.google.android.mms.pdu.CharacterSets; -import ws.com.google.android.mms.pdu.PduBody; -import ws.com.google.android.mms.pdu.PduPart; -import android.content.ContentUris; -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteOpenHelper; -import android.util.Log; - public class PartDatabase extends Database { private static final String TABLE_NAME = "part"; @@ -61,77 +62,77 @@ public class PartDatabase extends Database { public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ID + " INTEGER PRIMARY KEY, " + MMS_ID + " INTEGER, " + SEQUENCE + " INTEGER DEFAULT 0, " + CONTENT_TYPE + " TEXT, " + NAME + " TEXT, " + CHARSET + " INTEGER, " + - CONTENT_DISPOSITION + " TEXT, " + FILENAME + " TEXT, " + CONTENT_ID + " TEXT, " + - CONTENT_LOCATION + " TEXT, " + CONTENT_TYPE_START + " INTEGER, " + + CONTENT_DISPOSITION + " TEXT, " + FILENAME + " TEXT, " + CONTENT_ID + " TEXT, " + + CONTENT_LOCATION + " TEXT, " + CONTENT_TYPE_START + " INTEGER, " + CONTENT_TYPE_TYPE + " TEXT, " + ENCRYPTED + " INTEGER, " + DATA + " TEXT);"; - + public PartDatabase(Context context, SQLiteOpenHelper databaseHelper) { super(context, databaseHelper); } - + private void getPartValues(PduPart part, Cursor cursor) { int charsetColumn = cursor.getColumnIndexOrThrow(CHARSET); - + if (!cursor.isNull(charsetColumn)) part.setCharset(cursor.getInt(charsetColumn)); - + int contentTypeColumn = cursor.getColumnIndexOrThrow(CONTENT_TYPE); - + if (!cursor.isNull(contentTypeColumn)) part.setContentType(getBytes(cursor.getString(contentTypeColumn))); - + int nameColumn = cursor.getColumnIndexOrThrow(NAME); - + if (!cursor.isNull(nameColumn)) part.setName(getBytes(cursor.getString(nameColumn))); - + int fileNameColumn = cursor.getColumnIndexOrThrow(FILENAME); - + if (!cursor.isNull(fileNameColumn)) part.setFilename(getBytes(cursor.getString(fileNameColumn))); - + int contentDispositionColumn = cursor.getColumnIndexOrThrow(CONTENT_DISPOSITION); - + if (!cursor.isNull(contentDispositionColumn)) part.setContentDisposition(getBytes(cursor.getString(contentDispositionColumn))); - + int contentIdColumn = cursor.getColumnIndexOrThrow(CONTENT_ID); - + if (!cursor.isNull(contentIdColumn)) part.setContentId(getBytes(cursor.getString(contentIdColumn))); - + int contentLocationColumn = cursor.getColumnIndexOrThrow(CONTENT_LOCATION); - + if (!cursor.isNull(contentLocationColumn)) part.setContentLocation(getBytes(cursor.getString(contentLocationColumn))); - + int encryptedColumn = cursor.getColumnIndexOrThrow(ENCRYPTED); - + if (!cursor.isNull(encryptedColumn)) part.setEncrypted(cursor.getInt(encryptedColumn) == 1); } - + private ContentValues getContentValuesForPart(PduPart part) throws MmsException { ContentValues contentValues = new ContentValues(); - + if (part.getCharset() != 0 ) { contentValues.put(CHARSET, part.getCharset()); } if (part.getContentType() != null) { contentValues.put(CONTENT_TYPE, toIsoString(part.getContentType())); - + if (toIsoString(part.getContentType()).equals(ContentType.APP_SMIL)) - contentValues.put(SEQUENCE, -1); + contentValues.put(SEQUENCE, -1); } else { throw new MmsException("There is no content type for this part."); } - + if (part.getName() != null) { contentValues.put(NAME, new String(part.getName())); } - + if (part.getFilename() != null) { contentValues.put(FILENAME, new String(part.getFilename())); } @@ -147,33 +148,33 @@ public class PartDatabase extends Database { if (part.getContentLocation() != null) { contentValues.put(CONTENT_LOCATION, toIsoString(part.getContentLocation())); } - + contentValues.put(ENCRYPTED, part.getEncrypted() ? 1 : 0); return contentValues; } - + protected FileInputStream getPartInputStream(File file, PduPart part) throws FileNotFoundException { Log.w("PartDatabase", "Reading non-encrypted part from: " + file.getAbsolutePath()); return new FileInputStream(file); } - + protected FileOutputStream getPartOutputStream(File file, PduPart part) throws FileNotFoundException { Log.w("PartDatabase", "Writing non-encrypted part to: " + file.getAbsolutePath()); return new FileOutputStream(file); } - + private void readPartData(PduPart part, String filename) { try { File dataFile = new File(filename); FileInputStream fin = getPartInputStream(dataFile, part); - ByteArrayOutputStream baos = new ByteArrayOutputStream((int)dataFile.length()); + ByteArrayOutputStream baos = new ByteArrayOutputStream((int)dataFile.length()); byte[] buffer = new byte[512]; int read; - + while ((read = fin.read(buffer)) != -1) - baos.write(buffer, 0, read); - + baos.write(buffer, 0, read); + part.setData(baos.toByteArray()); fin.close(); } catch (IOException ioe) { @@ -181,7 +182,7 @@ public class PartDatabase extends Database { part.setData(null); } } - + private File writePartData(PduPart part) throws MmsException { try { File partsDirectory = context.getDir("parts", Context.MODE_PRIVATE); @@ -189,23 +190,23 @@ public class PartDatabase extends Database { FileOutputStream fout = getPartOutputStream(dataFile, part); if (part.getData() != null) { - Log.w("PartDatabase", "Writing part data from buffer"); - fout.write(part.getData()); - fout.close(); - return dataFile; + Log.w("PartDatabase", "Writing part data from buffer"); + fout.write(part.getData()); + fout.close(); + return dataFile; } else if (part.getDataUri() != null) { - Log.w("PartDatabase", "Writing part dat from URI"); - byte[] buf = new byte[512]; - InputStream in = context.getContentResolver().openInputStream(part.getDataUri()); - int read; - while ((read = in.read(buf)) != -1) - fout.write(buf, 0, read); - - fout.close(); - in.close(); - return dataFile; + Log.w("PartDatabase", "Writing part dat from URI"); + byte[] buf = new byte[512]; + InputStream in = context.getContentResolver().openInputStream(part.getDataUri()); + int read; + while ((read = in.read(buf)) != -1) + fout.write(buf, 0, read); + + fout.close(); + in.close(); + return dataFile; } else { - throw new MmsException("Part is empty!"); + throw new MmsException("Part is empty!"); } } catch (FileNotFoundException e) { throw new AssertionError(e); @@ -213,7 +214,7 @@ public class PartDatabase extends Database { throw new AssertionError(e); } } - + private PduPart getPart(Cursor cursor, boolean includeData) { PduPart part = new PduPart(); String dataLocation = cursor.getString(cursor.getColumnIndexOrThrow(DATA)); @@ -223,119 +224,119 @@ public class PartDatabase extends Database { if (includeData) readPartData(part, dataLocation); part.setDataUri(ContentUris.withAppendedId(PartProvider.CONTENT_URI, partId)); - + return part; } - + private long insertPart(PduPart part, long mmsId) throws MmsException { SQLiteDatabase database = databaseHelper.getWritableDatabase(); File dataFile = writePartData(part); - + Log.w("PartDatabase", "Wrote part to file: " + dataFile.getAbsolutePath()); ContentValues contentValues = getContentValuesForPart(part); - + contentValues.put(MMS_ID, mmsId); contentValues.put(DATA, dataFile.getAbsolutePath()); - return database.insert(TABLE_NAME, null, contentValues); + return database.insert(TABLE_NAME, null, contentValues); } - + public InputStream getPartStream(long partId) throws FileNotFoundException { SQLiteDatabase database = databaseHelper.getReadableDatabase(); Cursor cursor = null; - + Log.w("PartDatabase", "Getting part at ID: " + partId); try { cursor = database.query(TABLE_NAME, new String[]{DATA, ENCRYPTED}, ID_WHERE, new String[] {partId+""}, null, null, null); - + if (cursor != null && cursor.moveToFirst()) { - PduPart part = new PduPart(); - part.setEncrypted(cursor.getInt(1) == 1); - - return getPartInputStream(new File(cursor.getString(0)), part); + PduPart part = new PduPart(); + part.setEncrypted(cursor.getInt(1) == 1); + + return getPartInputStream(new File(cursor.getString(0)), part); } else { - throw new FileNotFoundException("No part for id: " + partId); + throw new FileNotFoundException("No part for id: " + partId); } } finally { if (cursor != null) - cursor.close(); - } + cursor.close(); + } } - public void insertParts(long mmsId, PduBody body) throws MmsException { + public void insertParts(long mmsId, PduBody body) throws MmsException { for (int i=0;i. */ package org.thoughtcrime.securesms.database; -import java.io.UnsupportedEncodingException; +import android.database.Cursor; +import android.util.Log; import ws.com.google.android.mms.InvalidHeaderValueException; import ws.com.google.android.mms.pdu.CharacterSets; import ws.com.google.android.mms.pdu.EncodedStringValue; import ws.com.google.android.mms.pdu.PduHeaders; -import android.database.Cursor; -import android.util.Log; + +import java.io.UnsupportedEncodingException; public class PduHeadersBuilder { private final PduHeaders headers; private final Cursor cursor; - + public PduHeadersBuilder(PduHeaders headers, Cursor cursor) { this.headers = headers; this.cursor = cursor; } - + public PduHeaders getHeaders() { return headers; } - + public void addLong(String key, int headersKey) { int columnIndex = cursor.getColumnIndexOrThrow(key); - + if (!cursor.isNull(columnIndex)) headers.setLongInteger(cursor.getLong(columnIndex), headersKey); } - + public void addOctet(String key, int headersKey) throws InvalidHeaderValueException { int columnIndex = cursor.getColumnIndexOrThrow(key); - + if (!cursor.isNull(columnIndex)) headers.setOctet(cursor.getInt(columnIndex), headersKey); } - + public void addText(String key, int headersKey) { String value = cursor.getString(cursor.getColumnIndexOrThrow(key)); if (value != null && value.trim().length() > 0) @@ -60,14 +61,14 @@ public class PduHeadersBuilder { } public void add(String key, String charsetKey, int headersKey) { String value = cursor.getString(cursor.getColumnIndexOrThrow(key)); - + if (value != null && value.trim().length() > 0) { int charsetValue = cursor.getInt(cursor.getColumnIndexOrThrow(charsetKey)); EncodedStringValue encodedValue = new EncodedStringValue(charsetValue, getBytes(value)); headers.setEncodedStringValue(encodedValue, headersKey); } } - + private byte[] getBytes(String data) { try { return data.getBytes(CharacterSets.MIMENAME_ISO_8859_1); diff --git a/src/org/thoughtcrime/securesms/database/Record.java b/src/org/thoughtcrime/securesms/database/Record.java index a5d6b43ad4..5f45ecae24 100644 --- a/src/org/thoughtcrime/securesms/database/Record.java +++ b/src/org/thoughtcrime/securesms/database/Record.java @@ -1,6 +1,6 @@ -/** +/** * Copyright (C) 2011 Whisper Systems - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -10,12 +10,16 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package org.thoughtcrime.securesms.database; +import android.content.Context; + +import org.thoughtcrime.securesms.util.Conversions; + import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -24,24 +28,20 @@ import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; -import org.thoughtcrime.securesms.util.Conversions; - -import android.content.Context; - public abstract class Record { - + protected final String address; protected final Context context; - + public Record(Context context, String address) { this.context = context; this.address = address; - } - + } + public void delete() { delete(this.context, this.address); } - + protected static void delete(Context context, String address) { getAddressFile(context, address).delete(); } @@ -52,44 +52,44 @@ public abstract class Record { protected RandomAccessFile openRandomAccessFile() throws FileNotFoundException { return new RandomAccessFile(getAddressFile(), "rw"); - } - + } + protected FileInputStream openInputStream() throws FileNotFoundException { return new FileInputStream(getAddressFile().getAbsolutePath()); } - + private File getAddressFile() { return getAddressFile(context, address); } - + private static File getAddressFile(Context context, String address) { - return new File(context.getFilesDir().getAbsolutePath() + File.separatorChar + "sessions", address); + return new File(context.getFilesDir().getAbsolutePath() + File.separatorChar + "sessions", address); } protected byte[] readBlob(FileInputStream in) throws IOException { int length = readInteger(in); byte[] blobBytes = new byte[length]; - + in.read(blobBytes, 0, blobBytes.length); return blobBytes; } - + protected void writeBlob(byte[] blobBytes, FileChannel out) throws IOException { writeInteger(blobBytes.length, out); ByteBuffer buffer = ByteBuffer.wrap(blobBytes); out.write(buffer); } - + protected int readInteger(FileInputStream in) throws IOException { byte[] integer = new byte[4]; in.read(integer, 0, integer.length); return Conversions.byteArrayToInt(integer); } - + protected void writeInteger(int value, FileChannel out) throws IOException { byte[] valueBytes = Conversions.intToByteArray(value); ByteBuffer buffer = ByteBuffer.wrap(valueBytes); out.write(buffer); } - + } diff --git a/src/org/thoughtcrime/securesms/database/RemoteKeyRecord.java b/src/org/thoughtcrime/securesms/database/RemoteKeyRecord.java index 2110839fcb..5ab32aca94 100644 --- a/src/org/thoughtcrime/securesms/database/RemoteKeyRecord.java +++ b/src/org/thoughtcrime/securesms/database/RemoteKeyRecord.java @@ -1,6 +1,6 @@ -/** +/** * Copyright (C) 2011 Whisper Systems - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -10,57 +10,57 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package org.thoughtcrime.securesms.database; +import android.content.Context; +import android.util.Log; + +import org.thoughtcrime.securesms.crypto.InvalidKeyException; +import org.thoughtcrime.securesms.crypto.PublicKey; +import org.thoughtcrime.securesms.recipients.Recipient; +import org.thoughtcrime.securesms.util.Hex; + import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.channels.FileChannel; -import org.thoughtcrime.securesms.crypto.InvalidKeyException; -import org.thoughtcrime.securesms.crypto.PublicKey; -import org.thoughtcrime.securesms.recipients.Recipient; -import org.thoughtcrime.securesms.util.Hex; - -import android.content.Context; -import android.util.Log; - /** * Represents the current and last public key belonging to the "remote" * endpoint in an encrypted session. These are stored on disk. - * + * * @author Moxie Marlinspike */ -public class RemoteKeyRecord extends Record { +public class RemoteKeyRecord extends Record { private static final Object FILE_LOCK = new Object(); - + private PublicKey remoteKeyCurrent; private PublicKey remoteKeyLast; - + public RemoteKeyRecord(Context context, Recipient recipient) { super(context,getFileNameForRecipient(context, recipient)); loadData(); } - + public static void delete(Context context, Recipient recipient) { Record.delete(context, getFileNameForRecipient(context, recipient)); } - + public static boolean hasRecord(Context context, Recipient recipient) { Log.w("LocalKeyRecord", "Checking: " + getFileNameForRecipient(context, recipient)); return Record.hasRecord(context, getFileNameForRecipient(context, recipient)); } - + private static String getFileNameForRecipient(Context context, Recipient recipient) { return CanonicalAddressDatabase.getInstance(context).getCanonicalAddress(recipient.getNumber()) + "-remote"; } - + public void updateCurrentRemoteKey(PublicKey remoteKey) { Log.w("RemoteKeyRecord", "Updating current remote key: " + remoteKey.getId()); if (remoteKey.getId() > remoteKeyCurrent.getId()) { @@ -68,29 +68,29 @@ public class RemoteKeyRecord extends Record { this.remoteKeyCurrent = remoteKey; } } - + public void setCurrentRemoteKey(PublicKey remoteKeyCurrent) { this.remoteKeyCurrent = remoteKeyCurrent; } - + public void setLastRemoteKey(PublicKey remoteKeyLast) { this.remoteKeyLast = remoteKeyLast; } - + public PublicKey getCurrentRemoteKey() { return this.remoteKeyCurrent; } - + public PublicKey getLastRemoteKey() { return this.remoteKeyLast; } - + public PublicKey getKeyForId(int id) throws InvalidKeyIdException { if (this.remoteKeyCurrent.getId() == id) return this.remoteKeyCurrent; else if (this.remoteKeyLast.getId() == id) return this.remoteKeyLast; else throw new InvalidKeyIdException("No remote key for ID: " + id); } - + public void save() { Log.w("RemoteKeyRecord", "Saving remote key record for recipient: " + this.address); synchronized (FILE_LOCK) { @@ -99,10 +99,10 @@ public class RemoteKeyRecord extends Record { FileChannel out = file.getChannel(); Log.w("RemoteKeyRecord", "Opened file of size: " + out.size()); out.position(0); - + writeKey(remoteKeyCurrent, out); writeKey(remoteKeyLast, out); - + out.truncate(out.position()); out.close(); file.close(); @@ -112,12 +112,12 @@ public class RemoteKeyRecord extends Record { } } } - + private void loadData() { Log.w("RemoteKeyRecord", "Loading remote key record for recipient: " + this.address); synchronized (FILE_LOCK) { try { - FileInputStream in = this.openInputStream(); + FileInputStream in = this.openInputStream(); remoteKeyCurrent = readKey(in); remoteKeyLast = readKey(in); in.close(); @@ -130,13 +130,13 @@ public class RemoteKeyRecord extends Record { } } } - + private void writeKey(PublicKey key, FileChannel out) throws IOException { byte[] keyBytes = key.serialize(); Log.w("RemoteKeyRecord", "Serializing remote key bytes: " + Hex.toString(keyBytes)); writeBlob(keyBytes, out); } - + private PublicKey readKey(FileInputStream in) throws IOException { try { byte[] keyBytes = readBlob(in); diff --git a/src/org/thoughtcrime/securesms/database/SessionKey.java b/src/org/thoughtcrime/securesms/database/SessionKey.java index dd5be1caae..2052bbe8cd 100644 --- a/src/org/thoughtcrime/securesms/database/SessionKey.java +++ b/src/org/thoughtcrime/securesms/database/SessionKey.java @@ -1,6 +1,6 @@ -/** +/** * Copyright (C) 2011 Whisper Systems - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -10,25 +10,25 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package org.thoughtcrime.securesms.database; -import javax.crypto.spec.SecretKeySpec; - import org.thoughtcrime.securesms.crypto.MasterCipher; import org.thoughtcrime.securesms.crypto.MasterSecret; import org.thoughtcrime.securesms.crypto.SessionCipher; import org.thoughtcrime.securesms.util.Conversions; import org.thoughtcrime.securesms.util.Util; +import javax.crypto.spec.SecretKeySpec; + /** * Represents the currently negotiated session key for a given * local key id and remote key id. This is stored encrypted on * disk. - * + * * @author Moxie Marlinspike */ @@ -39,7 +39,7 @@ public class SessionKey { private SecretKeySpec cipherKey; private SecretKeySpec macKey; private MasterCipher masterCipher; - + public SessionKey(int localKeyId, int remoteKeyId, SecretKeySpec cipherKey, SecretKeySpec macKey, MasterSecret masterSecret) { this.localKeyId = localKeyId; this.remoteKeyId = remoteKeyId; @@ -47,33 +47,33 @@ public class SessionKey { this.macKey = macKey; this.masterCipher = new MasterCipher(masterSecret); } - + public SessionKey(byte[] bytes, MasterSecret masterSecret) { this.masterCipher = new MasterCipher(masterSecret); deserialize(bytes); } - + public byte[] serialize() { byte[] localKeyIdBytes = Conversions.mediumToByteArray(localKeyId); byte[] remoteKeyIdBytes = Conversions.mediumToByteArray(remoteKeyId); byte[] cipherKeyBytes = cipherKey.getEncoded(); byte[] macKeyBytes = macKey.getEncoded(); byte[] combined = Util.combine(localKeyIdBytes, remoteKeyIdBytes, cipherKeyBytes, macKeyBytes); - + return masterCipher.encryptBytes(combined); } - + private void deserialize(byte[] bytes) { byte[] decrypted = masterCipher.encryptBytes(bytes); this.localKeyId = Conversions.byteArrayToMedium(decrypted, 0); this.remoteKeyId = Conversions.byteArrayToMedium(decrypted, 3); - + byte[] keyBytes = new byte[SessionCipher.CIPHER_KEY_LENGTH]; System.arraycopy(decrypted, 6, keyBytes, 0, keyBytes.length); byte[] macBytes = new byte[SessionCipher.MAC_KEY_LENGTH]; System.arraycopy(decrypted, 6 + keyBytes.length, macBytes, 0, macBytes.length); - + this.cipherKey = new SecretKeySpec(keyBytes, "AES"); this.macKey = new SecretKeySpec(macBytes, "HmacSHA1"); } @@ -93,5 +93,5 @@ public class SessionKey { public SecretKeySpec getMacKey() { return this.macKey; } - + } diff --git a/src/org/thoughtcrime/securesms/database/SessionRecord.java b/src/org/thoughtcrime/securesms/database/SessionRecord.java index 1bc1c4a0b4..f678aabced 100644 --- a/src/org/thoughtcrime/securesms/database/SessionRecord.java +++ b/src/org/thoughtcrime/securesms/database/SessionRecord.java @@ -208,8 +208,8 @@ public class SessionRecord extends Record { Log.w("SessionRecord", "No session information found."); return; } catch (IOException ioe) { - Log.w("keyrecord", ioe); - // XXX + Log.w("keyrecord", ioe); + // XXX } } } @@ -223,5 +223,4 @@ public class SessionRecord extends Record { return null; } - } diff --git a/src/org/thoughtcrime/securesms/database/SmsDatabase.java b/src/org/thoughtcrime/securesms/database/SmsDatabase.java index 2570cf25aa..b01688e650 100644 --- a/src/org/thoughtcrime/securesms/database/SmsDatabase.java +++ b/src/org/thoughtcrime/securesms/database/SmsDatabase.java @@ -117,12 +117,12 @@ public class SmsDatabase extends Database { try { cursor = db.rawQuery(sql, sqlArgs); if (cursor != null && cursor.moveToFirst()) - return cursor.getLong(0); + return cursor.getLong(0); else - return -1; + return -1; } finally { if (cursor != null) - cursor.close(); + cursor.close(); } } @@ -134,10 +134,10 @@ public class SmsDatabase extends Database { cursor = db.query(TABLE_NAME, new String[] {"COUNT(*)"}, THREAD_ID + " = ?", new String[] {threadId+""}, null, null, null); if (cursor != null && cursor.moveToFirst()) - return cursor.getInt(0); + return cursor.getInt(0); } finally { if (cursor != null) - cursor.close(); + cursor.close(); } return 0; @@ -201,7 +201,7 @@ public class SmsDatabase extends Database { public long insertMessageSent(String address, long threadId, String body, long date, long type) { ContentValues contentValues = new ContentValues(6); - // contentValues.put(ADDRESS, NumberUtil.filterNumber(address)); + // contentValues.put(ADDRESS, NumberUtil.filterNumber(address)); contentValues.put(ADDRESS, address); contentValues.put(THREAD_ID, threadId); contentValues.put(BODY, body); @@ -292,7 +292,7 @@ public class SmsDatabase extends Database { /*package*/ SQLiteStatement createInsertStatement(SQLiteDatabase database) { return database.compileStatement("INSERT INTO " + TABLE_NAME + " (" + ADDRESS + ", " + PERSON + ", " + DATE + ", " + PROTOCOL + ", " + READ + ", " + STATUS + ", " + TYPE + ", " + REPLY_PATH_PRESENT + ", " + SUBJECT + ", " + BODY + ", " + SERVICE_CENTER + ", THREAD_ID) " + - " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); } public static class Types { diff --git a/src/org/thoughtcrime/securesms/database/ThreadDatabase.java b/src/org/thoughtcrime/securesms/database/ThreadDatabase.java index ed8063dcd6..1303e4cb34 100644 --- a/src/org/thoughtcrime/securesms/database/ThreadDatabase.java +++ b/src/org/thoughtcrime/securesms/database/ThreadDatabase.java @@ -54,13 +54,12 @@ public class ThreadDatabase extends Database { super(context, databaseHelper); } - private long[] getRecipientIds(Recipients recipients) { Set recipientSet = new HashSet(); List recipientList = recipients.getRecipientsList(); for (Recipient recipient : recipientList) { - // String number = NumberUtil.filterNumber(recipient.getNumber()); + // String number = NumberUtil.filterNumber(recipient.getNumber()); String number = recipient.getNumber(); recipientSet.add(Long.valueOf(DatabaseFactory.getAddressDatabase(context).getCanonicalAddress(number))); } @@ -229,12 +228,12 @@ public class ThreadDatabase extends Database { cursor = db.query(TABLE_NAME, new String[]{ID}, where, recipientsArg, null, null, null); if (cursor != null && cursor.moveToFirst()) - return cursor.getLong(cursor.getColumnIndexOrThrow(ID)); + return cursor.getLong(cursor.getColumnIndexOrThrow(ID)); else - return -1L; + return -1L; } finally { if (cursor != null) - cursor.close(); + cursor.close(); } } @@ -250,12 +249,12 @@ public class ThreadDatabase extends Database { cursor = db.query(TABLE_NAME, new String[]{ID}, where, recipientsArg, null, null, null); if (cursor != null && cursor.moveToFirst()) - return cursor.getLong(cursor.getColumnIndexOrThrow(ID)); + return cursor.getLong(cursor.getColumnIndexOrThrow(ID)); else - return createThreadForRecipients(recipientsList, recipientIds.length); + return createThreadForRecipients(recipientsList, recipientIds.length); } finally { if (cursor != null) - cursor.close(); + cursor.close(); } } @@ -273,22 +272,18 @@ public class ThreadDatabase extends Database { try { cursor = mmsSmsDatabase.getConversationSnippet(threadId); - if (cursor != null && cursor.moveToFirst()) - updateThread(threadId, count, - cursor.getString(cursor.getColumnIndexOrThrow(SmsDatabase.BODY)), - cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.DATE))); - else - deleteThread(threadId); + if (cursor != null && cursor.moveToFirst()) { + updateThread(threadId, count, + cursor.getString(cursor.getColumnIndexOrThrow(SmsDatabase.BODY)), + cursor.getLong(cursor.getColumnIndexOrThrow(SmsDatabase.DATE))); + } else { + deleteThread(threadId); + } } finally { if (cursor != null) - cursor.close(); + cursor.close(); } notifyConversationListListeners(); } - - - - - } diff --git a/src/org/thoughtcrime/securesms/protocol/Message.java b/src/org/thoughtcrime/securesms/protocol/Message.java index 338dd8b302..a0b477efcb 100644 --- a/src/org/thoughtcrime/securesms/protocol/Message.java +++ b/src/org/thoughtcrime/securesms/protocol/Message.java @@ -1,6 +1,6 @@ -/** +/** * Copyright (C) 2011 Whisper Systems - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -10,38 +10,38 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package org.thoughtcrime.securesms.protocol; -import java.nio.ByteBuffer; +import android.util.Log; import org.thoughtcrime.securesms.crypto.InvalidKeyException; import org.thoughtcrime.securesms.crypto.InvalidMessageException; import org.thoughtcrime.securesms.crypto.PublicKey; import org.thoughtcrime.securesms.util.Conversions; -import android.util.Log; +import java.nio.ByteBuffer; /** * Parses and serializes the encrypted message format. - * + * * @author Moxie Marlinspike */ public class Message { - + public static final int SUPPORTED_VERSION = 1; - + private static final int VERSION_LENGTH = 1; private static final int SENDER_KEY_ID_LENGTH = 3; private static final int RECEIVER_KEY_ID_LENGTH = 3; private static final int NEXT_KEY_LENGTH = PublicKey.KEY_SIZE; private static final int COUNTER_LENGTH = 3; public static final int HEADER_LENGTH = VERSION_LENGTH + SENDER_KEY_ID_LENGTH + RECEIVER_KEY_ID_LENGTH + COUNTER_LENGTH + NEXT_KEY_LENGTH; - + private static final int VERSION_OFFSET = 0; private static final int SENDER_KEY_ID_OFFSET = VERSION_OFFSET + VERSION_LENGTH; private static final int RECEIVER_KEY_ID_OFFSET = SENDER_KEY_ID_OFFSET + SENDER_KEY_ID_LENGTH; @@ -55,9 +55,9 @@ public class Message { private int messageVersion; private int supportedVersion; private byte[] message; - + private PublicKey nextKey; - + public Message(int senderKeyId, int receiverKeyId, PublicKey nextKey, int counter, byte[] message, int messageVersion, int supportedVersion) { this.senderKeyId = senderKeyId; this.receiverKeyId = receiverKeyId; @@ -67,33 +67,33 @@ public class Message { this.messageVersion = messageVersion; this.supportedVersion = supportedVersion; } - + public Message(byte[] messageBytes) throws InvalidMessageException { try { if (messageBytes.length <= HEADER_LENGTH) throw new InvalidMessageException("Message is shorter than headers."); - + this.messageVersion = Conversions.highBitsToInt(messageBytes[VERSION_OFFSET]); this.supportedVersion = Conversions.lowBitsToInt(messageBytes[VERSION_OFFSET]); - + Log.w("Message", "Message Version: " + messageVersion); Log.w("Message", "Supported Version: " + supportedVersion); - + if (messageVersion > SUPPORTED_VERSION) throw new InvalidMessageException("Message protocol version not supported: " + messageVersion); - + this.senderKeyId = Conversions.byteArrayToMedium(messageBytes, SENDER_KEY_ID_OFFSET); this.receiverKeyId = Conversions.byteArrayToMedium(messageBytes, RECEIVER_KEY_ID_OFFSET); this.counter = Conversions.byteArrayToMedium(messageBytes, COUNTER_OFFSET); - + Log.w("Message", "Parsed current version: " + messageVersion + " supported version: " + supportedVersion); - + byte[] nextKeyBytes = new byte[NEXT_KEY_LENGTH]; byte[] textBytes = new byte[messageBytes.length - HEADER_LENGTH]; - + System.arraycopy(messageBytes, NEXT_KEY_OFFSET, nextKeyBytes, 0, nextKeyBytes.length); System.arraycopy(messageBytes, TEXT_OFFSET, textBytes, 0, textBytes.length); - + Log.w("Message", "Pulling next key out of message..."); this.nextKey = new PublicKey(nextKeyBytes); this.message = textBytes; @@ -101,10 +101,10 @@ public class Message { throw new AssertionError(ike); } } - + public byte[] serialize() { ByteBuffer buffer = ByteBuffer.allocate(HEADER_LENGTH + message.length); - + Log.w("Message", "Constructing Message Version: (" + messageVersion + "," + supportedVersion + ")"); byte versionByte = Conversions.intsToByteHighAndLow(messageVersion, supportedVersion); @@ -113,39 +113,39 @@ public class Message { Log.w("Message", "Serializing next key into message..."); byte[] nextKeyBytes = nextKey.serialize(); byte[] counterBytes = Conversions.mediumToByteArray(counter); - + buffer.put(versionByte); buffer.put(senderKeyIdBytes); buffer.put(receiverKeyIdBytes); buffer.put(nextKeyBytes); buffer.put(counterBytes); buffer.put(message); - + return buffer.array(); } - + public int getHighestMutuallySupportedVersion() { return Math.min(SUPPORTED_VERSION, this.supportedVersion); } - + public int getSenderKeyId() { return this.senderKeyId; } - + public int getReceiverKeyId() { return this.receiverKeyId; } - + public PublicKey getNextKey() { return this.nextKey; } - + public int getCounter() { return this.counter; } - + public byte[] getMessageText() { return this.message; } - + } diff --git a/src/org/thoughtcrime/securesms/protocol/Prefix.java b/src/org/thoughtcrime/securesms/protocol/Prefix.java index aeab35089d..33780ce67c 100644 --- a/src/org/thoughtcrime/securesms/protocol/Prefix.java +++ b/src/org/thoughtcrime/securesms/protocol/Prefix.java @@ -31,6 +31,6 @@ public class Prefix { public static final String ASYMMETRIC_ENCRYPT = "?TextSecureAsymmetricEncrypt"; public static final String ASYMMETRIC_LOCAL_ENCRYPT = "?TextSecureAsymmetricLocalEncrypt"; public static final String PROCESSED_KEY_EXCHANGE = "?TextSecureKeyExchangd"; - public static final String STALE_KEY_EXCHANGE = "?TextSecureKeyExchangs"; + public static final String STALE_KEY_EXCHANGE = "?TextSecureKeyExchangs"; } diff --git a/src/org/thoughtcrime/securesms/providers/PartProvider.java b/src/org/thoughtcrime/securesms/providers/PartProvider.java index 02c4e2f496..4220d2115d 100644 --- a/src/org/thoughtcrime/securesms/providers/PartProvider.java +++ b/src/org/thoughtcrime/securesms/providers/PartProvider.java @@ -1,6 +1,6 @@ -/** +/** * Copyright (C) 2011 Whisper Systems - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -10,22 +10,12 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package org.thoughtcrime.securesms.providers; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; - -import org.thoughtcrime.securesms.crypto.MasterSecret; -import org.thoughtcrime.securesms.database.DatabaseFactory; -import org.thoughtcrime.securesms.service.KeyCachingService; - import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentProvider; @@ -41,6 +31,16 @@ import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.util.Log; +import org.thoughtcrime.securesms.crypto.MasterSecret; +import org.thoughtcrime.securesms.database.DatabaseFactory; +import org.thoughtcrime.securesms.service.KeyCachingService; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + public class PartProvider extends ContentProvider { private static final String CONTENT_URI_STRING = "content://org.thoughtcrime.provider.securesms/part"; @@ -48,7 +48,7 @@ public class PartProvider extends ContentProvider { private static final int SINGLE_ROW = 1; private static final UriMatcher uriMatcher; - + static { uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI("org.thoughtcrime.provider.securesms", "part/#", SINGLE_ROW); @@ -58,85 +58,84 @@ public class PartProvider extends ContentProvider { private NewKeyReceiver receiver; @Override - public boolean onCreate() { + public boolean onCreate() { initializeMasterSecret(); return true; } - + public static boolean isAuthority(Uri uri) { return uriMatcher.match(uri) != -1; } - + private File copyPartToTemporaryFile(MasterSecret masterSecret, long partId) throws IOException { InputStream in = DatabaseFactory.getEncryptingPartDatabase(getContext(), masterSecret).getPartStream(partId); File tmpDir = getContext().getDir("tmp", 0); File tmpFile = File.createTempFile("test", ".jpg", tmpDir); FileOutputStream fout = new FileOutputStream(tmpFile); - + byte[] buffer = new byte[512]; int read; - + while ((read = in.read(buffer)) != -1) fout.write(buffer, 0, read); - + in.close(); return tmpFile; } - + @Override public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { Log.w("PartProvider", "openFile() called!"); - + if (this.masterSecret == null) return null; - + switch (uriMatcher.match(uri)) { case SINGLE_ROW: Log.w("PartProvider", "Parting out a single row..."); try { - int partId = Integer.parseInt(uri.getPathSegments().get(1)); - File tmpFile = copyPartToTemporaryFile(masterSecret, partId); - ParcelFileDescriptor pdf = ParcelFileDescriptor.open(tmpFile, ParcelFileDescriptor.MODE_READ_ONLY); - tmpFile.delete(); - return pdf; + int partId = Integer.parseInt(uri.getPathSegments().get(1)); + File tmpFile = copyPartToTemporaryFile(masterSecret, partId); + ParcelFileDescriptor pdf = ParcelFileDescriptor.open(tmpFile, ParcelFileDescriptor.MODE_READ_ONLY); + tmpFile.delete(); + return pdf; } catch (IOException ioe) { - Log.w("PartProvider", ioe); - throw new FileNotFoundException("Error opening file"); + Log.w("PartProvider", ioe); + throw new FileNotFoundException("Error opening file"); } } - + throw new FileNotFoundException("Request for bad part."); } - + @Override - public int delete(Uri arg0, String arg1, String[] arg2) { + public int delete(Uri arg0, String arg1, String[] arg2) { return 0; } @Override - public String getType(Uri arg0) { + public String getType(Uri arg0) { return null; } @Override - public Uri insert(Uri arg0, ContentValues arg1) { + public Uri insert(Uri arg0, ContentValues arg1) { return null; } @Override - public Cursor query(Uri arg0, String[] arg1, String arg2, String[] arg3, String arg4) { + public Cursor query(Uri arg0, String[] arg1, String arg2, String[] arg3, String arg4) { return null; } @Override - public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) { + public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) { return 0; } - private void initializeWithMasterSecret(MasterSecret masterSecret) { - Log.w("PartProvider", "Got master secret: " + masterSecret); + Log.w("PartProvider", "Got master secret: " + masterSecret); this.masterSecret = masterSecret; } @@ -148,15 +147,15 @@ public class PartProvider extends ContentProvider { Intent bindIntent = new Intent(getContext(), KeyCachingService.class); getContext().bindService(bindIntent, serviceConnection, Context.BIND_AUTO_CREATE); } - + private ServiceConnection serviceConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { - KeyCachingService keyCachingService = ((KeyCachingService.KeyCachingBinder)service).getService(); - MasterSecret masterSecret = keyCachingService.getMasterSecret(); + KeyCachingService keyCachingService = ((KeyCachingService.KeyCachingBinder)service).getService(); + MasterSecret masterSecret = keyCachingService.getMasterSecret(); - initializeWithMasterSecret(masterSecret); + initializeWithMasterSecret(masterSecret); - PartProvider.this.getContext().unbindService(this); + PartProvider.this.getContext().unbindService(this); } public void onServiceDisconnected(ComponentName name) {} @@ -164,7 +163,7 @@ public class PartProvider extends ContentProvider { private class NewKeyReceiver extends BroadcastReceiver { @Override - public void onReceive(Context context, Intent intent) { + public void onReceive(Context context, Intent intent) { Log.w("SendReceiveService", "Got a MasterSecret broadcast..."); initializeWithMasterSecret((MasterSecret)intent.getParcelableExtra("master_secret")); } diff --git a/src/org/thoughtcrime/securesms/recipients/RecipientFormattingException.java b/src/org/thoughtcrime/securesms/recipients/RecipientFormattingException.java index 7dc3feb8c6..9b2731e16b 100644 --- a/src/org/thoughtcrime/securesms/recipients/RecipientFormattingException.java +++ b/src/org/thoughtcrime/securesms/recipients/RecipientFormattingException.java @@ -1,6 +1,6 @@ -/** +/** * Copyright (C) 2011 Whisper Systems - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -10,7 +10,7 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ @@ -20,15 +20,15 @@ public class RecipientFormattingException extends Exception { public RecipientFormattingException() { super(); } - + public RecipientFormattingException(String message) { super(message); } - + public RecipientFormattingException(String message, Throwable nested) { super(message, nested); } - + public RecipientFormattingException(Throwable nested) { super(nested); } diff --git a/src/org/thoughtcrime/securesms/recipients/RecipientsFormatter.java b/src/org/thoughtcrime/securesms/recipients/RecipientsFormatter.java index a054308291..041299c4bf 100644 --- a/src/org/thoughtcrime/securesms/recipients/RecipientsFormatter.java +++ b/src/org/thoughtcrime/securesms/recipients/RecipientsFormatter.java @@ -1,6 +1,6 @@ -/** +/** * Copyright (C) 2011 Whisper Systems - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -10,32 +10,32 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package org.thoughtcrime.securesms.recipients; +import android.telephony.PhoneNumberUtils; +import android.text.TextUtils; + import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; -import android.telephony.PhoneNumberUtils; -import android.text.TextUtils; - public class RecipientsFormatter { private static String parseBracketedNumber(String recipient) throws RecipientFormattingException { int begin = recipient.indexOf('<'); int end = recipient.indexOf('>'); String value = recipient.substring(begin + 1, end); - + if (PhoneNumberUtils.isWellFormedSmsAddress(value)) return value; else throw new RecipientFormattingException("Bracketed value: " + value + " is not valid."); } - + private static String parseRecipient(String recipient) throws RecipientFormattingException { recipient = recipient.trim(); @@ -44,21 +44,21 @@ public class RecipientsFormatter { if (PhoneNumberUtils.isWellFormedSmsAddress(recipient)) return recipient; - + throw new RecipientFormattingException("Recipient: " + recipient + " is badly formatted."); } - + public static List getRecipients(String rawText) throws RecipientFormattingException { ArrayList results = new ArrayList(); StringTokenizer tokenizer = new StringTokenizer(rawText, ","); while (tokenizer.hasMoreTokens()) { - results.add(parseRecipient(tokenizer.nextToken())); + results.add(parseRecipient(tokenizer.nextToken())); } return results; } - + public static String formatNameAndNumber(String name, String number) { // Format like this: Mike Cleron <(650) 555-1234> // Erick Tseng <(650) 555-1212> @@ -72,5 +72,5 @@ public class RecipientsFormatter { } } - + } diff --git a/src/org/thoughtcrime/securesms/util/CharacterCalculator.java b/src/org/thoughtcrime/securesms/util/CharacterCalculator.java index 7f6bb08dae..696dc63f73 100644 --- a/src/org/thoughtcrime/securesms/util/CharacterCalculator.java +++ b/src/org/thoughtcrime/securesms/util/CharacterCalculator.java @@ -1,6 +1,6 @@ -/** +/** * Copyright (C) 2011 Whisper Systems - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -10,7 +10,7 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ @@ -22,7 +22,7 @@ public class CharacterCalculator { public CharacterState calculateCharacters(int charactersSpent) { int maxMessageSize; - + if (charactersSpent <= SmsTransportDetails.SMS_SIZE) { maxMessageSize = SmsTransportDetails.SMS_SIZE; } else { @@ -30,21 +30,21 @@ public class CharacterCalculator { } int messagesSpent = charactersSpent / maxMessageSize; - + if (((charactersSpent % maxMessageSize) > 0) || (messagesSpent == 0)) messagesSpent++; - + int charactersRemaining = (maxMessageSize * messagesSpent) - charactersSpent; return new CharacterState(messagesSpent, charactersRemaining, maxMessageSize); } - - + + public class CharacterState { public int charactersRemaining; public int messagesSpent; public int maxMessageSize; - + public CharacterState(int messagesSpent, int charactersRemaining, int maxMessageSize) { this.messagesSpent = messagesSpent; this.charactersRemaining = charactersRemaining; diff --git a/src/org/thoughtcrime/securesms/util/Combiner.java b/src/org/thoughtcrime/securesms/util/Combiner.java index da53b30da2..75d83df181 100644 --- a/src/org/thoughtcrime/securesms/util/Combiner.java +++ b/src/org/thoughtcrime/securesms/util/Combiner.java @@ -1,6 +1,6 @@ -/** +/** * Copyright (C) 2011 Whisper Systems - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -10,7 +10,7 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ @@ -32,7 +32,7 @@ public class Combiner { System.arraycopy(c, 0, combined, a.length + b.length, c.length); return combined; } - + public static byte[] combine(byte[] a, byte[] b, byte[] c, byte[] d) { byte[] combined = new byte[a.length + b.length + c.length + d.length]; System.arraycopy(a, 0, combined, 0, a.length); @@ -41,5 +41,5 @@ public class Combiner { System.arraycopy(d, 0, combined, a.length + b.length + c.length, d.length); return combined; } - + } diff --git a/src/org/thoughtcrime/securesms/util/Conversions.java b/src/org/thoughtcrime/securesms/util/Conversions.java index d0cdd29d42..91aede2eb8 100644 --- a/src/org/thoughtcrime/securesms/util/Conversions.java +++ b/src/org/thoughtcrime/securesms/util/Conversions.java @@ -1,6 +1,6 @@ -/** +/** * Copyright (C) 2011 Whisper Systems - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -10,7 +10,7 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ @@ -18,26 +18,26 @@ package org.thoughtcrime.securesms.util; public class Conversions { - public static byte intsToByteHighAndLow(int highValue, int lowValue) { + public static byte intsToByteHighAndLow(int highValue, int lowValue) { return (byte)((highValue << 4 | lowValue) & 0xFF); } - + public static int highBitsToInt(byte value) { return (value & 0xFF) >> 4; } - + public static int lowBitsToInt(byte value) { return (value & 0xF); } - + public static int highBitsToMedium(int value) { return (value >> 12); } - + public static int lowBitsToMedium(int value) { return (value & 0xFFF); } - + public static byte[] shortToByteArray(int value) { byte[] bytes = new byte[2]; shortToByteArray(bytes, 0, value); @@ -61,7 +61,7 @@ public class Conversions { mediumToByteArray(bytes, 0, value); return bytes; } - + public static int mediumToByteArray(byte[] bytes, int offset, int value) { bytes[offset + 2] = (byte)value; bytes[offset + 1] = (byte)(value >> 8); @@ -108,12 +108,12 @@ public class Conversions { bytes[offset] = (byte)(value >> 56); return 8; } - + public static int longTo4ByteArray(byte[] bytes, int offset, long value) { bytes[offset + 3] = (byte)value; bytes[offset + 2] = (byte)(value >> 8); bytes[offset + 1] = (byte)(value >> 16); - bytes[offset + 0] = (byte)(value >> 24); + bytes[offset + 0] = (byte)(value >> 24); return 4; } @@ -145,7 +145,7 @@ public class Conversions { (bytes[offset + 2] & 0xff) << 8 | (bytes[offset + 3] & 0xff); } - + public static int byteArrayToIntLittleEndian(byte[] bytes, int offset) { return (bytes[offset + 3] & 0xff) << 24 | diff --git a/src/org/thoughtcrime/securesms/util/EncryptedCharacterCalculator.java b/src/org/thoughtcrime/securesms/util/EncryptedCharacterCalculator.java index 1df345ed6b..df80b789b5 100644 --- a/src/org/thoughtcrime/securesms/util/EncryptedCharacterCalculator.java +++ b/src/org/thoughtcrime/securesms/util/EncryptedCharacterCalculator.java @@ -1,6 +1,6 @@ -/** +/** * Copyright (C) 2011 Whisper Systems - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -10,16 +10,16 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package org.thoughtcrime.securesms.util; -import org.thoughtcrime.securesms.sms.SmsTransportDetails; - import android.util.Log; +import org.thoughtcrime.securesms.sms.SmsTransportDetails; + public class EncryptedCharacterCalculator extends CharacterCalculator { private CharacterState calculateSingleRecordCharacters(int charactersSpent) { @@ -27,37 +27,37 @@ public class EncryptedCharacterCalculator extends CharacterCalculator { return new CharacterState(1, charactersRemaining, SmsTransportDetails.ENCRYPTED_SINGLE_MESSAGE_BODY_MAX_SIZE); } - + private CharacterState calculateMultiRecordCharacters(int charactersSpent) { int charactersInFirstRecord = SmsTransportDetails.ENCRYPTED_SINGLE_MESSAGE_BODY_MAX_SIZE; - int spillover = charactersSpent - charactersInFirstRecord; + int spillover = charactersSpent - charactersInFirstRecord; Log.w("EncryptedCharacterCalculator", "Spillover: " + spillover); - // int maxMultiMessageSize = SessionCipher.getMaxBodySizePerMultiMessage(charactersSpent); - // Log.w("EncryptedCharacterCalculator", "Maxmultimessagesize: " + maxMultiMessageSize); - // int spilloverMessagesSpent = spillover / maxMultiMessageSize; + // int maxMultiMessageSize = SessionCipher.getMaxBodySizePerMultiMessage(charactersSpent); + // Log.w("EncryptedCharacterCalculator", "Maxmultimessagesize: " + maxMultiMessageSize); + // int spilloverMessagesSpent = spillover / maxMultiMessageSize; int spilloverMessagesSpent = spillover / SmsTransportDetails.MULTI_MESSAGE_MAX_BYTES; Log.w("EncryptedCharacterCalculator", "Spillover messaegs spent: " + spilloverMessagesSpent); - // if ((spillover % maxMultiMessageSize) > 0) + // if ((spillover % maxMultiMessageSize) > 0) if ((spillover % SmsTransportDetails.MULTI_MESSAGE_MAX_BYTES) > 0) spilloverMessagesSpent++; Log.w("EncryptedCharacterCalculator", "Spillover messaegs spent: " + spilloverMessagesSpent); - // int charactersRemaining = (maxMultiMessageSize * spilloverMessagesSpent) - spillover; + // int charactersRemaining = (maxMultiMessageSize * spilloverMessagesSpent) - spillover; int charactersRemaining = (SmsTransportDetails.MULTI_MESSAGE_MAX_BYTES * spilloverMessagesSpent) - spillover; Log.w("EncryptedCharacterCalculator", "charactersRemaining: " + charactersRemaining); - - // return new CharacterState(spilloverMessagesSpent+1, charactersRemaining, maxMultiMessageSize); + + // return new CharacterState(spilloverMessagesSpent+1, charactersRemaining, maxMultiMessageSize); return new CharacterState(spilloverMessagesSpent+1, charactersRemaining, SmsTransportDetails.MULTI_MESSAGE_MAX_BYTES); } - + @Override public CharacterState calculateCharacters(int charactersSpent) { if (charactersSpent <= SmsTransportDetails.ENCRYPTED_SINGLE_MESSAGE_BODY_MAX_SIZE){ return calculateSingleRecordCharacters(charactersSpent); } else { return calculateMultiRecordCharacters(charactersSpent); - } + } } } diff --git a/src/org/thoughtcrime/securesms/util/Hex.java b/src/org/thoughtcrime/securesms/util/Hex.java index e6692346c8..0217343809 100644 --- a/src/org/thoughtcrime/securesms/util/Hex.java +++ b/src/org/thoughtcrime/securesms/util/Hex.java @@ -1,6 +1,6 @@ -/** +/** * Copyright (C) 2011 Whisper Systems - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -10,7 +10,7 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ @@ -46,7 +46,7 @@ public class Hex { public static String dump(byte[] bytes) { return dump(bytes, 0, bytes.length); } - + public static String dump(byte[] bytes, int offset, int length) { StringBuffer buf = new StringBuffer(); int lines = ((length - 1) / 16) + 1; @@ -59,7 +59,7 @@ public class Hex { appendDumpLine(buf, i, bytes, lineOffset, lineLength); buf.append(EOL); } - + return buf.toString(); } @@ -78,12 +78,12 @@ public class Hex { int idx = i + lineOffset; if (i < lineLength) { int b = bytes[idx]; - appendHexChar(buf, b); + appendHexChar(buf, b); } else { - buf.append(" "); + buf.append(" "); } if ((i % 2) == 1) { - buf.append(' '); + buf.append(' '); } } diff --git a/src/org/thoughtcrime/securesms/util/NumberUtil.java b/src/org/thoughtcrime/securesms/util/NumberUtil.java index 0dc6105191..84749ad9e7 100644 --- a/src/org/thoughtcrime/securesms/util/NumberUtil.java +++ b/src/org/thoughtcrime/securesms/util/NumberUtil.java @@ -1,6 +1,6 @@ -/** +/** * Copyright (C) 2012 Whisper Systems - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -10,33 +10,33 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package org.thoughtcrime.securesms.util; +import android.telephony.PhoneNumberUtils; + import java.util.regex.Matcher; import java.util.regex.Pattern; -import android.telephony.PhoneNumberUtils; - public class NumberUtil { - private static final Pattern emailPattern = android.util.Patterns.EMAIL_ADDRESS; - + private static final Pattern emailPattern = android.util.Patterns.EMAIL_ADDRESS; + public static boolean isValidEmail(String number) { Matcher matcher = emailPattern.matcher(number); return matcher.matches(); } - + public static boolean isValidSmsOrEmail(String number) { return PhoneNumberUtils.isWellFormedSmsAddress(number) || isValidEmail(number); } - + public static String filterNumber(String number) { if (number == null) return null; - + int length = number.length(); StringBuilder builder = new StringBuilder(length); @@ -44,10 +44,9 @@ public class NumberUtil { char character = number.charAt(i); if (Character.isDigit(character) || character == '+') - builder.append(character); + builder.append(character); } - + return builder.toString(); } - } diff --git a/src/org/thoughtcrime/securesms/util/RedPhoneCallTypes.java b/src/org/thoughtcrime/securesms/util/RedPhoneCallTypes.java index acae61eee1..d5f1a136dc 100644 --- a/src/org/thoughtcrime/securesms/util/RedPhoneCallTypes.java +++ b/src/org/thoughtcrime/securesms/util/RedPhoneCallTypes.java @@ -1,6 +1,6 @@ -/** +/** * Copyright (C) 2011 Whisper Systems - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -10,7 +10,7 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ @@ -19,5 +19,5 @@ package org.thoughtcrime.securesms.util; public interface RedPhoneCallTypes { public static final int INCOMING = 1023; public static final int OUTGOING = 1024; - public static final int MISSED = 1025; + public static final int MISSED = 1025; } diff --git a/src/org/thoughtcrime/securesms/util/Util.java b/src/org/thoughtcrime/securesms/util/Util.java index 27b631d0a2..15747ea49f 100644 --- a/src/org/thoughtcrime/securesms/util/Util.java +++ b/src/org/thoughtcrime/securesms/util/Util.java @@ -1,6 +1,6 @@ -/** +/** * Copyright (C) 2011 Whisper Systems - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -10,7 +10,7 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ @@ -25,65 +25,65 @@ public class Util { return combined; } - + public static byte[] combine(byte[] one, byte[] two, byte[] three) { byte[] combined = new byte[one.length + two.length + three.length]; System.arraycopy(one, 0, combined, 0, one.length); System.arraycopy(two, 0, combined, one.length, two.length); System.arraycopy(three, 0, combined, one.length + two.length, three.length); - + return combined; } - + public static byte[] combine(byte[] one, byte[] two, byte[] three, byte[] four) { byte[] combined = new byte[one.length + two.length + three.length + four.length]; System.arraycopy(one, 0, combined, 0, one.length); System.arraycopy(two, 0, combined, one.length, two.length); System.arraycopy(three, 0, combined, one.length + two.length, three.length); System.arraycopy(four, 0, combined, one.length + two.length + three.length, four.length); - + return combined; - + } - + public static String[] splitString(String string, int maxLength) { int count = string.length() / maxLength; - + if (string.length() % maxLength > 0) count++; - + String[] splitString = new String[count]; - + for (int i=0;i= - //// Math.abs(options.outWidth - targetWidth); + //// Log.w("Util", "Bitmap Origin Width: " + options.outWidth); + //// Log.w("Util", "Bitmap Origin Height: " + options.outHeight); //// - //// if (options.outHeight * options.outWidth >= targetWidth * targetHeight * 2) { - //// double sampleSize = scaleByHeight ? (double)options.outHeight / (double)targetHeight : (double)options.outWidth / (double)targetWidth; - ////// options.inSampleSize = (int)Math.pow(2d, Math.floor(Math.log(sampleSize) / Math.log(2d))); - //// Log.w("Util", "Sampling by: " + options.inSampleSize); - //// } + //// boolean scaleByHeight = + //// Math.abs(options.outHeight - targetHeight) >= + //// Math.abs(options.outWidth - targetWidth); //// - //// options.inJustDecodeBounds = false; - //// - //// return BitmapFactory.decodeStream(src, null, options); - // } + //// if (options.outHeight * options.outWidth >= targetWidth * targetHeight * 2) { + //// double sampleSize = scaleByHeight ? (double)options.outHeight / (double)targetHeight : (double)options.outWidth / (double)targetWidth; + ////// options.inSampleSize = (int)Math.pow(2d, Math.floor(Math.log(sampleSize) / Math.log(2d))); + //// Log.w("Util", "Sampling by: " + options.inSampleSize); + //// } + //// + //// options.inJustDecodeBounds = false; + //// + //// return BitmapFactory.decodeStream(src, null, options); + // } } diff --git a/src/org/thoughtcrime/securesms/util/WorkerThread.java b/src/org/thoughtcrime/securesms/util/WorkerThread.java index 546c3c445e..7d77f54310 100644 --- a/src/org/thoughtcrime/securesms/util/WorkerThread.java +++ b/src/org/thoughtcrime/securesms/util/WorkerThread.java @@ -1,6 +1,6 @@ -/** +/** * Copyright (C) 2011 Whisper Systems - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or @@ -10,7 +10,7 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ @@ -19,27 +19,28 @@ package org.thoughtcrime.securesms.util; import java.util.List; public class WorkerThread extends Thread { - + private final List workQueue; - + public WorkerThread(List workQueue, String name) { super(name); this.workQueue = workQueue; } - + private Runnable getWork() { synchronized (workQueue) { try { - while (workQueue.isEmpty()) - workQueue.wait(); - - return workQueue.remove(0); + while (workQueue.isEmpty()) + workQueue.wait(); + + return workQueue.remove(0); } catch (InterruptedException ie) { - throw new AssertionError(ie); + throw new AssertionError(ie); } } } - + + @Override public void run() { for (;;) getWork().run();