From c609eefefac5097c7c40a9f1b8741e9634da316f Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Mon, 3 Mar 2014 05:01:02 +0100 Subject: [PATCH] api changes. muc options --- AndroidManifest.xml | 5 + gen/eu/siacs/conversations/R.java | 95 +++++++----- .../sufficientlysecure/keychain/api/R.java | 1 + res/layout/fragment_conversation.xml | 30 ++++ res/layout/muc_options.xml | 76 +++++++++ res/values/strings.xml | 2 + .../siacs/conversations/crypto/PgpEngine.java | 78 +++++----- .../conversations/entities/Conversation.java | 5 + .../conversations/entities/MucOptions.java | 146 +++++++++++++++++- .../services/XmppConnectionService.java | 93 ++++++++++- .../ui/ConversationActivity.java | 17 +- .../ui/ConversationFragment.java | 43 +++++- .../conversations/ui/DialogMucDetails.java | 100 ++++++++++++ .../siacs/conversations/ui/XmppActivity.java | 15 ++ .../conversations/utils/MessageParser.java | 2 +- .../xmpp/OnIqPacketReceived.java | 2 +- .../xmpp/OnMessagePacketReceived.java | 2 +- .../xmpp/OnPresencePacketReceived.java | 2 +- .../conversations/xmpp/PacketReceived.java | 5 + .../conversations/xmpp/XmppConnection.java | 57 +++++-- 20 files changed, 648 insertions(+), 128 deletions(-) create mode 100644 res/layout/muc_options.xml create mode 100644 src/eu/siacs/conversations/ui/DialogMucDetails.java create mode 100644 src/eu/siacs/conversations/xmpp/PacketReceived.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index d511bef57..90e177c10 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -44,6 +44,11 @@ android:name="eu.siacs.conversations.ui.ManageAccountActivity" android:label="Manage Accounts" android:parentActivityName="eu.siacs.conversations.ui.ConversationActivity" > + + + + + + + + + + + + + + + + + + + + + + + + + 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 @@ sending… Renew PGP announcement Decrypting message. please wait… + Conference Details + Nickname is already in use 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 users = new ArrayList(); + 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 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; - } else { - conversation.nextMessageEncryption = latestEncryption; + 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 { + 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 iqPacketCallbacks = new Hashtable(); + private Hashtable packetCallbacks = new Hashtable(); 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(