// 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; }
BOOL CJabberProto::SendHttpAuthReply(CJabberHttpAuthParams *pParams, BOOL bAuthorized) { if (!m_bJabberOnline || !pParams || !m_ThreadInfo) return FALSE; if (pParams->m_nType == CJabberHttpAuthParams::IQ) { XmlNodeIq iq(bAuthorized ? _T("result") : _T("error"), pParams->m_szIqId, pParams->m_szFrom); if (!bAuthorized) { iq << XCHILDNS(_T("confirm"), JABBER_FEAT_HTTP_AUTH) << XATTR(_T("id"), pParams->m_szId) << XATTR(_T("method"), pParams->m_szMethod) << XATTR(_T("url"), pParams->m_szUrl); iq << XCHILD(_T("error")) << XATTRI(_T("code"), 401) << XATTR(_T("type"), _T("auth")) << XCHILDNS(_T("not-authorized"), _T("urn:ietf:params:xml:xmpp-stanzas")); } m_ThreadInfo->send(iq); } else if (pParams->m_nType == CJabberHttpAuthParams::MSG) { XmlNode msg(_T("message")); msg << XATTR(_T("to"), pParams->m_szFrom); if (!bAuthorized) msg << XATTR(_T("type"), _T("error")); if (pParams->m_szThreadId) msg << XCHILD(_T("thread"), pParams->m_szThreadId); msg << XCHILDNS(_T("confirm"), JABBER_FEAT_HTTP_AUTH) << XATTR(_T("id"), pParams->m_szId) << XATTR(_T("method"), pParams->m_szMethod) << XATTR(_T("url"), pParams->m_szUrl); if (!bAuthorized) msg << XCHILD(_T("error")) << XATTRI(_T("code"), 401) << XATTR(_T("type"), _T("auth")) << XCHILDNS(_T("not-authorized"), _T("urn:ietf:params:xml:xmpp-stanzas")); m_ThreadInfo->send(msg); } else return FALSE; return TRUE; }
BOOL CJabberProto::OnSiRequest(HXML node, CJabberIqInfo *pInfo) { const TCHAR *szProfile = XmlGetAttrValue(pInfo->GetChildNode(), _T("profile")); if (szProfile && !mir_tstrcmp(szProfile, JABBER_FEAT_SI_FT)) FtHandleSiRequest(node); else { XmlNodeIq iq(_T("error"), pInfo); HXML error = iq << XCHILD(_T("error")) << XATTRI(_T("code"), 400) << XATTR(_T("type"), _T("cancel")); error << XCHILDNS(_T("bad-request"), _T("urn:ietf:params:xml:ns:xmpp-stanzas")); error << XCHILD(_T("bad-profile")); m_ThreadInfo->send(iq); } return TRUE; }
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 ); }
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::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; }
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" ); }
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"))); }
void CJabberProto::ByteSendThread( JABBER_BYTE_TRANSFER *jbt ) { char* localAddr; char* localAddrInternal; struct in_addr in; DBVARIANT dbv; TCHAR szPort[8]; HANDLE hEvent = NULL; TCHAR* proxyJid; CJabberIqInfo* pInfo = NULL; int nIqId = 0; Log( "Thread started: type=bytestream_send" ); BOOL bDirect = m_options.BsDirect; if ( m_options.BsProxyManual ) { proxyJid = NULL; if ( !DBGetContactSettingString( NULL, m_szModuleName, "BsProxyServer", &dbv )) { proxyJid = mir_a2t( dbv.pszVal ); JFreeVariant( &dbv ); } if ( proxyJid ) { jbt->bProxyDiscovered = FALSE; jbt->szProxyHost = NULL; jbt->szProxyPort = NULL; jbt->szProxyJid = NULL; jbt->hProxyEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); pInfo = m_iqManager.AddHandler( &CJabberProto::IqResultProxyDiscovery, JABBER_IQ_TYPE_GET, proxyJid, 0, -1, jbt ); nIqId = pInfo->GetIqId(); XmlNodeIq iq( pInfo ); iq << XQUERY( _T(JABBER_FEAT_BYTESTREAMS)); m_ThreadInfo->send( iq ); WaitForSingleObject( jbt->hProxyEvent, INFINITE ); m_iqManager.ExpireIq ( nIqId ); CloseHandle( jbt->hProxyEvent ); jbt->hProxyEvent = NULL; mir_free( proxyJid ); if ( jbt->state == JBT_ERROR && !bDirect ) { Log( "Bytestream proxy failure" ); MsgPopup( pInfo->GetHContact(), TranslateT("Bytestream Proxy not available"), pInfo->GetReceiver()); jbt->ft->state = FT_DENIED; (this->*jbt->pfnFinal)( FALSE, jbt->ft ); jbt->ft = NULL; delete jbt; return; } } } pInfo = m_iqManager.AddHandler( &CJabberProto::ByteInitiateResult, JABBER_IQ_TYPE_SET, jbt->dstJID, 0, -1, jbt ); nIqId = pInfo->GetIqId(); { XmlNodeIq iq( pInfo ); HXML query = iq << XQUERY( _T(JABBER_FEAT_BYTESTREAMS)) << XATTR( _T("sid"), jbt->sid ); if ( bDirect ) { localAddr = NULL; if ( m_options.BsDirectManual == TRUE ) { if ( !DBGetContactSettingString( NULL, m_szModuleName, "BsDirectAddr", &dbv )) { localAddr = NEWSTR_ALLOCA( dbv.pszVal ); JFreeVariant( &dbv ); } } NETLIBBIND nlb = {0}; nlb.cbSize = sizeof( NETLIBBIND ); nlb.pfnNewConnectionV2 = JabberByteSendConnection; nlb.pExtra = this; nlb.wPort = 0; // Use user-specified incoming port ranges, if available jbt->hConn = ( HANDLE ) JCallService( MS_NETLIB_BINDPORT, ( WPARAM ) m_hNetlibUser, ( LPARAM )&nlb ); if ( jbt->hConn == NULL ) { Log( "Cannot allocate port for bytestream_send thread, thread ended." ); delete jbt; return; } if ( localAddr == NULL ) { in.S_un.S_addr = htonl(nlb.dwExternalIP); localAddr = NEWSTR_ALLOCA( inet_ntoa( in )); } in.S_un.S_addr = htonl(nlb.dwInternalIP); localAddrInternal = NEWSTR_ALLOCA( inet_ntoa( in )); mir_sntprintf( szPort, SIZEOF( szPort ), _T("%d"), nlb.wPort ); JABBER_LIST_ITEM *item = ListAdd( LIST_BYTE, szPort ); item->jbt = jbt; hEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); jbt->hEvent = hEvent; jbt->hSendEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); query << XCHILD( _T("streamhost")) << XATTR( _T("jid"), m_ThreadInfo->fullJID ) << XATTR( _T("host"), _A2T(localAddr)) << XATTRI( _T("port"), nlb.wPort ); if ( strcmp( localAddr, localAddrInternal )) query << XCHILD( _T("streamhost")) << XATTR( _T("jid"), m_ThreadInfo->fullJID ) << XATTR( _T("host"), _A2T(localAddrInternal)) << XATTRI( _T("port"), nlb.wPort ); } if ( jbt->bProxyDiscovered ) query << XCHILD( _T("streamhost")) << XATTR( _T("jid"), jbt->szProxyJid ) << XATTR( _T("host"), jbt->szProxyHost ) << XATTR( _T("port"), jbt->szProxyPort ); jbt->hProxyEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); jbt->szStreamhostUsed = NULL; m_ThreadInfo->send( iq ); } WaitForSingleObject( jbt->hProxyEvent, INFINITE ); m_iqManager.ExpireIq( nIqId ); CloseHandle( jbt->hProxyEvent ); jbt->hProxyEvent = NULL; if ( !jbt->szStreamhostUsed ) { if ( bDirect ) { SetEvent( jbt->hSendEvent ); CloseHandle( jbt->hSendEvent ); CloseHandle( hEvent ); jbt->hEvent = NULL; if ( jbt->hConn != NULL ) Netlib_CloseHandle( jbt->hConn ); jbt->hConn = NULL; ListRemove( LIST_BYTE, szPort ); } (this->*jbt->pfnFinal)(( jbt->state==JBT_DONE )?TRUE:FALSE, jbt->ft ); jbt->ft = NULL; // stupid fix: wait for listening thread exit Sleep( 100 ); delete jbt; return; } if ( jbt->bProxyDiscovered && !_tcscmp( jbt->szProxyJid, jbt->szStreamhostUsed )) { // jabber proxy used if ( bDirect ) { SetEvent( jbt->hSendEvent ); CloseHandle( jbt->hSendEvent ); CloseHandle( hEvent ); jbt->hEvent = NULL; if ( jbt->hConn != NULL ) Netlib_CloseHandle( jbt->hConn ); jbt->hConn = NULL; ListRemove( LIST_BYTE, szPort ); } ByteSendViaProxy( jbt ); } else { SetEvent( jbt->hSendEvent ); WaitForSingleObject( hEvent, INFINITE ); CloseHandle( hEvent ); CloseHandle( jbt->hSendEvent ); jbt->hEvent = NULL; (this->*jbt->pfnFinal)(( jbt->state == JBT_DONE ) ? TRUE : FALSE, jbt->ft ); jbt->ft = NULL; if ( jbt->hConn != NULL ) Netlib_CloseHandle( jbt->hConn ); jbt->hConn = NULL; ListRemove( LIST_BYTE, szPort ); } // stupid fix: wait for listening connection thread exit Sleep( 100 ); delete jbt; Log( "Thread ended: type=bytestream_send" ); }