int CJabberProto::OnContactDeleted( WPARAM wParam, LPARAM ) { if( !m_bJabberOnline ) // should never happen return 0; DBVARIANT dbv; if ( !JGetStringT(( HANDLE ) wParam, JGetByte( (HANDLE ) wParam, "ChatRoom", 0 )?(char*)"ChatRoomID":(char*)"jid", &dbv )) { if ( ListExist( LIST_ROSTER, dbv.ptszVal )) { if ( !_tcschr( dbv.ptszVal, _T( '@' ))) { TCHAR szStrippedJid[JABBER_MAX_JID_LEN]; JabberStripJid( m_ThreadInfo->fullJID, szStrippedJid, SIZEOF(szStrippedJid) ); TCHAR *szDog = _tcschr( szStrippedJid, _T('@')); if ( szDog && _tcsicmp( szDog + 1, dbv.ptszVal )) m_ThreadInfo->send( XmlNodeIq( _T("set"), SerialNext(), dbv.ptszVal ) << XQUERY( _T(JABBER_FEAT_REGISTER)) << XCHILD( _T("remove"))); } // Remove from roster, server also handles the presence unsubscription process. m_ThreadInfo->send( XmlNodeIq( _T("set"), SerialNext()) << XQUERY( _T(JABBER_FEAT_IQ_ROSTER)) << XCHILD( _T("item")) << XATTR( _T("jid"), dbv.ptszVal ) << XATTR( _T("subscription"), _T("remove"))); } JFreeVariant( &dbv ); } return 0; }
int CJabberProto::OnContactDeleted(WPARAM wParam, LPARAM) { if (!m_bJabberOnline) // should never happen return 0; HANDLE hContact = (HANDLE)wParam; ptrT jid(getTStringA(hContact, isChatRoom(hContact) ? "ChatRoomID" : "jid")); if (jid == NULL) return 0; if (ListGetItemPtr(LIST_ROSTER, jid)) { if (!_tcschr(jid, _T('@'))) { TCHAR szStrippedJid[JABBER_MAX_JID_LEN]; JabberStripJid(m_ThreadInfo->fullJID, szStrippedJid, SIZEOF(szStrippedJid)); TCHAR *szDog = _tcschr(szStrippedJid, _T('@')); if (szDog && _tcsicmp(szDog + 1, jid)) m_ThreadInfo->send(XmlNodeIq(_T("set"), SerialNext(), jid) << XQUERY(JABBER_FEAT_REGISTER) << XCHILD(_T("remove"))); } // Remove from roster, server also handles the presence unsubscription process. m_ThreadInfo->send(XmlNodeIq(_T("set"), SerialNext()) << XQUERY(JABBER_FEAT_IQ_ROSTER) << XCHILD(_T("item")) << XATTR(_T("jid"), jid) << XATTR(_T("subscription"), _T("remove"))); } return 0; }
INT_PTR __cdecl CJabberProto::JabberGetAvatarInfo(WPARAM wParam, LPARAM lParam) { if (!m_options.EnableAvatars) return GAIR_NOAVATAR; PROTO_AVATAR_INFORMATIONT* AI = (PROTO_AVATAR_INFORMATIONT*)lParam; ptrA szHashValue( getStringA(AI->hContact, "AvatarHash")); if (szHashValue == NULL) { debugLogA("No avatar"); return GAIR_NOAVATAR; } TCHAR tszFileName[MAX_PATH]; GetAvatarFileName(AI->hContact, tszFileName, SIZEOF(tszFileName)); _tcsncpy(AI->filename, tszFileName, SIZEOF(AI->filename)); AI->format = (AI->hContact == NULL) ? PA_FORMAT_PNG : getByte(AI->hContact, "AvatarType", 0); if (::_taccess(AI->filename, 0) == 0) { ptrA szSavedHash( getStringA(AI->hContact, "AvatarSaved")); if (szSavedHash != NULL && !strcmp(szSavedHash, szHashValue)) { debugLogA("Avatar is Ok: %s == %s", szSavedHash, szHashValue); return GAIR_SUCCESS; } } if ((wParam & GAIF_FORCE) != 0 && AI->hContact != NULL && m_bJabberOnline) { ptrT tszJid( getTStringA(AI->hContact, "jid")); if (tszJid != NULL) { JABBER_LIST_ITEM *item = ListGetItemPtr(LIST_ROSTER, tszJid); if (item != NULL) { BOOL isXVcard = getByte(AI->hContact, "AvatarXVcard", 0); TCHAR szJid[JABBER_MAX_JID_LEN]; szJid[0] = 0; if (item->arResources.getCount() != NULL && !isXVcard) if (TCHAR *bestResName = ListGetBestClientResourceNamePtr(tszJid)) mir_sntprintf(szJid, SIZEOF(szJid), _T("%s/%s"), tszJid, bestResName); if (szJid[0] == 0) _tcsncpy_s(szJid, SIZEOF(szJid), tszJid, _TRUNCATE); debugLogA("Rereading %s for %S", isXVcard ? JABBER_FEAT_VCARD_TEMP : JABBER_FEAT_AVATAR, szJid); m_ThreadInfo->send((isXVcard) ? XmlNodeIq( AddIQ(&CJabberProto::OnIqResultGetVCardAvatar, JABBER_IQ_TYPE_GET, szJid)) << XCHILDNS(_T("vCard"), JABBER_FEAT_VCARD_TEMP) : XmlNodeIq( AddIQ(&CJabberProto::OnIqResultGetClientAvatar, JABBER_IQ_TYPE_GET, szJid)) << XQUERY(JABBER_FEAT_AVATAR)); return GAIR_WAITFOR; } } } debugLogA("No avatar"); return GAIR_NOAVATAR; }
void CJabberProto::IbbSendThread( JABBER_IBB_TRANSFER *jibb ) { Log( "Thread started: type=ibb_send" ); jibb->hEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); jibb->bStreamInitialized = FALSE; jibb->bStreamClosed = FALSE; jibb->state = JIBB_SENDING; m_ThreadInfo->send( XmlNodeIq( m_iqManager.AddHandler( &CJabberProto::OnIbbInitiateResult, JABBER_IQ_TYPE_SET, jibb->dstJID, 0, -1, jibb )) << XCHILDNS( _T("open"), _T(JABBER_FEAT_IBB)) << XATTR( _T("sid"), jibb->sid ) << XATTRI( _T("block-size"), JABBER_IBB_BLOCK_SIZE ) << XATTR( _T("stanza"), _T("message"))); WaitForSingleObject( jibb->hEvent, INFINITE ); CloseHandle( jibb->hEvent ); jibb->hEvent = NULL; if ( jibb->bStreamInitialized ) { jibb->wPacketId = 0; BOOL bSent = (this->*jibb->pfnSend)( JABBER_IBB_BLOCK_SIZE, jibb->ft ); if ( !jibb->bStreamClosed ) { jibb->hEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); m_ThreadInfo->send( XmlNodeIq( m_iqManager.AddHandler( &CJabberProto::OnIbbCloseResult, JABBER_IQ_TYPE_SET, jibb->dstJID, 0, -1, jibb )) << XCHILDNS( _T("close"), _T(JABBER_FEAT_IBB)) << XATTR( _T("sid"), jibb->sid )); WaitForSingleObject( jibb->hEvent, INFINITE ); CloseHandle( jibb->hEvent ); jibb->hEvent = NULL; if ( jibb->bStreamClosed && bSent ) jibb->state = JIBB_DONE; } else { jibb->state = JIBB_ERROR; } } (this->*jibb->pfnFinal)(( jibb->state==JIBB_DONE )?TRUE:FALSE, jibb->ft ); jibb->ft = NULL; JabberIbbFreeJibb( jibb ); }
int CJabberProto::SearchRenewFields(HWND hwndDlg, JabberSearchData * dat) { TCHAR szServerName[100]; EnableWindow(GetDlgItem(hwndDlg, IDC_GO),FALSE); GetDlgItemText(hwndDlg,IDC_SERVER,szServerName,SIZEOF(szServerName)); dat->CurrentHeight = 0; dat->curPos = 0; SetScrollPos( GetDlgItem( hwndDlg, IDC_VSCROLL ), SB_CTL, 0, FALSE ); JabberSearchFreeData( hwndDlg, dat ); JabberSearchRefreshFrameScroll( hwndDlg, dat ); if ( m_bJabberOnline ) SetDlgItemText(hwndDlg,IDC_INSTRUCTIONS,TranslateT("Please wait...\r\nConnecting search server...")); else SetDlgItemText(hwndDlg,IDC_INSTRUCTIONS,TranslateT("You have to be connected to server")); if ( !m_bJabberOnline ) return 0; searchHandleDlg = hwndDlg; int iqId = SerialNext(); IqAdd( iqId, IQ_PROC_GETSEARCHFIELDS, &CJabberProto::OnIqResultGetSearchFields ); m_ThreadInfo->send( XmlNodeIq( _T("get"), iqId, szServerName ) << XQUERY( _T("jabber:iq:search"))); return iqId; }
void __cdecl CJabberProto::IbbReceiveThread(JABBER_IBB_TRANSFER *jibb) { debugLogA("Thread started: type=ibb_recv"); filetransfer *ft = jibb->ft; jibb->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); jibb->bStreamClosed = FALSE; jibb->wPacketId = 0; jibb->dwTransferredSize = 0; jibb->state = JIBB_RECVING; WaitForSingleObject(jibb->hEvent, INFINITE); CloseHandle(jibb->hEvent); jibb->hEvent = NULL; if (jibb->state == JIBB_ERROR) m_ThreadInfo->send( XmlNodeIq(_T("set"), SerialNext(), jibb->dstJID) << XCHILDNS(_T("close"), JABBER_FEAT_IBB) << XATTR(_T("sid"), jibb->sid)); if (jibb->bStreamClosed && jibb->dwTransferredSize == ft->dwExpectedRecvFileSize) jibb->state = JIBB_DONE; (this->*jibb->pfnFinal)((jibb->state==JIBB_DONE)?TRUE:FALSE, jibb->ft); jibb->ft = NULL; ListRemove(LIST_FTRECV, jibb->sid); JabberIbbFreeJibb(jibb); }
// last activity (XEP-0012) support BOOL CJabberProto::OnIqRequestLastActivity(HXML, CJabberIqInfo *pInfo) { m_ThreadInfo->send( XmlNodeIq(_T("result"), pInfo) << XQUERY(JABBER_FEAT_LAST_ACTIVITY) << XATTRI(_T("seconds"), m_tmJabberIdleStartTime ? time(0) - m_tmJabberIdleStartTime : 0)); return TRUE; }
void CJabberDlgBookmarks::UpdateData() { if (!m_proto->m_bJabberOnline) return; m_proto->m_ThreadInfo->send( XmlNodeIq( m_proto->AddIQ(&CJabberProto::OnIqResultDiscoBookmarks, JABBER_IQ_TYPE_GET)) << XQUERY(JABBER_FEAT_PRIVATE_STORAGE) << XCHILDNS(_T("storage"), _T("storage:bookmarks"))); }
int CJabberProto::SendGetVcard(const TCHAR *jid) { if (!m_bJabberOnline) return 0; CJabberIqInfo *pInfo = AddIQ(&CJabberProto::OnIqResultGetVcard, JABBER_IQ_TYPE_GET, jid); m_ThreadInfo->send(XmlNodeIq(pInfo) << XCHILDNS(_T("vCard"), JABBER_FEAT_VCARD_TEMP) << XATTR(_T("prodid"), _T("-//HandGen//NONSGML vGen v1.0//EN")) << XATTR(_T("version"), _T("2.0"))); return pInfo->GetIqId(); }
BOOL CJabberProto::OnFtHandleIbbIq(HXML iqNode, CJabberIqInfo *pInfo) { if (!mir_tstrcmp(pInfo->GetChildNodeName(), _T("open"))) FtHandleIbbRequest(iqNode, TRUE); else if (!mir_tstrcmp(pInfo->GetChildNodeName(), _T("close"))) FtHandleIbbRequest(iqNode, FALSE); else if (!mir_tstrcmp(pInfo->GetChildNodeName(), _T("data"))) { BOOL bOk = FALSE; const TCHAR *sid = XmlGetAttrValue(pInfo->GetChildNode(), _T("sid")); const TCHAR *seq = XmlGetAttrValue(pInfo->GetChildNode(), _T("seq")); if (sid && seq && XmlGetText(pInfo->GetChildNode())) bOk = OnIbbRecvdData(XmlGetText(pInfo->GetChildNode()), sid, seq); if (bOk) m_ThreadInfo->send( XmlNodeIq(_T("result"), pInfo)); else m_ThreadInfo->send( XmlNodeIq(_T("error"), pInfo) << XCHILD(_T("error")) << XATTRI(_T("code"), 404) << XATTR(_T("type"), _T("cancel")) << XCHILDNS(_T("item-not-found"), _T("urn:ietf:params:xml:ns:xmpp-stanzas"))); } return TRUE; }
virtual void OnInitDialog() { EnableWindow(GetParent(m_hwnd), FALSE); m_proto->m_hwndAgentRegInput = m_hwnd; SetWindowText(m_hwnd, TranslateT("Jabber Agent Registration")); SetDlgItemText(m_hwnd, IDC_SUBMIT, TranslateT("Register")); SetDlgItemText(m_hwnd, IDC_FRAME_TEXT, TranslateT("Please wait...")); m_proto->m_ThreadInfo->send( XmlNodeIq( m_proto->AddIQ(&CJabberProto::OnIqResultGetRegister, JABBER_IQ_TYPE_GET, m_jid)) << XQUERY(JABBER_FEAT_REGISTER)); // Enable WS_EX_CONTROLPARENT on IDC_FRAME (so tab stop goes through all its children) LONG_PTR frameExStyle = GetWindowLongPtr(GetDlgItem(m_hwnd, IDC_FRAME), GWL_EXSTYLE); frameExStyle |= WS_EX_CONTROLPARENT; SetWindowLongPtr(GetDlgItem(m_hwnd, IDC_FRAME), GWL_EXSTYLE, frameExStyle); }
void CJabberProto::OnIqResultGetCollectionList(HXML iqNode, CJabberIqInfo*) { const TCHAR *to = xmlGetAttrValue(iqNode, _T("to")); if (to == NULL || mir_tstrcmp( xmlGetAttrValue(iqNode, _T("type")), _T("result"))) return; HXML list = xmlGetChild(iqNode, "list"); if (!list || mir_tstrcmp( xmlGetAttrValue(list, _T("xmlns")), JABBER_FEAT_ARCHIVE)) return; MCONTACT hContact = NULL; time_t tmLast = 0; for (int nodeIdx = 1; ; nodeIdx++) { HXML itemNode = xmlGetNthChild(list, _T("chat"), nodeIdx); if (!itemNode) break; const TCHAR* start = xmlGetAttrValue(itemNode, _T("start")); const TCHAR* with = xmlGetAttrValue(itemNode, _T("with")); if (!start || !with) continue; if (hContact == NULL) { if ((hContact = HContactFromJID(with)) == NULL) continue; tmLast = getDword(hContact, "LastCollection", 0); } m_ThreadInfo->send( XmlNodeIq( AddIQ(&CJabberProto::OnIqResultGetCollection, JABBER_IQ_TYPE_GET)) << XCHILDNS( _T("retrieve"), JABBER_FEAT_ARCHIVE) << XATTR(_T("with"), with) << XATTR(_T("start"), start)); time_t tmThis = str2time(start); if ( tmThis > tmLast) { tmLast = tmThis; setDword(hContact, "LastCollection", tmLast+1); } } }
BOOL CJabberProto::OnHandleDiscoInfoRequest(HXML iqNode, CJabberIqInfo *pInfo) { if (!pInfo->GetChildNode()) return TRUE; const TCHAR *szNode = XmlGetAttrValue(pInfo->GetChildNode(), _T("node")); // caps hack if (m_clientCapsManager.HandleInfoRequest(iqNode, pInfo, szNode)) return TRUE; // ad-hoc hack: if (szNode && m_adhocManager.HandleInfoRequest(iqNode, pInfo, szNode)) return TRUE; // another request, send empty result m_ThreadInfo->send( XmlNodeIq(_T("error"), pInfo) << XCHILD(_T("error")) << XATTRI(_T("code"), 404) << XATTR(_T("type"), _T("cancel")) << XCHILDNS(_T("item-not-found"), _T("urn:ietf:params:xml:ns:xmpp-stanzas"))); return TRUE; }
BOOL CJabberProto::OnIqRequestAvatar(HXML, CJabberIqInfo *pInfo) { if (!m_options.EnableAvatars) return TRUE; int pictureType = m_options.AvatarType; if (pictureType == PA_FORMAT_UNKNOWN) return TRUE; TCHAR *szMimeType; switch (pictureType) { case PA_FORMAT_JPEG: szMimeType = _T("image/jpeg"); break; case PA_FORMAT_GIF: szMimeType = _T("image/gif"); break; case PA_FORMAT_PNG: szMimeType = _T("image/png"); break; case PA_FORMAT_BMP: szMimeType = _T("image/bmp"); break; default: return TRUE; } TCHAR szFileName[MAX_PATH]; GetAvatarFileName(NULL, szFileName, _countof(szFileName)); FILE* in = _tfopen(szFileName, _T("rb")); if (in == NULL) return TRUE; long bytes = _filelength(_fileno(in)); ptrA buffer((char*)mir_alloc(bytes * 4 / 3 + bytes + 1000)); if (buffer == NULL) { fclose(in); return TRUE; } fread(buffer, bytes, 1, in); fclose(in); ptrA str(mir_base64_encode((PBYTE)(char*)buffer, bytes)); m_ThreadInfo->send(XmlNodeIq(_T("result"), pInfo) << XQUERY(JABBER_FEAT_AVATAR) << XCHILD(_T("query"), _A2T(str)) << XATTR(_T("mimetype"), szMimeType)); return TRUE; }
int CJabberProto::SearchRenewFields(HWND hwndDlg, JabberSearchData * dat) { TCHAR szServerName[100]; EnableWindow(GetDlgItem(hwndDlg, IDC_GO),FALSE); GetDlgItemText(hwndDlg,IDC_SERVER,szServerName,SIZEOF(szServerName)); dat->CurrentHeight = 0; dat->curPos = 0; SetScrollPos(GetDlgItem(hwndDlg, IDC_VSCROLL), SB_CTL, 0, FALSE); JabberSearchFreeData(hwndDlg, dat); JabberSearchRefreshFrameScroll(hwndDlg, dat); SetDlgItemText(hwndDlg,IDC_INSTRUCTIONS,m_bJabberOnline ? TranslateT("Please wait...\r\nConnecting search server...") : TranslateT("You have to be connected to server")); if (!m_bJabberOnline) return 0; searchHandleDlg = hwndDlg; CJabberIqInfo *pInfo = AddIQ(&CJabberProto::OnIqResultGetSearchFields, JABBER_IQ_TYPE_GET, szServerName); m_ThreadInfo->send( XmlNodeIq(pInfo) << XQUERY(_T("jabber:iq:search"))); return pInfo->GetIqId(); }
void CJabberProto::EnableArchive(bool bEnable) { m_ThreadInfo->send( XmlNodeIq(_T("set"), SerialNext()) << XCHILDNS( _T("auto"), JABBER_FEAT_ARCHIVE) << XATTR(_T("save"), (bEnable) ? _T("true") : _T("false"))); }
JabberCapsBits CJabberProto::GetResourceCapabilites(const TCHAR *jid, BOOL appendBestResource) { TCHAR fullJid[JABBER_MAX_JID_LEN]; if (appendBestResource) GetClientJID(jid, fullJid, SIZEOF(fullJid)); else _tcsncpy(fullJid, jid, SIZEOF(fullJid)); pResourceStatus r(ResourceInfoFromJID(fullJid)); if (r == NULL) return JABBER_RESOURCE_CAPS_ERROR; // XEP-0115 mode if (r->m_tszCapsNode && r->m_tszCapsVer) { JabberCapsBits jcbCaps = 0, jcbExtCaps = 0; BOOL bRequestSent = FALSE; JabberCapsBits jcbMainCaps = m_clientCapsManager.GetClientCaps(r->m_tszCapsNode, r->m_tszCapsVer); if (jcbMainCaps == JABBER_RESOURCE_CAPS_TIMEOUT && !r->m_dwDiscoInfoRequestTime) jcbMainCaps = JABBER_RESOURCE_CAPS_ERROR; if (jcbMainCaps == JABBER_RESOURCE_CAPS_UNINIT) { // send disco#info query CJabberIqInfo *pInfo = AddIQ(&CJabberProto::OnIqResultCapsDiscoInfo, JABBER_IQ_TYPE_GET, fullJid, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_CHILD_TAG_NODE); pInfo->SetTimeout(JABBER_RESOURCE_CAPS_QUERY_TIMEOUT); m_clientCapsManager.SetClientCaps(r->m_tszCapsNode, r->m_tszCapsVer, JABBER_RESOURCE_CAPS_IN_PROGRESS, pInfo->GetIqId()); r->m_dwDiscoInfoRequestTime = pInfo->GetRequestTime(); TCHAR queryNode[512]; mir_sntprintf(queryNode, SIZEOF(queryNode), _T("%s#%s"), r->m_tszCapsNode, r->m_tszCapsVer); m_ThreadInfo->send(XmlNodeIq(pInfo) << XQUERY(JABBER_FEAT_DISCO_INFO) << XATTR(_T("node"), queryNode)); bRequestSent = TRUE; } else if (jcbMainCaps == JABBER_RESOURCE_CAPS_IN_PROGRESS) bRequestSent = TRUE; else if (jcbMainCaps != JABBER_RESOURCE_CAPS_TIMEOUT) jcbCaps |= jcbMainCaps; if (jcbMainCaps != JABBER_RESOURCE_CAPS_TIMEOUT && r->m_tszCapsExt) { TCHAR *caps = mir_tstrdup(r->m_tszCapsExt); TCHAR *token = _tcstok(caps, _T(" ")); while (token) { switch (jcbExtCaps = m_clientCapsManager.GetClientCaps(r->m_tszCapsNode, token)) { case JABBER_RESOURCE_CAPS_ERROR: break; case JABBER_RESOURCE_CAPS_UNINIT: { // send disco#info query CJabberIqInfo *pInfo = AddIQ(&CJabberProto::OnIqResultCapsDiscoInfo, JABBER_IQ_TYPE_GET, fullJid, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_CHILD_TAG_NODE); pInfo->SetTimeout(JABBER_RESOURCE_CAPS_QUERY_TIMEOUT); m_clientCapsManager.SetClientCaps(r->m_tszCapsNode, token, JABBER_RESOURCE_CAPS_IN_PROGRESS, pInfo->GetIqId()); m_ThreadInfo->send( XmlNodeIq(pInfo) << XQUERY(JABBER_FEAT_DISCO_INFO) << XATTR(_T("node"), CMString(FORMAT, _T("%s#%s"), r->m_tszCapsNode, token))); bRequestSent = TRUE; } break; case JABBER_RESOURCE_CAPS_IN_PROGRESS: bRequestSent = TRUE; break; default: jcbCaps |= jcbExtCaps; } token = _tcstok(NULL, _T(" ")); } mir_free(caps); } if (bRequestSent) return JABBER_RESOURCE_CAPS_IN_PROGRESS; return jcbCaps | r->m_jcbManualDiscoveredCaps; } // capability mode (version request + service discovery) // no version info: if (!r->m_tszSoftwareVersion && !r->m_tszSoftware) { // version request not sent: if (!r->m_dwVersionRequestTime) { // send version query CJabberIqInfo *pInfo = AddIQ(&CJabberProto::OnIqResultVersion, JABBER_IQ_TYPE_GET, fullJid, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_HCONTACT | JABBER_IQ_PARSE_CHILD_TAG_NODE); pInfo->SetTimeout(JABBER_RESOURCE_CAPS_QUERY_TIMEOUT); r->m_dwVersionRequestTime = pInfo->GetRequestTime(); XmlNodeIq iq(pInfo); iq << XQUERY(JABBER_FEAT_VERSION); m_ThreadInfo->send(iq); return JABBER_RESOURCE_CAPS_IN_PROGRESS; } // version not received: else if (r->m_dwVersionRequestTime != -1) { // no timeout? if (GetTickCount() - r->m_dwVersionRequestTime < JABBER_RESOURCE_CAPS_QUERY_TIMEOUT) return JABBER_RESOURCE_CAPS_IN_PROGRESS; // timeout r->m_dwVersionRequestTime = -1; } // no version information, try direct service discovery if (!r->m_dwDiscoInfoRequestTime) { // send disco#info query CJabberIqInfo *pInfo = AddIQ(&CJabberProto::OnIqResultCapsDiscoInfo, JABBER_IQ_TYPE_GET, fullJid, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_CHILD_TAG_NODE); pInfo->SetTimeout(JABBER_RESOURCE_CAPS_QUERY_TIMEOUT); r->m_dwDiscoInfoRequestTime = pInfo->GetRequestTime(); XmlNodeIq iq(pInfo); iq << XQUERY(JABBER_FEAT_DISCO_INFO); m_ThreadInfo->send(iq); return JABBER_RESOURCE_CAPS_IN_PROGRESS; } else if (r->m_dwDiscoInfoRequestTime == -1) return r->m_jcbCachedCaps | r->m_jcbManualDiscoveredCaps; else if (GetTickCount() - r->m_dwDiscoInfoRequestTime < JABBER_RESOURCE_CAPS_QUERY_TIMEOUT) return JABBER_RESOURCE_CAPS_IN_PROGRESS; else r->m_dwDiscoInfoRequestTime = -1; // version request timeout: return JABBER_RESOURCE_CAPS_NONE; } // version info available: if (r->m_tszSoftware && r->m_tszSoftwareVersion) { JabberCapsBits jcbMainCaps = m_clientCapsManager.GetClientCaps(r->m_tszSoftware, r->m_tszSoftwareVersion); if (jcbMainCaps == JABBER_RESOURCE_CAPS_ERROR) { // Bombus hack: if (!_tcscmp(r->m_tszSoftware, _T("Bombus")) || !_tcscmp(r->m_tszSoftware, _T("BombusMod"))) { jcbMainCaps = JABBER_CAPS_SI | JABBER_CAPS_SI_FT | JABBER_CAPS_IBB | JABBER_CAPS_MESSAGE_EVENTS | JABBER_CAPS_MESSAGE_EVENTS_NO_DELIVERY | JABBER_CAPS_DATA_FORMS | JABBER_CAPS_LAST_ACTIVITY | JABBER_CAPS_VERSION | JABBER_CAPS_COMMANDS | JABBER_CAPS_VCARD_TEMP; m_clientCapsManager.SetClientCaps(r->m_tszSoftware, r->m_tszSoftwareVersion, jcbMainCaps); } // Neos hack: else if (!_tcscmp(r->m_tszSoftware, _T("neos"))) { jcbMainCaps = JABBER_CAPS_OOB | JABBER_CAPS_MESSAGE_EVENTS | JABBER_CAPS_MESSAGE_EVENTS_NO_DELIVERY | JABBER_CAPS_LAST_ACTIVITY | JABBER_CAPS_VERSION; m_clientCapsManager.SetClientCaps(r->m_tszSoftware, r->m_tszSoftwareVersion, jcbMainCaps); } // sim hack: else if (!_tcscmp(r->m_tszSoftware, _T("sim"))) { jcbMainCaps = JABBER_CAPS_OOB | JABBER_CAPS_VERSION | JABBER_CAPS_MESSAGE_EVENTS | JABBER_CAPS_MESSAGE_EVENTS_NO_DELIVERY; m_clientCapsManager.SetClientCaps(r->m_tszSoftware, r->m_tszSoftwareVersion, jcbMainCaps); } } else if (jcbMainCaps == JABBER_RESOURCE_CAPS_UNINIT) { // send disco#info query CJabberIqInfo *pInfo = AddIQ(&CJabberProto::OnIqResultCapsDiscoInfo, JABBER_IQ_TYPE_GET, fullJid, JABBER_IQ_PARSE_FROM | JABBER_IQ_PARSE_CHILD_TAG_NODE); pInfo->SetTimeout(JABBER_RESOURCE_CAPS_QUERY_TIMEOUT); m_clientCapsManager.SetClientCaps(r->m_tszSoftware, r->m_tszSoftwareVersion, JABBER_RESOURCE_CAPS_IN_PROGRESS, pInfo->GetIqId()); r->m_dwDiscoInfoRequestTime = pInfo->GetRequestTime(); XmlNodeIq iq(pInfo); iq << XQUERY(JABBER_FEAT_DISCO_INFO); m_ThreadInfo->send(iq); jcbMainCaps = JABBER_RESOURCE_CAPS_IN_PROGRESS; } return jcbMainCaps | r->m_jcbManualDiscoveredCaps; } return JABBER_RESOURCE_CAPS_NONE; }
// XEP-0199: XMPP Ping support BOOL CJabberProto::OnIqRequestPing(HXML, CJabberIqInfo *pInfo) { m_ThreadInfo->send(XmlNodeIq(_T("result"), pInfo) << XATTR(_T("from"), m_ThreadInfo->fullJID)); return TRUE; }
void CJabberProto::ByteSendViaProxy( JABBER_BYTE_TRANSFER *jbt ) { TCHAR *szHost, *szPort; WORD port; HANDLE hConn; char data[3]; char* buffer; int datalen, bytesParsed, recvResult; BOOL validStreamhost; if ( jbt == NULL ) return; if (( buffer=( char* )mir_alloc( JABBER_NETWORK_BUFFER_SIZE )) == NULL ) { m_ThreadInfo->send( XmlNodeIq( _T("error"), jbt->iqId, jbt->srcJID ) << XCHILD( _T("error")) << XATTRI( _T("code"), 406 ) << XATTR( _T("type"), _T("auth")) << XCHILDNS( _T("not-acceptable"), _T("urn:ietf:params:xml:ns:xmpp-stanzas"))); return; } jbt->state = JBT_INIT; validStreamhost = FALSE; szPort = jbt->szProxyPort; szHost = jbt->szProxyHost; port = ( WORD )_ttoi( szPort ); if ( jbt->streamhostJID ) mir_free( jbt->streamhostJID ); jbt->streamhostJID = mir_tstrdup( jbt->szProxyJid ); NETLIBOPENCONNECTION nloc = { 0 }; nloc.cbSize = sizeof( nloc ); nloc.szHost = mir_t2a(szHost); nloc.wPort = port; hConn = ( HANDLE ) JCallService( MS_NETLIB_OPENCONNECTION, ( WPARAM ) m_hNetlibUser, ( LPARAM )&nloc ); mir_free((void*)nloc.szHost); if ( hConn != NULL ) { jbt->hConn = hConn; data[0] = 5; data[1] = 1; data[2] = 0; Netlib_Send( hConn, data, 3, 0 ); jbt->state = JBT_INIT; datalen = 0; while ( jbt->state!=JBT_DONE && jbt->state!=JBT_ERROR && jbt->state!=JBT_SOCKSERR ) { recvResult = Netlib_Recv( hConn, buffer+datalen, JABBER_NETWORK_BUFFER_SIZE-datalen, 0 ); if ( recvResult <= 0 ) break; datalen += recvResult; bytesParsed = ByteSendProxyParse( hConn, jbt, buffer, datalen ); if ( bytesParsed < datalen ) memmove( buffer, buffer+bytesParsed, datalen-bytesParsed ); datalen -= bytesParsed; if ( jbt->state == JBT_DONE ) validStreamhost = TRUE; } Netlib_CloseHandle( hConn ); } mir_free( buffer ); (this->*jbt->pfnFinal)(( jbt->state == JBT_DONE ) ? TRUE : FALSE, jbt->ft ); jbt->ft = NULL; if ( !validStreamhost ) m_ThreadInfo->send( XmlNodeIq( _T("error"), jbt->iqId, jbt->srcJID ) << XCHILD( _T("error")) << XATTRI( _T("code"), 404 ) << XATTR( _T("type"), _T("cancel")) << XCHILDNS( _T("item-not-found"), _T("urn:ietf:params:xml:ns:xmpp-stanzas"))); }
int CJabberProto::ByteSendProxyParse( HANDLE hConn, JABBER_BYTE_TRANSFER *jbt, char* buffer, int datalen ) { int num = datalen; switch ( jbt->state ) { case JBT_INIT: // received: // 00-00 ver ( 0x05 ) // 01-01 selected method ( 0=no auth, 0xff=error ) // send: // 00-00 ver ( 0x05 ) // 01-01 cmd ( 1=connect ) // 02-02 reserved ( 0 ) // 03-03 address type ( 3 ) // 04-44 dst.addr ( 41 bytes: 1-byte length, 40-byte SHA1 hash of [sid,srcJID,dstJID] ) // 45-46 dst.port ( 0 ) if ( datalen==2 && buffer[0]==5 && buffer[1]==0 ) { BYTE data[47]; ZeroMemory( data, sizeof( data )); *(( DWORD* )data ) = 0x03000105; data[4] = 40; TCHAR text[256]; TCHAR *szInitiatorJid = JabberPrepareJid(jbt->srcJID); TCHAR *szTargetJid = JabberPrepareJid(jbt->dstJID); mir_sntprintf( text, SIZEOF( text ), _T("%s%s%s"), jbt->sid, szInitiatorJid, szTargetJid ); mir_free(szInitiatorJid); mir_free(szTargetJid); char* szAuthString = mir_utf8encodeT( text ); Log( "Auth: '%s'", szAuthString ); char* szHash = JabberSha1( szAuthString ); strncpy(( char* )( data+5 ), szHash, 40 ); mir_free( szHash ); Netlib_Send( hConn, ( char* )data, 47, 0 ); jbt->state = JBT_CONNECT; mir_free( szAuthString ); } else jbt->state = JBT_SOCKSERR; break; case JBT_CONNECT: // received: // 00-00 ver ( 0x05 ) // 01-01 reply ( 0=success,2=not allowed ) // 02-02 reserved ( 0 ) // 03-03 address type ( 1=IPv4 address,3=host address ) // 04-mm bnd.addr server bound address ( 4-byte IP if IPv4, 1-byte length + n-byte host address string if host address ) // nn-nn+1 bnd.port server bound port if ( datalen>=5 && buffer[0]==5 && buffer[1]==0 && ( buffer[3]==1 || buffer[3]==3 || buffer[3]==0 )) { if ( buffer[3]==1 && datalen>=10 ) num = 10; else if ( buffer[3]==3 && datalen>=buffer[4]+7 ) num = buffer[4] + 7; else if ( buffer[3]==0 && datalen>=6 ) num = 6; else { jbt->state = JBT_SOCKSERR; break; } jbt->state = JBT_SENDING; jbt->hProxyEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); jbt->bStreamActivated = FALSE; int iqId = SerialNext(); TCHAR listJid[256]; mir_sntprintf(listJid, SIZEOF( listJid ), _T("ftproxy_%d"), iqId); JABBER_LIST_ITEM *item = ListAdd( LIST_FTIQID, listJid ); item->jbt = jbt; IqAdd( iqId, IQ_PROC_NONE, &CJabberProto::IqResultStreamActivate ); m_ThreadInfo->send( XmlNodeIq( _T("set"), iqId, jbt->streamhostJID ) << XQUERY( _T(JABBER_FEAT_BYTESTREAMS)) << XATTR( _T("sid"), jbt->sid ) << XCHILD( _T("activate"), jbt->dstJID )); WaitForSingleObject( jbt->hProxyEvent, INFINITE ); CloseHandle( jbt->hProxyEvent ); jbt->hProxyEvent = NULL; ListRemove( LIST_FTIQID, listJid ); if ( jbt->bStreamActivated) jbt->state = (this->*jbt->pfnSend)( hConn, jbt->ft ) ? JBT_DONE : JBT_ERROR; else jbt->state = JBT_ERROR; } else jbt->state = JBT_SOCKSERR; break; } return num; }
void __cdecl CJabberProto::ByteReceiveThread( JABBER_BYTE_TRANSFER *jbt ) { HXML iqNode, queryNode = NULL, n; const TCHAR *sid = NULL, *from = NULL, *to = NULL, *szId = NULL, *szHost, *szPort, *str; int i; WORD port; HANDLE hConn; char data[3]; char* buffer; int datalen, bytesParsed, recvResult; BOOL validStreamhost = FALSE; if ( jbt == NULL ) return; jbt->state = JBT_INIT; if ( iqNode = jbt->iqNode ) { from = xmlGetAttrValue( iqNode, _T("from")); to = xmlGetAttrValue( iqNode, _T("to")); szId = xmlGetAttrValue( iqNode, _T("id")); queryNode = xmlGetChild( iqNode , "query" ); if ( queryNode ) sid = xmlGetAttrValue( queryNode, _T("sid")); } if ( szId && from && to && sid && ( n = xmlGetChild( queryNode , "streamhost" ))!=NULL ) { jbt->iqId = mir_tstrdup( szId ); jbt->srcJID = mir_tstrdup( from ); jbt->dstJID = mir_tstrdup( to ); jbt->sid = mir_tstrdup( sid ); if (( buffer=( char* )mir_alloc( JABBER_NETWORK_BUFFER_SIZE ))) { for ( i=1; ( n = xmlGetNthChild( queryNode, _T("streamhost"), i ))!=NULL; i++ ) { if (( szHost = xmlGetAttrValue( n, _T("host"))) != NULL && ( szPort = xmlGetAttrValue( n, _T("port"))) != NULL && ( str = xmlGetAttrValue( n, _T("jid"))) != NULL ) { port = ( WORD )_ttoi( szPort ); if ( jbt->streamhostJID ) mir_free( jbt->streamhostJID ); jbt->streamhostJID = mir_tstrdup( str ); Log( "bytestream_recv connecting to " TCHAR_STR_PARAM ":%d", szHost, port ); NETLIBOPENCONNECTION nloc = { 0 }; nloc.cbSize = sizeof( nloc ); nloc.szHost = mir_t2a(szHost); nloc.wPort = port; hConn = ( HANDLE ) JCallService( MS_NETLIB_OPENCONNECTION, ( WPARAM ) m_hNetlibUser, ( LPARAM )&nloc ); mir_free((void*)nloc.szHost); if ( hConn == NULL ) { Log( "bytestream_recv_connection connection failed ( %d ), try next streamhost", WSAGetLastError()); continue; } jbt->hConn = hConn; data[0] = 5; data[1] = 1; data[2] = 0; Netlib_Send( hConn, data, 3, 0 ); jbt->state = JBT_INIT; datalen = 0; while ( jbt->state!=JBT_DONE && jbt->state!=JBT_ERROR && jbt->state!=JBT_SOCKSERR ) { recvResult = Netlib_Recv( hConn, buffer+datalen, JABBER_NETWORK_BUFFER_SIZE-datalen, 0 ); if ( recvResult <= 0 ) break; datalen += recvResult; bytesParsed = ByteReceiveParse( hConn, jbt, buffer, datalen ); if ( bytesParsed < datalen ) memmove( buffer, buffer+bytesParsed, datalen-bytesParsed ); datalen -= bytesParsed; if ( jbt->state == JBT_RECVING ) validStreamhost = TRUE; } Netlib_CloseHandle( hConn ); Log( "bytestream_recv_connection closing connection" ); } if ( jbt->state==JBT_ERROR || validStreamhost==TRUE ) break; Log( "bytestream_recv_connection stream cannot be established, try next streamhost" ); } mir_free( buffer ); } } (this->*jbt->pfnFinal)(( jbt->state==JBT_DONE )?TRUE:FALSE, jbt->ft ); jbt->ft = NULL; if ( !validStreamhost && szId && from ) { Log( "bytestream_recv_connection session not completed" ); m_ThreadInfo->send( XmlNodeIq( _T("error"), szId, from ) << XCHILD( _T("error")) << XATTRI( _T("code"), 404 ) << XATTR( _T("type"), _T("cancel")) << XCHILDNS( _T("item-not-found"), _T("urn:ietf:params:xml:ns:xmpp-stanzas"))); } delete jbt; Log( "Thread ended: type=bytestream_recv" ); }
int CJabberProto::ByteReceiveParse( HANDLE hConn, JABBER_BYTE_TRANSFER *jbt, char* buffer, int datalen ) { int bytesReceived, num = datalen; switch ( jbt->state ) { case JBT_INIT: // received: // 00-00 ver ( 0x05 ) // 01-01 selected method ( 0=no auth, 0xff=error ) // send: // 00-00 ver ( 0x05 ) // 01-01 cmd ( 1=connect ) // 02-02 reserved ( 0 ) // 03-03 address type ( 3 ) // 04-44 dst.addr ( 41 bytes: 1-byte length, 40-byte SHA1 hash of [sid,srcJID,dstJID] ) // 45-46 dst.port ( 0 ) if ( datalen==2 && buffer[0]==5 && buffer[1]==0 ) { BYTE data[47]; ZeroMemory( data, sizeof( data )); *(( DWORD* )data ) = 0x03000105; data[4] = 40; TCHAR text[JABBER_MAX_JID_LEN*2]; TCHAR *szInitiatorJid = JabberPrepareJid(jbt->srcJID); TCHAR *szTargetJid = JabberPrepareJid(jbt->dstJID); mir_sntprintf( text, SIZEOF( text ), _T("%s%s%s"), jbt->sid, szInitiatorJid, szTargetJid ); mir_free(szInitiatorJid); mir_free(szTargetJid); char* szAuthString = mir_utf8encodeT( text ); Log( "Auth: '%s'", szAuthString ); char* szHash = JabberSha1( szAuthString ); strncpy(( char* )( data+5 ), szHash, 40 ); mir_free( szHash ); Netlib_Send( hConn, ( char* )data, 47, 0 ); jbt->state = JBT_CONNECT; mir_free( szAuthString ); } else jbt->state = JBT_SOCKSERR; break; case JBT_CONNECT: // received: // 00-00 ver ( 0x05 ) // 01-01 reply ( 0=success,2=not allowed ) // 02-02 reserved ( 0 ) // 03-03 address type ( 1=IPv4 address,3=host address ) // 04-mm bnd.addr server bound address ( 4-byte IP if IPv4, 1-byte length + n-byte host address string if host address ) // nn-nn+1 bnd.port server bound port if ( datalen>=5 && buffer[0]==5 && buffer[1]==0 && ( buffer[3]==1 || buffer[3]==3 || buffer[3]==0 )) { if ( buffer[3]==1 && datalen>=10 ) num = 10; else if ( buffer[3]==3 && datalen>=buffer[4]+7 ) num = buffer[4] + 7; else if ( buffer[3]==0 && datalen>=6 ) num = 6; else { jbt->state = JBT_SOCKSERR; break; } jbt->state = JBT_RECVING; m_ThreadInfo->send( XmlNodeIq( _T("result"), jbt->iqId, jbt->srcJID ) << XQUERY( _T(JABBER_FEAT_BYTESTREAMS)) << XCHILD( _T("streamhost-used")) << XATTR( _T("jid"), jbt->streamhostJID )); } else jbt->state = JBT_SOCKSERR; break; case JBT_RECVING: bytesReceived = (this->*jbt->pfnRecv)( hConn, jbt->ft, buffer, datalen ); if ( bytesReceived < 0 ) jbt->state = JBT_ERROR; else if ( bytesReceived == 0 ) jbt->state = JBT_DONE; break; } return num; }