diff options
author | Daniel Gultsch <daniel@gultsch.de> | 2014-03-03 05:01:02 +0100 |
---|---|---|
committer | Daniel Gultsch <daniel@gultsch.de> | 2014-03-03 05:01:02 +0100 |
commit | c609eefefac5097c7c40a9f1b8741e9634da316f (patch) | |
tree | 53363dfbab46d84e81b8b95f49e586374dc358f0 | |
parent | 2ab6cb0ada6370e6ea83a73e0a6a39ea3ff90715 (diff) |
api changes. muc options
20 files changed, 647 insertions, 127 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml index d511bef57..90e177c10 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -45,6 +45,11 @@ android:label="Manage Accounts" android:parentActivityName="eu.siacs.conversations.ui.ConversationActivity" > </activity> + <activity + android:name="eu.siacs.conversations.ui.MucOptionsActivity" + android:label="Conference Details" + android:parentActivityName="eu.siacs.conversations.ui.ConversationActivity" > + </activity> <activity android:name="eu.siacs.conversations.ui.NewConversationActivity" android:label="@string/title_activity_new_conversation" diff --git a/gen/eu/siacs/conversations/R.java b/gen/eu/siacs/conversations/R.java index afe690627..8c71eebe7 100644 --- a/gen/eu/siacs/conversations/R.java +++ b/gen/eu/siacs/conversations/R.java @@ -34,43 +34,44 @@ public final class R { public static final int ic_action_add=0x7f020005; public static final int ic_action_add_person=0x7f020006; public static final int ic_action_cancel_launchersize=0x7f020007; - public static final int ic_action_delete=0x7f020008; - public static final int ic_action_group=0x7f020009; - public static final int ic_action_person=0x7f02000a; - public static final int ic_action_refresh=0x7f02000b; - public static final int ic_action_secure=0x7f02000c; - public static final int ic_action_send=0x7f02000d; - public static final int ic_action_send_now=0x7f02000e; - public static final int ic_action_unsecure=0x7f02000f; - public static final int ic_launcher=0x7f020010; - public static final int ic_profile=0x7f020011; - public static final int message_border=0x7f020012; - public static final int notification=0x7f020013; - public static final int red=0x7f020014; - public static final int redbackground=0x7f020015; - public static final int section_header=0x7f020016; + public static final int ic_action_cancel_launchersize_light=0x7f020008; + public static final int ic_action_delete=0x7f020009; + public static final int ic_action_group=0x7f02000a; + public static final int ic_action_person=0x7f02000b; + public static final int ic_action_refresh=0x7f02000c; + public static final int ic_action_secure=0x7f02000d; + public static final int ic_action_send=0x7f02000e; + public static final int ic_action_send_now=0x7f02000f; + public static final int ic_action_unsecure=0x7f020010; + public static final int ic_launcher=0x7f020011; + public static final int ic_profile=0x7f020012; + public static final int message_border=0x7f020013; + public static final int notification=0x7f020014; + public static final int red=0x7f020015; + public static final int redbackground=0x7f020016; + public static final int section_header=0x7f020017; } public static final class id { public static final int account_confirm_password_desc=0x7f0a001c; - public static final int account_delete=0x7f0a0038; - public static final int account_disable=0x7f0a0039; - public static final int account_enable=0x7f0a003a; + public static final int account_delete=0x7f0a0041; + public static final int account_disable=0x7f0a0042; + public static final int account_enable=0x7f0a0043; public static final int account_jid=0x7f0a0000; - public static final int account_list=0x7f0a0029; + public static final int account_list=0x7f0a002b; public static final int account_password=0x7f0a0019; public static final int account_password_confirm2=0x7f0a001d; public static final int account_status=0x7f0a0002; public static final int account_usetls=0x7f0a001a; - public static final int action_accounts=0x7f0a0032; - public static final int action_add=0x7f0a002d; - public static final int action_add_account=0x7f0a0037; - public static final int action_archive=0x7f0a0031; - public static final int action_contact_details=0x7f0a002f; - public static final int action_muc_details=0x7f0a0030; - public static final int action_refresh_contacts=0x7f0a003c; - public static final int action_security=0x7f0a002e; - public static final int action_settings=0x7f0a0033; - public static final int announce_pgp=0x7f0a003b; + public static final int action_accounts=0x7f0a003b; + public static final int action_add=0x7f0a0036; + public static final int action_add_account=0x7f0a0040; + public static final int action_archive=0x7f0a003a; + public static final int action_contact_details=0x7f0a0038; + public static final int action_muc_details=0x7f0a0039; + public static final int action_refresh_contacts=0x7f0a0045; + public static final int action_security=0x7f0a0037; + public static final int action_settings=0x7f0a003c; + public static final int announce_pgp=0x7f0a0044; public static final int contactList=0x7f0a0006; public static final int contact_display_name=0x7f0a0008; public static final int contact_jid=0x7f0a0009; @@ -88,22 +89,31 @@ public final class R { public static final int details_receive_presence=0x7f0a0014; public static final int details_send_presence=0x7f0a0013; public static final int edit_account_register_new=0x7f0a001b; - public static final int encryption_choice_none=0x7f0a0034; - public static final int encryption_choice_otr=0x7f0a0035; - public static final int encryption_choice_pgp=0x7f0a0036; + public static final int encryption_choice_none=0x7f0a003d; + public static final int encryption_choice_otr=0x7f0a003e; + public static final int encryption_choice_pgp=0x7f0a003f; public static final int info_box=0x7f0a0022; - public static final int list=0x7f0a0027; - public static final int message_body=0x7f0a002b; - public static final int message_photo=0x7f0a002a; - public static final int message_time=0x7f0a002c; + public static final int list=0x7f0a0029; + public static final int message_body=0x7f0a002d; + public static final int message_photo=0x7f0a002c; + public static final int message_time=0x7f0a002e; public static final int messages_view=0x7f0a0021; + public static final int muc_error=0x7f0a0023; + public static final int muc_error_msg=0x7f0a0024; + public static final int muc_moderators=0x7f0a0031; + public static final int muc_moderators_header=0x7f0a0030; + public static final int muc_participants=0x7f0a0033; + public static final int muc_participants_header=0x7f0a0032; + public static final int muc_visitors=0x7f0a0035; + public static final int muc_visitors_header=0x7f0a0034; + public static final int muc_your_nick=0x7f0a002f; public static final int new_conversation_search=0x7f0a0004; - public static final int new_fingerprint=0x7f0a0023; - public static final int otr_fingerprint=0x7f0a0024; - public static final int pgp_keyentry=0x7f0a0025; + public static final int new_fingerprint=0x7f0a0025; + public static final int otr_fingerprint=0x7f0a0026; + public static final int pgp_keyentry=0x7f0a0027; public static final int progressBar1=0x7f0a0003; - public static final int selected_conversation=0x7f0a0028; - public static final int slidingpanelayout=0x7f0a0026; + public static final int selected_conversation=0x7f0a002a; + public static final int slidingpanelayout=0x7f0a0028; public static final int textSendButton=0x7f0a0020; public static final int textView1=0x7f0a0018; public static final int textView2=0x7f0a0001; @@ -127,6 +137,7 @@ public final class R { public static final int message_error=0x7f03000a; public static final int message_recieved=0x7f03000b; public static final int message_sent=0x7f03000c; + public static final int muc_options=0x7f03000d; } public static final class menu { public static final int conversations=0x7f090000; @@ -146,8 +157,10 @@ public final class R { public static final int action_settings=0x7f050003; public static final int announce_pgp=0x7f05000e; public static final int app_name=0x7f050002; + public static final int conference_details=0x7f050010; public static final int encrypted_message=0x7f05000f; public static final int just_now=0x7f05000c; + public static final int nick_in_use=0x7f050011; public static final int openpgp_install_openkeychain_via=0x7f050001; public static final int openpgp_list_preference_none=0x7f050000; public static final int sending=0x7f05000d; diff --git a/gen/org/sufficientlysecure/keychain/api/R.java b/gen/org/sufficientlysecure/keychain/api/R.java index a49700a61..2cc4ddf77 100644 --- a/gen/org/sufficientlysecure/keychain/api/R.java +++ b/gen/org/sufficientlysecure/keychain/api/R.java @@ -9,6 +9,7 @@ package org.sufficientlysecure.keychain.api; public final class R { public static final class drawable { public static final int ic_action_cancel_launchersize = 0x7f020007; + public static final int ic_action_cancel_launchersize_light = 0x7f020008; } public static final class string { public static final int openpgp_install_openkeychain_via = 0x7f050001; diff --git a/res/layout/fragment_conversation.xml b/res/layout/fragment_conversation.xml index cea2be1f6..dabce4571 100644 --- a/res/layout/fragment_conversation.xml +++ b/res/layout/fragment_conversation.xml @@ -62,6 +62,36 @@ android:layout_width="fill_parent" android:orientation="vertical" > + + <LinearLayout + android:id="@+id/muc_error" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:background="@drawable/redbackground" + android:orientation="vertical" + android:visibility="gone" + > + + <TextView + android:id="@+id/muc_error_msg" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:textColor="#eee" + android:textStyle="bold" + android:padding="8dp" + android:textSize="20sp"/> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Click to edit conference details" + android:textColor="#eee" + android:paddingLeft="8dp" + android:paddingBottom="8dp" + android:textSize="14sp"/> + + </LinearLayout> + + <LinearLayout android:id="@+id/new_fingerprint" android:layout_width="fill_parent" diff --git a/res/layout/muc_options.xml b/res/layout/muc_options.xml new file mode 100644 index 000000000..3874de14c --- /dev/null +++ b/res/layout/muc_options.xml @@ -0,0 +1,76 @@ +<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical" + android:padding="8dp"> + <TextView + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Your nickname" + android:textColor="#33B5E5" + android:textSize="20sp" /> + + <EditText + android:id="@+id/muc_your_nick" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:ems="10" + android:inputType="textEmailAddress" + android:padding="8dp" + /> + + <TextView + android:paddingTop="16dp" + android:id="@+id/muc_moderators_header" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Moderators" + android:textColor="#33B5E5" + android:textSize="20sp" /> + <TextView + android:id="@+id/muc_moderators" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Romeo" + android:singleLine="true" + android:textSize="16sp" + android:paddingLeft="8dp" + android:paddingBottom="8dp"/> + + <TextView + android:id="@+id/muc_participants_header" + android:paddingTop="8dp" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Participants" + android:textColor="#33B5E5" + android:textSize="20sp" /> + <TextView + android:id="@+id/muc_participants" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Juilett" + android:singleLine="true" + android:textSize="16sp" + android:paddingLeft="8dp" + android:paddingBottom="8dp"/> + <TextView + android:id="@+id/muc_visitors_header" + android:paddingTop="8dp" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Visitors" + android:textColor="#33B5E5" + android:textSize="20sp" /> + <TextView + android:id="@+id/muc_visitors" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Benvolio" + android:singleLine="true" + android:textSize="16sp" + android:paddingLeft="8dp" + android:paddingBottom="8dp"/> + + +</LinearLayout> diff --git a/res/values/strings.xml b/res/values/strings.xml index dd372df66..557b2353b 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -15,4 +15,6 @@ <string name="sending">sending…</string> <string name="announce_pgp">Renew PGP announcement</string> <string name="encrypted_message">Decrypting message. please wait…</string> + <string name="conference_details">Conference Details</string> + <string name="nick_in_use">Nickname is already in use</string> </resources> diff --git a/src/eu/siacs/conversations/crypto/PgpEngine.java b/src/eu/siacs/conversations/crypto/PgpEngine.java index ba000c045..783844410 100644 --- a/src/eu/siacs/conversations/crypto/PgpEngine.java +++ b/src/eu/siacs/conversations/crypto/PgpEngine.java @@ -7,11 +7,9 @@ import java.io.InputStream; import org.openintents.openpgp.OpenPgpError; import org.openintents.openpgp.OpenPgpSignatureResult; import org.openintents.openpgp.util.OpenPgpApi; -import org.openintents.openpgp.util.OpenPgpConstants; import android.app.PendingIntent; -import android.os.Bundle; -import android.util.Log; +import android.content.Intent; public class PgpEngine { private OpenPgpApi api; @@ -22,34 +20,34 @@ public class PgpEngine { public String decrypt(String message) throws UserInputRequiredException, OpenPgpException { + Intent params = new Intent(); + params.setAction(OpenPgpApi.ACTION_DECRYPT_VERIFY); InputStream is = new ByteArrayInputStream(message.getBytes()); ByteArrayOutputStream os = new ByteArrayOutputStream(); - Bundle result = api.decryptAndVerify(is, os); - switch (result.getInt(OpenPgpConstants.RESULT_CODE)) { - case OpenPgpConstants.RESULT_CODE_SUCCESS: + Intent result = api.executeApi(params, is, os); + switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, 0)) { + case OpenPgpApi.RESULT_CODE_SUCCESS: return os.toString(); - case OpenPgpConstants.RESULT_CODE_USER_INTERACTION_REQUIRED: - throw new UserInputRequiredException( - (PendingIntent) result - .getParcelable(OpenPgpConstants.RESULT_INTENT)); - case OpenPgpConstants.RESULT_CODE_ERROR: + case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED: + throw new UserInputRequiredException((PendingIntent) result.getParcelableExtra(OpenPgpApi.RESULT_INTENT)); + case OpenPgpApi.RESULT_CODE_ERROR: throw new OpenPgpException( - (OpenPgpError) result - .getParcelable(OpenPgpConstants.RESULT_ERRORS)); + (OpenPgpError) result.getParcelableExtra(OpenPgpApi.RESULT_ERRORS)); default: return null; } } public String encrypt(long keyId, String message) { - Bundle params = new Bundle(); - params.putBoolean(OpenPgpConstants.PARAMS_REQUEST_ASCII_ARMOR, true); - long[] keyIds = { keyId }; - params.putLongArray(OpenPgpConstants.PARAMS_KEY_IDS, keyIds); - + Long[] keys = {keyId}; + Intent params = new Intent(); + params.setAction(OpenPgpApi.ACTION_ENCRYPT); + params.putExtra(OpenPgpApi.EXTRA_KEY_IDS,keys); + params.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true); + InputStream is = new ByteArrayInputStream(message.getBytes()); ByteArrayOutputStream os = new ByteArrayOutputStream(); - Bundle result = api.encrypt(params, is, os); + Intent result = api.executeApi(params, is, os); StringBuilder encryptedMessageBody = new StringBuilder(); String[] lines = os.toString().split("\n"); for (int i = 3; i < lines.length - 1; ++i) { @@ -74,47 +72,45 @@ public class PgpEngine { pgpSig.append(signature.replace("\n", "").trim()); pgpSig.append('\n'); pgpSig.append("-----END PGP SIGNATURE-----"); - Bundle params = new Bundle(); - params.putBoolean(OpenPgpConstants.PARAMS_REQUEST_ASCII_ARMOR, true); + Intent params = new Intent(); + params.setAction(OpenPgpApi.ACTION_DECRYPT_VERIFY); + params.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true); InputStream is = new ByteArrayInputStream(pgpSig.toString().getBytes()); ByteArrayOutputStream os = new ByteArrayOutputStream(); - Bundle result = api.decryptAndVerify(params, is, os); - switch (result.getInt(OpenPgpConstants.RESULT_CODE)) { - case OpenPgpConstants.RESULT_CODE_SUCCESS: - OpenPgpSignatureResult sigResult = result - .getParcelable(OpenPgpConstants.RESULT_SIGNATURE); + Intent result = api.executeApi(params, is, os); + switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, 0)) { + case OpenPgpApi.RESULT_CODE_SUCCESS: + OpenPgpSignatureResult sigResult + = result.getParcelableExtra(OpenPgpApi.RESULT_SIGNATURE); return sigResult.getKeyId(); - case OpenPgpConstants.RESULT_CODE_USER_INTERACTION_REQUIRED: + case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED: break; - case OpenPgpConstants.RESULT_CODE_ERROR: + case OpenPgpApi.RESULT_CODE_ERROR: throw new OpenPgpException( - (OpenPgpError) result - .getParcelable(OpenPgpConstants.RESULT_ERRORS)); + (OpenPgpError) result.getParcelableExtra(OpenPgpApi.RESULT_ERRORS)); } return 0; } public String generateSignature(String status) throws UserInputRequiredException { - Bundle params = new Bundle(); - params.putBoolean(OpenPgpConstants.PARAMS_REQUEST_ASCII_ARMOR, true); + Intent params = new Intent(); + params.putExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true); + params.setAction(OpenPgpApi.ACTION_SIGN); InputStream is = new ByteArrayInputStream(status.getBytes()); ByteArrayOutputStream os = new ByteArrayOutputStream(); - Bundle result = api.sign(params, is, os); + Intent result = api.executeApi(params, is, os); StringBuilder signatureBuilder = new StringBuilder(); - switch (result.getInt(OpenPgpConstants.RESULT_CODE)) { - case OpenPgpConstants.RESULT_CODE_SUCCESS: + switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, 0)) { + case OpenPgpApi.RESULT_CODE_SUCCESS: String[] lines = os.toString().split("\n"); for (int i = 7; i < lines.length - 1; ++i) { signatureBuilder.append(lines[i].trim()); } break; - case OpenPgpConstants.RESULT_CODE_USER_INTERACTION_REQUIRED: - UserInputRequiredException exception = new UserInputRequiredException( - (PendingIntent) result - .getParcelable(OpenPgpConstants.RESULT_INTENT)); - throw exception; - case OpenPgpConstants.RESULT_CODE_ERROR: + case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED: + throw new UserInputRequiredException((PendingIntent) result.getParcelableExtra(OpenPgpApi.RESULT_INTENT)); + case OpenPgpApi.RESULT_CODE_ERROR: break; } return signatureBuilder.toString(); diff --git a/src/eu/siacs/conversations/entities/Conversation.java b/src/eu/siacs/conversations/entities/Conversation.java index d1186a7d2..1a4745f9a 100644 --- a/src/eu/siacs/conversations/entities/Conversation.java +++ b/src/eu/siacs/conversations/entities/Conversation.java @@ -275,10 +275,15 @@ public class Conversation extends AbstractEntity { if (this.mucOptions == null) { this.mucOptions = new MucOptions(); } + this.mucOptions.setConversation(this); return this.mucOptions ; } public void resetMucOptions() { this.mucOptions = null; } + + public void setContactJid(String jid) { + this.contactJid = jid; + } } diff --git a/src/eu/siacs/conversations/entities/MucOptions.java b/src/eu/siacs/conversations/entities/MucOptions.java index d5340ea83..b3b53e1da 100644 --- a/src/eu/siacs/conversations/entities/MucOptions.java +++ b/src/eu/siacs/conversations/entities/MucOptions.java @@ -1,9 +1,21 @@ package eu.siacs.conversations.entities; +import java.util.ArrayList; +import java.util.List; + +import eu.siacs.conversations.xml.Element; +import eu.siacs.conversations.xmpp.PresencePacket; import android.annotation.SuppressLint; +import android.util.Log; @SuppressLint("DefaultLocale") public class MucOptions { + public static final int ERROR_NICK_IN_USE = 1; + + public interface OnRenameListener { + public void onRename(boolean success); + } + public class User { public static final int ROLE_MODERATOR = 3; public static final int ROLE_NONE = 0; @@ -17,6 +29,15 @@ public class MucOptions { private int role; private int affiliation; + private String name; + + public String getName() { + return name; + } + public void setName(String user) { + this.name = user; + } + public int getRole() { return this.role; } @@ -35,8 +56,127 @@ public class MucOptions { public int getAffiliation() { return this.affiliation; } - public void setAffiliation() { - + public void setAffiliation(String affiliation) { + if (affiliation.equalsIgnoreCase("admin")) { + this.affiliation = AFFILIATION_ADMIN; + } else if (affiliation.equalsIgnoreCase("owner")) { + this.affiliation = AFFILIATION_OWNER; + } else if (affiliation.equalsIgnoreCase("member")) { + this.affiliation = AFFILIATION_MEMBER; + } else if (affiliation.equalsIgnoreCase("outcast")) { + this.affiliation = AFFILIATION_OUTCAST; + } else { + this.affiliation = AFFILIATION_NONE; + } + } + } + private ArrayList<User> users = new ArrayList<User>(); + private Conversation conversation; + private boolean isOnline = false; + private int error = 0; + private OnRenameListener renameListener = null; + + + public void deleteUser(String name) { + for(int i = 0; i < users.size(); ++i) { + if (users.get(i).getName().equals(name)) { + users.remove(i); + return; + } + } + } + + public void addUser(User user) { + for(int i = 0; i < users.size(); ++i) { + if (users.get(i).getName().equals(user.getName())) { + users.set(i, user); + return; + } } + users.add(user); + } + + public void processPacket(PresencePacket packet) { + Log.d("xmppService","process Packet for muc options: "+packet.toString()); + String name = packet.getAttribute("from").split("/")[1]; + String type = packet.getAttribute("type"); + if (type==null) { + User user = new User(); + Element item = packet.findChild("x").findChild("item"); + user.setName(name); + user.setAffiliation(item.getAttribute("affiliation")); + user.setRole(item.getAttribute("role")); + user.setName(name); + addUser(user); + Log.d("xmppService","nick: "+getNick()); + Log.d("xmppService","name: "+name); + if (name.equals(getNick())) { + this.isOnline = true; + this.error = 0; + } + } else if (type.equals("unavailable")) { + Log.d("xmppService","name: "+name); + if (name.equals(getNick())) { + Element item = packet.findChild("x").findChild("item"); + Log.d("xmppService","nick equals name"); + String nick = item.getAttribute("nick"); + if (nick!=null) { + if (renameListener!=null) { + renameListener.onRename(true); + } + this.setNick(nick); + } + } + deleteUser(packet.getAttribute("from").split("/")[1]); + } else if (type.equals("error")) { + Element error = packet.findChild("error"); + if (error.hasChild("conflict")) { + this.error = ERROR_NICK_IN_USE; + } + } + } + + public List<User> getUsers() { + return this.users; + } + + public String getNick() { + String[] split = conversation.getContactJid().split("/"); + if (split.length == 2) { + return split[1]; + } else { + return conversation.getAccount().getUsername(); + } + } + + public void setNick(String nick) { + String jid = conversation.getContactJid().split("/")[0]+"/"+nick; + conversation.setContactJid(jid); + } + + public void setConversation(Conversation conversation) { + this.conversation = conversation; + } + + public boolean online() { + return this.isOnline; + } + + public int getError() { + return this.error; + } + + public void setOnRenameListener(OnRenameListener listener) { + this.renameListener = listener; + } + + public OnRenameListener getOnRenameListener() { + return this.renameListener; + } + + public void setOffline() { + this.users.clear(); + this.error = 0; + this.isOnline = false; } -} +}
\ No newline at end of file diff --git a/src/eu/siacs/conversations/services/XmppConnectionService.java b/src/eu/siacs/conversations/services/XmppConnectionService.java index 218d5088b..175377294 100644 --- a/src/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/eu/siacs/conversations/services/XmppConnectionService.java @@ -20,12 +20,15 @@ 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.entities.MucOptions.OnRenameListener; import eu.siacs.conversations.entities.Presences; import eu.siacs.conversations.persistance.DatabaseBackend; import eu.siacs.conversations.persistance.OnPhoneContactsMerged; import eu.siacs.conversations.ui.OnAccountListChangedListener; import eu.siacs.conversations.ui.OnConversationListChangedListener; import eu.siacs.conversations.ui.OnRosterFetchedListener; +import eu.siacs.conversations.ui.XmppActivity; import eu.siacs.conversations.utils.MessageParser; import eu.siacs.conversations.utils.OnPhoneContactsLoadedListener; import eu.siacs.conversations.utils.PhoneHelper; @@ -53,6 +56,7 @@ import android.os.PowerManager; import android.preference.PreferenceManager; import android.provider.ContactsContract; import android.util.Log; +import android.widget.Toast; public class XmppConnectionService extends Service { @@ -116,7 +120,7 @@ public class XmppConnectionService extends Service { } else if (packet.getType() == MessagePacket.TYPE_ERROR) { message = MessageParser.parseError(packet, account, service); } else { - Log.d(LOGTAG, "unparsed message " + packet.toString()); + //Log.d(LOGTAG, "unparsed message " + packet.toString()); } if (message == null) { return; @@ -188,8 +192,15 @@ public class XmppConnectionService extends Service { @Override public void onPresencePacketReceived(Account account, PresencePacket packet) { + Log.d(LOGTAG, packet.toString()); if (packet.hasChild("x")&&(packet.findChild("x").getAttribute("xmlns").startsWith("http://jabber.org/protocol/muc"))) { - Log.d(LOGTAG,"got muc presence "+packet.toString()); + Conversation muc = findMuc(packet.getAttribute("from").split("/")[0]); + if (muc!=null) { + muc.getMucOptions().processPacket(packet); + if (convChangedListener!=null) { + convChangedListener.onConversationListChanged(); + } + } } else { String[] fromParts = packet.getAttribute("from").split("/"); Contact contact = findContact(account, fromParts[0]); @@ -290,6 +301,15 @@ public class XmppConnectionService extends Service { } + protected Conversation findMuc(String name) { + for(Conversation conversation : this.conversations) { + if (conversation.getContactJid().split("/")[0].equals(name)) { + return conversation; + } + } + return null; + } + private void processRosterItems(Account account, Element elements) { String version = elements.getAttribute("ver"); if (version != null) { @@ -506,7 +526,7 @@ public class XmppConnectionService extends Service { } else if (message.getConversation().getMode() == Conversation.MODE_MULTI) { packet.setType(MessagePacket.TYPE_GROUPCHAT); packet.setBody(message.getBody()); - packet.setTo(message.getCounterpart()); + packet.setTo(message.getCounterpart().split("/")[0]); packet.setFrom(account.getJid()); } return packet; @@ -653,7 +673,7 @@ public class XmppConnectionService extends Service { boolean muc) { for (Conversation conv : this.getConversations()) { if ((conv.getAccount().equals(account)) - && (conv.getContactJid().equals(jid))) { + && (conv.getContactJid().split("/")[0].equals(jid))) { return conv; } } @@ -799,10 +819,19 @@ public class XmppConnectionService extends Service { } public void joinMuc(Conversation conversation) { - String muc = conversation.getContactJid(); + String[] mucParts = conversation.getContactJid().split("/"); + String muc; + String nick; + if (mucParts.length == 2) { + muc = mucParts[0]; + nick = mucParts[1]; + } else { + muc = mucParts[0]; + nick = conversation.getAccount().getUsername(); + } PresencePacket packet = new PresencePacket(); packet.setAttribute("to", muc + "/" - + conversation.getAccount().getUsername()); + + nick); Element x = new Element("x"); x.setAttribute("xmlns", "http://jabber.org/protocol/muc"); if (conversation.getMessages().size() != 0) { @@ -816,9 +845,55 @@ public class XmppConnectionService extends Service { conversation.getAccount().getXmppConnection() .sendPresencePacket(packet); } + + public void renameInMuc(final Conversation conversation, final String nick, final XmppActivity activity) { + final MucOptions options = conversation.getMucOptions(); + if (options.online()) { + options.setOnRenameListener(new OnRenameListener() { + + @Override + public void onRename(final boolean success) { + activity.runOnUiThread(new Runnable() { + + @Override + public void run() { + if (success) { + databaseBackend.updateConversation(conversation); + Toast.makeText(activity, "Your nickname has been changed", Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(activity, "Nickname already in use",Toast.LENGTH_SHORT).show(); + } + } + }); + } + }); + PresencePacket packet = new PresencePacket(); + packet.setAttribute("to", conversation.getContactJid().split("/")[0]+"/"+nick); + conversation.getAccount().getXmppConnection().sendPresencePacket(packet, new OnPresencePacketReceived() { + + @Override + public void onPresencePacketReceived(Account account, PresencePacket packet) { + final boolean changed; + String type = packet.getAttribute("type"); + changed = (!"error".equals(type)); + if (!changed) { + options.getOnRenameListener().onRename(changed); + } + options.processPacket(packet); + } + }); + } else { + String jid = conversation.getContactJid().split("/")[0]+"/"+nick; + conversation.setContactJid(jid); + databaseBackend.updateConversation(conversation); + if (conversation.getAccount().getStatus() == Account.STATUS_ONLINE) { + joinMuc(conversation); + } + } + } public void leaveMuc(Conversation conversation) { - + conversation.getMucOptions().setOffline(); } public void disconnect(Account account) { @@ -943,4 +1018,8 @@ public class XmppConnectionService extends Service { sendPgpPresence(account, signature); } } + + public void updateConversation(Conversation conversation) { + this.databaseBackend.updateConversation(conversation); + } }
\ No newline at end of file diff --git a/src/eu/siacs/conversations/ui/ConversationActivity.java b/src/eu/siacs/conversations/ui/ConversationActivity.java index 7660b8fd9..f826040bc 100644 --- a/src/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/eu/siacs/conversations/ui/ConversationActivity.java @@ -208,17 +208,7 @@ public class ConversationActivity extends XmppActivity { getActionBar().setDisplayHomeAsUpEnabled(false); getActionBar().setTitle(R.string.app_name); invalidateOptionsMenu(); - - InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); - - View focus = getCurrentFocus(); - - if (focus != null) { - - inputManager.hideSoftInputFromWindow( - focus.getWindowToken(), - InputMethodManager.HIDE_NOT_ALWAYS); - } + hideKeyboard(); } @Override @@ -316,6 +306,11 @@ public class ConversationActivity extends XmppActivity { builder.create().show(); } break; + case R.id.action_muc_details: + DialogMucDetails mucDetails = new DialogMucDetails(); + mucDetails.setConversation(getSelectedConversation()); + mucDetails.show(getFragmentManager(), "details"); + break; case R.id.action_security: final Conversation selConv = getSelectedConversation(); View menuItemView = findViewById(R.id.action_security); diff --git a/src/eu/siacs/conversations/ui/ConversationFragment.java b/src/eu/siacs/conversations/ui/ConversationFragment.java index ff06fafcc..a19cb18c2 100644 --- a/src/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/eu/siacs/conversations/ui/ConversationFragment.java @@ -13,9 +13,11 @@ import net.java.otr4j.session.SessionStatus; import eu.siacs.conversations.R; import eu.siacs.conversations.crypto.PgpEngine.OpenPgpException; import eu.siacs.conversations.crypto.PgpEngine.UserInputRequiredException; +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.XmppConnectionService; import eu.siacs.conversations.utils.PhoneHelper; import eu.siacs.conversations.utils.UIHelper; @@ -95,6 +97,17 @@ public class ConversationFragment extends Fragment { } }; private LinearLayout pgpInfo; + private LinearLayout mucError; + private TextView mucErrorText; + private OnClickListener clickToMuc = new OnClickListener() { + + @Override + public void onClick(View v) { + DialogMucDetails mucDetails = new DialogMucDetails(); + mucDetails.setConversation(conversation); + mucDetails.show(getFragmentManager(), "details"); + } + }; public void hidePgpPassphraseBox() { pgpInfo.setVisibility(View.GONE); @@ -138,6 +151,9 @@ public class ConversationFragment extends Fragment { pgpInfo = (LinearLayout) view.findViewById(R.id.pgp_keyentry); pgpInfo.setOnClickListener(clickToDecryptListener); + mucError = (LinearLayout) view.findViewById(R.id.muc_error); + mucError.setOnClickListener(clickToMuc ); + mucErrorText = (TextView) view.findViewById(R.id.muc_error_msg); messagesView = (ListView) view.findViewById(R.id.messages_view); @@ -348,15 +364,26 @@ public class ConversationFragment extends Fragment { this.messageList.clear(); this.messageList.addAll(this.conversation.getMessages()); this.messageListAdapter.notifyDataSetChanged(); - if (messageList.size() >= 1) { - int latestEncryption = this.conversation.getLatestMessage() - .getEncryption(); - if (latestEncryption== Message.ENCRYPTION_DECRYPTED) { - conversation.nextMessageEncryption = Message.ENCRYPTION_PGP; + if (conversation.getMode() == Conversation.MODE_SINGLE) { + if (messageList.size() >= 1) { + int latestEncryption = this.conversation.getLatestMessage() + .getEncryption(); + if (latestEncryption== Message.ENCRYPTION_DECRYPTED) { + conversation.nextMessageEncryption = Message.ENCRYPTION_PGP; + } else { + conversation.nextMessageEncryption = latestEncryption; + } + makeFingerprintWarning(latestEncryption); + } + } else { + if (conversation.getMucOptions().getError() != 0) { + mucError.setVisibility(View.VISIBLE); + if (conversation.getMucOptions().getError() == MucOptions.ERROR_NICK_IN_USE) { + mucErrorText.setText(getString(R.string.nick_in_use)); + } } else { - conversation.nextMessageEncryption = latestEncryption; + mucError.setVisibility(View.GONE); } - makeFingerprintWarning(latestEncryption); } getActivity().invalidateOptionsMenu(); updateChatMsgHint(); diff --git a/src/eu/siacs/conversations/ui/DialogMucDetails.java b/src/eu/siacs/conversations/ui/DialogMucDetails.java new file mode 100644 index 000000000..a752e88fa --- /dev/null +++ b/src/eu/siacs/conversations/ui/DialogMucDetails.java @@ -0,0 +1,100 @@ +package eu.siacs.conversations.ui; + + +import eu.siacs.conversations.R; +import eu.siacs.conversations.entities.Conversation; +import eu.siacs.conversations.entities.MucOptions; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.EditText; +import android.widget.TextView; + +public class DialogMucDetails extends DialogFragment { + private XmppActivity activity; + private Conversation conversation; + private EditText mYourNick; + private OnClickListener changeNickListener = new OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + MucOptions options = conversation.getMucOptions(); + String nick = mYourNick.getText().toString(); + if (!options.getNick().equals(nick)) { + activity.xmppConnectionService.renameInMuc(conversation,nick,activity); + } + } + }; + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + this.activity = (XmppActivity) getActivity(); + AlertDialog.Builder builder = new AlertDialog.Builder(this.activity); + LayoutInflater inflater = getActivity().getLayoutInflater(); + View view = inflater.inflate(R.layout.muc_options, null); + builder.setView(view); + builder.setTitle(getString(R.string.conference_details)); + mYourNick = (EditText) view.findViewById(R.id.muc_your_nick); + TextView mTextModerators = (TextView) view.findViewById(R.id.muc_moderators); + TextView mTextParticipants = (TextView) view.findViewById(R.id.muc_participants); + TextView mTextVisiotors = (TextView) view.findViewById(R.id.muc_visitors); + TextView mTextModeratorsHead = (TextView) view.findViewById(R.id.muc_moderators_header); + TextView mTextParticipantsHead = (TextView) view.findViewById(R.id.muc_participants_header); + TextView mTextVisiotorsHead = (TextView) view.findViewById(R.id.muc_visitors_header); + StringBuilder mods = new StringBuilder(); + StringBuilder participants = new StringBuilder(); + StringBuilder visitors = new StringBuilder(); + for(MucOptions.User user : conversation.getMucOptions().getUsers()) { + if (user.getRole() == MucOptions.User.ROLE_MODERATOR) { + if (mods.length()>=1) { + mods.append("\n, "+user.getName()); + } else { + mods.append(user.getName()); + } + } else if (user.getRole() == MucOptions.User.ROLE_PARTICIPANT) { + if (participants.length()>=1) { + participants.append("\n, "+user.getName()); + } else { + participants.append(user.getName()); + } + } else { + if (visitors.length()>=1) { + visitors.append("\n, "+user.getName()); + } else { + visitors.append(user.getName()); + } + } + } + if (mods.length()>0) { + mTextModerators.setText(mods.toString()); + } else { + mTextModerators.setVisibility(View.GONE); + mTextModeratorsHead.setVisibility(View.GONE); + } + if (participants.length()>0) { + mTextParticipants.setText(participants.toString()); + } else { + mTextParticipants.setVisibility(View.GONE); + mTextParticipantsHead.setVisibility(View.GONE); + } + if (visitors.length()>0) { + mTextVisiotors.setText(visitors.toString()); + } else { + mTextVisiotors.setVisibility(View.GONE); + mTextVisiotorsHead.setVisibility(View.GONE); + } + mYourNick.setText(conversation.getMucOptions().getNick()); + builder.setPositiveButton("Done", this.changeNickListener ); + builder.setNegativeButton("Cancel", null); + return builder.create(); + } + + public void setConversation(Conversation conversation) { + this.conversation = conversation; + } +} diff --git a/src/eu/siacs/conversations/ui/XmppActivity.java b/src/eu/siacs/conversations/ui/XmppActivity.java index 5114e640c..569563c1a 100644 --- a/src/eu/siacs/conversations/ui/XmppActivity.java +++ b/src/eu/siacs/conversations/ui/XmppActivity.java @@ -8,6 +8,8 @@ import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.IBinder; +import android.view.View; +import android.view.inputmethod.InputMethodManager; public abstract class XmppActivity extends Activity { public XmppConnectionService xmppConnectionService; @@ -48,5 +50,18 @@ public abstract class XmppActivity extends Activity { } } + protected void hideKeyboard() { + InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); + + View focus = getCurrentFocus(); + + if (focus != null) { + + inputManager.hideSoftInputFromWindow( + focus.getWindowToken(), + InputMethodManager.HIDE_NOT_ALWAYS); + } + } + abstract void onBackendConnected(); } diff --git a/src/eu/siacs/conversations/utils/MessageParser.java b/src/eu/siacs/conversations/utils/MessageParser.java index dc0cd35cf..65186957a 100644 --- a/src/eu/siacs/conversations/utils/MessageParser.java +++ b/src/eu/siacs/conversations/utils/MessageParser.java @@ -85,7 +85,7 @@ public class MessageParser { return null; } String counterPart = fromParts[1]; - if (counterPart.equals(account.getUsername())) { + if (counterPart.equals(conversation.getMucOptions().getNick())) { status = Message.STATUS_SEND; } else { status = Message.STATUS_RECIEVED; diff --git a/src/eu/siacs/conversations/xmpp/OnIqPacketReceived.java b/src/eu/siacs/conversations/xmpp/OnIqPacketReceived.java index 4e09282c3..54909f88c 100644 --- a/src/eu/siacs/conversations/xmpp/OnIqPacketReceived.java +++ b/src/eu/siacs/conversations/xmpp/OnIqPacketReceived.java @@ -2,6 +2,6 @@ package eu.siacs.conversations.xmpp; import eu.siacs.conversations.entities.Account; -public interface OnIqPacketReceived { +public interface OnIqPacketReceived extends PacketReceived { public void onIqPacketReceived(Account account, IqPacket packet); } diff --git a/src/eu/siacs/conversations/xmpp/OnMessagePacketReceived.java b/src/eu/siacs/conversations/xmpp/OnMessagePacketReceived.java index 3d169300d..6f0b387dc 100644 --- a/src/eu/siacs/conversations/xmpp/OnMessagePacketReceived.java +++ b/src/eu/siacs/conversations/xmpp/OnMessagePacketReceived.java @@ -2,6 +2,6 @@ package eu.siacs.conversations.xmpp; import eu.siacs.conversations.entities.Account; -public interface OnMessagePacketReceived { +public interface OnMessagePacketReceived extends PacketReceived { public void onMessagePacketReceived(Account account, MessagePacket packet); } diff --git a/src/eu/siacs/conversations/xmpp/OnPresencePacketReceived.java b/src/eu/siacs/conversations/xmpp/OnPresencePacketReceived.java index 058d8be91..55672fff2 100644 --- a/src/eu/siacs/conversations/xmpp/OnPresencePacketReceived.java +++ b/src/eu/siacs/conversations/xmpp/OnPresencePacketReceived.java @@ -2,6 +2,6 @@ package eu.siacs.conversations.xmpp; import eu.siacs.conversations.entities.Account; -public interface OnPresencePacketReceived { +public interface OnPresencePacketReceived extends PacketReceived { public void onPresencePacketReceived(Account account, PresencePacket packet); } diff --git a/src/eu/siacs/conversations/xmpp/PacketReceived.java b/src/eu/siacs/conversations/xmpp/PacketReceived.java new file mode 100644 index 000000000..d9f424598 --- /dev/null +++ b/src/eu/siacs/conversations/xmpp/PacketReceived.java @@ -0,0 +1,5 @@ +package eu.siacs.conversations.xmpp; + +abstract interface PacketReceived { + +} diff --git a/src/eu/siacs/conversations/xmpp/XmppConnection.java b/src/eu/siacs/conversations/xmpp/XmppConnection.java index 4583c145b..6e65e1ed0 100644 --- a/src/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/eu/siacs/conversations/xmpp/XmppConnection.java @@ -53,7 +53,7 @@ public class XmppConnection implements Runnable { private static final int PACKET_MESSAGE = 1; private static final int PACKET_PRESENCE = 2; - private Hashtable<String, OnIqPacketReceived> iqPacketCallbacks = new Hashtable<String, OnIqPacketReceived>(); + private Hashtable<String, PacketReceived> packetCallbacks = new Hashtable<String, PacketReceived>(); private OnPresencePacketReceived presenceListener = null; private OnIqPacketReceived unregisteredIqListener = null; private OnMessagePacketReceived messageListener = null; @@ -212,24 +212,33 @@ public class XmppConnection implements Runnable { return element; } - private IqPacket processIq(Tag currentTag) throws XmlPullParserException, + private void processIq(Tag currentTag) throws XmlPullParserException, IOException { IqPacket packet = (IqPacket) processPacket(currentTag, PACKET_IQ); - if (iqPacketCallbacks.containsKey(packet.getId())) { - iqPacketCallbacks.get(packet.getId()).onIqPacketReceived(account, - packet); - iqPacketCallbacks.remove(packet.getId()); + if (packetCallbacks.containsKey(packet.getId())) { + if (packetCallbacks.get(packet.getId()) instanceof OnIqPacketReceived) { + ((OnIqPacketReceived) packetCallbacks.get(packet.getId())).onIqPacketReceived(account, + packet); + } + + packetCallbacks.remove(packet.getId()); } else if (this.unregisteredIqListener != null) { this.unregisteredIqListener.onIqPacketReceived(account, packet); } - return packet; } private void processMessage(Tag currentTag) throws XmlPullParserException, IOException { MessagePacket packet = (MessagePacket) processPacket(currentTag, PACKET_MESSAGE); - if (this.messageListener != null) { + String id = packet.getAttribute("id"); + if ((id!=null)&&(packetCallbacks.containsKey(id))) { + if (packetCallbacks.get(id) instanceof OnMessagePacketReceived) { + ((OnMessagePacketReceived) packetCallbacks.get(id)).onMessagePacketReceived(account, + packet); + } + packetCallbacks.remove(id); + } else if (this.messageListener != null) { this.messageListener.onMessagePacketReceived(account, packet); } } @@ -238,7 +247,14 @@ public class XmppConnection implements Runnable { IOException { PresencePacket packet = (PresencePacket) processPacket(currentTag, PACKET_PRESENCE); - if (this.presenceListener != null) { + String id = packet.getAttribute("id"); + if ((id!=null)&&(packetCallbacks.containsKey(id))) { + if (packetCallbacks.get(id) instanceof OnPresencePacketReceived) { + ((OnPresencePacketReceived) packetCallbacks.get(id)).onPresencePacketReceived(account, + packet); + } + packetCallbacks.remove(id); + } else if (this.presenceListener != null) { this.presenceListener.onPresencePacketReceived(account, packet); } } @@ -405,19 +421,34 @@ public class XmppConnection implements Runnable { packet.setAttribute("id", id); tagWriter.writeElement(packet); if (callback != null) { - iqPacketCallbacks.put(id, callback); + packetCallbacks.put(id, callback); } - //Log.d(LOGTAG, account.getJid() + ": sending: " + packet.toString()); } public void sendMessagePacket(MessagePacket packet) { - Log.d(LOGTAG,"sending message packet "+packet.toString()); + this.sendMessagePacket(packet, null); + } + + public void sendMessagePacket(MessagePacket packet, OnMessagePacketReceived callback) { + String id = nextRandomId(); + packet.setAttribute("id", id); tagWriter.writeElement(packet); + if (callback != null) { + packetCallbacks.put(id, callback); + } } public void sendPresencePacket(PresencePacket packet) { + this.sendPresencePacket(packet, null); + } + + public void sendPresencePacket(PresencePacket packet, OnPresencePacketReceived callback) { + String id = nextRandomId(); + packet.setAttribute("id", id); tagWriter.writeElement(packet); - Log.d(LOGTAG, account.getJid() + ": sending: " + packet.toString()); + if (callback != null) { + packetCallbacks.put(id, callback); + } } public void setOnMessagePacketReceivedListener( |