brought ad hoc conferences back. fixed #688 fixed #367

This commit is contained in:
iNPUTmice 2014-11-20 18:20:42 +01:00
parent e9948f6b84
commit 0ad6d0616f
13 changed files with 481 additions and 138 deletions

View file

@ -149,11 +149,19 @@ public class Conversation extends AbstractEntity {
} }
public String getName() { public String getName() {
if (getMode() == MODE_MULTI && getMucOptions().getSubject() != null) { if (getMode() == MODE_MULTI) {
return getMucOptions().getSubject(); if (getMucOptions().getSubject() != null) {
} else if (getMode() == MODE_MULTI && bookmark != null return getMucOptions().getSubject();
&& bookmark.getName() != null) { } else if (bookmark != null && bookmark.getName() != null) {
return bookmark.getName(); return bookmark.getName();
} else {
String generatedName = getMucOptions().createNameFromParticipants();
if (generatedName != null) {
return generatedName;
} else {
return getContactJid().getLocalpart();
}
}
} else { } else {
return this.getContact().getDisplayName(); return this.getContact().getDisplayName();
} }

View file

@ -4,18 +4,20 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.crypto.PgpEngine; import eu.siacs.conversations.crypto.PgpEngine;
import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.InvalidJidException;
import eu.siacs.conversations.xmpp.jid.Jid; import eu.siacs.conversations.xmpp.jid.Jid;
import eu.siacs.conversations.xmpp.stanzas.PresencePacket; import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.util.Log;
@SuppressLint("DefaultLocale") @SuppressLint("DefaultLocale")
public class MucOptions { public class MucOptions {
public static final int ERROR_NO_ERROR = 0; public static final int ERROR_NO_ERROR = 0;
public static final int ERROR_NICK_IN_USE = 1; public static final int ERROR_NICK_IN_USE = 1;
public static final int ERROR_ROOM_NOT_FOUND = 2; public static final int ERROR_UNKNOWN = 2;
public static final int ERROR_PASSWORD_REQUIRED = 3; public static final int ERROR_PASSWORD_REQUIRED = 3;
public static final int ERROR_BANNED = 4; public static final int ERROR_BANNED = 4;
public static final int ERROR_MEMBERS_ONLY = 5; public static final int ERROR_MEMBERS_ONLY = 5;
@ -25,8 +27,17 @@ public class MucOptions {
public static final String STATUS_CODE_BANNED = "301"; public static final String STATUS_CODE_BANNED = "301";
public static final String STATUS_CODE_KICKED = "307"; public static final String STATUS_CODE_KICKED = "307";
public interface OnRenameListener { private interface OnEventListener {
public void onRename(boolean success); public void onSuccess();
public void onFailure();
}
public interface OnRenameListener extends OnEventListener {
}
public interface OnJoinListener extends OnEventListener {
} }
public class User { public class User {
@ -119,13 +130,13 @@ public class MucOptions {
private List<User> users = new CopyOnWriteArrayList<>(); private List<User> users = new CopyOnWriteArrayList<>();
private Conversation conversation; private Conversation conversation;
private boolean isOnline = false; private boolean isOnline = false;
private int error = ERROR_ROOM_NOT_FOUND; private int error = ERROR_UNKNOWN;
private OnRenameListener renameListener = null; private OnRenameListener onRenameListener = null;
private boolean aboutToRename = false; private OnJoinListener onJoinListener = null;
private User self = new User(); private User self = new User();
private String subject = null; private String subject = null;
private String joinnick;
private String password = null; private String password = null;
private boolean mNickChangingInProgress = false;
public MucOptions(Conversation conversation) { public MucOptions(Conversation conversation) {
this.account = conversation.getAccount(); this.account = conversation.getAccount();
@ -155,10 +166,11 @@ public class MucOptions {
final Jid from = packet.getFrom(); final Jid from = packet.getFrom();
if (!from.isBareJid()) { if (!from.isBareJid()) {
final String name = from.getResourcepart(); final String name = from.getResourcepart();
String type = packet.getAttribute("type"); final String type = packet.getAttribute("type");
final Element x = packet.findChild("x","http://jabber.org/protocol/muc#user");
final List<String> codes = getStatusCodes(x);
if (type == null) { if (type == null) {
User user = new User(); User user = new User();
Element x = packet.findChild("x","http://jabber.org/protocol/muc#user");
if (x != null) { if (x != null) {
Element item = x.findChild("item"); Element item = x.findChild("item");
if (item != null) { if (item != null) {
@ -166,16 +178,16 @@ public class MucOptions {
user.setAffiliation(item.getAttribute("affiliation")); user.setAffiliation(item.getAttribute("affiliation"));
user.setRole(item.getAttribute("role")); user.setRole(item.getAttribute("role"));
user.setJid(item.getAttributeAsJid("jid")); user.setJid(item.getAttributeAsJid("jid"));
user.setName(name); if (codes.contains("110")) {
if (name.equals(this.joinnick)) {
this.isOnline = true; this.isOnline = true;
this.error = ERROR_NO_ERROR; this.error = ERROR_NO_ERROR;
self = user; self = user;
if (aboutToRename) { if (mNickChangingInProgress) {
if (renameListener != null) { onRenameListener.onSuccess();
renameListener.onRename(true); mNickChangingInProgress = false;
} } else if (this.onJoinListener != null) {
aboutToRename = false; this.onJoinListener.onSuccess();
this.onJoinListener = null;
} }
} else { } else {
addUser(user); addUser(user);
@ -196,48 +208,65 @@ public class MucOptions {
} }
} }
} }
} else if (type.equals("unavailable") && name.equals(this.joinnick)) { } else if (type.equals("unavailable") && codes.contains("110")) {
Element x = packet.findChild("x", if (codes.contains("303")) {
"http://jabber.org/protocol/muc#user"); this.mNickChangingInProgress = true;
if (x != null) { } else if (codes.contains(STATUS_CODE_KICKED)) {
Element status = x.findChild("status"); setError(KICKED_FROM_ROOM);
if (status != null) { } else if (codes.contains(STATUS_CODE_BANNED)) {
String code = status.getAttribute("code"); setError(ERROR_BANNED);
if (STATUS_CODE_KICKED.equals(code)) { } else {
this.isOnline = false; setError(ERROR_UNKNOWN);
this.error = KICKED_FROM_ROOM;
} else if (STATUS_CODE_BANNED.equals(code)) {
this.isOnline = false;
this.error = ERROR_BANNED;
}
}
} }
} else if (type.equals("unavailable")) { } else if (type.equals("unavailable")) {
deleteUser(packet.getAttribute("from").split("/", 2)[1]); deleteUser(name);
} else if (type.equals("error")) { } else if (type.equals("error")) {
Element error = packet.findChild("error"); Element error = packet.findChild("error");
if (error != null && error.hasChild("conflict")) { if (error != null && error.hasChild("conflict")) {
if (aboutToRename) { if (isOnline) {
if (renameListener != null) { if (onRenameListener != null) {
renameListener.onRename(false); onRenameListener.onFailure();
} }
aboutToRename = false;
this.setJoinNick(getActualNick());
} else { } else {
this.error = ERROR_NICK_IN_USE; setError(ERROR_NICK_IN_USE);
} }
} else if (error != null && error.hasChild("not-authorized")) { } else if (error != null && error.hasChild("not-authorized")) {
this.error = ERROR_PASSWORD_REQUIRED; setError(ERROR_PASSWORD_REQUIRED);
} else if (error != null && error.hasChild("forbidden")) { } else if (error != null && error.hasChild("forbidden")) {
this.error = ERROR_BANNED; setError(ERROR_BANNED);
} else if (error != null } else if (error != null && error.hasChild("registration-required")) {
&& error.hasChild("registration-required")) { setError(ERROR_MEMBERS_ONLY);
this.error = ERROR_MEMBERS_ONLY; } else {
setError(ERROR_UNKNOWN);
} }
} }
} }
} }
private void setError(int error) {
this.isOnline = false;
this.error = error;
if (onJoinListener != null) {
onJoinListener.onFailure();
onJoinListener = null;
}
}
private List<String> getStatusCodes(Element x) {
List<String> codes = new ArrayList<String>();
if (x != null) {
for(Element child : x.getChildren()) {
if (child.getName().equals("status")) {
String code = child.getAttribute("code");
if (code!=null) {
codes.add(code);
}
}
}
}
return codes;
}
public List<User> getUsers() { public List<User> getUsers() {
return this.users; return this.users;
} }
@ -263,10 +292,6 @@ public class MucOptions {
} }
} }
public void setJoinNick(String nick) {
this.joinnick = nick;
}
public boolean online() { public boolean online() {
return this.isOnline; return this.isOnline;
} }
@ -276,11 +301,11 @@ public class MucOptions {
} }
public void setOnRenameListener(OnRenameListener listener) { public void setOnRenameListener(OnRenameListener listener) {
this.renameListener = listener; this.onRenameListener = listener;
} }
public OnRenameListener getOnRenameListener() { public void setOnJoinListener(OnJoinListener listener) {
return this.renameListener; this.onJoinListener = listener;
} }
public void setOffline() { public void setOffline() {
@ -301,8 +326,28 @@ public class MucOptions {
return this.subject; return this.subject;
} }
public void flagAboutToRename() { public String createNameFromParticipants() {
this.aboutToRename = true; if (users.size() >= 2) {
List<String> names = new ArrayList<String>();
for (User user : users) {
Contact contact = user.getContact();
if (contact != null && !contact.getDisplayName().isEmpty()) {
names.add(contact.getDisplayName().split("\\s+")[0]);
} else {
names.add(user.getName());
}
}
StringBuilder builder = new StringBuilder();
for (int i = 0; i < names.size(); ++i) {
builder.append(names.get(i));
if (i != names.size() - 1) {
builder.append(", ");
}
}
return builder.toString();
} else {
return null;
}
} }
public long[] getPgpKeyIds() { public long[] getPgpKeyIds() {
@ -337,10 +382,9 @@ public class MucOptions {
return true; return true;
} }
public Jid getJoinJid() { public Jid createJoinJid(String nick) {
try { try {
return Jid.fromString(this.conversation.getContactJid().toBareJid().toString() + "/" return Jid.fromString(this.conversation.getContactJid().toBareJid().toString() + "/"+nick);
+ this.joinnick);
} catch (final InvalidJidException e) { } catch (final InvalidJidException e) {
return null; return null;
} }
@ -356,8 +400,7 @@ public class MucOptions {
} }
public String getPassword() { public String getPassword() {
this.password = conversation this.password = conversation.getAttribute(Conversation.ATTRIBUTE_MUC_PASSWORD);
.getAttribute(Conversation.ATTRIBUTE_MUC_PASSWORD);
if (this.password == null && conversation.getBookmark() != null if (this.password == null && conversation.getBookmark() != null
&& conversation.getBookmark().getPassword() != null) { && conversation.getBookmark().getPassword() != null) {
return conversation.getBookmark().getPassword(); return conversation.getBookmark().getPassword();
@ -372,8 +415,7 @@ public class MucOptions {
} else { } else {
this.password = password; this.password = password;
} }
conversation conversation.setAttribute(Conversation.ATTRIBUTE_MUC_PASSWORD, password);
.setAttribute(Conversation.ATTRIBUTE_MUC_PASSWORD, password);
} }
public Conversation getConversation() { public Conversation getConversation() {

View file

@ -153,14 +153,14 @@ public class MessageGenerator extends AbstractGenerator {
return packet; return packet;
} }
public MessagePacket invite(Conversation conversation, String contact) { public MessagePacket invite(Conversation conversation, Jid contact) {
MessagePacket packet = new MessagePacket(); MessagePacket packet = new MessagePacket();
packet.setTo(conversation.getContactJid().toBareJid()); packet.setTo(conversation.getContactJid().toBareJid());
packet.setFrom(conversation.getAccount().getJid()); packet.setFrom(conversation.getAccount().getJid());
Element x = new Element("x"); Element x = new Element("x");
x.setAttribute("xmlns", "http://jabber.org/protocol/muc#user"); x.setAttribute("xmlns", "http://jabber.org/protocol/muc#user");
Element invite = new Element("invite"); Element invite = new Element("invite");
invite.setAttribute("to", contact); invite.setAttribute("to", contact.toBareJid().toString());
x.addChild(invite); x.addChild(invite);
packet.addChild(x); packet.addChild(x);
return packet; return packet;

View file

@ -274,7 +274,7 @@ public class AvatarService {
} }
} }
} }
String name = user.getName(); String name = contact != null ? contact.getDisplayName() : user.getName();
String letter; String letter;
int color; int color;
if (name.length() > 0) { if (name.length() > 0) {

View file

@ -35,6 +35,7 @@ import org.openintents.openpgp.util.OpenPgpServiceConnection;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.math.BigInteger;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
@ -273,7 +274,6 @@ public class XmppConnectionService extends Service {
} }
}; };
private LruCache<String, Bitmap> mBitmapCache; private LruCache<String, Bitmap> mBitmapCache;
private OnRenameListener renameListener = null;
private IqGenerator mIqGenerator = new IqGenerator(this); private IqGenerator mIqGenerator = new IqGenerator(this);
public PgpEngine getPgpEngine() { public PgpEngine getPgpEngine() {
@ -1055,10 +1055,6 @@ public class XmppConnectionService extends Service {
updateConversationUi(); updateConversationUi();
} }
public int getConversationCount() {
return this.databaseBackend.getConversationCount();
}
public void createAccount(Account account) { public void createAccount(Account account) {
account.initOtrEngine(this); account.initOtrEngine(this);
databaseBackend.createAccount(account); databaseBackend.createAccount(account);
@ -1276,10 +1272,9 @@ public class XmppConnectionService extends Service {
Log.d(Config.LOGTAG, Log.d(Config.LOGTAG,
"joining conversation " + conversation.getContactJid()); "joining conversation " + conversation.getContactJid());
String nick = conversation.getMucOptions().getProposedNick(); String nick = conversation.getMucOptions().getProposedNick();
conversation.getMucOptions().setJoinNick(nick); Jid joinJid = conversation.getMucOptions().createJoinJid(nick);
PresencePacket packet = new PresencePacket(); PresencePacket packet = new PresencePacket();
final Jid joinJid = conversation.getMucOptions().getJoinJid(); packet.setTo(joinJid);
packet.setTo(conversation.getMucOptions().getJoinJid());
Element x = new Element("x"); Element x = new Element("x");
x.setAttribute("xmlns", "http://jabber.org/protocol/muc"); x.setAttribute("xmlns", "http://jabber.org/protocol/muc");
if (conversation.getMucOptions().getPassword() != null) { if (conversation.getMucOptions().getPassword() != null) {
@ -1311,10 +1306,6 @@ public class XmppConnectionService extends Service {
} }
} }
public void setOnRenameListener(OnRenameListener listener) {
this.renameListener = listener;
}
public void providePasswordForMuc(Conversation conversation, String password) { public void providePasswordForMuc(Conversation conversation, String password) {
if (conversation.getMode() == Conversation.MODE_MULTI) { if (conversation.getMode() == Conversation.MODE_MULTI) {
conversation.getMucOptions().setPassword(password); conversation.getMucOptions().setPassword(password);
@ -1327,33 +1318,33 @@ public class XmppConnectionService extends Service {
} }
} }
public void renameInMuc(final Conversation conversation, final String nick) { public void renameInMuc(final Conversation conversation, final String nick, final UiCallback<Conversation> callback) {
final MucOptions options = conversation.getMucOptions(); final MucOptions options = conversation.getMucOptions();
options.setJoinNick(nick); final Jid joinJid = options.createJoinJid(nick);
if (options.online()) { if (options.online()) {
Account account = conversation.getAccount(); Account account = conversation.getAccount();
options.setOnRenameListener(new OnRenameListener() { options.setOnRenameListener(new OnRenameListener() {
@Override @Override
public void onRename(boolean success) { public void onSuccess() {
if (renameListener != null) { conversation.setContactJid(joinJid);
renameListener.onRename(success); databaseBackend.updateConversation(conversation);
} Bookmark bookmark = conversation.getBookmark();
if (success) { if (bookmark != null) {
conversation.setContactJid(conversation.getMucOptions() bookmark.setNick(nick);
.getJoinJid()); pushBookmarks(bookmark.getAccount());
databaseBackend.updateConversation(conversation);
Bookmark bookmark = conversation.getBookmark();
if (bookmark != null) {
bookmark.setNick(nick);
pushBookmarks(bookmark.getAccount());
}
} }
callback.success(conversation);
}
@Override
public void onFailure() {
callback.error(R.string.nick_in_use,conversation);
} }
}); });
options.flagAboutToRename();
PresencePacket packet = new PresencePacket(); PresencePacket packet = new PresencePacket();
packet.setTo(options.getJoinJid()); packet.setTo(joinJid);
packet.setFrom(conversation.getAccount().getJid()); packet.setFrom(conversation.getAccount().getJid());
String sig = account.getPgpSignature(); String sig = account.getPgpSignature();
@ -1363,7 +1354,7 @@ public class XmppConnectionService extends Service {
} }
sendPresencePacket(account, packet); sendPresencePacket(account, packet);
} else { } else {
conversation.setContactJid(options.getJoinJid()); conversation.setContactJid(joinJid);
databaseBackend.updateConversation(conversation); databaseBackend.updateConversation(conversation);
if (conversation.getAccount().getStatus() == Account.State.ONLINE) { if (conversation.getAccount().getStatus() == Account.State.ONLINE) {
Bookmark bookmark = conversation.getBookmark(); Bookmark bookmark = conversation.getBookmark();
@ -1382,7 +1373,7 @@ public class XmppConnectionService extends Service {
account.pendingConferenceLeaves.remove(conversation); account.pendingConferenceLeaves.remove(conversation);
if (account.getStatus() == Account.State.ONLINE) { if (account.getStatus() == Account.State.ONLINE) {
PresencePacket packet = new PresencePacket(); PresencePacket packet = new PresencePacket();
packet.setTo(conversation.getMucOptions().getJoinJid()); packet.setTo(conversation.getContactJid());
packet.setFrom(conversation.getAccount().getJid()); packet.setFrom(conversation.getAccount().getJid());
packet.setAttribute("type", "unavailable"); packet.setAttribute("type", "unavailable");
sendPresencePacket(conversation.getAccount(), packet); sendPresencePacket(conversation.getAccount(), packet);
@ -1395,6 +1386,117 @@ public class XmppConnectionService extends Service {
} }
} }
private String findConferenceServer(final Account account) {
String server;
if (account.getXmppConnection() != null) {
server = account.getXmppConnection().getMucServer();
if (server != null) {
return server;
}
}
for(Account other : getAccounts()) {
if (other != account && other.getXmppConnection() != null) {
server = other.getXmppConnection().getMucServer();
if (server != null) {
return server;
}
}
}
return null;
}
public void createAdhocConference(final Account account, final List<Jid> jids, final UiCallback<Conversation> callback) {
Log.d(Config.LOGTAG,account.getJid().toBareJid().toString()+": creating adhoc conference with "+ jids.toString());
if (account.getStatus() == Account.State.ONLINE) {
try {
String server = findConferenceServer(account);
if (server == null) {
if (callback != null) {
callback.error(R.string.no_conference_server_found,null);
}
return;
}
String name = new BigInteger(75,getRNG()).toString(32);
Jid jid = Jid.fromParts(name,server,null);
final Conversation conversation = findOrCreateConversation(account, jid, true);
joinMuc(conversation);
Bundle options = new Bundle();
options.putString("muc#roomconfig_persistentroom", "1");
options.putString("muc#roomconfig_membersonly", "1");
options.putString("muc#roomconfig_publicroom", "0");
options.putString("muc#roomconfig_whois", "anyone");
pushConferenceConfiguration(conversation, options, new OnConferenceOptionsPushed() {
@Override
public void onPushSucceeded() {
for(Jid invite : jids) {
invite(conversation,invite);
}
if (callback != null) {
callback.success(conversation);
}
}
@Override
public void onPushFailed() {
if (callback != null) {
callback.error(R.string.conference_creation_failed, conversation);
}
}
});
} catch (InvalidJidException e) {
if (callback != null) {
callback.error(R.string.conference_creation_failed, null);
}
}
} else {
if (callback != null) {
callback.error(R.string.not_connected_try_again,null);
}
}
}
public void pushConferenceConfiguration(final Conversation conversation,final Bundle options, final OnConferenceOptionsPushed callback) {
IqPacket request = new IqPacket(IqPacket.TYPE_GET);
request.setTo(conversation.getContactJid().toBareJid());
request.query("http://jabber.org/protocol/muc#owner");
sendIqPacket(conversation.getAccount(),request,new OnIqPacketReceived() {
@Override
public void onIqPacketReceived(Account account, IqPacket packet) {
if (packet.getType() != IqPacket.TYPE_ERROR) {
Data data = Data.parse(packet.query().findChild("x", "jabber:x:data"));
for (Field field : data.getFields()) {
if (options.containsKey(field.getName())) {
field.setValue(options.getString(field.getName()));
}
}
data.submit();
IqPacket set = new IqPacket(IqPacket.TYPE_SET);
set.setTo(conversation.getContactJid().toBareJid());
set.query("http://jabber.org/protocol/muc#owner").addChild(data);
sendIqPacket(account, set, new OnIqPacketReceived() {
@Override
public void onIqPacketReceived(Account account, IqPacket packet) {
if (packet.getType() == IqPacket.TYPE_RESULT) {
if (callback != null) {
callback.onPushSucceeded();
}
} else {
if (callback != null) {
callback.onPushFailed();
}
}
}
});
} else {
if (callback != null) {
callback.onPushFailed();
}
}
}
});
}
public void disconnect(Account account, boolean force) { public void disconnect(Account account, boolean force) {
if ((account.getStatus() == Account.State.ONLINE) if ((account.getStatus() == Account.State.ONLINE)
|| (account.getStatus() == Account.State.DISABLED)) { || (account.getStatus() == Account.State.DISABLED)) {
@ -1726,7 +1828,7 @@ public class XmppConnectionService extends Service {
}).start(); }).start();
} }
public void invite(Conversation conversation, String contact) { public void invite(Conversation conversation, Jid contact) {
MessagePacket packet = mMessageGenerator.invite(conversation, contact); MessagePacket packet = mMessageGenerator.invite(conversation, contact);
sendMessagePacket(conversation.getAccount(), packet); sendMessagePacket(conversation.getAccount(), packet);
} }
@ -2023,6 +2125,11 @@ public class XmppConnectionService extends Service {
public void onRosterUpdate(); public void onRosterUpdate();
} }
private interface OnConferenceOptionsPushed {
public void onPushSucceeded();
public void onPushFailed();
}
public class XmppConnectionBinder extends Binder { public class XmppConnectionBinder extends Binder {
public XmppConnectionService getService() { public XmppConnectionService getService() {
return XmppConnectionService.this; return XmppConnectionService.this;

View file

@ -34,7 +34,7 @@ import eu.siacs.conversations.entities.MucOptions.User;
import eu.siacs.conversations.services.XmppConnectionService.OnConversationUpdate; import eu.siacs.conversations.services.XmppConnectionService.OnConversationUpdate;
import eu.siacs.conversations.xmpp.stanzas.MessagePacket; import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
public class ConferenceDetailsActivity extends XmppActivity implements OnConversationUpdate, OnRenameListener { public class ConferenceDetailsActivity extends XmppActivity implements OnConversationUpdate {
public static final String ACTION_VIEW_MUC = "view_muc"; public static final String ACTION_VIEW_MUC = "view_muc";
private Conversation mConversation; private Conversation mConversation;
private OnClickListener inviteListener = new OnClickListener() { private OnClickListener inviteListener = new OnClickListener() {
@ -57,26 +57,34 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
private List<User> users = new ArrayList<>(); private List<User> users = new ArrayList<>();
private User mSelectedUser = null; private User mSelectedUser = null;
@Override private UiCallback<Conversation> renameCallback = new UiCallback<Conversation>() {
public void onRename(final boolean success) { @Override
runOnUiThread(new Runnable() { public void success(Conversation object) {
runOnUiThread(new Runnable() {
@Override @Override
public void run() { public void run() {
populateView(); Toast.makeText(ConferenceDetailsActivity.this,getString(R.string.your_nick_has_been_changed),Toast.LENGTH_SHORT).show();
if (success) { populateView();
Toast.makeText(
ConferenceDetailsActivity.this,
getString(R.string.your_nick_has_been_changed),
Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(ConferenceDetailsActivity.this,
getString(R.string.nick_in_use),
Toast.LENGTH_SHORT).show();
} }
} });
});
} }
@Override
public void error(final int errorCode, Conversation object) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(ConferenceDetailsActivity.this,getString(errorCode),Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void userInputRequried(PendingIntent pi, Conversation object) {
}
};
@Override @Override
public void onConversationUpdate() { public void onConversationUpdate() {
@ -114,8 +122,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
@Override @Override
public void onValueEdited(String value) { public void onValueEdited(String value) {
xmppConnectionService.renameInMuc(mConversation, xmppConnectionService.renameInMuc(mConversation,value,renameCallback);
value);
} }
}); });
} }

View file

@ -225,6 +225,18 @@ public class ConversationActivity extends XmppActivity implements
} }
} }
@Override
public void switchToConversation(Conversation conversation) {
setSelectedConversation(conversation);
runOnUiThread(new Runnable() {
@Override
public void run() {
ConversationActivity.this.mConversationFragment.reInit(getSelectedConversation());
openConversation();
}
});
}
public void openConversation() { public void openConversation() {
ActionBar ab = getActionBar(); ActionBar ab = getActionBar();
if (ab != null) { if (ab != null) {
@ -286,7 +298,7 @@ public class ConversationActivity extends XmppActivity implements
menuAttach.setVisible(false); menuAttach.setVisible(false);
} else { } else {
menuMucDetails.setVisible(false); menuMucDetails.setVisible(false);
menuInviteContact.setVisible(false); menuInviteContact.setTitle(R.string.conference_with);
} }
if (this.getSelectedConversation().isMuted()) { if (this.getSelectedConversation().isMuted()) {
menuMute.setVisible(false); menuMute.setVisible(false);

View file

@ -553,7 +553,7 @@ public class ConversationFragment extends Fragment {
showSnackbar(R.string.nick_in_use, R.string.edit, showSnackbar(R.string.nick_in_use, R.string.edit,
clickToMuc); clickToMuc);
break; break;
case MucOptions.ERROR_ROOM_NOT_FOUND: case MucOptions.ERROR_UNKNOWN:
showSnackbar(R.string.conference_not_found, showSnackbar(R.string.conference_not_found,
R.string.leave, leaveMuc); R.string.leave, leaveMuc);
break; break;

View file

@ -42,6 +42,7 @@ import android.view.View;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
import android.widget.EditText; import android.widget.EditText;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.Toast;
import com.google.zxing.BarcodeFormat; import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType; import com.google.zxing.EncodeHintType;
@ -54,6 +55,7 @@ import net.java.otr4j.session.SessionID;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.List; import java.util.List;
import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.RejectedExecutionException;
@ -240,9 +242,6 @@ public abstract class XmppActivity extends Activity {
if (this instanceof XmppConnectionService.OnRosterUpdate) { if (this instanceof XmppConnectionService.OnRosterUpdate) {
this.xmppConnectionService.setOnRosterUpdateListener((XmppConnectionService.OnRosterUpdate) this); this.xmppConnectionService.setOnRosterUpdateListener((XmppConnectionService.OnRosterUpdate) this);
} }
if (this instanceof MucOptions.OnRenameListener) {
this.xmppConnectionService.setOnRenameListener((MucOptions.OnRenameListener) this);
}
} }
protected void unregisterListeners() { protected void unregisterListeners() {
@ -255,9 +254,6 @@ public abstract class XmppActivity extends Activity {
if (this instanceof XmppConnectionService.OnRosterUpdate) { if (this instanceof XmppConnectionService.OnRosterUpdate) {
this.xmppConnectionService.removeOnRosterUpdateListener(); this.xmppConnectionService.removeOnRosterUpdateListener();
} }
if (this instanceof MucOptions.OnRenameListener) {
this.xmppConnectionService.setOnRenameListener(null);
}
} }
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
@ -603,18 +599,53 @@ public abstract class XmppActivity extends Activity {
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_INVITE_TO_CONVERSATION if (requestCode == REQUEST_INVITE_TO_CONVERSATION
&& resultCode == RESULT_OK) { && resultCode == RESULT_OK) {
String contactJid = data.getStringExtra("contact"); try {
String conversationUuid = data.getStringExtra("conversation"); Jid jid = Jid.fromString(data.getStringExtra("contact"));
Conversation conversation = xmppConnectionService String conversationUuid = data.getStringExtra("conversation");
.findConversationByUuid(conversationUuid); Conversation conversation = xmppConnectionService
if (conversation.getMode() == Conversation.MODE_MULTI) { .findConversationByUuid(conversationUuid);
xmppConnectionService.invite(conversation, contactJid); if (conversation.getMode() == Conversation.MODE_MULTI) {
xmppConnectionService.invite(conversation, jid);
} else {
List<Jid> jids = new ArrayList<Jid>();
jids.add(conversation.getContactJid().toBareJid());
jids.add(jid);
xmppConnectionService.createAdhocConference(conversation.getAccount(), jids, adhocCallback);
}
} catch (final InvalidJidException ignored) {
} }
Log.d(Config.LOGTAG, "inviting " + contactJid + " to "
+ conversation.getName());
} }
} }
private UiCallback<Conversation> adhocCallback = new UiCallback<Conversation>() {
@Override
public void success(final Conversation conversation) {
switchToConversation(conversation);
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(XmppActivity.this,R.string.conference_created,Toast.LENGTH_LONG).show();
}
});
}
@Override
public void error(final int errorCode, Conversation object) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(XmppActivity.this,errorCode,Toast.LENGTH_LONG).show();
}
});
}
@Override
public void userInputRequried(PendingIntent pi, Conversation object) {
}
};
public int getSecondaryTextColor() { public int getSecondaryTextColor() {
return this.mSecondaryTextColor; return this.mSecondaryTextColor;
} }

View file

@ -1049,7 +1049,14 @@ public class XmppConnection implements Runnable {
} }
public String getMucServer() { public String getMucServer() {
return findDiscoItemByFeature("http://jabber.org/protocol/muc"); final List<String> items = new ArrayList<>();
for (Entry<String, List<String>> cursor : disco.entrySet()) {
final List<String> value = cursor.getValue();
if (value.contains("http://jabber.org/protocol/muc") && !value.contains("jabber:iq:gateway")) {
return cursor.getKey();
}
}
return null;
} }
public int getTimeToNextAttempt() { public int getTimeToNextAttempt() {

View file

@ -0,0 +1,75 @@
package eu.siacs.conversations.xmpp.forms;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import eu.siacs.conversations.xml.Element;
public class Data extends Element {
public Data() {
super("x");
this.setAttribute("xmlns","jabber:x:data");
}
public List<Field> getFields() {
ArrayList<Field> fields = new ArrayList<Field>();
for(Element child : getChildren()) {
if (child.getName().equals("field")) {
fields.add(Field.parse(child));
}
}
return fields;
}
public Field getFieldByName(String needle) {
for(Element child : getChildren()) {
if (child.getName().equals("field") && needle.equals(child.getAttribute("var"))) {
return Field.parse(child);
}
}
return null;
}
public void put(String name, String value) {
Field field = getFieldByName(name);
if (field == null) {
field = new Field(name);
}
field.setValue(value);
}
public void put(String name, Collection<String> values) {
Field field = getFieldByName(name);
if (field == null) {
field = new Field(name);
}
field.setValues(values);
}
public void submit() {
this.setAttribute("type","submit");
removeNonFieldChildren();
for(Field field : getFields()) {
field.removeNonValueChildren();
}
}
private void removeNonFieldChildren() {
for(Iterator<Element> iterator = this.children.iterator(); iterator.hasNext();) {
Element element = iterator.next();
if (!element.getName().equals("field")) {
iterator.remove();
}
}
}
public static Data parse(Element element) {
Data data = new Data();
data.setAttributes(element.getAttributes());
data.setChildren(element.getChildren());
return data;
}
}

View file

@ -0,0 +1,50 @@
package eu.siacs.conversations.xmpp.forms;
import java.util.Collection;
import java.util.Iterator;
import eu.siacs.conversations.xml.Element;
public class Field extends Element {
public Field(String name) {
super("field");
this.setAttribute("var",name);
}
private Field() {
super("field");
}
public String getName() {
return this.getAttribute("var");
}
public void setValue(String value) {
this.children.clear();
this.addChild("value").setContent(value);
}
public void setValues(Collection<String> values) {
this.children.clear();
for(String value : values) {
this.addChild("value").setContent(value);
}
}
public void removeNonValueChildren() {
for(Iterator<Element> iterator = this.children.iterator(); iterator.hasNext();) {
Element element = iterator.next();
if (!element.getName().equals("value")) {
iterator.remove();
}
}
}
public static Field parse(Element element) {
Field field = new Field();
field.setAttributes(element.getAttributes());
field.setChildren(element.getChildren());
return field;
}
}

View file

@ -352,4 +352,8 @@
<string name="pref_show_dynamic_tags">Show dynamic tags</string> <string name="pref_show_dynamic_tags">Show dynamic tags</string>
<string name="pref_show_dynamic_tags_summary">Display read-only tags underneath contacts</string> <string name="pref_show_dynamic_tags_summary">Display read-only tags underneath contacts</string>
<string name="enable_notifications">Enable notifications</string> <string name="enable_notifications">Enable notifications</string>
<string name="conference_with">Create conference with…</string>
<string name="no_conference_server_found">No conference server found</string>
<string name="conference_creation_failed">Conference creation failed!</string>
<string name="conference_created">Conference created!</string>
</resources> </resources>