2014-01-24 01:04:05 +00:00
|
|
|
package de.gultsch.chat.services;
|
|
|
|
|
2014-02-11 14:34:24 +00:00
|
|
|
import java.text.ParseException;
|
|
|
|
import java.text.SimpleDateFormat;
|
|
|
|
import java.util.Date;
|
2014-02-01 14:07:20 +00:00
|
|
|
import java.util.Hashtable;
|
2014-01-25 18:33:12 +00:00
|
|
|
import java.util.List;
|
2014-02-13 22:40:08 +00:00
|
|
|
|
2014-02-27 23:22:56 +00:00
|
|
|
import org.json.JSONException;
|
|
|
|
import org.openintents.openpgp.util.OpenPgpApi;
|
|
|
|
import org.openintents.openpgp.util.OpenPgpServiceConnection;
|
|
|
|
|
2014-02-13 22:40:08 +00:00
|
|
|
import net.java.otr4j.OtrException;
|
|
|
|
import net.java.otr4j.session.Session;
|
|
|
|
import net.java.otr4j.session.SessionStatus;
|
2014-01-25 18:33:12 +00:00
|
|
|
|
2014-02-27 23:22:56 +00:00
|
|
|
import de.gultsch.chat.crypto.PgpEngine;
|
|
|
|
import de.gultsch.chat.crypto.PgpEngine.OpenPgpException;
|
2014-01-27 19:40:42 +00:00
|
|
|
import de.gultsch.chat.entities.Account;
|
|
|
|
import de.gultsch.chat.entities.Contact;
|
2014-01-25 18:33:12 +00:00
|
|
|
import de.gultsch.chat.entities.Conversation;
|
|
|
|
import de.gultsch.chat.entities.Message;
|
2014-02-08 23:47:11 +00:00
|
|
|
import de.gultsch.chat.entities.Presences;
|
2014-01-25 18:33:12 +00:00
|
|
|
import de.gultsch.chat.persistance.DatabaseBackend;
|
2014-02-19 00:35:23 +00:00
|
|
|
import de.gultsch.chat.persistance.OnPhoneContactsMerged;
|
2014-02-04 14:09:50 +00:00
|
|
|
import de.gultsch.chat.ui.OnAccountListChangedListener;
|
2014-02-01 14:07:20 +00:00
|
|
|
import de.gultsch.chat.ui.OnConversationListChangedListener;
|
2014-02-02 15:05:15 +00:00
|
|
|
import de.gultsch.chat.ui.OnRosterFetchedListener;
|
2014-02-19 00:35:23 +00:00
|
|
|
import de.gultsch.chat.utils.MessageParser;
|
2014-02-10 02:34:00 +00:00
|
|
|
import de.gultsch.chat.utils.OnPhoneContactsLoadedListener;
|
|
|
|
import de.gultsch.chat.utils.PhoneHelper;
|
2014-02-03 17:38:47 +00:00
|
|
|
import de.gultsch.chat.utils.UIHelper;
|
2014-02-02 15:05:15 +00:00
|
|
|
import de.gultsch.chat.xml.Element;
|
|
|
|
import de.gultsch.chat.xmpp.IqPacket;
|
2014-02-01 14:07:20 +00:00
|
|
|
import de.gultsch.chat.xmpp.MessagePacket;
|
2014-02-02 15:05:15 +00:00
|
|
|
import de.gultsch.chat.xmpp.OnIqPacketReceived;
|
2014-02-01 14:07:20 +00:00
|
|
|
import de.gultsch.chat.xmpp.OnMessagePacketReceived;
|
2014-02-07 01:57:36 +00:00
|
|
|
import de.gultsch.chat.xmpp.OnPresencePacketReceived;
|
2014-02-04 14:09:50 +00:00
|
|
|
import de.gultsch.chat.xmpp.OnStatusChanged;
|
2014-02-05 21:33:39 +00:00
|
|
|
import de.gultsch.chat.xmpp.PresencePacket;
|
2014-01-30 15:42:35 +00:00
|
|
|
import de.gultsch.chat.xmpp.XmppConnection;
|
2014-02-03 17:38:47 +00:00
|
|
|
import android.app.NotificationManager;
|
2014-01-24 01:04:05 +00:00
|
|
|
import android.app.Service;
|
2014-01-30 15:42:35 +00:00
|
|
|
import android.content.Context;
|
2014-01-24 01:04:05 +00:00
|
|
|
import android.content.Intent;
|
2014-02-23 20:33:37 +00:00
|
|
|
import android.content.SharedPreferences;
|
2014-02-10 14:24:34 +00:00
|
|
|
import android.database.ContentObserver;
|
2014-02-19 00:35:23 +00:00
|
|
|
import android.database.DatabaseUtils;
|
2014-01-24 01:04:05 +00:00
|
|
|
import android.os.Binder;
|
2014-02-05 21:33:39 +00:00
|
|
|
import android.os.Bundle;
|
2014-01-24 01:04:05 +00:00
|
|
|
import android.os.IBinder;
|
2014-01-30 15:42:35 +00:00
|
|
|
import android.os.PowerManager;
|
2014-02-23 20:33:37 +00:00
|
|
|
import android.preference.PreferenceManager;
|
2014-02-05 21:33:39 +00:00
|
|
|
import android.provider.ContactsContract;
|
2014-01-25 18:33:12 +00:00
|
|
|
import android.util.Log;
|
2014-01-24 01:04:05 +00:00
|
|
|
|
|
|
|
public class XmppConnectionService extends Service {
|
2014-02-03 17:38:47 +00:00
|
|
|
|
2014-01-30 15:42:35 +00:00
|
|
|
protected static final String LOGTAG = "xmppService";
|
2014-02-19 00:35:23 +00:00
|
|
|
public DatabaseBackend databaseBackend;
|
2014-02-03 17:38:47 +00:00
|
|
|
|
2014-01-30 15:42:35 +00:00
|
|
|
public long startDate;
|
2014-02-03 17:38:47 +00:00
|
|
|
|
2014-01-30 15:42:35 +00:00
|
|
|
private List<Account> accounts;
|
2014-02-01 14:07:20 +00:00
|
|
|
private List<Conversation> conversations = null;
|
2014-02-03 17:38:47 +00:00
|
|
|
|
2014-02-19 00:35:23 +00:00
|
|
|
public OnConversationListChangedListener convChangedListener = null;
|
2014-02-04 14:09:50 +00:00
|
|
|
private OnAccountListChangedListener accountChangedListener = null;
|
2014-02-11 22:55:03 +00:00
|
|
|
|
2014-02-10 14:24:34 +00:00
|
|
|
private ContentObserver contactObserver = new ContentObserver(null) {
|
|
|
|
@Override
|
2014-02-11 22:55:03 +00:00
|
|
|
public void onChange(boolean selfChange) {
|
|
|
|
super.onChange(selfChange);
|
|
|
|
Log.d(LOGTAG, "contact list has changed");
|
2014-02-19 00:35:23 +00:00
|
|
|
mergePhoneContactsWithRoster(null);
|
2014-02-11 22:55:03 +00:00
|
|
|
}
|
2014-02-10 14:24:34 +00:00
|
|
|
};
|
2014-02-03 17:38:47 +00:00
|
|
|
|
2014-02-19 00:35:23 +00:00
|
|
|
private XmppConnectionService service = this;
|
|
|
|
|
2014-02-03 17:38:47 +00:00
|
|
|
private final IBinder mBinder = new XmppConnectionBinder();
|
2014-02-01 14:07:20 +00:00
|
|
|
private OnMessagePacketReceived messageListener = new OnMessagePacketReceived() {
|
2014-02-03 17:38:47 +00:00
|
|
|
|
2014-02-01 14:07:20 +00:00
|
|
|
@Override
|
2014-02-03 17:38:47 +00:00
|
|
|
public void onMessagePacketReceived(Account account,
|
|
|
|
MessagePacket packet) {
|
2014-02-19 00:35:23 +00:00
|
|
|
Message message = null;
|
|
|
|
boolean notify = false;
|
|
|
|
if ((packet.getType() == MessagePacket.TYPE_CHAT)) {
|
2014-02-27 23:22:56 +00:00
|
|
|
String pgpBody = MessageParser.getPgpBody(packet);
|
|
|
|
if (pgpBody != null) {
|
|
|
|
message = MessageParser.parsePgpChat(pgpBody, packet,
|
|
|
|
account, service);
|
|
|
|
notify = false;
|
|
|
|
} else if (packet.hasChild("body")
|
2014-02-19 00:35:23 +00:00
|
|
|
&& (packet.getBody().startsWith("?OTR"))) {
|
|
|
|
message = MessageParser.parseOtrChat(packet, account,
|
|
|
|
service);
|
|
|
|
notify = true;
|
|
|
|
} else if (packet.hasChild("body")) {
|
|
|
|
message = MessageParser.parsePlainTextChat(packet, account,
|
|
|
|
service);
|
|
|
|
notify = true;
|
|
|
|
} else if (packet.hasChild("received")
|
|
|
|
|| (packet.hasChild("sent"))) {
|
|
|
|
message = MessageParser.parseCarbonMessage(packet, account,
|
|
|
|
service);
|
2014-02-05 21:33:39 +00:00
|
|
|
}
|
2014-02-19 00:35:23 +00:00
|
|
|
|
|
|
|
} else if (packet.getType() == MessagePacket.TYPE_GROUPCHAT) {
|
|
|
|
message = MessageParser
|
|
|
|
.parseGroupchat(packet, account, service);
|
|
|
|
if (message != null) {
|
|
|
|
notify = (message.getStatus() == Message.STATUS_RECIEVED);
|
2014-02-05 21:33:39 +00:00
|
|
|
}
|
2014-02-20 16:00:50 +00:00
|
|
|
} else if (packet.getType() == MessagePacket.TYPE_ERROR) {
|
2014-02-23 20:33:37 +00:00
|
|
|
message = MessageParser.parseError(packet, account, service);
|
2014-02-19 00:35:23 +00:00
|
|
|
} else {
|
|
|
|
Log.d(LOGTAG, "unparsed message " + packet.toString());
|
|
|
|
}
|
|
|
|
if (message == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (packet.hasChild("delay")) {
|
|
|
|
try {
|
|
|
|
String stamp = packet.findChild("delay").getAttribute(
|
|
|
|
"stamp");
|
|
|
|
stamp = stamp.replace("Z", "+0000");
|
|
|
|
Date date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
|
|
|
|
.parse(stamp);
|
|
|
|
message.setTime(date.getTime());
|
|
|
|
} catch (ParseException e) {
|
|
|
|
Log.d(LOGTAG, "error trying to parse date" + e.getMessage());
|
2014-02-11 14:34:24 +00:00
|
|
|
}
|
2014-02-19 00:35:23 +00:00
|
|
|
}
|
|
|
|
if (notify) {
|
|
|
|
message.markUnread();
|
|
|
|
}
|
|
|
|
Conversation conversation = message.getConversation();
|
|
|
|
conversation.getMessages().add(message);
|
2014-02-20 16:00:50 +00:00
|
|
|
if (packet.getType() != MessagePacket.TYPE_ERROR) {
|
|
|
|
databaseBackend.createMessage(message);
|
|
|
|
}
|
2014-02-19 00:35:23 +00:00
|
|
|
if (convChangedListener != null) {
|
|
|
|
convChangedListener.onConversationListChanged();
|
|
|
|
} else {
|
2014-02-11 22:55:03 +00:00
|
|
|
if (notify) {
|
2014-02-19 00:35:23 +00:00
|
|
|
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
|
|
|
mNotificationManager.notify(2342, UIHelper
|
|
|
|
.getUnreadMessageNotification(
|
|
|
|
getApplicationContext(), conversation));
|
2014-02-02 16:53:34 +00:00
|
|
|
}
|
2014-02-01 14:07:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2014-02-04 14:09:50 +00:00
|
|
|
private OnStatusChanged statusListener = new OnStatusChanged() {
|
2014-02-05 21:33:39 +00:00
|
|
|
|
2014-02-04 14:09:50 +00:00
|
|
|
@Override
|
|
|
|
public void onStatusChanged(Account account) {
|
|
|
|
if (accountChangedListener != null) {
|
|
|
|
accountChangedListener.onAccountListChangedListener();
|
|
|
|
}
|
2014-02-05 21:33:39 +00:00
|
|
|
if (account.getStatus() == Account.STATUS_ONLINE) {
|
2014-02-08 23:47:11 +00:00
|
|
|
databaseBackend.clearPresences(account);
|
2014-02-05 21:33:39 +00:00
|
|
|
connectMultiModeConversations(account);
|
2014-02-11 22:55:03 +00:00
|
|
|
List<Conversation> conversations = getConversations();
|
2014-02-13 22:40:08 +00:00
|
|
|
for (int i = 0; i < conversations.size(); ++i) {
|
|
|
|
if (conversations.get(i).getAccount() == account) {
|
|
|
|
sendUnsendMessages(conversations.get(i));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (convChangedListener != null) {
|
|
|
|
convChangedListener.onConversationListChanged();
|
|
|
|
}
|
2014-02-27 23:22:56 +00:00
|
|
|
if (account.getKeys().has("pgp_signature")) {
|
|
|
|
try {
|
|
|
|
sendPgpPresence(account, account.getKeys().getString("pgp_signature"));
|
|
|
|
} catch (JSONException e) {
|
|
|
|
//
|
|
|
|
}
|
|
|
|
}
|
2014-02-05 21:33:39 +00:00
|
|
|
}
|
2014-02-04 14:09:50 +00:00
|
|
|
}
|
|
|
|
};
|
2014-02-08 23:47:11 +00:00
|
|
|
|
2014-02-07 01:57:36 +00:00
|
|
|
private OnPresencePacketReceived presenceListener = new OnPresencePacketReceived() {
|
2014-02-08 23:47:11 +00:00
|
|
|
|
2014-02-07 01:57:36 +00:00
|
|
|
@Override
|
2014-02-08 23:47:11 +00:00
|
|
|
public void onPresencePacketReceived(Account account,
|
|
|
|
PresencePacket packet) {
|
|
|
|
String[] fromParts = packet.getAttribute("from").split("/");
|
2014-02-10 14:24:34 +00:00
|
|
|
Contact contact = findContact(account, fromParts[0]);
|
|
|
|
if (contact == null) {
|
2014-02-09 13:10:52 +00:00
|
|
|
// most likely muc, self or roster not synced
|
2014-02-23 20:33:37 +00:00
|
|
|
Log.d(LOGTAG,
|
|
|
|
"got presence for non contact " + packet.toString());
|
2014-02-10 14:24:34 +00:00
|
|
|
return;
|
2014-02-08 23:47:11 +00:00
|
|
|
}
|
2014-02-07 01:57:36 +00:00
|
|
|
String type = packet.getAttribute("type");
|
2014-02-08 23:47:11 +00:00
|
|
|
if (type == null) {
|
|
|
|
Element show = packet.findChild("show");
|
2014-02-09 13:10:52 +00:00
|
|
|
if (show == null) {
|
|
|
|
contact.updatePresence(fromParts[1], Presences.ONLINE);
|
2014-02-08 23:47:11 +00:00
|
|
|
} else if (show.getContent().equals("away")) {
|
2014-02-09 13:10:52 +00:00
|
|
|
contact.updatePresence(fromParts[1], Presences.AWAY);
|
2014-02-08 23:47:11 +00:00
|
|
|
} else if (show.getContent().equals("xa")) {
|
2014-02-09 13:10:52 +00:00
|
|
|
contact.updatePresence(fromParts[1], Presences.XA);
|
2014-02-08 23:47:11 +00:00
|
|
|
} else if (show.getContent().equals("chat")) {
|
2014-02-09 13:10:52 +00:00
|
|
|
contact.updatePresence(fromParts[1], Presences.CHAT);
|
2014-02-08 23:47:11 +00:00
|
|
|
} else if (show.getContent().equals("dnd")) {
|
2014-02-09 13:10:52 +00:00
|
|
|
contact.updatePresence(fromParts[1], Presences.DND);
|
2014-02-08 23:47:11 +00:00
|
|
|
}
|
2014-02-27 23:22:56 +00:00
|
|
|
Element x = packet.findChild("x");
|
|
|
|
if ((x != null)
|
|
|
|
&& (x.getAttribute("xmlns").equals("jabber:x:signed"))) {
|
|
|
|
try {
|
|
|
|
Log.d(LOGTAG,"pgp signature for contact" +packet.getAttribute("from"));
|
|
|
|
contact.setPgpKeyId(getPgpEngine().fetchKeyId(packet.findChild("status")
|
|
|
|
.getContent(), x.getContent()));
|
|
|
|
databaseBackend.updateContact(contact);
|
|
|
|
} catch (OpenPgpException e) {
|
|
|
|
Log.d(LOGTAG,"faulty pgp. just ignore");
|
|
|
|
}
|
|
|
|
}
|
2014-02-08 23:47:11 +00:00
|
|
|
databaseBackend.updateContact(contact);
|
|
|
|
} else if (type.equals("unavailable")) {
|
2014-02-09 13:10:52 +00:00
|
|
|
if (fromParts.length != 2) {
|
|
|
|
// Log.d(LOGTAG,"received presence with no resource "+packet.toString());
|
2014-02-08 23:47:11 +00:00
|
|
|
} else {
|
|
|
|
contact.removePresence(fromParts[1]);
|
|
|
|
databaseBackend.updateContact(contact);
|
|
|
|
}
|
2014-02-21 20:35:23 +00:00
|
|
|
} else if (type.equals("subscribe")) {
|
2014-02-23 20:33:37 +00:00
|
|
|
if (contact
|
|
|
|
.getSubscriptionOption(Contact.Subscription.PREEMPTIVE_GRANT)) {
|
2014-02-21 20:35:23 +00:00
|
|
|
sendPresenceUpdatesTo(contact);
|
|
|
|
contact.setSubscriptionOption(Contact.Subscription.FROM);
|
|
|
|
contact.resetSubscriptionOption(Contact.Subscription.PREEMPTIVE_GRANT);
|
|
|
|
replaceContactInConversation(contact.getJid(), contact);
|
|
|
|
databaseBackend.updateContact(contact);
|
2014-02-23 20:33:37 +00:00
|
|
|
if ((contact
|
|
|
|
.getSubscriptionOption(Contact.Subscription.ASKING))
|
|
|
|
&& (!contact
|
|
|
|
.getSubscriptionOption(Contact.Subscription.TO))) {
|
|
|
|
requestPresenceUpdatesFrom(contact);
|
|
|
|
}
|
2014-02-21 20:35:23 +00:00
|
|
|
} else {
|
2014-02-23 20:33:37 +00:00
|
|
|
// TODO: ask user to handle it maybe
|
2014-02-21 20:35:23 +00:00
|
|
|
}
|
|
|
|
} else {
|
2014-02-23 20:33:37 +00:00
|
|
|
Log.d(LOGTAG, packet.toString());
|
2014-02-07 01:57:36 +00:00
|
|
|
}
|
2014-02-23 20:33:37 +00:00
|
|
|
replaceContactInConversation(contact.getJid(), contact);
|
2014-02-07 01:57:36 +00:00
|
|
|
}
|
|
|
|
};
|
2014-02-19 00:35:23 +00:00
|
|
|
|
|
|
|
private OnIqPacketReceived unknownIqListener = new OnIqPacketReceived() {
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onIqPacketReceived(Account account, IqPacket packet) {
|
|
|
|
if (packet.hasChild("query")) {
|
|
|
|
Element query = packet.findChild("query");
|
|
|
|
String xmlns = query.getAttribute("xmlns");
|
|
|
|
if ((xmlns != null) && (xmlns.equals("jabber:iq:roster"))) {
|
|
|
|
processRosterItems(account, query);
|
|
|
|
mergePhoneContactsWithRoster(null);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-02-27 23:22:56 +00:00
|
|
|
private OpenPgpServiceConnection pgpServiceConnection;
|
|
|
|
private PgpEngine mPgpEngine = null;
|
|
|
|
|
|
|
|
public PgpEngine getPgpEngine() {
|
|
|
|
if (pgpServiceConnection.isBound()) {
|
|
|
|
if (this.mPgpEngine == null) {
|
|
|
|
this.mPgpEngine = new PgpEngine(new OpenPgpApi(
|
|
|
|
getApplicationContext(),
|
|
|
|
pgpServiceConnection.getService()));
|
|
|
|
}
|
|
|
|
return mPgpEngine;
|
|
|
|
} else {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2014-02-19 00:35:23 +00:00
|
|
|
private void processRosterItems(Account account, Element elements) {
|
2014-02-28 01:58:15 +00:00
|
|
|
String version = elements.getAttribute("ver");
|
|
|
|
if (version != null) {
|
|
|
|
account.setRosterVersion(version);
|
|
|
|
databaseBackend.updateAccount(account);
|
|
|
|
}
|
2014-02-19 00:35:23 +00:00
|
|
|
for (Element item : elements.getChildren()) {
|
|
|
|
if (item.getName().equals("item")) {
|
|
|
|
String jid = item.getAttribute("jid");
|
|
|
|
String subscription = item.getAttribute("subscription");
|
|
|
|
Contact contact = databaseBackend.findContact(account, jid);
|
|
|
|
if (contact == null) {
|
2014-02-21 20:35:23 +00:00
|
|
|
if (!subscription.equals("remove")) {
|
|
|
|
String name = item.getAttribute("name");
|
|
|
|
if (name == null) {
|
|
|
|
name = jid.split("@")[0];
|
|
|
|
}
|
|
|
|
contact = new Contact(account, name, jid, null);
|
|
|
|
contact.parseSubscriptionFromElement(item);
|
|
|
|
databaseBackend.createContact(contact);
|
2014-02-19 00:35:23 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (subscription.equals("remove")) {
|
|
|
|
databaseBackend.deleteContact(contact);
|
2014-02-20 16:00:50 +00:00
|
|
|
replaceContactInConversation(contact.getJid(), null);
|
2014-02-19 00:35:23 +00:00
|
|
|
} else {
|
2014-02-21 20:35:23 +00:00
|
|
|
contact.parseSubscriptionFromElement(item);
|
2014-02-19 00:35:23 +00:00
|
|
|
databaseBackend.updateContact(contact);
|
2014-02-23 20:33:37 +00:00
|
|
|
replaceContactInConversation(contact.getJid(), contact);
|
2014-02-19 00:35:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-20 16:00:50 +00:00
|
|
|
private void replaceContactInConversation(String jid, Contact contact) {
|
2014-02-13 22:40:08 +00:00
|
|
|
List<Conversation> conversations = getConversations();
|
2014-02-19 00:35:23 +00:00
|
|
|
for (int i = 0; i < conversations.size(); ++i) {
|
2014-02-20 16:00:50 +00:00
|
|
|
if ((conversations.get(i).getContactJid().equals(jid))) {
|
2014-02-13 22:40:08 +00:00
|
|
|
conversations.get(i).setContact(contact);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-01-24 01:04:05 +00:00
|
|
|
|
2014-02-03 17:38:47 +00:00
|
|
|
public class XmppConnectionBinder extends Binder {
|
|
|
|
public XmppConnectionService getService() {
|
|
|
|
return XmppConnectionService.this;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
|
|
|
for (Account account : accounts) {
|
2014-02-13 22:40:08 +00:00
|
|
|
if (account.getXmppConnection() == null) {
|
2014-02-04 20:44:16 +00:00
|
|
|
if (!account.isOptionSet(Account.OPTION_DISABLED)) {
|
2014-02-13 22:40:08 +00:00
|
|
|
account.setXmppConnection(this.createConnection(account));
|
2014-02-04 20:44:16 +00:00
|
|
|
}
|
2014-02-03 17:38:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return START_STICKY;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onCreate() {
|
|
|
|
databaseBackend = DatabaseBackend.getInstance(getApplicationContext());
|
|
|
|
this.accounts = databaseBackend.getAccounts();
|
2014-02-11 22:55:03 +00:00
|
|
|
|
|
|
|
getContentResolver().registerContentObserver(
|
|
|
|
ContactsContract.Contacts.CONTENT_URI, true, contactObserver);
|
2014-02-27 23:22:56 +00:00
|
|
|
this.pgpServiceConnection = new OpenPgpServiceConnection(
|
|
|
|
getApplicationContext(), "org.sufficientlysecure.keychain");
|
|
|
|
this.pgpServiceConnection.bindToService();
|
2014-02-03 17:38:47 +00:00
|
|
|
}
|
2014-02-05 21:33:39 +00:00
|
|
|
|
2014-02-13 22:40:08 +00:00
|
|
|
@Override
|
|
|
|
public void onDestroy() {
|
|
|
|
super.onDestroy();
|
|
|
|
for (Account account : accounts) {
|
|
|
|
if (account.getXmppConnection() != null) {
|
|
|
|
disconnect(account);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-04 14:09:50 +00:00
|
|
|
public XmppConnection createConnection(Account account) {
|
|
|
|
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
|
|
|
|
XmppConnection connection = new XmppConnection(account, pm);
|
2014-02-05 21:33:39 +00:00
|
|
|
connection.setOnMessagePacketReceivedListener(this.messageListener);
|
|
|
|
connection.setOnStatusChangedListener(this.statusListener);
|
2014-02-07 01:57:36 +00:00
|
|
|
connection.setOnPresencePacketReceivedListener(this.presenceListener);
|
2014-02-19 00:35:23 +00:00
|
|
|
connection
|
|
|
|
.setOnUnregisteredIqPacketReceivedListener(this.unknownIqListener);
|
2014-02-04 14:09:50 +00:00
|
|
|
Thread thread = new Thread(connection);
|
|
|
|
thread.start();
|
|
|
|
return connection;
|
|
|
|
}
|
2014-02-19 00:35:23 +00:00
|
|
|
|
2014-02-27 23:22:56 +00:00
|
|
|
public void sendMessage(Message message, String presence) {
|
|
|
|
Account account = message.getConversation().getAccount();
|
2014-02-13 22:40:08 +00:00
|
|
|
Conversation conv = message.getConversation();
|
|
|
|
boolean saveInDb = false;
|
|
|
|
boolean addToConversation = false;
|
2014-02-11 22:55:03 +00:00
|
|
|
if (account.getStatus() == Account.STATUS_ONLINE) {
|
2014-02-13 22:40:08 +00:00
|
|
|
MessagePacket packet;
|
|
|
|
if (message.getEncryption() == Message.ENCRYPTION_OTR) {
|
2014-02-16 15:32:15 +00:00
|
|
|
if (!conv.hasValidOtrSession()) {
|
2014-02-19 00:35:23 +00:00
|
|
|
// starting otr session. messages will be send later
|
2014-02-16 15:32:15 +00:00
|
|
|
conv.startOtrSession(getApplicationContext(), presence);
|
2014-02-19 00:35:23 +00:00
|
|
|
} else if (conv.getOtrSession().getSessionStatus() == SessionStatus.ENCRYPTED) {
|
|
|
|
// otr session aleary exists, creating message packet
|
|
|
|
// accordingly
|
2014-02-13 22:40:08 +00:00
|
|
|
packet = prepareMessagePacket(account, message,
|
|
|
|
conv.getOtrSession());
|
|
|
|
account.getXmppConnection().sendMessagePacket(packet);
|
|
|
|
message.setStatus(Message.STATUS_SEND);
|
|
|
|
}
|
|
|
|
saveInDb = true;
|
|
|
|
addToConversation = true;
|
2014-02-27 23:22:56 +00:00
|
|
|
} else if (message.getEncryption() == Message.ENCRYPTION_PGP) {
|
|
|
|
long keyId = message.getConversation().getContact()
|
|
|
|
.getPgpKeyId();
|
|
|
|
packet = new MessagePacket();
|
|
|
|
packet.setType(MessagePacket.TYPE_CHAT);
|
|
|
|
packet.setFrom(message.getConversation().getAccount()
|
|
|
|
.getFullJid());
|
|
|
|
packet.setTo(message.getCounterpart());
|
|
|
|
packet.setBody("This is an XEP-0027 encryted message");
|
|
|
|
Element x = new Element("x");
|
|
|
|
x.setAttribute("xmlns", "jabber:x:encrypted");
|
|
|
|
x.setContent(this.getPgpEngine().encrypt(keyId,
|
|
|
|
message.getBody()));
|
|
|
|
packet.addChild(x);
|
|
|
|
account.getXmppConnection().sendMessagePacket(packet);
|
|
|
|
message.setStatus(Message.STATUS_SEND);
|
|
|
|
message.setEncryption(Message.ENCRYPTION_DECRYPTED);
|
|
|
|
saveInDb = true;
|
|
|
|
addToConversation = true;
|
2014-02-13 22:40:08 +00:00
|
|
|
} else {
|
|
|
|
// don't encrypt
|
2014-02-11 22:55:03 +00:00
|
|
|
if (message.getConversation().getMode() == Conversation.MODE_SINGLE) {
|
2014-02-13 22:40:08 +00:00
|
|
|
message.setStatus(Message.STATUS_SEND);
|
|
|
|
saveInDb = true;
|
|
|
|
addToConversation = true;
|
2014-02-11 22:55:03 +00:00
|
|
|
}
|
2014-02-19 00:35:23 +00:00
|
|
|
|
2014-02-13 22:40:08 +00:00
|
|
|
packet = prepareMessagePacket(account, message, null);
|
|
|
|
account.getXmppConnection().sendMessagePacket(packet);
|
2014-02-11 22:55:03 +00:00
|
|
|
}
|
|
|
|
} else {
|
2014-02-13 22:40:08 +00:00
|
|
|
// account is offline
|
|
|
|
saveInDb = true;
|
|
|
|
addToConversation = true;
|
|
|
|
|
|
|
|
}
|
|
|
|
if (saveInDb) {
|
2014-02-09 00:00:23 +00:00
|
|
|
databaseBackend.createMessage(message);
|
2014-02-13 22:40:08 +00:00
|
|
|
}
|
|
|
|
if (addToConversation) {
|
|
|
|
conv.getMessages().add(message);
|
|
|
|
if (convChangedListener != null) {
|
2014-02-11 22:55:03 +00:00
|
|
|
convChangedListener.onConversationListChanged();
|
|
|
|
}
|
|
|
|
}
|
2014-02-13 22:40:08 +00:00
|
|
|
|
2014-02-11 22:55:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private void sendUnsendMessages(Conversation conversation) {
|
|
|
|
for (int i = 0; i < conversation.getMessages().size(); ++i) {
|
|
|
|
if (conversation.getMessages().get(i).getStatus() == Message.STATUS_UNSEND) {
|
2014-02-13 22:40:08 +00:00
|
|
|
Message message = conversation.getMessages().get(i);
|
2014-02-11 22:55:03 +00:00
|
|
|
MessagePacket packet = prepareMessagePacket(
|
2014-02-13 22:40:08 +00:00
|
|
|
conversation.getAccount(), message, null);
|
|
|
|
conversation.getAccount().getXmppConnection()
|
|
|
|
.sendMessagePacket(packet);
|
2014-02-11 22:55:03 +00:00
|
|
|
message.setStatus(Message.STATUS_SEND);
|
|
|
|
if (conversation.getMode() == Conversation.MODE_SINGLE) {
|
|
|
|
databaseBackend.updateMessage(message);
|
|
|
|
} else {
|
|
|
|
databaseBackend.deleteMessage(message);
|
|
|
|
conversation.getMessages().remove(i);
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
}
|
2014-02-09 00:00:23 +00:00
|
|
|
}
|
2014-02-11 22:55:03 +00:00
|
|
|
}
|
|
|
|
|
2014-02-19 00:35:23 +00:00
|
|
|
public MessagePacket prepareMessagePacket(Account account, Message message,
|
|
|
|
Session otrSession) {
|
2014-02-04 14:09:50 +00:00
|
|
|
MessagePacket packet = new MessagePacket();
|
2014-02-05 21:33:39 +00:00
|
|
|
if (message.getConversation().getMode() == Conversation.MODE_SINGLE) {
|
|
|
|
packet.setType(MessagePacket.TYPE_CHAT);
|
2014-02-13 22:40:08 +00:00
|
|
|
if (otrSession != null) {
|
|
|
|
try {
|
|
|
|
packet.setBody(otrSession.transformSending(message
|
|
|
|
.getBody()));
|
|
|
|
} catch (OtrException e) {
|
|
|
|
Log.d(LOGTAG,
|
|
|
|
account.getJid()
|
|
|
|
+ ": could not encrypt message to "
|
|
|
|
+ message.getCounterpart());
|
|
|
|
}
|
|
|
|
Element privateMarker = new Element("private");
|
|
|
|
privateMarker.setAttribute("xmlns", "urn:xmpp:carbons:2");
|
|
|
|
packet.addChild(privateMarker);
|
2014-02-19 00:35:23 +00:00
|
|
|
packet.setTo(otrSession.getSessionID().getAccountID() + "/"
|
|
|
|
+ otrSession.getSessionID().getUserID());
|
2014-02-13 22:40:08 +00:00
|
|
|
packet.setFrom(account.getFullJid());
|
|
|
|
} else {
|
|
|
|
packet.setBody(message.getBody());
|
|
|
|
packet.setTo(message.getCounterpart());
|
|
|
|
packet.setFrom(account.getJid());
|
|
|
|
}
|
2014-02-05 21:33:39 +00:00
|
|
|
} else if (message.getConversation().getMode() == Conversation.MODE_MULTI) {
|
|
|
|
packet.setType(MessagePacket.TYPE_GROUPCHAT);
|
2014-02-13 22:40:08 +00:00
|
|
|
packet.setBody(message.getBody());
|
|
|
|
packet.setTo(message.getCounterpart());
|
|
|
|
packet.setFrom(account.getJid());
|
2014-02-05 21:33:39 +00:00
|
|
|
}
|
2014-02-11 22:55:03 +00:00
|
|
|
return packet;
|
2014-02-03 17:38:47 +00:00
|
|
|
}
|
2014-02-08 23:47:11 +00:00
|
|
|
|
|
|
|
public void getRoster(Account account,
|
|
|
|
final OnRosterFetchedListener listener) {
|
2014-02-07 01:57:36 +00:00
|
|
|
List<Contact> contacts = databaseBackend.getContacts(account);
|
2014-02-08 23:47:11 +00:00
|
|
|
for (int i = 0; i < contacts.size(); ++i) {
|
2014-02-07 15:50:29 +00:00
|
|
|
contacts.get(i).setAccount(account);
|
|
|
|
}
|
2014-02-05 21:33:39 +00:00
|
|
|
if (listener != null) {
|
|
|
|
listener.onRosterFetched(contacts);
|
|
|
|
}
|
|
|
|
}
|
2014-02-03 17:38:47 +00:00
|
|
|
|
2014-02-05 21:33:39 +00:00
|
|
|
public void updateRoster(final Account account,
|
2014-02-03 17:38:47 +00:00
|
|
|
final OnRosterFetchedListener listener) {
|
2014-02-19 00:35:23 +00:00
|
|
|
IqPacket iqPacket = new IqPacket(IqPacket.TYPE_GET);
|
|
|
|
Element query = new Element("query");
|
|
|
|
query.setAttribute("xmlns", "jabber:iq:roster");
|
|
|
|
query.setAttribute("ver", account.getRosterVersion());
|
|
|
|
iqPacket.addChild(query);
|
|
|
|
account.getXmppConnection().sendIqPacket(iqPacket,
|
|
|
|
new OnIqPacketReceived() {
|
2014-02-05 21:33:39 +00:00
|
|
|
|
2014-02-10 02:34:00 +00:00
|
|
|
@Override
|
2014-02-19 00:35:23 +00:00
|
|
|
public void onIqPacketReceived(final Account account,
|
|
|
|
IqPacket packet) {
|
|
|
|
Element roster = packet.findChild("query");
|
|
|
|
if (roster != null) {
|
|
|
|
processRosterItems(account, roster);
|
2014-02-23 20:33:37 +00:00
|
|
|
StringBuilder mWhere = new StringBuilder();
|
|
|
|
mWhere.append("jid NOT IN(");
|
|
|
|
List<Element> items = roster.getChildren();
|
|
|
|
for (int i = 0; i < items.size(); ++i) {
|
|
|
|
mWhere.append(DatabaseUtils
|
|
|
|
.sqlEscapeString(items.get(i)
|
|
|
|
.getAttribute("jid")));
|
|
|
|
if (i != items.size() - 1) {
|
|
|
|
mWhere.append(",");
|
2014-02-19 00:35:23 +00:00
|
|
|
}
|
|
|
|
}
|
2014-02-23 20:33:37 +00:00
|
|
|
mWhere.append(") and accountUuid = \"");
|
|
|
|
mWhere.append(account.getUuid());
|
|
|
|
mWhere.append("\"");
|
|
|
|
List<Contact> contactsToDelete = databaseBackend
|
|
|
|
.getContats(mWhere.toString());
|
|
|
|
for (Contact contact : contactsToDelete) {
|
|
|
|
databaseBackend.deleteContact(contact);
|
|
|
|
replaceContactInConversation(contact.getJid(),
|
|
|
|
null);
|
2014-02-19 00:35:23 +00:00
|
|
|
}
|
2014-02-23 20:33:37 +00:00
|
|
|
|
2014-02-19 00:35:23 +00:00
|
|
|
}
|
2014-02-23 20:33:37 +00:00
|
|
|
mergePhoneContactsWithRoster(new OnPhoneContactsMerged() {
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void phoneContactsMerged() {
|
|
|
|
if (listener != null) {
|
|
|
|
getRoster(account, listener);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2014-02-10 02:34:00 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2014-02-23 20:33:37 +00:00
|
|
|
public void mergePhoneContactsWithRoster(
|
|
|
|
final OnPhoneContactsMerged listener) {
|
2014-02-19 00:35:23 +00:00
|
|
|
PhoneHelper.loadPhoneContacts(getApplicationContext(),
|
2014-02-10 02:34:00 +00:00
|
|
|
new OnPhoneContactsLoadedListener() {
|
|
|
|
@Override
|
|
|
|
public void onPhoneContactsLoaded(
|
|
|
|
Hashtable<String, Bundle> phoneContacts) {
|
|
|
|
List<Contact> contacts = databaseBackend
|
|
|
|
.getContacts(null);
|
|
|
|
for (int i = 0; i < contacts.size(); ++i) {
|
|
|
|
Contact contact = contacts.get(i);
|
|
|
|
if (phoneContacts.containsKey(contact.getJid())) {
|
|
|
|
Bundle phoneContact = phoneContacts.get(contact
|
|
|
|
.getJid());
|
|
|
|
String systemAccount = phoneContact
|
|
|
|
.getInt("phoneid")
|
|
|
|
+ "#"
|
|
|
|
+ phoneContact.getString("lookup");
|
|
|
|
contact.setSystemAccount(systemAccount);
|
|
|
|
contact.setPhotoUri(phoneContact
|
|
|
|
.getString("photouri"));
|
|
|
|
contact.setDisplayName(phoneContact
|
|
|
|
.getString("displayname"));
|
|
|
|
databaseBackend.updateContact(contact);
|
2014-02-23 20:33:37 +00:00
|
|
|
replaceContactInConversation(contact.getJid(),
|
|
|
|
contact);
|
2014-02-10 02:34:00 +00:00
|
|
|
} else {
|
|
|
|
if ((contact.getSystemAccount() != null)
|
|
|
|
|| (contact.getProfilePhoto() != null)) {
|
|
|
|
contact.setSystemAccount(null);
|
|
|
|
contact.setPhotoUri(null);
|
|
|
|
databaseBackend.updateContact(contact);
|
2014-02-23 20:33:37 +00:00
|
|
|
replaceContactInConversation(
|
|
|
|
contact.getJid(), contact);
|
2014-02-05 21:33:39 +00:00
|
|
|
}
|
2014-02-04 14:09:50 +00:00
|
|
|
}
|
2014-02-10 02:34:00 +00:00
|
|
|
}
|
2014-02-23 20:33:37 +00:00
|
|
|
if (listener != null) {
|
2014-02-19 00:35:23 +00:00
|
|
|
listener.phoneContactsMerged();
|
|
|
|
}
|
2014-02-10 02:34:00 +00:00
|
|
|
}
|
|
|
|
});
|
2014-02-03 17:38:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public List<Conversation> getConversations() {
|
|
|
|
if (this.conversations == null) {
|
|
|
|
Hashtable<String, Account> accountLookupTable = new Hashtable<String, Account>();
|
|
|
|
for (Account account : this.accounts) {
|
|
|
|
accountLookupTable.put(account.getUuid(), account);
|
|
|
|
}
|
|
|
|
this.conversations = databaseBackend
|
|
|
|
.getConversations(Conversation.STATUS_AVAILABLE);
|
|
|
|
for (Conversation conv : this.conversations) {
|
2014-02-10 14:24:34 +00:00
|
|
|
Account account = accountLookupTable.get(conv.getAccountUuid());
|
|
|
|
conv.setAccount(account);
|
|
|
|
conv.setContact(findContact(account, conv.getContactJid()));
|
2014-02-10 21:45:59 +00:00
|
|
|
conv.setMessages(databaseBackend.getMessages(conv, 50));
|
2014-02-03 17:38:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return this.conversations;
|
|
|
|
}
|
|
|
|
|
|
|
|
public List<Account> getAccounts() {
|
|
|
|
return this.accounts;
|
|
|
|
}
|
2014-02-11 22:55:03 +00:00
|
|
|
|
2014-02-10 14:24:34 +00:00
|
|
|
public Contact findContact(Account account, String jid) {
|
2014-02-21 20:35:23 +00:00
|
|
|
Contact contact = databaseBackend.findContact(account, jid);
|
2014-02-23 20:33:37 +00:00
|
|
|
if (contact != null) {
|
2014-02-21 20:35:23 +00:00
|
|
|
contact.setAccount(account);
|
|
|
|
}
|
|
|
|
return contact;
|
2014-02-05 21:33:39 +00:00
|
|
|
}
|
2014-02-03 17:38:47 +00:00
|
|
|
|
2014-02-11 22:55:03 +00:00
|
|
|
public Conversation findOrCreateConversation(Account account, String jid,
|
|
|
|
boolean muc) {
|
2014-02-03 17:38:47 +00:00
|
|
|
for (Conversation conv : this.getConversations()) {
|
|
|
|
if ((conv.getAccount().equals(account))
|
2014-02-10 14:24:34 +00:00
|
|
|
&& (conv.getContactJid().equals(jid))) {
|
2014-02-03 17:38:47 +00:00
|
|
|
return conv;
|
|
|
|
}
|
|
|
|
}
|
2014-02-11 22:55:03 +00:00
|
|
|
Conversation conversation = databaseBackend.findConversation(account,
|
|
|
|
jid);
|
2014-02-03 17:38:47 +00:00
|
|
|
if (conversation != null) {
|
|
|
|
conversation.setStatus(Conversation.STATUS_AVAILABLE);
|
|
|
|
conversation.setAccount(account);
|
2014-02-07 15:50:29 +00:00
|
|
|
if (muc) {
|
|
|
|
conversation.setMode(Conversation.MODE_MULTI);
|
2014-02-08 23:47:11 +00:00
|
|
|
if (account.getStatus() == Account.STATUS_ONLINE) {
|
2014-02-13 22:40:08 +00:00
|
|
|
joinMuc(conversation);
|
2014-02-07 15:50:29 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
conversation.setMode(Conversation.MODE_SINGLE);
|
|
|
|
}
|
2014-02-03 17:38:47 +00:00
|
|
|
this.databaseBackend.updateConversation(conversation);
|
2014-02-19 00:35:23 +00:00
|
|
|
conversation.setContact(findContact(account,
|
|
|
|
conversation.getContactJid()));
|
2014-02-03 17:38:47 +00:00
|
|
|
} else {
|
2014-02-10 14:24:34 +00:00
|
|
|
String conversationName;
|
|
|
|
Contact contact = findContact(account, jid);
|
2014-02-11 22:55:03 +00:00
|
|
|
if (contact != null) {
|
2014-02-10 14:24:34 +00:00
|
|
|
conversationName = contact.getDisplayName();
|
|
|
|
} else {
|
|
|
|
conversationName = jid.split("@")[0];
|
|
|
|
}
|
2014-02-07 15:50:29 +00:00
|
|
|
if (muc) {
|
2014-02-11 22:55:03 +00:00
|
|
|
conversation = new Conversation(conversationName, account, jid,
|
2014-02-07 15:50:29 +00:00
|
|
|
Conversation.MODE_MULTI);
|
2014-02-08 23:47:11 +00:00
|
|
|
if (account.getStatus() == Account.STATUS_ONLINE) {
|
2014-02-13 22:40:08 +00:00
|
|
|
joinMuc(conversation);
|
2014-02-07 15:50:29 +00:00
|
|
|
}
|
|
|
|
} else {
|
2014-02-10 14:24:34 +00:00
|
|
|
conversation = new Conversation(conversationName, account, jid,
|
2014-02-07 15:50:29 +00:00
|
|
|
Conversation.MODE_SINGLE);
|
|
|
|
}
|
2014-02-10 14:24:34 +00:00
|
|
|
conversation.setContact(contact);
|
2014-02-03 17:38:47 +00:00
|
|
|
this.databaseBackend.createConversation(conversation);
|
|
|
|
}
|
|
|
|
this.conversations.add(conversation);
|
|
|
|
if (this.convChangedListener != null) {
|
|
|
|
this.convChangedListener.onConversationListChanged();
|
|
|
|
}
|
|
|
|
return conversation;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void archiveConversation(Conversation conversation) {
|
2014-02-13 22:40:08 +00:00
|
|
|
if (conversation.getMode() == Conversation.MODE_MULTI) {
|
|
|
|
leaveMuc(conversation);
|
|
|
|
} else {
|
|
|
|
try {
|
|
|
|
conversation.endOtrIfNeeded();
|
|
|
|
} catch (OtrException e) {
|
|
|
|
Log.d(LOGTAG,
|
|
|
|
"error ending otr session for "
|
|
|
|
+ conversation.getName());
|
|
|
|
}
|
|
|
|
}
|
2014-02-03 17:38:47 +00:00
|
|
|
this.databaseBackend.updateConversation(conversation);
|
|
|
|
this.conversations.remove(conversation);
|
|
|
|
if (this.convChangedListener != null) {
|
|
|
|
this.convChangedListener.onConversationListChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getConversationCount() {
|
|
|
|
return this.databaseBackend.getConversationCount();
|
|
|
|
}
|
2014-01-28 18:21:54 +00:00
|
|
|
|
|
|
|
public void createAccount(Account account) {
|
|
|
|
databaseBackend.createAccount(account);
|
2014-02-04 14:09:50 +00:00
|
|
|
this.accounts.add(account);
|
2014-02-13 22:40:08 +00:00
|
|
|
account.setXmppConnection(this.createConnection(account));
|
2014-02-05 21:33:39 +00:00
|
|
|
if (accountChangedListener != null)
|
|
|
|
accountChangedListener.onAccountListChangedListener();
|
2014-01-28 18:21:54 +00:00
|
|
|
}
|
2014-02-23 20:33:37 +00:00
|
|
|
|
2014-02-20 16:00:50 +00:00
|
|
|
public void deleteContact(Contact contact) {
|
|
|
|
IqPacket iq = new IqPacket(IqPacket.TYPE_SET);
|
|
|
|
Element query = new Element("query");
|
|
|
|
query.setAttribute("xmlns", "jabber:iq:roster");
|
|
|
|
Element item = new Element("item");
|
|
|
|
item.setAttribute("jid", contact.getJid());
|
|
|
|
item.setAttribute("subscription", "remove");
|
|
|
|
query.addChild(item);
|
|
|
|
iq.addChild(query);
|
|
|
|
contact.getAccount().getXmppConnection().sendIqPacket(iq, null);
|
|
|
|
replaceContactInConversation(contact.getJid(), null);
|
|
|
|
databaseBackend.deleteContact(contact);
|
|
|
|
}
|
2014-02-03 17:38:47 +00:00
|
|
|
|
2014-01-28 18:21:54 +00:00
|
|
|
public void updateAccount(Account account) {
|
|
|
|
databaseBackend.updateAccount(account);
|
2014-02-13 22:40:08 +00:00
|
|
|
if (account.getXmppConnection() != null) {
|
|
|
|
disconnect(account);
|
2014-02-04 14:09:50 +00:00
|
|
|
}
|
2014-02-04 20:44:16 +00:00
|
|
|
if (!account.isOptionSet(Account.OPTION_DISABLED)) {
|
2014-02-13 22:40:08 +00:00
|
|
|
account.setXmppConnection(this.createConnection(account));
|
2014-02-04 20:44:16 +00:00
|
|
|
}
|
2014-02-05 21:33:39 +00:00
|
|
|
if (accountChangedListener != null)
|
|
|
|
accountChangedListener.onAccountListChangedListener();
|
2014-01-28 18:21:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void deleteAccount(Account account) {
|
2014-02-05 21:33:39 +00:00
|
|
|
Log.d(LOGTAG, "called delete account");
|
2014-02-13 22:40:08 +00:00
|
|
|
if (account.getXmppConnection() != null) {
|
|
|
|
this.disconnect(account);
|
2014-02-04 14:09:50 +00:00
|
|
|
}
|
2014-01-28 18:21:54 +00:00
|
|
|
databaseBackend.deleteAccount(account);
|
2014-02-11 22:55:03 +00:00
|
|
|
this.accounts.remove(account);
|
2014-02-05 21:33:39 +00:00
|
|
|
if (accountChangedListener != null)
|
|
|
|
accountChangedListener.onAccountListChangedListener();
|
2014-01-28 18:21:54 +00:00
|
|
|
}
|
2014-02-03 17:38:47 +00:00
|
|
|
|
|
|
|
public void setOnConversationListChangedListener(
|
|
|
|
OnConversationListChangedListener listener) {
|
2014-02-01 14:07:20 +00:00
|
|
|
this.convChangedListener = listener;
|
|
|
|
}
|
2014-02-03 17:38:47 +00:00
|
|
|
|
2014-02-01 14:07:20 +00:00
|
|
|
public void removeOnConversationListChangedListener() {
|
|
|
|
this.convChangedListener = null;
|
|
|
|
}
|
2014-02-05 21:33:39 +00:00
|
|
|
|
|
|
|
public void setOnAccountListChangedListener(
|
|
|
|
OnAccountListChangedListener listener) {
|
2014-02-04 14:09:50 +00:00
|
|
|
this.accountChangedListener = listener;
|
|
|
|
}
|
2014-02-05 21:33:39 +00:00
|
|
|
|
2014-02-04 14:09:50 +00:00
|
|
|
public void removeOnAccountListChangedListener() {
|
|
|
|
this.accountChangedListener = null;
|
|
|
|
}
|
2014-02-05 21:33:39 +00:00
|
|
|
|
|
|
|
public void connectMultiModeConversations(Account account) {
|
|
|
|
List<Conversation> conversations = getConversations();
|
|
|
|
for (int i = 0; i < conversations.size(); i++) {
|
|
|
|
Conversation conversation = conversations.get(i);
|
|
|
|
if ((conversation.getMode() == Conversation.MODE_MULTI)
|
|
|
|
&& (conversation.getAccount() == account)) {
|
2014-02-13 22:40:08 +00:00
|
|
|
joinMuc(conversation);
|
2014-02-05 21:33:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-02-08 23:47:11 +00:00
|
|
|
|
2014-02-13 22:40:08 +00:00
|
|
|
public void joinMuc(Conversation conversation) {
|
2014-02-07 15:50:29 +00:00
|
|
|
String muc = conversation.getContactJid();
|
|
|
|
PresencePacket packet = new PresencePacket();
|
2014-02-13 22:40:08 +00:00
|
|
|
packet.setAttribute("to", muc + "/"
|
|
|
|
+ conversation.getAccount().getUsername());
|
2014-02-07 15:50:29 +00:00
|
|
|
Element x = new Element("x");
|
|
|
|
x.setAttribute("xmlns", "http://jabber.org/protocol/muc");
|
2014-02-11 22:55:03 +00:00
|
|
|
if (conversation.getMessages().size() != 0) {
|
2014-02-11 14:34:24 +00:00
|
|
|
Element history = new Element("history");
|
2014-02-16 15:32:15 +00:00
|
|
|
long lastMsgTime = conversation.getLatestMessage().getTimeSent();
|
2014-02-19 00:35:23 +00:00
|
|
|
long diff = (System.currentTimeMillis() - lastMsgTime) / 1000 - 1;
|
|
|
|
history.setAttribute("seconds", diff + "");
|
2014-02-11 14:34:24 +00:00
|
|
|
x.addChild(history);
|
|
|
|
}
|
2014-02-07 15:50:29 +00:00
|
|
|
packet.addChild(x);
|
2014-02-13 22:40:08 +00:00
|
|
|
conversation.getAccount().getXmppConnection()
|
|
|
|
.sendPresencePacket(packet);
|
2014-02-07 15:50:29 +00:00
|
|
|
}
|
2014-02-05 21:33:39 +00:00
|
|
|
|
2014-02-13 22:40:08 +00:00
|
|
|
public void leaveMuc(Conversation conversation) {
|
|
|
|
|
|
|
|
}
|
2014-02-05 21:33:39 +00:00
|
|
|
|
2014-02-13 22:40:08 +00:00
|
|
|
public void disconnect(Account account) {
|
|
|
|
List<Conversation> conversations = getConversations();
|
|
|
|
for (int i = 0; i < conversations.size(); i++) {
|
|
|
|
Conversation conversation = conversations.get(i);
|
|
|
|
if (conversation.getAccount() == account) {
|
|
|
|
if (conversation.getMode() == Conversation.MODE_MULTI) {
|
|
|
|
leaveMuc(conversation);
|
|
|
|
} else {
|
|
|
|
try {
|
|
|
|
conversation.endOtrIfNeeded();
|
|
|
|
} catch (OtrException e) {
|
|
|
|
Log.d(LOGTAG, "error ending otr session for "
|
|
|
|
+ conversation.getName());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
account.getXmppConnection().disconnect();
|
|
|
|
Log.d(LOGTAG, "disconnected account: " + account.getJid());
|
|
|
|
account.setXmppConnection(null);
|
2014-02-05 21:33:39 +00:00
|
|
|
}
|
2014-02-08 23:47:11 +00:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public IBinder onBind(Intent intent) {
|
|
|
|
return mBinder;
|
|
|
|
}
|
2014-02-16 15:32:15 +00:00
|
|
|
|
|
|
|
public void updateContact(Contact contact) {
|
|
|
|
databaseBackend.updateContact(contact);
|
|
|
|
}
|
2014-02-20 16:00:50 +00:00
|
|
|
|
2014-02-27 23:22:56 +00:00
|
|
|
public void updateMessage(Message message) {
|
|
|
|
databaseBackend.updateMessage(message);
|
|
|
|
}
|
|
|
|
|
2014-02-20 16:00:50 +00:00
|
|
|
public void createContact(Contact contact) {
|
2014-02-23 20:33:37 +00:00
|
|
|
SharedPreferences sharedPref = PreferenceManager
|
|
|
|
.getDefaultSharedPreferences(getApplicationContext());
|
|
|
|
boolean autoGrant = sharedPref.getBoolean("grant_new_contacts", true);
|
|
|
|
if (autoGrant) {
|
|
|
|
contact.setSubscriptionOption(Contact.Subscription.PREEMPTIVE_GRANT);
|
|
|
|
contact.setSubscriptionOption(Contact.Subscription.ASKING);
|
|
|
|
}
|
|
|
|
databaseBackend.createContact(contact);
|
2014-02-20 16:00:50 +00:00
|
|
|
IqPacket iq = new IqPacket(IqPacket.TYPE_SET);
|
|
|
|
Element query = new Element("query");
|
|
|
|
query.setAttribute("xmlns", "jabber:iq:roster");
|
|
|
|
Element item = new Element("item");
|
|
|
|
item.setAttribute("jid", contact.getJid());
|
|
|
|
item.setAttribute("name", contact.getJid());
|
|
|
|
query.addChild(item);
|
|
|
|
iq.addChild(query);
|
|
|
|
Account account = contact.getAccount();
|
|
|
|
account.getXmppConnection().sendIqPacket(iq, null);
|
2014-02-23 20:33:37 +00:00
|
|
|
if (autoGrant) {
|
|
|
|
requestPresenceUpdatesFrom(contact);
|
|
|
|
}
|
2014-02-20 16:00:50 +00:00
|
|
|
replaceContactInConversation(contact.getJid(), contact);
|
|
|
|
}
|
2014-02-21 20:35:23 +00:00
|
|
|
|
|
|
|
public void requestPresenceUpdatesFrom(Contact contact) {
|
2014-02-23 20:33:37 +00:00
|
|
|
// Requesting a Subscription type=subscribe
|
2014-02-21 20:35:23 +00:00
|
|
|
PresencePacket packet = new PresencePacket();
|
|
|
|
packet.setAttribute("type", "subscribe");
|
|
|
|
packet.setAttribute("to", contact.getJid());
|
2014-02-23 20:33:37 +00:00
|
|
|
packet.setAttribute("from", contact.getAccount().getJid());
|
|
|
|
Log.d(LOGTAG, packet.toString());
|
2014-02-21 20:35:23 +00:00
|
|
|
contact.getAccount().getXmppConnection().sendPresencePacket(packet);
|
|
|
|
}
|
2014-02-23 20:33:37 +00:00
|
|
|
|
2014-02-21 20:35:23 +00:00
|
|
|
public void stopPresenceUpdatesFrom(Contact contact) {
|
2014-02-23 20:33:37 +00:00
|
|
|
// Unsubscribing type='unsubscribe'
|
2014-02-21 20:35:23 +00:00
|
|
|
PresencePacket packet = new PresencePacket();
|
|
|
|
packet.setAttribute("type", "unsubscribe");
|
|
|
|
packet.setAttribute("to", contact.getJid());
|
2014-02-23 20:33:37 +00:00
|
|
|
packet.setAttribute("from", contact.getAccount().getJid());
|
|
|
|
Log.d(LOGTAG, packet.toString());
|
2014-02-21 20:35:23 +00:00
|
|
|
contact.getAccount().getXmppConnection().sendPresencePacket(packet);
|
|
|
|
}
|
2014-02-23 20:33:37 +00:00
|
|
|
|
2014-02-21 20:35:23 +00:00
|
|
|
public void stopPresenceUpdatesTo(Contact contact) {
|
2014-02-23 20:33:37 +00:00
|
|
|
// Canceling a Subscription type=unsubscribed
|
2014-02-21 20:35:23 +00:00
|
|
|
PresencePacket packet = new PresencePacket();
|
|
|
|
packet.setAttribute("type", "unsubscribed");
|
|
|
|
packet.setAttribute("to", contact.getJid());
|
2014-02-23 20:33:37 +00:00
|
|
|
packet.setAttribute("from", contact.getAccount().getJid());
|
|
|
|
Log.d(LOGTAG, packet.toString());
|
2014-02-21 20:35:23 +00:00
|
|
|
contact.getAccount().getXmppConnection().sendPresencePacket(packet);
|
|
|
|
}
|
2014-02-23 20:33:37 +00:00
|
|
|
|
2014-02-21 20:35:23 +00:00
|
|
|
public void sendPresenceUpdatesTo(Contact contact) {
|
2014-02-23 20:33:37 +00:00
|
|
|
// type='subscribed'
|
2014-02-21 20:35:23 +00:00
|
|
|
PresencePacket packet = new PresencePacket();
|
|
|
|
packet.setAttribute("type", "subscribed");
|
|
|
|
packet.setAttribute("to", contact.getJid());
|
2014-02-23 20:33:37 +00:00
|
|
|
packet.setAttribute("from", contact.getAccount().getJid());
|
|
|
|
Log.d(LOGTAG, packet.toString());
|
2014-02-21 20:35:23 +00:00
|
|
|
contact.getAccount().getXmppConnection().sendPresencePacket(packet);
|
|
|
|
}
|
2014-02-27 23:22:56 +00:00
|
|
|
|
|
|
|
public void sendPgpPresence(Account account, String signature) {
|
|
|
|
PresencePacket packet = new PresencePacket();
|
|
|
|
packet.setAttribute("from", account.getFullJid());
|
|
|
|
Element status = new Element("status");
|
|
|
|
status.setContent("online");
|
|
|
|
packet.addChild(status);
|
|
|
|
Element x = new Element("x");
|
|
|
|
x.setAttribute("xmlns", "jabber:x:signed");
|
|
|
|
x.setContent(signature);
|
|
|
|
packet.addChild(x);
|
|
|
|
account.getXmppConnection().sendPresencePacket(packet);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void generatePgpAnnouncement(Account account)
|
|
|
|
throws PgpEngine.UserInputRequiredException {
|
|
|
|
if (account.getStatus() == Account.STATUS_ONLINE) {
|
|
|
|
String signature = getPgpEngine().generateSignature("online");
|
|
|
|
account.setKey("pgp_signature", signature);
|
|
|
|
databaseBackend.updateAccount(account);
|
|
|
|
sendPgpPresence(account, signature);
|
|
|
|
}
|
|
|
|
}
|
2014-02-08 23:47:11 +00:00
|
|
|
}
|