From 356199978eaef303cef7faa90280dafb0425af71 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sun, 14 Feb 2016 18:19:11 +0100 Subject: fixed server info push not showing up when unavailable --- src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/main/java/eu/siacs/conversations') diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java index 9b6e40763..2656966bb 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java @@ -686,9 +686,9 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate this.mServerInfoHttpUpload.setText(R.string.server_info_unavailable); } - this.mPushRow.setVisibility(xmppConnectionService.getPushManagementService().available(mAccount) ? View.VISIBLE : View.GONE); + this.mPushRow.setVisibility(xmppConnectionService.getPushManagementService().isStub() ? View.GONE : View.VISIBLE); - if (features.push()) { + if (xmppConnectionService.getPushManagementService().available(mAccount)) { this.mServerInfoPush.setText(R.string.server_info_available); } else { this.mServerInfoPush.setText(R.string.server_info_unavailable); -- cgit v1.2.3 From 8ccb2005b325d1d26d74c682574008553b6879ad Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sun, 14 Feb 2016 23:53:17 +0100 Subject: only show load more messages button when mam is available also update ui after that button has been pressed. fixes #1695 --- src/main/java/eu/siacs/conversations/ui/ConversationActivity.java | 1 + src/main/java/eu/siacs/conversations/ui/ConversationFragment.java | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'src/main/java/eu/siacs/conversations') diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index 97774650b..5ec2dc97f 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -1606,6 +1606,7 @@ public class ConversationActivity extends XmppActivity public void setMessagesLoaded() { if (mConversationFragment != null) { mConversationFragment.setMessagesLoaded(); + mConversationFragment.updateMessages(); } } } diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index 5874adae3..c555ead03 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -62,6 +62,7 @@ import eu.siacs.conversations.ui.adapter.MessageAdapter.OnContactPictureClicked; import eu.siacs.conversations.ui.adapter.MessageAdapter.OnContactPictureLongClicked; import eu.siacs.conversations.utils.GeoHelper; import eu.siacs.conversations.utils.UIHelper; +import eu.siacs.conversations.xmpp.XmppConnection; import eu.siacs.conversations.xmpp.chatstate.ChatState; import eu.siacs.conversations.xmpp.jid.Jid; @@ -1014,7 +1015,10 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa protected void updateStatusMessages() { synchronized (this.messageList) { - if (conversation.getLastClearHistory() != 0) { + final XmppConnection connection = conversation.getAccount().getXmppConnection(); + if (conversation.getLastClearHistory() != 0 + && connection != null + && connection.getFeatures().mam()) { this.messageList.add(0, Message.createLoadMoreMessage(conversation)); } if (conversation.getMode() == Conversation.MODE_SINGLE) { -- cgit v1.2.3 From c4b1df1bf305a84a972837298106de2674bb1c5c Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 15 Feb 2016 22:12:39 +0100 Subject: add missing type='submit' attribute to enable push form --- src/main/java/eu/siacs/conversations/generator/IqGenerator.java | 1 + 1 file changed, 1 insertion(+) (limited to 'src/main/java/eu/siacs/conversations') diff --git a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java index 258897a19..4395a5460 100644 --- a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java @@ -331,6 +331,7 @@ public class IqGenerator extends AbstractGenerator { Data data = new Data(); data.setFormType("http://jabber.org/protocol/pubsub#publish-options"); data.put("secret",secret); + data.submit(); enable.addChild(data); return packet; } -- cgit v1.2.3 From 335058b78bb20f8234d98fb4f205a1954b25e7e8 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 15 Feb 2016 23:09:42 +0100 Subject: removed unnecessary conditions when sending read marker --- src/main/java/eu/siacs/conversations/ui/ConversationActivity.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'src/main/java/eu/siacs/conversations') diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java index 5ec2dc97f..11e2e8892 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java @@ -366,11 +366,7 @@ public class ConversationActivity extends XmppActivity public void sendReadMarkerIfNecessary(final Conversation conversation) { if (!mActivityPaused && conversation != null) { - if (!conversation.isRead()) { - xmppConnectionService.sendReadMarker(conversation); - } else { - xmppConnectionService.markRead(conversation); - } + xmppConnectionService.sendReadMarker(conversation); } } -- cgit v1.2.3 From c0b3a3ff0c32c8025174ebb92fbcf4a7fc67f497 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 15 Feb 2016 23:15:04 +0100 Subject: basic support for XEP-0308: Last Message Correction. fixes #864 --- .../siacs/conversations/entities/Conversation.java | 20 ++++++ .../eu/siacs/conversations/entities/Message.java | 38 ++++++++++-- .../conversations/generator/AbstractGenerator.java | 1 + .../conversations/generator/MessageGenerator.java | 3 + .../siacs/conversations/parser/MessageParser.java | 61 +++++++++++++----- .../conversations/persistance/DatabaseBackend.java | 14 ++++- .../services/XmppConnectionService.java | 13 ++-- .../conversations/ui/ConversationFragment.java | 72 +++++++++++++++++----- .../eu/siacs/conversations/ui/EditMessage.java | 2 + .../conversations/ui/adapter/MessageAdapter.java | 15 ++++- 10 files changed, 200 insertions(+), 39 deletions(-) (limited to 'src/main/java/eu/siacs/conversations') diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index 53bd19a5f..a0600d130 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -82,6 +82,7 @@ public class Conversation extends AbstractEntity implements Blockable { private ChatState mIncomingChatState = Config.DEFAULT_CHATSTATE; private String mLastReceivedOtrMessageId = null; private String mFirstMamReference = null; + private Message correctingMessage; public boolean hasMessagesLeftOnServer() { return messagesLeftOnServer; @@ -226,6 +227,17 @@ public class Conversation extends AbstractEntity implements Blockable { return null; } + public Message findMessageWithRemoteIdAndCounterpart(String id, Jid counterpart) { + synchronized (this.messages) { + for(Message message : this.messages) { + if(id.equals(message.getRemoteMsgId()) && counterpart.equals(message.getCounterpart())) { + return message; + } + } + } + return null; + } + public Message findSentMessageWithUuid(String id) { synchronized (this.messages) { for (Message message : this.messages) { @@ -294,6 +306,14 @@ public class Conversation extends AbstractEntity implements Blockable { return getLongAttribute("last_clear_history", 0); } + public void setCorrectingMessage(Message correctingMessage) { + this.correctingMessage = correctingMessage; + } + + public Message getCorrectingMessage() { + return this.correctingMessage; + } + public interface OnMessageFound { void onMessageFound(final Message message); } diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index f37ae4271..1f9212fdb 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -52,6 +52,7 @@ public class Message extends AbstractEntity { public static final String STATUS = "status"; public static final String TYPE = "type"; public static final String CARBON = "carbon"; + public static final String EDITED = "edited"; public static final String REMOTE_MSG_ID = "remoteMsgId"; public static final String SERVER_MSG_ID = "serverMsgId"; public static final String RELATIVE_FILE_PATH = "relativeFilePath"; @@ -71,6 +72,7 @@ public class Message extends AbstractEntity { protected int status; protected int type; protected boolean carbon = false; + protected String edited = null; protected String relativeFilePath; protected boolean read = true; protected String remoteMsgId = null; @@ -104,7 +106,8 @@ public class Message extends AbstractEntity { null, null, null, - true); + true, + null); this.conversation = conversation; } @@ -112,7 +115,8 @@ public class Message extends AbstractEntity { final Jid trueCounterpart, final String body, final long timeSent, final int encryption, final int status, final int type, final boolean carbon, final String remoteMsgId, final String relativeFilePath, - final String serverMsgId, final String fingerprint, final boolean read) { + final String serverMsgId, final String fingerprint, final boolean read, + final String edited) { this.uuid = uuid; this.conversationUuid = conversationUUid; this.counterpart = counterpart; @@ -128,6 +132,7 @@ public class Message extends AbstractEntity { this.serverMsgId = serverMsgId; this.axolotlFingerprint = fingerprint; this.read = read; + this.edited = edited; } public static Message fromCursor(Cursor cursor) { @@ -162,12 +167,13 @@ public class Message extends AbstractEntity { cursor.getInt(cursor.getColumnIndex(ENCRYPTION)), cursor.getInt(cursor.getColumnIndex(STATUS)), cursor.getInt(cursor.getColumnIndex(TYPE)), - cursor.getInt(cursor.getColumnIndex(CARBON))>0, + cursor.getInt(cursor.getColumnIndex(CARBON)) > 0, cursor.getString(cursor.getColumnIndex(REMOTE_MSG_ID)), cursor.getString(cursor.getColumnIndex(RELATIVE_FILE_PATH)), cursor.getString(cursor.getColumnIndex(SERVER_MSG_ID)), cursor.getString(cursor.getColumnIndex(FINGERPRINT)), - cursor.getInt(cursor.getColumnIndex(READ)) > 0); + cursor.getInt(cursor.getColumnIndex(READ)) > 0, + cursor.getString(cursor.getColumnIndex(EDITED))); } public static Message createStatusMessage(Conversation conversation, String body) { @@ -211,7 +217,8 @@ public class Message extends AbstractEntity { values.put(RELATIVE_FILE_PATH, relativeFilePath); values.put(SERVER_MSG_ID, serverMsgId); values.put(FINGERPRINT, axolotlFingerprint); - values.put(READ,read); + values.put(READ,read ? 1 : 0); + values.put(EDITED, edited); return values; } @@ -340,10 +347,22 @@ public class Message extends AbstractEntity { this.carbon = carbon; } + public void setEdited(String edited) { + this.edited = edited; + } + + public boolean edited() { + return this.edited != null; + } + public void setTrueCounterpart(Jid trueCounterpart) { this.trueCounterpart = trueCounterpart; } + public Jid getTrueCounterpart() { + return this.trueCounterpart; + } + public Transferable getTransferable() { return this.transferable; } @@ -421,6 +440,7 @@ public class Message extends AbstractEntity { this.getEncryption() == message.getEncryption() && this.getCounterpart() != null && this.getCounterpart().equals(message.getCounterpart()) && + this.edited() == message.edited() && (message.getTimeSent() - this.getTimeSent()) <= (Config.MESSAGE_MERGE_WINDOW * 1000) && !GeoHelper.isGeoUri(message.getBody()) && !GeoHelper.isGeoUri(this.body) && @@ -510,6 +530,14 @@ public class Message extends AbstractEntity { } } + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public String getEditedId() { + return edited; + } + public enum Decision { MUST, SHOULD, diff --git a/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java b/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java index d50596056..d223ab842 100644 --- a/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java @@ -31,6 +31,7 @@ public abstract class AbstractGenerator { "urn:xmpp:avatar:metadata+notify", "http://jabber.org/protocol/nick+notify", "urn:xmpp:ping", + "urn:xmpp:message-correct:0", "jabber:iq:version", "http://jabber.org/protocol/chatstates", AxolotlService.PEP_DEVICE_LIST+"+notify"}; diff --git a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java index b849f56f4..0e7a8ce6e 100644 --- a/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/MessageGenerator.java @@ -47,6 +47,9 @@ public class MessageGenerator extends AbstractGenerator { } packet.setFrom(account.getJid()); packet.setId(message.getUuid()); + if (message.edited()) { + packet.addChild("replace","urn:xmpp:message-correct:0").setAttribute("id",message.getEditedId()); + } return packet; } diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index 3bf488316..18edfdeb5 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -297,6 +297,8 @@ public class MessageParser extends AbstractParser implements final String body = packet.getBody(); final Element mucUserElement = packet.findChild("x", "http://jabber.org/protocol/muc#user"); final String pgpEncrypted = packet.findChildContent("x", "jabber:x:encrypted"); + final Element replaceElement = packet.findChild("replace","urn:xmpp:message-correct:0"); + final String replacementId = replaceElement == null ? null : replaceElement.getAttribute("id"); final Element axolotlEncrypted = packet.findChild(XmppAxolotlMessage.CONTAINERTAG, AxolotlService.PEP_PREFIX); int status; final Jid counterpart; @@ -390,6 +392,33 @@ public class MessageParser extends AbstractParser implements } else { updateLastseen(timestamp, account, packet.getFrom(), true); } + + if (replacementId != null) { + Message replacedMessage = conversation.findMessageWithRemoteIdAndCounterpart(replacementId, counterpart); + if (replacedMessage != null) { + final boolean fingerprintsMatch = replacedMessage.getAxolotlFingerprint() == null + || replacedMessage.getAxolotlFingerprint().equals(message.getAxolotlFingerprint()); + final boolean trueCountersMatch = replacedMessage.getTrueCounterpart() != null + && replacedMessage.getTrueCounterpart().equals(message.getTrueCounterpart()); + if (fingerprintsMatch && (trueCountersMatch || conversation.getMode() == Conversation.MODE_SINGLE)) { + Log.d(Config.LOGTAG, "replaced message '" + replacedMessage.getBody() + "' with '" + message.getBody() + "'"); + replacedMessage.setBody(message.getBody()); + replacedMessage.setEdited(replacedMessage.getRemoteMsgId()); + replacedMessage.setRemoteMsgId(remoteMsgId); + if (replacedMessage.getStatus() == Message.STATUS_RECEIVED) { + replacedMessage.markUnread(); + } + mXmppConnectionService.updateMessage(replacedMessage); + if (mXmppConnectionService.confirmMessages() && remoteMsgId != null && !isForwarded && !isTypeGroupChat) { + sendMessageReceipts(account, packet); + } + return; + } else { + Log.d(Config.LOGTAG,account.getJid().toBareJid()+": received message correction but verification didn't check out"); + } + } + } + boolean checkForDuplicates = query != null || (isTypeGroupChat && packet.hasChild("delay","urn:xmpp:delay")) || message.getType() == Message.TYPE_PRIVATE; @@ -420,20 +449,7 @@ public class MessageParser extends AbstractParser implements } if (mXmppConnectionService.confirmMessages() && remoteMsgId != null && !isForwarded && !isTypeGroupChat) { - ArrayList receiptsNamespaces = new ArrayList<>(); - if (packet.hasChild("markable", "urn:xmpp:chat-markers:0")) { - receiptsNamespaces.add("urn:xmpp:chat-markers:0"); - } - if (packet.hasChild("request", "urn:xmpp:receipts")) { - receiptsNamespaces.add("urn:xmpp:receipts"); - } - if (receiptsNamespaces.size() > 0) { - MessagePacket receipt = mXmppConnectionService.getMessageGenerator().received(account, - packet, - receiptsNamespaces, - packet.getType()); - mXmppConnectionService.sendMessagePacket(account, receipt); - } + sendMessageReceipts(account, packet); } if (message.getStatus() == Message.STATUS_RECEIVED @@ -524,4 +540,21 @@ public class MessageParser extends AbstractParser implements contact.setPresenceName(nick); } } + + private void sendMessageReceipts(Account account, MessagePacket packet) { + ArrayList receiptsNamespaces = new ArrayList<>(); + if (packet.hasChild("markable", "urn:xmpp:chat-markers:0")) { + receiptsNamespaces.add("urn:xmpp:chat-markers:0"); + } + if (packet.hasChild("request", "urn:xmpp:receipts")) { + receiptsNamespaces.add("urn:xmpp:receipts"); + } + if (receiptsNamespaces.size() > 0) { + MessagePacket receipt = mXmppConnectionService.getMessageGenerator().received(account, + packet, + receiptsNamespaces, + packet.getType()); + mXmppConnectionService.sendMessagePacket(account, receipt); + } + } } diff --git a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java index 2f28a30ff..dcba4f748 100644 --- a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java @@ -51,7 +51,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { private static DatabaseBackend instance = null; private static final String DATABASE_NAME = "history"; - private static final int DATABASE_VERSION = 23; + private static final int DATABASE_VERSION = 24; private static String CREATE_CONTATCS_STATEMENT = "create table " + Contact.TABLENAME + "(" + Contact.ACCOUNT + " TEXT, " @@ -161,6 +161,7 @@ public class DatabaseBackend extends SQLiteOpenHelper { + Message.SERVER_MSG_ID + " TEXT, " + Message.FINGERPRINT + " TEXT, " + Message.CARBON + " INTEGER, " + + Message.EDITED + " TEXT, " + Message.READ + " NUMBER DEFAULT 1, " + Message.REMOTE_MSG_ID + " TEXT, FOREIGN KEY(" + Message.CONVERSATION + ") REFERENCES " @@ -370,6 +371,10 @@ public class DatabaseBackend extends SQLiteOpenHelper { if (oldVersion < 23 && newVersion >= 23) { db.execSQL(CREATE_DISCOVERY_RESULTS_STATEMENT); } + + if (oldVersion < 24 && newVersion >= 24) { + db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN " + Message.EDITED + " TEXT"); + } } public static synchronized DatabaseBackend getInstance(Context context) { @@ -586,6 +591,13 @@ public class DatabaseBackend extends SQLiteOpenHelper { + "=?", args); } + public void updateMessage(Message message, String uuid) { + SQLiteDatabase db = this.getWritableDatabase(); + String[] args = {uuid}; + db.update(Message.TABLENAME, message.getContentValues(), Message.UUID + + "=?", args); + } + public void readRoster(Roster roster) { SQLiteDatabase db = this.getReadableDatabase(); Cursor cursor; diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 16d7f139c..10f6b5efd 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -841,8 +841,9 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa final Conversation conversation = message.getConversation(); account.deactivateGracePeriod(); MessagePacket packet = null; - final boolean addToConversation = conversation.getMode() != Conversation.MODE_MULTI - || account.getServerIdentity() != XmppConnection.Identity.SLACK; + final boolean addToConversation = (conversation.getMode() != Conversation.MODE_MULTI + || account.getServerIdentity() != XmppConnection.Identity.SLACK) + && !message.edited(); boolean saveInDb = addToConversation; message.setStatus(Message.STATUS_WAITING); @@ -966,8 +967,12 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa if (addToConversation) { conversation.add(message); } - if (saveInDb && (message.getEncryption() == Message.ENCRYPTION_NONE || saveEncryptedMessages())) { - databaseBackend.createMessage(message); + if (message.getEncryption() == Message.ENCRYPTION_NONE || saveEncryptedMessages()) { + if (saveInDb) { + databaseBackend.createMessage(message); + } else if (message.edited()) { + databaseBackend.updateMessage(message, message.getEditedId()); + } } updateConversationUi(); } diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index c555ead03..6ead99625 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -8,7 +8,6 @@ import android.content.ActivityNotFoundException; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; -import android.content.IntentSender; import android.content.IntentSender.SendIntentException; import android.os.Bundle; import android.support.annotation.Nullable; @@ -40,6 +39,7 @@ import net.java.otr4j.session.SessionStatus; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.UUID; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; @@ -51,7 +51,6 @@ import eu.siacs.conversations.entities.DownloadableFile; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.MucOptions; import eu.siacs.conversations.entities.Presence; -import eu.siacs.conversations.entities.Presences; import eu.siacs.conversations.entities.Transferable; import eu.siacs.conversations.entities.TransferablePlaceholder; import eu.siacs.conversations.services.XmppConnectionService; @@ -294,8 +293,14 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa activity.attachFile(ConversationActivity.ATTACHMENT_CHOICE_CHOOSE_IMAGE); break; case CANCEL: - if (conversation != null && conversation.getMode() == Conversation.MODE_MULTI) { - conversation.setNextCounterpart(null); + if (conversation != null) { + if (conversation.getCorrectingMessage() != null) { + conversation.setCorrectingMessage(null); + mEditMessage.getEditableText().clear(); + } + if (conversation.getMode() == Conversation.MODE_MULTI) { + conversation.setNextCounterpart(null); + } updateChatMsgHint(); updateSendButton(); } @@ -330,12 +335,21 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa if (body.length() == 0 || this.conversation == null) { return; } - Message message = new Message(conversation, body, conversation.getNextEncryption()); - if (conversation.getMode() == Conversation.MODE_MULTI) { - if (conversation.getNextCounterpart() != null) { - message.setCounterpart(conversation.getNextCounterpart()); - message.setType(Message.TYPE_PRIVATE); + final Message message; + if (conversation.getCorrectingMessage() == null) { + message = new Message(conversation, body, conversation.getNextEncryption()); + if (conversation.getMode() == Conversation.MODE_MULTI) { + if (conversation.getNextCounterpart() != null) { + message.setCounterpart(conversation.getNextCounterpart()); + message.setType(Message.TYPE_PRIVATE); + } } + } else { + message = conversation.getCorrectingMessage(); + message.setBody(body); + message.setEdited(message.getUuid()); + message.setUuid(UUID.randomUUID().toString()); + conversation.setCorrectingMessage(null); } switch (conversation.getNextEncryption()) { case Message.ENCRYPTION_OTR: @@ -356,7 +370,9 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa public void updateChatMsgHint() { final boolean multi = conversation.getMode() == Conversation.MODE_MULTI; - if (multi && conversation.getNextCounterpart() != null) { + if (conversation.getCorrectingMessage() != null) { + this.mEditMessage.setHint(R.string.send_corrected_message); + } else if (multi && conversation.getNextCounterpart() != null) { this.mEditMessage.setHint(getString( R.string.send_private_message_to, conversation.getNextCounterpart().getResourcepart())); @@ -487,8 +503,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa } @Override - public void onCreateContextMenu(ContextMenu menu, View v, - ContextMenuInfo menuInfo) { + public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { synchronized (this.messageList) { super.onCreateContextMenu(menu, v, menuInfo); AdapterView.AdapterContextMenuInfo acmi = (AdapterContextMenuInfo) menuInfo; @@ -503,6 +518,7 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa activity.getMenuInflater().inflate(R.menu.message_context, menu); menu.setHeaderTitle(R.string.message_options); MenuItem copyText = menu.findItem(R.id.copy_text); + MenuItem correctMessage = menu.findItem(R.id.correct_message); MenuItem shareWith = menu.findItem(R.id.share_with); MenuItem sendAgain = menu.findItem(R.id.send_again); MenuItem copyUrl = menu.findItem(R.id.copy_url); @@ -514,6 +530,11 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa && m.treatAsDownloadable() != Message.Decision.MUST) { copyText.setVisible(true); } + if (m.getType() == Message.TYPE_TEXT + && m.getStatus() != Message.STATUS_RECEIVED + && !m.isCarbon()) { + correctMessage.setVisible(true); + } if ((m.getType() != Message.TYPE_TEXT && m.getType() != Message.TYPE_PRIVATE && m.getTransferable() == null) @@ -550,6 +571,9 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa case R.id.copy_text: copyText(selectedMessage); return true; + case R.id.correct_message: + correctMessage(selectedMessage); + return true; case R.id.send_again: resendMessage(selectedMessage); return true; @@ -652,6 +676,16 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa updateSendButton(); } + private void correctMessage(Message message) { + while(message.mergeable(message.next())) { + message = message.next(); + } + this.conversation.setCorrectingMessage(message); + this.mEditMessage.getEditableText().clear(); + this.mEditMessage.getEditableText().append(message.getBody()); + + } + protected void highlightInConference(String nick) { String oldString = mEditMessage.getText().toString().trim(); if (oldString.isEmpty() || mEditMessage.getSelectionStart() == 0) { @@ -958,9 +992,12 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa final Conversation c = this.conversation; final SendButtonAction action; final Presence.Status status; - final boolean empty = this.mEditMessage == null || this.mEditMessage.getText().length() == 0; + final String text = this.mEditMessage == null ? "" : this.mEditMessage.getText().toString(); + final boolean empty = text.length() == 0; final boolean conference = c.getMode() == Conversation.MODE_MULTI; - if (conference && !c.getAccount().httpUploadAvailable()) { + if (c.getCorrectingMessage() != null && (empty || text.equals(c.getCorrectingMessage().getBody()))) { + action = SendButtonAction.CANCEL; + } else if (conference && !c.getAccount().httpUploadAvailable()) { if (empty && c.getNextCounterpart() != null) { action = SendButtonAction.CANCEL; } else { @@ -1238,6 +1275,13 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa updateSendButton(); } + @Override + public void onTextChanged() { + if (conversation != null && conversation.getCorrectingMessage() != null) { + updateSendButton(); + } + } + private int completionIndex = 0; private int lastCompletionLength = 0; private String incomplete; diff --git a/src/main/java/eu/siacs/conversations/ui/EditMessage.java b/src/main/java/eu/siacs/conversations/ui/EditMessage.java index fc655b0ce..e3841d1d5 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditMessage.java +++ b/src/main/java/eu/siacs/conversations/ui/EditMessage.java @@ -69,6 +69,7 @@ public class EditMessage extends EditText { this.isUserTyping = false; this.keyboardListener.onTextDeleted(); } + this.keyboardListener.onTextChanged(); } } @@ -84,6 +85,7 @@ public class EditMessage extends EditText { void onTypingStarted(); void onTypingStopped(); void onTextDeleted(); + void onTextChanged(); boolean onTabPressed(boolean repeated); } diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java index fc2bd2abc..f6496b21c 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java @@ -123,6 +123,16 @@ public class MessageAdapter extends ArrayAdapter { if (viewHolder.indicatorReceived != null) { viewHolder.indicatorReceived.setVisibility(View.GONE); } + + if (viewHolder.edit_indicator != null) { + if (message.edited()) { + viewHolder.edit_indicator.setVisibility(View.VISIBLE); + viewHolder.edit_indicator.setImageResource(darkBackground ? R.drawable.ic_mode_edit_white_18dp : R.drawable.ic_mode_edit_black_18dp); + viewHolder.edit_indicator.setAlpha(darkBackground ? 0.7f : 0.57f); + } else { + viewHolder.edit_indicator.setVisibility(View.GONE); + } + } boolean multiReceived = message.getConversation().getMode() == Conversation.MODE_MULTI && message.getMergedStatus() <= Message.STATUS_RECEIVED; if (message.getType() == Message.TYPE_IMAGE || message.getType() == Message.TYPE_FILE || message.getTransferable() != null) { @@ -179,7 +189,7 @@ public class MessageAdapter extends ArrayAdapter { if (message.getEncryption() == Message.ENCRYPTION_NONE) { viewHolder.indicator.setVisibility(View.GONE); } else { - viewHolder.indicator.setImageResource(darkBackground ? R.drawable.ic_secure_indicator_white : R.drawable.ic_secure_indicator); + viewHolder.indicator.setImageResource(darkBackground ? R.drawable.ic_lock_white_18dp : R.drawable.ic_lock_black_18dp); viewHolder.indicator.setVisibility(View.VISIBLE); if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL) { XmppAxolotlSession.Trust trust = message.getConversation() @@ -463,6 +473,7 @@ public class MessageAdapter extends ArrayAdapter { .findViewById(R.id.download_button); viewHolder.indicator = (ImageView) view .findViewById(R.id.security_indicator); + viewHolder.edit_indicator = (ImageView) view.findViewById(R.id.edit_indicator); viewHolder.image = (ImageView) view .findViewById(R.id.message_image); viewHolder.messageBody = (TextView) view @@ -483,6 +494,7 @@ public class MessageAdapter extends ArrayAdapter { .findViewById(R.id.download_button); viewHolder.indicator = (ImageView) view .findViewById(R.id.security_indicator); + viewHolder.edit_indicator = (ImageView) view.findViewById(R.id.edit_indicator); viewHolder.image = (ImageView) view .findViewById(R.id.message_image); viewHolder.messageBody = (TextView) view @@ -701,6 +713,7 @@ public class MessageAdapter extends ArrayAdapter { protected TextView status_message; protected TextView encryption; public Button load_more_messages; + public ImageView edit_indicator; } class BitmapWorkerTask extends AsyncTask { -- cgit v1.2.3 From 0ca4a33bfb76d63a3c2d4447643a5bd90ac5315f Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 16 Feb 2016 09:15:41 +0100 Subject: added some OTR logging --- .../java/eu/siacs/conversations/entities/Conversation.java | 11 +++++++---- .../siacs/conversations/services/XmppConnectionService.java | 8 +++++++- 2 files changed, 14 insertions(+), 5 deletions(-) (limited to 'src/main/java/eu/siacs/conversations') diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index a0600d130..c72ac09e3 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -517,15 +517,18 @@ public class Conversation extends AbstractEntity implements Blockable { return mSmp; } - public void startOtrIfNeeded() { - if (this.otrSession != null - && this.otrSession.getSessionStatus() != SessionStatus.ENCRYPTED) { + public boolean startOtrIfNeeded() { + if (this.otrSession != null && this.otrSession.getSessionStatus() != SessionStatus.ENCRYPTED) { try { this.otrSession.startSession(); + return true; } catch (OtrException e) { this.resetOtrSession(); + return false; } - } + } else { + return true; + } } public boolean endOtrIfNeeded() { diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 10f6b5efd..a8fe7586f 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -288,7 +288,9 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa List conversations = getConversations(); for (Conversation conversation : conversations) { if (conversation.getAccount() == account && conversation.getMode() == Conversation.MODE_SINGLE) { - conversation.startOtrIfNeeded(); + if (!conversation.startOtrIfNeeded()) { + Log.d(Config.LOGTAG,account.getJid().toBareJid()+": couldn't start OTR with "+conversation.getContact().getJid()+" when needed"); + } sendUnsentMessages(conversation); } } @@ -900,8 +902,11 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa if (message.fixCounterpart()) { conversation.startOtrSession(message.getCounterpart().getResourcepart(), true); } else { + Log.d(Config.LOGTAG,account.getJid().toBareJid()+": could not fix counterpart for OTR message to contact "+message.getContact().getJid()); break; } + } else { + Log.d(Config.LOGTAG,account.getJid().toBareJid()+" OTR session with "+message.getContact()+" is in wrong state: "+otrSession.getSessionStatus().toString()); } break; case Message.ENCRYPTION_AXOLOTL: @@ -946,6 +951,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa break; case Message.ENCRYPTION_OTR: if (!conversation.hasValidOtrSession() && message.getCounterpart() != null) { + Log.d(Config.LOGTAG,account.getJid().toBareJid()+": create otr session without starting for "+message.getContact().getJid()); conversation.startOtrSession(message.getCounterpart().getResourcepart(), false); } break; -- cgit v1.2.3 From a9b957e8a2b9cb7729ed0d2cc8b5efa1bee50c79 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 16 Feb 2016 09:57:59 +0100 Subject: added setting to opt-out of message correction. renamed preferences and options to settings --- .../java/eu/siacs/conversations/generator/AbstractGenerator.java | 7 ++++++- src/main/java/eu/siacs/conversations/parser/MessageParser.java | 2 +- .../eu/siacs/conversations/services/XmppConnectionService.java | 4 ++++ src/main/java/eu/siacs/conversations/ui/SettingsActivity.java | 3 ++- 4 files changed, 13 insertions(+), 3 deletions(-) (limited to 'src/main/java/eu/siacs/conversations') diff --git a/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java b/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java index d223ab842..05fa0b82e 100644 --- a/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/AbstractGenerator.java @@ -31,7 +31,6 @@ public abstract class AbstractGenerator { "urn:xmpp:avatar:metadata+notify", "http://jabber.org/protocol/nick+notify", "urn:xmpp:ping", - "urn:xmpp:message-correct:0", "jabber:iq:version", "http://jabber.org/protocol/chatstates", AxolotlService.PEP_DEVICE_LIST+"+notify"}; @@ -39,6 +38,9 @@ public abstract class AbstractGenerator { "urn:xmpp:chat-markers:0", "urn:xmpp:receipts" }; + private final String[] MESSAGE_CORRECTION_FEATURES = { + "urn:xmpp:message-correct:0" + }; private String mVersion = null; protected final String IDENTITY_NAME = "Conversations"; protected final String IDENTITY_TYPE = "phone"; @@ -90,6 +92,9 @@ public abstract class AbstractGenerator { if (mXmppConnectionService.confirmMessages()) { features.addAll(Arrays.asList(MESSAGE_CONFIRMATION_FEATURES)); } + if (mXmppConnectionService.allowMessageCorrection()) { + features.addAll(Arrays.asList(MESSAGE_CORRECTION_FEATURES)); + } Collections.sort(features); return features; } diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index 18edfdeb5..620039a15 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -393,7 +393,7 @@ public class MessageParser extends AbstractParser implements updateLastseen(timestamp, account, packet.getFrom(), true); } - if (replacementId != null) { + if (replacementId != null && mXmppConnectionService.allowMessageCorrection()) { Message replacedMessage = conversation.findMessageWithRemoteIdAndCounterpart(replacementId, counterpart); if (replacedMessage != null) { final boolean fingerprintsMatch = replacedMessage.getAxolotlFingerprint() == null diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index a8fe7586f..0c8f0b8b2 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -2615,6 +2615,10 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa return getPreferences().getBoolean("confirm_messages", true); } + public boolean allowMessageCorrection() { + return getPreferences().getBoolean("allow_message_correction", true); + } + public boolean sendChatStates() { return getPreferences().getBoolean("chat_states", false); } diff --git a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java index aa23e36db..07c328b9a 100644 --- a/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/SettingsActivity.java @@ -162,7 +162,8 @@ public class SettingsActivity extends XmppActivity implements xmppConnectionService.toggleForegroundService(); } else if (name.equals("confirm_messages") || name.equals("xa_on_silent_mode") - || name.equals("away_when_screen_off")) { + || name.equals("away_when_screen_off") + || name.equals("allow_message_correction")) { if (xmppConnectionServiceBound) { if (name.equals("away_when_screen_off")) { xmppConnectionService.toggleScreenEventReceiver(); -- cgit v1.2.3 From 349dd8291df78c33d6570d7f7937362ac08e4d66 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 16 Feb 2016 12:52:31 +0100 Subject: made clear that archiving preferences are server side --- src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/main/java/eu/siacs/conversations') diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java index 2656966bb..53fa9ff72 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java @@ -918,7 +918,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate mFetchingMamPrefsToast.cancel(); } AlertDialog.Builder builder = new Builder(EditAccountActivity.this); - builder.setTitle(R.string.mam_prefs); + builder.setTitle(R.string.server_side_mam_prefs); String defaultAttr = prefs.getAttribute("default"); final List defaults = Arrays.asList("never", "roster", "always"); final AtomicInteger choice = new AtomicInteger(Math.max(0,defaults.indexOf(defaultAttr))); -- cgit v1.2.3 From 86b1865eec5784795358b3d81eefe39d37ecd55a Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 16 Feb 2016 14:22:21 +0100 Subject: fixed regression that caused ui to redraw a lot --- .../siacs/conversations/services/XmppConnectionService.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'src/main/java/eu/siacs/conversations') diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 0c8f0b8b2..b7ac7571b 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -2726,7 +2726,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa return null; } - public void markRead(final Conversation conversation) { + public boolean markRead(final Conversation conversation) { mNotificationService.clear(conversation); final List readMessages = conversation.markRead(); if (readMessages.size() > 0) { @@ -2739,8 +2739,11 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } }; mDatabaseExecutor.execute(runnable); + updateUnreadCountBadge(); + return true; + } else { + return false; } - updateUnreadCountBadge(); } public synchronized void updateUnreadCountBadge() { @@ -2758,7 +2761,9 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa public void sendReadMarker(final Conversation conversation) { final Message markable = conversation.getLatestMarkableMessage(); - this.markRead(conversation); + if (this.markRead(conversation)) { + updateConversationUi(); + } if (confirmMessages() && markable != null && markable.getRemoteMsgId() != null) { Log.d(Config.LOGTAG, conversation.getAccount().getJid().toBareJid() + ": sending read marker to " + markable.getCounterpart().toString()); Account account = conversation.getAccount(); @@ -2766,7 +2771,6 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa MessagePacket packet = mMessageGenerator.confirm(account, to, markable.getRemoteMsgId()); this.sendMessagePacket(conversation.getAccount(), packet); } - updateConversationUi(); } public SecureRandom getRNG() { -- cgit v1.2.3 From c2fbdbde830fb3f15e4bdd1c1fb904e69b68927e Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Tue, 16 Feb 2016 14:22:47 +0100 Subject: log reason why otr message won't be parsed --- src/main/java/eu/siacs/conversations/parser/MessageParser.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/main/java/eu/siacs/conversations') diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index 620039a15..69b0e828e 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -312,7 +312,7 @@ public class MessageParser extends AbstractParser implements } boolean isTypeGroupChat = packet.getType() == MessagePacket.TYPE_GROUPCHAT; - boolean isProperlyAddressed = (to != null ) && (!to.isBareJid() || account.countPresences() == 1); + boolean isProperlyAddressed = (to != null ) && (!to.isBareJid() || account.countPresences() <= 1); boolean isMucStatusMessage = from.isBareJid() && mucUserElement != null && mucUserElement.hasChild("status"); if (packet.fromAccount(account)) { status = Message.STATUS_SEND; @@ -357,6 +357,7 @@ public class MessageParser extends AbstractParser implements return; } } else { + Log.d(Config.LOGTAG,account.getJid().toBareJid()+": ignoring OTR message from "+from+" isForwarded="+Boolean.toString(isForwarded)+", isProperlyAddressed="+Boolean.valueOf(isProperlyAddressed)); message = new Message(conversation, body, Message.ENCRYPTION_NONE, status); } } else if (pgpEncrypted != null) { -- cgit v1.2.3 From 3626e4b3a0d3d3da4be1bdf7645045d8cf892b50 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 17 Feb 2016 16:50:48 +0100 Subject: fixed regression that caused messages in muc not being send --- .../siacs/conversations/services/XmppConnectionService.java | 13 +++++++------ .../java/eu/siacs/conversations/xmpp/XmppConnection.java | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'src/main/java/eu/siacs/conversations') diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index b7ac7571b..33f7210f7 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -287,7 +287,8 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa } List conversations = getConversations(); for (Conversation conversation : conversations) { - if (conversation.getAccount() == account && conversation.getMode() == Conversation.MODE_SINGLE) { + if (conversation.getAccount() == account + && !account.pendingConferenceJoins.contains(conversation)) { if (!conversation.startOtrIfNeeded()) { Log.d(Config.LOGTAG,account.getJid().toBareJid()+": couldn't start OTR with "+conversation.getContact().getJid()+" when needed"); } @@ -1757,20 +1758,20 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa List conversations = getConversations(); for (Conversation conversation : conversations) { if (conversation.getMode() == Conversation.MODE_MULTI && conversation.getAccount() == account) { - joinMuc(conversation, true, null); + joinMuc(conversation); } } } public void joinMuc(Conversation conversation) { - joinMuc(conversation, false, null); + joinMuc(conversation, null); } - private void joinMuc(Conversation conversation, boolean now, final OnConferenceJoined onConferenceJoined) { + private void joinMuc(Conversation conversation, final OnConferenceJoined onConferenceJoined) { Account account = conversation.getAccount(); account.pendingConferenceJoins.remove(conversation); account.pendingConferenceLeaves.remove(conversation); - if (account.getStatus() == Account.State.ONLINE || now) { + if (account.getStatus() == Account.State.ONLINE) { conversation.resetMucOptions(); fetchConferenceConfiguration(conversation, new OnConferenceConfigurationFetched() { @@ -1949,7 +1950,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa String name = new BigInteger(75, getRNG()).toString(32); Jid jid = Jid.fromParts(name, server, null); final Conversation conversation = findOrCreateConversation(account, jid, true); - joinMuc(conversation, true, new OnConferenceJoined() { + joinMuc(conversation, new OnConferenceJoined() { @Override public void onConferenceJoined(final Conversation conversation) { Bundle options = new Bundle(); diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index 889457ffb..6be220c72 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -1077,10 +1077,10 @@ public class XmppConnection implements Runnable { if (mPendingServiceDiscoveries == 0) { Log.d(Config.LOGTAG,account.getJid().toBareJid()+": done with service discovery"); Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": online with resource " + account.getResource()); - changeStatus(Account.State.ONLINE); if (bindListener != null) { bindListener.onBind(account); } + changeStatus(Account.State.ONLINE); } } } -- cgit v1.2.3 From 59978e157ccbf4717a15238ddb0b0d0d422d7e3f Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 17 Feb 2016 16:51:36 +0100 Subject: only offer message correction for the very last message --- .../eu/siacs/conversations/entities/Conversation.java | 15 +++++++++++---- .../java/eu/siacs/conversations/entities/Message.java | 15 +++++++++++++++ .../java/eu/siacs/conversations/parser/MessageParser.java | 6 +++++- .../eu/siacs/conversations/ui/ConversationFragment.java | 9 ++++++--- 4 files changed, 37 insertions(+), 8 deletions(-) (limited to 'src/main/java/eu/siacs/conversations') diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index c72ac09e3..a179d96bf 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -227,11 +227,18 @@ public class Conversation extends AbstractEntity implements Blockable { return null; } - public Message findMessageWithRemoteIdAndCounterpart(String id, Jid counterpart) { + public Message findMessageWithRemoteIdAndCounterpart(String id, Jid counterpart, boolean received, boolean carbon) { synchronized (this.messages) { - for(Message message : this.messages) { - if(id.equals(message.getRemoteMsgId()) && counterpart.equals(message.getCounterpart())) { - return message; + for(int i = this.messages.size() - 1; i >= 0; --i) { + Message message = messages.get(i); + if (counterpart.equals(message.getCounterpart()) + && ((message.getStatus() == Message.STATUS_RECEIVED) == received) + && (carbon == message.isCarbon() || received) ) { + if (id.equals(message.getRemoteMsgId())) { + return message; + } else { + return null; + } } } } diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index 1f9212fdb..63db9a447 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -428,6 +428,21 @@ public class Message extends AbstractEntity { } } + public boolean isLastCorrectableMessage() { + Message next = next(); + while(next != null) { + if (next.isCorrectable()) { + return false; + } + next = next.next(); + } + return isCorrectable(); + } + + private boolean isCorrectable() { + return getStatus() != STATUS_RECEIVED && !isCarbon(); + } + public boolean mergeable(final Message message) { return message != null && (message.getType() == Message.TYPE_TEXT && diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index 69b0e828e..c4b63d61d 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -336,6 +336,7 @@ public class MessageParser extends AbstractParser implements if (isTypeGroupChat) { if (counterpart.getResourcepart().equals(conversation.getMucOptions().getActualNick())) { status = Message.STATUS_SEND_RECEIVED; + isCarbon = true; //not really carbon but received from another resource if (mXmppConnectionService.markMessage(conversation, remoteMsgId, status)) { return; } else if (remoteMsgId == null || Config.IGNORE_ID_REWRITE_IN_MUC) { @@ -395,7 +396,10 @@ public class MessageParser extends AbstractParser implements } if (replacementId != null && mXmppConnectionService.allowMessageCorrection()) { - Message replacedMessage = conversation.findMessageWithRemoteIdAndCounterpart(replacementId, counterpart); + Message replacedMessage = conversation.findMessageWithRemoteIdAndCounterpart(replacementId, + counterpart, + message.getStatus() == Message.STATUS_RECEIVED, + message.isCarbon()); if (replacedMessage != null) { final boolean fingerprintsMatch = replacedMessage.getAxolotlFingerprint() == null || replacedMessage.getAxolotlFingerprint().equals(message.getAxolotlFingerprint()); diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index 6ead99625..c02a33b0c 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -514,6 +514,10 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa private void populateContextMenu(ContextMenu menu) { final Message m = this.selectedMessage; + Message relevantForCorrection = m; + while(relevantForCorrection.mergeable(relevantForCorrection.next())) { + relevantForCorrection = relevantForCorrection.next(); + } if (m.getType() != Message.TYPE_STATUS) { activity.getMenuInflater().inflate(R.menu.message_context, menu); menu.setHeaderTitle(R.string.message_options); @@ -530,9 +534,8 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa && m.treatAsDownloadable() != Message.Decision.MUST) { copyText.setVisible(true); } - if (m.getType() == Message.TYPE_TEXT - && m.getStatus() != Message.STATUS_RECEIVED - && !m.isCarbon()) { + if (relevantForCorrection.getType() == Message.TYPE_TEXT + && relevantForCorrection.isLastCorrectableMessage()) { correctMessage.setVisible(true); } if ((m.getType() != Message.TYPE_TEXT -- cgit v1.2.3 From ac687d6bbd08674d97a52b3548df8fe49bee48d9 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Wed, 17 Feb 2016 16:52:57 +0100 Subject: don't log start reason --- src/main/java/eu/siacs/conversations/services/XmppConnectionService.java | 1 - 1 file changed, 1 deletion(-) (limited to 'src/main/java/eu/siacs/conversations') diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 33f7210f7..9b7306378 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -477,7 +477,6 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa final String action = intent == null ? null : intent.getAction(); boolean interactive = false; if (action != null) { - Log.d(Config.LOGTAG,"start reason: "+action); switch (action) { case ConnectivityManager.CONNECTIVITY_ACTION: if (hasInternetConnection() && Config.RESET_ATTEMPT_COUNT_ON_NETWORK_CHANGE) { -- cgit v1.2.3 From 49a3f6f281c9a01f9bdaf7f5141c46dd1c6ca2cb Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 19 Feb 2016 11:09:28 +0100 Subject: never parse show in presences as offline --- .../eu/siacs/conversations/entities/Presence.java | 26 +++++++++++++--------- .../siacs/conversations/parser/PresenceParser.java | 2 +- 2 files changed, 16 insertions(+), 12 deletions(-) (limited to 'src/main/java/eu/siacs/conversations') diff --git a/src/main/java/eu/siacs/conversations/entities/Presence.java b/src/main/java/eu/siacs/conversations/entities/Presence.java index 69cde8327..442f1bcac 100644 --- a/src/main/java/eu/siacs/conversations/entities/Presence.java +++ b/src/main/java/eu/siacs/conversations/entities/Presence.java @@ -1,6 +1,7 @@ package eu.siacs.conversations.entities; import java.lang.Comparable; +import java.util.Locale; import eu.siacs.conversations.xml.Element; @@ -32,21 +33,24 @@ public class Presence implements Comparable { this.hash = hash; } - public static Presence parse(Element show, Element caps) { + public static Presence parse(String show, Element caps) { final String hash = caps == null ? null : caps.getAttribute("hash"); final String ver = caps == null ? null : caps.getAttribute("ver"); - if ((show == null) || (show.getContent() == null)) { + if (show == null) { return new Presence(Status.ONLINE, ver, hash); - } else if (show.getContent().equals("away")) { - return new Presence(Status.AWAY, ver, hash); - } else if (show.getContent().equals("xa")) { - return new Presence(Status.XA, ver, hash); - } else if (show.getContent().equals("chat")) { - return new Presence(Status.CHAT, ver, hash); - } else if (show.getContent().equals("dnd")) { - return new Presence(Status.DND, ver, hash); } else { - return new Presence(Status.OFFLINE, ver, hash); + switch (show.toLowerCase(Locale.US)) { + case "away": + return new Presence(Status.AWAY, ver, hash); + case "xa": + return new Presence(Status.XA, ver, hash); + case "dnd": + return new Presence(Status.DND, ver, hash); + case "chat": + return new Presence(Status.CHAT, ver, hash); + default: + return new Presence(Status.ONLINE, ver, hash); + } } } diff --git a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java index 45c31e2b0..dc02eda8f 100644 --- a/src/main/java/eu/siacs/conversations/parser/PresenceParser.java +++ b/src/main/java/eu/siacs/conversations/parser/PresenceParser.java @@ -186,7 +186,7 @@ public class PresenceParser extends AbstractParser implements } int sizeBefore = contact.getPresences().size(); - final Element show = packet.findChild("show"); + final String show = packet.findChildContent("show"); final Element caps = packet.findChild("c", "http://jabber.org/protocol/caps"); final Presence presence = Presence.parse(show, caps); contact.updatePresence(resource, presence); -- cgit v1.2.3 From df992d25665aed3eaec25662e70a3b859667c624 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 19 Feb 2016 20:54:43 +0100 Subject: don't reset whisper on reInit. fixes #1637 --- src/main/java/eu/siacs/conversations/ui/ConversationFragment.java | 3 --- 1 file changed, 3 deletions(-) (limited to 'src/main/java/eu/siacs/conversations') diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index c02a33b0c..a39b6feef 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -738,9 +738,6 @@ public class ConversationFragment extends Fragment implements EditMessage.Keyboa this.keychainUnlock = KEYCHAIN_UNLOCK_NOT_REQUIRED; this.conversation = conversation; - if (this.conversation.getMode() == Conversation.MODE_MULTI) { - this.conversation.setNextCounterpart(null); - } boolean canWrite = this.conversation.getMode() == Conversation.MODE_SINGLE || this.conversation.getMucOptions().participating(); this.mEditMessage.setEnabled(canWrite); this.mSendButton.setEnabled(canWrite); -- cgit v1.2.3 From a2cb009f4cb750a1e2953202852e889f78041c05 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 19 Feb 2016 20:54:53 +0100 Subject: skip avatar ui when pep is not available. fixes #1706 --- .../java/eu/siacs/conversations/ui/EditAccountActivity.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/main/java/eu/siacs/conversations') diff --git a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java index 53fa9ff72..266ae8406 100644 --- a/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java +++ b/src/main/java/eu/siacs/conversations/ui/EditAccountActivity.java @@ -50,6 +50,7 @@ import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.utils.UIHelper; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.OnKeyStatusUpdated; +import eu.siacs.conversations.xmpp.XmppConnection; import eu.siacs.conversations.xmpp.XmppConnection.Features; import eu.siacs.conversations.xmpp.forms.Data; import eu.siacs.conversations.xmpp.jid.InvalidJidException; @@ -304,15 +305,14 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate @Override public void run() { final Intent intent; - if (avatar != null) { - intent = new Intent(getApplicationContext(), - StartConversationActivity.class); + final XmppConnection connection = mAccount.getXmppConnection(); + if (avatar != null || (connection != null && !connection.getFeatures().pep())) { + intent = new Intent(getApplicationContext(), StartConversationActivity.class); if (xmppConnectionService != null && xmppConnectionService.getAccounts().size() == 1) { intent.putExtra("init", true); } } else { - intent = new Intent(getApplicationContext(), - PublishProfilePictureActivity.class); + intent = new Intent(getApplicationContext(), PublishProfilePictureActivity.class); intent.putExtra(EXTRA_ACCOUNT, mAccount.getJid().toBareJid().toString()); intent.putExtra("setup", true); } -- cgit v1.2.3 From e6f8b7d9fa30e4e231a07cdbbb225e462893eb3d Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Fri, 19 Feb 2016 21:02:33 +0100 Subject: decrypt pgp message corrections --- .../eu/siacs/conversations/parser/MessageParser.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'src/main/java/eu/siacs/conversations') diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index c4b63d61d..247fd72b6 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -117,13 +117,6 @@ public class MessageParser extends AbstractParser implements return finishedMessage; } - private Message parsePGPChat(final Conversation conversation, String pgpEncrypted, int status) { - final Message message = new Message(conversation, pgpEncrypted, Message.ENCRYPTION_PGP, status); - PgpDecryptionService pgpDecryptionService = conversation.getAccount().getPgpDecryptionService(); - pgpDecryptionService.add(message); - return message; - } - private class Invite { Jid jid; String password; @@ -362,7 +355,7 @@ public class MessageParser extends AbstractParser implements message = new Message(conversation, body, Message.ENCRYPTION_NONE, status); } } else if (pgpEncrypted != null) { - message = parsePGPChat(conversation, pgpEncrypted, status); + message = new Message(conversation, pgpEncrypted, Message.ENCRYPTION_PGP, status); } else if (axolotlEncrypted != null) { message = parseAxolotlChat(axolotlEncrypted, from, remoteMsgId, conversation, status); if (message == null) { @@ -410,6 +403,7 @@ public class MessageParser extends AbstractParser implements replacedMessage.setBody(message.getBody()); replacedMessage.setEdited(replacedMessage.getRemoteMsgId()); replacedMessage.setRemoteMsgId(remoteMsgId); + replacedMessage.setEncryption(message.getEncryption()); if (replacedMessage.getStatus() == Message.STATUS_RECEIVED) { replacedMessage.markUnread(); } @@ -417,6 +411,9 @@ public class MessageParser extends AbstractParser implements if (mXmppConnectionService.confirmMessages() && remoteMsgId != null && !isForwarded && !isTypeGroupChat) { sendMessageReceipts(account, packet); } + if (replacedMessage.getEncryption() == Message.ENCRYPTION_PGP) { + conversation.getAccount().getPgpDecryptionService().add(replacedMessage); + } return; } else { Log.d(Config.LOGTAG,account.getJid().toBareJid()+": received message correction but verification didn't check out"); @@ -438,6 +435,10 @@ public class MessageParser extends AbstractParser implements conversation.add(message); } + if (message.getEncryption() == Message.ENCRYPTION_PGP) { + conversation.getAccount().getPgpDecryptionService().add(message); + } + if (query == null || query.getWith() == null) { //either no mam or catchup if (status == Message.STATUS_SEND || status == Message.STATUS_SEND_RECEIVED) { mXmppConnectionService.markRead(conversation); -- cgit v1.2.3 From 3bde4dbedb80a8e1de89c09f58d842d7382598e8 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Sat, 20 Feb 2016 00:01:39 +0100 Subject: change uuid when replacing messages --- src/main/java/eu/siacs/conversations/parser/MessageParser.java | 5 ++++- .../java/eu/siacs/conversations/services/XmppConnectionService.java | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'src/main/java/eu/siacs/conversations') diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index 247fd72b6..f01e7ce1f 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -9,6 +9,7 @@ import net.java.otr4j.session.SessionStatus; import java.util.ArrayList; import java.util.Set; +import java.util.UUID; import eu.siacs.conversations.Config; import eu.siacs.conversations.crypto.axolotl.AxolotlService; @@ -400,6 +401,8 @@ public class MessageParser extends AbstractParser implements && replacedMessage.getTrueCounterpart().equals(message.getTrueCounterpart()); if (fingerprintsMatch && (trueCountersMatch || conversation.getMode() == Conversation.MODE_SINGLE)) { Log.d(Config.LOGTAG, "replaced message '" + replacedMessage.getBody() + "' with '" + message.getBody() + "'"); + final String uuid = replacedMessage.getUuid(); + replacedMessage.setUuid(UUID.randomUUID().toString()); replacedMessage.setBody(message.getBody()); replacedMessage.setEdited(replacedMessage.getRemoteMsgId()); replacedMessage.setRemoteMsgId(remoteMsgId); @@ -407,7 +410,7 @@ public class MessageParser extends AbstractParser implements if (replacedMessage.getStatus() == Message.STATUS_RECEIVED) { replacedMessage.markUnread(); } - mXmppConnectionService.updateMessage(replacedMessage); + mXmppConnectionService.updateMessage(replacedMessage, uuid); if (mXmppConnectionService.confirmMessages() && remoteMsgId != null && !isForwarded && !isTypeGroupChat) { sendMessageReceipts(account, packet); } diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 9b7306378..b836e780a 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -2159,6 +2159,11 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa updateConversationUi(); } + public void updateMessage(Message message, String uuid) { + databaseBackend.updateMessage(message, uuid); + updateConversationUi(); + } + protected void syncDirtyContacts(Account account) { for (Contact contact : account.getRoster().getContacts()) { if (contact.getOption(Contact.Options.DIRTY_PUSH)) { -- cgit v1.2.3