Beispiel #1
0
JabberClient::PresenceRequest::~PresenceRequest()
{
    unsigned status = STATUS_UNKNOWN;
    if (m_type == "unavailable"){
        status = STATUS_OFFLINE;
    }else if (m_type.length() == 0){
        status = STATUS_ONLINE;
        if (m_show == "away"){
            status = STATUS_AWAY;
        }else if (m_show == "xa"){
            status = STATUS_NA;
        }else if (m_show == "dnd"){
            status = STATUS_DND;
        }
    }else{
        if (m_type == "subscribe"){
            m_client->auth_request(m_from.c_str(), MessageAuthRequest, m_status.c_str(), true);
        }else if (m_type == "subscribed"){
            m_client->auth_request(m_from.c_str(), MessageAuthGranted, m_status.c_str(), true);
        }else if (m_type == "unsubscribed"){
            m_client->auth_request(m_from.c_str(), MessageRemoved, m_status.c_str(), true);
        }else{
            log(L_DEBUG, "Unsupported presence type %s", m_type.c_str());
        }
    }
    if (status != STATUS_UNKNOWN){
        Contact *contact;
        JabberUserData *data = m_client->findContact(m_from.c_str(), NULL, NULL, false, contact);
        if (data){
            bool bOnLine = false;
            bool bChanged = set_str(&data->AutoReply, m_status.c_str());
            if (data->Status != status){
                time_t now;
                time(&now);
                bChanged = true;
                if ((status == STATUS_ONLINE) &&
                        ((now - m_client->data.owner.OnlineTime > 60) ||
                         (data->Status != STATUS_OFFLINE)))
                    bOnLine = true;
                if (data->Status == STATUS_OFFLINE)
                    data->OnlineTime = now;
                data->Status = status;
                data->StatusTime = now;
            }
            if (bChanged){
                StatusMessage m;
                m.setContact(contact->id());
                m.setClient(m_client->dataName(data).c_str());
                m.setFlags(MESSAGE_RECEIVED);
                m.setStatus(status);
                Event e(EventMessageReceived, &m);
                e.process();
            }
            if (bOnLine){
                Event e(EventContactOnline, contact);
                e.process();
            }
        }
    }
}
Beispiel #2
0
void YahooClient::processStatus(unsigned short service, const char *id,
                                const char *_state, const char *_msg,
                                const char *_away, const char *_idle)
{
    Contact *contact;
    YahooUserData *data = findContact(id, NULL, contact);
    if (data == NULL)
        return;
    unsigned state = 0;
    unsigned away  = 0;
    unsigned idle  = 0;
    if (_state)
        state = atol(_state);
    if (_away)
        away  = atol(_away);
    if (_idle)
        idle  = atol(_idle);
    if (service == YAHOO_SERVICE_LOGOFF)
        state = YAHOO_STATUS_OFFLINE;
    if ((state != data->Status.value) ||
            ((state == YAHOO_STATUS_CUSTOM) &&
             (((away != 0) != data->bAway.bValue) || _cmp(_msg, data->AwayMessage.ptr)))) {

        unsigned long old_status = STATUS_UNKNOWN;
        unsigned style  = 0;
        const char *statusIcon = NULL;
        contactInfo(data, old_status, style, statusIcon);

        time_t now;
        time(&now);
        now -= idle;
        if (data->Status.value == YAHOO_STATUS_OFFLINE)
            data->OnlineTime.value = now;
        data->Status.value = state;
        data->bAway.bValue = (away != 0);
        data->StatusTime.value = now;

        unsigned long new_status = STATUS_UNKNOWN;
        contactInfo(data, old_status, style, statusIcon);

        if (old_status != new_status) {
            StatusMessage m;
            m.setContact(contact->id());
            m.setClient(dataName(data).c_str());
            m.setFlags(MESSAGE_RECEIVED);
            m.setStatus(STATUS_OFFLINE);
            Event e(EventMessageReceived, &m);
            e.process();
            if ((new_status == STATUS_ONLINE) && !contact->getIgnore()) {
                Event e(EventContactOnline, contact);
                e.process();
            }
        } else {
            Event e(EventContactStatus, contact);
            e.process();
        }
    }
}
Beispiel #3
0
void JabberClient::setStatus(unsigned status, const char *ar)
{
    if (status  != m_status){
        time_t now;
        time(&now);
        data.owner.StatusTime = now;
        if (m_status == STATUS_OFFLINE)
            data.owner.OnlineTime = now;
        m_status = status;
        m_socket->writeBuffer.packetStart();
        const char *priority = "5";
        const char *show = NULL;
        const char *type = NULL;
        if (getInvisible()){
            type = "invisible";
        }else{
            switch (status){
            case STATUS_AWAY:
                show = "away";
                break;
            case STATUS_NA:
                show = "xa";
                break;
            case STATUS_DND:
                show = "dnd";
                break;
            case STATUS_FFC:
                show = "chat";
                break;
            case STATUS_OFFLINE:
                priority = NULL;
                type = "unavailable";
                break;
            }
        }
        m_socket->writeBuffer << "<presence";
        if (type)
            m_socket->writeBuffer << " type=\"" << type << "\"";
        m_socket->writeBuffer << ">\n";
        if (show && *show)
            m_socket->writeBuffer << "<show>" << show << "</show>\n";
        if (ar && *ar){
            m_socket->writeBuffer << "<status>" << ar << "</status>\n";
        }
        if (priority)
            m_socket->writeBuffer << "<priority>" << priority << "</priority>\n";
        m_socket->writeBuffer << "</presence>";
        sendPacket();
        Event e(EventClientChanged, static_cast<Client*>(this));
        e.process();
    }
    if (status == STATUS_OFFLINE){
        if (m_socket){
            m_socket->writeBuffer.packetStart();
            m_socket->writeBuffer
            << "</stream:stream>\n";
            sendPacket();
        }
        Contact *contact;
        ContactList::ContactIterator it;
        time_t now;
        time(&now);
        data.owner.StatusTime = now;
        while ((contact = ++it) != NULL){
            JabberUserData *data;
            ClientDataIterator it(contact->clientData, this);
            while ((data = (JabberUserData*)(++it)) != NULL){
                if (data->Status == STATUS_OFFLINE)
                    continue;
                data->StatusTime = now;
                setOffline(data);
                StatusMessage m;
                m.setContact(contact->id());
                m.setClient(dataName(data).c_str());
                m.setFlags(MESSAGE_RECEIVED);
                m.setStatus(STATUS_OFFLINE);
                Event e(EventMessageReceived, &m);
                e.process();
            }
        }
    }
}
Beispiel #4
0
void ICQClient::snac_buddy(unsigned short type, unsigned short)
{
    string screen;
    Contact *contact;
    ICQUserData *data;
    switch (type){
    case ICQ_SNACxBDY_RIGHTSxGRANTED:
        log(L_DEBUG, "Buddy rights granted");
        break;
    case ICQ_SNACxBDY_USEROFFLINE:
        screen = m_socket->readBuffer.unpackScreen();
        data = findContact(screen.c_str(), NULL, false, contact);
        if (data && (data->Status.value != ICQ_STATUS_OFFLINE)){
            setOffline(data);
            StatusMessage m;
            m.setContact(contact->id());
            m.setClient(dataName(data).c_str());
            m.setStatus(STATUS_OFFLINE);
            m.setFlags(MESSAGE_RECEIVED);
            Event e(EventMessageReceived, &m);
            e.process();
        }
        break;
    case ICQ_SNACxBDY_USERONLINE:
        screen = m_socket->readBuffer.unpackScreen();
        data = findContact(screen.c_str(), NULL, false, contact);
        if (data){
            time_t now;
            time(&now);

            bool bChanged     = false;
            bool bAwayChanged = false;
            unsigned long prevStatus = data->Status.value;

            unsigned short level, len;
            m_socket->readBuffer >> level >> len;
            data->WarningLevel.value = level;

            TlvList tlv(m_socket->readBuffer);

            Tlv *tlvClass = tlv(0x0001);
            if (tlvClass){
                unsigned short userClass = *tlvClass;
                if (userClass != data->Class.value){
                    if ((userClass & CLASS_AWAY) != (data->Class.value & CLASS_AWAY)){
                        data->StatusTime.value = (unsigned long)now;
                        bAwayChanged = true;
                    }
                    data->Class.value = userClass;
                    bChanged = true;
                }
                if (data->Uin.value == 0){
                    if (userClass & CLASS_AWAY){
                        fetchAwayMessage(data);
                    }else{
                        set_str(&data->AutoReply.ptr, NULL);
                    }
                }
            }

            // Status TLV
            Tlv *tlvStatus = tlv(0x0006);
            if (tlvStatus){
                unsigned long status = *tlvStatus;
                if (status != data->Status.value){
                    data->Status.value = status;
                    if ((status & 0xFF) == 0)
                        set_str(&data->AutoReply.ptr, NULL);
                    data->StatusTime.value = (unsigned long)now;
                }
            }else if (data->Status.value == ICQ_STATUS_OFFLINE){
                data->Status.value = ICQ_STATUS_ONLINE;
                data->StatusTime.value = (unsigned long)now;
            }

            // Online time TLV
            Tlv *tlvOnlineTime = tlv(0x0003);
            if (tlvOnlineTime){
                unsigned long OnlineTime = *tlvOnlineTime;
                if (OnlineTime != data->OnlineTime.value){
                    data->OnlineTime.value = OnlineTime;
                    bChanged = true;
                }
            }
            Tlv *tlvNATime = tlv(0x0004);
            if (tlvNATime){
                unsigned short na_time = *tlvNATime;
                unsigned long StatusTime = (unsigned long)now - na_time * 60;
                if (StatusTime != data->StatusTime.value){
                    data->StatusTime.value = StatusTime;
                    bChanged = true;
                }
            }

            // IP TLV
            Tlv *tlvIP = tlv(0x000A);
            if (tlvIP)
                bChanged |= set_ip(&data->IP, htonl((unsigned long)(*tlvIP)));

            Tlv *tlvCapability = tlv(0x000D);
            if (tlvCapability){
                data->Caps.value = 0;
                Buffer info(*tlvCapability);
                for (; info.readPos() < info.size(); ){
                    capability cap;
                    info.unpack((char*)cap, sizeof(capability));
                    for (unsigned i = 0;; i++){
                        if (*capabilities[i] == 0) break;
                        unsigned size = sizeof(capability);
                        if (i == CAP_SIMOLD) size--;
                        if ((i == CAP_MICQ) || (i == CAP_LICQ) || (i == CAP_SIM)) size -= 4;
                        if (!memcmp(cap, capabilities[i], size)){
                            if (i == CAP_SIMOLD){
                                unsigned char build = cap[sizeof(capability)-1];
                                if (build && ((build == 0x92) || (build < (1 << 6)))) continue;
                                data->Build.value = build;
                            }
                            if ((i == CAP_MICQ) || (i == CAP_LICQ) || (i == CAP_SIM)){
                                unsigned char *p = (unsigned char*)cap;
                                p += 12;
                                data->Build.value = (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3];
                            }
                            data->Caps.value |= (1 << i);
                            break;
                        }
                    }
                }
            }

            unsigned long infoUpdateTime = 0;
            unsigned long pluginInfoTime = 0;
            unsigned long pluginStatusTime = 0;

            // Direct connection info
            Tlv *tlvDirect = tlv(0x000C);
            if (tlvDirect){
                Buffer info(*tlvDirect);
                unsigned long  realIP;
                unsigned short port;
                char mode, version, junk;
                info >> realIP;
                info.incReadPos(2);
                info >> port;
                if (realIP == 0x7F000001)
                    realIP = 0;
                bChanged |= set_ip(&data->RealIP, htonl(realIP));
                data->Port.value = port;
                unsigned long DCcookie;
                info >> mode >> junk >> version >> DCcookie;
                data->DCcookie.value = DCcookie;
                info.incReadPos(8);
                info
                >> infoUpdateTime
                >> pluginInfoTime
                >> pluginStatusTime;
                if (mode == MODE_DENIED) mode = MODE_INDIRECT;
                if ((mode != MODE_DIRECT) && (mode != MODE_INDIRECT))
                    mode = MODE_INDIRECT;
                data->Mode.value    = mode;
                data->Version.value = version;
            }

            Tlv *tlvPlugin = tlv(0x0011);
            if (tlvPlugin && data->Uin.value){
                Buffer info(*tlvPlugin);
                char type;
                unsigned long time;
                info >> type;
                info.unpack(time);
                plugin p;
                unsigned plugin_index;
                unsigned long plugin_status;
                switch (type){
                case 1:
                    addFullInfoRequest(data->Uin.value);
                    break;
                case 2:
                    info.incReadPos(6);
                    info.unpack((char*)p, sizeof(p));
                    data->PluginInfoTime.value = time;
                    for (plugin_index = 0; plugin_index < PLUGIN_NULL; plugin_index++)
                        if (!memcmp(p, plugins[plugin_index], sizeof(p)))
                            break;
                    switch (plugin_index){
                    case PLUGIN_PHONEBOOK:
                        log(L_DEBUG, "Updated phonebook");
                        addPluginInfoRequest(data->Uin.value, plugin_index);
                        break;
                    case PLUGIN_PICTURE:
                        log(L_DEBUG, "Updated picture");
                        addPluginInfoRequest(data->Uin.value, plugin_index);
                        break;
                    case PLUGIN_QUERYxINFO:
                        log(L_DEBUG, "Updated info plugin list");
                        addPluginInfoRequest(data->Uin.value, plugin_index);
                        break;
                    default:
                        if (plugin_index >= PLUGIN_NULL)
                            log(L_WARN, "Unknown plugin sign");
                    }
                    break;
                case 3:
                    info.incReadPos(6);
                    info.unpack((char*)p, sizeof(p));
                    info.incReadPos(1);
                    info.unpack(plugin_status);
                    data->PluginStatusTime.value = time;
                    for (plugin_index = 0; plugin_index < PLUGIN_NULL; plugin_index++)
                        if (!memcmp(p, plugins[plugin_index], sizeof(p)))
                            break;
                    switch (plugin_index){
                    case PLUGIN_FOLLOWME:
                        if (data->FollowMe.value == plugin_status)
                            break;
                        data->FollowMe.value = plugin_status;
                        bChanged = true;
                        break;
                    case PLUGIN_FILESERVER:
                        if ((data->SharedFiles.value != 0) == (plugin_status != 0))
                            break;
                        data->SharedFiles.value = (plugin_status != 0);
                        bChanged = true;
                        break;
                    case PLUGIN_ICQPHONE:
                        if (data->ICQPhone.value == plugin_status)
                            break;
                        data->ICQPhone.value = plugin_status;
                        bChanged = true;
                        break;
                    default:
                        if (plugin_index >= PLUGIN_NULL)
                            log(L_WARN, "Unknown plugin sign");
                    }
                    break;

                }
            }else{
                data->InfoUpdateTime.value   = infoUpdateTime;
                data->PluginInfoTime.value   = pluginInfoTime;
                data->PluginStatusTime.value = pluginStatusTime;
                if (getAutoUpdate()){
                    if (infoUpdateTime == 0)
                        infoUpdateTime = 1;
                    if (infoUpdateTime != data->InfoFetchTime.value)
                        addFullInfoRequest(data->Uin.value);
                    if ((data->PluginInfoTime.value != data->PluginInfoFetchTime.value)){
                        if (data->PluginInfoTime.value)
                            addPluginInfoRequest(data->Uin.value, PLUGIN_QUERYxINFO);
                    }
                    if ((data->PluginInfoTime.value != data->PluginInfoFetchTime.value) ||
                            (data->PluginStatusTime.value != data->PluginStatusFetchTime.value)){
                        if (data->SharedFiles.bValue){
                            data->SharedFiles.bValue = false;
                            bChanged = true;
                        }
                        if (data->FollowMe.value){
                            data->FollowMe.value = 0;
                            bChanged = true;
                        }
                        if (data->ICQPhone.bValue){
                            data->ICQPhone.bValue = false;
                            bChanged = true;
                        }
                        if (data->PluginStatusTime.value)
                            addPluginInfoRequest(data->Uin.value, PLUGIN_QUERYxSTATUS);
                    }
                }
            }
            if (data->bInvisible.bValue){
                data->bInvisible.bValue = false;
                bChanged = true;
            }
            if (bChanged){
                Event e(EventContactChanged, contact);
                e.process();
            }
            if ((data->Status.value != prevStatus) || bAwayChanged){
                unsigned status = STATUS_OFFLINE;
                if ((data->Status.value & 0xFFFF) != ICQ_STATUS_OFFLINE){
                    status = STATUS_ONLINE;
                    if (data->Status.value & ICQ_STATUS_DND){
                        status = STATUS_DND;
                    }else if (data->Status.value & ICQ_STATUS_OCCUPIED){
                        status = STATUS_OCCUPIED;
                    }else if (data->Status.value & ICQ_STATUS_NA){
                        status = STATUS_NA;
                    }else if (data->Status.value & ICQ_STATUS_AWAY){
                        status = STATUS_AWAY;
                    }else if (data->Status.value & ICQ_STATUS_FFC){
                        status = STATUS_FFC;
                    }
                }
                if ((status == STATUS_ONLINE) && (data->Class.value & CLASS_AWAY))
                    status = STATUS_AWAY;
                StatusMessage m;
                m.setContact(contact->id());
                m.setClient(dataName(data).c_str());
                m.setStatus(status);
                m.setFlags(MESSAGE_RECEIVED);
                Event e(EventMessageReceived, &m);
                e.process();
                if (!contact->getIgnore() &&
                        ((data->Class.value & CLASS_AWAY) == 0) &&
                        (((data->Status.value & 0xFF) == ICQ_STATUS_ONLINE) &&
                         (((prevStatus & 0xFF) != ICQ_STATUS_ONLINE)) || bAwayChanged) &&
                        (((prevStatus & 0xFFFF) != ICQ_STATUS_OFFLINE) ||
                         (data->OnlineTime.value > this->data.owner.OnlineTime.value))){
                    Event e(EventContactOnline, contact);
                    e.process();
                }
                if (getAutoReplyUpdate() && ((data->Status.value & 0xFF) != ICQ_STATUS_ONLINE)){
                    if ((getInvisible() && data->VisibleId.value) ||
                            (!getInvisible() && (data->InvisibleId.value == 0)))
                        addPluginInfoRequest(data->Uin.value, PLUGIN_AR);
                }
            }
        }
Beispiel #5
0
JabberClient::PresenceRequest::~PresenceRequest()
{
    unsigned status = STATUS_UNKNOWN;
    /*
        m_type - flags after draft-ietf-xmpp-core-16 / 8.4.1
    */
    if (m_type == "unavailable") {
        status = STATUS_OFFLINE;
    } else if (m_type == "subscribe") {
        m_client->auth_request(m_from.c_str(), MessageAuthRequest, m_status.c_str(), true);
    } else if (m_type == "subscribed") {
        m_client->auth_request(m_from.c_str(), MessageAuthGranted, m_status.c_str(), true);
    } else if (m_type == "unsubscribe") {
        m_client->auth_request(m_from.c_str(), MessageRemoved, m_status.c_str(), true);
    } else if (m_type == "unsubscribed") {
        m_client->auth_request(m_from.c_str(), MessageAuthRefused, m_status.c_str(), true);
    } else if (m_type == "probe") {
        // server want to to know if we're living
        m_client->ping();
    } else if (m_type == "error") {
        log(L_DEBUG, "An error has occurred regarding processing or delivery of a previously-sent presence stanza");
    } else if (m_type.length() == 0) {
        // m_show - flags after draft-ietf-xmpp-im-15 / 4.2
        status = STATUS_ONLINE;
        if (m_show == "away") {
            status = STATUS_AWAY;
        } else if (m_show == "chat") {
            status = STATUS_FFC;
        } else if (m_show == "xa") {
            status = STATUS_NA;
        } else if (m_show == "dnd") {
            status = STATUS_DND;
        } else if (m_show == "online") {
            status = STATUS_ONLINE;
        } else if (m_show.empty()) {
            status = STATUS_ONLINE;
            if (m_status == "Online") {
                status = STATUS_ONLINE;
            } else if (m_status == "Disconnected") {
                status = STATUS_OFFLINE;
            } else if (m_status == "Connected") {
                status = STATUS_ONLINE;
            } else if (!m_status.empty()) {
                log(L_DEBUG, "Unsupported status %s", m_status.c_str());
            }
        } else {
            log(L_DEBUG, "Unsupported available status %s", m_show.c_str());
        }
    } else {
        log(L_DEBUG, "Unsupported presence type %s", m_type.c_str());
    }
    if (status != STATUS_UNKNOWN) {
        Contact *contact;
        JabberUserData *data = m_client->findContact(m_from.c_str(), NULL, false, contact);
        if (data) {
            bool bOnLine = false;
            bool bChanged = set_str(&data->AutoReply, m_status.c_str());
            if (data->Status != status) {
                time_t now;
                time(&now);
                bChanged = true;
                if ((status == STATUS_ONLINE) &&
                        ((now - m_client->data.owner.OnlineTime > 60) ||
                         (data->Status != STATUS_OFFLINE)))
                    bOnLine = true;
                if (data->Status == STATUS_OFFLINE)
                    data->OnlineTime = now;
                data->Status = status;
                data->StatusTime = now;
            }
            if (bChanged) {
                StatusMessage m;
                m.setContact(contact->id());
                m.setClient(m_client->dataName(data).c_str());
                m.setFlags(MESSAGE_RECEIVED);
                m.setStatus(status);
                Event e(EventMessageReceived, &m);
                e.process();
            }
            if (bOnLine && !contact->getIgnore() && !m_client->isAgent(data->ID)) {
                Event e(EventContactOnline, contact);
                e.process();
            }
        }
    }
}
Beispiel #6
0
bool SnacIcqBuddy::process(unsigned short subtype, ICQBuffer* buf, unsigned short seq)
{
    switch (subtype)
	{
    case ICQ_SNACxBDY_RIGHTSxGRANTED:
        log(L_DEBUG, "Buddy rights granted");
        break;
    case ICQ_SNACxBDY_USEROFFLINE:
		{
			Contact *contact;
			QString screen = buf->unpackScreen();
            log(L_DEBUG, "Buddy offline: %s", qPrintable(screen));
			ICQUserData *data = m_client->findContact(screen, NULL, false, contact);
			if(!data)
				break;
            if(data->getStatus() != ICQ_STATUS_OFFLINE)
			{
				m_client->setOffline(data);
				StatusMessage *m = new StatusMessage;
				m->setContact(contact->id());
				m->setClient(m_client->dataName(data));
				m->setStatus(STATUS_OFFLINE);
				m->setFlags(MESSAGE_RECEIVED);
				EventMessageReceived e(m);
				if(!e.process())
					delete m;
			}
			else
			{
				// hack for trillian
				EventContact e(contact, EventContact::eOnline);
				e.process();
			}
			break;
		}
    case ICQ_SNACxBDY_USERONLINE:
		{
            Contact *contact;
            QString screen = buf->unpackScreen();
            log(L_DEBUG, "Buddy online: %s", qPrintable(screen));
			ICQUserData *data = m_client->findContact(screen, NULL, false, contact);
			if(data)
			{
				bool bChanged     = false;
				bool bAwayChanged = false;
                unsigned long prevStatus = data->getStatus();

				unsigned short level, len;
				(*buf) >> level >> len;
				data->setWarningLevel(level);

				TlvList tlv((*buf));
				Tlv* tlvClass = tlv(TLV_USER_CLASS);
				if(tlvClass)
				{
					unsigned short userClass = *tlvClass;
                    if(userClass != data->getClass())
					{
                        if ((userClass & CLASS_AWAY) != (data->getClass() & CLASS_AWAY))
						{
                            data->setStatusTime((unsigned long)time(NULL));
							bAwayChanged = true;
						}
                        data->setClass(userClass);
						bChanged = true;
					}
                    if(data->getUin() == 0)
					{
						if (userClass & CLASS_AWAY)
						{
							m_client->fetchAwayMessage(data);
						}
						else
						{
                            data->setAutoReply(QString::null);
						}
					}
				}

				// Status TLV
				Tlv *tlvStatus = tlv(TLV_USER_STATUS);
				if(tlvStatus)
				{
					uint32_t status = *tlvStatus;
                    if (status != data->getStatus())
					{
                        data->setStatus(status);
						if ((status & 0xFF) == 0)
                            data->setAutoReply(QString::null);
                        data->setStatusTime((unsigned long)time(NULL));
					}
				}
                else if(data->getStatus() == ICQ_STATUS_OFFLINE)
				{
                    data->setStatus(ICQ_STATUS_ONLINE);
                    data->setStatusTime((unsigned long)time(NULL));
				}

				// Online time TLV
				Tlv *tlvOnlineTime = tlv(TLV_USER_SIGNON_TIME);
				if(tlvOnlineTime)
				{
					uint32_t OnlineTime = *tlvOnlineTime;
					if(OnlineTime != data->getOnlineTime())
					{
						data->setOnlineTime(OnlineTime);
						bChanged = true;
					}
				}
				Tlv *tlvNATime = tlv(0x0004);
				if(tlvNATime)
				{
					unsigned short na_time = *tlvNATime;
					unsigned long StatusTime = (unsigned long)time(NULL) - na_time * 60;
                    if(StatusTime != data->getStatusTime())
					{
                        data->setStatusTime(StatusTime);
						bChanged = true;
					}
				}

				// IP TLV
				Tlv *tlvIP = tlv(TLV_USER_EXT_IP);
                unsigned long oldip = data->getIP();
                data->setIP(htonl((uint32_t)(*tlvIP)));
				if(tlvIP)
                    bChanged |= oldip != data->getIP();

				// short caps tlv
				Tlv *tlvCapShort = tlv(TLV_USER_NEWCAPS);
				if(tlvCapShort)
				{
                    data->setCaps(0);
                    data->setCaps2(0);

					ICQBuffer info(*tlvCapShort);

					for (; info.readPos() < (unsigned)info.size(); )
					{
						unsigned char shortcap[2];
						info.unpack((char*)shortcap, sizeof(shortcap));
						for (unsigned i = 0;; i++)
						{
							if (!memcmp(m_client->capabilities[i],"\x00\x00\x00\x00", 4)) {
                                    log(L_DEBUG, "%lu unknown cap %s", data->getUin(),
                                        makeCapStr(shortcap, sizeof(shortcap)).toLatin1().data());
								break;
							}
							// we don't go through all caps, only the starting with 0x09
							if (*m_client->capabilities[i] != '\x09')
								continue;
							if(!memcmp(&m_client->capabilities[i][2], shortcap, sizeof(shortcap)))
							{
                                m_client->setCap(data, (cap_id_t)i);
								break;
							}
						}
					}
				}
				// normal cap tlv
				Tlv *tlvCapability = tlv(TLV_USER_CAPS);
				if (tlvCapability)
				{
					if(!tlvCapShort)
					{
                        data->setCaps(0);
                        data->setCaps2(0);
					}
					ICQBuffer info(*tlvCapability);
					for(; info.readPos() < (unsigned)info.size(); )
					{
						capability cap;
						info.unpack((char*)cap, sizeof(capability));
						for(unsigned i = 0;; i++)
						{
							unsigned size = sizeof(capability);
							if (i == CAP_SIMOLD)
								size--;

							if (!memcmp(m_client->capabilities[i], "\x00\x00\x00\x00", 4)) 
							{
                                log( L_DEBUG, "%lu unknown cap %s", data->getUin(), qPrintable(makeCapStr( cap, size )) );
								break;
							}
                            if (i == CAP_MICQ || i == CAP_LICQ || i == CAP_SIM || i == CAP_KOPETE || i == CAP_QIP2010)
								size -= 4;
                            if (i == CAP_ANDRQ)
								size -= 7;
                            if (i == CAP_MIRANDA)
								size -= 8;
							if ((i == CAP_JIMM))
								size -= 11;
							if (i == CAP_ICQJP)
								size -= (16 - 4);

							if (!memcmp(cap, m_client->capabilities[i], size))
							{
								if (i == CAP_SIMOLD)
								{
									unsigned char build = cap[sizeof(capability)-1];
                                    if (build && (build == 0x92 || build < (1 << 6))) continue;
                                    data->setBuild(build);
								}
                                if (i == CAP_MICQ || i == CAP_LICQ || i == CAP_SIM || i == CAP_KOPETE)
								{
									unsigned char *p = (unsigned char*)cap;
									p += 12;
                                    data->setBuild((p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3]);
								}
                                if (i == CAP_ANDRQ)
								{
									unsigned char *p = (unsigned char*)cap;
									p += 9;
                                    data->setBuild((p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3]);
								}
                                if (i == CAP_MIRANDA)
								{
									unsigned char *p = (unsigned char*)cap;
									p += 8;
                                    data->setBuild((p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3]);
								}
                                if (i == CAP_JIMM)
								{
									char *p = (char*)cap;
									p += 5;
									const QString str = QString::fromAscii(p, 10);
									const QStringList sl = str.split('.');
									unsigned char maj = 0, min = 0;
									unsigned short rev = 0;
									if(sl.count() > 0)
										maj = sl[0].toUShort();
									if(sl.count() > 1)
										min = sl[1].toUShort();
									if(sl.count() > 2)
										rev = sl[2].toUShort();

                                    data->setBuild((maj << 24) + (min << 16) + rev);
								}
								if (i == CAP_ICQJP)
								{
                                    log(L_DEBUG, "%lu ICQJP cap is set", data->getUin());
                                    data->setBuild(cap[0x4] << 0x18 | cap[0x5] << 0x10 |
                                        cap[0x6] << 8 | cap[0x7]);
								}
								m_client->setCap(data, (cap_id_t)i);
								break;
							}
						}
					}
				}

				// buddy info
				Tlv *tlvBuddy = tlv(TLV_USER_BUDDYINFO);
				if (tlvBuddy)
				{
                    QByteArray ba = data->getBuddyHash();
					unsigned short iconID;
					unsigned char iconFlags, hashSize;
					ICQBuffer info(*tlvBuddy);
					QByteArray hash;
					QString fname = m_client->pictureFile(data);
					QFileInfo fi(fname);

					info >> iconID >> iconFlags >> hashSize;
					hash.resize(hashSize);
					info.unpack(hash.data(), hashSize);
                    if(data->getBuddyID() != iconID ||
							ba != hash ||
							!fi.exists() || fi.size() == 0) {
                        data->setBuddyID(iconID);
                        data->setBuddyHash(hash);
						m_client->requestBuddy(data);
					}
				}

				unsigned long infoUpdateTime = 0;
				unsigned long pluginInfoTime = 0;
				unsigned long pluginStatusTime = 0;

				// Direct connection info
				Tlv *tlvDirect = tlv(TLV_USER_DC_INFO);
				if(tlvDirect)
				{
					ICQBuffer info(*tlvDirect);
					unsigned long  realIP;
					unsigned short port;
					char mode, version, junk;
					info >> realIP;
					info.incReadPos(2);
					info >> port;
					if (realIP == 0x7F000001)
						realIP = 0;
                    unsigned long oldip = data->getRealIP();
                    data->setRealIP(htonl(realIP));
                    bChanged |= oldip != data->getRealIP();
                    data->setPort(port);
					unsigned long DCcookie;
					info >> mode >> junk >> version >> DCcookie;
                    data->setDCcookie(DCcookie);
					info.incReadPos(8);
					info
						>> infoUpdateTime
						>> pluginInfoTime
						>> pluginStatusTime;
                    if (mode == MODE_DENIED || mode != MODE_DIRECT && mode != MODE_INDIRECT)
                        mode = MODE_INDIRECT;
                    data->setMode(mode);
                    data->setVersion(version);
				}

				Tlv *tlvPlugin = tlv(0x0011);
                if(tlvPlugin && data->getUin())
				{
					ICQBuffer info(*tlvPlugin);
					char type;
					unsigned long time;
					info >> type;
					info.unpack(time);
					plugin p;
					unsigned plugin_index;
					unsigned long plugin_status;
					switch (type){
						case 1:
                            m_client->addFullInfoRequest(data->getUin());
							break;
						case 2:
                            if (!m_client->getInvisible() && data->getInvisibleId() == 0 || m_client->getInvisible() && data->getVisibleId()){
								info.incReadPos(6);
								info.unpack((char*)p, sizeof(p));
                                data->setPluginInfoTime(time);
								for (plugin_index = 0; plugin_index < PLUGIN_NULL; plugin_index++)
									if (!memcmp(p, m_client->plugins[plugin_index], sizeof(p)))
										break;
								switch (plugin_index)
								{
									case PLUGIN_PHONEBOOK:
										log(L_DEBUG, "Updated phonebook");
                                        m_client->addPluginInfoRequest(data->getUin(), plugin_index);
										break;
									case PLUGIN_PICTURE:
										log(L_DEBUG, "Updated picture");
										// when buddyID -> new avatar support, no need to ask for old picture plugin
                                        if(data->getBuddyID() == 0 || data->getBuddyHash().size() != 16) {
                                            data->setBuddyID(0);
                                            m_client->addPluginInfoRequest(data->getUin(), plugin_index);
										}
										break;
									case PLUGIN_QUERYxINFO:
										log(L_DEBUG, "Updated info plugin list");
                                        m_client->addPluginInfoRequest(data->getUin(), plugin_index);
										break;
									default:
										if (plugin_index >= PLUGIN_NULL)
											log(L_WARN, "Unknown plugin sign (%04X %04X)",
													type, plugin_index);
								}
							}
							break;
						case 3:
							info.incReadPos(6);
							info.unpack((char*)p, sizeof(p));
							info.incReadPos(1);
							info.unpack(plugin_status);
                            data->setPluginStatusTime(time);
							for (plugin_index = 0; plugin_index < PLUGIN_NULL; plugin_index++)
								if (!memcmp(p, m_client->plugins[plugin_index], sizeof(p)))
									break;
							switch (plugin_index){
								case PLUGIN_FOLLOWME:
                                    if (data->getFollowMe() == plugin_status)
										break;
                                    data->setFollowMe(plugin_status);
									bChanged = true;
									break;
								case PLUGIN_FILESERVER:
                                    if ((data->getSharedFiles() != 0) == (plugin_status != 0))
										break;
                                    data->setSharedFiles(plugin_status != 0);
									bChanged = true;
									break;
								case PLUGIN_ICQPHONE:
                                    if (data->getICQPhone() == plugin_status)
										break;
                                    data->setICQPhone(plugin_status);
									bChanged = true;
									break;
								default:
									if (plugin_index >= PLUGIN_NULL)
										log(L_WARN, "Unknown plugin sign (%04X %04X)", type, plugin_index);
							}
							break;

					}
				}
				else
				{
                    data->setInfoUpdateTime(infoUpdateTime);
                    data->setPluginInfoTime(pluginInfoTime);
                    data->setPluginStatusTime(pluginStatusTime);
                    if (    !m_client->getDisableAutoUpdate() 
                        && (!m_client->getInvisible() || data->getVisibleId())
                        && (m_client->getInvisible()  || data->getInvisibleId() == 0))
                    {
						if (infoUpdateTime == 0)
							infoUpdateTime = 1;
                        if (infoUpdateTime != data->getInfoFetchTime())
                            m_client->addFullInfoRequest(data->getUin());
                        if (   data->getPluginInfoTime() != data->getPluginInfoFetchTime() 
                            && data->getPluginInfoTime())
                            m_client->addPluginInfoRequest(data->getUin(), PLUGIN_QUERYxINFO);
                        if (   data->getPluginInfoTime() != data->getPluginInfoFetchTime() 
                            || data->getPluginStatusTime() != data->getPluginStatusFetchTime()){
                            if (data->getSharedFiles())
                            {
                                data->setSharedFiles(false);
								bChanged = true;
							}
                            if (data->getFollowMe())
                            {
                                data->setFollowMe(0);
								bChanged = true;
							}
                            if (data->getICQPhone())
                            {
                                data->setICQPhone(0);
								bChanged = true;
							}
                            if (data->getPluginStatusTime())
                                m_client->addPluginInfoRequest(data->getUin(), PLUGIN_QUERYxSTATUS);
						}
					}
				}
                if (data->getInvisible())
                {
                    data->setInvisible(false);
					bChanged = true;
				}
                if (bChanged)
                    EventContact(contact, EventContact::eChanged).process();
                if (data->getStatus() != prevStatus || bAwayChanged){
					unsigned status = STATUS_OFFLINE;
                    if ((data->getStatus() & 0xFFFF) != ICQ_STATUS_OFFLINE)
                    {
						status = STATUS_ONLINE;
                        if (data->getStatus() & ICQ_STATUS_DND)
                            status = STATUS_DND;
                        else if (data->getStatus() & ICQ_STATUS_OCCUPIED)
                            status = STATUS_OCCUPIED;
                        else if (data->getStatus() & ICQ_STATUS_NA)
                            status = STATUS_NA;
                        else if (data->getStatus() & ICQ_STATUS_AWAY)
                            status = STATUS_AWAY;
                        else if (data->getStatus() & ICQ_STATUS_FFC)
                            status = STATUS_FFC;
					}
                    if((status == STATUS_ONLINE) && (data->getClass() & CLASS_AWAY))
						status = STATUS_AWAY;
					StatusMessage *m = new StatusMessage();
					m->setContact(contact->id());
					m->setClient(m_client->dataName(data));
					m->setStatus(status);
					m->setFlags(MESSAGE_RECEIVED);
					EventMessageReceived e(m);
					if(!e.process())
						delete m;
                    if (    !contact->getIgnore() 
                        && (data->getClass() & CLASS_AWAY) == 0 
                        && ((data->getStatus() & 0xFF) == ICQ_STATUS_ONLINE && (prevStatus & 0xFF) != ICQ_STATUS_ONLINE || bAwayChanged) 
                        && ((prevStatus & 0xFFFF) != ICQ_STATUS_OFFLINE || data->getOnlineTime() > m_client->data.owner.getOnlineTime())
                        )
                    {
						EventContact e(contact, EventContact::eOnline);
						e.process();
					}
                    if (    !m_client->getDisableAutoReplyUpdate() 
                        && (data->getStatus() & 0xFF) != ICQ_STATUS_ONLINE 
                        && (!m_client->getInvisible() || data->getVisibleId()) 
                        && (m_client->getInvisible() || data->getInvisibleId() == 0)
                        )
                        m_client->addPluginInfoRequest(data->getUin(), PLUGIN_AR);
				}
			}
			break;
		}