net.ustyugov.jtalk.service.JTalkService.java Source code

Java tutorial

Introduction

Here is the source code for net.ustyugov.jtalk.service.JTalkService.java

Source

/*
 * Copyright (C) 2012, Igor Ustyugov <igor@ustyugov.net>
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License,
 * or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see http://www.gnu.org/licenses/
 */

package net.ustyugov.jtalk.service;

import java.io.File;
import java.io.FileOutputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

import android.app.Activity;
import android.net.sip.*;
import android.os.PowerManager;
import net.ustyugov.jtalk.*;
import net.ustyugov.jtalk.activity.RosterActivity;
import net.ustyugov.jtalk.db.AccountDbHelper;
import net.ustyugov.jtalk.db.JTalkProvider;
import net.ustyugov.jtalk.listener.*;
import net.ustyugov.jtalk.receivers.ChangeConnectionReceiver;
import net.ustyugov.jtalk.receivers.ScreenStateReceiver;
import net.ustyugov.jtalk.smiles.Smiles;

import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.PrivacyListManager;
import org.jivesoftware.smack.Roster;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.SmackConfiguration;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.PacketTypeFilter;
import org.jivesoftware.smack.packet.*;
import org.jivesoftware.smack.provider.PrivacyProvider;
import org.jivesoftware.smack.provider.ProviderManager;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smackx.*;
import org.jivesoftware.smackx.bookmark.BookmarkManager;
import org.jivesoftware.smackx.bookmark.BookmarkedConference;
import org.jivesoftware.smackx.commands.AdHocCommandManager;
import org.jivesoftware.smackx.filetransfer.FileTransferManager;
import org.jivesoftware.smackx.filetransfer.FileTransferRequest;
import org.jivesoftware.smackx.muc.DiscussionHistory;
import org.jivesoftware.smackx.muc.MultiUserChat;
import org.jivesoftware.smackx.note.Notes;
import org.jivesoftware.smackx.packet.*;
import org.jivesoftware.smackx.provider.*;
import org.jivesoftware.smackx.search.UserSearch;
import org.xbill.DNS.Credibility;
import org.xbill.DNS.Lookup;
import org.xbill.DNS.Record;
import org.xbill.DNS.SRVRecord;
import org.xbill.DNS.Type;

import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.ConnectivityManager;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.support.v4.app.NotificationCompat;
import android.util.Log;

import com.jtalk2.R;

public class JTalkService extends Service {
    private boolean started = false;
    private boolean connecting = false;
    private static JTalkService js = new JTalkService();
    private Smiles smiles;
    private List<String> collapsedGroups = new ArrayList<String>();
    private Hashtable<String, List<String>> activeChats = new Hashtable<String, List<String>>();
    private Hashtable<String, Integer> msgCounter = new Hashtable<String, Integer>();
    private List<MessageItem> unreadMessages = new ArrayList<MessageItem>();
    private Hashtable<String, List<String>> mucHighlightsList = new Hashtable<String, List<String>>();
    private Hashtable<String, String> passHash = new Hashtable<String, String>();
    private Hashtable<String, String> textHash = new Hashtable<String, String>();
    private Hashtable<String, String> stateHash = new Hashtable<String, String>();
    private Hashtable<String, Hashtable<String, String>> resourceHash = new Hashtable<String, Hashtable<String, String>>();
    private Hashtable<String, Integer> positionHash = new Hashtable<String, Integer>();
    private Hashtable<String, Conference> joinedConferences = new Hashtable<String, Conference>();
    private Hashtable<String, Hashtable<String, MultiUserChat>> conferences = new Hashtable<String, Hashtable<String, MultiUserChat>>();
    private Hashtable<String, Bitmap> avatarsHash = new Hashtable<String, Bitmap>();
    private Hashtable<String, Hashtable<String, Integer>> messagesCount = new Hashtable<String, Hashtable<String, Integer>>();
    private Hashtable<String, DataForm> formHash = new Hashtable<String, DataForm>();
    private Hashtable<String, XMPPConnection> connections = new Hashtable<String, XMPPConnection>();
    private Hashtable<String, VCard> vcards = new Hashtable<String, VCard>();
    private Hashtable<String, ConListener> conListeners = new Hashtable<String, ConListener>();
    private Hashtable<String, ConnectionTask> connectionTasks = new Hashtable<String, ConnectionTask>();
    private Hashtable<String, Timer> pingTimers = new Hashtable<String, Timer>();
    private Hashtable<String, SipManager> sipManagers = new Hashtable<String, SipManager>();
    private Hashtable<String, XmlListener> XmlListeners = new Hashtable<String, XmlListener>();
    private String currentJid = "me";
    private String sidebarMode = "users";
    private String globalState = "";
    private SharedPreferences prefs;
    //    private BroadcastReceiver updateReceiver;
    private ScreenStateReceiver screenStateReceiver;
    private ChangeConnectionReceiver connectionReceiver;
    private Hashtable<String, FileTransferManager> fileTransferManagers = new Hashtable<String, FileTransferManager>();
    private List<FileTransferRequest> incomingRequests = new ArrayList<FileTransferRequest>();
    private Timer autoStatusTimer = new Timer();
    private boolean autoStatus = false;
    private Presence oldPresence;
    private SipAudioCall call = null;

    private WifiManager.WifiLock wifiLock;
    private PowerManager.WakeLock wakeLock;

    private IconPicker iconPicker;

    private Hashtable<String, Hashtable<String, List<MessageItem>>> messages = new Hashtable<String, Hashtable<String, List<MessageItem>>>();

    public static JTalkService getInstance() {
        return js;
    }

    public Smiles getSmiles(Activity activity) {
        if (smiles != null)
            return smiles;
        else
            return new Smiles(activity);
    }

    public void removeSmiles() {
        smiles = null;
    }

    public void addPassword(String account, String password) {
        passHash.put(account, password);
    }

    public List<MessageItem> getMessageList(String account, String jid) {
        Hashtable<String, List<MessageItem>> hash = new Hashtable<String, List<MessageItem>>();
        if (messages.containsKey(account))
            hash = messages.get(account);

        if (!hash.containsKey(jid))
            return new ArrayList<MessageItem>();
        else
            return hash.get(jid);
    }

    public void setMessageList(String account, String jid, List<MessageItem> list) {
        Hashtable<String, List<MessageItem>> hash = new Hashtable<String, List<MessageItem>>();
        if (messages.containsKey(account))
            hash = messages.get(account);

        hash.put(jid, list);
        messages.put(account, hash);
    }

    public XmlListener getXmlListener(String account) {
        if (XmlListeners.containsKey(account)) {
            return XmlListeners.get(account);
        } else
            return null;
    }

    private void removeConnectionListener(String account) {
        if (conListeners.containsKey(account)) {
            ConListener listener = conListeners.remove(account);
            XMPPConnection connection = getConnection(account);
            if (connection != null)
                connection.removeConnectionListener(listener);
        }
    }

    private void addConnectionListener(String account, XMPPConnection connection) {
        if (!conListeners.containsKey(account)) {
            ConListener listener = new ConListener(this, account);
            connection.addConnectionListener(listener);
            conListeners.put(account, listener);
        }
    }

    public ConListener getConnectionListener(String account) {
        if (conListeners.containsKey(account))
            return conListeners.get(account);
        else
            return null;
    }

    public Collection<XMPPConnection> getAllConnections() {
        return connections.values();
    }

    public void setState(String account, String state) {
        if (state == null)
            state = "null";
        if (account != null)
            stateHash.put(account, state);
    }

    public String getState(String account) {
        if (stateHash.containsKey(account))
            return stateHash.get(account);
        else {
            if (isAuthenticated(account)) {
                return getStatus(account, account);
            } else
                return getString(R.string.Disconnect);
        }
    }

    public void addConnection(String account, XMPPConnection connection) {
        connections.put(account, connection);
    }

    public XMPPConnection getConnection(String account) {
        if (account != null && connections.containsKey(account))
            return connections.get(account);
        else
            return null;
    }

    public int getMessagesCount() {
        int result = 0;
        for (Hashtable<String, Integer> hash : messagesCount.values()) {
            for (Integer i : hash.values()) {
                result = result + i;
            }
        }
        return result;
    }

    public int getMessagesCount(String account, String jid) {
        if (messagesCount.containsKey(account)) {
            Hashtable<String, Integer> hash = messagesCount.get(account);
            if (hash.containsKey(jid))
                return hash.get(jid);
        }
        return 0;
    }

    public void addMessagesCount(String account, String jid) {
        Hashtable<String, Integer> hash = new Hashtable<String, Integer>();
        if (messagesCount.containsKey(account)) {
            hash = messagesCount.get(account);
            hash.put(jid, getMessagesCount(account, jid) + 1);
        } else {
            hash.put(jid, 1);
        }
        messagesCount.put(account, hash);
        //       updateWidget();
    }

    public void removeMessagesCount(String account, String jid) {
        if (messagesCount.containsKey(account)) {
            Hashtable<String, Integer> hash = messagesCount.get(account);
            if (hash.containsKey(jid))
                hash.remove(jid);
        }
        //       updateWidget();
    }

    public void removeMessagesCountForJid(String account, String jid) {
        if (messagesCount.containsKey(account)) {
            Hashtable<String, Integer> hash = messagesCount.get(account);
            Enumeration<String> keys = hash.keys();
            while (keys.hasMoreElements()) {
                String key = keys.nextElement();
                if (key.startsWith(jid)) {
                    hash.remove(key);
                }
            }
        }
        //       updateWidget();
    }

    public void addDataForm(String id, DataForm form) {
        formHash.put(id, form);
    }

    public DataForm getDataForm(String id) {
        if (formHash.containsKey(id))
            return formHash.remove(id);
        else
            return null;
    }

    public void addLastPosition(String jid, int position) {
        positionHash.put(jid, position);
    }

    public int getLastPosition(String jid) {
        if (positionHash.containsKey(jid))
            return positionHash.remove(jid);
        else
            return -1;
    }

    public void addSipManager(String account, SipManager manager) {
        sipManagers.put(account, manager);
    }

    public SipManager getSipManager(String account) {
        if (sipManagers.containsKey(account))
            return sipManagers.get(account);
        else
            return null;
    }

    public void setIncomingCall(SipAudioCall call) {
        this.call = call;
    }

    public SipAudioCall getIncomingCall() {
        return this.call;
    }

    public IconPicker getIconPicker() {
        return iconPicker;
    }

    public String getSidebarMode() {
        return sidebarMode;
    }

    public void setSidebarMode(String mode) {
        this.sidebarMode = mode;
    }

    public void setAutoStatus(boolean auto) {
        this.autoStatus = auto;
    }

    public boolean getAutoStatus() {
        return autoStatus;
    }

    public void setOldPresence(Presence presence) {
        this.oldPresence = presence;
    }

    public Presence getOldPresence() {
        return oldPresence;
    }

    public FileTransferManager getFileTransferManager(String account) {
        if (fileTransferManagers.containsKey(account))
            return fileTransferManagers.get(account);
        else
            return null;
    }

    public void addIncomingFileRequest(FileTransferRequest request) {
        incomingRequests.add(request);
    }

    public FileTransferRequest getIncomingRequest() {
        if (incomingRequests.size() > 0)
            return incomingRequests.remove(0);
        else
            return null;
    }

    public void setCurrentJid(String jid) {
        this.currentJid = jid;
    }

    public String getCurrentJid() {
        return currentJid;
    }

    public String getGlobalState() {
        return globalState;
    }

    public void setGlobalState(String s) {
        globalState = s;
    }

    public Roster getRoster(String account) {
        if (connections != null && account != null && connections.containsKey(account)) {
            XMPPConnection connection = connections.get(account);
            if (connection != null)
                return connection.getRoster();
            else
                return null;
        } else
            return null;
    }

    public List<String> getCollapsedGroups() {
        return collapsedGroups;
    }

    public Hashtable<String, Hashtable<String, MultiUserChat>> getConferences() {
        return conferences;
    }

    public Hashtable<String, MultiUserChat> getConferencesHash(String account) {
        if (conferences.containsKey(account))
            return conferences.get(account);
        else {
            conferences.put(account, new Hashtable<String, MultiUserChat>());
            return conferences.get(account);
        }
    }

    public Hashtable<String, Conference> getJoinedConferences() {
        return joinedConferences;
    }

    public Hashtable<String, Bitmap> getAvatarsHash() {
        return avatarsHash;
    }

    public void addUnreadMessage(MessageItem item) {
        String account = item.getAccount();
        String jid = item.getJid();
        if (!getConferencesHash(account).containsKey(jid)
                && !getConferencesHash(account).containsKey(StringUtils.parseBareAddress(jid)))
            jid = StringUtils.parseBareAddress(jid);

        for (MessageItem message : unreadMessages) {
            if (message.getAccount().equals(account)) {
                String j = StringUtils.parseBareAddress(message.getJid());
                if (j.equals(jid))
                    return;
            }
        }

        unreadMessages.add(item);
    }

    public MessageItem getUnreadMessage() {
        if (!unreadMessages.isEmpty())
            return unreadMessages.remove(0);
        else
            return null;
    }

    public void removeUnreadMesage(String account, String jid) {
        if (!getConferencesHash(account).containsKey(jid)
                && !getConferencesHash(account).containsKey(StringUtils.parseBareAddress(jid)))
            jid = StringUtils.parseBareAddress(jid);

        for (MessageItem i : unreadMessages) {
            if (i.getAccount().equals(account)) {
                String j = i.getJid();
                if (j.startsWith(jid)) {
                    unreadMessages.remove(i);
                    return;
                }
            }
        }
    }

    public List<MessageItem> getUnreadMessages() {
        return unreadMessages;
    }

    public boolean isHighlight(String account, String jid) {
        if (!mucHighlightsList.containsKey(account))
            return false;
        List<String> list = mucHighlightsList.get(account);
        return list.contains(jid);
    }

    public void removeHighlight(String account, String jid) {
        if (!mucHighlightsList.containsKey(account))
            return;
        List<String> list = mucHighlightsList.get(account);
        if (list.contains(jid))
            list.remove(jid);
        mucHighlightsList.put(account, list);
    }

    public void addHighlight(String account, String jid) {
        List<String> list = new ArrayList<String>();
        if (mucHighlightsList.containsKey(account)) {
            list = mucHighlightsList.get(account);
            if (!list.contains(jid))
                list.add(jid);
        } else {
            list.add(jid);
        }
        mucHighlightsList.put(account, list);
    }

    public void addActiveChat(String account, String jid) {
        if (getConferencesHash(account).containsKey(jid))
            return;
        if (activeChats.containsKey(account)) {
            List<String> chats = activeChats.get(account);
            if (!chats.contains(jid))
                chats.add(jid);
        } else {
            List<String> chats = new ArrayList<String>();
            chats.add(jid);
            activeChats.put(account, chats);
        }
    }

    public void removeActiveChat(String account, String jid) {
        if (activeChats.containsKey(account)) {
            List<String> chats = activeChats.remove(account);
            while (chats.contains(jid))
                chats.remove(jid);
            activeChats.put(account, chats);
        }
    }

    public List<String> getActiveChats(String account) {
        if (activeChats.containsKey(account))
            return activeChats.get(account);
        else
            return new ArrayList<String>();
    }

    public List<String> getPrivateMessages(String account) {
        List<String> list = new ArrayList<String>();
        for (String jid : getActiveChats(account)) {
            if (getConferencesHash(account).containsKey(StringUtils.parseBareAddress(jid))
                    && !getConferencesHash(account).containsKey(jid)) {
                list.add(jid);
            }
        }
        return list;
    }

    public void setResource(String account, String jid, String resource) {
        Hashtable<String, String> hash = new Hashtable<String, String>();
        hash.put(jid, resource);
        resourceHash.put(account, hash);
    }

    public String getResource(String account, String jid) {
        if (resourceHash.containsKey(account)) {
            Hashtable<String, String> hash = resourceHash.get(account);
            if (hash.containsKey(jid))
                return hash.get(jid);
        }
        return "";
    }

    public void setText(String jid, String text) {
        if (text != null)
            textHash.put(jid, text);
    }

    public String getText(String jid) {
        if (textHash.containsKey(jid))
            return textHash.get(jid);
        else
            return "";
    }

    public VCard getVCard(String account) {
        if (vcards.containsKey(account))
            return vcards.get(account);
        else
            return null;
    }

    public void setVCard(final String account, VCard vcard) {
        if (vcard != null) {
            vcards.put(account, vcard);
            final byte[] buffer = vcard.getAvatar();
            if (buffer != null) {
                new Thread() {
                    public void run() {
                        try {
                            File f = new File(Constants.PATH);
                            f.mkdirs();
                            FileOutputStream fos = new FileOutputStream(Constants.PATH + "/" + account);
                            fos.write(buffer);
                            fos.close();
                        } catch (Throwable ignored) {
                        }
                    }
                }.start();
            }
            Intent intent = new Intent(Constants.UPDATE);
            sendBroadcast(intent);
        }
    }

    public Presence getPresence(String account, String user) {
        Presence unavailable = new Presence(Presence.Type.unavailable);
        if (connections.containsKey(account)) {
            if (!connections.get(account).isAuthenticated())
                return unavailable;

            if (StringUtils.parseResource(user).length() > 0) {
                String bareJid = StringUtils.parseBareAddress(user);
                if (getConferencesHash(account).containsKey(bareJid)) {
                    Presence p = getConferencesHash(account).get(bareJid).getOccupantPresence(user);
                    if (p != null)
                        return p;
                    else
                        return unavailable;
                } else {
                    Presence p = getRoster(account).getPresenceResource(user);
                    if (p != null)
                        return p;
                    else
                        return unavailable;
                }
            } else {
                Iterator<Presence> it = getRoster(account).getPresences(user);
                if (it.hasNext()) {
                    return it.next();
                } else {
                    return unavailable;
                }
            }
        }
        return unavailable;
    }

    public Presence.Type getType(String account, String user) {
        if (connections.containsKey(account)) {
            if (StringUtils.parseResource(user).length() > 0) {
                String g = StringUtils.parseBareAddress(user);
                if (getConferencesHash(account).containsKey(g)) {
                    Presence p = getConferencesHash(account).get(g).getOccupantPresence(user);
                    if (p != null)
                        return p.getType();
                    else
                        return Presence.Type.unavailable;
                } else {
                    Presence p = getRoster(account).getPresenceResource(user);
                    if (p != null)
                        return p.getType();
                    else
                        return Presence.Type.unavailable;
                }
            } else {
                Presence p = getRoster(account).getPresence(user);
                if (p != null)
                    return p.getType();
                else
                    return Presence.Type.unavailable;
            }
        }
        return Presence.Type.unavailable;
    }

    public Presence.Mode getMode(String account, String user) {
        if (connections.containsKey(account)) {
            if (StringUtils.parseResource(user).length() > 0) {
                String g = StringUtils.parseBareAddress(user);
                if (getConferencesHash(account).containsKey(g)) {
                    Presence p = getConferencesHash(account).get(g).getOccupantPresence(user);
                    if (p != null) {
                        Presence.Mode m = p.getMode();
                        if (m == null)
                            return Presence.Mode.available;
                        else
                            return m;
                    } else
                        return Presence.Mode.available;
                } else {
                    Presence p = getRoster(account).getPresenceResource(user);
                    if (p != null) {
                        Presence.Mode m = p.getMode();
                        if (m == null)
                            return Presence.Mode.available;
                        else
                            return m;
                    } else
                        return Presence.Mode.available;
                }
            }

            Iterator<Presence> it = getRoster(account).getPresences(user);
            if (it.hasNext()) {
                Presence presence = it.next();
                if (presence.getType() != Presence.Type.unavailable)
                    return presence.getMode();
                else
                    return Presence.Mode.available;
            }
        }
        return Presence.Mode.available;
    }

    public String getStatus(String account, String user) {
        if (connections.containsKey(account)) {
            if (StringUtils.parseResource(user).length() > 0) {
                String g = StringUtils.parseBareAddress(user);
                if (getConferencesHash(account).containsKey(g)) {
                    Presence p = getConferencesHash(account).get(g).getOccupantPresence(user);
                    if (p != null) {
                        String s = p.getStatus();
                        if (s == null)
                            return "";
                        else
                            return s;
                    } else
                        return "";
                } else {
                    Roster roster = getRoster(account);
                    if (roster != null) {
                        Presence p = getRoster(account).getPresenceResource(user);
                        if (p != null) {
                            String s = p.getStatus();
                            if (s == null)
                                return "";
                            else
                                return s;
                        } else
                            return "";
                    } else
                        return "";
                }
            }

            Roster roster = getRoster(account);
            if (roster != null) {
                Iterator<Presence> it = roster.getPresences(user);
                while (it.hasNext()) {
                    Presence presence = it.next();
                    if (presence.getType() != Presence.Type.unavailable)
                        if (presence.getStatus() == null)
                            return "";
                        else
                            return presence.getStatus();
                }
            }
        }
        return "";
    }

    public String getNode(String account, String user) {
        Roster roster = getRoster(account);
        if (roster == null)
            return null;

        if (connections.containsKey(account)) {
            if (StringUtils.parseResource(user).length() > 0) {
                String g = StringUtils.parseBareAddress(user);
                if (getConferencesHash(account).containsKey(g)) {
                    Presence p = getConferencesHash(account).get(g).getOccupantPresence(user);
                    if (p != null) {
                        CapsExtension caps = (CapsExtension) p.getExtension(CapsExtension.NODE_NAME,
                                CapsExtension.XMLNS);
                        if (caps != null)
                            return caps.getNode();
                        else
                            return null;
                    } else
                        return null;
                } else {
                    Presence p = roster.getPresenceResource(user);
                    if (p != null) {
                        CapsExtension caps = (CapsExtension) p.getExtension(CapsExtension.NODE_NAME,
                                CapsExtension.XMLNS);
                        if (caps != null)
                            return caps.getNode();
                        else
                            return null;
                    }
                }
            }

            List<String> list = new ArrayList<String>();
            Iterator<Presence> it = roster.getPresences(user);
            while (it.hasNext()) {
                Presence presence = it.next();
                if (presence.getType() != Presence.Type.unavailable) {
                    CapsExtension caps = (CapsExtension) presence.getExtension(CapsExtension.NODE_NAME,
                            CapsExtension.XMLNS);
                    if (caps != null)
                        list.add(caps.getNode());
                }
            }

            if (!list.isEmpty())
                return list.get(0);
            else
                return null;
        }
        return null;
    }

    public void resetTimer() {
        if (prefs != null) {
            if (prefs.getBoolean("AutoStatusOnDisplay", false))
                return;

            autoStatusTimer.purge();
            autoStatusTimer.cancel();
            if (autoStatus) {
                autoStatus = false;

                Enumeration<String> e = connections.keys();
                while (e.hasMoreElements()) {
                    sendPresence(e.nextElement(), oldPresence.getStatus(), oldPresence.getMode().name(),
                            oldPresence.getPriority());
                }
            }
            autoStatusTimer = new Timer();
            int delayAway = 10;
            int delayXa = 20;
            try {
                delayAway = Integer.parseInt(prefs.getString("AutoStatusAway", "10"));
                delayXa = Integer.parseInt(prefs.getString("AutoStatusXa", "20"));
            } catch (NumberFormatException ignored) {
            }
            if (delayAway < 1)
                delayAway = 1;
            if (delayXa < delayAway)
                delayXa = delayAway + 1;
            autoStatusTimer.schedule(new AutoAwayStatus(), delayAway * 60000);
            autoStatusTimer.schedule(new AutoXaStatus(), delayXa * 60000);
        }
    }

    //    public void updateWidget() {
    //      int   count = 0;
    //      
    //      String[] statusArray = getResources().getStringArray(R.array.statusArray);   
    //      String status = getString(R.string.NotConnected);
    //      if (isAuthenticated()) {
    //         status = statusArray[prefs.getInt("currentSelection", 0)];
    //         count = getMessagesCount();
    //      }
    //      
    //      ContentValues values = new ContentValues();
    //        values.put(WidgetDbHelper.MODE, status);
    //        values.put(WidgetDbHelper.COUNTER, count + "");
    //        getContentResolver().update(JTalkProvider.WIDGET_URI, values, null, null);
    //        
    //        sendBroadcast(new Intent(Constants.WIDGET_UPDATE));
    //    }

    @Override
    public void onCreate() {
        configure();
        js = this;
        prefs = PreferenceManager.getDefaultSharedPreferences(this);
        iconPicker = new IconPicker(this);

        //        updateReceiver = new BroadcastReceiver() {
        //         @Override
        //         public void onReceive(Context arg0, Intent arg1) {
        //            updateWidget();
        //         }
        //        };
        //        registerReceiver(updateReceiver, new IntentFilter(Constants.UPDATE));

        connectionReceiver = new ChangeConnectionReceiver();
        registerReceiver(connectionReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));

        screenStateReceiver = new ScreenStateReceiver();
        registerReceiver(new ScreenStateReceiver(), new IntentFilter(Intent.ACTION_SCREEN_ON));
        registerReceiver(new ScreenStateReceiver(), new IntentFilter(Intent.ACTION_SCREEN_OFF));

        Intent i = new Intent(this, RosterActivity.class);
        i.setAction(Intent.ACTION_MAIN);
        i.addCategory(Intent.CATEGORY_LAUNCHER);
        i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0, i, 0);

        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);
        mBuilder.setSmallIcon(R.drawable.stat_offline);
        mBuilder.setContentTitle(getString(R.string.app_name));
        mBuilder.setContentIntent(contentIntent);

        startForeground(Notify.NOTIFICATION, mBuilder.build());

        WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
        wifiLock = wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, "jTalk");
        PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
        wakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK, "jTalk");

        started = true;

        Cursor cursor = getContentResolver().query(JTalkProvider.ACCOUNT_URI, null,
                AccountDbHelper.ENABLED + " = '" + 1 + "'", null, null);
        if (cursor != null && cursor.getCount() > 0) {
            connect();
            cursor.close();
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onDestroy() {
        try {
            //          unregisterReceiver(updateReceiver);
            unregisterReceiver(connectionReceiver);
            unregisterReceiver(screenStateReceiver);
        } catch (Exception ignored) {
        }

        Notify.cancelAll(this);
        stopForeground(true);
        disconnect();
        clearAll();
        //        updateWidget();
        started = false;
    }

    public void disconnect() {
        if (!started)
            return;
        if (wifiLock != null && wifiLock.isHeld())
            wifiLock.release();
        if (wakeLock != null && wakeLock.isHeld())
            wakeLock.release();
        Collection<XMPPConnection> con = getAllConnections();
        for (XMPPConnection connection : con) {
            String account = StringUtils.parseBareAddress(connection.getUser());
            if (isAuthenticated(account)) {
                if (connectionTasks.containsKey(account)) {
                    connectionTasks.remove(account).cancel(true);
                }
                if (pingTimers.containsKey(account)) {
                    Timer timer = pingTimers.remove(account);
                    timer.cancel();
                    timer.purge();
                }
                removeConnectionListener(account);
                Presence presence = new Presence(Presence.Type.unavailable, "", 0, null);
                connection.disconnect(presence);

                try {
                    if (sipManagers.containsKey(account)) {
                        SipManager manager = sipManagers.get(account);
                        manager.close("sip:" + account);
                    }
                } catch (Exception ignored) {
                }
            } else if (connection.isConnected())
                connection.disconnect();
            setState(account, getString(R.string.Disconnect));
            connections.remove(account);
        }
    }

    public void disconnect(String account) {
        if (!started)
            return;
        Log.e("Disconnect", account);
        if (connections.containsKey(account)) {
            if (connectionTasks.containsKey(account)) {
                connectionTasks.remove(account).cancel(true);
            }

            if (pingTimers.containsKey(account)) {
                Timer timer = pingTimers.remove(account);
                timer.cancel();
                timer.purge();
            }

            try {
                removeConnectionListener(account);
                Presence presence = new Presence(Presence.Type.unavailable, "", 0, null);
                XMPPConnection connection = connections.remove(account);
                connection.disconnect(presence);
            } catch (Exception ignored) {
            }

            try {
                if (sipManagers.containsKey(account)) {
                    SipManager manager = sipManagers.get(account);
                    manager.close("sip:" + account);
                }
            } catch (Exception ignored) {
            }
            setState(account, getString(R.string.Disconnect));
        }
        sendBroadcast(new Intent(Constants.UPDATE));
    }

    public void reconnect() {
        if (!started)
            return;
        globalState = getResources().getString(R.string.Reconnecting) + "...";
        Intent i = new Intent(Constants.UPDATE);
        sendBroadcast(i);
        new Thread() {
            @Override
            public void run() {
                disconnect();
                connect();
            }
        }.start();
    }

    public void reconnect(final String account) {
        if (!started)
            return;
        setState(account, getResources().getString(R.string.Reconnecting) + "...");
        Intent i = new Intent(Constants.UPDATE);
        sendBroadcast(i);
        new Thread() {
            @Override
            public void run() {
                //             disconnect(account);
                try {
                    Thread.sleep(8000);
                } catch (Exception ignored) {
                }
                connect(account);
            }
        }.start();
    }

    public void connect() {
        if (!started)
            return;
        if (prefs.getBoolean("WifiLock", false))
            wifiLock.acquire();
        if (prefs.getBoolean("WakeLock", false))
            wakeLock.acquire();

        //      String text  = prefs.getString("currentStatus", "");
        String mode = prefs.getString("currentMode", "available");

        if (mode.equals("online")) {
            mode = "available";
            setPreference("currentSelection", 0);
        }

        if (!mode.equals("unavailable")) {
            //         globalState = getString(R.string.Connecting) + "...";
            Intent i = new Intent(Constants.UPDATE);
            sendBroadcast(i);

            Cursor cursor = getContentResolver().query(JTalkProvider.ACCOUNT_URI, null,
                    AccountDbHelper.ENABLED + " = '" + 1 + "'", null, null);
            if (cursor != null && cursor.getCount() > 0) {
                cursor.moveToFirst();
                do {
                    String username = cursor.getString(cursor.getColumnIndex(AccountDbHelper.JID)).trim();
                    String password = cursor.getString(cursor.getColumnIndex(AccountDbHelper.PASS)).trim();
                    int port = 5222;

                    if (password.isEmpty()) {
                        if (passHash.containsKey(username)) {
                            password = passHash.get(username);
                        } else {
                            Notify.passwordNotify(username);
                            continue;
                        }
                    }

                    try {
                        port = Integer.parseInt(cursor.getString(cursor.getColumnIndex(AccountDbHelper.PORT)));
                    } catch (NumberFormatException ignored) {
                    }

                    String resource = cursor.getString(cursor.getColumnIndex(AccountDbHelper.RESOURCE)).trim();
                    String service = cursor.getString(cursor.getColumnIndex(AccountDbHelper.SERVER));
                    String tls = cursor.getString(cursor.getColumnIndex(AccountDbHelper.TLS));
                    String sasl = cursor.getString(cursor.getColumnIndex(AccountDbHelper.SASL));
                    String compression = "1";
                    if (AccountDbHelper.VERSION > 3) {
                        compression = cursor.getString(cursor.getColumnIndex(AccountDbHelper.COMPRESSION));
                        if (compression == null)
                            compression = "1";
                    }

                    ConnectionTask task = new ConnectionTask(username, password, service, port, resource,
                            tls.equals("1"), sasl.equals("1"), compression.equals("1"));
                    if (connectionTasks.containsKey(username))
                        task = connectionTasks.get(username);
                    if (task.getStatus() != AsyncTask.Status.RUNNING
                            && task.getStatus() != AsyncTask.Status.FINISHED) {
                        task.execute();
                        connectionTasks.put(username, task);
                    }
                } while (cursor.moveToNext());
                cursor.close();
            }
        } else {
            //         globalState = text;
            Intent i = new Intent(Constants.UPDATE);
            sendBroadcast(i);
        }
    }

    public void connect(String account) {
        if (!started)
            return;
        Cursor cursor = getContentResolver().query(JTalkProvider.ACCOUNT_URI, null,
                AccountDbHelper.JID + " = '" + account + "'", null, null);
        if (cursor != null && cursor.getCount() > 0) {
            cursor.moveToFirst();

            String username = cursor.getString(cursor.getColumnIndex(AccountDbHelper.JID)).trim();
            String password = cursor.getString(cursor.getColumnIndex(AccountDbHelper.PASS)).trim();
            String resource = cursor.getString(cursor.getColumnIndex(AccountDbHelper.RESOURCE)).trim();
            String service = cursor.getString(cursor.getColumnIndex(AccountDbHelper.SERVER));
            String tls = cursor.getString(cursor.getColumnIndex(AccountDbHelper.TLS));
            String sasl = cursor.getString(cursor.getColumnIndex(AccountDbHelper.SASL));
            String compression = "1";
            if (AccountDbHelper.VERSION > 3) {
                compression = cursor.getString(cursor.getColumnIndex(AccountDbHelper.COMPRESSION));
                if (compression == null)
                    compression = "1";
            }

            int port = 5222;
            try {
                port = Integer.parseInt(cursor.getString(cursor.getColumnIndex(AccountDbHelper.PORT)));
            } catch (NumberFormatException ignored) {
            }

            if (password.isEmpty()) {
                if (passHash.containsKey(username)) {
                    password = passHash.get(username);
                }
            }

            ConnectionTask task = new ConnectionTask(username, password, service, port, resource, tls.equals("1"),
                    sasl.equals("1"), compression.equals("1"));
            task.execute();
            connectionTasks.put(username, task);
            cursor.close();
        }
    }

    public void joinRoom(final String account, final String group, final String nick, final String password) {
        if (connections.containsKey(account)) {
            final XMPPConnection connection = connections.get(account);
            if (!connection.isConnected() || !connection.isAuthenticated())
                return;

            new Thread() {
                @Override
                public void run() {
                    boolean reconnecting = false;
                    if (getConferencesHash(account).containsKey(group)) {
                        getConferencesHash(account).remove(group);
                        reconnecting = true;
                    }

                    MultiUserChat muc = new MultiUserChat(connection, group);
                    getConferencesHash(account).put(group, muc);

                    Presence presence = new Presence(Presence.Type.available);
                    presence.setStatus(prefs.getString("currentStatus", ""));
                    presence.setMode(Presence.Mode.valueOf(prefs.getString("currentMode", "available")));

                    DiscussionHistory h = new DiscussionHistory();
                    if (!reconnecting) {
                        try {
                            h.setMaxStanzas(Integer.parseInt(prefs.getString("MucHistorySize", "10")));
                        } catch (NumberFormatException nfe) {
                            h.setMaxStanzas(10);
                        }
                    } else
                        h.setMaxStanzas(0);

                    try {
                        writeMucMessage(account, group, nick, getString(R.string.YouJoin));

                        muc.addParticipantListener(new PacketListener() {
                            @Override
                            public void processPacket(Packet packet) {
                                Presence p = (Presence) packet;
                                if (p.isAvailable())
                                    sendBroadcast(new Intent(Constants.PRESENCE_CHANGED));
                            }
                        });
                        muc.join(nick, password, h, 10000, presence);
                    } catch (Exception e) {
                        Intent eIntent = new Intent(Constants.ERROR);
                        eIntent.putExtra("error", "[" + group + "] " + "Error: " + e.getLocalizedMessage());
                        sendBroadcast(eIntent);
                        return;
                    }

                    if (muc.isJoined()) {
                        Intent updateIntent = new Intent(Constants.PRESENCE_CHANGED);
                        updateIntent.putExtra("join", true);
                        updateIntent.putExtra("group", group);
                        sendBroadcast(updateIntent);

                        try {
                            Thread.sleep(10000);
                        } catch (Exception ignored) {
                        }
                        Conference conf = new Conference(group, nick, password);
                        joinedConferences.put(group, conf);
                        muc.addParticipantStatusListener(new MucParticipantStatusListener(account, group));

                        if (prefs.getBoolean("LoadAllAvatars", false)) {
                            Avatars.loadAllAvatars(connection, group);
                        }
                    }
                }
            }.start();
        }
    }

    public void leaveRoom(String account, String group) {
        if (getConferencesHash(account).containsKey(group)) {
            try {
                MultiUserChat muc = getConferencesHash(account).get(group);
                if (muc.isJoined()) {
                    writeMucMessage(account, group, muc.getNickname(), getString(R.string.YouLeave));
                    muc.leave();
                }
            } catch (IllegalStateException ignored) {
            }
            getConferencesHash(account).remove(group);
            setMessageList(account, group, new ArrayList<MessageItem>());
        }
        while (joinedConferences.containsKey(group))
            joinedConferences.remove(group);
        Intent updateIntent = new Intent(Constants.PRESENCE_CHANGED);
        sendBroadcast(updateIntent);
    }

    public void leaveAllRooms(String account) {
        Hashtable<String, MultiUserChat> hash = conferences.get(account);
        if (!hash.isEmpty()) {
            Enumeration<String> groups = hash.keys();
            while (groups.hasMoreElements()) {
                String group = groups.nextElement();
                MultiUserChat muc = hash.get(group);
                writeMucMessage(account, group, muc.getNickname(), getString(R.string.YouLeave));
                try {
                    if (muc.isJoined()) {
                        muc.leave();
                    }
                } catch (IllegalStateException ignored) {
                }
            }
        }
        Intent updateIntent = new Intent(Constants.PRESENCE_CHANGED);
        sendBroadcast(updateIntent);
    }

    public void addContact(String account, String jid, String name, String group) {
        try {
            Roster roster = getRoster(account);
            if (roster != null) {
                String[] groups = { group };
                roster.createEntry(jid, name, groups);
                if (roster.getSubscriptionMode() == Roster.SubscriptionMode.manual) {
                    Presence presence = new Presence(Presence.Type.subscribe);
                    presence.setTo(jid);
                    sendPacket(account, presence);
                }
            }
        } catch (XMPPException ignored) {
        }
    }

    public void removeContact(String account, String jid) {
        try {
            Roster roster = getRoster(account);
            if (roster != null) {
                RosterEntry entry = roster.getEntry(jid);
                if (entry != null)
                    roster.removeEntry(entry);
            }

            //          getContentResolver().delete(JTalkProvider.CONTENT_URI, "jid = '" + jid + "'", null);
            //             if (getMessagesHash(account).containsKey(jid)) {
            //                getMessagesHash(account).remove(jid);
            //             }
        } catch (XMPPException ignored) {
        }
    }

    public boolean isAuthenticated() {
        for (XMPPConnection connection : connections.values()) {
            if (connection.isAuthenticated())
                return true;
        }
        return false;
    }

    public boolean isAuthenticated(String account) {
        if (account != null && connections.containsKey(account)) {
            XMPPConnection connection = connections.get(account);
            return connection.getUser() != null && connection.isAuthenticated();
        } else
            return false;
    }

    public void sendMessage(String account, String user, String message) {
        String resource = StringUtils.parseResource(user);
        if (resource.length() > 0)
            sendMessage(account, StringUtils.parseBareAddress(user), message, resource);
        else
            sendMessage(account, user, message, null);
    }

    private void sendMessage(String account, String user, String message, String resource) {
        if (connections.containsKey(account)) {
            final XMPPConnection connection = connections.get(account);

            String mil = System.currentTimeMillis() + "";

            final Message msg;
            if (resource != null && resource.length() > 0) {
                msg = new Message(user + "/" + resource, Message.Type.chat);
                if (getConferencesHash(account).containsKey(user))
                    user = user + "/" + resource;
            } else
                msg = new Message(user, Message.Type.chat);
            msg.setPacketID(mil);
            msg.setBody(message);

            ReceiptExtension receipt = new ReceiptExtension(Receipt.request, "");
            msg.addExtension(receipt);

            Date date = new java.util.Date();
            String time = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss").format(date);

            MessageItem msgItem = new MessageItem(account, user);
            msgItem.setTime(time);
            msgItem.setName(getResources().getString(R.string.Me));
            msgItem.setId(mil);
            msgItem.setBody(message);
            msgItem.setReceived(false);

            MessageLog.writeMessage(account, user, msgItem);

            new Thread() {
                @Override
                public void run() {
                    if (connection != null && connection.getUser() != null) {
                        connection.sendPacket(msg);
                    }
                }
            }.start();
        }
    }

    public void editMessage(String account, final String user, final String id, final String message) {
        if (connections.containsKey(account)) {
            XMPPConnection connection = connections.get(account);
            String mil = System.currentTimeMillis() + "";

            final Message msg = new Message(user, Message.Type.chat);
            msg.setPacketID(mil);
            msg.setBody(message);

            ReplaceExtension replace = new ReplaceExtension(id);
            msg.addExtension(replace);

            if (connection != null && connection.getUser() != null) {
                connection.sendPacket(msg);
                MessageLog.editMessage(account, user, id, message);
            }
        }
    }

    public void sendPacket(String from, final Packet packet) {
        if (connections.containsKey(from)) {
            final XMPPConnection connection = connections.get(from);

            new Thread() {
                @Override
                public void run() {
                    if (connection != null && connection.getUser() != null) {
                        connection.sendPacket(packet);
                    }
                }
            }.start();
        }
    }

    public void sendReceivedPacket(final XMPPConnection connection, String user, String id) {
        ReceiptExtension extension = new ReceiptExtension(Receipt.received, id);
        final Message msg = new Message(user);
        msg.setPacketID(id);
        msg.addExtension(extension);
        new Thread() {
            @Override
            public void run() {
                if (connection != null && connection.getUser() != null) {
                    connection.sendPacket(msg);
                }
            }
        }.start();
    }

    public void setChatState(String account, String user, ChatState state) {
        if (connections.containsKey(account)) {
            final XMPPConnection connection = connections.get(account);

            if (user != null && getType(account, user) != Presence.Type.unavailable) {
                ChatStateExtension extension = new ChatStateExtension(state);
                final Message msg = new Message(user, Message.Type.chat);
                msg.addExtension(extension);
                new Thread() {
                    @Override
                    public void run() {
                        if (connection != null && connection.getUser() != null) {
                            connection.sendPacket(msg);
                        }
                    }
                }.start();
            }
        }
    }

    // Global status
    public void sendPresence(final String state, final String mode, final int priority) {
        for (final XMPPConnection connection : connections.values()) {
            new Thread() {
                public void run() {
                    //                   setPreference(JTalkService.this, "currentPriority", priority);
                    //                     setPreference(JTalkService.this, "currentMode", mode);
                    //                     setPreference(JTalkService.this, "currentStatus", state);
                    //                 setPreference(JTalkService.this, "currentSelection", getPosition(mode));
                    //                 setPreference(JTalkService.this, "lastStatus"+mode, state);

                    if (connection.isAuthenticated()) {
                        String account = StringUtils.parseBareAddress(connection.getUser());
                        if (!mode.equals("unavailable")) {
                            Presence presence = new Presence(Presence.Type.available);
                            if (state != null)
                                presence.setStatus(state);
                            presence.setMode(Presence.Mode.valueOf(mode));
                            presence.setPriority(priority);
                            connection.sendPacket(presence);

                            for (Hashtable<String, MultiUserChat> hash : conferences.values()) {
                                Enumeration<String> e = hash.keys();
                                while (e.hasMoreElements()) {
                                    try {
                                        MultiUserChat muc = hash.get(e.nextElement());
                                        if (muc.isJoined())
                                            muc.changeAvailabilityStatus(state, Presence.Mode.valueOf(mode));
                                    } catch (IllegalStateException ignored) {
                                    }
                                }
                            }
                            Notify.updateNotify();
                        } else {
                            removeConnectionListener(account);
                            Presence presence = new Presence(Presence.Type.unavailable, state, priority, null);
                            connection.disconnect(presence);
                            if (!isAuthenticated())
                                Notify.offlineNotify(JTalkService.this, state);
                        }
                    } else {
                        if (mode.equals("unavailable")) {
                            if (!isAuthenticated())
                                Notify.offlineNotify(JTalkService.this, state);
                        }
                    }

                    Intent i = new Intent(Constants.UPDATE);
                    sendBroadcast(i);
                }
            }.start();
        }
    }

    public void sendPresence(final String account, final String state, final String mode, final int priority) {
        if (connections.containsKey(account)) {
            new Thread() {
                public void run() {
                    XMPPConnection connection = connections.get(account);
                    if (connection.isAuthenticated()) {
                        String account = StringUtils.parseBareAddress(connection.getUser());
                        if (!mode.equals("unavailable")) {
                            Presence presence = new Presence(Presence.Type.available);
                            if (state != null)
                                presence.setStatus(state);
                            presence.setMode(Presence.Mode.valueOf(mode));
                            presence.setPriority(priority);
                            connection.sendPacket(presence);

                            Enumeration<String> e = getConferencesHash(account).keys();
                            while (e.hasMoreElements()) {
                                try {
                                    MultiUserChat muc = getConferencesHash(account).get(e.nextElement());
                                    if (muc.isJoined())
                                        muc.changeAvailabilityStatus(state, Presence.Mode.valueOf(mode));
                                } catch (IllegalStateException ignored) {
                                }
                            }

                            Notify.updateNotify();
                        } else {
                            removeConnectionListener(account);
                            Presence presence = new Presence(Presence.Type.unavailable, state, priority, null);
                            connection.disconnect(presence);
                            if (!isAuthenticated())
                                Notify.offlineNotify(JTalkService.this, state);
                        }
                    } else {
                        if (mode.equals("unavailable")) {
                            if (isAuthenticated())
                                Notify.offlineNotify(JTalkService.this, state);
                        }
                    }
                    setState(account, state);

                    Intent i = new Intent(Constants.UPDATE);
                    sendBroadcast(i);
                }
            }.start();
        }
    }

    public void sendPresenceTo(String account, final String to, final String state, final String mode,
            final int priority) {
        if (connections.containsKey(account)) {
            final XMPPConnection connection = connections.get(account);

            new Thread() {
                public void run() {
                    if (connection.getUser() != null) {
                        Presence presence;

                        if (!mode.equals("unavailable")) {
                            presence = new Presence(Presence.Type.available);
                            presence.setMode(Presence.Mode.valueOf(mode));
                        } else
                            presence = new Presence(Presence.Type.unavailable);
                        if (state != null)
                            presence.setStatus(state);
                        presence.setTo(to);
                        presence.setPriority(priority);
                        connection.sendPacket(presence);
                    }
                }
            }.start();
        }
    }

    public void sendTunes(final String artist, final String title, final String source) {
        Collection<XMPPConnection> collection = connections.values();
        for (XMPPConnection connection : collection) {
            if (connection.isAuthenticated()) {
                TuneItem tune = new TuneItem(System.currentTimeMillis() + "");
                tune.setArtist(StringUtils.escapeForXML(artist));
                tune.setTitle(StringUtils.escapeForXML(title));
                tune.setSource(StringUtils.escapeForXML(source));

                PEPManager pep = new PEPManager(connection);
                pep.publish(tune);
            }
        }
    }

    public void setPreference(String name, Object value) {
        if (!started)
            return;
        if (prefs == null)
            prefs = PreferenceManager.getDefaultSharedPreferences(this);
        SharedPreferences.Editor editor = prefs.edit();
        if (value instanceof String)
            editor.putString(name, String.valueOf(value));
        else if (value instanceof Integer)
            editor.putInt(name, Integer.parseInt(String.valueOf(value)));
        else if (value instanceof Boolean)
            editor.putBoolean(name, (Boolean) value);
        editor.commit();
    }

    private void writeMucMessage(String account, String group, String nick, String message) {
        String time = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss").format(new java.util.Date());

        MessageItem item = new MessageItem(account, group + "/" + nick);
        item.setBody(message);
        item.setType(MessageItem.Type.status);
        item.setName(StringUtils.parseName(group));
        item.setTime(time);

        MessageLog.writeMucMessage(account, group, nick, item);
    }

    private void clearAll() {
        activeChats.clear();
        msgCounter.clear();
        autoStatusTimer.cancel();
        collapsedGroups.clear();
        unreadMessages.clear();
        conferences.clear();
        joinedConferences.clear();
        avatarsHash.clear();
        vcards.clear();
        textHash.clear();
        messagesCount.clear();
    }

    public void configure() {
        ProviderManager pm = ProviderManager.getInstance();

        pm.addIQProvider("query", "jabber:iq:private", new PrivateDataManager.PrivateDataIQProvider());
        pm.addIQProvider("query", "jabber:iq:version", new VersionProvider());

        //  Roster Exchange
        pm.addExtensionProvider("x", "jabber:x:roster", new RosterExchangeProvider());

        //  Caps
        pm.addExtensionProvider("c", CapsExtension.XMLNS, new CapsExtensionProvider());

        // Messages Receipts
        pm.addExtensionProvider("request", "urn:xmpp:receipts", new ReceiptExtension.Provider());
        pm.addExtensionProvider("received", "urn:xmpp:receipts", new ReceiptExtension.Provider());

        // Last Message Correction
        pm.addExtensionProvider("replace", "urn:xmpp:message-correct:0", new ReplaceExtension.Provider());

        // Captcha
        pm.addExtensionProvider("captcha", "urn:xmpp:captcha", new CaptchaExtension.Provider());
        pm.addExtensionProvider("data", "urn:xmpp:bob", new BobExtension.Provider());

        //  Chat State
        pm.addExtensionProvider("active", "http://jabber.org/protocol/chatstates",
                new ChatStateExtension.Provider());
        pm.addExtensionProvider("composing", "http://jabber.org/protocol/chatstates",
                new ChatStateExtension.Provider());
        pm.addExtensionProvider("paused", "http://jabber.org/protocol/chatstates",
                new ChatStateExtension.Provider());
        pm.addExtensionProvider("inactive", "http://jabber.org/protocol/chatstates",
                new ChatStateExtension.Provider());
        pm.addExtensionProvider("gone", "http://jabber.org/protocol/chatstates", new ChatStateExtension.Provider());

        //  Group Chat Invitations
        pm.addExtensionProvider("x", "jabber:x:conference", new GroupChatInvitation.Provider());

        //  Service Discovery # Items
        pm.addIQProvider("query", "http://jabber.org/protocol/disco#items", new DiscoverItemsProvider());
        pm.addIQProvider("query", "http://jabber.org/protocol/disco#info", new DiscoverInfoProvider());

        //  Data Forms
        pm.addExtensionProvider("x", "jabber:x:data", new DataFormProvider());

        //  MUC User
        pm.addExtensionProvider("x", "http://jabber.org/protocol/muc#user", new MUCUserProvider());

        //  MUC Admin
        pm.addIQProvider("query", "http://jabber.org/protocol/muc#admin", new MUCAdminProvider());

        //  MUC Owner
        pm.addIQProvider("query", "http://jabber.org/protocol/muc#owner", new MUCOwnerProvider());

        //  Delayed Delivery
        pm.addExtensionProvider("x", "jabber:x:delay", new DelayInformationProvider());

        //  VCard
        pm.addIQProvider("vCard", "vcard-temp", new VCardProvider());

        //  Offline Message Requests
        pm.addIQProvider("offline", "http://jabber.org/protocol/offline", new OfflineMessageRequest.Provider());

        //  Offline Message Indicator
        pm.addExtensionProvider("offline", "http://jabber.org/protocol/offline", new OfflineMessageInfo.Provider());

        //  Last Activity
        pm.addIQProvider("query", "jabber:iq:last", new LastActivity.Provider());

        //  User Search
        pm.addIQProvider("query", "jabber:iq:search", new UserSearch.Provider());

        //  SharedGroupsInfo
        pm.addIQProvider("sharedgroup", "http://www.jivesoftware.org/protocol/sharedgroup",
                new SharedGroupsInfo.Provider());

        //  JEP-33: Extended Stanza Addressing
        pm.addExtensionProvider("addresses", "http://jabber.org/protocol/address",
                new MultipleAddresses.Provider());

        //   FileTransfer
        pm.addIQProvider("si", "http://jabber.org/protocol/si", new StreamInitiationProvider());
        pm.addIQProvider("query", "http://jabber.org/protocol/bytestreams", new BytestreamsProvider());
        pm.addIQProvider("open", "http://jabber.org/protocol/ibb", new IBBProviders.Open());
        pm.addIQProvider("close", "http://jabber.org/protocol/ibb", new IBBProviders.Close());
        pm.addExtensionProvider("data", "http://jabber.org/protocol/ibb", new IBBProviders.Data());

        //  Privacy
        pm.addIQProvider("query", "jabber:iq:privacy", new PrivacyProvider());
        pm.addIQProvider("command", "http://jabber.org/protocol/commands", new AdHocCommandDataProvider());
        pm.addExtensionProvider("malformed-action", "http://jabber.org/protocol/commands",
                new AdHocCommandDataProvider.MalformedActionError());
        pm.addExtensionProvider("bad-locale", "http://jabber.org/protocol/commands",
                new AdHocCommandDataProvider.BadLocaleError());
        pm.addExtensionProvider("bad-payload", "http://jabber.org/protocol/commands",
                new AdHocCommandDataProvider.BadPayloadError());
        pm.addExtensionProvider("bad-sessionid", "http://jabber.org/protocol/commands",
                new AdHocCommandDataProvider.BadSessionIDError());
        pm.addExtensionProvider("session-expired", "http://jabber.org/protocol/commands",
                new AdHocCommandDataProvider.SessionExpiredError());
    }

    private void registerSip(String username, String password) {
        if (!prefs.getBoolean("EnableSIP", false))
            return;
        if (SipManager.isApiSupported(JTalkService.this) && SipManager.isVoipSupported(JTalkService.this)) {
            Log.d("SIP", "Api supported");
            String user = StringUtils.parseName(username);
            String host = StringUtils.parseServer(username);
            int port = 5060;
            try {
                Lookup lookup = new Lookup("_sip._udp." + host, Type.SRV);
                lookup.setCredibility(Credibility.ANY);
                Record[] records = lookup.run();
                if (lookup.getResult() == Lookup.SUCCESSFUL) {
                    if (records.length > 0) {
                        SRVRecord record = (SRVRecord) records[0];
                        host = record.getTarget().toString();
                        host = host.substring(0, host.length() - 1);
                        port = record.getPort();
                    }
                }
            } catch (Exception ignored) {
            }
            Log.d("SIP", "user: " + user + "; host: " + host + "; port: " + port);

            try {
                SipProfile.Builder builder = new SipProfile.Builder("sip:" + username);
                builder.setDisplayName(username);
                builder.setProfileName(username);
                builder.setAutoRegistration(true);
                builder.setOutboundProxy(host);
                builder.setProtocol("UDP");
                builder.setPort(port);
                builder.setPassword(password);
                builder.setSendKeepAlive(true);
                SipProfile profile = builder.build();

                SipManager manager = getSipManager(username);
                if (manager == null)
                    manager = SipManager.newInstance(JTalkService.this);

                Intent intent = new Intent();
                intent.putExtra("account", username);
                intent.setAction(Constants.INCOMING_CALL);
                PendingIntent pendingIntent = PendingIntent.getBroadcast(JTalkService.this, 0, intent,
                        PendingIntent.FLAG_UPDATE_CURRENT);
                if (!manager.isOpened(profile.getUriString()))
                    manager.open(profile, pendingIntent, null);
                Thread.sleep(4000);
                manager.setRegistrationListener(profile.getUriString(), new SipRegistrationListener() {
                    @Override
                    public void onRegistering(String localProfileUri) {
                        Log.d("REGLISTENER", "Registering with SIP Server...");
                    }

                    @Override
                    public void onRegistrationDone(String localProfileUri, long expiryTime) {
                        Log.d("REGLISTENER", "Ready");
                    }

                    @Override
                    public void onRegistrationFailed(String localProfileUri, int errorCode, String errorMessage) {
                        Log.d("REGLISTENER", "Registration failed.  Please check settings. MSG: [" + errorCode
                                + "] " + errorMessage);
                    }
                });
                addSipManager(username, manager);
            } catch (ParseException pe) {
                Log.e("CreateSipProfile", pe.getLocalizedMessage());
            } catch (SipException se) {
                Log.e("SIPExtension", se.getLocalizedMessage());
            } catch (InterruptedException ignored) {
            }
        }
    }

    public String getDerivedNick(final String username, BookmarkedConference bc) {
        String bareJid = StringUtils.parseBareAddress(username);
        String nick = null;

        // try bookmark if passed
        if (bc != null) {
            nick = bc.getNickname();
        }

        // no nickname with bookmark
        if (nick == null || nick.length() < 1) {
            // try account preference
            Cursor cursor = getContentResolver().query(JTalkProvider.ACCOUNT_URI, null,
                    AccountDbHelper.JID + " = '" + bareJid + "'", null, null);
            if (cursor != null && cursor.getCount() > 0) {
                cursor.moveToFirst();
                if (AccountDbHelper.VERSION > 4) {
                    nick = cursor.getString(cursor.getColumnIndex(AccountDbHelper.NICK));
                }
            }
            cursor.close();
        }
        // no nickname account preference
        if (nick == null || nick.length() < 1) {
            // use localpart of JID
            nick = StringUtils.parseName(bareJid);
        }
        return nick;
    }

    public class ConnectionTask extends AsyncTask<String, Integer, String> {
        Intent intent = new Intent(Constants.UPDATE);
        String username, password, resource, service;
        boolean tls = true, sasl = true, compression = false;
        int port = 5222;

        public ConnectionTask(String username, String password, String service, int port, String resource,
                boolean tls, boolean sasl, boolean compression) {
            this.username = username;
            this.password = password;
            this.service = service;
            this.port = port;
            this.resource = resource;
            this.tls = tls;
            this.sasl = sasl;
            this.compression = compression;
        }

        @Override
        protected String doInBackground(String... args) {
            if (connecting)
                return null;
            else
                connecting = true;

            if (username == null || username.indexOf("@") < 1) {
                setState(username, getString(R.string.ConnectionError));
                sendBroadcast(intent);
                return null;
            } else {
                Notify.connectingNotify(username);

                setState(username, getString(R.string.Connecting));
                sendBroadcast(new Intent(Constants.UPDATE));

                SmackConfiguration.setPacketReplyTimeout(60000);
                SmackConfiguration.setKeepAliveInterval(60000);

                String host = StringUtils.parseServer(username);
                String user = StringUtils.parseName(username);

                if (service == null || service.length() < 4) {
                    try {
                        Lookup lookup = new Lookup("_xmpp-client._tcp." + host, Type.SRV);
                        lookup.setCredibility(Credibility.ANY);
                        Record[] records = lookup.run();
                        if (lookup.getResult() == Lookup.SUCCESSFUL) {
                            if (records.length > 0) {
                                SRVRecord record = (SRVRecord) records[0];
                                service = record.getTarget().toString();
                                service = service.substring(0, service.length() - 1);
                                port = record.getPort();
                            }
                        }
                    } catch (Exception ignored) {
                    }
                }

                if (service == null || service.length() <= 3)
                    service = host;

                ConnectionConfiguration cc = new ConnectionConfiguration(service, port, host);
                cc.setCapsNode("http://jtalk.ustyugov.net/caps");
                cc.setSelfSignedCertificateEnabled(true);
                cc.setReconnectionAllowed(false);
                cc.setRosterLoadedAtLogin(true);
                cc.setSendPresence(false);
                cc.setSASLAuthenticationEnabled(sasl);
                cc.setSecurityMode(tls ? SecurityMode.enabled : SecurityMode.disabled);
                cc.setCompressionEnabled(compression);

                XMPPConnection connection = new XMPPConnection(cc);
                connection.setSoftName(getString(R.string.app_name));
                connection.setSoftVersion(getString(R.string.version) + " (" + getString(R.string.build) + ")");
                connection.addFeature("http://jabber.org/protocol/disco#info");
                connection.addFeature("http://jabber.org/protocol/muc");
                connection.addFeature("http://jabber.org/protocol/chatstates");
                connection.addFeature("http://jabber.org/protocol/bytestreams");
                connection.addFeature("http://jabber.org/protocol/tune");
                connection.addFeature("http://jabber.org/protocol/pubsub#event");
                connection.addFeature("jabber:iq:version");
                connection.addFeature("urn:xmpp:receipts");
                connection.addFeature("urn:xmpp:time");
                connection.addFeature(ReplaceExtension.NAMESPACE);
                connection.addFeature(Notes.NAMESPACE);

                XmlListeners.put(username, new XmlListener(connection));

                try {
                    if (!connection.isConnected())
                        connection.connect();
                } catch (XMPPException xe) {
                    String error = "[" + connection.getServiceName() + "] Error: " + xe.getLocalizedMessage();
                    setState(username, error);
                    sendBroadcast(intent);
                    if (!isAuthenticated())
                        Notify.offlineNotify(JTalkService.this, error);
                    return null;
                }

                try {
                    if (connection.isConnected() && !connection.isAuthenticated()) {
                        connection.login(user, password, resource);

                        connection.addPacketListener(new MsgListener(JTalkService.this, connection, username),
                                new PacketTypeFilter(Message.class));
                        addConnectionListener(username, connection);

                        Roster roster = connection.getRoster();
                        roster.setSubscriptionMode(Roster.SubscriptionMode.valueOf(
                                prefs.getString("SubscriptionMode", Roster.SubscriptionMode.accept_all.name())));
                        roster.addRosterListener(new RstListener(username));

                        connections.put(username, connection);
                        return username;
                    }
                } catch (Exception e) {
                    setState(username, e.getLocalizedMessage());
                    sendBroadcast(intent);
                    if (!isAuthenticated())
                        Notify.offlineNotify(JTalkService.this, e.getLocalizedMessage());
                    return null;
                }
            }
            return null;
        }

        @Override
        public void onPostExecute(final String username) {
            connecting = false;
            if (username != null) {
                final XMPPConnection connection = connections.get(username);
                if (!connection.isAuthenticated() || !connection.isConnected())
                    return;

                int priority = prefs.getInt("currentPriority", 0);
                String status = prefs.getString("currentStatus", "");
                String mode = prefs.getString("currentMode", "available");
                sendPresence(username, status, mode, priority);
                setState(username, status);

                new PrivacyListManager(connection);
                new ServiceDiscoveryManager(connection);
                new AdHocCommandManager(connection);

                FileTransferManager fileTransferManager = new FileTransferManager(connection);
                fileTransferManager.addFileTransferListener(new IncomingFileListener());
                fileTransferManagers.put(username, fileTransferManager);

                try {
                    MultiUserChat.addInvitationListener(connection, new InviteListener(username));
                } catch (Exception ignored) {
                }

                // Join to rooms if reconnected or autojoin is enabled
                new Thread() {
                    public void run() {
                        try {
                            Thread.sleep(5000);
                        } catch (Exception ignored) {
                        }

                        if (!getConferencesHash(username).isEmpty()) {
                            Collection<Conference> coll = joinedConferences.values();
                            for (Conference conf : coll) {
                                joinRoom(username, conf.getName(), conf.getNick(), conf.getPassword());
                            }
                        } else {
                            if (prefs.getBoolean("EnableAutojoin", true)) {
                                try {
                                    BookmarkManager bm = BookmarkManager.getBookmarkManager(connection);
                                    Collection<BookmarkedConference> bookmarks = bm.getBookmarkedConferences();
                                    for (BookmarkedConference bc : bookmarks) {
                                        if (bc.isAutoJoin()) {
                                            String nick = getDerivedNick(username, bc);
                                            joinRoom(username, bc.getJid(), nick, bc.getPassword());
                                        }
                                    }
                                } catch (XMPPException ignored) {
                                }
                            }
                        }
                    }
                }.start();

                if (prefs.getBoolean("Ping", false)) {
                    int timeout = 60000;
                    try {
                        timeout = Integer.parseInt(prefs.getString("PingTimeout", 60 + "")) * 1000;
                    } catch (NumberFormatException ignored) {
                    }
                    Timer pingTimer = new Timer();
                    pingTimer.schedule(new TimerTask() {
                        @Override
                        public void run() {
                            new PingTask(username).execute();
                        }
                    }, timeout, timeout * 2);
                    pingTimers.put(username, pingTimer);
                }

                try {
                    OfflineMessageManager omm = new OfflineMessageManager(connection);
                    omm.deleteMessages();
                } catch (Exception ignored) {
                }

                Notify.updateNotify();
                new IgnoreList(connection).createIgnoreList();
                resetTimer();

                if (connectionTasks.containsKey(username))
                    connectionTasks.remove(username);
                sendBroadcast(new Intent(Constants.UPDATE));

                registerSip(username, password);
            }
        }
    }
}