aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/main/java/eu/siacs/conversations/entities/MucOptions.java30
-rw-r--r--src/main/java/eu/siacs/conversations/parser/MessageParser.java82
-rw-r--r--src/main/java/eu/siacs/conversations/services/XmppConnectionService.java30
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java27
-rw-r--r--src/main/java/eu/siacs/conversations/ui/ConversationActivity.java11
-rw-r--r--src/main/res/values-de/strings.xml19
-rw-r--r--src/main/res/values/strings.xml3
7 files changed, 137 insertions, 65 deletions
diff --git a/src/main/java/eu/siacs/conversations/entities/MucOptions.java b/src/main/java/eu/siacs/conversations/entities/MucOptions.java
index 6a12f407..96860a16 100644
--- a/src/main/java/eu/siacs/conversations/entities/MucOptions.java
+++ b/src/main/java/eu/siacs/conversations/entities/MucOptions.java
@@ -4,6 +4,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
+import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.crypto.PgpEngine;
import eu.siacs.conversations.xml.Element;
@@ -12,6 +13,7 @@ import eu.siacs.conversations.xmpp.jid.Jid;
import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
import android.annotation.SuppressLint;
+import android.util.Log;
@SuppressLint("DefaultLocale")
public class MucOptions {
@@ -51,8 +53,6 @@ public class MucOptions {
}
}
- ;
-
public enum Role {
MODERATOR("moderator", R.string.moderator),
VISITOR("visitor", R.string.visitor),
@@ -86,6 +86,7 @@ public class MucOptions {
public static final int KICKED_FROM_ROOM = 9;
+ public static final String STATUS_CODE_ROOM_CONFIG_CHANGED = "104";
public static final String STATUS_CODE_SELF_PRESENCE = "110";
public static final String STATUS_CODE_BANNED = "301";
public static final String STATUS_CODE_CHANGED_NICK = "303";
@@ -107,8 +108,8 @@ public class MucOptions {
}
public class User {
- private Role role;
- private Affiliation affiliation;
+ private Role role = Role.NONE;
+ private Affiliation affiliation = Affiliation.NONE;
private String name;
private Jid jid;
private long pgpKeyId = 0;
@@ -190,6 +191,7 @@ public class MucOptions {
private Account account;
private List<User> users = new CopyOnWriteArrayList<>();
+ private List<String> features = new ArrayList<>();
private Conversation conversation;
private boolean isOnline = false;
private int error = ERROR_UNKNOWN;
@@ -205,6 +207,23 @@ public class MucOptions {
this.conversation = conversation;
}
+ public void updateFeatures(ArrayList<String> features) {
+ this.features.clear();
+ this.features.addAll(features);
+ }
+
+ public boolean hasFeature(String feature) {
+ return this.features.contains(feature);
+ }
+
+ public boolean canInvite() {
+ return !membersOnly() || self.getAffiliation().ranks(Affiliation.ADMIN);
+ }
+
+ public boolean membersOnly() {
+ return hasFeature("muc_membersonly");
+ }
+
public void deleteUser(String name) {
for (int i = 0; i < users.size(); ++i) {
if (users.get(i).getName().equals(name)) {
@@ -225,6 +244,7 @@ public class MucOptions {
}
public void processPacket(PresencePacket packet, PgpEngine pgp) {
+ Log.d(Config.LOGTAG, packet.toString());
final Jid from = packet.getFrom();
if (!from.isBareJid()) {
final String name = from.getResourcepart();
@@ -320,7 +340,7 @@ public class MucOptions {
}
private List<String> getStatusCodes(Element x) {
- List<String> codes = new ArrayList<String>();
+ List<String> codes = new ArrayList<>();
if (x != null) {
for (Element child : x.getChildren()) {
if (child.getName().equals("status")) {
diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java
index 65a8f9e6..bb9de061 100644
--- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java
+++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java
@@ -1,15 +1,13 @@
package eu.siacs.conversations.parser;
-import android.util.Log;
-
import net.java.otr4j.session.Session;
import net.java.otr4j.session.SessionStatus;
-import eu.siacs.conversations.Config;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
import eu.siacs.conversations.entities.Message;
+import eu.siacs.conversations.entities.MucOptions;
import eu.siacs.conversations.services.MessageArchiveService;
import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.utils.CryptoHelper;
@@ -142,14 +140,25 @@ public class MessageParser extends AbstractParser implements
Conversation conversation = mXmppConnectionService
.findOrCreateConversation(account, from.toBareJid(), true);
if (packet.hasChild("subject")) {
- conversation.getMucOptions().setSubject(
- packet.findChild("subject").getContent());
+ conversation.getMucOptions().setSubject(packet.findChild("subject").getContent());
mXmppConnectionService.updateConversationUi();
return null;
}
- if (from.isBareJid()) {
+
+ final Element x = packet.findChild("x", "http://jabber.org/protocol/muc#user");
+ if (from.isBareJid() && (x == null || !x.hasChild("status"))) {
return null;
+ } else if (from.isBareJid() && x.hasChild("status")) {
+ for(Element child : x.getChildren()) {
+ if (child.getName().equals("status")) {
+ String code = child.getAttribute("code");
+ if (code.contains(MucOptions.STATUS_CODE_ROOM_CONFIG_CHANGED)) {
+ mXmppConnectionService.fetchConferenceConfiguration(conversation);
+ }
+ }
+ }
}
+
if (from.getResourcepart().equals(conversation.getMucOptions().getActualNick())) {
if (mXmppConnectionService.markMessage(conversation,
packet.getId(), Message.STATUS_SEND)) {
@@ -348,6 +357,17 @@ public class MessageParser extends AbstractParser implements
private void parseNonMessage(Element packet, Account account) {
final Jid from = packet.getAttributeAsJid("from");
+ Element invite = extractInvite(packet);
+ if (invite != null) {
+ Conversation conversation = mXmppConnectionService.findOrCreateConversation(account, from, true);
+ if (!conversation.getMucOptions().online()) {
+ Element password = invite.findChild("password");
+ conversation.getMucOptions().setPassword(password == null ? null : password.getContent());
+ mXmppConnectionService.databaseBackend.updateConversation(conversation);
+ mXmppConnectionService.joinMuc(conversation);
+ mXmppConnectionService.updateConversationUi();
+ }
+ }
if (packet.hasChild("event", "http://jabber.org/protocol/pubsub#event")) {
Element event = packet.findChild("event",
"http://jabber.org/protocol/pubsub#event");
@@ -374,42 +394,18 @@ public class MessageParser extends AbstractParser implements
updateLastseen(packet, account, false);
mXmppConnectionService.markMessage(account, from.toBareJid(),
id, Message.STATUS_SEND_RECEIVED);
- } else if (packet.hasChild("x", "http://jabber.org/protocol/muc#user")) {
- Element x = packet.findChild("x",
- "http://jabber.org/protocol/muc#user");
- if (x.hasChild("invite")) {
- Conversation conversation = mXmppConnectionService
- .findOrCreateConversation(account,
- packet.getAttributeAsJid("from"), true);
- if (!conversation.getMucOptions().online()) {
- if (x.hasChild("password")) {
- Element password = x.findChild("password");
- conversation.getMucOptions().setPassword(
- password.getContent());
- mXmppConnectionService.databaseBackend
- .updateConversation(conversation);
- }
- mXmppConnectionService.joinMuc(conversation);
- mXmppConnectionService.updateConversationUi();
- }
- }
- } else if (packet.hasChild("x", "jabber:x:conference")) {
- Element x = packet.findChild("x", "jabber:x:conference");
- Jid jid = x.getAttributeAsJid("jid");
- String password = x.getAttribute("password");
- if (jid != null) {
- Conversation conversation = mXmppConnectionService
- .findOrCreateConversation(account, jid, true);
- if (!conversation.getMucOptions().online()) {
- if (password != null) {
- conversation.getMucOptions().setPassword(password);
- mXmppConnectionService.databaseBackend
- .updateConversation(conversation);
- }
- mXmppConnectionService.joinMuc(conversation);
- mXmppConnectionService.updateConversationUi();
- }
- }
+ }
+ }
+
+ private Element extractInvite(Element message) {
+ Element x = message.findChild("x","http://jabber.org/protocol/muc#user");
+ if (x == null) {
+ x = message.findChild("x","jabber:x:conference");
+ }
+ if (x != null && x.hasChild("invite")) {
+ return x;
+ } else {
+ return null;
}
}
@@ -493,7 +489,7 @@ public class MessageParser extends AbstractParser implements
if (message != null) {
message.markUnread();
}
- } else if (packet.hasChild("body")) {
+ } else if (packet.hasChild("body") && extractInvite(packet) == null) {
message = this.parseChat(packet, account);
if (message != null) {
message.markUnread();
diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
index 4ab2d42b..5c16ef3f 100644
--- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
+++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java
@@ -1316,6 +1316,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
packet.addChild("x", "jabber:x:signed").setContent(sig);
}
sendPresencePacket(account, packet);
+ fetchConferenceConfiguration(conversation);
if (!joinJid.equals(conversation.getJid())) {
conversation.setContactJid(joinJid);
databaseBackend.updateConversation(conversation);
@@ -1475,6 +1476,29 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
}
}
+ public void fetchConferenceConfiguration(final Conversation conversation) {
+ IqPacket request = new IqPacket(IqPacket.TYPE.GET);
+ request.setTo(conversation.getJid().toBareJid());
+ request.query("http://jabber.org/protocol/disco#info");
+ sendIqPacket(conversation.getAccount(), request, new OnIqPacketReceived() {
+ @Override
+ public void onIqPacketReceived(Account account, IqPacket packet) {
+ if (packet.getType() != IqPacket.TYPE.ERROR) {
+ ArrayList<String> features = new ArrayList<String>();
+ for (Element child : packet.query().getChildren()) {
+ if (child != null && child.getName().equals("feature")) {
+ String var = child.getAttribute("var");
+ if (var != null) {
+ features.add(var);
+ }
+ }
+ }
+ conversation.getMucOptions().updateFeatures(features);
+ }
+ }
+ });
+ }
+
public void pushConferenceConfiguration(final Conversation conversation,final Bundle options, final OnConferenceOptionsPushed callback) {
IqPacket request = new IqPacket(IqPacket.TYPE.GET);
request.setTo(conversation.getJid().toBareJid());
@@ -1520,14 +1544,14 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
final Jid jid = user.toBareJid();
IqPacket request = this.mIqGenerator.changeAffiliation(conference, jid, affiliation.toString());
Log.d(Config.LOGTAG,request.toString());
- sendIqPacket(conference.getAccount(),request,new OnIqPacketReceived() {
+ sendIqPacket(conference.getAccount(), request, new OnIqPacketReceived() {
@Override
public void onIqPacketReceived(Account account, IqPacket packet) {
- Log.d(Config.LOGTAG,packet.toString());
+ Log.d(Config.LOGTAG, packet.toString());
if (packet.getType() == IqPacket.TYPE.RESULT) {
callback.onAffiliationChangedSuccessful(jid);
} else {
- callback.onAffiliationChangeFailed(jid,R.string.could_not_change_affiliation);
+ callback.onAffiliationChangeFailed(jid, R.string.could_not_change_affiliation);
}
}
});
diff --git a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java
index 41190ef2..5272c922 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConferenceDetailsActivity.java
@@ -1,8 +1,10 @@
package eu.siacs.conversations.ui;
import android.annotation.TargetApi;
+import android.app.AlertDialog;
import android.app.PendingIntent;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.IntentSender.SendIntentException;
import android.graphics.Bitmap;
import android.os.Build;
@@ -285,13 +287,31 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
xmppConnectionService.changeAffiliationInConference(mConversation,mSelectedUser.getJid(), MucOptions.Affiliation.MEMBER,this);
return true;
case R.id.remove_from_room:
- xmppConnectionService.changeAffiliationInConference(mConversation,mSelectedUser.getJid(), MucOptions.Affiliation.OUTCAST,this);
+ removeFromRoom(mSelectedUser);
return true;
default:
return super.onContextItemSelected(item);
}
}
+ private void removeFromRoom(final User user) {
+ if (mConversation.getMucOptions().membersOnly()) {
+ xmppConnectionService.changeAffiliationInConference(mConversation,user.getJid(), MucOptions.Affiliation.NONE,this);
+ } else {
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle(R.string.ban_user_from_conference);
+ builder.setMessage(getString(R.string.removing_from_public_conference,user.getName()));
+ builder.setNegativeButton(R.string.cancel,null);
+ builder.setPositiveButton(R.string.ban_now,new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ xmppConnectionService.changeAffiliationInConference(mConversation,user.getJid(), MucOptions.Affiliation.OUTCAST,ConferenceDetailsActivity.this);
+ }
+ });
+ builder.create().show();
+ }
+ }
+
protected void startConversation(User user) {
if (user.getJid() != null) {
Conversation conversation = xmppConnectionService.findOrCreateConversation(this.mConversation.getAccount(),user.getJid().toBareJid(),false);
@@ -397,6 +417,11 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
ImageView iv = (ImageView) view.findViewById(R.id.contact_photo);
iv.setImageBitmap(bm);
membersView.addView(view);
+ if (mConversation.getMucOptions().canInvite()) {
+ mInviteButton.setVisibility(View.VISIBLE);
+ } else {
+ mInviteButton.setVisibility(View.GONE);
+ }
}
}
diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java
index 795dabf2..ba5b3e59 100644
--- a/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java
+++ b/src/main/java/eu/siacs/conversations/ui/ConversationActivity.java
@@ -9,7 +9,6 @@ import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.IntentSender.SendIntentException;
-import android.media.MediaActionSound;
import android.net.Uri;
import android.os.Bundle;
import android.os.SystemClock;
@@ -83,11 +82,6 @@ public class ConversationActivity extends XmppActivity
private boolean mActivityPaused = false;
-
- public List<Conversation> getConversationList() {
- return this.conversationList;
- }
-
public Conversation getSelectedConversation() {
return this.mSelectedConversation;
}
@@ -284,8 +278,7 @@ public class ConversationActivity extends XmppActivity
final MenuItem menuBlock = menu.findItem(R.id.action_block);
final MenuItem menuUnblock = menu.findItem(R.id.action_unblock);
- if (isConversationsOverviewVisable()
- && isConversationsOverviewHideable()) {
+ if (isConversationsOverviewVisable() && isConversationsOverviewHideable()) {
menuArchive.setVisible(false);
menuMucDetails.setVisible(false);
menuContactDetails.setVisible(false);
@@ -309,9 +302,9 @@ public class ConversationActivity extends XmppActivity
menuAttach.setVisible(false);
menuBlock.setVisible(false);
menuUnblock.setVisible(false);
+ menuInviteContact.setVisible(getSelectedConversation().getMucOptions().canInvite());
} else {
menuMucDetails.setVisible(false);
- menuInviteContact.setTitle(R.string.conference_with);
if (this.getSelectedConversation().isBlocked()) {
menuBlock.setVisible(false);
} else {
diff --git a/src/main/res/values-de/strings.xml b/src/main/res/values-de/strings.xml
index aa87f758..c482f268 100644
--- a/src/main/res/values-de/strings.xml
+++ b/src/main/res/values-de/strings.xml
@@ -374,10 +374,21 @@
<string name="shared_secret_can_not_be_empty">Dein gemeinsamer Schlüssel darf nicht leer sein</string>
<string name="manual_verification_explanation">Vergleiche den angezeigten Fingerabdruck sorgfältig mit dem deines Kontakts.\nDu kannst dazu einen sicheren Kommunikationsweg (z.B. verschlüsselte E-Mail oder Telefonanruf) zum Austausch nutzen.</string>
<string name="change_password">Passwort ändern</string>
- <string name="current_password">Aktuelles Passwort</string>
- <string name="new_password">Neues Passwort</string>
- <string name="password_should_not_be_empty">Das Passwort darf nicht leer sein</string>
+ <string name="current_password">Aktuelles Passwort</string>
+ <string name="new_password">Neues Passwort</string>
+ <string name="password_should_not_be_empty">Das Passwort darf nicht leer sein</string>
<string name="enable_all_accounts">Alle Konten anschalten</string>
- <string name="disable_all_accounts">Alle Konten abschalten</string>
+ <string name="disable_all_accounts">Alle Konten abschalten</string>
<string name="perform_action_with">Aktion durchführen mit</string>
+ <string name="no_affiliation">Keine Zugehörigkeit</string>
+ <string name="no_role">Keine Rolle</string>
+ <string name="outcast">Ausgeschlossen</string>
+ <string name="member">Mitglied</string>
+ <string name="advanced_mode">Experten Modus</string>
+ <string name="grant_membership">Mitgliedschaft gewähren</string>
+ <string name="remove_membership">Mitgliedschaft entziehen</string>
+ <string name="grant_admin_privileges">Administratorrechte gewähren</string>
+ <string name="remove_admin_privileges">Administratorrechte entziehen</string>
+ <string name="remove_from_room">Aus Konferenz entfernen</string>
+ <string name="could_not_change_affiliation">Zugehörigkeit kann nicht geändert werden</string>
</resources>
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index d78e135a..c8e84d75 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -417,4 +417,7 @@
<string name="remove_admin_privileges">Remove admin privileges</string>
<string name="remove_from_room">Remove from room</string>
<string name="could_not_change_affiliation">Could not change affiliation</string>
+ <string name="ban_user_from_conference">Ban user from conference</string>
+ <string name="removing_from_public_conference">You are trying to remove %s from a public conference. The only way to do that is to ban that user for ever.</string>
+ <string name="ban_now">Ban now</string>
</resources>