api changes. muc options

This commit is contained in:
Daniel Gultsch 2014-03-03 05:01:02 +01:00
parent 2ab6cb0ada
commit c609eefefa
20 changed files with 648 additions and 128 deletions

View file

@ -44,6 +44,11 @@
android:name="eu.siacs.conversations.ui.ManageAccountActivity"
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"

View file

@ -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;

View file

@ -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;

View file

@ -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"

View file

@ -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>

View file

@ -15,4 +15,6 @@
<string name="sending">sending&#8230;</string>
<string name="announce_pgp">Renew PGP announcement</string>
<string name="encrypted_message">Decrypting message. please wait&#8230;</string>
<string name="conference_details">Conference Details</string>
<string name="nick_in_use">Nickname is already in use</string>
</resources>

View file

@ -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();

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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) {
@ -817,8 +846,54 @@ public class XmppConnectionService extends Service {
.sendPresencePacket(packet);
}
public void leaveMuc(Conversation conversation) {
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);
}
}

View file

@ -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);

View file

@ -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();

View file

@ -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;
}
}

View file

@ -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();
}

View file

@ -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;

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -0,0 +1,5 @@
package eu.siacs.conversations.xmpp;
abstract interface PacketReceived {
}

View file

@ -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(