muc PM in the separate conversation

This commit is contained in:
kosyak 2023-09-15 11:28:50 +02:00
parent c62cc344b5
commit 1ca354c208
31 changed files with 427 additions and 157 deletions

View file

@ -46,7 +46,7 @@ public class ShareViaAccountActivity extends XmppActivity {
try {
final Jid contact = Jid.of(getIntent().getStringExtra(EXTRA_CONTACT));
final Conversation conversation = xmppConnectionService.findOrCreateConversation(
account, contact, false, false);
account, contact, null, false, false, false, null);
switchToConversation(conversation, body);
} catch (IllegalArgumentException e) {
// ignore error
@ -76,7 +76,7 @@ public class ShareViaAccountActivity extends XmppActivity {
try {
final Jid contact = Jid.of(getIntent().getStringExtra(EXTRA_CONTACT));
final Conversation conversation = xmppConnectionService.findOrCreateConversation(
account, contact, false, false);
account, contact, null, false, false, false, null);
switchToConversation(conversation, body);
} catch (IllegalArgumentException e) {
// ignore error

View file

@ -1532,8 +1532,18 @@ public class AxolotlService implements OnAdvancedStreamFeaturesLoaded {
if (contact.showInRoster() || contact.isSelf()) {
return true;
}
final Conversation conversation = mXmppConnectionService.find(account, jid);
return conversation != null && conversation.sentMessagesCount() > 0;
Conversation conversation = mXmppConnectionService.find(account, jid, null);
if (conversation != null && conversation.sentMessagesCount() > 0) {
return true;
}
conversation = mXmppConnectionService.find(account, jid, jid);
if (conversation != null && conversation.sentMessagesCount() > 0) {
return true;
}
return false;
}
private void completeSession(XmppAxolotlSession session) {

View file

@ -14,11 +14,13 @@ import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
import eu.siacs.conversations.Config;
@ -51,6 +53,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
public static final String CREATED = "created";
public static final String MODE = "mode";
public static final String ATTRIBUTES = "attributes";
public static final String NEXT_COUNTERPART = "next_counterpart";
public static final String ATTRIBUTE_MUTED_TILL = "muted_till";
public static final String ATTRIBUTE_ALWAYS_NOTIFY = "always_notify";
@ -86,17 +89,19 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
private String mFirstMamReference = null;
protected Message replyTo = null;
private WeakReference<Conversation> parentConversation = null;
public Conversation(final String name, final Account account, final Jid contactJid,
final int mode) {
final int mode, Jid nextCounterpart) {
this(java.util.UUID.randomUUID().toString(), name, null, account
.getUuid(), contactJid, System.currentTimeMillis(),
STATUS_AVAILABLE, mode, "");
STATUS_AVAILABLE, mode, "", nextCounterpart);
this.account = account;
}
public Conversation(final String uuid, final String name, final String contactUuid,
final String accountUuid, final Jid contactJid, final long created, final int status,
final int mode, final String attributes) {
final int mode, final String attributes, Jid nextCounterpart) {
this.uuid = uuid;
this.name = name;
this.contactUuid = contactUuid;
@ -110,9 +115,19 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
} catch (JSONException e) {
this.attributes = new JSONObject();
}
this.nextCounterpart = nextCounterpart;
}
public String getContactUuid() {
return contactUuid;
}
public JSONObject getAttributes() {
return attributes;
}
public static Conversation fromCursor(Cursor cursor) {
String counterpart = cursor.getString(cursor.getColumnIndex(NEXT_COUNTERPART));
return new Conversation(cursor.getString(cursor.getColumnIndex(UUID)),
cursor.getString(cursor.getColumnIndex(NAME)),
cursor.getString(cursor.getColumnIndex(CONTACT)),
@ -121,7 +136,8 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
cursor.getLong(cursor.getColumnIndex(CREATED)),
cursor.getInt(cursor.getColumnIndex(STATUS)),
cursor.getInt(cursor.getColumnIndex(MODE)),
cursor.getString(cursor.getColumnIndex(ATTRIBUTES)));
cursor.getString(cursor.getColumnIndex(ATTRIBUTES)),
counterpart == null ? null : JidHelper.parseOrFallbackToInvalid(counterpart));
}
public static Message getLatestMarkableMessage(final List<Message> messages, boolean isPrivateAndNonAnonymousMuc) {
@ -215,6 +231,17 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
return null;
}
public Conversation getParentConversation() {
if (parentConversation == null) {
return null;
}
return parentConversation.get();
}
public void setParentConversation(Conversation c) {
this.parentConversation = new WeakReference<>(c);
}
public Message findUnsentMessageWithUuid(String uuid) {
synchronized (this.messages) {
@ -641,6 +668,10 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
return this.accountUuid;
}
public Jid getContactJid() {
return contactJid;
}
public Account getAccount() {
return this.account;
}
@ -680,6 +711,11 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
values.put(CREATED, created);
values.put(STATUS, status);
values.put(MODE, mode);
if (nextCounterpart != null) {
values.put(NEXT_COUNTERPART, nextCounterpart.toString());
}
synchronized (this.attributes) {
values.put(ATTRIBUTES, attributes.toString());
}
@ -706,6 +742,12 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
}
public synchronized MucOptions getMucOptions() {
Conversation parent = parentConversation == null ? null : parentConversation.get();
if (parent != null) {
this.mucOptions = parent.getMucOptions();
}
if (this.mucOptions == null) {
this.mucOptions = new MucOptions(this);
}
@ -984,22 +1026,69 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
}
public void add(Message message) {
synchronized (this.messages) {
this.messages.add(message);
String res1 = message.getCounterpart() == null ? null : message.getCounterpart().getResource();
String res2 = nextCounterpart == null ? null : nextCounterpart.getResource();
if (nextCounterpart == null) {
if (!message.isPrivateMessage()) {
synchronized (this.messages) {
this.messages.add(message);
}
}
} else {
if (message.isPrivateMessage() && Objects.equals(res1, res2)) {
synchronized (this.messages) {
this.messages.add(message);
}
}
}
}
public void prepend(int offset, Message message) {
synchronized (this.messages) {
this.messages.add(Math.min(offset, this.messages.size()), message);
String res1 = message.getCounterpart() == null ? null : message.getCounterpart().getResource();
String res2 = nextCounterpart == null ? null : nextCounterpart.getResource();
if (nextCounterpart == null) {
if (!message.isPrivateMessage()) {
synchronized (this.messages) {
this.messages.add(Math.min(offset, this.messages.size()), message);
}
}
} else {
if (message.isPrivateMessage() && Objects.equals(res1, res2)) {
synchronized (this.messages) {
this.messages.add(Math.min(offset, this.messages.size()), message);
}
}
}
}
public void addAll(int index, List<Message> messages) {
synchronized (this.messages) {
this.messages.addAll(index, messages);
ArrayList<Message> newM = new ArrayList<>();
if (nextCounterpart == null) {
for(Message m : messages) {
if (!m.isPrivateMessage()) {
newM.add(m);
}
}
} else {
for(Message m : messages) {
String res1 = m.getCounterpart() == null ? null : m.getCounterpart().getResource();
String res2 = nextCounterpart == null ? null : nextCounterpart.getResource();
if (m.isPrivateMessage() && Objects.equals(res1, res2)) {
newM.add(m);
}
}
}
account.getPgpDecryptionService().decrypt(messages);
synchronized (this.messages) {
this.messages.addAll(index, newM);
}
account.getPgpDecryptionService().decrypt(newM);
}
public void expireOldMessages(long timestamp) {

View file

@ -45,4 +45,6 @@ public interface Conversational {
int getMode();
String getUuid();
Jid getNextCounterpart();
}

View file

@ -39,11 +39,14 @@ public class StubConversation implements Conversational {
private final Jid jid;
private final int mode;
public StubConversation(Account account, String uuid, Jid jid, int mode) {
private final Jid nexCounterpart;
public StubConversation(Account account, String uuid, Jid jid, int mode, Jid nextCounterpart) {
this.account = account;
this.uuid = uuid;
this.jid = jid;
this.mode = mode;
this.nexCounterpart = nextCounterpart;
}
@Override
@ -70,4 +73,9 @@ public class StubConversation implements Conversational {
public String getUuid() {
return uuid;
}
@Override
public Jid getNextCounterpart() {
return nexCounterpart;
}
}

View file

@ -269,7 +269,6 @@ class EditActivity : AppCompatActivity(), CropImageView.OnCropImageCompleteListe
updateBackgroundBitmap(bitmap)
layoutParams.width = bitmap.width
layoutParams.height = bitmap.height
android.util.Log.e("31fd", bitmap.height.toString() + " " + height)
translationY = max((height - bitmap.height) / 2f, 0f)
requestLayout()

View file

@ -341,7 +341,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
final Element error = packet.findChild("error");
final boolean pingWorthyError = error != null && (error.hasChild("not-acceptable") || error.hasChild("remote-server-timeout") || error.hasChild("remote-server-not-found"));
if (pingWorthyError) {
Conversation conversation = mXmppConnectionService.find(account, from);
Conversation conversation = mXmppConnectionService.find(account, from, null);
if (conversation != null && conversation.getMode() == Conversational.MODE_MULTI) {
if (conversation.getMucOptions().online()) {
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": received ping worthy error for seemingly online muc at " + from);
@ -463,9 +463,16 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
}
}
Jid nextCounterpart = null;
final boolean conversationIsProbablyMuc = isTypeGroupChat || mucUserElement != null || account.getXmppConnection().getMucServersWithholdAccount().contains(counterpart.getDomain().toEscapedString());
if (conversationIsProbablyMuc && !isTypeGroupChat) {
nextCounterpart = counterpart;
}
if ((body != null || pgpEncrypted != null || (axolotlEncrypted != null && axolotlEncrypted.hasChild("payload")) || oobUrl != null) && !isMucStatusMessage) {
final boolean conversationIsProbablyMuc = isTypeGroupChat || mucUserElement != null || account.getXmppConnection().getMucServersWithholdAccount().contains(counterpart.getDomain().toEscapedString());
final Conversation conversation = mXmppConnectionService.findOrCreateConversation(account, counterpart.asBareJid(), conversationIsProbablyMuc, false, query, false);
final Conversation conversation = mXmppConnectionService.findOrCreateConversation(account, counterpart.asBareJid(), null, conversationIsProbablyMuc, nextCounterpart != null, false, nextCounterpart);
final boolean conversationMultiMode = conversation.getMode() == Conversation.MODE_MULTI;
if (serverMsgId == null) {
@ -545,7 +552,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
message = trial;
}
if (message == null) {
if (query == null && extractChatState(mXmppConnectionService.find(account, counterpart.asBareJid()), isTypeGroupChat, packet)) {
if (query == null && extractChatState(mXmppConnectionService.find(account, counterpart.asBareJid(), nextCounterpart), isTypeGroupChat, packet)) {
mXmppConnectionService.updateConversationUi();
}
if (query != null && status == Message.STATUS_SEND && remoteMsgId != null) {
@ -649,7 +656,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
if (replacedMessage.getStatus() == Message.STATUS_RECEIVED) {
replacedMessage.markUnread();
}
extractChatState(mXmppConnectionService.find(account, counterpart.asBareJid()), isTypeGroupChat, packet);
extractChatState(mXmppConnectionService.find(account, counterpart.asBareJid(), nextCounterpart), isTypeGroupChat, packet);
mXmppConnectionService.updateMessage(replacedMessage, uuid);
if (mXmppConnectionService.confirmMessages()
&& replacedMessage.getStatus() == Message.STATUS_RECEIVED
@ -733,7 +740,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
}
if (query == null) {
extractChatState(mXmppConnectionService.find(account, counterpart.asBareJid()), isTypeGroupChat, packet);
extractChatState(mXmppConnectionService.find(account, counterpart.asBareJid(), nextCounterpart), isTypeGroupChat, packet);
mXmppConnectionService.updateConversationUi();
}
@ -759,7 +766,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
}
} else if (!packet.hasChild("body")) { //no body
final Conversation conversation = mXmppConnectionService.find(account, from.asBareJid());
final Conversation conversation = mXmppConnectionService.find(account, from.asBareJid(), nextCounterpart);
if (axolotlEncrypted != null) {
Jid origin;
if (conversation != null && conversation.getMode() == Conversation.MODE_MULTI) {
@ -784,7 +791,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
}
}
if (query == null && extractChatState(mXmppConnectionService.find(account, counterpart.asBareJid()), isTypeGroupChat, packet)) {
if (query == null && extractChatState(mXmppConnectionService.find(account, counterpart.asBareJid(), nextCounterpart), isTypeGroupChat, packet)) {
mXmppConnectionService.updateConversationUi();
}
@ -864,7 +871,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
final Element description = child.findChild("description");
final String namespace = description == null ? null : description.getNamespace();
if (Namespace.JINGLE_APPS_RTP.equals(namespace)) {
final Conversation c = mXmppConnectionService.findOrCreateConversation(account, counterpart.asBareJid(), false, false);
final Conversation c = mXmppConnectionService.findOrCreateConversation(account, counterpart.asBareJid(), null, false, false, false, nextCounterpart);
final Message preExistingMessage = c.findRtpSession(sessionId, status);
if (preExistingMessage != null) {
preExistingMessage.setServerMsgId(serverMsgId);
@ -885,7 +892,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
}
} else if ("proceed".equals(action)) {
//status needs to be flipped to find the original propose
final Conversation c = mXmppConnectionService.findOrCreateConversation(account, counterpart.asBareJid(), false, false);
final Conversation c = mXmppConnectionService.findOrCreateConversation(account, counterpart.asBareJid(), null, false, false, false, nextCounterpart);
final int s = packet.fromAccount(account) ? Message.STATUS_RECEIVED : Message.STATUS_SEND;
final Message message = c.findRtpSession(sessionId, s);
if (message != null) {
@ -906,7 +913,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
final Element description = child.findChild("description");
final String namespace = description == null ? null : description.getNamespace();
if (Namespace.JINGLE_APPS_RTP.equals(namespace)) {
final Conversation c = mXmppConnectionService.findOrCreateConversation(account, counterpart.asBareJid(), false, false);
final Conversation c = mXmppConnectionService.findOrCreateConversation(account, counterpart.asBareJid(), null, false, false, false, nextCounterpart);
final Message preExistingMessage = c.findRtpSession(sessionId, status);
if (preExistingMessage != null) {
preExistingMessage.setServerMsgId(serverMsgId);
@ -963,12 +970,12 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
final String id = displayed.getAttribute("id");
final Jid sender = InvalidJid.getNullForInvalid(displayed.getAttributeAsJid("sender"));
if (packet.fromAccount(account) && !selfAddressed) {
dismissNotification(account, counterpart, query, id);
dismissNotification(account, counterpart, query, id, nextCounterpart);
if (query == null) {
activateGracePeriod(account);
}
} else if (isTypeGroupChat) {
final Conversation conversation = mXmppConnectionService.find(account, counterpart.asBareJid());
final Conversation conversation = mXmppConnectionService.find(account, counterpart.asBareJid(), nextCounterpart);
final Message message;
if (conversation != null && id != null) {
if (sender != null) {
@ -1004,7 +1011,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
message = message.prev();
}
if (displayedMessage != null && selfAddressed) {
dismissNotification(account, counterpart, query, id);
dismissNotification(account, counterpart, query, id, nextCounterpart);
}
}
}
@ -1033,8 +1040,8 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
}
}
private void dismissNotification(Account account, Jid counterpart, MessageArchiveService.Query query, final String id) {
final Conversation conversation = mXmppConnectionService.find(account, counterpart.asBareJid());
private void dismissNotification(Account account, Jid counterpart, MessageArchiveService.Query query, final String id, Jid nextCounterpart) {
final Conversation conversation = mXmppConnectionService.find(account, counterpart.asBareJid(), nextCounterpart);
if (conversation != null && (query == null || query.isCatchup())) {
final String displayableId = conversation.findMostRecentRemoteDisplayableId();
if (displayableId != null && displayableId.equals(id)) {
@ -1092,7 +1099,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
public boolean execute(Account account) {
if (jid != null) {
Conversation conversation = mXmppConnectionService.findOrCreateConversation(account, jid, true, false);
Conversation conversation = mXmppConnectionService.findOrCreateConversation(account, jid, null, true, false, false, null);
if (conversation.getMucOptions().online()) {
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": received invite to " + jid + " but muc is considered to be online");
mXmppConnectionService.mucSelfPingAndRejoin(conversation);

View file

@ -36,8 +36,11 @@ public class PresenceParser extends AbstractParser implements
}
public void parseConferencePresence(PresencePacket packet, Account account) {
final Conversation conversation = packet.getFrom() == null ? null : mXmppConnectionService.find(account, packet.getFrom().asBareJid());
if (conversation != null) {
final List<Conversation> res = packet.getFrom() == null ? null : mXmppConnectionService.findAll(account, packet.getFrom().asBareJid());
if (res == null) return;
for (Conversation conversation : res) {
final MucOptions mucOptions = conversation.getMucOptions();
boolean before = mucOptions.online();
int count = mucOptions.getUserCount();
@ -362,7 +365,7 @@ public class PresenceParser extends AbstractParser implements
} else {
contact.setOption(Contact.Options.PENDING_SUBSCRIPTION_REQUEST);
final Conversation conversation = mXmppConnectionService.findOrCreateConversation(
account, contact.getJid().asBareJid(), false, false);
account, contact.getJid().asBareJid(), null, false, false, false, null);
final String statusMessage = packet.findChildContent("status");
if (statusMessage != null
&& !statusMessage.isEmpty()

View file

@ -64,7 +64,7 @@ import eu.siacs.conversations.xmpp.mam.MamReference;
public class DatabaseBackend extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "history";
private static final int DATABASE_VERSION = 52;
private static final int DATABASE_VERSION = 53;
private static boolean requiresMessageIndexRebuild = false;
private static DatabaseBackend instance = null;
@ -241,7 +241,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
+ Conversation.ACCOUNT + " TEXT, " + Conversation.CONTACTJID
+ " TEXT, " + Conversation.CREATED + " NUMBER, "
+ Conversation.STATUS + " NUMBER, " + Conversation.MODE
+ " NUMBER, " + Conversation.ATTRIBUTES + " TEXT, FOREIGN KEY("
+ " NUMBER, " + Conversation.NEXT_COUNTERPART + " TEXT, " + Conversation.ATTRIBUTES + " TEXT, FOREIGN KEY("
+ Conversation.ACCOUNT + ") REFERENCES " + Account.TABLENAME
+ "(" + Account.UUID + ") ON DELETE CASCADE);");
db.execSQL("create table " + Message.TABLENAME + "( " + Message.UUID
@ -606,6 +606,10 @@ public class DatabaseBackend extends SQLiteOpenHelper {
if (oldVersion < 52 && newVersion >= 52) {
db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN " + Message.PAYLOADS + " TEXT");
}
if (oldVersion < 53 && newVersion >= 53) {
db.execSQL("ALTER TABLE " + Conversation.TABLENAME + " ADD COLUMN " + Conversation.NEXT_COUNTERPART + " TEXT");
}
}
private void canonicalizeJids(SQLiteDatabase db) {
@ -803,26 +807,42 @@ public class DatabaseBackend extends SQLiteOpenHelper {
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor;
if (timestamp == -1) {
String[] selectionArgs = {conversation.getUuid()};
cursor = db.query(Message.TABLENAME, null, Message.CONVERSATION
+ "=?", selectionArgs, null, null, Message.TIME_SENT
if (conversation.getNextCounterpart() == null) {
String[] selectionArgs = {conversation.getUuid()};
cursor = db.query(Message.TABLENAME, null, Message.CONVERSATION
+ "=?", selectionArgs, null, null, Message.TIME_SENT
+ " DESC", String.valueOf(limit));
} else {
String[] selectionArgs = {conversation.getUuid(), String.valueOf(Message.TYPE_PRIVATE), String.valueOf(Message.TYPE_PRIVATE_FILE), conversation.getNextCounterpart().toString()};
cursor = db.query(Message.TABLENAME, null, Message.CONVERSATION
+ "=? and (" + Message.TYPE + "=? or " + Message.TYPE + "=?) and " + Message.COUNTERPART + "=?" , selectionArgs, null, null, Message.TIME_SENT
+ " DESC", String.valueOf(limit));
}
} else {
String[] selectionArgs = {conversation.getUuid(),
Long.toString(timestamp)};
cursor = db.query(Message.TABLENAME, null, Message.CONVERSATION
+ "=? and " + Message.TIME_SENT + "<?", selectionArgs,
null, null, Message.TIME_SENT + " DESC",
String.valueOf(limit));
if (conversation.getNextCounterpart() == null) {
String[] selectionArgs = {conversation.getUuid(),
Long.toString(timestamp)};
cursor = db.query(Message.TABLENAME, null, Message.CONVERSATION
+ "=? and " + Message.TIME_SENT + "<?", selectionArgs,
null, null, Message.TIME_SENT + " DESC",
String.valueOf(limit));
} else {
String[] selectionArgs = {conversation.getUuid(), String.valueOf(Message.TYPE_PRIVATE), String.valueOf(Message.TYPE_PRIVATE_FILE), conversation.getNextCounterpart().toString(), Long.toString(timestamp)};
cursor = db.query(Message.TABLENAME, null, Message.CONVERSATION
+ "=? and (" + Message.TYPE + "=? or " + Message.TYPE + "=?) and " + Message.COUNTERPART + "=? and " + Message.TIME_SENT + "<?" , selectionArgs, null, null, Message.TIME_SENT
+ " DESC", String.valueOf(limit));
}
}
CursorUtils.upgradeCursorWindowSize(cursor);
while (cursor.moveToNext()) {
try {
list.add(0, Message.fromCursor(cursor, conversation));
Message m = Message.fromCursor(cursor, conversation);
list.add(0, m);
} catch (Exception e) {
Log.e(Config.LOGTAG, "unable to restore message");
}
}
cursor.close();
return list;
}
@ -831,7 +851,7 @@ public class DatabaseBackend extends SQLiteOpenHelper {
final SQLiteDatabase db = this.getReadableDatabase();
final StringBuilder SQL = new StringBuilder();
final String[] selectionArgs;
SQL.append("SELECT " + Message.TABLENAME + ".*," + Conversation.TABLENAME + "." + Conversation.CONTACTJID + "," + Conversation.TABLENAME + "." + Conversation.ACCOUNT + "," + Conversation.TABLENAME + "." + Conversation.MODE + " FROM " + Message.TABLENAME + " JOIN " + Conversation.TABLENAME + " ON " + Message.TABLENAME + "." + Message.CONVERSATION + "=" + Conversation.TABLENAME + "." + Conversation.UUID + " JOIN messages_index ON messages_index.rowid=messages.rowid WHERE " + Message.ENCRYPTION + " NOT IN(" + Message.ENCRYPTION_AXOLOTL_NOT_FOR_THIS_DEVICE + "," + Message.ENCRYPTION_PGP + "," + Message.ENCRYPTION_DECRYPTION_FAILED + "," + Message.ENCRYPTION_AXOLOTL_FAILED + ") AND " + Message.TYPE + " IN(" + Message.TYPE_TEXT + "," + Message.TYPE_PRIVATE + ") AND messages_index.body MATCH ?");
SQL.append("SELECT " + Message.TABLENAME + ".*," + Conversation.TABLENAME + "." + Conversation.CONTACTJID + "," + Conversation.TABLENAME + "." + Conversation.ACCOUNT + "," + Conversation.TABLENAME + "." + Conversation.MODE + "," + Conversation.TABLENAME + "." + Conversation.NEXT_COUNTERPART + " FROM " + Message.TABLENAME + " JOIN " + Conversation.TABLENAME + " ON " + Message.TABLENAME + "." + Message.CONVERSATION + "=" + Conversation.TABLENAME + "." + Conversation.UUID + " JOIN messages_index ON messages_index.rowid=messages.rowid WHERE " + Message.ENCRYPTION + " NOT IN(" + Message.ENCRYPTION_AXOLOTL_NOT_FOR_THIS_DEVICE + "," + Message.ENCRYPTION_PGP + "," + Message.ENCRYPTION_DECRYPTION_FAILED + "," + Message.ENCRYPTION_AXOLOTL_FAILED + ") AND " + Message.TYPE + " IN(" + Message.TYPE_TEXT + "," + Message.TYPE_PRIVATE + ") AND messages_index.body MATCH ?");
if (uuid == null) {
selectionArgs = new String[]{FtsUtils.toMatchString(term)};
} else {
@ -949,25 +969,52 @@ public class DatabaseBackend extends SQLiteOpenHelper {
}
}
public Conversation findConversation(final Account account, final Jid contactJid) {
public Conversation findConversation(final Account account, final Jid contactJid, final Jid counterpart) {
SQLiteDatabase db = this.getReadableDatabase();
String[] selectionArgs = {account.getUuid(),
contactJid.asBareJid().toString() + "/%",
contactJid.asBareJid().toString()
};
try(final Cursor cursor = db.query(Conversation.TABLENAME, null,
Conversation.ACCOUNT + "=? AND (" + Conversation.CONTACTJID
+ " like ? OR " + Conversation.CONTACTJID + "=?)", selectionArgs, null, null, null)) {
if (cursor.getCount() == 0) {
return null;
if (counterpart != null) {
String[] selectionArgs = {account.getUuid(),
contactJid.asBareJid().toString() + "/%",
contactJid.asBareJid().toString(),
counterpart.toString()
};
try (final Cursor cursor = db.query(Conversation.TABLENAME, null,
Conversation.ACCOUNT + "=? AND (" + Conversation.CONTACTJID
+ " like ? OR " + Conversation.CONTACTJID + "=?) AND " + Conversation.NEXT_COUNTERPART + "=?", selectionArgs, null, null, null)) {
if (cursor.getCount() != 0) {
cursor.moveToFirst();
final Conversation conversation = Conversation.fromCursor(cursor);
if (!(conversation.getJid() instanceof InvalidJid)) {
return conversation;
}
}
}
cursor.moveToFirst();
final Conversation conversation = Conversation.fromCursor(cursor);
if (conversation.getJid() instanceof InvalidJid) {
return null;
} else {
String[] selectionArgs = new String[]{
account.getUuid(),
contactJid.asBareJid().toString() + "/%",
contactJid.asBareJid().toString()
};
try(final Cursor cursor = db.query(Conversation.TABLENAME, null,
Conversation.ACCOUNT + "=? AND (" + Conversation.CONTACTJID
+ " like ? OR " + Conversation.CONTACTJID + "=?)", selectionArgs, null, null, null)) {
if (cursor.getCount() == 0) {
return null;
}
cursor.moveToFirst();
final Conversation conversation = Conversation.fromCursor(cursor);
if (!(conversation.getJid() instanceof InvalidJid)) {
return conversation;
}
}
return conversation;
}
return null;
}
public void updateConversation(final Conversation conversation) {

View file

@ -302,7 +302,7 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded {
if (conversation.getMode() == Conversation.MODE_SINGLE) {
return get(conversation.getContact(), size, cachedOnly);
} else {
return get(conversation.getMucOptions(), size, cachedOnly);
return get(conversation.getMucOptions(), size, cachedOnly, conversation.getNextCounterpart());
}
}
@ -325,13 +325,21 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded {
}
}
private Bitmap get(MucOptions mucOptions, int size, boolean cachedOnly) {
final String KEY = key(mucOptions, size);
private Bitmap get(MucOptions mucOptions, int size, boolean cachedOnly, Jid nextCounterpart) {
final String KEY = key(mucOptions, size, nextCounterpart);
Bitmap bitmap = this.mXmppConnectionService.getBitmapCache().get(KEY);
if (bitmap != null || cachedOnly) {
return bitmap;
}
if (nextCounterpart != null) {
for (MucOptions.User u : mucOptions.getUsersRelevantForNameAndAvatar()) {
if (u.getComparableName().equals(nextCounterpart.getResource())) {
return get(u, size, cachedOnly);
}
}
}
bitmap = mXmppConnectionService.getFileBackend().getAvatar(mucOptions.getAvatar(), size);
if (bitmap == null) {
@ -404,16 +412,21 @@ public class AvatarService implements OnAdvancedStreamFeaturesLoaded {
}
synchronized (this.sizes) {
for (Integer size : sizes) {
this.mXmppConnectionService.getBitmapCache().remove(key(options, size));
this.mXmppConnectionService.getBitmapCache().remove(key(options, size, null));
}
}
}
private String key(final MucOptions options, int size) {
private String key(final MucOptions options, int size, Jid nextCounterpart) {
synchronized (this.sizes) {
this.sizes.add(size);
}
return PREFIX_CONVERSATION + "_" + options.getConversation().getUuid() + "_" + size;
if (nextCounterpart == null) {
return PREFIX_CONVERSATION + "_" + options.getConversation().getUuid() + "_" + size;
} else {
return PREFIX_CONVERSATION + "_" + options.getConversation().getUuid() + "_" + size + "_" + nextCounterpart;
}
}
private String key(List<MucOptions.User> users, int size) {

View file

@ -102,6 +102,7 @@ public class MessageSearchTask implements Runnable, Cancellable {
final int indexAccount = cursor.getColumnIndex(Conversation.ACCOUNT);
final int indexContact = cursor.getColumnIndex(Conversation.CONTACTJID);
final int indexMode = cursor.getColumnIndex(Conversation.MODE);
final int indexNextCounterpart = cursor.getColumnIndex(Conversation.NEXT_COUNTERPART);
do {
if (isCancelled) {
Log.d(Config.LOGTAG, "canceled search task");
@ -117,8 +118,9 @@ public class MessageSearchTask implements Runnable, Cancellable {
if (conversation == null) {
String accountUuid = cursor.getString(indexAccount);
String contactJid = cursor.getString(indexContact);
String nextCounterpart = cursor.getString(indexNextCounterpart);
int mode = cursor.getInt(indexMode);
conversation = findOrGenerateStub(conversationUuid, accountUuid, contactJid, mode);
conversation = findOrGenerateStub(conversationUuid, accountUuid, contactJid, mode, nextCounterpart);
conversationCache.put(conversationUuid, conversation);
}
Message message = IndividualMessage.fromCursor(cursor, conversation);
@ -137,7 +139,7 @@ public class MessageSearchTask implements Runnable, Cancellable {
}
}
private Conversational findOrGenerateStub(String conversationUuid, String accountUuid, String contactJid, int mode) throws Exception {
private Conversational findOrGenerateStub(String conversationUuid, String accountUuid, String contactJid, int mode, String nextCounterpart) throws Exception {
Conversation conversation = xmppConnectionService.findConversationByUuid(conversationUuid);
if (conversation != null) {
return conversation;
@ -145,7 +147,7 @@ public class MessageSearchTask implements Runnable, Cancellable {
Account account = xmppConnectionService.findAccountByUuid(accountUuid);
Jid jid = Jid.of(contactJid);
if (account != null && jid != null) {
return new StubConversation(account, conversationUuid, jid.asBareJid(), mode);
return new StubConversation(account, conversationUuid, jid.asBareJid(), mode, Jid.of(nextCounterpart));
}
throw new Exception("Unable to generate stub for " + contactJid);
}

View file

@ -463,7 +463,7 @@ public class NotificationService {
final int failedDeliveries = conversation.countFailedDeliveries();
final Notification notification =
new Builder(mXmppConnectionService, "delivery_failed")
.setContentTitle(conversation.getName())
.setContentTitle(getConversationName(conversation))
.setAutoCancel(true)
.setSmallIcon(R.drawable.ic_error_white_24dp)
.setContentText(
@ -1104,7 +1104,7 @@ public class NotificationService {
continue;
}
conversation = (Conversation) messages.get(0).getConversation();
final String name = conversation.getName().toString();
final String name = getConversationName(conversation);
SpannableString styledString;
if (Config.HIDE_MESSAGE_TEXT_IN_NOTIFICATION) {
int count = messages.size();
@ -1166,7 +1166,7 @@ public class NotificationService {
.get(
conversation,
AvatarService.getSystemUiAvatarSize(mXmppConnectionService)));
mBuilder.setContentTitle(conversation.getName());
mBuilder.setContentTitle(getConversationName(conversation));
if (Config.HIDE_MESSAGE_TEXT_IN_NOTIFICATION) {
int count = messages.size();
mBuilder.setContentText(
@ -1375,7 +1375,7 @@ public class NotificationService {
new NotificationCompat.MessagingStyle(me);
final boolean multiple = conversation.getMode() == Conversation.MODE_MULTI;
if (multiple) {
messagingStyle.setConversationTitle(conversation.getName());
messagingStyle.setConversationTitle(getConversationName(conversation));
}
for (Message message : messages) {
final Person sender =
@ -1913,6 +1913,14 @@ public class NotificationService {
}
}
private String getConversationName(Conversation c) {
if (c.getNextCounterpart() == null) {
return c.getName().toString();
} else {
return mXmppConnectionService.getResources().getString(R.string.muc_private_conversation_title, c.getNextCounterpart().getResource(), c.getName());
}
}
private static class MissedCallsInfo {
private int numberOfCalls;
private long lastTime;

View file

@ -71,6 +71,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
@ -642,16 +643,17 @@ public class XmppConnectionService extends Service {
});
}
public Conversation find(Bookmark bookmark) {
return find(bookmark.getAccount(), bookmark.getJid());
public Conversation find(final Account account, final Jid jid, final Jid counterpart) {
return find(getConversations(), account, jid, counterpart);
}
public Conversation find(final Account account, final Jid jid) {
return find(getConversations(), account, jid);
public List<Conversation> findAll(final Account account, final Jid jid) {
return findAll(getConversations(), account, jid);
}
public boolean isMuc(final Account account, final Jid jid) {
final Conversation c = find(account, jid);
final Conversation c = find(account, jid, null);
return c != null && c.getMode() == Conversational.MODE_MULTI;
}
@ -1817,7 +1819,7 @@ public class XmppConnectionService extends Service {
}
public void processDeletedBookmark(Account account, Jid jid) {
final Conversation conversation = find(account, jid);
final Conversation conversation = find(account, jid, null);
if (conversation != null && conversation.getMucOptions().getError() == MucOptions.Error.DESTROYED) {
Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": archiving destroyed conference (" + conversation.getJid() + ") after receiving pep");
archiveConversation(conversation, false);
@ -1826,7 +1828,7 @@ public class XmppConnectionService extends Service {
private void processModifiedBookmark(Bookmark bookmark, final boolean pep, final boolean synchronizeWithBookmarks) {
final Account account = bookmark.getAccount();
Conversation conversation = find(bookmark);
Conversation conversation = find(bookmark.getAccount(), bookmark.getJid(), null);
if (conversation != null) {
if (conversation.getMode() != Conversation.MODE_MULTI) {
return;
@ -1847,7 +1849,7 @@ public class XmppConnectionService extends Service {
}
}
} else if (synchronizeWithBookmarks && bookmark.autojoin()) {
conversation = findOrCreateConversation(account, bookmark.getFullJid(), true, true, false);
conversation = findOrCreateConversation(account, bookmark.getFullJid(), null, true, true, false, null);
bookmark.setConversation(conversation);
}
}
@ -1939,6 +1941,17 @@ public class XmppConnectionService extends Service {
});
}
private Map<String, Conversation> computeBareIdConversationsMap() {
Map<String, Conversation> res = new HashMap<>();
for (Conversation c : this.conversations) {
if (c.getNextCounterpart() == null) {
res.put(c.getJid().asBareJid().toString(), c);
}
}
return res;
}
private void restoreFromDatabase() {
synchronized (this.conversations) {
final Map<String, Account> accountLookupTable = new Hashtable<>();
@ -1948,7 +1961,24 @@ public class XmppConnectionService extends Service {
Log.d(Config.LOGTAG, "restoring conversations...");
final long startTimeConversationsRestore = SystemClock.elapsedRealtime();
this.conversations.addAll(databaseBackend.getConversations(Conversation.STATUS_AVAILABLE));
for (Iterator<Conversation> iterator = conversations.listIterator(); iterator.hasNext(); ) {
Map<String, Conversation> map = null;
for (Conversation c : this.conversations) {
if (c.getNextCounterpart() != null) {
if (map == null) {
map = computeBareIdConversationsMap();
}
Conversation parent = map.get(c.getJid().asBareJid().toString());
if (parent != null) {
c.setParentConversation(parent);
}
}
}
for (Iterator<Conversation> iterator = conversations.listIterator(); iterator.hasNext();) {
Conversation conversation = iterator.next();
Account account = accountLookupTable.get(conversation.getAccountUuid());
if (account != null) {
@ -2140,7 +2170,9 @@ public class XmppConnectionService extends Service {
if (messages.size() > 0) {
conversation.addAll(0, messages);
callback.onMoreMessagesLoaded(messages.size(), conversation);
} else if (conversation.hasMessagesLeftOnServer()
} else if (
conversation.getNextCounterpart() == null
&& conversation.hasMessagesLeftOnServer()
&& account.isOnlineAndConnected()
&& conversation.getLastClearHistory().getTimestamp() == 0) {
final boolean mamAvailable;
@ -2195,19 +2227,52 @@ public class XmppConnectionService extends Service {
return null;
}
public Conversation find(final Iterable<Conversation> haystack, final Account account, final Jid jid) {
private Conversation find(final Iterable<Conversation> haystack, final Account account, final Jid jid, final Jid counterpart) {
if (jid == null) {
return null;
}
for (final Conversation conversation : haystack) {
if ((account == null || conversation.getAccount() == account)
&& (conversation.getJid().asBareJid().equals(jid.asBareJid()))) {
return conversation;
if (counterpart != null) {
for (final Conversation conversation : haystack) {
if ((account == null || conversation.getAccount() == account)
&& (conversation.getJid().asBareJid().equals(jid.asBareJid()))
&& Objects.equal(conversation.getNextCounterpart(), counterpart)
) {
return conversation;
}
}
} else {
for (final Conversation conversation : haystack) {
if ((account == null || conversation.getAccount() == account)
&& (conversation.getJid().asBareJid().equals(jid.asBareJid()))
&& conversation.getNextCounterpart() == null
) {
return conversation;
}
}
}
return null;
}
private List<Conversation> findAll(final Iterable<Conversation> haystack, final Account account, final Jid jid) {
if (jid == null) {
return null;
}
List<Conversation> res = new ArrayList<>();
for (final Conversation conversation : haystack) {
if ((account == null || conversation.getAccount() == account)
&& (conversation.getJid().asBareJid().equals(jid.asBareJid()))
) {
res.add(conversation);
}
}
return res;
}
public boolean isConversationsListEmpty(final Conversation ignore) {
synchronized (this.conversations) {
final int size = this.conversations.size();
@ -2225,22 +2290,13 @@ public class XmppConnectionService extends Service {
}
return false;
}
public Conversation findOrCreateConversation(Account account, Jid jid, boolean muc, final boolean async) {
return this.findOrCreateConversation(account, jid, muc, false, async);
}
public Conversation findOrCreateConversation(final Account account, final Jid jid, final boolean muc, final boolean joinAfterCreate, final boolean async) {
return this.findOrCreateConversation(account, jid, muc, joinAfterCreate, null, async);
}
public Conversation findOrCreateConversation(final Account account, final Jid jid, final boolean muc, final boolean joinAfterCreate, final MessageArchiveService.Query query, final boolean async) {
public Conversation findOrCreateConversation(final Account account, final Jid jid, final MessageArchiveService.Query query, final boolean muc, final boolean joinAfterCreate, final boolean async, Jid counterpart) {
synchronized (this.conversations) {
Conversation conversation = find(account, jid);
Conversation conversation = find(account, jid, counterpart);
if (conversation != null) {
return conversation;
}
conversation = databaseBackend.findConversation(account, jid);
conversation = databaseBackend.findConversation(account, jid, counterpart);
final boolean loadMessagesFromDb;
if (conversation != null) {
conversation.setStatus(Conversation.STATUS_AVAILABLE);
@ -2262,12 +2318,13 @@ public class XmppConnectionService extends Service {
} else {
conversationName = jid.getLocal();
}
if (muc) {
conversation = new Conversation(conversationName, account, jid,
Conversation.MODE_MULTI);
Conversation.MODE_MULTI, counterpart);
} else {
conversation = new Conversation(conversationName, account, jid.asBareJid(),
Conversation.MODE_SINGLE);
Conversation.MODE_SINGLE, counterpart);
}
this.databaseBackend.createConversation(conversation);
loadMessagesFromDb = false;
@ -2301,6 +2358,14 @@ public class XmppConnectionService extends Service {
runnable.run();
}
this.conversations.add(conversation);
if (counterpart != null) {
Conversation parent = find(account, jid, null);
if (parent != null) {
conversation.setParentConversation(parent);
}
}
updateConversationUi();
return conversation;
}
@ -3284,7 +3349,7 @@ public class XmppConnectionService extends Service {
public void createPublicChannel(final Account account, final String name, final Jid address, final UiCallback<Conversation> callback) {
joinMuc(findOrCreateConversation(account, address, true, false, true), conversation -> {
joinMuc(findOrCreateConversation(account, address, null, true, false, true, null), conversation -> {
final Bundle configuration = IqGenerator.defaultChannelConfiguration();
if (!TextUtils.isEmpty(name)) {
configuration.putString("muc#roomconfig_roomname", name);
@ -3323,7 +3388,7 @@ public class XmppConnectionService extends Service {
return false;
}
final Jid jid = Jid.of(CryptoHelper.pronounceable(), server, null);
final Conversation conversation = findOrCreateConversation(account, jid, true, false, true);
final Conversation conversation = findOrCreateConversation(account, jid, null, true, false, true, null);
joinMuc(conversation, new OnConferenceJoined() {
@Override
public void onConferenceJoined(final Conversation conversation) {
@ -3971,7 +4036,7 @@ public class XmppConnectionService extends Service {
}
updateConversationUi();
} else {
Conversation conversation = find(account, avatar.owner.asBareJid());
Conversation conversation = find(account, avatar.owner.asBareJid(), null);
if (conversation != null && conversation.getMode() == Conversation.MODE_MULTI) {
MucOptions.User user = conversation.getMucOptions().findUserByFullJid(avatar.owner);
if (user != null) {
@ -4138,8 +4203,8 @@ public class XmppConnectionService extends Service {
final Message message = conversation.findSentMessageWithUuidOrRemoteId(uuid);
if (message != null) {
markMessage(message, status, errorMessage);
return message;
}
return message;
}
}
return null;
@ -4371,7 +4436,7 @@ public class XmppConnectionService extends Service {
public Conversation findUniqueConversationByJid(XmppUri xmppUri) {
List<Conversation> findings = new ArrayList<>();
for (Conversation c : getConversations()) {
if (c.getAccount().isEnabled() && c.getJid().asBareJid().equals(xmppUri.getJid()) && ((c.getMode() == Conversational.MODE_MULTI) == xmppUri.isAction(XmppUri.ACTION_JOIN))) {
if (c.getAccount().isEnabled() && c.getJid().asBareJid().equals(xmppUri.getJid()) && c.getNextCounterpart() == null && ((c.getMode() == Conversational.MODE_MULTI) == xmppUri.isAction(XmppUri.ACTION_JOIN))) {
findings.add(c);
}
}
@ -4626,7 +4691,7 @@ public class XmppConnectionService extends Service {
public Conversation findFirstMuc(Jid jid) {
for (Conversation conversation : getConversations()) {
if (conversation.getAccount().isEnabled() && conversation.getJid().asBareJid().equals(jid.asBareJid()) && conversation.getMode() == Conversation.MODE_MULTI) {
if (conversation.getAccount().isEnabled() && conversation.getJid().asBareJid().equals(jid.asBareJid()) && conversation.getNextCounterpart() == null && conversation.getMode() == Conversation.MODE_MULTI) {
return conversation;
}
}

View file

@ -271,7 +271,7 @@ public class ChannelDiscoveryActivity extends XmppActivity implements MenuItem.O
final Jid jid = Config.DOMAIN_LOCK == null ? Jid.ofEscaped(selectedAccount) : Jid.ofLocalAndDomainEscaped(selectedAccount, Config.DOMAIN_LOCK);
final boolean syncAutoJoin = getBooleanPreference("autojoin", R.bool.autojoin);
final Account account = xmppConnectionService.findAccountByJid(jid);
final Conversation conversation = xmppConnectionService.findOrCreateConversation(account, result.getRoom(), true, true, true);
final Conversation conversation = xmppConnectionService.findOrCreateConversation(account, result.getRoom(), null, true, true, true, null);
Bookmark bookmark = conversation.getBookmark();
if (bookmark != null) {
if (!bookmark.autojoin() && syncAutoJoin) {

View file

@ -99,7 +99,17 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
public static void open(final Activity activity, final Conversation conversation) {
Intent intent = new Intent(activity, ConferenceDetailsActivity.class);
intent.setAction(ConferenceDetailsActivity.ACTION_VIEW_MUC);
intent.putExtra("uuid", conversation.getUuid());
Conversation parentConversation = conversation.getParentConversation();
String uuid;
if (parentConversation != null) {
uuid = parentConversation.getUuid();
} else {
uuid = conversation.getUuid();
}
intent.putExtra("uuid", uuid);
activity.startActivity(intent);
}

View file

@ -556,7 +556,6 @@ public class ConversationFragment extends XmppFragment
binding.textinput.append(conversation.getDraftMessage());
conversation.setDraftMessage(null);
} else if (conversation.getMode() == Conversation.MODE_MULTI) {
conversation.setNextCounterpart(null);
binding.textinput.setText("");
} else {
binding.textinput.setText("");
@ -1008,12 +1007,15 @@ public class ConversationFragment extends XmppFragment
this.binding.textInputHint.setVisibility(View.GONE);
this.binding.textinput.setHint(R.string.send_corrected_message);
} else if (multi && conversation.getNextCounterpart() != null) {
this.binding.textinput.setHint(R.string.send_unencrypted_message);
/*this.binding.textinput.setHint(R.string.send_unencrypted_message);
this.binding.textInputHint.setVisibility(View.VISIBLE);
this.binding.textInputHint.setText(
getString(
R.string.send_private_message_to,
conversation.getNextCounterpart().getResource()));
conversation.getNextCounterpart().getResource())); */
this.binding.textInputHint.setVisibility(View.GONE);
this.binding.textinput.setHint(UIHelper.getMessageHint(getActivity(), conversation));
getActivity().invalidateOptionsMenu();
} else if (multi && !conversation.getMucOptions().participating()) {
this.binding.textInputHint.setVisibility(View.GONE);
this.binding.textinput.setHint(R.string.you_are_not_participating);
@ -1651,7 +1653,7 @@ public class ConversationFragment extends XmppFragment
activity.switchToContactDetails(conversation.getContact());
break;
case R.id.action_muc_details:
ConferenceDetailsActivity.open(getActivity(), conversation);
ConferenceDetailsActivity.open(activity, conversation);
break;
case R.id.action_invite:
startActivityForResult(
@ -2407,14 +2409,8 @@ public class ConversationFragment extends XmppFragment
}
public void privateMessageWith(final Jid counterpart) {
if (conversation.setOutgoingChatState(Config.DEFAULT_CHAT_STATE)) {
activity.xmppConnectionService.sendChatState(conversation);
}
this.binding.textinput.setText("");
this.conversation.setNextCounterpart(counterpart);
updateChatMsgHint();
updateSendButton();
updateEditablity();
Conversation c = activity.xmppConnectionService.findOrCreateConversation(conversation.getAccount(), conversation.getJid(), null, true, true, false, counterpart);
activity.switchToConversation(c);
}
private void correctMessage(Message message) {

View file

@ -630,7 +630,11 @@ public class ConversationsActivity extends XmppActivity implements OnConversatio
if (mainFragment instanceof ConversationFragment) {
final Conversation conversation = ((ConversationFragment) mainFragment).getConversation();
if (conversation != null) {
actionBar.setTitle(conversation.getName());
if (conversation.getNextCounterpart() != null) {
actionBar.setTitle(getString(R.string.muc_private_conversation_title, conversation.getNextCounterpart().getResource(), conversation.getName()));
} else {
actionBar.setTitle(conversation.getName());
}
actionBar.setDisplayHomeAsUpEnabled(true);
ActionBarUtil.setActionBarOnClickListener(
binding.toolbar,

View file

@ -246,7 +246,7 @@ public class RtpSessionActivity extends XmppActivity
final Contact contact = getWith();
final Conversation conversation =
xmppConnectionService.findOrCreateConversation(
contact.getAccount(), contact.getJid(), false, true);
contact.getAccount(), contact.getJid(), null, false, false, true, null);
switchToConversation(conversation);
}
@ -1361,7 +1361,7 @@ public class RtpSessionActivity extends XmppActivity
final Account account = extractAccount(intent);
final Jid with = Jid.ofEscaped(intent.getStringExtra(EXTRA_WITH));
final Conversation conversation =
xmppConnectionService.findOrCreateConversation(account, with, false, true);
xmppConnectionService.findOrCreateConversation(account, with, null, false, false, true, null);
final Intent launchIntent = new Intent(this, ConversationsActivity.class);
launchIntent.setAction(ConversationsActivity.ACTION_VIEW_CONVERSATION);
launchIntent.putExtra(ConversationsActivity.EXTRA_CONVERSATION, conversation.getUuid());

View file

@ -201,9 +201,12 @@ public class SearchActivity extends XmppActivity implements TextWatcher, OnSearc
} else {
return xmppConnectionService.findOrCreateConversation(conversational.getAccount(),
conversational.getJid(),
null,
conversational.getMode() == Conversational.MODE_MULTI,
false,
true,
true);
conversational.getNextCounterpart()
);
}
}

View file

@ -178,7 +178,7 @@ public class ShareWithActivity extends XmppActivity implements XmppConnectionSer
}
try {
conversation = xmppConnectionService.findOrCreateConversation(account, Jid.of(share.contact), false, true);
conversation = xmppConnectionService.findOrCreateConversation(account, Jid.of(share.contact), null, false, false, true, null);
} catch (final IllegalArgumentException e) {
return;
}

View file

@ -93,6 +93,7 @@ import eu.siacs.conversations.ui.util.PendingItem;
import eu.siacs.conversations.ui.util.SoftKeyboardUtils;
import eu.siacs.conversations.ui.widget.SwipeRefreshListFragment;
import eu.siacs.conversations.utils.AccountUtils;
import eu.siacs.conversations.utils.StringUtils;
import eu.siacs.conversations.utils.UIHelper;
import eu.siacs.conversations.utils.XmppUri;
import eu.siacs.conversations.xmpp.Jid;
@ -430,7 +431,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
}
protected void openConversationForContact(Contact contact) {
Conversation conversation = xmppConnectionService.findOrCreateConversation(contact.getAccount(), contact.getJid(), false, true);
Conversation conversation = xmppConnectionService.findOrCreateConversation(contact.getAccount(), contact.getJid(), null, false, false, true, null);
SoftKeyboardUtils.hideSoftKeyboard(this);
switchToConversation(conversation);
}
@ -467,7 +468,7 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
Toast.makeText(this, R.string.invalid_jid, Toast.LENGTH_SHORT).show();
return;
}
Conversation conversation = xmppConnectionService.findOrCreateConversation(bookmark.getAccount(), jid, true, true, true);
Conversation conversation = xmppConnectionService.findOrCreateConversation(bookmark.getAccount(), jid, null, true, true, true, null);
bookmark.setConversation(conversation);
if (!bookmark.autojoin() && getPreferences().getBoolean("autojoin", getResources().getBoolean(R.bool.autojoin))) {
bookmark.setAutojoin(true);
@ -580,13 +581,14 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
bookmark.setNick(nick);
}
xmppConnectionService.createBookmark(account, bookmark);
final Conversation conversation = xmppConnectionService
.findOrCreateConversation(account, contactJid, true, true, true);
.findOrCreateConversation(account, contactJid, null, true, true, true, null);
bookmark.setConversation(conversation);
switchToConversationDoNotAppend(conversation, invite == null ? null : invite.getBody());
}
} else {
final Conversation conversation = xmppConnectionService.findOrCreateConversation(account, contactJid, true, true, true);
final Conversation conversation = xmppConnectionService.findOrCreateConversation(account, contactJid, null, true, true, true, null);
switchToConversationDoNotAppend(conversation, invite == null ? null : invite.getBody());
}
} else {
@ -669,13 +671,8 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
}
}
protected void switchToConversation(Contact contact) {
Conversation conversation = xmppConnectionService.findOrCreateConversation(contact.getAccount(), contact.getJid(), false, true);
switchToConversation(conversation);
}
protected void switchToConversationDoNotAppend(Contact contact, String body) {
Conversation conversation = xmppConnectionService.findOrCreateConversation(contact.getAccount(), contact.getJid(), false, true);
Conversation conversation = xmppConnectionService.findOrCreateConversation(contact.getAccount(), contact.getJid(), null, false, false, true, null);
switchToConversationDoNotAppend(conversation, body);
}
@ -1192,14 +1189,14 @@ public class StartConversationActivity extends XmppActivity implements XmppConne
}
xmppConnectionService.createBookmark(account, bookmark);
final Conversation conversation = xmppConnectionService
.findOrCreateConversation(account, conferenceJid, true, true, true);
.findOrCreateConversation(account, conferenceJid, null, true, true, true, null);
bookmark.setConversation(conversation);
dialog.dismiss();
switchToConversation(conversation);
}
} else {
final Conversation conversation = xmppConnectionService
.findOrCreateConversation(account, conferenceJid, true, true, true);
.findOrCreateConversation(account, conferenceJid, null, true, true, true, null);
dialog.dismiss();
switchToConversation(conversation);
}

View file

@ -552,7 +552,7 @@ public abstract class XmppActivity extends ActionBarActivity {
}
protected void switchToConversationDoNotAppend(Contact contact, String body, String postInit) {
Conversation conversation = xmppConnectionService.findOrCreateConversation(contact.getAccount(), contact.getJid(), false, true);
Conversation conversation = xmppConnectionService.findOrCreateConversation(contact.getAccount(), contact.getJid(), null, false, false, true, null);
switchToConversation(conversation, body, false, null, false, true, postInit);
}

View file

@ -59,7 +59,12 @@ public class ConversationAdapter
if (conversation == null) {
return;
}
CharSequence name = conversation.getName();
if (conversation.getNextCounterpart() != null) {
name = viewHolder.binding.getRoot().getResources().getString(R.string.muc_private_conversation_title, conversation.getNextCounterpart().getResource(), conversation.getName());
}
if (name instanceof Jid) {
viewHolder.binding.conversationName.setText(
IrregularUnicodeDetector.style(activity, (Jid) name));

View file

@ -523,7 +523,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
} else {
String privateMarker;
/*String privateMarker;
if (message.getStatus() <= Message.STATUS_RECEIVED) {
privateMarker = activity.getString(R.string.private_message);
} else {
@ -544,7 +544,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
if (hasMeCommand) {
body.setSpan(new StyleSpan(Typeface.BOLD_ITALIC), privateMarkerIndex + 1,
privateMarkerIndex + 1 + nick.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}*/
}
if (message.getConversation().getMode() == Conversation.MODE_MULTI && message.getStatus() == Message.STATUS_RECEIVED) {
if (message.getConversation() instanceof Conversation) {
@ -644,7 +644,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
}
private void toggleWhisperInfo(ViewHolder viewHolder, final Message message, final boolean darkBackground) {
if (message.isPrivateMessage()) {
if (false && message.isPrivateMessage()) {
final String privateMarker;
if (message.getStatus() <= Message.STATUS_RECEIVED) {
privateMarker = activity.getString(R.string.private_message);

View file

@ -120,7 +120,8 @@ public final class MucDetailsContextMenuHelper {
}
}
managePermissions.setVisible(managePermissionsVisible);
sendPrivateMessage.setVisible(!isGroupChat && mucOptions.allowPm() && user.getRole().ranks(MucOptions.Role.VISITOR));
sendPrivateMessage.setVisible(true);
sendPrivateMessage.setEnabled(true);
} else {
sendPrivateMessage.setVisible(true);
sendPrivateMessage.setEnabled(user != null && mucOptions.allowPm() && user.getRole().ranks(MucOptions.Role.VISITOR));
@ -222,7 +223,7 @@ public final class MucDetailsContextMenuHelper {
private static void startConversation(User user, XmppActivity activity) {
if (user.getRealJid() != null) {
Conversation newConversation = activity.xmppConnectionService.findOrCreateConversation(user.getAccount(), user.getRealJid().asBareJid(), false, true);
Conversation newConversation = activity.xmppConnectionService.findOrCreateConversation(user.getAccount(), user.getRealJid().asBareJid(), null, false, false, true, null);
activity.switchToConversation(newConversation);
}
}

View file

@ -59,7 +59,7 @@ public class SendButtonTool {
}
} else {
if (empty) {
if (conference && c.getNextCounterpart() != null) {
if (false && conference && c.getNextCounterpart() != null) {
return SendButtonAction.CANCEL;
} else {
String setting = preferences.getString("quick_action", activity.getResources().getString(R.string.quick_action));

View file

@ -89,7 +89,7 @@ public class ExceptionHelper {
builder.setPositiveButton(activity.getText(R.string.send_now), (dialog, which) -> {
Log.d(Config.LOGTAG, "using account=" + account.getJid().asBareJid() + " to send in stack trace");
Conversation conversation = service.findOrCreateConversation(account, Config.BUG_REPORTS, false, true);
Conversation conversation = service.findOrCreateConversation(account, Config.BUG_REPORTS, null, false, false, true, null);
Message message = new Message(conversation, report.toString(), Message.ENCRYPTION_NONE);
service.sendMessage(message);
});

View file

@ -297,7 +297,7 @@ public class JingleConnectionManager extends AbstractConnectionManager {
if ("proceed".equals(message.getName())) {
final Conversation c =
mXmppConnectionService.findOrCreateConversation(
account, id.with, false, false);
account, id.with, null, false, false, false, null);
final Message previousBusy = c.findRtpSession(sessionId, Message.STATUS_RECEIVED);
if (previousBusy != null) {
previousBusy.setBody(new RtpSessionStatus(true, 0).toString());
@ -503,7 +503,7 @@ public class JingleConnectionManager extends AbstractConnectionManager {
long timestamp) {
final Conversation conversation =
mXmppConnectionService.findOrCreateConversation(
account, with.asBareJid(), false, false);
account, with.asBareJid(), null, false, false, false, null);
final Message message =
new Message(conversation, Message.STATUS_SEND, Message.TYPE_RTP_SESSION, sessionId);
message.setBody(new RtpSessionStatus(false, 0).toString());
@ -520,7 +520,7 @@ public class JingleConnectionManager extends AbstractConnectionManager {
long timestamp) {
final Conversation conversation =
mXmppConnectionService.findOrCreateConversation(
account, with.asBareJid(), false, false);
account, with.asBareJid(), null, false, false, false, null);
final Message message =
new Message(
conversation, Message.STATUS_RECEIVED, Message.TYPE_RTP_SESSION, sessionId);

View file

@ -426,7 +426,7 @@ public class JingleFileTransferConnection extends AbstractJingleConnection imple
private void init(JinglePacket packet) { //should move to deliverPacket
//TODO if not 'OFFERED' reply with out-of-order
this.mJingleStatus = JINGLE_STATUS_INITIATED;
final Conversation conversation = this.xmppConnectionService.findOrCreateConversation(id.account, id.with.asBareJid(), false, false);
final Conversation conversation = this.xmppConnectionService.findOrCreateConversation(id.account, id.with.asBareJid(), null, false, false, false, null);
this.message = new Message(conversation, "", Message.ENCRYPTION_NONE);
this.message.setStatus(Message.STATUS_RECEIVED);
this.mStatus = Transferable.STATUS_OFFER;

View file

@ -180,7 +180,7 @@ public class JingleRtpConnection extends AbstractJingleConnection
final Conversation conversation =
jingleConnectionManager
.getXmppConnectionService()
.findOrCreateConversation(id.account, id.with.asBareJid(), false, false);
.findOrCreateConversation(id.account, id.with.asBareJid(), null, false, false, false, null);
this.message =
new Message(
conversation,

View file

@ -1045,4 +1045,5 @@
<string name="resize">resize</string>
<string name="filter">filter</string>
<string name="could_not_create_file">could_not_create_file</string>
<string name="muc_private_conversation_title">%1$s (%2$s)</string>
</resources>