/** * Copyright (C) 2013 Jonathan Gillett, Joseph Heron * * 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 * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * 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 <http://www.gnu.org/licenses/>. */ package com.tinfoil.sms.database; import java.util.ArrayList; import java.util.List; import android.content.ContentValues; import android.content.Context; import android.content.SharedPreferences; import android.database.Cursor; import android.preference.PreferenceManager; import com.tinfoil.sms.R; import com.tinfoil.sms.dataStructures.Entry; import com.tinfoil.sms.dataStructures.Message; import com.tinfoil.sms.dataStructures.Number; import com.tinfoil.sms.dataStructures.TrustedContact; import com.tinfoil.sms.dataStructures.User; import com.tinfoil.sms.dataStructures.WalkthroughStep; import com.tinfoil.sms.settings.QuickPrefsActivity; import com.tinfoil.sms.sms.ConversationView; import com.tinfoil.sms.utility.SMSUtility; import com.tinfoil.sms.utility.Walkthrough.Step; /** * Creates a database that is read and write and provides methods to * facilitate the reading and writing to the database. Table Names * are all from SQLitehelper since they are created in that class. */ public class DBAccessor { public static final int TRUE = 1; public static final int FALSE = 0; private static String USER_NAME = "Me"; public static final int LENGTH = 20; public static final int OTHER_INDEX = 7; public static String[] TYPES = new String[] {"Home", "Mobile", "Work", "Work Fax", "Home Fax", "Pager", "Other", "Custom", "Callback", "Car", "Company Main", "ISDN", "Main", "Other Fax", "Telex", "TTY TTD", "Work Mobile", "Work Pager", "Assistant", "MMS"}; public static final String DEFAULT_BOOK_PATH = "path/path"; public static final String DEFAULT_BOOK_INVERSE_PATH = "path/inverse"; public static final String DEFAULT_S1 = "Initiator"; public static final String DEFAULT_S2 = "Receiver"; public static final int ALL = 0; public static final int TRUSTED = 1; public static final int UNTRUSTED = 2; private SharedPreferences sharedPrefs; private Context context; /** * Creates a database that is read and write * @param c : Context, where the database is available */ public DBAccessor (Context c) { this.context = c; localizeStrings(c); this.sharedPrefs = PreferenceManager.getDefaultSharedPreferences(c); } public static void localizeStrings(Context c) { USER_NAME = c.getString(R.string.user); TYPES = c.getResources().getStringArray(R.array.phone_types); } /** * Get the pending key exchange message for the contact with the given * number. * @param number The number of the contact whose key exchange message is * needed. * @return The Entry in the key exchange db that contains the number and the * key exchange message. */ public Entry getKeyExchangeMessage(String number) { long id = this.getNumberId(SMSUtility.format(number)); //open(); Cursor cur = context.getContentResolver().query(DatabaseProvider.EXCHANGE_CONTENT_URI, new String[]{ SQLitehelper.KEY_ID, SQLitehelper.KEY_EXCHANGE_MESSAGE}, SQLitehelper.KEY_NUMBER_REFERENCE + " = " + id, null, null); if(cur.moveToFirst()) { Entry exchangeMessage = new Entry(number, cur.getString(cur.getColumnIndex(SQLitehelper.KEY_EXCHANGE_MESSAGE)), cur.getLong(cur.getColumnIndex(SQLitehelper.KEY_ID)), TRUE); cur.close(); return exchangeMessage; } if(cur != null) { cur.close(); } return null; } /** * Get all of the pending key exchange messages. */ public ArrayList<Entry> getAllKeyExchangeMessages() { Cursor cur = context.getContentResolver().query(DatabaseProvider.EXCHANGE_CONTENT_URI, new String[]{ SQLitehelper.KEY_ID, SQLitehelper.KEY_NUMBER_REFERENCE, SQLitehelper.KEY_EXCHANGE_MESSAGE}, null, null, null); ArrayList<Entry> exchangeMessage = null; if(cur.moveToFirst()) { exchangeMessage = new ArrayList<Entry>(); do exchangeMessage.add(new Entry( getNumber(cur.getLong(cur.getColumnIndex(SQLitehelper.KEY_NUMBER_REFERENCE))), cur.getString(cur.getColumnIndex(SQLitehelper.KEY_EXCHANGE_MESSAGE)), cur.getLong(cur.getColumnIndex(SQLitehelper.KEY_ID)), TRUE)); while(cur.moveToNext()); } cur.close(); return exchangeMessage; } /** * Get all of the pending key exchange messages. * @return The number of key exchanges pending */ public int getKeyExchangeMessageCount() { Cursor cur = context.getContentResolver().query(DatabaseProvider.EXCHANGE_CONTENT_URI, new String[]{ SQLitehelper.KEY_ID}, null, null, null); int count = 0; if(cur.moveToFirst()) { count = cur.getCount(); } cur.close(); return count; } /** * Add a pending key exchange message. * @param keyExchange The pending key exchange message * @return The error message, if null the addition was successful. */ public String addKeyExchangeMessage(Entry keyExchange) { Entry prev = getKeyExchangeMessage(keyExchange.getNumber()); if(prev == null) { ContentValues cv = new ContentValues(); cv.put(SQLitehelper.KEY_NUMBER_REFERENCE, getNumberId(SMSUtility.format(keyExchange.getNumber()))); cv.put(SQLitehelper.KEY_EXCHANGE_MESSAGE, keyExchange.getMessage()); context.getContentResolver().insert(DatabaseProvider.EXCHANGE_CONTENT_URI, cv); return null; } else { if(prev.getMessage().compareTo(keyExchange.getMessage()) == 0) { //Contact sent another message return keyExchange.getNumber() + " " + context.getString(R.string.duplicate_key_exchange); } else { return context.getString(R.string.duplicate_key_exchange_warning_1) + " " + keyExchange.getNumber() + " " + context.getString(R.string.duplicate_key_exchange_warning_2); } } } /** * Delete the pending key exchange message. Calling this method means the * user has either rejected the key exchange or accepted. * @param number The number of the contact who had a pending key exchange * that has now been dealt with. */ public void deleteKeyExchangeMessage(String number) { long id = getNumberId(number); context.getContentResolver().delete(DatabaseProvider.EXCHANGE_CONTENT_URI, SQLitehelper.KEY_NUMBER_REFERENCE + " = " + id, null); } /** * Add a row to the numbers table. * @param reference The reference id of the contact the number belongs to. * @param number The Number that contains all the information to be stored. */ private long addNumbersRow (long reference, Number number) { ContentValues cv = new ContentValues(); //add given values to a row cv.put(SQLitehelper.KEY_REFERENCE, reference); cv.put(SQLitehelper.KEY_NUMBER, SMSUtility.format(number.getNumber())); cv.put(SQLitehelper.KEY_TYPE, number.getType()); cv.put(SQLitehelper.KEY_UNREAD, number.getUnreadMessageCount()); cv.put(SQLitehelper.KEY_PUBLIC_KEY, number.getPublicKey()); cv.put(SQLitehelper.KEY_SIGNATURE, number.getSignature()); cv.put(SQLitehelper.KEY_NONCE_ENCRYPT, number.getNonceEncrypt()); cv.put(SQLitehelper.KEY_NONCE_DECRYPT, number.getNonceDecrypt()); cv.put(SQLitehelper.KEY_INITIATOR, number.getInitiatorInt()); cv.put(SQLitehelper.KEY_EXCHANGE_SETTING, number.getKeyExchangeFlag()); //Insert the row into the database long id = Long.valueOf(context.getContentResolver().insert(DatabaseProvider .NUMBER_CONTENT_URI, cv).getLastPathSegment()); updateBookPaths(id, number.getBookPath(), number.getBookInversePath()); addSharedInfo(id, number.getSharedInfo1(), number.getSharedInfo2()); return id; } /** * TODO implement passive message deleter, (such that every time a message is added it will * check if the message count is above the limit, if it is it will delete the oldest messages * until it is under the limit * * Add a message to the database, only a limited number of messages are stored in the database. * @param reference The id of the number that the message came from or was sent to. * @param message A message object containing all the information for the message. */ private void addMessageRow (long reference, Message message) { ContentValues cv = new ContentValues(); //add given values to a row cv.put(SQLitehelper.KEY_REFERENCE, reference); cv.put(SQLitehelper.KEY_MESSAGE, message.getMessage()); cv.put(SQLitehelper.KEY_DATE, message.getDate()); cv.put(SQLitehelper.KEY_SENT, message.getSent()); //Insert the row into the database Cursor cur = context.getContentResolver().query(DatabaseProvider.MESSAGE_CONTENT_URI, new String[]{SQLitehelper.KEY_ID}, SQLitehelper.KEY_REFERENCE + " = " + reference, null, null); if (cur.moveToFirst() && cur.getCount() >= Integer.valueOf(sharedPrefs.getString (QuickPrefsActivity.MESSAGE_LIMIT_SETTING_KEY, String.valueOf(SMSUtility.LIMIT)))) { // Update the last item to the new message to preserve message limit context.getContentResolver().update(DatabaseProvider.MESSAGE_CONTENT_URI, cv, SQLitehelper.KEY_ID + " = (SELECT " + SQLitehelper.KEY_ID + " FROM " + SQLitehelper.MESSAGES_TABLE_NAME + " WHERE " + SQLitehelper.KEY_REFERENCE + " = " + reference + " ORDER by " + SQLitehelper.KEY_DATE + " LIMIT 1)", null); } else { // Insert the new message context.getContentResolver().insert(DatabaseProvider.MESSAGE_CONTENT_URI, cv); } cur.close(); } /** * Delete messages that are stored in the database * @param id The id of the message in the database. * @return Whether the message was deleted or not. */ public boolean deleteMessage(long id) { int num = context.getContentResolver().delete(DatabaseProvider.MESSAGE_CONTENT_URI, SQLitehelper.KEY_REFERENCE + " = " + id, null); if(num == 0) { return false; } return true; } /** * Delete the messages that this number has stored in the database. * @param number The number of the contact that is in the database. * @return Whether the messages are deleted or not. */ public boolean deleteMessage(String number) { number = SMSUtility.format(number); long id = getNumberId(number); return deleteMessage(id); } /** * Updates the message count for the particular given number to the given * new count. * @param number A number from the contact. * @param unreadMessageCount The new number of unread messages. */ public void updateMessageCount(String number, int unreadMessageCount) { ContentValues cv = new ContentValues(); cv.put(SQLitehelper.KEY_UNREAD, unreadMessageCount); context.getContentResolver().update(DatabaseProvider.NUMBER_CONTENT_URI, cv, "number = ?", new String[] {number}); } /** * Add a new message to the database. * @param message The Message that contains all the information to be * stored. * @param number The number of the contact the message was sent to or * received from. * @param unread Whether the message has been read or has not, true the * message is unread, false otherwise. */ public void addNewMessage(Message message, String number, boolean unread) { number = SMSUtility.format(number); addMessageRow(getNumberId(number), message); if (unread) { updateMessageCount(number, getUnreadMessageCount(number)+1); } } /** * Add a row to the shared_information table. * @param reference : int the id of the contact * @param s1 The first shared information * @param s2 The second shared information */ private void addSharedInfo (long reference, String s1, String s2) { ContentValues cv = new ContentValues(); //add given values to a row cv.put(SQLitehelper.KEY_REFERENCE, reference); cv.put(SQLitehelper.KEY_SHARED_INFO_1, s1); cv.put(SQLitehelper.KEY_SHARED_INFO_2, s2); //Insert the row into the database context.getContentResolver().insert( DatabaseProvider.SHARED_INFO_CONTENT_URI, cv); } /** * Used for updating the shared information * @param reference : int the id of the contact * @param s1 The first shared information * @param s2 The second shared information */ public void updateSharedInfo(long reference, String s1, String s2) { ContentValues cv = new ContentValues(); //add given values to a row cv.put(SQLitehelper.KEY_REFERENCE, reference); cv.put(SQLitehelper.KEY_SHARED_INFO_1, s1); cv.put(SQLitehelper.KEY_SHARED_INFO_2, s2); //Insert the row into the database context.getContentResolver().update(DatabaseProvider.SHARED_INFO_CONTENT_URI, cv, SQLitehelper.KEY_REFERENCE + " = " + reference, null); } /** * Used to retrieve the shared information * @param reference The reference id for the contact * @return Both pieces of shared information for that contact (s1 and s2) */ public String[] getSharedInfo(long reference) { Cursor cur = context.getContentResolver().query(DatabaseProvider.SHARED_INFO_CONTENT_URI, new String[] {SQLitehelper.KEY_REFERENCE, SQLitehelper.KEY_SHARED_INFO_1, SQLitehelper.KEY_SHARED_INFO_2}, SQLitehelper.KEY_REFERENCE + " = " + reference, null, null); if (cur.moveToFirst()) { //Found the reference number in the database String sharedInfo[] = new String[] {cur.getString(cur.getColumnIndex (SQLitehelper.KEY_SHARED_INFO_1)), cur.getString(cur. getColumnIndex(SQLitehelper.KEY_SHARED_INFO_2))}; cur.close(); return sharedInfo; } cur.close(); return new String[] { null, null }; } /** * Add a row to the shared_information table. * @param reference The id of the contact * @param bookPath The path for looking up the book source * @param bookInversePath The path for looking up the inverse book source */ private void addBookPath (long reference, String bookPath, String bookInversePath) { ContentValues cv = new ContentValues(); //add given values to a row cv.put(SQLitehelper.KEY_REFERENCE, reference); if(bookPath.equalsIgnoreCase("") || bookPath.equalsIgnoreCase(DEFAULT_BOOK_PATH)) { bookPath = DBAccessor.DEFAULT_BOOK_PATH; } cv.put(SQLitehelper.KEY_BOOK_PATH, bookPath); if(bookInversePath.equalsIgnoreCase("") || bookInversePath.equalsIgnoreCase(DEFAULT_BOOK_INVERSE_PATH)) { bookInversePath = DBAccessor.DEFAULT_BOOK_INVERSE_PATH; } cv.put(SQLitehelper.KEY_BOOK_INVERSE_PATH, bookInversePath); //Insert the row into the database context.getContentResolver().insert(DatabaseProvider.BOOK_PATHS_CONTENT_URI, cv); } /** * Sets the book path back to the default path * @param reference The id of the contact */ public void resetBookPath (long reference) { if (!bookIsDefault(reference)) { context.getContentResolver().delete(DatabaseProvider.BOOK_PATHS_CONTENT_URI, SQLitehelper.KEY_REFERENCE + " = " + reference, null); } } /** * Used for updating the book paths. * @param reference The id of the contact. * @param bookPath The path for looking up the book source. * @param bookInversePath The path for looking up the inverse book source. */ public void updateBookPaths(long reference, String bookPath, String bookInversePath) { resetBookPath(reference); if(bookPath != null && bookInversePath != null) { if(((!bookPath.equalsIgnoreCase("") || !bookInversePath.equalsIgnoreCase("")) && (!bookPath.equalsIgnoreCase(DEFAULT_BOOK_PATH)) || !bookInversePath.equalsIgnoreCase(DEFAULT_BOOK_INVERSE_PATH))) { addBookPath(reference, bookPath, bookInversePath); } } } /** * Finds out whether the contact has an entry in the book path database. * @param reference The id of the contact. * @return True if the book path is the default, false otherwise. */ private boolean bookIsDefault(long reference) { Cursor cur = context.getContentResolver().query(DatabaseProvider.BOOK_PATHS_CONTENT_URI, new String[] {SQLitehelper.KEY_REFERENCE, SQLitehelper.KEY_BOOK_PATH, SQLitehelper.KEY_BOOK_INVERSE_PATH}, SQLitehelper.KEY_REFERENCE + " = " + reference, null, null); if (cur.moveToFirst()) { cur.close(); return false; } cur.close(); return true; } /** * Used to retrieve the book paths * @param reference The id of the contact * @return The book path, and the book inverse path */ public String[] getBookPath(long reference) { Cursor cur = context.getContentResolver().query(DatabaseProvider.BOOK_PATHS_CONTENT_URI, new String[] {SQLitehelper.KEY_REFERENCE, SQLitehelper.KEY_BOOK_PATH, SQLitehelper.KEY_BOOK_INVERSE_PATH}, SQLitehelper.KEY_REFERENCE + " = " + reference, null, null); if (cur.moveToFirst()) { //Found the reference number in the database String bookPaths[] = new String[] {cur.getString(cur.getColumnIndex(SQLitehelper.KEY_BOOK_PATH)), cur.getString(cur.getColumnIndex(SQLitehelper.KEY_BOOK_INVERSE_PATH))}; cur.close(); return bookPaths; } cur.close(); return new String[] { DEFAULT_BOOK_PATH, DEFAULT_BOOK_INVERSE_PATH }; } /** * Adds a trusted contact to the database * @param tc The TrustedContact that contains all the information about the * contact. */ public void addRow (TrustedContact tc) { if (!inDatabase(tc.getNumber())) { ContentValues cv = new ContentValues(); //add given values to a row cv.put(SQLitehelper.KEY_NAME, tc.getName()); //Insert the row into the database long id = Long.valueOf(context.getContentResolver().insert(DatabaseProvider .TRUSTED_CONTENT_URI, cv).getLastPathSegment()); if (!tc.isNumbersEmpty()) { for (int i = 0; i< tc.getNumber().size();i++) { long id2 = addNumbersRow(id, tc.getNumber().get(i)); for (int j = 0; j < tc.getNumber().get(i).getMessages().size(); j++) { addMessageRow(id2, tc.getNumber().get(i).getMessage(j)); } } } } } /** * Returns the id of the contact with the given number * @param number The number of the contact * @return :The id for the contact with the given number */ private long getId(String number) { Cursor cur = context.getContentResolver().query(DatabaseProvider.NUMBER_CONTENT_URI, new String[]{SQLitehelper.KEY_REFERENCE}, SQLitehelper.KEY_NUMBER + " = ?", new String[] {number}, null); if (cur.moveToFirst()) { long id = cur.getInt(cur.getColumnIndex((SQLitehelper.KEY_REFERENCE))); cur.close(); return id; } cur.close(); return 0; } /** * Get the number's id to use as a reference for the message table. * @param number The number. * @return The id number of the number. * If there is no number in the database it will return 0 */ private long getNumberId(String number) { Cursor cur = context.getContentResolver().query(DatabaseProvider.NUMBER_CONTENT_URI, new String[]{SQLitehelper.KEY_ID}, SQLitehelper.KEY_NUMBER + " = ?", new String[] {number}, null); if (cur.moveToFirst()) { long id = cur.getInt(cur.getColumnIndex((SQLitehelper.KEY_ID))); cur.close(); return id; } cur.close(); return 0; } /** * Get the number give the id for the that number in the database. * @param id The id of the number in the database. * @return The number that is stored at the given id. */ private String getNumber(long id) { Cursor cur = context.getContentResolver().query(DatabaseProvider.NUMBER_CONTENT_URI, new String[]{SQLitehelper.KEY_NUMBER}, SQLitehelper.KEY_ID + " = " + id, null, null); if (cur.moveToFirst()) { //long id = cur.getInt(cur.getColumnIndex((KEY_ID))); String number = cur.getString(cur.getColumnIndex(SQLitehelper.KEY_NUMBER)); cur.close(); return number; } cur.close(); return null; } /** * Check to see if any of the given numbers is already in the database * @param number The list of numbers to check of numbers * @return true if at least one of the numbers is already in the database, * false otherwise. */ public boolean inDatabase(ArrayList<Number> number) { for (int i = 0; i < number.size(); i++) { if (inDatabase(number.get(i).getNumber())) { return true; } } return false; } /** * Checks if the contact is already in the database. * @param number The number that is to look for. * @return True if the number is in the database already, false otherwise. */ public boolean inDatabase(String number) { Cursor idCur = context.getContentResolver().query(DatabaseProvider.NUMBER_CONTENT_URI, new String[]{SQLitehelper.KEY_REFERENCE, SQLitehelper.KEY_NUMBER}, SQLitehelper.KEY_NUMBER + " = ?", new String[] {SMSUtility.format(number)}, null); long id = 0; if (idCur.moveToFirst()) { id = idCur.getInt(idCur.getColumnIndex(SQLitehelper.KEY_REFERENCE)); } idCur.close(); Cursor cur = context.getContentResolver().query(DatabaseProvider.TRUSTED_CONTENT_URI, new String[]{SQLitehelper.KEY_NAME}, SQLitehelper.KEY_ID + " = " + id, null, null); if (cur.moveToFirst()) { cur.close(); return true; } cur.close(); return false; } /** * Get all of the messages sent and received from the given number. * @param number The number whose messages are going to be retrieved. * @return A list of containing all the important information about the * messages. */ public List<String[]> getSMSList(String number) { List<String[]> smsList = new ArrayList<String[]>(); String reversed = ""; /* Reverse the order of the list when loading. */ if (sharedPrefs.getBoolean(QuickPrefsActivity.REVERSE_MESSAGE_ORDERING_KEY, false)) { reversed = " DESC"; } Cursor cur = context.getContentResolver().query(DatabaseProvider.TNM_CONTENT_URI, new String[]{ SQLitehelper.TRUSTED_TABLE_NAME + "." + SQLitehelper.KEY_NAME, SQLitehelper.MESSAGES_TABLE_NAME + "." + SQLitehelper.KEY_MESSAGE, SQLitehelper.MESSAGES_TABLE_NAME + "." + SQLitehelper.KEY_SENT, SQLitehelper.MESSAGES_TABLE_NAME + "." + SQLitehelper.KEY_DATE, SQLitehelper.MESSAGES_TABLE_NAME + "." + SQLitehelper.KEY_ID}, SQLitehelper.TRUSTED_TABLE_NAME + "." + SQLitehelper.KEY_ID + " = " + SQLitehelper.NUMBERS_TABLE_NAME + "." + SQLitehelper.KEY_REFERENCE + " AND " + SQLitehelper.NUMBERS_TABLE_NAME + "." + SQLitehelper.KEY_ID + " = " + SQLitehelper.MESSAGES_TABLE_NAME + "." + SQLitehelper.KEY_REFERENCE + " AND " + SQLitehelper.MESSAGES_TABLE_NAME + "." + SQLitehelper.KEY_MESSAGE + " IS NOT NULL AND " + SQLitehelper.NUMBERS_TABLE_NAME + "." + SQLitehelper.KEY_NUMBER + " = ?", new String[]{ SMSUtility.format(number)}, SQLitehelper.MESSAGES_TABLE_NAME + "." + SQLitehelper.KEY_DATE + reversed); if (cur.moveToFirst()) { do { String name = USER_NAME; int sentFlag = cur.getInt(cur.getColumnIndex(SQLitehelper.KEY_SENT)); if (sentFlag >= Message.RECEIVED_DEFAULT && sentFlag <= Message.RECEIVED_ENC_OBF_FAIL || (sentFlag >= Message.RECEIVED_KEY_EXCHANGE_INIT && sentFlag <= Message.RECEIVED_KEY_EXCHANGE_INIT_RESP)) { name = cur.getString(cur.getColumnIndex(SQLitehelper.KEY_NAME)); } //Locale a = ; String message = cur.getString(cur.getColumnIndex(SQLitehelper.KEY_MESSAGE)); String date = Message.millisToDate(cur.getLong(cur.getColumnIndex(SQLitehelper.KEY_DATE)), context.getResources().getConfiguration().locale); String id = String.valueOf(cur.getLong(cur.getColumnIndex(SQLitehelper.KEY_ID))); String sent = String.valueOf(sentFlag); //String count = cur.getString(cur.getColumnIndex(KEY_UNREAD)); smsList.add(new String[]{name, message, date, id, sent}); }while(cur.moveToNext()); } cur.close(); return smsList; } /** * Get all of the last messages sent from every contact. * @return The list of information needed to display the conversations. */ public List<String[]> getConversations() { Cursor cur = context.getContentResolver().query(DatabaseProvider.QUERY_CONTENT_URI, new String[]{SQLitehelper.KEY_NAME, SQLitehelper.KEY_NUMBER, SQLitehelper.KEY_UNREAD, SQLitehelper.KEY_MESSAGE, SQLitehelper.KEY_SENT}, null, null, SQLitehelper.KEY_DATE + " DESC"); List<String[]> sms = new ArrayList<String[]>(); while (cur.moveToNext()) { String address = cur.getString(cur.getColumnIndex(SQLitehelper.KEY_NUMBER)); String count = cur.getString(cur.getColumnIndex(SQLitehelper.KEY_UNREAD)); String name = cur.getString(cur.getColumnIndex(SQLitehelper.KEY_NAME)); int type = cur.getInt(cur.getColumnIndex(SQLitehelper.KEY_SENT)); String message = cur.getString(cur.getColumnIndex(SQLitehelper.KEY_MESSAGE)); sms.add(new String[] {address, name, message, count, String.valueOf(type)}); } cur.close(); return sms; } /** * Get a Number from the database given the number. This method is met to * simplify transactions that require only the contact's Number and no other * information. It is a less expensive query * @param number The contact's number * @return The Number containing all the relevant information about the * contact's number */ public Number getNumber(String number) { Cursor cur = context.getContentResolver().query(DatabaseProvider.NUMBER_CONTENT_URI, new String[]{SQLitehelper.KEY_ID, SQLitehelper.KEY_NUMBER, SQLitehelper.KEY_DRAFT, SQLitehelper.KEY_TYPE, SQLitehelper.KEY_UNREAD, SQLitehelper.KEY_PUBLIC_KEY, SQLitehelper.KEY_SIGNATURE, SQLitehelper.KEY_NONCE_ENCRYPT, SQLitehelper.KEY_NONCE_DECRYPT, SQLitehelper.KEY_INITIATOR, SQLitehelper.KEY_EXCHANGE_SETTING}, SQLitehelper.KEY_NUMBER + " = ?", new String[]{number}, null); if(cur.moveToFirst()) { Number returnNumber = new Number(cur.getLong(cur.getColumnIndex(SQLitehelper.KEY_ID)), cur.getString(cur.getColumnIndex(SQLitehelper.KEY_NUMBER)), cur.getString(cur.getColumnIndex(SQLitehelper.KEY_DRAFT)), cur.getInt(cur.getColumnIndex(SQLitehelper.KEY_TYPE)), cur.getInt(cur.getColumnIndex(SQLitehelper.KEY_UNREAD)), cur.getBlob(cur.getColumnIndex(SQLitehelper.KEY_PUBLIC_KEY)), cur.getBlob(cur.getColumnIndex(SQLitehelper.KEY_SIGNATURE)), cur.getInt(cur.getColumnIndex(SQLitehelper.KEY_NONCE_ENCRYPT)), cur.getInt(cur.getColumnIndex(SQLitehelper.KEY_NONCE_DECRYPT)), cur.getInt(cur.getColumnIndex(SQLitehelper.KEY_INITIATOR)), cur.getInt(cur.getColumnIndex(SQLitehelper.KEY_EXCHANGE_SETTING))); //Retrieve the book paths returnNumber.setBookPaths(getBookPath(returnNumber.getId())); //Retrieve the shared information returnNumber.setSharedInfo(getSharedInfo(returnNumber.getId())); cur.close(); return returnNumber; } cur.close(); return null; } /** * Retrieve the information relating to the contact who has the given * number. This does not however retrieve the messages of each particular * contact's number. * @param number The number of the contact to retrieve * @return The TrustedContact containing all the information in the database * about that contact. */ public TrustedContact getRow(String number) { // Get the id of the number to look up the contact. Cursor idCur = context.getContentResolver().query(DatabaseProvider.NUMBER_CONTENT_URI, new String[]{SQLitehelper.KEY_REFERENCE}, SQLitehelper.KEY_NUMBER + " = ?", new String[] {number}, null); long id = 0; long num_id = 0; int i = 0; if (idCur.moveToFirst()) { id = idCur.getInt(idCur.getColumnIndex(SQLitehelper.KEY_REFERENCE)); } idCur.close(); // Find the contact from the TrustedContact table Cursor cur = context.getContentResolver().query(DatabaseProvider.TRUSTED_CONTENT_URI, new String[]{SQLitehelper.KEY_NAME}, SQLitehelper.KEY_ID +" = " + id, null, null); if (cur.moveToFirst()) { TrustedContact tc = new TrustedContact (cur.getString(cur.getColumnIndex(SQLitehelper.KEY_NAME))); cur.close(); // Query the number table to access the number information. Cursor pCur = context.getContentResolver().query(DatabaseProvider.TN_CONTENT_URI, null, SQLitehelper.TRUSTED_TABLE_NAME + "." + SQLitehelper.KEY_ID + " = " + SQLitehelper.NUMBERS_TABLE_NAME + "." + SQLitehelper.KEY_REFERENCE + " AND " + SQLitehelper.TRUSTED_TABLE_NAME + "." + SQLitehelper.KEY_ID + " = " + id, null, null); if (pCur.moveToFirst()) { i = 0; do { num_id = pCur.getLong(pCur.getColumnIndex(SQLitehelper.KEY_ID)); tc.addNumber(new Number (num_id, pCur.getString(pCur.getColumnIndex(SQLitehelper.KEY_NUMBER)), pCur.getString(pCur.getColumnIndex(SQLitehelper.KEY_DRAFT)), pCur.getInt(pCur.getColumnIndex(SQLitehelper.KEY_TYPE)), pCur.getInt(pCur.getColumnIndex(SQLitehelper.KEY_UNREAD)), pCur.getBlob(pCur.getColumnIndex(SQLitehelper.KEY_PUBLIC_KEY)), pCur.getBlob(pCur.getColumnIndex(SQLitehelper.KEY_SIGNATURE)), pCur.getInt(pCur.getColumnIndex(SQLitehelper.KEY_NONCE_ENCRYPT)), pCur.getInt(pCur.getColumnIndex(SQLitehelper.KEY_NONCE_DECRYPT)), pCur.getInt(pCur.getColumnIndex(SQLitehelper.KEY_INITIATOR)), pCur.getInt(pCur.getColumnIndex(SQLitehelper.KEY_EXCHANGE_SETTING)))); //Retrieve the book paths tc.getNumber().get(i).setBookPaths(getBookPath(num_id)); //Retrieve the shared information tc.getNumber().get(i).setSharedInfo(getSharedInfo(num_id)); i++; }while(pCur.moveToNext()); } pCur.close(); return tc; } cur.close(); return null; } public boolean anyTrusted() { Cursor cur = context.getContentResolver().query(DatabaseProvider.NUMBER_CONTENT_URI, new String[]{SQLitehelper.KEY_ID}, SQLitehelper.KEY_PUBLIC_KEY + " IS NOT NULL" , null, null); if(cur != null) { if (cur.moveToFirst()) { if(cur.getCount()> 0) { cur.close(); return true; } cur.close(); } } return false; } /** * Get all of the rows in the database with the columns * @param select Whether to get trusted, untrusted or all contacts. * @return The list of all the contacts in the database with all relevant * information about them. */ public ArrayList<TrustedContact> getAllRows(int select) { String selectString = ""; if (select == TRUSTED) { selectString = " AND " + SQLitehelper.NUMBERS_TABLE_NAME + "." + SQLitehelper.KEY_PUBLIC_KEY + " NOT NULL"; } else if (select == UNTRUSTED) { selectString = " AND " + SQLitehelper.NUMBERS_TABLE_NAME + "." + SQLitehelper.KEY_PUBLIC_KEY + " IS NULL"; } Cursor cur = context.getContentResolver().query(DatabaseProvider.TN_CONTENT_URI, new String[]{ SQLitehelper.TRUSTED_TABLE_NAME + ".*", SQLitehelper.NUMBERS_TABLE_NAME + "." + SQLitehelper.KEY_NUMBER, SQLitehelper.NUMBERS_TABLE_NAME + "." + SQLitehelper.KEY_PUBLIC_KEY}, SQLitehelper.TRUSTED_TABLE_NAME + "." + SQLitehelper.KEY_ID + " = " + SQLitehelper.NUMBERS_TABLE_NAME + "." + SQLitehelper.KEY_REFERENCE + selectString, null, SQLitehelper.TRUSTED_TABLE_NAME + "." + SQLitehelper.KEY_ID); ArrayList<TrustedContact> tc = new ArrayList<TrustedContact>(); if (cur.moveToFirst()) { // Set to 0 so that the first contact's id will be unqiue. long prevContId = 0; // Since the prevContId is setting to increment i by 1 the index // must be set to -1 to all for the index to properly be used int i = -1; do { long curContId = cur.getLong(cur.getColumnIndex(SQLitehelper.KEY_ID)); // Only add the contact as a new trusted contact if they are not already in the database. if (prevContId != curContId) { tc.add(new TrustedContact (cur.getString(cur.getColumnIndex(SQLitehelper.KEY_NAME)))); prevContId = curContId; i++; } tc.get(i).addNumber(new Number (cur.getString(cur.getColumnIndex(SQLitehelper.KEY_NUMBER)), cur.getBlob(cur.getColumnIndex(SQLitehelper.KEY_PUBLIC_KEY)))); }while (cur.moveToNext()); cur.close(); return tc; } cur.close(); return null; } /** * Get number of messages that are unread for all numbers * @return The number of messages unread for all numbers */ public int getUnreadMessageCount() { Cursor cur = context.getContentResolver().query(DatabaseProvider.NUMBER_CONTENT_URI, new String[]{"SUM("+SQLitehelper.KEY_UNREAD+")"}, null, null, SQLitehelper.KEY_ID); int count = 0; if (cur.moveToFirst()) { count = cur.getInt(0); } cur.close(); return count; } /** * Get the unread message count for a given number * @param number A number * @return The number of unread messages */ public int getUnreadMessageCount(String number) { if(number != null) { Cursor cur = context.getContentResolver().query(DatabaseProvider.NUMBER_CONTENT_URI, new String[]{SQLitehelper.KEY_UNREAD}, SQLitehelper.KEY_NUMBER + " = ?", new String[]{SMSUtility.format(number)}, SQLitehelper.KEY_ID); int count = 0; if (cur != null && cur.moveToFirst()) { count = cur.getInt(cur.getColumnIndex(SQLitehelper.KEY_UNREAD)); } cur.close(); return count; } return -1; } /** * Store the user's public key, private key and signature. * @param user The user object that contains the public and private key, and * the signature. */ public void setUser(User user) { //if (!isKeyGen()) //{ ContentValues cv = new ContentValues(); //add given values to a row cv.put(SQLitehelper.KEY_PUBLIC_KEY, user.getPublicKey()); cv.put(SQLitehelper.KEY_PRIVATE_KEY, user.getPrivateKey()); //Insert the row into the database context.getContentResolver().insert(DatabaseProvider.USER_CONTENT_URI, cv); //} } /** * Get the user's public key, private key and signature * @return The user that contains the public and private key, and the * signature. */ public User getUserRow() { Cursor cur = context.getContentResolver().query(DatabaseProvider.USER_CONTENT_URI, new String[] {SQLitehelper.KEY_PUBLIC_KEY, SQLitehelper.KEY_PRIVATE_KEY}, null, null, null); if(cur == null) { return null; } if (cur.moveToFirst()) { User user = new User(cur.getBlob(cur.getColumnIndex(SQLitehelper.KEY_PUBLIC_KEY)), cur.getBlob(cur.getColumnIndex(SQLitehelper.KEY_PRIVATE_KEY))); cur.close(); return user; } cur.close(); return null; } /** * Update all of the values in a row * @param tc The new values for the row * @param number The number of the contact in the database */ public void updateRow (TrustedContact tc, String number) { long id = getId(SMSUtility.format(number)); updateTrustedRow(tc, number, id); updateNumberRow(tc.getNumber(), id); } /** * Update all of the values in a row * @param tc The new values for the row * @param number The number of the contact in the database */ public void updateContactInfo (TrustedContact tc, String number) { long id = getId(SMSUtility.format(number)); updateTrustedRow(tc, number, id); updateNumberRowType(tc.getNumber(), id); } /** * Update a TrustedContact row * @param tc The new information to be stored * @param number A number owned by the contact * @param id The id for the contact's database row */ public void updateTrustedRow (TrustedContact tc, String number, long id) { ContentValues cv = new ContentValues(); if (id == 0) { id = getId(SMSUtility.format(number)); } //Trusted Table cv.put(SQLitehelper.KEY_NAME, tc.getName()); context.getContentResolver().update(DatabaseProvider.TRUSTED_CONTENT_URI, cv, SQLitehelper.KEY_ID + " = " + id, null); } /** * Update a row from the Numbers table key * @param Number the number object with the new key */ public void updateKey (Number number) { ContentValues cv = new ContentValues(); long id = getId(number.getNumber()); cv.put(SQLitehelper.KEY_PUBLIC_KEY, number.getPublicKey()); cv.put(SQLitehelper.KEY_SIGNATURE, number.getSignature()); cv.put(SQLitehelper.KEY_INITIATOR, number.getInitiatorInt()); cv.put(SQLitehelper.KEY_NONCE_ENCRYPT, number.getNonceEncrypt()); cv.put(SQLitehelper.KEY_NONCE_DECRYPT, number.getNonceDecrypt()); context.getContentResolver().update(DatabaseProvider.NUMBER_CONTENT_URI, cv, SQLitehelper.KEY_REFERENCE + " = " + id + " AND " + SQLitehelper.KEY_NUMBER + " LIKE ?" , new String[]{number.getNumber()}); } /** * Update a row from the Numbers table initiator * @param Number the number object with the new initiator value */ public void updateInitiator (Number number) { ContentValues cv = new ContentValues(); long id = getId(number.getNumber()); cv.put(SQLitehelper.KEY_INITIATOR, number.getInitiatorInt()); context.getContentResolver().update(DatabaseProvider.NUMBER_CONTENT_URI, cv, SQLitehelper.KEY_REFERENCE + " = " + id + " AND " + SQLitehelper.KEY_NUMBER + " LIKE ?" , new String[]{number.getNumber()}); } /** * Update the Decrypt Nonce count in the database. * @param numb The Number that contains all the contact's security * information with the new decryption nonce to add to the database. */ public void updateDecryptNonce(Number numb) { ContentValues cv = new ContentValues(); cv.put(SQLitehelper.KEY_NONCE_DECRYPT, numb.getNonceDecrypt()); context.getContentResolver().update(DatabaseProvider.NUMBER_CONTENT_URI, cv, SQLitehelper.KEY_NUMBER + " LIKE ? ", new String[]{SMSUtility.format(numb.getNumber())}); } /** * Update the Encrypt Nonce count in the database. * @param numb The Number that contains all the contact's security * information with the new encryption nonce to add to the database. */ public void updateEncryptNonce(Number numb) { ContentValues cv = new ContentValues(); cv.put(SQLitehelper.KEY_NONCE_ENCRYPT, numb.getNonceEncrypt()); context.getContentResolver().update(DatabaseProvider.NUMBER_CONTENT_URI, cv, SQLitehelper.KEY_NUMBER + " LIKE ?", new String[]{SMSUtility.format(numb.getNumber())}); } public boolean deleteNumber(String number) { int count = context.getContentResolver().delete(DatabaseProvider.NUMBER_CONTENT_URI, SQLitehelper.KEY_NUMBER + " LIKE ?", new String[]{number}); if (count > 0) { return true; } return false; } /** * Update a row from the Numbers table * @param tc The new information to be stored * @param number A number owned by the contact * @param id The id for the contact's database row */ public void updateNumberRow(Number numb, String number, long id) { number = SMSUtility.format(number); ContentValues cv = new ContentValues(); if (id == 0) { id = getId(number); } long num_id = getNumberId(number); cv.put(SQLitehelper.KEY_REFERENCE, id); cv.put(SQLitehelper.KEY_NUMBER, numb.getNumber()); cv.put(SQLitehelper.KEY_DRAFT, numb.getDraft()); cv.put(SQLitehelper.KEY_TYPE, numb.getType()); cv.put(SQLitehelper.KEY_UNREAD, numb.getUnreadMessageCount()); cv.put(SQLitehelper.KEY_PUBLIC_KEY, numb.getPublicKey()); cv.put(SQLitehelper.KEY_SIGNATURE, numb.getSignature()); cv.put(SQLitehelper.KEY_NONCE_ENCRYPT, numb.getNonceEncrypt()); cv.put(SQLitehelper.KEY_NONCE_DECRYPT, numb.getNonceDecrypt()); cv.put(SQLitehelper.KEY_INITIATOR, numb.getInitiatorInt()); cv.put(SQLitehelper.KEY_EXCHANGE_SETTING, numb.getKeyExchangeFlag()); context.getContentResolver().update(DatabaseProvider.NUMBER_CONTENT_URI, cv, SQLitehelper.KEY_REFERENCE + " = " + id + " AND " + SQLitehelper.KEY_NUMBER + " LIKE ?" , new String[]{number}); updateBookPaths(num_id, numb.getBookPath(), numb.getBookInversePath()); updateSharedInfo(num_id, numb.getSharedInfo1(), numb.getSharedInfo2()); } /** * Update the draft in the database. * @param number The number of the contact the draft is for. * @param draft The draft of the message. */ public void updateDraft(String number, String draft) { ContentValues cv = new ContentValues(); cv.put(SQLitehelper.KEY_DRAFT, draft); context.getContentResolver().update(DatabaseProvider.NUMBER_CONTENT_URI, cv, SQLitehelper.KEY_NUMBER + " LIKE ?" , new String[]{number}); } /** * Update a row from the Numbers table * @param tc The new information to be stored * @param number A number owned by the contact * @param id The id for the contact's database row */ public void updateNumberRowType (ArrayList<Number> number, long id) { ContentValues cv = new ContentValues(); for(int i = 0; i < number.size(); i++) { cv.put(SQLitehelper.KEY_TYPE, number.get(i).getType()); context.getContentResolver().update(DatabaseProvider.NUMBER_CONTENT_URI, cv, SQLitehelper.KEY_REFERENCE + " = " + id + " AND " + SQLitehelper.KEY_NUMBER + " = ?", new String[]{number.get(i).getNumber()}); cv.clear(); } } /** * Update a row from the Numbers table * @param tc The new information to be stored * @param number A number owned by the contact * @param id The id for the contact's database row */ public void updateNumberRow (ArrayList<Number> number, long id) { ContentValues cv = new ContentValues(); for(int i = 0; i < number.size(); i++) { cv.put(SQLitehelper.KEY_REFERENCE, id); cv.put(SQLitehelper.KEY_NUMBER, number.get(i).getNumber()); cv.put(SQLitehelper.KEY_DRAFT, number.get(i).getDraft()); cv.put(SQLitehelper.KEY_TYPE, number.get(i).getType()); cv.put(SQLitehelper.KEY_UNREAD, number.get(i).getUnreadMessageCount()); cv.put(SQLitehelper.KEY_PUBLIC_KEY, number.get(i).getPublicKey()); cv.put(SQLitehelper.KEY_SIGNATURE, number.get(i).getSignature()); cv.put(SQLitehelper.KEY_NONCE_ENCRYPT, number.get(i).getNonceEncrypt()); cv.put(SQLitehelper.KEY_NONCE_DECRYPT, number.get(i).getNonceDecrypt()); cv.put(SQLitehelper.KEY_INITIATOR, number.get(i).getInitiatorInt()); cv.put(SQLitehelper.KEY_EXCHANGE_SETTING, number.get(i).getKeyExchangeFlag()); int num = context.getContentResolver().update(DatabaseProvider.NUMBER_CONTENT_URI, cv, SQLitehelper.KEY_REFERENCE + " = " + id + " AND " + SQLitehelper.KEY_ID + " = " + number.get(i).getId(), null); cv.clear(); if(num == 0) { addNumbersRow(id, number.get(i)); } } } /** * Deletes the rows with the given number * @param number The primary number of the contact to be deleted * @return True if the contacts were deleted properly, false otherwise. */ public boolean removeRow(String number) { number = SMSUtility.format(number); long id = getId(number); int num = 0; num = context.getContentResolver().delete(DatabaseProvider.TRUSTED_CONTENT_URI, SQLitehelper.KEY_ID + " = " + id, null); if (num == 0) { return false; } return true; } /** * Checks if the given number is a trusted contact's number * @param number The number of the potential trusted contact * @return True if the contact is found in the database and is in the * trusted state, false otherwise. A contact is in the trusted state if they * have a key (!= null) */ public boolean isTrustedContact (String number) { Number trustedNumber = this.getNumber(SMSUtility.format(number)); if (trustedNumber != null) { if (!trustedNumber.isPublicKeyNull()) { return true; } } return false; } /** * @param tc The contact to check for a trusted number * @return True if the contact is trusted, false otherwise. * (NOTE: see isTrustedContact(String number) for more details) */ public boolean isTrustedContact (TrustedContact tc) { for (int i=0;i<tc.getNumber().size();i++) { if(isTrustedContact(tc.getNumber().get(i).getNumber())) { return true; } } return false; } /** * @param contacts The contact to check for a trusted number * @return True if the contact is trusted, false otherwise. * * (NOTE: see isTrustedContact(String number) for more details) */ public boolean[] isNumberTrusted (ArrayList<Number> number) { boolean[] trusted = new boolean[number.size()]; for (int i=0;i<number.size();i++) { trusted[i] = isTrustedContact(number.get(i).getNumber()); } return trusted; } public void updateWalkthrough(WalkthroughStep ws) { ContentValues cv = new ContentValues(); if(ws.get(Step.INTRO) != null) cv.put(SQLitehelper.KEY_INTRO, ws.get(Step.INTRO)); if(ws.get(Step.START_IMPORT) != null) cv.put(SQLitehelper.KEY_START_IMPORT, ws.get(Step.START_IMPORT)); if(ws.get(Step.IMPORT) != null) cv.put(SQLitehelper.KEY_IMPORT, ws.get(Step.IMPORT)); if(ws.get(Step.START_EXCHANGE) != null) cv.put(SQLitehelper.KEY_START_EXCHANGE, ws.get(Step.START_EXCHANGE)); if(ws.get(Step.SET_SECRET) != null) cv.put(SQLitehelper.KEY_SET_SECRET, ws.get(Step.SET_SECRET)); if(ws.get(Step.KEY_SENT) != null) cv.put(SQLitehelper.KEY_KEY_SENT, ws.get(Step.KEY_SENT)); if(ws.get(Step.PENDING) != null) cv.put(SQLitehelper.KEY_PENDING, ws.get(Step.PENDING)); if(ws.get(Step.ACCEPT) != null) cv.put(SQLitehelper.KEY_ACCEPT, ws.get(Step.ACCEPT)); if(ws.get(Step.SUCCESS) != null) cv.put(SQLitehelper.KEY_SUCCESS, ws.get(Step.SUCCESS)); if(ws.get(Step.CLOSE) != null) cv.put(SQLitehelper.KEY_CLOSE, ws.get(Step.CLOSE)); context.getContentResolver().update(DatabaseProvider.WALKTHROUGH_CONTENT_URI, cv, null, null); } public WalkthroughStep getWalkthrough() { Cursor cur = context.getContentResolver().query(DatabaseProvider.WALKTHROUGH_CONTENT_URI, new String[]{SQLitehelper.KEY_INTRO, SQLitehelper.KEY_START_IMPORT, SQLitehelper.KEY_IMPORT, SQLitehelper.KEY_START_EXCHANGE, SQLitehelper.KEY_SET_SECRET, SQLitehelper.KEY_KEY_SENT, SQLitehelper.KEY_PENDING, SQLitehelper.KEY_ACCEPT, SQLitehelper.KEY_SUCCESS, SQLitehelper.KEY_CLOSE}, null, null, null); WalkthroughStep ws = new WalkthroughStep(); if(cur.moveToFirst()) { ws.set(Step.INTRO, cur.getInt(cur.getColumnIndex(SQLitehelper.KEY_INTRO))); ws.set(Step.START_IMPORT, cur.getInt(cur.getColumnIndex(SQLitehelper.KEY_START_IMPORT))); ws.set(Step.IMPORT, cur.getInt(cur.getColumnIndex(SQLitehelper.KEY_IMPORT))); ws.set(Step.START_EXCHANGE, cur.getInt(cur.getColumnIndex(SQLitehelper.KEY_START_EXCHANGE))); ws.set(Step.SET_SECRET, cur.getInt(cur.getColumnIndex(SQLitehelper.KEY_SET_SECRET))); ws.set(Step.KEY_SENT, cur.getInt(cur.getColumnIndex(SQLitehelper.KEY_KEY_SENT))); ws.set(Step.PENDING, cur.getInt(cur.getColumnIndex(SQLitehelper.KEY_PENDING))); ws.set(Step.ACCEPT, cur.getInt(cur.getColumnIndex(SQLitehelper.KEY_ACCEPT))); ws.set(Step.SUCCESS, cur.getInt(cur.getColumnIndex(SQLitehelper.KEY_SUCCESS))); ws.set(Step.CLOSE, cur.getInt(cur.getColumnIndex(SQLitehelper.KEY_CLOSE))); cur.close(); return ws; } cur.close(); return null; } /** * Adding a message to the queue to be sent when there is service to send * the message. Once the message has been sent it will be removed from the * queue. * @param number The number for the contact that the message will be sent * to. * @param message The message that will be sent to the contact with the * given number. */ public synchronized void addMessageToQueue (String number, String message, boolean keyExchange) { long numberReference = getNumberId(number); ContentValues cv = new ContentValues(); cv.put(SQLitehelper.KEY_NUMBER_REFERENCE, numberReference); cv.put(SQLitehelper.KEY_MESSAGE, message); if(keyExchange) { cv.put(SQLitehelper.KEY_EXCHANGE, TRUE); } else { cv.put(SQLitehelper.KEY_EXCHANGE, FALSE); } context.getContentResolver().insert(DatabaseProvider.QUEUE_CONTENT_URI, cv); ConversationView.messageSender.threadNotify(true); } /** * Get the first element within the queue. * *Note the entry is also removed from the queue. * @return The first element in the queue stored in the database. If the * queue is empty then the return is null. */ public synchronized Entry getFirstInQueue () { Cursor cur = context.getContentResolver().query(DatabaseProvider.QUEUE_CONTENT_URI, new String[]{SQLitehelper.KEY_ID, SQLitehelper.KEY_NUMBER_REFERENCE, SQLitehelper.KEY_MESSAGE, SQLitehelper.KEY_EXCHANGE}, SQLitehelper.KEY_ID + " = (SELECT MIN(" + SQLitehelper.KEY_ID + ") FROM " + SQLitehelper.QUEUE_TABLE_NAME +")", null, null); if(cur == null) { return null; } if (cur.moveToFirst()) { long id = cur.getLong(cur.getColumnIndex(SQLitehelper.KEY_ID)); String number = getNumber(cur.getLong(cur.getColumnIndex(SQLitehelper.KEY_NUMBER_REFERENCE))); if(number != null) { Entry entry = new Entry(number, cur.getString(cur.getColumnIndex(SQLitehelper.KEY_MESSAGE)), id, cur.getInt(cur.getColumnIndex(SQLitehelper.KEY_EXCHANGE))); cur.close(); deleteQueueEntry(id); return entry; } } cur.close(); return null; } /** * Delete a given entry from the queue * @param id The private key */ public void deleteQueueEntry (long id) { context.getContentResolver().delete(DatabaseProvider.QUEUE_CONTENT_URI, SQLitehelper.KEY_ID + " = " + id, null); } /** * Delete the first entry in the queue */ public synchronized void deleteFirstQueueEntry() { context.getContentResolver().delete(DatabaseProvider.QUEUE_CONTENT_URI, SQLitehelper.KEY_ID + " = (SELECT MIN(" + SQLitehelper.KEY_ID + ") FROM " + SQLitehelper.QUEUE_TABLE_NAME +")", null); } }