Beispiel #1
0
void ICQClientPrivate::processMsgQueueSMS()
{
    list<ICQEvent*>::iterator it;
    for (it = msgQueue.begin(); it != msgQueue.end();){
        if ((sock == NULL) || (sock->isError())) return;
        ICQEvent *e = *it;
        if (e->message() == NULL){
            it++;
            continue;
        }
        if (e->message()->Type() != ICQ_MSGxSMS){
            it++;
            continue;
        }
        ICQSMS *msg = static_cast<ICQSMS*>(e->message());
        XmlBranch xmltree("icq_sms_message");
        string destination = "+";
        for (const char *p = msg->Phone.c_str(); *p; p++){
            if ((*p >= '0') && (*p <= '9'))
                destination += *p;
        }
        string text = msg->Message.c_str();
        client->translate("utf8", msg->Charset.c_str(), text);
        text = client->clearHTML(text);
        string sender = client->owner->name(true);
        char uin[13];
        snprintf(uin, sizeof(uin), "%lu", client->owner->Uin);
        xmltree.pushnode(new XmlLeaf("destination",destination));
        xmltree.pushnode(new XmlLeaf("text",text));
        xmltree.pushnode(new XmlLeaf("codepage","1252"));
        xmltree.pushnode(new XmlLeaf("encoding","utf8"));
        xmltree.pushnode(new XmlLeaf("senders_UIN",uin));
        xmltree.pushnode(new XmlLeaf("senders_name",sender));
        xmltree.pushnode(new XmlLeaf("delivery_receipt","Yes"));

        /* Time string, format: Wkd, DD Mnm YYYY HH:MM:SS TMZ */
        char timestr[30];
        time_t t;
        struct tm *tm;
        time(&t);
        tm = gmtime(&t);

        snprintf(timestr, sizeof(timestr), "%s, %02u %s %04u %02u:%02u:%02u GMT",
                 w_days[tm->tm_wday], tm->tm_mday, months[tm->tm_mon], tm->tm_year + 1900,
                 tm->tm_hour, tm->tm_min, tm->tm_sec);
        xmltree.pushnode(new XmlLeaf("time",string(timestr)));
        string xmlstr = xmltree.toString(0);

        serverRequest(ICQ_SRVxREQ_MORE);
        sock->writeBuffer << ICQ_SRVxREQ_SEND_SMS
        << 0x00010016L << 0x00000000L << 0x00000000L
        << 0x00000000L << 0x00000000L << (unsigned long)(xmlstr.size());
        sock->writeBuffer << xmlstr.c_str();
        sendServerRequest();
        msgQueue.remove(e);
        e->m_nId = m_nMsgSequence;
        varEvents.push_back(e);
        it = msgQueue.begin();
    }
}
Beispiel #2
0
void ICQClient::processMsgQueueSMS()
{
    list<ICQEvent*>::iterator it;
    for (it = msgQueue.begin(); it != msgQueue.end();){
        ICQEvent *e = *it;
        if (e->message() == NULL){
            it++;
            continue;
        }
        if (e->message()->Type() != ICQ_MSGxSMS){
            it++;
            continue;
        }
        ICQSMS *msg = static_cast<ICQSMS*>(e->message());
        XmlBranch xmltree("icq_sms_message");
        string destination = "+";
        for (const char *p = msg->Phone.c_str(); *p; p++){
            if ((*p >= '0') && (*p <= '9'))
                destination += *p;
        }
        string text = clearHTML(msg->Message.c_str());
        toUTF(text);
        string sender = name(true);
        char uin[13];
        snprintf(uin, sizeof(uin), "%lu", Uin());
        xmltree.pushnode(new XmlLeaf("destination",destination));
        xmltree.pushnode(new XmlLeaf("text",text));
        xmltree.pushnode(new XmlLeaf("codepage","1252"));
        xmltree.pushnode(new XmlLeaf("encoding","urf8"));
        xmltree.pushnode(new XmlLeaf("senders_UIN",uin));
        xmltree.pushnode(new XmlLeaf("senders_name",sender));
        xmltree.pushnode(new XmlLeaf("delivery_receipt","Yes"));

        /* Time string, format: Wkd, DD Mnm YYYY HH:MM:SS TMZ */
        char timestr[30];
        time_t t;
        struct tm *tm;
        time(&t);
        tm = gmtime(&t);
        strftime(timestr, 30, "%a, %d %b %Y %T %Z", tm);
        xmltree.pushnode(new XmlLeaf("time",string(timestr)));
        string xmlstr = xmltree.toString(0);

        serverRequest(ICQ_SRVxREQ_MORE);
        writeBuffer << ICQ_SRVxREQ_SEND_SMS
        << 0x00010016L << 0x00000000L << 0x00000000L
        << 0x00000000L << 0x00000000L << (unsigned long)(xmlstr.size());
        writeBuffer << xmlstr.c_str();
        sendServerRequest();
        msgQueue.remove(e);
        e->m_nId = m_nMsgSequence;
        varEvents.push_back(e);
        it = msgQueue.begin();
    }
}
Beispiel #3
0
void ICQClientPrivate::processMsgQueueAuth()
{
    list<ICQEvent*>::iterator it;
    for (it = msgQueue.begin(); it != msgQueue.end();){
        ICQEvent *e = *it;
        if (e->message() == NULL){
            msgQueue.remove(e);
            e->state = ICQEvent::Fail;
            client->process_event(e);
            it = msgQueue.begin();
            continue;
        }
        switch (e->message()->Type()){
        case ICQ_MSGxAUTHxREQUEST:{
                ICQAuthRequest *msg = static_cast<ICQAuthRequest*>(e->message());
                snac(ICQ_SNACxFAM_LISTS, ICQ_SNACxLISTS_REQUEST_AUTH);
                ICQUser *u = client->getUser(msg->getUin());
                sock->writeBuffer.packUin(msg->getUin());
                string message = client->clearHTML(msg->Message.c_str());
                client->toServer(message, u);
                sock->writeBuffer << (unsigned short)(message.length());
                sock->writeBuffer << message.c_str();
                sock->writeBuffer << (unsigned short)0;
                sendPacket();
                (*it)->state = ICQEvent::Success;
                break;
            }
        case ICQ_MSGxAUTHxGRANTED:{
                ICQAuthRequest *msg = static_cast<ICQAuthRequest*>(e->message());
                snac(ICQ_SNACxFAM_LISTS, ICQ_SNACxLISTS_AUTHxSEND);
                sock->writeBuffer.packUin(msg->getUin());
                sock->writeBuffer
                << (char)0x01
                << (unsigned long)0;
                sendPacket();
                (*it)->state = ICQEvent::Success;
                break;
            }
        case ICQ_MSGxAUTHxREFUSED:{
                ICQAuthRequest *msg = static_cast<ICQAuthRequest*>(e->message());
                snac(ICQ_SNACxFAM_LISTS, ICQ_SNACxLISTS_REQUEST_AUTH);
                ICQUser *u = client->getUser(msg->getUin());
                sock->writeBuffer.packUin(msg->getUin());
                string message = client->clearHTML(msg->Message.c_str());
                string original = message;
                client->toServer(message, u);
                sock->writeBuffer
                << (char) 0
                << message
                << (unsigned long)0x00010001;
                if (message == original){
                    sock->writeBuffer << (unsigned char)0;
                }else{
                    string charset = "utf-8";
                    sock->writeBuffer << charset;
                }
                sock->writeBuffer << (unsigned short)0;
                sendPacket();
                (*it)->state = ICQEvent::Success;
                break;
            }
        }
        if (e->state != ICQEvent::Success){
            it++;
            continue;
        }
        msgQueue.remove(e);
        client->process_event(e);
        it = msgQueue.begin();
    }
}
Beispiel #4
0
void ICQClientPrivate::snac_lists(unsigned short type, unsigned short seq)
{
    switch (type){
    case ICQ_SNACxLISTS_RIGHTS:
        log(L_DEBUG, "List rights");
        break;
    case ICQ_SNACxLISTS_ROSTER:{
            char c;
            unsigned short list_len;
            log(L_DEBUG,"Rosters");
            sock->readBuffer >> c;
            if (c){
                log(L_WARN, "Bad first roster byte %02X", c);
                break;
            }
            bool bIgnoreTime = false;
            vector<ICQGroup*>::iterator it_grp;
            list<ICQUser*>::iterator it_usr;
            if (!m_bRosters){
                m_bRosters = true;
                client->contacts.Invisible = 0;
                for (it_grp = client->contacts.groups.begin(); it_grp != client->contacts.groups.end(); it_grp++)
                    (*it_grp)->bChecked = false;
                for (it_usr = client->contacts.users.begin(); it_usr != client->contacts.users.end(); it_usr++){
                    if ((*it_usr)->Type != USER_TYPE_ICQ) continue;
                    (*it_usr)->Id = 0;
                    (*it_usr)->GrpId = 0;
                    (*it_usr)->IgnoreId = 0;
                    (*it_usr)->VisibleId = 0;
                    (*it_usr)->InvisibleId = 0;
                }
            }
            sock->readBuffer >> list_len;
            for (unsigned i = 0; i < list_len; i++){
                string str;
                unsigned short id, grp_id, type, len;
                sock->readBuffer.unpackStr(str);
                sock->readBuffer >> grp_id >> id >> type >> len;
                TlvList *inf = NULL;
                if (len){
                    Buffer b(len);
                    b.pack(sock->readBuffer.Data(sock->readBuffer.readPos()), len);
                    sock->readBuffer.incReadPos(len);
                    inf = new TlvList(b);
                }
                switch (type){
                case 0x0000: /* User */{
                        unsigned long uin = atol(str.c_str());
                        if (uin){
                            Tlv *tlv_name = NULL;
                            if (inf) tlv_name = (*inf)(0x0131);
                            string alias = tlv_name ? (char*)(*tlv_name) : "";
                            client->fromUTF(alias, client->owner->Encoding.c_str());
                            bool needAuth = false;
                            if (inf && (*inf)(0x0066)) needAuth = true;
                            ICQUser *user = client->getUser(uin, true);
                            user->Id = id;
                            user->GrpId = grp_id;
                            user->Alias = alias;
                            user->WaitAuth = needAuth;
                            Tlv *tlv_phone = NULL;
                            if (inf) tlv_phone = (*inf)(0x13A);
                            if (tlv_phone){
                                user->Phones.add(*tlv_phone, "Private cellular", SMS, true, false);
                                user->adjustPhones();
                            }
                        }else{
                            bIgnoreTime = true;
                        }
                        break;
                    }
                case ICQ_GROUPS:{
                        if (str.size() == 0) break;
                        client->fromUTF(str, client->owner->Encoding.c_str());
                        ICQGroup *grp = client->getGroup(grp_id, true);
                        if (grp == NULL){
                            grp = client->createGroup();
                            client->contacts.groups.push_back(grp);
                        }
                        grp->Id = grp_id;
                        grp->Name = str;
                        grp->bChecked = true;
                        break;
                    }
                case ICQ_VISIBLE_LIST:{
                        unsigned long uin = atol(str.c_str());
                        if (uin)
                            client->getUser(atol(str.c_str()), true)->VisibleId = id;
                        break;
                    }
                case ICQ_INVISIBLE_LIST:{
                        unsigned long uin = atol(str.c_str());
                        if (uin)
                            client->getUser(atol(str.c_str()), true)->InvisibleId = id;
                        break;
                    }
                case ICQ_IGNORE_LIST:{
                        unsigned long uin = atol(str.c_str());
                        if (uin)
                            client->getUser(atol(str.c_str()), true)->IgnoreId = id;
                        break;
                    }
                case ICQ_INVISIBLE_STATE:
                    client->contacts.Invisible = id;
                    break;
                case 0x0009:
                case 0x0011:
                case 0x0013:
                    break;
                default:
                    log(L_WARN,"Unknown roster type %04X", type);
                }
                if (inf) delete inf;
            }
            unsigned long time;
            sock->readBuffer >> time;
            if ((time == 0) && list_len && !bIgnoreTime)
                break;

            client->contacts.Time = time;
            for (;;){
                bool ok = true;
                for (it_grp = client->contacts.groups.begin(); it_grp != client->contacts.groups.end(); it_grp++){
                    if (!(*it_grp)->bChecked){
                        client->contacts.groups.erase(it_grp);
                        ok = false;
                        break;
                    }
                }
                if (ok) break;
            }
            for (it_usr = client->contacts.users.begin(); it_usr != client->contacts.users.end(); it_usr++){
                unsigned short grpId = (*it_usr)->GrpId;
                bool ok = false;
                for (it_grp = client->contacts.groups.begin(); it_grp != client->contacts.groups.end(); it_grp++){
                    if ((*it_grp)->Id == grpId){
                        ok = true;
                        break;
                    }
                }
                if (!ok) (*it_usr)->GrpId = 0;
            }
            ICQEvent e(EVENT_GROUP_CHANGED);
            client->process_event(&e);
            m_state = Logged;
        }
    case ICQ_SNACxLISTS_ROSTERxOK:	// FALLTHROUGH
        {
            log(L_DEBUG, "Rosters OK");
            snac(ICQ_SNACxFAM_LISTS, ICQ_SNACxLISTS_UNKNOWN);
            sendPacket();
            sendCapability();
            sendICMB();
            sendLogonStatus();
            sendClientReady();
            sendMessageRequest();
            sendPhoneStatus();
            if (client->owner->Nick.size() == 0){
                client->addInfoRequest(client->owner->Uin);
                client->searchByUin(client->owner->Uin);
            }
            list<ICQUser*>::iterator it;
            for (it = client->contacts.users.begin(); it != client->contacts.users.end(); it++){
                ICQUser *u = *it;
                if (u->IgnoreId) continue;
                if (u->Nick.size() || u->Alias.size()) continue;
                client->addInfoRequest(u->Uin);
            }
            if (client->contacts.groups.size() == 0){
                m_state = Logged;
                client->createGroup("General");
            }
            if (client->contacts.Invisible == 0){
                snac(ICQ_SNACxFAM_LISTS, ICQ_SNACxLISTS_EDIT);
                sendPacket();
                snac(ICQ_SNACxFAM_LISTS, ICQ_SNACxLISTS_CREATE, true);
                sock->writeBuffer
                << 0x00000000L << 0x00000001L
                << 0x000400C8L << (unsigned short)0;
                sendPacket();
                snac(ICQ_SNACxFAM_LISTS, ICQ_SNACxLISTS_SAVE);
                sendPacket();
            }
            break;
        }
    case ICQ_SNACxLISTS_ADDED:{
            sock->readBuffer.incReadPos(8);
            unsigned long uin = sock->readBuffer.unpackUin();
            ICQAddedToList *m = new ICQAddedToList;
            m->Uin.push_back(uin);
            messageReceived(m);
            break;
        }
    case ICQ_SNACxLISTS_AUTHxREQUEST:{
            sock->readBuffer.incReadPos(8);
            unsigned long uin = sock->readBuffer.unpackUin();
            ICQUser *u = client->getUser(uin);
            string message;
            string charset;
            unsigned short have_charset;
            sock->readBuffer.unpackStr(message);
            sock->readBuffer >> have_charset;
            if (have_charset){
                sock->readBuffer.incReadPos(2);
                sock->readBuffer.unpackStr(charset);
            }
            if (charset.size()){
                client->translate(client->localCharset(u), charset.c_str(), message);
            }else{
                client->fromServer(message, u);
            }
            log(L_DEBUG, "Auth request %lu", uin);

            ICQAuthRequest *m = new ICQAuthRequest;
            m->Uin.push_back(uin);
            m->Message = message;
            messageReceived(m);
            break;
        }
    case ICQ_SNACxLISTS_AUTH:{
            sock->readBuffer.incReadPos(8);
            unsigned long uin = sock->readBuffer.unpackUin();
            char auth_ok;
            sock->readBuffer >> auth_ok;
            string message;
            string charset;
            unsigned short have_charset;
            sock->readBuffer.unpackStr(message);
            sock->readBuffer >> have_charset;
            if (have_charset){
                sock->readBuffer.incReadPos(2);
                sock->readBuffer.unpackStr(charset);
            }
            ICQUser *u = client->getUser(uin);
            if (charset.size()){
                client->translate(client->localCharset(u), charset.c_str(), message);
            }else{
                client->fromServer(message, u);
            }
            log(L_DEBUG, "Auth %u %lu", auth_ok, uin);
            if (auth_ok){
                ICQUser *user = client->getUser(uin);
                if (user){
                    user->WaitAuth = false;
                    ICQEvent e(EVENT_INFO_CHANGED, uin);
                    client->process_event(&e);
                }
                ICQAuthGranted *m = new ICQAuthGranted();
                m->Uin.push_back(uin);
                messageReceived(m);
            }else{
                ICQAuthRefused *m = new ICQAuthRefused();
                m->Uin.push_back(uin);
                m->Message = message;
                messageReceived(m);
            }
            break;
        }
    case ICQ_SNACxLISTS_DONE:{
            ICQEvent *e = findListEvent(seq);
            if (e == NULL) break;
            sock->readBuffer.incReadPos(8);
            unsigned short res;
            sock->readBuffer >> res;
            e->processAnswer(this, sock->readBuffer, res);
            delete e;
            break;
        }
    default:
        log(L_WARN, "Unknown lists family type %04X", type);
    }
}
Beispiel #5
0
/*------------------------------------------------------------------------------
 * ProcessRunningEvent_tep
 *
 * Thread entry point to run an event.  First checks to see if the socket for
 * the given event needs to be connected and calls the relevant connection
 * function.  Then sends the event, retrying after a timeout.  If an ack is
 * received, the thread will be cancelled by the receiving thread.
 * 
 * The parameter is only used to get the CICQDaemon, the actual event is
 * now popped off the send queue to prevent packets being sent out of order
 * which is a severe error with OSCAR.
 *----------------------------------------------------------------------------*/
void *ProcessRunningEvent_Server_tep(void *p)
{
  pthread_detach(pthread_self());

  static unsigned short nNext = 0;
  static pthread_mutex_t send_mutex = PTHREAD_MUTEX_INITIALIZER;

  /* want to be cancelled immediately so we don't try to derefrence the event
     after it has been deleted */
  pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);

  DEBUG_THREADS("[ProcessRunningEvent_Server_tep] Caught event.\n");

  CICQDaemon *d = gLicqDaemon;

  if (!d) pthread_exit(NULL);

  // Must send packets in sequential order
  pthread_mutex_lock(&send_mutex);
  pthread_mutex_lock(&d->mutex_sendqueue_server);

  list<ICQEvent *>::iterator iter;
  ICQEvent *e = NULL;

  while (e == NULL)
  {

    for (iter = d->m_lxSendQueue_Server.begin();
         iter != d->m_lxSendQueue_Server.end(); iter++)
    {
      if ((*iter)->Channel() == ICQ_CHNxNEW)
      {
        e = *iter;
        nNext = e->Sequence() + 1;
        break;
      }

      if ((*iter)->Sequence() == nNext)
      {
        e = *iter;
        nNext++;
        break;
      }
    }

    if (e == NULL)
    {
      bool bEmpty = d->m_lxSendQueue_Server.empty();

      pthread_mutex_unlock(&d->mutex_sendqueue_server);
      pthread_mutex_unlock(&send_mutex);

      if (bEmpty)
        pthread_exit(NULL);

      struct timeval tv = { 1, 0 };
      select(0, NULL, NULL, NULL, &tv);
      pthread_mutex_lock(&send_mutex);
      pthread_mutex_lock(&d->mutex_sendqueue_server);
    }
    else
    {
      d->m_lxSendQueue_Server.erase(iter);

      if (e->m_bCancelled)
      {
        delete e;
        e = NULL;
      }
    }
  }

  pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);

  e->thread_send = pthread_self();
  e->thread_running = true;

  // Done reading the queue now
  pthread_mutex_unlock(&d->mutex_sendqueue_server);

  // declared here because pthread_cleanup_push starts a new block
  CBuffer *buf;
  bool sent = false;
  bool bExit = false;
  char szErrorBuf[128];

  pthread_cleanup_push(cleanup_mutex, &send_mutex);

    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    pthread_testcancel();

    int socket = -1;
    unsigned short nSequence;
    INetSocket *s;
    
    // Check if the socket is connected
    if (e->m_nSocketDesc == -1)
    {
      // Connect to the server if we are logging on
      if (e->m_pPacket->Channel() == ICQ_CHNxNEW)
      {
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
        gLog.Info(tr("%sConnecting to login server.\n"), L_SRVxSTR);

        pthread_t *t = new pthread_t;
        int *s = new int;
        pthread_create(t, NULL, ConnectToServer_tep, s);
        pthread_cleanup_push(cleanup_thread, t);
          pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
          pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
          pthread_testcancel();
          pthread_join(*t, NULL);
        pthread_cleanup_pop(0);
        int socket = *s;
        delete t;
        delete s;

        pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
        pthread_testcancel();

        e->m_nSocketDesc = socket;

        // Check again, if still -1, fail the event
        if (e->m_nSocketDesc == -1)
        {
          pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
          gLog.Info(tr("%sConnecting to login server failed, failing event\n"),
                    L_SRVxSTR);
          // we need to initialize the logon time for the next retry
          d->m_tLogonTime = time(NULL);
          d->m_eStatus = STATUS_OFFLINE_FORCED;
          d->m_bLoggingOn = false;
          if (d->DoneEvent(e, EVENT_ERROR) != NULL)
          {
            d->DoneExtendedEvent(e, EVENT_ERROR);
            d->ProcessDoneEvent(e);
          }
          else
          {
            pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
            pthread_testcancel();
            delete e;
          }
          bExit = true;
          goto exit_server_thread;
        }
      }
      else
      {
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
        gLog.Info(tr("%sNot connected to server, failing event\n"), L_SRVxSTR);
        if (d->DoneEvent(e, EVENT_ERROR) != NULL)
        {
          d->DoneExtendedEvent(e, EVENT_ERROR);
          d->ProcessDoneEvent(e);
        }
        else
        {
          pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
          pthread_testcancel();
          delete e;
        }
        bExit = true;
        goto exit_server_thread;
      }
    }

    socket = e->m_nSocketDesc;
    nSequence = e->m_nSequence;

    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
    // Start sending the event
    s = gSocketManager.FetchSocket(socket);
    if (s == NULL)
    {
      gLog.Warn(tr("%sSocket not connected or invalid (#%hu).\n"), L_WARNxSTR,
                nSequence);
      if (d->DoneEvent(e, EVENT_ERROR) != NULL)
      {
        d->DoneExtendedEvent(e, EVENT_ERROR);
        d->ProcessDoneEvent(e);
      }
      else
      {
        pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
        pthread_testcancel();
        delete e;
      }
      bExit = true;
      goto exit_server_thread;
    }

    pthread_cleanup_push(cleanup_socket, s);

      pthread_mutex_lock(&d->mutex_cancelthread);

      // check to make sure we were not cancelled already
      pthread_cleanup_push(cleanup_mutex, &d->mutex_cancelthread);
        pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
        pthread_testcancel();
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);

        //if we get here  then we haven't been cancelled and we won't be
        //as long as we hold mutex_cancelthread

        buf = e->m_pPacket->Finalize(NULL);

        pthread_mutex_unlock(&d->mutex_cancelthread);
      pthread_cleanup_pop(0); //mutex_cancelthread

      sent = s->Send(buf);
      delete buf;

      if (!sent)
      {
        s->ErrorStr(szErrorBuf, 128);
      }

      // We don't close the socket as it should be closed by the server thread
      gSocketManager.DropSocket(s);
    pthread_cleanup_pop(0); //socket

exit_server_thread:
    pthread_mutex_unlock(&send_mutex);
  pthread_cleanup_pop(0); //send_mutex

  if (bExit)
    pthread_exit(NULL);
    
  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
  pthread_testcancel();

  if (!sent)
  {
    unsigned short nSequence = e->m_nSequence;

    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);

    gLog.Warn(tr("%sError sending event (#%hu):\n%s%s.\n"), L_WARNxSTR,
              nSequence, L_BLANKxSTR, szErrorBuf);

    if (d->DoneEvent(e, EVENT_ERROR) != NULL)
    {
      d->DoneExtendedEvent(e, EVENT_ERROR);
      d->ProcessDoneEvent(e);
    }
    else
    {
      pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
      pthread_testcancel();
      delete e;
    }
  }
  else
  {
    if (e->m_NoAck)
    {
      pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
      // send successfully and we don't get an answer from the server
      if (d->DoneEvent(e, EVENT_ACKED) != NULL)
      {
        d->DoneExtendedEvent(e, EVENT_ACKED);
        d->ProcessDoneEvent(e);
      }
      else
      {
        pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
        pthread_testcancel();
        delete e;
      }
    }
    else
    {
      e->thread_running = false;
      // pthread_exit is not async cancel safe???
      pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
    }
  }

  pthread_exit(NULL);

  return NULL;
}
Beispiel #6
0
void *ProcessRunningEvent_Client_tep(void *p)
{
  pthread_detach(pthread_self());

  pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
  /* want to be cancelled immediately so we don't try to derefence the event
     after it has been deleted */
  pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);

  DEBUG_THREADS("[ProcessRunningEvent_Client_tep] Caught event.\n");

  ICQEvent *e = (ICQEvent *)p;

  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
  pthread_testcancel();

  CICQDaemon *d = e->m_pDaemon;

  // Check if the socket is connected
  if (e->m_nSocketDesc == -1)
  {
    unsigned long nDestinationUin = e->m_nDestinationUin;
    unsigned char nChannel = e->Channel();
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
   
    ICQUser *u = gUserManager.FetchUser(nDestinationUin, LOCK_R);
    if (u == NULL)
    {
      if (d->DoneEvent(e, EVENT_ERROR) != NULL)
        d->ProcessDoneEvent(e);
      else
      {
        pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
        pthread_testcancel();
        delete e;
      }
      pthread_exit(NULL);
    }

    unsigned long nVersion = u->Version();
    unsigned char nMode = u->Mode();
    unsigned short nRemotePort = u->Port();
    bool bSendIntIp = u->SendIntIp();
    gUserManager.DropUser(u);

    ICQOwner *o = gUserManager.FetchOwner(LOCK_R);
    unsigned long nIP = bSendIntIp ? o->IntIp() : o->Ip();
    unsigned short nLocalPort = o->Port();
    gUserManager.DropOwner();

    int socket = -1;
    if (!bSendIntIp && nVersion > 6 && nMode != MODE_DIRECT)
    {
      int nId = d->RequestReverseConnection(nDestinationUin, nChannel, nIP,
                                            nLocalPort, nRemotePort);
      if (nId != -1)
      {
        d->WaitForReverseConnection(nId, nDestinationUin);
        u = gUserManager.FetchUser(nDestinationUin, LOCK_R);
        if (u == NULL)
        {
          if (d->DoneEvent(e, EVENT_ERROR) != NULL)
            d->ProcessDoneEvent(e);
          else
          {
            pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
            pthread_testcancel();
            delete e;
          }
          pthread_exit(NULL);
        }
        socket = u->SocketDesc(nChannel);
        gUserManager.DropUser(u);
      }
      
      // if we failed, try direct anyway
      if (socket == -1)
      {
        pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
        pthread_testcancel();
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);

        socket = d->ConnectToUser(nDestinationUin, nChannel);
      }
    }
    else
    {
      socket = d->ConnectToUser(nDestinationUin, nChannel);

      // if we failed, try through server
      if (socket == -1)
      {
        pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
        pthread_testcancel();
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);

        int nId = d->RequestReverseConnection(nDestinationUin, nChannel, nIP,
                                              nLocalPort, nRemotePort);
        if (nId != -1)
        {
          d->WaitForReverseConnection(nId, nDestinationUin);
          u = gUserManager.FetchUser(nDestinationUin, LOCK_R);
          if (u == NULL)
          {
            if (d->DoneEvent(e, EVENT_ERROR) != NULL)
              d->ProcessDoneEvent(e);
            else
            {
              pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
              pthread_testcancel();
              delete e;
            }
            pthread_exit(NULL);
          }
          socket = u->SocketDesc(nChannel);
          gUserManager.DropUser(u);
        }
      }
    }

    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    pthread_testcancel();
    e->m_nSocketDesc = socket;
    // Check again, if still -1, fail the event
    if (e->m_nSocketDesc == -1)
    {
      pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
      if (d->DoneEvent(e, EVENT_ERROR) != NULL)
        d->ProcessDoneEvent(e);
      else
      {
        pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
        pthread_testcancel();
        delete e;
      }
      pthread_exit(NULL);
    }
  }

  int socket = e->m_nSocketDesc;
  pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
  INetSocket *s = gSocketManager.FetchSocket(socket);
  if (s == NULL)
  {
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    pthread_testcancel();
    unsigned short nSequence = e->m_nSequence;
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);

    gLog.Warn(tr("%sSocket %d does not exist (#%hu).\n"), L_WARNxSTR, socket,
       nSequence);
    if (d->DoneEvent(e, EVENT_ERROR) != NULL)
      d->ProcessDoneEvent(e);
    else
    {
      pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
      pthread_testcancel();
      delete e;
    }
    pthread_exit(NULL);
  }

  CBuffer *buf;
  bool sent;
  char szErrorBuf[128];
  pthread_cleanup_push(cleanup_socket, s);

    pthread_mutex_lock(&d->mutex_cancelthread);

    // check to make sure we were not cancelled already
    pthread_cleanup_push(cleanup_mutex, &d->mutex_cancelthread);
      pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
      pthread_testcancel();
      pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);

      //if we get here  then we haven't been cancelled and we won't be
      //as long as we hold mutex_cancelthread

      buf = e->m_pPacket->Finalize(s);

      pthread_mutex_unlock(&d->mutex_cancelthread);
    pthread_cleanup_pop(0);

    sent = s->Send(buf);

    if (!sent)
      s->ErrorStr(szErrorBuf, 128);

    gSocketManager.DropSocket(s);
  pthread_cleanup_pop(0);

  if (!sent)
  {
    // Close the socket, alert the socket thread
    gSocketManager.CloseSocket(socket);
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    pthread_testcancel();
    unsigned short nSequence = e->m_nSequence;
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);

    gLog.Warn(tr("%sError sending event (#%hu):\n%s%s.\n"), L_WARNxSTR,
     -nSequence, L_BLANKxSTR, szErrorBuf);
    write(d->pipe_newsocket[PIPE_WRITE], "S", 1);
    // Kill the event, do after the above as ProcessDoneEvent erase the event
    if (d->DoneEvent(e, EVENT_ERROR) != NULL)
      d->ProcessDoneEvent(e);
    else
    {
      pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
      pthread_testcancel();
      delete e;
    }
    pthread_exit(NULL);
  }
  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
  pthread_testcancel();

  e->thread_running = false;

  // pthread_exit is not async cancel safe???
  pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
  pthread_exit(NULL);
  // Avoid compiler warnings
  return NULL;
}
Beispiel #7
0
void ICQClient::snac_various(unsigned short type, unsigned short)
{
    switch (type){
    case ICQ_SNACxVAR_DATA:{
            TlvList tlv(readBuffer);
            if (tlv(0x0001) == NULL){
                log(L_WARN, "Bad server response");
                break;
            }
            Buffer msg(*tlv(1));
            unsigned short len, nType, nId;
            unsigned long own_uin;
            msg >> len >> own_uin >> nType >> nId;
            switch (nType){
            case ICQ_SRVxEND_OFFLINE_MSG:
                log(L_DEBUG, "End offline messages");
                serverRequest(ICQ_SRVxREQ_ACK_OFFLINE_MSG);
                sendServerRequest();
                break;
            case ICQ_SRVxOFFLINE_MSG:{
                    log(L_DEBUG, "Offline message");
                    unsigned long uin;
                    char type, flag;
                    struct tm sendTM;
                    memset(&sendTM, 0, sizeof(sendTM));
                    string message;
                    unsigned short year;
                    char month, day, hours, min;
                    msg >> uin
                    >> year >> month >> day >> hours >> min
                    >> type >> flag;
                    msg >> message;
                    uin = htonl(uin);
                    year = htons(year);
                    sendTM.tm_year = year-1900;
                    sendTM.tm_mon  = month-1;
                    sendTM.tm_mday = day;
                    sendTM.tm_hour = hours;
                    sendTM.tm_min  = min;
                    sendTM.tm_sec  = 0;
                    time_t send_time = mktime(&sendTM);
                    log(L_DEBUG, "Offline message %u [%08lX] %02X %02X %s", uin, uin, type & 0xFF, flag  & 0xFF, message.c_str());
                    ICQMessage *m = parseMessage(type, uin, message, msg, 0, 0, 0, 0);
                    if (m){
                        m->Time = (unsigned long)send_time;
                        messageReceived(m);
                    }
                    break;
                }
            case ICQ_SRVxANSWER_MORE:{
                    unsigned short nSubtype;
                    char nResult;
                    msg >> nSubtype >> nResult;
                    log(L_DEBUG, "Server answer %02X %04X", nResult & 0xFF, nSubtype);
                    if ((nResult == 0x32) || (nResult == 0x14) || (nResult == 0x1E)){
                        ICQEvent *e = findVarEvent(htons(nId));
                        if (e == NULL){
                            log(L_WARN, "Various event ID %04X not found (%X)", nId, nResult);
                            break;
                        }
                        e->failAnswer(this);
                        varEvents.remove(e);
                        delete e;
                        break;
                    }
                    ICQEvent *e = findVarEvent(htons(nId));
                    if (e == NULL){
                        log(L_WARN, "Various event ID %04X not found (%X)", nId, nResult);
                        break;
                    }
                    bool nDelete = e->processAnswer(this, msg, nSubtype);
                    if (nDelete){
                        log(L_DEBUG, "Delete event");
                        varEvents.remove(e);
                        delete e;
                    }
                    break;
                }
            default:
                log(L_WARN, "Unknown SNAC(15,03) response type %04X", nType);
            }
            break;
        }
    default:
        log(L_WARN, "Unknown various family type %04X", type);
    }
}
Beispiel #8
0
void ICQClient::snac_message(unsigned short type, unsigned short)
{
    switch (type){
    case ICQ_SNACxMSG_RIGHTSxGRANTED:
        log(L_DEBUG, "Message rights granted");
        break;
    case ICQ_SNACxMSG_ACK:
        log(L_DEBUG, "Ack message");
        break;
    case ICQ_SNACxMSG_AUTOREPLY:{
            unsigned long timestamp1, timestamp2;
            readBuffer >> timestamp1 >> timestamp2;
            readBuffer.incReadPos(2);
            unsigned long uin = readBuffer.unpackUin();
            readBuffer.incReadPos(6);
            unsigned long t1, t2;
            readBuffer >> t1 >> t2;
            unsigned short seq;
            readBuffer.incReadPos(0x0F);
            readBuffer >> seq;
            if ((t1 == 0) && (t2 == 0)){
                readBuffer.incReadPos(0x16);
                string answer;
                readBuffer >> answer;
                fromServer(answer);
                if (timestamp1 || timestamp2){
                    log(L_DEBUG, "Message declined %s", answer.c_str());
                    list<ICQEvent*>::iterator it;
                    for (it = processQueue.begin(); it != processQueue.end(); ++it){
                        ICQEvent *e = *it;
                        if (e->type() != EVENT_MESSAGE_SEND) continue;
                        ICQMessage *msg = e->message();
                        if (msg == NULL) continue;
                        if ((msg->Uin == uin) && (msg->timestamp1 == timestamp1) && (msg->timestamp2 == timestamp2)){
                            msg->DeclineReason = answer;
                            cancelMessage(msg, false);
                            break;
                        }
                    }
                    if (it == processQueue.end())
                        log(L_WARN, "Decline file answer: message not found");
                }else{
                    log(L_DEBUG, "[%X] Autoreply from %u %s", seq, uin, answer.c_str());
                    ICQUser *u = getUser(uin);
                    if (u) u->AutoReply = answer;
                    ICQEvent e(EVENT_STATUS_CHANGED, uin);
                    process_event(&e);
                    processResponseRequestQueue(seq);
                }
            }
            if ((t1 == 0xA0E93F37L) && (t2 == 0x4FE9D311L)){
                ICQUser *u = getUser(uin);
                if (u == NULL){
                    log(L_WARN, "Request info no my user %lu", uin);
                    return;
                }
                if (u->inIgnore()){
                    log(L_WARN, "Request info ignore user %lu", uin);
                    return;
                }

                readBuffer.incReadPos(0x1D);
                unsigned long cookie;
                readBuffer >> cookie;
                readBuffer.incReadPos(4);
                readBuffer.unpack(t1);
                if (t1 == 3){
                    u->PhoneBookTime = (unsigned long)htonl(cookie);
                    u->bPhoneChanged = false;
                    log(L_DEBUG, "[%X] Phone book info %u", seq, uin);
                    PhoneBook::iterator it;
                    PhonePtrList myNumbers;
                    for (it = u->Phones.begin(); it != u->Phones.end(); ++it){
                        PhoneInfo *phone = static_cast<PhoneInfo*>(*it);
                        if (!phone->MyInfo()) continue;
                        PhoneInfo *myPhone = new PhoneInfo;
                        *myPhone = *phone;
                        myNumbers.push_back(myPhone);
                    }
                    u->Phones.clear();
                    unsigned long nPhones;
                    readBuffer.unpack(nPhones);
                    for (unsigned i = 0; i < nPhones; i++){
                        PhoneInfo *phone = new PhoneInfo;
                        u->Phones.push_back(phone);
                        readBuffer.unpackStr32(phone->Name);
                        readBuffer.unpackStr32(phone->AreaCode);
                        readBuffer.unpackStr32(phone->Number);
                        readBuffer.unpackStr32(phone->Extension);
                        readBuffer.unpackStr32(phone->Country);
                        unsigned long type;
                        readBuffer.unpack(type);
                        if (type) phone->Active = true;
                        if (readBuffer.readPos() >= readBuffer.size()) break;
                    }
                    for (it = u->Phones.begin(); it != u->Phones.end(); it++){
                        PhoneInfo *phone = static_cast<PhoneInfo*>(*it);
                        string prop;
                        readBuffer.unpackStr32(prop);
                        Buffer b;
                        b.pack(prop.c_str(), prop.length());
                        b.unpack(phone->Type);
                        b.unpackStr32(phone->Provider);
                        if (readBuffer.readPos() >= readBuffer.size()) break;
                    }
                    for (;;){
                        for (it = u->Phones.begin(); it != u->Phones.end(); it++){
                            PhoneInfo *phone = static_cast<PhoneInfo*>(*it);
                            bool bOK = (phone->getNumber().length() > 0);
                            if (bOK && !*phone->Number.c_str()) bOK = false;
                            if (bOK)
                                for (const char *p = phone->Number.c_str(); *p; p++){
                                    if ((*p >= '0') && (*p <= '9')) continue;
                                    if ((*p == ' ') || (*p == '-')) continue;
                                    bOK = false;
                                    break;
                                }
                            if (bOK) continue;
                            u->Phones.remove(phone);
                            break;
                        }
                        if (it == u->Phones.end()) break;
                    }
                    u->adjustPhones();
                    u->Phones.add(myNumbers);
                    ICQEvent e(EVENT_INFO_CHANGED, uin);
                    process_event(&e);
                    processPhoneRequestQueue(seq);
                }
            }
            break;
        }
Beispiel #9
0
void ICQClient::snac_lists(unsigned short type, unsigned short seq)
{
    bool bFull = false;
    switch (type){
    case ICQ_SNACxLISTS_RIGHTS:
        log(L_DEBUG, "List rights");
        break;
    case ICQ_SNACxLISTS_ROSTER:{
            char c;
            unsigned short list_len;
            log(L_DEBUG,"Rosters");
            if (m_bRosters){
                log(L_DEBUG, "Rosters part 2");
                break;
            }
            readBuffer >> c;
            if (c){
                log(L_WARN, "Bad first roster byte %02X", c);
                break;
            }
            vector<ICQGroup*>::iterator it_grp;
            list<ICQUser*>::iterator it_usr;
            for (it_grp = contacts.groups.begin(); it_grp != contacts.groups.end(); it_grp++)
                (*it_grp)->bChecked = false;
            for (it_usr = contacts.users.begin(); it_usr != contacts.users.end(); it_usr++){
                if ((*it_usr)->Type != USER_TYPE_ICQ) continue;
                (*it_usr)->Id = 0;
                (*it_usr)->GrpId = 0;
                (*it_usr)->inIgnore = false;
                (*it_usr)->inVisible = false;
                (*it_usr)->inInvisible = false;
            }
            readBuffer >> list_len;
            for (unsigned i = 0; i < list_len; i++){
                string str;
                unsigned short id, grp_id, type, len;
                readBuffer.unpackStr(str);
                readBuffer >> grp_id >> id >> type >> len;
                TlvList *inf = NULL;
                if (len){
                    Buffer b(len);
                    b.pack(readBuffer.Data(readBuffer.readPos()), len);
                    readBuffer.incReadPos(len);
                    inf = new TlvList(b);
                }
                switch (type){
                case 0x0000: /* User */{
                        unsigned long uin = atol(str.c_str());
                        if (uin == 0){
                            log(L_WARN, "Bad uin record %s\n", str.c_str());
                            break;
                        }
                        Tlv *tlv_name = NULL;
                        if (inf) tlv_name = (*inf)(0x0131);
                        string alias = tlv_name ? (char*)(*tlv_name) : "";
                        fromUTF(alias);
                        bool needAuth = false;
                        if (inf && (*inf)(0x0066)) needAuth = true;
                        ICQUser *user = getUser(uin, true);
                        user->Id = id;
                        user->GrpId = grp_id;
                        user->Alias = alias;
                        user->WaitAuth = needAuth;
                        break;
                    }
                case ICQ_GROUPS:{
                        if (str.size() == 0) break;
                        fromUTF(str);
                        ICQGroup *grp = getGroup(grp_id, true);
                        if (grp == NULL){
                            grp = new ICQGroup();
                            contacts.groups.push_back(grp);
                        }
                        grp->Id = grp_id;
                        grp->Name = str;
                        grp->bChecked = true;
                        break;
                    }
                case ICQ_VISIBLE_LIST:{
                        unsigned long uin = atol(str.c_str());
                        if (uin)
                            getUser(atol(str.c_str()), true)->inVisible = true;
                        break;
                    }
                case ICQ_INVISIBLE_LIST:{
                        unsigned long uin = atol(str.c_str());
                        if (uin)
                            getUser(atol(str.c_str()), true)->inInvisible = true;
                        break;
                    }
                case ICQ_IGNORE_LIST:{
                        unsigned long uin = atol(str.c_str());
                        if (uin)
                            getUser(atol(str.c_str()), true)->inIgnore = true;
                        break;
                    }
                case ICQ_INVISIBLE_STATE:
                    contacts.Invisible = id;
                    break;
                case 0x0009:
                    break;
                default:
                    log(L_WARN,"Unknown roster type %04X", type);
                }
                if (inf) delete inf;
            }
            unsigned long time;
            readBuffer >> time;
            contacts.Time = time;
            for (;;){
                bool ok = true;
                for (it_grp = contacts.groups.begin(); it_grp != contacts.groups.end(); it_grp++){
                    if (!(*it_grp)->bChecked){
                        contacts.groups.erase(it_grp);
                        ok = false;
                        break;
                    }
                }
                if (ok) break;
            }
            for (it_usr = contacts.users.begin(); it_usr != contacts.users.end(); it_usr++){
                unsigned short grpId = (*it_usr)->GrpId();
                bool ok = false;
                for (it_grp = contacts.groups.begin(); it_grp != contacts.groups.end(); it_grp++){
                    if ((*it_grp)->Id() == grpId){
                        ok = true;
                        break;
                    }
                }
                if (!ok) (*it_usr)->GrpId = 0;
            }
            ICQEvent e(EVENT_GROUP_CHANGED);
            process_event(&e);
            m_state = Logged;
            bFull = true;
        }
    case ICQ_SNACxLISTS_ROSTERxOK:	// FALLTHROUGH
        {
            m_bRosters = true;
            log(L_DEBUG, "Rosters OK");
            snac(ICQ_SNACxFAM_LISTS, ICQ_SNACxLISTS_UNKNOWN);
            sendPacket();
            sendCapability();
            sendICMB();
            sendLogonStatus();
            sendClientReady();
            sendMessageRequest();
            sendPhoneInit();
            sendPhoneStatus();
            if (bFull || (Nick.size() == 0)){
                addInfoRequest(Uin);
                searchByUin(Uin);
            }
            list<ICQUser*>::iterator it;
            for (it = contacts.users.begin(); it != contacts.users.end(); it++){
                if ((*it)->inIgnore()) continue;
                if (!bFull && (*it)->Nick.size()) continue;
                addInfoRequest((*it)->Uin);
            }
            if (contacts.groups.size() == 0){
                m_state = Logged;
                createGroup("General");
            }
            break;
        }
    case ICQ_SNACxLISTS_ADDED:{
            readBuffer.incReadPos(8);
            unsigned long uin = readBuffer.unpackUin();
            ICQAddedToList *m = new ICQAddedToList;
            m->Uin.push_back(uin);
            messageReceived(m);
            break;
        }
    case ICQ_SNACxLISTS_AUTHxREQUEST:{
            readBuffer.incReadPos(8);
            unsigned long uin = readBuffer.unpackUin();
            ICQUser *u = getUser(uin);
            string message;
            string charset;
            unsigned short have_charset;
            readBuffer.unpackStr(message);
            readBuffer >> have_charset;
            if (have_charset){
                readBuffer.incReadPos(2);
                readBuffer.unpackStr(charset);
            }
            if (charset.size()){
                translate(localCharset(u), charset.c_str(), message);
            }else{
                fromServer(message, u);
            }
            log(L_DEBUG, "Auth request %lu", uin);

            ICQAuthRequest *m = new ICQAuthRequest;
            m->Uin.push_back(uin);
            m->Message = message;
            messageReceived(m);
            break;
        }
    case ICQ_SNACxLISTS_AUTH:{
            readBuffer.incReadPos(8);
            unsigned long uin = readBuffer.unpackUin();
            char auth_ok; readBuffer >> auth_ok;
            string message;
            string charset;
            unsigned short have_charset;
            readBuffer.unpackStr(message);
            readBuffer >> have_charset;
            if (have_charset){
                readBuffer.incReadPos(2);
                readBuffer.unpackStr(charset);
            }
            ICQUser *u = getUser(uin);
            if (charset.size()){
                translate(localCharset(u), charset.c_str(), message);
            }else{
                fromServer(message, u);
            }
            log(L_DEBUG, "Auth %u %lu", auth_ok, uin);
            if (auth_ok){
                ICQUser *user = getUser(uin);
                if (user){
                    user->WaitAuth = false;
                    ICQEvent e(EVENT_INFO_CHANGED, uin);
                    process_event(&e);
                }
                ICQAuthGranted *m = new ICQAuthGranted();
                m->Uin.push_back(uin);
                messageReceived(m);
            }else{
                ICQAuthRefused *m = new ICQAuthRefused();
                m->Uin.push_back(uin);
                m->Message = message;
                messageReceived(m);
            }
            break;
        }
    case ICQ_SNACxLISTS_DONE:{
            ICQEvent *e = findListEvent(seq);
            if (e == NULL) break;
            readBuffer.incReadPos(8);
            unsigned short res;
            readBuffer >> res;
            e->processAnswer(this, readBuffer, res);
            delete e;
            break;
        }
    default:
        log(L_WARN, "Unknown lists family type %04X", type);
    }
}