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