/* Jabber Protocol Plugin for Miranda IM Copyright ( C ) 2002-04 Santithorn Bunchua Copyright ( C ) 2005-06 George Hazan This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or ( at your option ) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. File name : $Source: /cvsroot/miranda/miranda/protocols/JabberG/jabber_iqid.cpp,v $ Revision : $Revision: 3703 $ Last change on : $Date: 2006-09-05 17:54:42 +0400 (Втр, 05 Сен 2006) $ Last change by : $Author: ghazan $ */ #include "jabber.h" #include "resource.h" #include "jabber_list.h" #include "jabber_iq.h" #include "sha1.h" extern char* jabberVcardPhotoFileName; extern char* jabberVcardPhotoType; static void JabberOnLoggedIn( ThreadData* info ) { jabberOnline = TRUE; jabberLoggedInTime = time(0); int iqId = JabberSerialNext(); JabberIqAdd( iqId, IQ_PROC_NONE, JabberIqResultGetRoster ); XmlNode iq( "iq" ); iq.addAttr( "type", "get" ); iq.addAttrID( iqId ); XmlNode* query = iq.addChild( "query" ); query->addAttr( "xmlns", "jabber:iq:roster" ); JabberSend( info->s, iq ); } void JabberIqResultGetAuth( XmlNode *iqNode, void *userdata ) { // RECVED: result of the request for authentication method // ACTION: send account authentication information to log in JabberLog( " iqIdGetAuth" ); ThreadData* info = ( ThreadData* ) userdata; XmlNode *queryNode; TCHAR* type; if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return; if (( queryNode=JabberXmlGetChild( iqNode, "query" )) == NULL ) return; if ( !lstrcmp( type, _T("result"))) { int iqId = JabberSerialNext(); JabberIqAdd( iqId, IQ_PROC_NONE, JabberIqResultSetAuth ); XmlNodeIq iq( "set", iqId ); XmlNode* query = iq.addQuery( "jabber:iq:auth" ); query->addChild( "username", info->username ); if ( JabberXmlGetChild( queryNode, "digest" )!=NULL && streamId ) { char* str = JabberUtf8Encode( info->password ); char text[200]; mir_snprintf( text, SIZEOF(text), "%s%s", streamId, str ); mir_free( str ); if (( str=JabberSha1( text )) != NULL ) { query->addChild( "digest", str ); mir_free( str ); } } else if ( JabberXmlGetChild( queryNode, "password" ) != NULL ) query->addChild( "password", info->password ); else { JabberLog( "No known authentication mechanism accepted by the server." ); JabberSend( info->s, "" ); return; } if ( JabberXmlGetChild( queryNode, "resource" ) != NULL ) query->addChild( "resource", info->resource ); JabberSend( info->s, iq ); } else if ( !lstrcmp( type, _T("error"))) { JabberSend( info->s, "" ); TCHAR text[128]; mir_sntprintf( text, SIZEOF( text ), _T("%s %s."), TranslateT( "Authentication failed for" ), info->username ); MessageBox( NULL, text, TranslateT( "Jabber Authentication" ), MB_OK|MB_ICONSTOP|MB_SETFOREGROUND ); JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPASSWORD ); jabberThreadInfo = NULL; // To disallow auto reconnect } } void JabberIqResultSetAuth( XmlNode *iqNode, void *userdata ) { ThreadData* info = ( ThreadData* ) userdata; TCHAR* type; int iqId; // RECVED: authentication result // ACTION: if successfully logged in, continue by requesting roster list and set my initial status JabberLog( " iqIdSetAuth" ); if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return; if ( !lstrcmp( type, _T("result"))) { DBVARIANT dbv; if ( JGetStringT( NULL, "Nick", &dbv )) JSetStringT( NULL, "Nick", info->username ); else JFreeVariant( &dbv ); jabberOnline = TRUE; jabberLoggedInTime = time(0); iqId = JabberSerialNext(); JabberIqAdd( iqId, IQ_PROC_NONE, JabberIqResultGetRoster ); { XmlNodeIq iq( "get", iqId ); XmlNode* query = iq.addQuery( "jabber:iq:roster" ); JabberSend( info->s, iq ); } if ( hwndJabberAgents ) { // Retrieve agent information iqId = JabberSerialNext(); JabberIqAdd( iqId, IQ_PROC_GETAGENTS, JabberIqResultGetAgents ); XmlNodeIq iq( "get", iqId ); XmlNode* query = iq.addQuery( "jabber:iq:agents" ); JabberSend( info->s, iq ); } } // What to do if password error? etc... else if ( !lstrcmp( type, _T("error"))) { TCHAR text[128]; JabberSend( info->s, "" ); mir_sntprintf( text, SIZEOF( text ), _T("%s %s."), TranslateT( "Authentication failed for" ), info->username ); MessageBox( NULL, text, TranslateT( "Jabber Authentication" ), MB_OK|MB_ICONSTOP|MB_SETFOREGROUND ); JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPASSWORD ); jabberThreadInfo = NULL; // To disallow auto reconnect } } void JabberIqResultBind( XmlNode *iqNode, void *userdata ) { ThreadData* info = ( ThreadData* ) userdata; XmlNode* n = JabberXmlGetChild( iqNode, "bind" ); if ( n != NULL ) { if ( n = JabberXmlGetChild( n, "jid" )) { if ( n->text ) { if ( !_tcsncmp( info->fullJID, n->text, SIZEOF( info->fullJID ))) JabberLog( "Result Bind: "TCHAR_STR_PARAM" %s "TCHAR_STR_PARAM, info->fullJID, "confirmed.", NULL ); else { JabberLog( "Result Bind: "TCHAR_STR_PARAM" %s "TCHAR_STR_PARAM, info->fullJID, "changed to", n->text); _tcsncpy( info->fullJID, n->text, SIZEOF( info->fullJID )); } } } if ( info->bIsSessionAvailable ) { int iqId = JabberSerialNext(); JabberIqAdd( iqId, IQ_PROC_NONE, JabberIqResultSession ); XmlNodeIq iq( "set" ); iq.addAttrID( iqId ); iq.addChild( "session" )->addAttr( "xmlns", "urn:ietf:params:xml:ns:xmpp-session" ); JabberSend( info->s, iq ); } else JabberOnLoggedIn( info ); } else if ( n = JabberXmlGetChild( n, "error" )) { //rfc3920 page 39 TCHAR errorMessage [256]; int pos=0; pos = mir_sntprintf( errorMessage, SIZEOF(errorMessage), TranslateT("Resource ")); XmlNode *tempNode; if (tempNode = JabberXmlGetChild( n, "resource" )) pos += mir_sntprintf(errorMessage,256-pos,_T("\"%s\" "),tempNode->text); pos += mir_sntprintf( errorMessage+pos,256-pos,TranslateT("refused by server\n%s: %s"),TranslateT("Type"),Translate(JabberXmlGetAttrValue( n, "type" ))); if ( n->numChild ) pos += mir_sntprintf( errorMessage+pos,256-pos,_T("\n%s: ")_T(TCHAR_STR_PARAM)_T("\n"),TranslateT("Reason"),JTranslate( n->child[0]->name)); mir_sntprintf( errorMessage,256-pos, _T("%s @")_T(TCHAR_STR_PARAM)_T("."), TranslateT( "Authentication failed for" ), info->username, info->server ); MessageBox( NULL, errorMessage, TranslateT( "Jabber Protocol" ), MB_OK|MB_ICONSTOP|MB_SETFOREGROUND ); JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPROTOCOL ); JabberSend( info->s, "" ); jabberThreadInfo = NULL; // To disallow auto reconnect } } void JabberIqResultSession( XmlNode *iqNode, void *userdata ) { ThreadData* info = ( ThreadData* )userdata; TCHAR* type; if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return; if ( !lstrcmp( type, _T("result"))) JabberOnLoggedIn( info ); } ///////////////////////////////////////////////////////////////////////////////////////// // JabberIqResultGetRoster - populates LIST_ROSTER and creates contact for any new rosters void sttGroupchatJoinByHContact( HANDLE hContact ) { DBVARIANT dbv; if( JGetStringT( hContact, "ChatRoomID", &dbv )) return; if( dbv.type != DBVT_ASCIIZ && dbv.type != DBVT_WCHAR ) return; TCHAR* roomjid = mir_tstrdup( dbv.ptszVal ); JFreeVariant( &dbv ); if( !roomjid ) return; TCHAR* room = roomjid; TCHAR* server = _tcschr( roomjid, '@' ); if( !server ) return; server[0] = '\0'; server++; TCHAR nick[ 256 ]; if ( JGetStringT( hContact, "MyNick", &dbv )) { TCHAR* jidnick = JabberNickFromJID( jabberJID ); if( !jidnick ) { mir_free( jidnick ); mir_free( roomjid ); return; } _tcsncpy( nick, jidnick, SIZEOF( nick )); mir_free( jidnick ); } else { _tcsncpy( nick, dbv.ptszVal, SIZEOF( nick )); JFreeVariant( &dbv ); } JabberGroupchatJoinRoom( server, room, nick, _T("")); mir_free( roomjid ); } void CALLBACK sttCreateRoom( ULONG dwParam ) { char* jid = t2a(( TCHAR* )dwParam), *p; GCSESSION gcw = {0}; gcw.cbSize = sizeof(GCSESSION); gcw.iType = GCW_CHATROOM; gcw.pszID = jid; gcw.pszModule = jabberProtoName; gcw.pszName = strcpy(( char* )alloca( strlen(jid)+1 ), jid ); if (( p = (char*)strchr( gcw.pszName, '@' )) != NULL ) *p = 0; CallService( MS_GC_NEWSESSION, 0, ( LPARAM )&gcw ); mir_free(jid); } void JabberIqResultGetRoster( XmlNode* iqNode, void* ) { JabberLog( " iqIdGetRoster" ); TCHAR* type = JabberXmlGetAttrValue( iqNode, "type" ); if ( lstrcmp( type, _T("result"))) return; XmlNode* queryNode = JabberXmlGetChild( iqNode, "query" ); if ( queryNode == NULL ) return; if ( lstrcmp( JabberXmlGetAttrValue( queryNode, "xmlns" ), _T("jabber:iq:roster"))) return; TCHAR* name, *nick; int i; SortedList chatRooms = {0}; chatRooms.increment = 10; for ( i=0; i < queryNode->numChild; i++ ) { XmlNode* itemNode = queryNode->child[i]; if ( strcmp( itemNode->name, "item" )) continue; TCHAR* str = JabberXmlGetAttrValue( itemNode, "subscription" ); JABBER_SUBSCRIPTION sub; if ( str == NULL ) sub = SUB_NONE; else if ( !_tcscmp( str, _T("both"))) sub = SUB_BOTH; else if ( !_tcscmp( str, _T("to"))) sub = SUB_TO; else if ( !_tcscmp( str, _T("from"))) sub = SUB_FROM; else sub = SUB_NONE; TCHAR* jid = JabberXmlGetAttrValue( itemNode, "jid" ); if ( jid == NULL ) continue; if (( name = JabberXmlGetAttrValue( itemNode, "name" )) != NULL ) nick = mir_tstrdup( name ); else nick = JabberNickFromJID( jid ); if ( nick == NULL ) continue; JABBER_LIST_ITEM* item = JabberListAdd( LIST_ROSTER, jid ); item->subscription = sub; if ( item->nick ) mir_free( item->nick ); item->nick = nick; if ( item->group ) mir_free( item->group ); XmlNode* groupNode = JabberXmlGetChild( itemNode, "group" ); if ( groupNode != NULL && groupNode->text != NULL ) item->group = mir_tstrdup( groupNode->text ); else item->group = NULL; HANDLE hContact = JabberHContactFromJID( jid ); if ( hContact == NULL ) { // Received roster has a new JID. // Add the jid ( with empty resource ) to Miranda contact list. hContact = JabberDBCreateContact( jid, nick, FALSE, TRUE ); } DBVARIANT dbNick; if ( !JGetStringT( hContact, "Nick", &dbNick )) { if ( lstrcmp( nick, dbNick.ptszVal ) != 0 ) DBWriteContactSettingTString( hContact, "CList", "MyHandle", nick ); else DBDeleteContactSetting( hContact, "CList", "MyHandle" ); JFreeVariant( &dbNick ); } else DBWriteContactSettingTString( hContact, "CList", "MyHandle", nick ); if ( JGetByte( hContact, "ChatRoom", 0 )) { //DBDeleteContactSetting( hContact, "CList", "Hidden" ); QueueUserAPC( sttCreateRoom, hMainThread, ( unsigned long )jid ); DBDeleteContactSetting( hContact, "CList", "Hidden" ); li.List_Insert( &chatRooms, hContact, chatRooms.realCount ); } if ( item->group != NULL ) { JabberContactListCreateGroup( item->group ); // Don't set group again if already correct, or Miranda may show wrong group count in some case DBVARIANT dbv; if ( !DBGetContactSettingTString( hContact, "CList", "Group", &dbv )) { if ( lstrcmp( dbv.ptszVal, item->group )) DBWriteContactSettingTString( hContact, "CList", "Group", item->group ); JFreeVariant( &dbv ); } else DBWriteContactSettingTString( hContact, "CList", "Group", item->group ); } else DBDeleteContactSetting( hContact, "CList", "Group" ); } // Delete orphaned contacts ( if roster sync is enabled ) if ( JGetByte( "RosterSync", FALSE ) == TRUE ) { int listSize = 0, listAllocSize = 0; HANDLE* list = NULL; HANDLE hContact = ( HANDLE ) JCallService( MS_DB_CONTACT_FINDFIRST, 0, 0 ); while ( hContact != NULL ) { char* str = ( char* )JCallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 ); if ( str != NULL && !strcmp( str, jabberProtoName )) { DBVARIANT dbv; if ( !JGetStringT( hContact, "jid", &dbv )) { if ( !JabberListExist( LIST_ROSTER, dbv.ptszVal )) { JabberLog( "Syncing roster: preparing to delete " TCHAR_STR_PARAM " ( hContact=0x%x )", dbv.ptszVal, hContact ); if ( listSize >= listAllocSize ) { listAllocSize = listSize + 100; if (( list=( HANDLE * ) mir_realloc( list, listAllocSize * sizeof( HANDLE ))) == NULL ) { listSize = 0; break; } } list[listSize++] = hContact; } JFreeVariant( &dbv ); } } hContact = ( HANDLE ) JCallService( MS_DB_CONTACT_FINDNEXT, ( WPARAM ) hContact, 0 ); } for ( i=0; i < listSize; i++ ) { JabberLog( "Syncing roster: deleting 0x%x", list[i] ); JCallService( MS_DB_CONTACT_DELETE, ( WPARAM ) list[i], 0 ); } if ( list != NULL ) mir_free( list ); } JabberEnableMenuItems( TRUE ); if ( hwndJabberGroupchat ) SendMessage( hwndJabberGroupchat, WM_JABBER_CHECK_ONLINE, 0, 0 ); if ( hwndJabberJoinGroupchat ) SendMessage( hwndJabberJoinGroupchat, WM_JABBER_CHECK_ONLINE, 0, 0 ); JabberLog( "Status changed via THREADSTART" ); modeMsgStatusChangePending = FALSE; JabberSetServerStatus( jabberDesiredStatus ); if ( JGetByte( "AutoJoinConferences", 0 )) { for ( int i=0; i < chatRooms.realCount; i++ ) sttGroupchatJoinByHContact(( HANDLE )chatRooms.items[i] ); } li.List_Destroy( &chatRooms ); if ( hwndJabberAgents ) SendMessage( hwndJabberAgents, WM_JABBER_TRANSPORT_REFRESH, 0, 0 ); if ( hwndJabberVcard ) SendMessage( hwndJabberVcard, WM_JABBER_CHECK_ONLINE, 0, 0 ); } void JabberIqResultGetAgents( XmlNode *iqNode, void *userdata ) { ThreadData* info = ( ThreadData* ) userdata; XmlNode *queryNode; TCHAR* type, *jid, *str; // RECVED: agent list // ACTION: refresh agent list dialog JabberLog( " iqIdGetAgents" ); if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return; if (( queryNode=JabberXmlGetChild( iqNode, "query" )) == NULL ) return; if ( !lstrcmp( type, _T("result"))) { str = JabberXmlGetAttrValue( queryNode, "xmlns" ); if ( str!=NULL && !lstrcmp( str, _T("jabber:iq:agents"))) { XmlNode *agentNode, *n; JABBER_LIST_ITEM *item; int i; JabberListRemoveList( LIST_AGENT ); for ( i=0; inumChild; i++ ) { agentNode = queryNode->child[i]; if ( !lstrcmpA( agentNode->name, "agent" )) { if (( jid=JabberXmlGetAttrValue( agentNode, "jid" )) != NULL ) { item = JabberListAdd( LIST_AGENT, jid ); if ( JabberXmlGetChild( agentNode, "register" ) != NULL ) item->cap |= AGENT_CAP_REGISTER; if ( JabberXmlGetChild( agentNode, "search" ) != NULL ) item->cap |= AGENT_CAP_SEARCH; if ( JabberXmlGetChild( agentNode, "groupchat" ) != NULL ) item->cap |= AGENT_CAP_GROUPCHAT; // set service also??? // most chatroom servers don't announce so we will // also treat public as groupchat services if (( n=JabberXmlGetChild( agentNode, "service" ))!=NULL && n->text!=NULL && !_tcscmp( n->text, _T("public"))) item->cap |= AGENT_CAP_GROUPCHAT; if (( n=JabberXmlGetChild( agentNode, "name" ))!=NULL && n->text!=NULL ) item->name = mir_tstrdup( n->text ); } } } } if ( hwndJabberAgents != NULL ) { if (( jid = JabberXmlGetAttrValue( iqNode, "from" )) != NULL ) SendMessage( hwndJabberAgents, WM_JABBER_AGENT_REFRESH, 0, ( LPARAM )jid ); else SendMessage( hwndJabberAgents, WM_JABBER_AGENT_REFRESH, 0, ( LPARAM )info->server ); } } } void JabberIqResultGetRegister( XmlNode *iqNode, void *userdata ) { // RECVED: result of the request for ( agent ) registration mechanism // ACTION: activate ( agent ) registration input dialog JabberLog( " iqIdGetRegister" ); ThreadData* info = ( ThreadData* ) userdata; XmlNode *queryNode, *n; TCHAR *type; if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return; if (( queryNode=JabberXmlGetChild( iqNode, "query" )) == NULL ) return; if ( !lstrcmp( type, _T("result"))) { if ( hwndAgentRegInput ) if (( n = JabberXmlCopyNode( iqNode )) != NULL ) SendMessage( hwndAgentRegInput, WM_JABBER_REGINPUT_ACTIVATE, 1 /*success*/, ( LPARAM )n ); } else if ( !lstrcmp( type, _T("error"))) { if ( hwndAgentRegInput ) { XmlNode *errorNode = JabberXmlGetChild( iqNode, "error" ); TCHAR* str = JabberErrorMsg( errorNode ); SendMessage( hwndAgentRegInput, WM_JABBER_REGINPUT_ACTIVATE, 0 /*error*/, ( LPARAM )str ); mir_free( str ); } } } void JabberIqResultSetRegister( XmlNode *iqNode, void *userdata ) { // RECVED: result of registration process // ACTION: notify of successful agent registration JabberLog( " iqIdSetRegister" ); TCHAR *type; if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return; if ( !lstrcmp( type, _T("result"))) { if ( hwndRegProgress ) SendMessage( hwndRegProgress, WM_JABBER_REGDLG_UPDATE, 100, ( LPARAM )TranslateT( "Registration successful" )); } else if ( !lstrcmp( type, _T("error"))) { if ( hwndRegProgress ) { XmlNode *errorNode = JabberXmlGetChild( iqNode, "error" ); TCHAR* str = JabberErrorMsg( errorNode ); SendMessage( hwndRegProgress, WM_JABBER_REGDLG_UPDATE, 100, ( LPARAM )str ); mir_free( str ); } } } ///////////////////////////////////////////////////////////////////////////////////////// // JabberIqResultGetVcard - processes the server-side v-card static void JabberIqResultGetVcardPhoto( const TCHAR* jid, XmlNode* n, HANDLE hContact, BOOL& hasPhoto ) { if ( hasPhoto ) return; XmlNode* o = JabberXmlGetChild( n, "BINVAL" ); if ( o == NULL || o->text == NULL ) return; int bufferLen; char* buffer = JabberBase64Decode( o->text, &bufferLen ); if ( buffer == NULL ) return; XmlNode* m = JabberXmlGetChild( n, "TYPE" ); if ( m == NULL || m->text == NULL ) { LBL_NoTypeSpecified: char* szPicType; switch( JabberGetPictureType( buffer )) { case PA_FORMAT_GIF: szPicType = "image/gif"; break; case PA_FORMAT_BMP: szPicType = "image/bmp"; break; case PA_FORMAT_PNG: szPicType = "image/png"; break; case PA_FORMAT_JPEG: szPicType = "image/jpeg"; break; default: goto LBL_Ret; } replaceStr( jabberVcardPhotoType, szPicType ); } else { if ( _tcscmp( m->text, _T("image/jpeg")) && _tcscmp( m->text, _T("image/png")) && _tcscmp( m->text, _T("image/gif")) && _tcscmp( m->text, _T("image/bmp"))) goto LBL_NoTypeSpecified; if ( jabberVcardPhotoType ) mir_free(jabberVcardPhotoType); jabberVcardPhotoType = t2a( m->text ); } DWORD nWritten; char szTempPath[MAX_PATH], szTempFileName[MAX_PATH]; JABBER_LIST_ITEM *item; DBVARIANT dbv; if ( GetTempPathA( sizeof( szTempPath ), szTempPath ) <= 0 ) lstrcpyA( szTempPath, ".\\" ); if ( !GetTempFileNameA( szTempPath, jabberProtoName, GetTickCount(), szTempFileName )) { LBL_Ret: mir_free( buffer ); return; } { char* p = strrchr( szTempFileName, '.' ); if ( p != NULL ) lstrcpyA( p+1, jabberVcardPhotoType + 6 ); } JabberLog( "Picture file name set to %s", szTempFileName ); HANDLE hFile = CreateFileA( szTempFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if ( hFile == INVALID_HANDLE_VALUE ) goto LBL_Ret; JabberLog( "Writing %d bytes", bufferLen ); if ( !WriteFile( hFile, buffer, bufferLen, &nWritten, NULL )) goto LBL_Ret; JabberLog( "%d bytes written", nWritten ); if ( hContact == NULL ) { hasPhoto = TRUE; if ( jabberVcardPhotoFileName ) { DeleteFileA( jabberVcardPhotoFileName ); mir_free( jabberVcardPhotoFileName ); jabberVcardPhotoFileName = NULL; } replaceStr( jabberVcardPhotoFileName, szTempFileName ); JabberLog( "My picture saved to %s", szTempFileName ); } else if ( !JGetStringT( hContact, "jid", &dbv )) { if (( item = JabberListGetItemPtr( LIST_ROSTER, jid )) != NULL ) { hasPhoto = TRUE; if ( item->photoFileName ) DeleteFileA( item->photoFileName ); replaceStr( item->photoFileName, szTempFileName ); JabberLog( "Contact's picture saved to %s", szTempFileName ); } JFreeVariant( &dbv ); } CloseHandle( hFile ); if ( !hasPhoto ) DeleteFileA( szTempFileName ); goto LBL_Ret; } void JabberIqResultGetVcard( XmlNode *iqNode, void *userdata ) { XmlNode *vCardNode, *m, *n, *o; TCHAR* type, *jid; HANDLE hContact; TCHAR text[128]; int len; DBVARIANT dbv; JabberLog( " iqIdGetVcard" ); if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return; if (( jid=JabberXmlGetAttrValue( iqNode, "from" )) == NULL ) return; len = _tcslen( jabberJID ); if ( !_tcsnicmp( jid, jabberJID, len ) && ( jid[len]=='/' || jid[len]=='\0' )) { hContact = NULL; JabberLog( "Vcard for myself" ); } else { if (( hContact = JabberHContactFromJID( jid )) == NULL ) return; JabberLog( "Other user's vcard" ); } if ( !lstrcmp( type, _T("result"))) { BOOL hasFn, hasNick, hasGiven, hasFamily, hasMiddle, hasBday, hasGender; BOOL hasPhone, hasFax, hasCell, hasUrl; BOOL hasHome, hasHomeStreet, hasHomeStreet2, hasHomeLocality, hasHomeRegion, hasHomePcode, hasHomeCtry; BOOL hasWork, hasWorkStreet, hasWorkStreet2, hasWorkLocality, hasWorkRegion, hasWorkPcode, hasWorkCtry; BOOL hasOrgname, hasOrgunit, hasRole, hasTitle; BOOL hasDesc, hasPhoto; int nEmail, nPhone, nYear, nMonth, nDay; hasFn = hasNick = hasGiven = hasFamily = hasMiddle = hasBday = hasGender = FALSE; hasPhone = hasFax = hasCell = hasUrl = FALSE; hasHome = hasHomeStreet = hasHomeStreet2 = hasHomeLocality = hasHomeRegion = hasHomePcode = hasHomeCtry = FALSE; hasWork = hasWorkStreet = hasWorkStreet2 = hasWorkLocality = hasWorkRegion = hasWorkPcode = hasWorkCtry = FALSE; hasOrgname = hasOrgunit = hasRole = hasTitle = FALSE; hasDesc = hasPhoto = FALSE; nEmail = nPhone = 0; if (( vCardNode=JabberXmlGetChild( iqNode, "vCard" )) != NULL ) { for ( int i=0; inumChild; i++ ) { n = vCardNode->child[i]; if ( n==NULL || n->name==NULL ) continue; if ( !strcmp( n->name, "FN" )) { if ( n->text != NULL ) { hasFn = TRUE; JSetStringT( hContact, "FullName", n->text ); } } else if ( !strcmp( n->name, "NICKNAME" )) { if ( n->text != NULL ) { hasNick = TRUE; JSetStringT( hContact, "Nick", n->text ); } } else if ( !strcmp( n->name, "N" )) { // First/Last name if ( !hasGiven && !hasFamily && !hasMiddle ) { if (( m=JabberXmlGetChild( n, "GIVEN" )) != NULL && m->text!=NULL ) { hasGiven = TRUE; JSetStringT( hContact, "FirstName", m->text ); } if (( m=JabberXmlGetChild( n, "FAMILY" )) != NULL && m->text!=NULL ) { hasFamily = TRUE; JSetStringT( hContact, "LastName", m->text ); } if (( m=JabberXmlGetChild( n, "MIDDLE" )) != NULL && m->text != NULL ) { hasMiddle = TRUE; JSetStringT( hContact, "MiddleName", m->text ); } } } else if ( !strcmp( n->name, "EMAIL" )) { // E-mail address( es ) if (( m=JabberXmlGetChild( n, "USERID" )) == NULL ) // Some bad client put e-mail directly in instead of m = n; if ( m->text != NULL ) { char text[100]; if ( hContact != NULL ) { if ( nEmail == 0 ) strcpy( text, "e-mail" ); else sprintf( text, "e-mail%d", nEmail-1 ); } else sprintf( text, "e-mail%d", nEmail ); JSetStringT( hContact, text, m->text ); if ( hContact == NULL ) { sprintf( text, "e-mailFlag%d", nEmail ); int nFlag = 0; if ( JabberXmlGetChild( n, "HOME" ) != NULL ) nFlag |= JABBER_VCEMAIL_HOME; if ( JabberXmlGetChild( n, "WORK" ) != NULL ) nFlag |= JABBER_VCEMAIL_WORK; if ( JabberXmlGetChild( n, "INTERNET" ) != NULL ) nFlag |= JABBER_VCEMAIL_INTERNET; if ( JabberXmlGetChild( n, "X400" ) != NULL ) nFlag |= JABBER_VCEMAIL_X400; JSetWord( NULL, text, nFlag ); } nEmail++; } } else if ( !strcmp( n->name, "BDAY" )) { // Birthday if ( !hasBday && n->text!=NULL ) { if ( hContact != NULL ) { if ( _stscanf( n->text, _T("%d-%d-%d"), &nYear, &nMonth, &nDay ) == 3 ) { hasBday = TRUE; JSetWord( hContact, "BirthYear", ( WORD )nYear ); JSetByte( hContact, "BirthMonth", ( BYTE ) nMonth ); JSetByte( hContact, "BirthDay", ( BYTE ) nDay ); } } else { hasBday = TRUE; JSetStringT( NULL, "BirthDate", n->text ); } } } else if ( !lstrcmpA( n->name, "GENDER" )) { // Gender if ( !hasGender && n->text!=NULL ) { if ( hContact != NULL ) { if ( n->text[0] && strchr( "mMfF", n->text[0] )!=NULL ) { hasGender = TRUE; JSetByte( hContact, "Gender", ( BYTE ) toupper( n->text[0] )); } } else { hasGender = TRUE; JSetStringT( NULL, "GenderString", n->text ); } } } else if ( !strcmp( n->name, "ADR" )) { if ( !hasHome && JabberXmlGetChild( n, "HOME" )!=NULL ) { // Home address hasHome = TRUE; if (( m=JabberXmlGetChild( n, "STREET" )) != NULL && m->text != NULL ) { hasHomeStreet = TRUE; if ( hContact != NULL ) { if (( o=JabberXmlGetChild( n, "EXTADR" )) != NULL && o->text != NULL ) mir_sntprintf( text, SIZEOF( text ), _T("%s\r\n%s"), m->text, o->text ); else if (( o=JabberXmlGetChild( n, "EXTADD" ))!=NULL && o->text!=NULL ) mir_sntprintf( text, SIZEOF( text ), _T("%s\r\n%s"), m->text, o->text ); else _tcsncpy( text, m->text, SIZEOF( text )); text[sizeof( text )-1] = '\0'; JSetStringT( hContact, "Street", text ); } else { JSetStringT( hContact, "Street", m->text ); if (( m=JabberXmlGetChild( n, "EXTADR" )) == NULL ) m = JabberXmlGetChild( n, "EXTADD" ); if ( m!=NULL && m->text!=NULL ) { hasHomeStreet2 = TRUE; JSetStringT( hContact, "Street2", m->text ); } } } if (( m=JabberXmlGetChild( n, "LOCALITY" ))!=NULL && m->text!=NULL ) { hasHomeLocality = TRUE; JSetStringT( hContact, "City", m->text ); } if (( m=JabberXmlGetChild( n, "REGION" ))!=NULL && m->text!=NULL ) { hasHomeRegion = TRUE; JSetStringT( hContact, "State", m->text ); } if (( m=JabberXmlGetChild( n, "PCODE" ))!=NULL && m->text!=NULL ) { hasHomePcode = TRUE; JSetStringT( hContact, "ZIP", m->text ); } if (( m=JabberXmlGetChild( n, "CTRY" ))==NULL || m->text==NULL ) // Some bad client use instead of m = JabberXmlGetChild( n, "COUNTRY" ); if ( m!=NULL && m->text!=NULL ) { hasHomeCtry = TRUE; if ( hContact != NULL ) JSetWord( hContact, "Country", ( WORD )JabberCountryNameToId( m->text )); else JSetStringT( hContact, "CountryName", m->text ); } } if ( !hasWork && JabberXmlGetChild( n, "WORK" )!=NULL ) { // Work address hasWork = TRUE; if (( m=JabberXmlGetChild( n, "STREET" ))!=NULL && m->text!=NULL ) { hasWorkStreet = TRUE; if ( hContact != NULL ) { if (( o=JabberXmlGetChild( n, "EXTADR" ))!=NULL && o->text!=NULL ) mir_sntprintf( text, SIZEOF( text ), _T("%s\r\n%s"), m->text, o->text ); else if (( o=JabberXmlGetChild( n, "EXTADD" ))!=NULL && o->text!=NULL ) mir_sntprintf( text, SIZEOF( text ), _T("%s\r\n%s"), m->text, o->text ); else _tcsncpy( text, m->text, SIZEOF( text )); text[sizeof( text )-1] = '\0'; JSetStringT( hContact, "CompanyStreet", text ); } else { JSetStringT( hContact, "CompanyStreet", m->text ); if (( m=JabberXmlGetChild( n, "EXTADR" )) == NULL ) m = JabberXmlGetChild( n, "EXTADD" ); if ( m!=NULL && m->text!=NULL ) { hasWorkStreet2 = TRUE; JSetStringT( hContact, "CompanyStreet2", m->text ); } } } if (( m=JabberXmlGetChild( n, "LOCALITY" ))!=NULL && m->text!=NULL ) { hasWorkLocality = TRUE; JSetStringT( hContact, "CompanyCity", m->text ); } if (( m=JabberXmlGetChild( n, "REGION" ))!=NULL && m->text!=NULL ) { hasWorkRegion = TRUE; JSetStringT( hContact, "CompanyState", m->text ); } if (( m=JabberXmlGetChild( n, "PCODE" ))!=NULL && m->text!=NULL ) { hasWorkPcode = TRUE; JSetStringT( hContact, "CompanyZIP", m->text ); } if (( m=JabberXmlGetChild( n, "CTRY" ))==NULL || m->text==NULL ) // Some bad client use instead of m = JabberXmlGetChild( n, "COUNTRY" ); if ( m!=NULL && m->text!=NULL ) { hasWorkCtry = TRUE; if ( hContact != NULL ) JSetWord( hContact, "CompanyCountry", ( WORD )JabberCountryNameToId( m->text )); else JSetStringT( hContact, "CompanyCountryName", m->text ); } } } else if ( !strcmp( n->name, "TEL" )) { // Telephone/Fax/Cellular if (( m=JabberXmlGetChild( n, "NUMBER" ))!=NULL && m->text!=NULL ) { if ( hContact != NULL ) { if ( !hasFax && JabberXmlGetChild( n, "FAX" )!=NULL ) { hasFax = TRUE; JSetStringT( hContact, "Fax", m->text ); } if ( !hasCell && JabberXmlGetChild( n, "CELL" )!=NULL ) { hasCell = TRUE; JSetStringT( hContact, "Cellular", m->text ); } if ( !hasPhone && ( JabberXmlGetChild( n, "HOME" )!=NULL || JabberXmlGetChild( n, "WORK" )!=NULL || JabberXmlGetChild( n, "VOICE" )!=NULL || ( JabberXmlGetChild( n, "FAX" )==NULL && JabberXmlGetChild( n, "PAGER" )==NULL && JabberXmlGetChild( n, "MSG" )==NULL && JabberXmlGetChild( n, "CELL" )==NULL && JabberXmlGetChild( n, "VIDEO" )==NULL && JabberXmlGetChild( n, "BBS" )==NULL && JabberXmlGetChild( n, "MODEM" )==NULL && JabberXmlGetChild( n, "ISDN" )==NULL && JabberXmlGetChild( n, "PCS" )==NULL )) ) { hasPhone = TRUE; JSetStringT( hContact, "Phone", m->text ); } } else { char text[ 100 ]; sprintf( text, "Phone%d", nPhone ); JSetStringT( NULL, text, m->text ); sprintf( text, "PhoneFlag%d", nPhone ); int nFlag = 0; if ( JabberXmlGetChild( n, "HOME" ) != NULL ) nFlag |= JABBER_VCTEL_HOME; if ( JabberXmlGetChild( n, "WORK" ) != NULL ) nFlag |= JABBER_VCTEL_WORK; if ( JabberXmlGetChild( n, "VOICE" ) != NULL ) nFlag |= JABBER_VCTEL_VOICE; if ( JabberXmlGetChild( n, "FAX" ) != NULL ) nFlag |= JABBER_VCTEL_FAX; if ( JabberXmlGetChild( n, "PAGER" ) != NULL ) nFlag |= JABBER_VCTEL_PAGER; if ( JabberXmlGetChild( n, "MSG" ) != NULL ) nFlag |= JABBER_VCTEL_MSG; if ( JabberXmlGetChild( n, "CELL" ) != NULL ) nFlag |= JABBER_VCTEL_CELL; if ( JabberXmlGetChild( n, "VIDEO" ) != NULL ) nFlag |= JABBER_VCTEL_VIDEO; if ( JabberXmlGetChild( n, "BBS" ) != NULL ) nFlag |= JABBER_VCTEL_BBS; if ( JabberXmlGetChild( n, "MODEM" ) != NULL ) nFlag |= JABBER_VCTEL_MODEM; if ( JabberXmlGetChild( n, "ISDN" ) != NULL ) nFlag |= JABBER_VCTEL_ISDN; if ( JabberXmlGetChild( n, "PCS" ) != NULL ) nFlag |= JABBER_VCTEL_PCS; JSetWord( NULL, text, nFlag ); nPhone++; } } } else if ( !strcmp( n->name, "URL" )) { // Homepage if ( !hasUrl && n->text!=NULL ) { hasUrl = TRUE; JSetStringT( hContact, "Homepage", n->text ); } } else if ( !strcmp( n->name, "ORG" )) { if ( !hasOrgname && !hasOrgunit ) { if (( m=JabberXmlGetChild( n, "ORGNAME" ))!=NULL && m->text!=NULL ) { hasOrgname = TRUE; JSetStringT( hContact, "Company", m->text ); } if (( m=JabberXmlGetChild( n, "ORGUNIT" ))!=NULL && m->text!=NULL ) { // The real vCard can have multiple but we will only display the first one hasOrgunit = TRUE; JSetStringT( hContact, "CompanyDepartment", m->text ); } } } else if ( !strcmp( n->name, "ROLE" )) { if ( !hasRole && n->text!=NULL ) { hasRole = TRUE; JSetStringT( hContact, "Role", n->text ); } } else if ( !strcmp( n->name, "TITLE" )) { if ( !hasTitle && n->text!=NULL ) { hasTitle = TRUE; JSetStringT( hContact, "CompanyPosition", n->text ); } } else if ( !strcmp( n->name, "DESC" )) { if ( !hasDesc && n->text!=NULL ) { hasDesc = TRUE; TCHAR* szMemo = JabberUnixToDosT( n->text ); JSetStringT( hContact, "About", szMemo ); mir_free( szMemo ); } } else if ( !strcmp( n->name, "PHOTO" )) JabberIqResultGetVcardPhoto( jid, n, hContact, hasPhoto ); } } if ( !hasFn ) JDeleteSetting( hContact, "FullName" ); // We are not deleting "Nick" // if ( !hasNick ) // JDeleteSetting( hContact, "Nick" ); if ( !hasGiven ) JDeleteSetting( hContact, "FirstName" ); if ( !hasFamily ) JDeleteSetting( hContact, "LastName" ); if ( !hasMiddle ) JDeleteSetting( hContact, "MiddleName" ); if ( hContact != NULL ) { while ( true ) { if ( nEmail <= 0 ) JDeleteSetting( hContact, "e-mail" ); else { char text[ 100 ]; sprintf( text, "e-mail%d", nEmail-1 ); if ( DBGetContactSetting( hContact, jabberProtoName, text, &dbv )) break; JFreeVariant( &dbv ); JDeleteSetting( hContact, text ); } nEmail++; } } else { while ( true ) { char text[ 100 ]; sprintf( text, "e-mail%d", nEmail ); if ( DBGetContactSetting( NULL, jabberProtoName, text, &dbv )) break; JFreeVariant( &dbv ); JDeleteSetting( NULL, text ); sprintf( text, "e-mailFlag%d", nEmail ); JDeleteSetting( NULL, text ); nEmail++; } } if ( !hasBday ) { JDeleteSetting( hContact, "BirthYear" ); JDeleteSetting( hContact, "BirthMonth" ); JDeleteSetting( hContact, "BirthDay" ); JDeleteSetting( hContact, "BirthDate" ); } if ( !hasGender ) { if ( hContact != NULL ) JDeleteSetting( hContact, "Gender" ); else JDeleteSetting( NULL, "GenderString" ); } if ( hContact != NULL ) { if ( !hasPhone ) JDeleteSetting( hContact, "Phone" ); if ( !hasFax ) JDeleteSetting( hContact, "Fax" ); if ( !hasCell ) JDeleteSetting( hContact, "Cellular" ); } else { while ( true ) { char text[ 100 ]; sprintf( text, "Phone%d", nPhone ); if ( DBGetContactSetting( NULL, jabberProtoName, text, &dbv )) break; JFreeVariant( &dbv ); JDeleteSetting( NULL, text ); sprintf( text, "PhoneFlag%d", nPhone ); JDeleteSetting( NULL, text ); nPhone++; } } if ( !hasHomeStreet ) JDeleteSetting( hContact, "Street" ); if ( !hasHomeStreet2 && hContact==NULL ) JDeleteSetting( hContact, "Street2" ); if ( !hasHomeLocality ) JDeleteSetting( hContact, "City" ); if ( !hasHomeRegion ) JDeleteSetting( hContact, "State" ); if ( !hasHomePcode ) JDeleteSetting( hContact, "ZIP" ); if ( !hasHomeCtry ) { if ( hContact != NULL ) JDeleteSetting( hContact, "Country" ); else JDeleteSetting( hContact, "CountryName" ); } if ( !hasWorkStreet ) JDeleteSetting( hContact, "CompanyStreet" ); if ( !hasWorkStreet2 && hContact==NULL ) JDeleteSetting( hContact, "CompanyStreet2" ); if ( !hasWorkLocality ) JDeleteSetting( hContact, "CompanyCity" ); if ( !hasWorkRegion ) JDeleteSetting( hContact, "CompanyState" ); if ( !hasWorkPcode ) JDeleteSetting( hContact, "CompanyZIP" ); if ( !hasWorkCtry ) { if ( hContact != NULL ) JDeleteSetting( hContact, "CompanyCountry" ); else JDeleteSetting( hContact, "CompanyCountryName" ); } if ( !hasUrl ) JDeleteSetting( hContact, "Homepage" ); if ( !hasOrgname ) JDeleteSetting( hContact, "Company" ); if ( !hasOrgunit ) JDeleteSetting( hContact, "CompanyDepartment" ); if ( !hasRole ) JDeleteSetting( hContact, "Role" ); if ( !hasTitle ) JDeleteSetting( hContact, "CompanyPosition" ); if ( !hasDesc ) JDeleteSetting( hContact, "About" ); if ( !hasPhoto && jabberVcardPhotoFileName!=NULL ) { DeleteFileA( jabberVcardPhotoFileName ); jabberVcardPhotoFileName = NULL; } if ( hContact != NULL ) JSendBroadcast( hContact, ACKTYPE_GETINFO, ACKRESULT_SUCCESS, ( HANDLE ) 1, 0 ); else if ( hwndJabberVcard ) SendMessage( hwndJabberVcard, WM_JABBER_REFRESH, 0, 0 ); } else if ( !lstrcmp( type, _T("error"))) { if ( hContact != NULL ) JSendBroadcast( hContact, ACKTYPE_GETINFO, ACKRESULT_FAILED, ( HANDLE ) 1, 0 ); } } void JabberIqResultSetVcard( XmlNode *iqNode, void *userdata ) { JabberLog( " iqIdSetVcard" ); TCHAR* type = JabberXmlGetAttrValue( iqNode, "type" ); if ( type == NULL ) return; if ( hwndJabberVcard ) SendMessage( hwndJabberVcard, WM_JABBER_REFRESH, 0, 0 ); } void JabberIqResultSetSearch( XmlNode *iqNode, void *userdata ) { XmlNode *queryNode, *itemNode, *n; TCHAR* type, *jid, *str; int id, i; JABBER_SEARCH_RESULT jsr; JabberLog( " iqIdGetSearch" ); if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return; if (( str=JabberXmlGetAttrValue( iqNode, "id" )) == NULL ) return; id = _ttoi( str+strlen( JABBER_IQID )); if ( !lstrcmp( type, _T("result"))) { if (( queryNode=JabberXmlGetChild( iqNode, "query" )) == NULL ) return; jsr.hdr.cbSize = sizeof( JABBER_SEARCH_RESULT ); for ( i=0; inumChild; i++ ) { itemNode = queryNode->child[i]; if ( !lstrcmpA( itemNode->name, "item" )) { if (( jid=JabberXmlGetAttrValue( itemNode, "jid" )) != NULL ) { _tcsncpy( jsr.jid, jid, SIZEOF( jsr.jid )); jsr.jid[ SIZEOF( jsr.jid )-1] = '\0'; JabberLog( "Result jid = " TCHAR_STR_PARAM, jid ); if (( n=JabberXmlGetChild( itemNode, "nick" ))!=NULL && n->text!=NULL ) jsr.hdr.nick = t2a( n->text ); else jsr.hdr.nick = mir_strdup( "" ); if (( n=JabberXmlGetChild( itemNode, "first" ))!=NULL && n->text!=NULL ) jsr.hdr.firstName = t2a( n->text ); else jsr.hdr.firstName = mir_strdup( "" ); if (( n=JabberXmlGetChild( itemNode, "last" ))!=NULL && n->text!=NULL ) jsr.hdr.lastName = t2a( n->text ); else jsr.hdr.lastName = mir_strdup( "" ); if (( n=JabberXmlGetChild( itemNode, "email" ))!=NULL && n->text!=NULL ) jsr.hdr.email = t2a( n->text ); else jsr.hdr.email = mir_strdup( "" ); JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, ( HANDLE ) id, ( LPARAM )&jsr ); mir_free( jsr.hdr.nick ); mir_free( jsr.hdr.firstName ); mir_free( jsr.hdr.lastName ); mir_free( jsr.hdr.email ); } } } JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, ( HANDLE ) id, 0 ); } else if ( !lstrcmp( type, _T("error"))) JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, ( HANDLE ) id, 0 ); } void JabberIqResultExtSearch( XmlNode *iqNode, void *userdata ) { XmlNode *queryNode; TCHAR* type, *str; JabberLog( " iqIdGetExtSearch" ); if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return; if (( str=JabberXmlGetAttrValue( iqNode, "id" )) == NULL ) return; int id = _ttoi( str+strlen( JABBER_IQID )); if ( !lstrcmp( type, _T("result"))) { if (( queryNode=JabberXmlGetChild( iqNode, "query" )) == NULL ) return; if (( queryNode=JabberXmlGetChild( queryNode, "x" )) == NULL ) return; for ( int i=0; inumChild; i++ ) { XmlNode* itemNode = queryNode->child[i]; if ( strcmp( itemNode->name, "item" )) continue; JABBER_SEARCH_RESULT jsr = { 0 }; jsr.hdr.cbSize = sizeof( JABBER_SEARCH_RESULT ); // jsr.hdr.firstName = ""; for ( int j=0; j < itemNode->numChild; j++ ) { XmlNode* fieldNode = itemNode->child[j]; if ( strcmp( fieldNode->name, "field" )) continue; TCHAR* fieldName = JabberXmlGetAttrValue( fieldNode, "var" ); if ( fieldName == NULL ) continue; XmlNode* n = JabberXmlGetChild( fieldNode, "value" ); if ( n == NULL ) continue; if ( !lstrcmp( fieldName, _T("jid"))) { _tcsncpy( jsr.jid, n->text, SIZEOF( jsr.jid )); jsr.jid[sizeof( jsr.jid )-1] = '\0'; JabberLog( "Result jid = " TCHAR_STR_PARAM, jsr.jid ); } else if ( !lstrcmp( fieldName, _T("nickname"))) jsr.hdr.nick = ( n->text != NULL ) ? t2a( n->text ) : mir_strdup( "" ); else if ( !lstrcmp( fieldName, _T("fn"))) { mir_free( jsr.hdr.firstName ); jsr.hdr.firstName = ( n->text != NULL ) ? t2a(n->text) : mir_strdup( "" ); } else if ( !lstrcmp( fieldName, _T("given"))) { mir_free( jsr.hdr.firstName ); jsr.hdr.firstName = ( n->text != NULL ) ? t2a(n->text) : mir_strdup( "" ); } else if ( !lstrcmp( fieldName, _T("family"))) jsr.hdr.lastName = ( n->text != NULL ) ? t2a(n->text) : mir_strdup( "" ); else if ( !lstrcmp( fieldName, _T("email"))) jsr.hdr.email = ( n->text != NULL ) ? t2a(n->text) : mir_strdup( "" ); } JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, ( HANDLE ) id, ( LPARAM )&jsr ); mir_free( jsr.hdr.nick ); mir_free( jsr.hdr.firstName ); mir_free( jsr.hdr.lastName ); mir_free( jsr.hdr.email ); } JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, ( HANDLE ) id, 0 ); } else if ( !lstrcmp( type, _T("error"))) JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, ( HANDLE ) id, 0 ); } void JabberIqResultSetPassword( XmlNode *iqNode, void *userdata ) { JabberLog( " iqIdSetPassword" ); TCHAR* type = JabberXmlGetAttrValue( iqNode, "type" ); if ( type == NULL ) return; if ( !lstrcmp( type, _T("result"))) { strncpy( jabberThreadInfo->password, jabberThreadInfo->newPassword, SIZEOF( jabberThreadInfo->password )); MessageBox( NULL, TranslateT( "Password is successfully changed. Don't forget to update your password in the Jabber protocol option." ), TranslateT( "Change Password" ), MB_OK|MB_ICONINFORMATION|MB_SETFOREGROUND ); } else if ( !lstrcmp( type, _T("error"))) MessageBox( NULL, TranslateT( "Password cannot be changed." ), TranslateT( "Change Password" ), MB_OK|MB_ICONSTOP|MB_SETFOREGROUND ); } void JabberIqResultDiscoAgentItems( XmlNode *iqNode, void *userdata ) { ThreadData* info = ( ThreadData* ) userdata; XmlNode *queryNode, *itemNode; TCHAR* type, *jid, *from; // RECVED: agent list // ACTION: refresh agent list dialog JabberLog( " iqIdDiscoAgentItems" ); if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return; if (( from=JabberXmlGetAttrValue( iqNode, "from" )) == NULL ) return; if ( !lstrcmp( type, _T("result"))) { if (( queryNode=JabberXmlGetChild( iqNode, "query" )) != NULL ) { TCHAR* str = JabberXmlGetAttrValue( queryNode, "xmlns" ); if ( !lstrcmp( str, _T("http://jabber.org/protocol/disco#items"))) { JabberListRemoveList( LIST_AGENT ); for ( int i=0; inumChild; i++ ) { if (( itemNode=queryNode->child[i] )!=NULL && itemNode->name!=NULL && !lstrcmpA( itemNode->name, "item" )) { if (( jid=JabberXmlGetAttrValue( itemNode, "jid" )) != NULL ) { JABBER_LIST_ITEM* item = JabberListAdd( LIST_AGENT, jid ); replaceStr( item->name, JabberXmlGetAttrValue( itemNode, "name" )); item->cap = AGENT_CAP_REGISTER | AGENT_CAP_GROUPCHAT; // default to all cap until specific info is later received int iqId = JabberSerialNext(); JabberIqAdd( iqId, IQ_PROC_NONE, JabberIqResultDiscoAgentInfo ); XmlNodeIq iq( "get", iqId, jid ); XmlNode* query = iq.addQuery( "http://jabber.org/protocol/disco#info" ); JabberSend( jabberThreadInfo->s, iq ); } } } } } if ( hwndJabberAgents != NULL ) { if (( jid=JabberXmlGetAttrValue( iqNode, "from" )) != NULL ) SendMessage( hwndJabberAgents, WM_JABBER_AGENT_REFRESH, 0, ( LPARAM )jid ); else SendMessage( hwndJabberAgents, WM_JABBER_AGENT_REFRESH, 0, ( LPARAM )info->server ); } } else if ( !lstrcmp( type, _T("error"))) { // disco is not supported, try jabber:iq:agents int iqId = JabberSerialNext(); JabberIqAdd( iqId, IQ_PROC_GETAGENTS, JabberIqResultGetAgents ); XmlNodeIq iq( "get", iqId, from ); XmlNode* query = iq.addQuery( "jabber:iq:agents" ); JabberSend( jabberThreadInfo->s, iq ); } } void JabberIqResultDiscoAgentInfo( XmlNode *iqNode, void *userdata ) { ThreadData* info = ( ThreadData* ) userdata; XmlNode *queryNode, *itemNode, *identityNode; TCHAR* type, *from, *var; JABBER_LIST_ITEM *item; // RECVED: info for a specific agent // ACTION: refresh agent list dialog JabberLog( " iqIdDiscoAgentInfo" ); if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return; if (( from = JabberXmlGetAttrValue( iqNode, "from" )) == NULL ) return; if ( !lstrcmp( type, _T("result"))) { if (( queryNode=JabberXmlGetChild( iqNode, "query" )) != NULL ) { TCHAR* str = JabberXmlGetAttrValue( queryNode, "xmlns" ); if ( !lstrcmp( str, _T("http://jabber.org/protocol/disco#info"))) { if (( item=JabberListGetItemPtr( LIST_AGENT, from )) != NULL ) { // Use the first to set name if (( identityNode=JabberXmlGetChild( queryNode, "identity" )) != NULL ) { if (( str=JabberXmlGetAttrValue( identityNode, "name" )) != NULL ) replaceStr( item->name, str ); } item->cap = 0; for ( int i=0; inumChild; i++ ) { if (( itemNode=queryNode->child[i] )!=NULL && itemNode->name!=NULL ) { if ( !strcmp( itemNode->name, "feature" )) { if (( var=JabberXmlGetAttrValue( itemNode, "var" )) != NULL ) { if ( !lstrcmp( var, _T("jabber:iq:register"))) item->cap |= AGENT_CAP_REGISTER; else if ( !lstrcmp( var, _T("http://jabber.org/protocol/muc"))) item->cap |= AGENT_CAP_GROUPCHAT; } } } } } } } if ( hwndJabberAgents != NULL ) SendMessage( hwndJabberAgents, WM_JABBER_AGENT_REFRESH, 0, ( LPARAM )NULL ); } } void JabberIqResultDiscoClientInfo( XmlNode *iqNode, void *userdata ) { ThreadData* info = ( ThreadData* ) userdata; XmlNode *queryNode, *itemNode; TCHAR* type, *from, *var; JABBER_LIST_ITEM *item; // RECVED: info for a specific client // ACTION: update client cap // ACTION: if item->ft is pending, initiate file transfer JabberLog( " iqIdDiscoClientInfo" ); if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return; if (( from=JabberXmlGetAttrValue( iqNode, "from" )) == NULL ) return; if ( lstrcmp( type, _T("result")) != 0 ) return; if (( item=JabberListGetItemPtr( LIST_ROSTER, from )) == NULL ) return; if (( queryNode=JabberXmlGetChild( iqNode, "query" )) != NULL ) { TCHAR* str = JabberXmlGetAttrValue( queryNode, "xmlns" ); if ( !lstrcmp( str, _T("http://jabber.org/protocol/disco#info"))) { item->cap = CLIENT_CAP_READY; for ( int i=0; inumChild; i++ ) { if (( itemNode=queryNode->child[i] )!=NULL && itemNode->name!=NULL ) { if ( !strcmp( itemNode->name, "feature" )) { if (( var=JabberXmlGetAttrValue( itemNode, "var" )) != NULL ) { if ( !lstrcmp( var, _T("http://jabber.org/protocol/si"))) item->cap |= CLIENT_CAP_SI; else if ( !lstrcmp( var, _T("http://jabber.org/protocol/si/profile/file-transfer"))) item->cap |= CLIENT_CAP_SIFILE; else if ( !lstrcmp( var, _T("http://jabber.org/protocol/bytestreams"))) item->cap |= CLIENT_CAP_BYTESTREAM; } } } } } } // Check for pending file transfer session request if ( item->ft != NULL ) { filetransfer* ft = item->ft; item->ft = NULL; if (( item->cap & CLIENT_CAP_FILE ) && ( item->cap & CLIENT_CAP_BYTESTREAM )) JabberFtInitiate( item->jid, ft ); else JabberForkThread(( JABBER_THREAD_FUNC )JabberFileServerThread, 0, ft ); } } void JabberIqResultGetAvatar( XmlNode *iqNode, void *userdata ) { if ( !JGetByte( "EnableAvatars", TRUE )) return; ThreadData* info = ( ThreadData* ) userdata; TCHAR* type; // RECVED: agent list // ACTION: refresh agent list dialog JabberLog( " iqIdResultGetAvatar" ); if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return; if ( _tcscmp( type, _T("result"))) return; TCHAR* from = JabberXmlGetAttrValue( iqNode, "from" ); if ( from == NULL ) return; HANDLE hContact = JabberHContactFromJID( from ); if ( hContact == NULL ) return; XmlNode* n = NULL; TCHAR* mimeType = NULL; if (JGetByte(hContact,"AvatarXVcard",0)){ XmlNode *vCard = JabberXmlGetChild( iqNode, "vCard" ); if (vCard == NULL) return; vCard = JabberXmlGetChild( vCard, "PHOTO" ); if (vCard == NULL) return; XmlNode *typeNode = JabberXmlGetChild( vCard, "TYPE" ); if (typeNode != NULL) mimeType = typeNode->text; n = JabberXmlGetChild( vCard, "BINVAL" ); }else { XmlNode *queryNode = JabberXmlGetChild( iqNode, "query" ); if ( queryNode == NULL ) return; TCHAR* xmlns = JabberXmlGetAttrValue( queryNode, "xmlns" ); if ( lstrcmp( xmlns, _T("jabber:iq:avatar"))) return; mimeType = JabberXmlGetAttrValue( n, "mimetype" ); n = JabberXmlGetChild( queryNode, "data" ); } if ( n == NULL ) return; int resultLen = 0; char* body = JabberBase64Decode( n->text, &resultLen ); int pictureType; if ( mimeType != NULL ) { if ( !lstrcmp( mimeType, _T("image/jpeg"))) pictureType = PA_FORMAT_JPEG; else if ( !lstrcmp( mimeType, _T("image/png"))) pictureType = PA_FORMAT_PNG; else if ( !lstrcmp( mimeType, _T("image/gif"))) pictureType = PA_FORMAT_GIF; else if ( !lstrcmp( mimeType, _T("image/bmp"))) pictureType = PA_FORMAT_BMP; else { LBL_ErrFormat: JabberLog( "Invalid mime type specified for picture: " TCHAR_STR_PARAM, mimeType ); mir_free( body ); return; } } else if (( pictureType = JabberGetPictureType( body )) == PA_FORMAT_UNKNOWN ) goto LBL_ErrFormat; PROTO_AVATAR_INFORMATION AI; AI.cbSize = sizeof AI; AI.format = pictureType; AI.hContact = hContact; if ( JGetByte( hContact, "AvatarType", PA_FORMAT_UNKNOWN ) != (unsigned char)pictureType ) { JabberGetAvatarFileName( hContact, AI.filename, sizeof AI.filename ); DeleteFileA( AI.filename ); } JSetByte( hContact, "AvatarType", pictureType ); char buffer[ 41 ]; uint8_t digest[20]; SHA1Context sha; SHA1Reset( &sha ); SHA1Input( &sha, ( const unsigned __int8* )body, resultLen ); SHA1Result( &sha, digest ); for ( int i=0; i<20; i++ ) sprintf( buffer+( i<<1 ), "%02x", digest[i] ); JSetString( hContact, "AvatarSaved", buffer ); JabberGetAvatarFileName( hContact, AI.filename, sizeof AI.filename ); DBWriteContactSettingString( hContact, "ContactPhoto", "File", AI.filename ); FILE* out = fopen( AI.filename, "wb" ); if ( out != NULL ) { fwrite( body, resultLen, 1, out ); fclose( out ); JSendBroadcast( hContact, ACKTYPE_AVATAR, ACKRESULT_SUCCESS, HANDLE( &AI ), NULL ); JabberLog("Broadcast new avatar: %s",AI.filename); } else JSendBroadcast( hContact, ACKTYPE_AVATAR, ACKRESULT_FAILED, HANDLE( &AI ), NULL ); mir_free( body ); }