diff options
author | watcherhd <watcherhd@e753b5eb-9565-29b2-b5c5-2cc6f99dfbcb> | 2011-04-21 14:14:52 +0000 |
---|---|---|
committer | watcherhd <watcherhd@e753b5eb-9565-29b2-b5c5-2cc6f99dfbcb> | 2011-04-21 14:14:52 +0000 |
commit | cb4a46e7fbe62d788e66ed6121c717a2d22a4d7c (patch) | |
tree | 30df260fdc5a1b5a7049c2f8cac8b7ef17513d6d /miranda-wine/protocols/JabberG | |
parent | 19b6f534d2e784a1e120bf52c4aa07004798f473 (diff) |
svn.miranda.im is moving to a new home!
git-svn-id: http://miranda-plugins.googlecode.com/svn/trunk@7 e753b5eb-9565-29b2-b5c5-2cc6f99dfbcb
Diffstat (limited to 'miranda-wine/protocols/JabberG')
60 files changed, 19222 insertions, 0 deletions
diff --git a/miranda-wine/protocols/JabberG/icos/add2roster.ico b/miranda-wine/protocols/JabberG/icos/add2roster.ico Binary files differnew file mode 100644 index 0000000..170e255 --- /dev/null +++ b/miranda-wine/protocols/JabberG/icos/add2roster.ico diff --git a/miranda-wine/protocols/JabberG/icos/addcontact.ico b/miranda-wine/protocols/JabberG/icos/addcontact.ico Binary files differnew file mode 100644 index 0000000..2efc4dc --- /dev/null +++ b/miranda-wine/protocols/JabberG/icos/addcontact.ico diff --git a/miranda-wine/protocols/JabberG/icos/block.ico b/miranda-wine/protocols/JabberG/icos/block.ico Binary files differnew file mode 100644 index 0000000..a71ddd4 --- /dev/null +++ b/miranda-wine/protocols/JabberG/icos/block.ico diff --git a/miranda-wine/protocols/JabberG/icos/delete.ico b/miranda-wine/protocols/JabberG/icos/delete.ico Binary files differnew file mode 100644 index 0000000..c541793 --- /dev/null +++ b/miranda-wine/protocols/JabberG/icos/delete.ico diff --git a/miranda-wine/protocols/JabberG/icos/grant.ico b/miranda-wine/protocols/JabberG/icos/grant.ico Binary files differnew file mode 100644 index 0000000..08b6710 --- /dev/null +++ b/miranda-wine/protocols/JabberG/icos/grant.ico diff --git a/miranda-wine/protocols/JabberG/icos/group.ico b/miranda-wine/protocols/JabberG/icos/group.ico Binary files differnew file mode 100644 index 0000000..3303179 --- /dev/null +++ b/miranda-wine/protocols/JabberG/icos/group.ico diff --git a/miranda-wine/protocols/JabberG/icos/jabber.ico b/miranda-wine/protocols/JabberG/icos/jabber.ico Binary files differnew file mode 100644 index 0000000..27d618c --- /dev/null +++ b/miranda-wine/protocols/JabberG/icos/jabber.ico diff --git a/miranda-wine/protocols/JabberG/icos/key.ico b/miranda-wine/protocols/JabberG/icos/key.ico Binary files differnew file mode 100644 index 0000000..a82c4c4 --- /dev/null +++ b/miranda-wine/protocols/JabberG/icos/key.ico diff --git a/miranda-wine/protocols/JabberG/icos/open.ico b/miranda-wine/protocols/JabberG/icos/open.ico Binary files differnew file mode 100644 index 0000000..c6d213b --- /dev/null +++ b/miranda-wine/protocols/JabberG/icos/open.ico diff --git a/miranda-wine/protocols/JabberG/icos/pages.ico b/miranda-wine/protocols/JabberG/icos/pages.ico Binary files differnew file mode 100644 index 0000000..af93fd2 --- /dev/null +++ b/miranda-wine/protocols/JabberG/icos/pages.ico diff --git a/miranda-wine/protocols/JabberG/icos/rename.ico b/miranda-wine/protocols/JabberG/icos/rename.ico Binary files differnew file mode 100644 index 0000000..6dd597e --- /dev/null +++ b/miranda-wine/protocols/JabberG/icos/rename.ico diff --git a/miranda-wine/protocols/JabberG/icos/request.ico b/miranda-wine/protocols/JabberG/icos/request.ico Binary files differnew file mode 100644 index 0000000..b183e31 --- /dev/null +++ b/miranda-wine/protocols/JabberG/icos/request.ico diff --git a/miranda-wine/protocols/JabberG/icos/save.ico b/miranda-wine/protocols/JabberG/icos/save.ico Binary files differnew file mode 100644 index 0000000..bf2fe98 --- /dev/null +++ b/miranda-wine/protocols/JabberG/icos/save.ico diff --git a/miranda-wine/protocols/JabberG/icos/user2room.ico b/miranda-wine/protocols/JabberG/icos/user2room.ico Binary files differnew file mode 100644 index 0000000..8acddbb --- /dev/null +++ b/miranda-wine/protocols/JabberG/icos/user2room.ico diff --git a/miranda-wine/protocols/JabberG/icos/write.ico b/miranda-wine/protocols/JabberG/icos/write.ico Binary files differnew file mode 100644 index 0000000..b799ba2 --- /dev/null +++ b/miranda-wine/protocols/JabberG/icos/write.ico diff --git a/miranda-wine/protocols/JabberG/jabber.cpp b/miranda-wine/protocols/JabberG/jabber.cpp new file mode 100644 index 0000000..378812a --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber.cpp @@ -0,0 +1,350 @@ +/*
+
+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.cpp,v $
+Revision : $Revision: 3611 $
+Last change on : $Date: 2006-08-27 23:36:15 +0400 (Вск, 27 Авг 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+#include "jabber_ssl.h"
+#include "jabber_iq.h"
+#include "resource.h"
+#include "version.h"
+
+HINSTANCE hInst;
+PLUGINLINK *pluginLink;
+
+PLUGININFO pluginInfo = {
+ sizeof( PLUGININFO ),
+ #if defined( _UNICODE )
+ "Jabber Protocol (Unicode)",
+ #else
+ "Jabber Protocol",
+ #endif
+ __VERSION_DWORD,
+ "Jabber protocol plugin for Miranda IM ( "__DATE__" )",
+ "George Hazan",
+ "ghazan@miranda-im.org",
+ "( c ) 2002-05 Santithorn Bunchua, George Hazan",
+ "http://miranda-im.org/download/details.php?action=viewfile&id=437",
+ 0,
+ 0
+};
+
+MM_INTERFACE memoryManagerInterface;
+LIST_INTERFACE li;
+
+HANDLE hMainThread = NULL;
+DWORD jabberMainThreadId;
+char* jabberProtoName; // "JABBER"
+char* jabberModuleName; // "Jabber"
+CRITICAL_SECTION mutex;
+HANDLE hNetlibUser;
+// Main jabber server connection thread global variables
+struct ThreadData *jabberThreadInfo = NULL;
+BOOL jabberConnected = FALSE;
+time_t jabberLoggedInTime = 0;
+BOOL jabberOnline = FALSE;
+BOOL jabberChatDllPresent = FALSE;
+int jabberStatus = ID_STATUS_OFFLINE;
+int jabberDesiredStatus;
+BOOL modeMsgStatusChangePending = FALSE;
+BOOL jabberChangeStatusMessageOnly = FALSE;
+TCHAR* jabberJID = NULL;
+char* streamId = NULL;
+DWORD jabberLocalIP;
+UINT jabberCodePage;
+JABBER_MODEMSGS modeMsgs;
+//char* jabberModeMsg;
+CRITICAL_SECTION modeMsgMutex;
+char* jabberVcardPhotoFileName = NULL;
+char* jabberVcardPhotoType = NULL;
+BOOL jabberSendKeepAlive;
+
+// SSL-related global variable
+HMODULE hLibSSL = NULL;
+PVOID jabberSslCtx;
+
+const char xmlnsAdmin[] = "http://jabber.org/protocol/muc#admin";
+const char xmlnsOwner[] = "http://jabber.org/protocol/muc#owner";
+
+HWND hwndJabberAgents = NULL;
+HWND hwndJabberGroupchat = NULL;
+HWND hwndJabberJoinGroupchat = NULL;
+HWND hwndAgentReg = NULL;
+HWND hwndAgentRegInput = NULL;
+HWND hwndAgentManualReg = NULL;
+HWND hwndRegProgress = NULL;
+HWND hwndJabberVcard = NULL;
+HWND hwndMucVoiceList = NULL;
+HWND hwndMucMemberList = NULL;
+HWND hwndMucModeratorList = NULL;
+HWND hwndMucBanList = NULL;
+HWND hwndMucAdminList = NULL;
+HWND hwndMucOwnerList = NULL;
+HWND hwndJabberChangePassword = NULL;
+
+// Service and event handles
+HANDLE heventRawXMLIn;
+HANDLE heventRawXMLOut;
+
+int JabberOptInit( WPARAM wParam, LPARAM lParam );
+int JabberUserInfoInit( WPARAM wParam, LPARAM lParam );
+int JabberMsgUserTyping( WPARAM wParam, LPARAM lParam );
+void JabberMenuInit( void );
+int JabberSvcInit( void );
+int JabberSvcUninit( void );
+
+extern "C" BOOL WINAPI DllMain( HINSTANCE hModule, DWORD dwReason, LPVOID lpvReserved )
+{
+ #ifdef _DEBUG
+ _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
+ #endif
+ hInst = hModule;
+ return TRUE;
+}
+
+extern "C" __declspec( dllexport ) PLUGININFO *MirandaPluginInfo( DWORD mirandaVersion )
+{
+ if ( mirandaVersion < PLUGIN_MAKE_VERSION( 0,5,0,0 )) {
+ MessageBoxA( NULL, "The Jabber protocol plugin cannot be loaded. It requires Miranda IM 0.5 or later.", "Jabber Protocol Plugin", MB_OK|MB_ICONWARNING|MB_SETFOREGROUND|MB_TOPMOST );
+ return NULL;
+ }
+
+ return &pluginInfo;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// OnPreShutdown - prepares Miranda to be shut down
+
+static int OnPreShutdown( WPARAM wParam, LPARAM lParam )
+{
+ if ( hwndJabberAgents ) SendMessage( hwndJabberAgents, WM_CLOSE, 0, 0 );
+ if ( hwndJabberGroupchat ) SendMessage( hwndJabberGroupchat, WM_CLOSE, 0, 0 );
+ if ( hwndJabberJoinGroupchat ) SendMessage( hwndJabberJoinGroupchat, WM_CLOSE, 0, 0 );
+ if ( hwndAgentReg ) SendMessage( hwndAgentReg, WM_CLOSE, 0, 0 );
+ if ( hwndAgentRegInput ) SendMessage( hwndAgentRegInput, WM_CLOSE, 0, 0 );
+ if ( hwndRegProgress ) SendMessage( hwndRegProgress, WM_CLOSE, 0, 0 );
+ if ( hwndJabberVcard ) SendMessage( hwndJabberVcard, WM_CLOSE, 0, 0 );
+ if ( hwndMucVoiceList ) SendMessage( hwndMucVoiceList, WM_CLOSE, 0, 0 );
+ if ( hwndMucMemberList ) SendMessage( hwndMucMemberList, WM_CLOSE, 0, 0 );
+ if ( hwndMucModeratorList ) SendMessage( hwndMucModeratorList, WM_CLOSE, 0, 0 );
+ if ( hwndMucBanList ) SendMessage( hwndMucBanList, WM_CLOSE, 0, 0 );
+ if ( hwndMucAdminList ) SendMessage( hwndMucAdminList, WM_CLOSE, 0, 0 );
+ if ( hwndMucOwnerList ) SendMessage( hwndMucOwnerList, WM_CLOSE, 0, 0 );
+ if ( hwndJabberChangePassword ) SendMessage( hwndJabberChangePassword, WM_CLOSE, 0, 0 );
+
+ hwndJabberAgents = NULL;
+ hwndJabberGroupchat = NULL;
+ hwndJabberJoinGroupchat = NULL;
+ hwndAgentReg = NULL;
+ hwndAgentRegInput = NULL;
+ hwndAgentManualReg = NULL;
+ hwndRegProgress = NULL;
+ hwndJabberVcard = NULL;
+ hwndMucVoiceList = NULL;
+ hwndMucMemberList = NULL;
+ hwndMucModeratorList = NULL;
+ hwndMucBanList = NULL;
+ hwndMucAdminList = NULL;
+ hwndMucOwnerList = NULL;
+ hwndJabberChangePassword = NULL;
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// OnModulesLoaded - execute some code when all plugins are initialized
+
+int JabberGcEventHook( WPARAM, LPARAM );
+int JabberGcMenuHook( WPARAM, LPARAM );
+int JabberGcInit( WPARAM, LPARAM );
+
+static COLORREF crCols[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
+HANDLE hChatEvent = NULL,
+ hChatMenu = NULL,
+ hChatMess = NULL,
+ hInitChat = NULL,
+ hEvInitChat = NULL,
+ hEvModulesLoaded = NULL,
+ hEvOptInit = NULL,
+ hEvPreShutdown = NULL,
+ hEvUserInfoInit = NULL;
+
+static int OnModulesLoaded( WPARAM wParam, LPARAM lParam )
+{
+ JabberWsInit();
+ JabberSslInit();
+ HookEvent( ME_USERINFO_INITIALISE, JabberUserInfoInit );
+
+ if ( ServiceExists( MS_GC_REGISTER )) {
+ jabberChatDllPresent = true;
+
+ GCREGISTER gcr = {0};
+ gcr.cbSize = sizeof( GCREGISTER );
+ gcr.dwFlags = GC_TYPNOTIF|GC_CHANMGR;
+ gcr.iMaxText = 0;
+ gcr.nColors = 16;
+ gcr.pColors = &crCols[0];
+ gcr.pszModuleDispName = jabberProtoName;
+ gcr.pszModule = jabberProtoName;
+ JCallService( MS_GC_REGISTER, NULL, ( LPARAM )&gcr );
+
+ hChatEvent = HookEvent( ME_GC_EVENT, JabberGcEventHook );
+ hChatMenu = HookEvent( ME_GC_BUILDMENU, JabberGcMenuHook );
+
+ char szEvent[ 200 ];
+ mir_snprintf( szEvent, sizeof szEvent, "%s\\ChatInit", jabberProtoName );
+ hInitChat = CreateHookableEvent( szEvent );
+ hEvInitChat = HookEvent( szEvent, JabberGcInit );
+ }
+
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// OnLoad - initialize the plugin instance
+
+extern "C" int __declspec( dllexport ) Load( PLUGINLINK *link )
+{
+ pluginLink = link;
+
+ // set the memory manager
+ memoryManagerInterface.cbSize = sizeof(MM_INTERFACE);
+ JCallService(MS_SYSTEM_GET_MMI,0,(LPARAM)&memoryManagerInterface);
+
+ // set the lists manager;
+ li.cbSize = sizeof( li );
+ if ( CallService(MS_SYSTEM_GET_LI,0,(LPARAM)&li) == CALLSERVICE_NOTFOUND ) {
+ MessageBoxA( NULL, "This plugin requires Miranda IM 0.5 or later", "Fatal error", MB_OK );
+ return 1;
+ }
+
+ if ( !ServiceExists( MS_DB_CONTACT_GETSETTING_STR )) {
+ MessageBoxA( NULL, "This plugin requires db3x plugin version 0.5.1.0 or later", "Jabber", MB_OK );
+ return 1;
+ }
+
+ char text[_MAX_PATH];
+ char* p, *q;
+
+ GetModuleFileNameA( hInst, text, sizeof( text ));
+ p = strrchr( text, '\\' );
+ p++;
+ q = strrchr( p, '.' );
+ *q = '\0';
+ jabberProtoName = mir_strdup( p );
+ _strupr( jabberProtoName );
+
+ mir_snprintf( text, sizeof( text ), "%s/Status", jabberProtoName );
+ JCallService( MS_DB_SETSETTINGRESIDENT, TRUE, ( LPARAM )text );
+
+ jabberModuleName = mir_strdup( jabberProtoName );
+ _strlwr( jabberModuleName );
+ jabberModuleName[0] = toupper( jabberModuleName[0] );
+
+ JabberLog( "Setting protocol/module name to '%s/%s'", jabberProtoName, jabberModuleName );
+
+ DuplicateHandle( GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &hMainThread, THREAD_SET_CONTEXT, FALSE, 0 );
+ jabberMainThreadId = GetCurrentThreadId();
+
+ hEvOptInit = HookEvent( ME_OPT_INITIALISE, JabberOptInit );
+ hEvModulesLoaded = HookEvent( ME_SYSTEM_MODULESLOADED, OnModulesLoaded );
+ hEvPreShutdown = HookEvent( ME_SYSTEM_PRESHUTDOWN, OnPreShutdown );
+
+ // Register protocol module
+ PROTOCOLDESCRIPTOR pd;
+ ZeroMemory( &pd, sizeof( PROTOCOLDESCRIPTOR ));
+ pd.cbSize = sizeof( PROTOCOLDESCRIPTOR );
+ pd.szName = jabberProtoName;
+ pd.type = PROTOTYPE_PROTOCOL;
+ JCallService( MS_PROTO_REGISTERMODULE, 0, ( LPARAM )&pd );
+
+ // Set all contacts to offline
+ HANDLE hContact = ( HANDLE ) JCallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ while ( hContact != NULL ) {
+ char* szProto = ( char* )JCallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 );
+ if ( szProto != NULL && !strcmp( szProto, jabberProtoName ))
+ if ( JGetWord( hContact, "Status", ID_STATUS_OFFLINE ) != ID_STATUS_OFFLINE )
+ JSetWord( hContact, "Status", ID_STATUS_OFFLINE );
+
+ hContact = ( HANDLE ) JCallService( MS_DB_CONTACT_FINDNEXT, ( WPARAM ) hContact, 0 );
+ }
+
+ memset(( char* )&modeMsgs, 0, sizeof( JABBER_MODEMSGS ));
+ //jabberModeMsg = NULL;
+ jabberCodePage = JGetWord( NULL, "CodePage", CP_ACP );
+
+ InitializeCriticalSection( &mutex );
+ InitializeCriticalSection( &modeMsgMutex );
+
+ srand(( unsigned ) time( NULL ));
+ JabberSerialInit();
+ JabberIqInit();
+ JabberListInit();
+ JabberSvcInit();
+ JabberMenuInit();
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Unload - destroy the plugin instance
+
+extern "C" int __declspec( dllexport ) Unload( void )
+{
+ if ( hChatEvent ) UnhookEvent( hChatEvent );
+ if ( hChatMenu ) UnhookEvent( hChatMenu );
+ if ( hChatMess ) UnhookEvent( hChatMess );
+ if ( hEvInitChat ) UnhookEvent( hEvInitChat );
+ if ( hEvModulesLoaded ) UnhookEvent( hEvModulesLoaded );
+ if ( hEvOptInit ) UnhookEvent( hEvOptInit );
+ if ( hEvPreShutdown ) UnhookEvent( hEvPreShutdown );
+ if ( hEvUserInfoInit ) UnhookEvent( hEvUserInfoInit );
+
+ if ( hInitChat )
+ DestroyHookableEvent( hInitChat );
+
+ JabberSvcUninit();
+ JabberSslUninit();
+ JabberListUninit();
+ JabberIqUninit();
+ JabberSerialUninit();
+ JabberWsUninit();
+ DeleteCriticalSection( &modeMsgMutex );
+ DeleteCriticalSection( &mutex );
+ mir_free( modeMsgs.szOnline );
+ mir_free( modeMsgs.szAway );
+ mir_free( modeMsgs.szNa );
+ mir_free( modeMsgs.szDnd );
+ mir_free( modeMsgs.szFreechat );
+ mir_free( jabberModuleName );
+ mir_free( jabberProtoName );
+ if ( jabberVcardPhotoFileName ) {
+ DeleteFileA( jabberVcardPhotoFileName );
+ mir_free( jabberVcardPhotoFileName );
+ }
+ if ( jabberVcardPhotoType ) mir_free( jabberVcardPhotoType );
+ if ( streamId ) mir_free( streamId );
+
+ if ( hMainThread ) CloseHandle( hMainThread );
+ return 0;
+}
diff --git a/miranda-wine/protocols/JabberG/jabber.h b/miranda-wine/protocols/JabberG/jabber.h new file mode 100644 index 0000000..006c680 --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber.h @@ -0,0 +1,586 @@ +/*
+
+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.
+
+*/
+
+#ifndef _JABBER_H_
+#define _JABBER_H_
+
+#if defined(UNICODE) && !defined(_UNICODE)
+ #define _UNICODE
+#endif
+
+#include <malloc.h>
+
+#define NEWSTR_ALLOCA(A) (A==NULL)?NULL:strcpy((char*)alloca(strlen(A)+1),A)
+#define NEWTSTR_ALLOCA(A) (A==NULL)?NULL:_tcscpy((TCHAR*)alloca(sizeof(TCHAR)*(_tcslen(A)+1)),A)
+
+#if defined( _UNICODE )
+ #define TCHAR_STR_PARAM "%S"
+#else
+ #define TCHAR_STR_PARAM "%s"
+#endif
+
+#ifdef _DEBUG
+#define _CRTDBG_MAP_ALLOC
+#include <stdlib.h>
+#include <crtdbg.h>
+#endif
+
+/*******************************************************************
+ * Global header files
+ *******************************************************************/
+#define _WIN32_WINNT 0x500
+#include <windows.h>
+#include <process.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <time.h>
+#include <limits.h>
+#include <newpluginapi.h>
+#include <m_system.h>
+#include <m_netlib.h>
+#include <m_protomod.h>
+#include <m_protosvc.h>
+#include <m_clist.h>
+#include <m_clui.h>
+#include <m_options.h>
+#include <m_userinfo.h>
+#include <m_database.h>
+#include <m_langpack.h>
+#include <m_utils.h>
+#include <m_message.h>
+#include <m_skin.h>
+#include <m_chat.h>
+#include <win2k.h>
+
+#include "jabber_xml.h"
+#include "jabber_byte.h"
+
+#if !defined(OPENFILENAME_SIZE_VERSION_400)
+ #define OPENFILENAME_SIZE_VERSION_400 sizeof(OPENFILENAME)
+#endif
+
+/*******************************************************************
+ * Global constants
+ *******************************************************************/
+#define JABBER_DEFAULT_PORT 5222
+#define JABBER_IQID "mir_"
+#define JABBER_MAX_JID_LEN 256
+
+// User-defined message
+#define WM_JABBER_REGDLG_UPDATE WM_USER + 100
+#define WM_JABBER_AGENT_REFRESH WM_USER + 101
+#define WM_JABBER_TRANSPORT_REFRESH WM_USER + 102
+#define WM_JABBER_REGINPUT_ACTIVATE WM_USER + 103
+#define WM_JABBER_REFRESH WM_USER + 104
+#define WM_JABBER_CHECK_ONLINE WM_USER + 105
+#define WM_JABBER_CHANGED WM_USER + 106
+#define WM_JABBER_ACTIVATE WM_USER + 107
+#define WM_JABBER_SET_FONT WM_USER + 108
+#define WM_JABBER_FLASHWND WM_USER + 109
+#define WM_JABBER_GC_MEMBER_ADD WM_USER + 110
+#define WM_JABBER_GC_FORCE_QUIT WM_USER + 111
+#define WM_JABBER_SHUTDOWN WM_USER + 112
+#define WM_JABBER_SMILEY WM_USER + 113
+#define WM_JABBER_JOIN WM_USER + 114
+#define WM_JABBER_ADD_TO_ROSTER WM_USER + 115
+// Error code
+#define JABBER_ERROR_REDIRECT 302
+#define JABBER_ERROR_BAD_REQUEST 400
+#define JABBER_ERROR_UNAUTHORIZED 401
+#define JABBER_ERROR_PAYMENT_REQUIRED 402
+#define JABBER_ERROR_FORBIDDEN 403
+#define JABBER_ERROR_NOT_FOUND 404
+#define JABBER_ERROR_NOT_ALLOWED 405
+#define JABBER_ERROR_NOT_ACCEPTABLE 406
+#define JABBER_ERROR_REGISTRATION_REQUIRED 407
+#define JABBER_ERROR_REQUEST_TIMEOUT 408
+#define JABBER_ERROR_CONFLICT 409
+#define JABBER_ERROR_INTERNAL_SERVER_ERROR 500
+#define JABBER_ERROR_NOT_IMPLEMENTED 501
+#define JABBER_ERROR_REMOTE_SERVER_ERROR 502
+#define JABBER_ERROR_SERVICE_UNAVAILABLE 503
+#define JABBER_ERROR_REMOTE_SERVER_TIMEOUT 504
+// Vcard flag
+#define JABBER_VCEMAIL_HOME 1
+#define JABBER_VCEMAIL_WORK 2
+#define JABBER_VCEMAIL_INTERNET 4
+#define JABBER_VCEMAIL_X400 8
+#define JABBER_VCTEL_HOME 1
+#define JABBER_VCTEL_WORK 2
+#define JABBER_VCTEL_VOICE 4
+#define JABBER_VCTEL_FAX 8
+#define JABBER_VCTEL_PAGER 16
+#define JABBER_VCTEL_MSG 32
+#define JABBER_VCTEL_CELL 64
+#define JABBER_VCTEL_VIDEO 128
+#define JABBER_VCTEL_BBS 256
+#define JABBER_VCTEL_MODEM 512
+#define JABBER_VCTEL_ISDN 1024
+#define JABBER_VCTEL_PCS 2048
+// File transfer setting
+#define JABBER_OPTION_FT_DIRECT 0 // Direct connection
+#define JABBER_OPTION_FT_PASS 1 // Use PASS server
+#define JABBER_OPTION_FT_PROXY 2 // Use proxy with local port forwarding
+// Font style saved in DB
+#define JABBER_FONT_BOLD 1
+#define JABBER_FONT_ITALIC 2
+// Font for groupchat log dialog
+#define JABBER_GCLOG_NUM_FONT 6 // 6 fonts ( 0:send, 1:msg, 2:time, 3:nick, 4:sys, 5:/me )
+// Old SDK don't have this
+#ifndef SPI_GETSCREENSAVERRUNNING
+#define SPI_GETSCREENSAVERRUNNING 114
+#endif
+#define IDC_STATIC ( -1 )
+// Icon list
+enum {
+ JABBER_IDI_GCOWNER = 0,
+ JABBER_IDI_GCADMIN,
+ JABBER_IDI_GCMODERATOR,
+ JABBER_IDI_GCVOICE,
+ JABBER_ICON_TOTAL
+};
+
+// Services and Events
+#define JE_RAWXMLIN "/RawXMLIn"
+#define JE_RAWXMLOUT "/RawXMLOut"
+
+#define JS_SENDXML "/SendXML"
+
+/*******************************************************************
+ * Global data structures and data type definitions
+ *******************************************************************/
+typedef HANDLE JABBER_SOCKET;
+
+enum JABBER_SESSION_TYPE
+{
+ JABBER_SESSION_NORMAL,
+ JABBER_SESSION_REGISTER
+};
+
+struct ThreadData {
+ HANDLE hThread;
+ JABBER_SESSION_TYPE type;
+
+ TCHAR username[128];
+ char password[128];
+ char server[128];
+ char manualHost[128];
+ TCHAR resource[128];
+ TCHAR fullJID[256];
+ WORD port;
+ JABBER_SOCKET s;
+ BOOL useSSL;
+
+ char newPassword[128];
+
+ HWND reg_hwndDlg;
+ BOOL reg_done, bIsSessionAvailable;
+};
+
+struct JABBER_MODEMSGS
+{
+ char* szOnline;
+ char* szAway;
+ char* szNa;
+ char* szDnd;
+ char* szFreechat;
+};
+
+struct JABBER_REG_ACCOUNT
+{
+ TCHAR username[128];
+ TCHAR password[128];
+ char server[128];
+ char manualHost[128];
+ WORD port;
+ BOOL useSSL;
+};
+
+typedef enum { FT_SI, FT_OOB, FT_BYTESTREAM } JABBER_FT_TYPE;
+typedef enum { FT_CONNECTING, FT_INITIALIZING, FT_RECEIVING, FT_DONE, FT_ERROR, FT_DENIED } JABBER_FILE_STATE;
+
+struct filetransfer
+{
+ filetransfer();
+ ~filetransfer();
+
+ void close();
+ void complete();
+ int create();
+
+ PROTOFILETRANSFERSTATUS std;
+
+// HANDLE hContact;
+ JABBER_FT_TYPE type;
+ JABBER_SOCKET s;
+ JABBER_FILE_STATE state;
+ TCHAR* jid;
+ int fileId;
+ TCHAR* iqId;
+ TCHAR* sid;
+ int bCompleted;
+ HANDLE hWaitEvent;
+ WCHAR* wszFileName;
+
+ // For type == FT_BYTESTREAM
+ JABBER_BYTE_TRANSFER *jbt;
+
+ // Used by file receiving only
+ char* httpHostName;
+ WORD httpPort;
+ char* httpPath;
+
+ // Used by file sending only
+ HANDLE hFileEvent;
+ long *fileSize;
+ char* szDescription;
+};
+
+struct JABBER_SEARCH_RESULT
+{
+ PROTOSEARCHRESULT hdr;
+ TCHAR jid[256];
+};
+
+struct JABBER_GCLOG_FONT
+{
+ char face[LF_FACESIZE]; // LF_FACESIZE is from LOGFONT struct
+ BYTE style;
+ char size; // signed
+ BYTE charset;
+ COLORREF color;
+};
+
+struct JABBER_FIELD_MAP
+{
+ int id;
+ char* name;
+};
+
+enum JABBER_MUC_JIDLIST_TYPE
+{
+ MUC_VOICELIST,
+ MUC_MEMBERLIST,
+ MUC_MODERATORLIST,
+ MUC_BANLIST,
+ MUC_ADMINLIST,
+ MUC_OWNERLIST
+};
+
+struct JABBER_MUC_JIDLIST_INFO
+{
+ JABBER_MUC_JIDLIST_TYPE type;
+ TCHAR* roomJid; // filled-in by the WM_JABBER_REFRESH code
+ XmlNode *iqNode;
+
+ TCHAR* type2str( void ) const;
+};
+
+typedef void ( *JABBER_FORM_SUBMIT_FUNC )( XmlNode* values, void *userdata );
+typedef void ( __cdecl *JABBER_THREAD_FUNC )( void * );
+
+#include "jabber_list.h"
+
+/*******************************************************************
+ * Global variables
+ *******************************************************************/
+extern HINSTANCE hInst;
+extern HANDLE hMainThread;
+extern DWORD jabberMainThreadId;
+extern char* jabberProtoName;
+extern char* jabberModuleName;
+extern HANDLE hNetlibUser;
+extern HMODULE hLibSSL;
+extern PVOID jabberSslCtx;
+
+extern struct ThreadData *jabberThreadInfo;
+extern TCHAR* jabberJID;
+extern char* streamId;
+extern DWORD jabberLocalIP;
+extern BOOL jabberConnected;
+extern BOOL jabberOnline;
+extern int jabberStatus;
+extern int jabberDesiredStatus;
+extern time_t jabberLoggedInTime;
+
+extern CRITICAL_SECTION modeMsgMutex;
+extern JABBER_MODEMSGS modeMsgs;
+extern BOOL modeMsgStatusChangePending;
+
+extern BOOL jabberChangeStatusMessageOnly;
+extern BOOL jabberSendKeepAlive;
+extern BOOL jabberChatDllPresent;
+
+extern HWND hwndJabberAgents;
+extern HWND hwndAgentReg;
+extern HWND hwndAgentRegInput;
+extern HWND hwndAgentManualReg;
+extern HWND hwndRegProgress;
+extern HWND hwndJabberVcard;
+extern HWND hwndJabberChangePassword;
+extern HWND hwndJabberGroupchat;
+extern HWND hwndJabberJoinGroupchat;
+extern HWND hwndMucVoiceList;
+extern HWND hwndMucMemberList;
+extern HWND hwndMucModeratorList;
+extern HWND hwndMucBanList;
+extern HWND hwndMucAdminList;
+extern HWND hwndMucOwnerList;
+
+extern const char xmlnsOwner[], xmlnsAdmin[];
+// Service and event handles
+extern HANDLE heventRawXMLIn;
+extern HANDLE heventRawXMLOut;
+
+/*******************************************************************
+ * Function declarations
+ *******************************************************************/
+
+//---- jabber_bitmap.cpp ----------------------------------------------
+
+HBITMAP __stdcall JabberBitmapToAvatar( HBITMAP hBitmap );
+int __stdcall JabberEnterBitmapName( char* szDest );
+
+//---- jabber_chat.cpp ----------------------------------------------
+
+void JabberGcLogCreate( JABBER_LIST_ITEM* item );
+void JabberGcLogUpdateMemberStatus( JABBER_LIST_ITEM* item, TCHAR* nick, int action, XmlNode* reason );
+void JabberGcQuit( JABBER_LIST_ITEM* jid, int code, XmlNode* reason );
+
+//---- jabber_file.c ------------------------------------------------
+
+void __cdecl JabberFileReceiveThread( filetransfer* ft );
+void __cdecl JabberFileServerThread( filetransfer* ft );
+
+//---- jabber_form.c ------------------------------------------------
+
+void JabberFormCreateUI( HWND hwndStatic, XmlNode *xNode, int *formHeight );
+void JabberFormCreateDialog( XmlNode *xNode, TCHAR* defTitle, JABBER_FORM_SUBMIT_FUNC pfnSubmit, void *userdata );
+
+XmlNode* JabberFormGetData( HWND hwndStatic, XmlNode *xNode );
+
+//---- jabber_ft.c --------------------------------------------------
+
+void JabberFtCancel( filetransfer* ft );
+void JabberFtInitiate( TCHAR* jid, filetransfer* ft );
+void JabberFtHandleSiRequest( XmlNode *iqNode );
+void JabberFtAcceptSiRequest( filetransfer* ft );
+BOOL JabberFtHandleBytestreamRequest( XmlNode *iqNode );
+
+//---- jabber_groupchat.c -------------------------------------------
+
+int JabberMenuHandleGroupchat( WPARAM wParam, LPARAM lParam );
+void JabberGroupchatJoinRoom( const TCHAR* server, const TCHAR* room, const TCHAR* nick, const TCHAR* password );
+void JabberGroupchatProcessPresence( XmlNode *node, void *userdata );
+void JabberGroupchatProcessMessage( XmlNode *node, void *userdata );
+void JabberGroupchatProcessInvite( TCHAR* roomJid, TCHAR* from, TCHAR* reason, TCHAR* password );
+
+//---- jabber_libstr.c ----------------------------------------------
+
+void __stdcall replaceStr( char*& dest, const char* src );
+void __stdcall replaceStr( WCHAR*& dest, const WCHAR* src );
+char* __stdcall rtrim( char *string );
+#if defined( _UNICODE )
+ TCHAR* __stdcall rtrim( TCHAR *string );
+#endif
+
+//---- jabber_misc.c ------------------------------------------------
+
+void JabberAddContactToRoster( const TCHAR* jid, const TCHAR* nick, const TCHAR* grpName, JABBER_SUBSCRIPTION subscription );
+void JabberChatDllError( void );
+int JabberCompareJids( const TCHAR* jid1, const TCHAR* jid2 );
+void JabberContactListCreateGroup( TCHAR* groupName );
+void JabberDBAddAuthRequest( TCHAR* jid, TCHAR* nick );
+HANDLE JabberDBCreateContact( TCHAR* jid, TCHAR* nick, BOOL temporary, BOOL stripResource );
+ULONG JabberForkThread( void ( __cdecl *threadcode )( void* ), unsigned long stacksize, void *arg );
+void JabberGetAvatarFileName( HANDLE hContact, char* pszDest, int cbLen );
+void JabberSetServerStatus( int iNewStatus );
+char* EscapeChatTags(char* pszText);
+char* UnEscapeChatTags(char* str_in);
+
+//---- jabber_svc.c -------------------------------------------------
+
+void JabberEnableMenuItems( BOOL bEnable );
+
+//---- jabber_std.cpp ----------------------------------------------
+
+#if defined( _DEBUG )
+ #define JCallService CallService
+#else
+ int __stdcall JCallService( const char* szSvcName, WPARAM wParam, LPARAM lParam );
+#endif
+
+HANDLE __stdcall JCreateServiceFunction( const char* szService, MIRANDASERVICE serviceProc );
+HANDLE __stdcall JCreateHookableEvent( const char* szService );
+void __stdcall JDeleteSetting( HANDLE hContact, const char* valueName );
+DWORD __stdcall JGetByte( const char* valueName, int parDefltValue );
+DWORD __stdcall JGetByte( HANDLE hContact, const char* valueName, int parDefltValue );
+char* __stdcall JGetContactName( HANDLE hContact );
+DWORD __stdcall JGetDword( HANDLE hContact, const char* valueName, DWORD parDefltValue );
+int __stdcall JGetStaticString( const char* valueName, HANDLE hContact, char* dest, int dest_len );
+int __stdcall JGetStringUtf( HANDLE hContact, char* valueName, DBVARIANT* dbv );
+int __stdcall JGetStringT( HANDLE hContact, char* valueName, DBVARIANT* dbv );
+WORD __stdcall JGetWord( HANDLE hContact, const char* valueName, int parDefltValue );
+void __fastcall JFreeVariant( DBVARIANT* dbv );
+int __stdcall JSendBroadcast( HANDLE hContact, int type, int result, HANDLE hProcess, LPARAM lParam );
+DWORD __stdcall JSetByte( const char* valueName, int parValue );
+DWORD __stdcall JSetByte( HANDLE hContact, const char* valueName, int parValue );
+DWORD __stdcall JSetDword( HANDLE hContact, const char* valueName, DWORD parValue );
+DWORD __stdcall JSetString( HANDLE hContact, const char* valueName, const char* parValue );
+DWORD __stdcall JSetStringT( HANDLE hContact, const char* valueName, const TCHAR* parValue );
+DWORD __stdcall JSetStringUtf( HANDLE hContact, const char* valueName, const char* parValue );
+DWORD __stdcall JSetWord( HANDLE hContact, const char* valueName, int parValue );
+char* __stdcall JTranslate( const char* str );
+
+//---- jabber_thread.cpp -------------------------------------------
+
+void __cdecl JabberServerThread( struct ThreadData *info );
+
+//---- jabber_util.c ----------------------------------------------
+
+void __stdcall JabberSerialInit( void );
+void __stdcall JabberSerialUninit( void );
+unsigned int __stdcall JabberSerialNext( void );
+int __stdcall JabberSend( JABBER_SOCKET s, const char* fmt, ... );
+int __stdcall JabberSend( JABBER_SOCKET s, XmlNode& node );
+HANDLE __stdcall JabberHContactFromJID( const TCHAR* jid );
+void __stdcall JabberLog( const char* fmt, ... );
+TCHAR* __stdcall JabberNickFromJID( const TCHAR* jid );
+char* __stdcall JabberUrlDecode( char* str );
+void __stdcall JabberUrlDecodeW( WCHAR* str );
+char* __stdcall JabberUrlEncode( const char* str );
+char* __stdcall JabberUtf8Decode( char*,WCHAR** );
+char* __stdcall JabberUtf8Encode( const char* str );
+char* __stdcall JabberSha1( char* str );
+char* __stdcall JabberUnixToDos( const char* str );
+WCHAR* __stdcall JabberUnixToDosW( const WCHAR* str );
+void __stdcall JabberHttpUrlDecode( char* str );
+char* __stdcall JabberHttpUrlEncode( const char* str );
+int __stdcall JabberCombineStatus( int status1, int status2 );
+TCHAR* __stdcall JabberErrorStr( int errorCode );
+TCHAR* __stdcall JabberErrorMsg( XmlNode *errorNode );
+void __stdcall JabberSendVisibleInvisiblePresence( BOOL invisible );
+char* __stdcall JabberTextEncode( const char* str );
+char* __stdcall JabberTextEncodeW( const wchar_t *str );
+char* __stdcall JabberTextDecode( const char* str );
+void __stdcall JabberUtfToTchar( const char* str, size_t cbLen, LPTSTR& dest );
+char* __stdcall JabberBase64Encode( const char* buffer, int bufferLen );
+char* __stdcall JabberBase64Decode( const TCHAR* buffer, int *resultLen );
+char* __stdcall JabberGetVersionText();
+time_t __stdcall JabberIsoToUnixTime( TCHAR* stamp );
+int __stdcall JabberCountryNameToId( TCHAR* ctry );
+void __stdcall JabberSendPresenceTo( int status, TCHAR* to, XmlNode* extra );
+void __stdcall JabberSendPresence( int );
+void __stdcall JabberStringAppend( char* *str, int *sizeAlloced, const char* fmt, ... );
+TCHAR* __stdcall JabberGetClientJID( const TCHAR* jid, TCHAR*, size_t );
+TCHAR* __stdcall JabberStripJid( const TCHAR* jid, TCHAR* dest, size_t destLen );
+int __stdcall JabberGetPictureType( const char* buf );
+
+#if defined( _UNICODE )
+ #define JabberUnixToDosT JabberUnixToDosW
+#else
+ #define JabberUnixToDosT JabberUnixToDos
+#endif
+
+//---- jabber_vcard.c -----------------------------------------------
+
+int JabberSendGetVcard( const TCHAR* jid );
+
+//---- jabber_ws.c -------------------------------------------------
+
+BOOL JabberWsInit( void );
+void JabberWsUninit( void );
+JABBER_SOCKET JabberWsConnect( char* host, WORD port );
+int JabberWsSend( JABBER_SOCKET s, char* data, int datalen );
+int JabberWsRecv( JABBER_SOCKET s, char* data, long datalen );
+
+///////////////////////////////////////////////////////////////////////////////
+// memory interface
+
+extern MM_INTERFACE memoryManagerInterface;
+#define mir_alloc(n) memoryManagerInterface.mmi_malloc(n)
+#define mir_free(ptr) memoryManagerInterface.mmi_free(ptr)
+#define mir_realloc(ptr,size) memoryManagerInterface.mmi_realloc(ptr,size)
+
+__forceinline char * mir_strdup(const char *src)
+{
+ return (src == NULL) ? NULL : strcpy(( char* )mir_alloc( strlen(src)+1 ), src );
+}
+
+__forceinline WCHAR* mir_wstrdup(const WCHAR *src)
+{
+ return (src == NULL) ? NULL : wcscpy(( WCHAR* )mir_alloc(( wcslen(src)+1 )*sizeof( WCHAR )), src );
+}
+
+#if defined( _UNICODE )
+ #define mir_tstrdup mir_wstrdup
+#else
+ #define mir_tstrdup mir_strdup
+#endif
+
+extern LIST_INTERFACE li;
+
+///////////////////////////////////////////////////////////////////////////////
+// TXT encode helper
+
+class TextEncoder {
+ char* m_body;
+
+public:
+ __forceinline TextEncoder( const char* pSrc ) :
+ m_body( JabberTextEncode( pSrc ))
+ {}
+
+ __forceinline ~TextEncoder()
+ { mir_free( m_body );
+ }
+
+ __forceinline const char* str() const { return m_body; }
+};
+
+#define TXT(A) TextEncoder(A).str()
+
+///////////////////////////////////////////////////////////////////////////////
+// UTF encode helper
+
+class Utf8Encoder {
+ char* m_body;
+
+public:
+ __forceinline Utf8Encoder( const char* pSrc ) :
+ m_body( JabberUtf8Encode( pSrc ))
+ {}
+
+ __forceinline ~Utf8Encoder()
+ { mir_free( m_body );
+ }
+
+ __forceinline const char* str() const { return m_body; }
+};
+
+#define UTF8(A) Utf8Encoder(A).str()
+
+char* t2a( const TCHAR* src );
+char* u2a( const wchar_t* src );
+wchar_t* a2u( const char* src );
+
+#endif
diff --git a/miranda-wine/protocols/JabberG/jabber.rc b/miranda-wine/protocols/JabberG/jabber.rc new file mode 100644 index 0000000..cad3677 --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber.rc @@ -0,0 +1,839 @@ +// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "winres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""winres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_OPT_JABBERMAIN DIALOGEX 0, 0, 312, 247
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "",IDC_OPTIONSTAB,"SysTabControl32",WS_TABSTOP,1,1,310,245,
+ WS_EX_ACCEPTFILES
+END
+
+IDD_OPT_JABBER DIALOGEX 0, 0, 304, 227
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Jabber",IDC_SIMPLE,8,4,290,99
+ LTEXT "Username:",IDC_STATIC,19,21,45,8
+ EDITTEXT IDC_EDIT_USERNAME,70,19,86,12,ES_AUTOHSCROLL
+ LTEXT "Password:",IDC_STATIC,19,35,45,8
+ EDITTEXT IDC_EDIT_PASSWORD,70,33,86,12,ES_PASSWORD |
+ ES_AUTOHSCROLL
+ LTEXT "Resource:",IDC_RESOURCE_T,19,49,45,8
+ EDITTEXT IDC_EDIT_RESOURCE,70,47,86,12,ES_AUTOHSCROLL
+ LTEXT "Priority:",IDC_PRIORITY_LABEL,165,49,31,8
+ EDITTEXT IDC_PRIORITY,199,47,42,12,ES_AUTOHSCROLL | ES_NUMBER
+ CONTROL "Spin1",IDC_PRIORITY_SPIN,"msctls_updown32",
+ UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY |
+ UDS_NOTHOUSANDS,231,47,11,12
+ CONTROL "Save password",IDC_SAVEPASSWORD,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,70,61,172,10
+ LTEXT "Login server:",IDC_STATIC,19,75,45,8
+ EDITTEXT IDC_EDIT_LOGIN_SERVER,70,73,86,12,ES_AUTOHSCROLL
+ LTEXT "Port:",IDC_STATIC,19,89,45,8
+ EDITTEXT IDC_PORT,70,87,26,12,ES_AUTOHSCROLL | ES_NUMBER
+ CONTROL "Use SSL",IDC_USE_SSL,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,104,88,82,10
+ CONTROL "Use TLS",IDC_USE_TLS,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,193,88,97,10
+ PUSHBUTTON "Register new user",IDC_BUTTON_REGISTER,165,19,78,13
+ CONTROL "List of public servers",IDC_LINK_PUBLIC_SERVER,
+ "Hyperlink",WS_TABSTOP,165,74,79,11
+ GROUPBOX "Expert",IDC_STATIC,8,108,290,112
+ CONTROL "Manually specify connection host",IDC_MANUAL,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,19,121,223,10
+ LTEXT "Host:",IDC_STATIC,31,134,26,8
+ EDITTEXT IDC_HOST,62,132,90,12,ES_AUTOHSCROLL | WS_DISABLED
+ LTEXT "Port:",IDC_STATIC,161,134,21,8
+ EDITTEXT IDC_HOSTPORT,186,132,31,12,ES_AUTOHSCROLL | ES_NUMBER |
+ WS_DISABLED
+ CONTROL "Keep connection alive",IDC_KEEPALIVE,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,19,146,221,10
+ CONTROL "Automatically delete contacts not in my roster",
+ IDC_ROSTER_SYNC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,19,
+ 158,221,10
+ LTEXT "User directory:",IDC_JUD_LABEL,19,175,68,8
+ EDITTEXT IDC_JUD,92,172,103,12,ES_AUTOHSCROLL
+ LTEXT "Messaging language:",IDC_MSGLANG_LABEL,19,189,70,8
+ COMBOBOX IDC_MSGLANG,92,187,103,69,CBS_DROPDOWNLIST | CBS_SORT |
+ WS_VSCROLL | WS_TABSTOP
+END
+
+IDD_OPT_JABBER2 DIALOGEX 0, 0, 304, 199
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "File Transfer",IDC_STATIC,8,4,290,69
+ CONTROL "Allow file sending through direct peer-to-peer connection",
+ IDC_DIRECT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,18,
+ 202,10
+ CONTROL "Specify proxy server",IDC_PROXY_MANUAL,"Button",
+ BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,16,54,102,10
+ CONTROL "Allow file sending through bytestream proxy server",
+ IDC_PROXY,"Button",BS_AUTOCHECKBOX | WS_DISABLED |
+ WS_TABSTOP,16,42,202,10
+ EDITTEXT IDC_PROXY_ADDR,124,53,81,12,ES_AUTOHSCROLL | WS_DISABLED |
+ WS_GROUP
+ CONTROL "Specify external address",IDC_DIRECT_MANUAL,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,16,30,101,10
+ EDITTEXT IDC_DIRECT_ADDR,124,29,81,12,ES_AUTOHSCROLL
+ GROUPBOX "Miscellaneous",IDC_STATIC,8,75,290,116
+ CONTROL "Automatically add contact when accept authorization",
+ IDC_AUTO_ADD,"Button",BS_AUTOCHECKBOX | BS_TOP |
+ WS_TABSTOP,16,90,280,12
+ CONTROL "Automatically join conferences on login",IDC_AUTOJOIN,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,102,280,10
+ CONTROL "Autoaccept multiuser chat invitations",
+ IDC_AUTO_ACCEPT_MUC,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,16,114,280,10
+ CONTROL "Send messages slower, but with full acknowledgement",
+ IDC_MSG_ACK,"Button",BS_AUTOCHECKBOX | BS_TOP |
+ WS_TABSTOP,16,126,269,10
+ CONTROL "Disable main menu",IDC_DISABLE_MAINMENU,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,16,138,280,10
+ CONTROL "Show transport agents on contact list",
+ IDC_SHOW_TRANSPORT,"Button",BS_AUTOCHECKBOX | BS_TOP |
+ WS_TABSTOP,16,150,280,10
+ CONTROL "Enable avatars",IDC_ENABLE_AVATARS,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,16,162,280,10
+ CONTROL "Disable SASL authentication (for old servers)",
+ IDC_DISABLE_SASL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+ 16,174,279,10
+END
+
+IDD_INFO_JABBER DIALOGEX 0, 0, 221, 132
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "JID:",IDC_STATIC,7,7,19,8
+ EDITTEXT IDC_INFO_JID,31,7,183,12,ES_AUTOHSCROLL | ES_READONLY |
+ NOT WS_BORDER
+ LTEXT "Resources:",IDC_STATIC,7,65,81,8
+ LISTBOX IDC_INFO_RESOURCE,7,75,69,50,LBS_SORT |
+ LBS_NOINTEGRALHEIGHT | WS_VSCROLL
+ LTEXT "Subscription type:",IDC_STATIC,7,20,60,8,NOT WS_GROUP
+ EDITTEXT IDC_SUBSCRIPTION,70,20,144,12,ES_READONLY | NOT
+ WS_BORDER
+ LTEXT "Software:",IDC_STATIC,81,74,35,8
+ LTEXT "Version:",IDC_STATIC,81,103,35,8
+ LTEXT "System:",IDC_STATIC,81,117,35,8
+ EDITTEXT IDC_SOFTWARE,121,74,93,26,ES_MULTILINE | ES_READONLY |
+ WS_DISABLED | NOT WS_BORDER
+ EDITTEXT IDC_VERSION,121,103,93,12,ES_AUTOHSCROLL | ES_READONLY |
+ WS_DISABLED | NOT WS_BORDER
+ EDITTEXT IDC_SYSTEM,121,117,93,13,ES_AUTOHSCROLL | ES_READONLY |
+ WS_DISABLED | NOT WS_BORDER
+END
+
+IDD_OPT_REGISTER DIALOGEX 0, 0, 165, 61
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP |
+ WS_CAPTION
+CAPTION "Jabber Account Registration"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "",IDC_REG_STATUS,18,7,139,19
+ CONTROL "Progress1",IDC_PROGRESS_REG,"msctls_progress32",NOT
+ WS_VISIBLE | WS_BORDER | WS_TABSTOP,18,27,130,7
+ PUSHBUTTON "OK",IDOK,29,40,50,14
+ DEFPUSHBUTTON "Cancel",IDCANCEL,85,40,50,14
+ DEFPUSHBUTTON "OK",IDOK2,55,40,50,14,NOT WS_VISIBLE
+ DEFPUSHBUTTON "Cancel",IDCANCEL2,55,40,50,14,NOT WS_VISIBLE
+END
+
+IDD_AGENTS DIALOGEX 0, 0, 294, 254
+STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER |
+ WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Jabber Agents"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Register/Search Jabber Agents",IDC_STATIC,7,7,280,115
+ LTEXT "Jabber server:",IDC_STATIC,13,20,47,8
+ EDITTEXT IDC_AGENT_SERVER,65,19,136,12,ES_AUTOHSCROLL
+ DEFPUSHBUTTON "Browse",IDC_AGENT_BROWSE,209,19,46,13,WS_DISABLED
+ CONTROL "List1",IDC_AGENT_LIST,"SysListView32",LVS_REPORT |
+ LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER |
+ WS_BORDER | WS_TABSTOP,13,36,267,60
+ PUSHBUTTON "Register...",IDC_AGENT_REGISTER,13,100,50,14,
+ WS_DISABLED
+ PUSHBUTTON "Browse/Join chat room...",IDC_JOIN,69,100,93,14,
+ WS_DISABLED
+ PUSHBUTTON "Search...",IDC_AGENT_SEARCH,171,100,50,14,NOT
+ WS_VISIBLE | WS_DISABLED
+ GROUPBOX "Registered Jabber Transports",IDC_STATIC,7,128,280,99
+ CONTROL "List1",IDC_AGENT_TRANSPORT,"SysListView32",LVS_REPORT |
+ LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER |
+ WS_BORDER | WS_TABSTOP,13,142,267,60
+ PUSHBUTTON "Log on",IDC_AGENT_LOGON,13,206,50,14,WS_DISABLED
+ PUSHBUTTON "Log off",IDC_AGENT_LOGOFF,69,206,50,14,WS_DISABLED
+ PUSHBUTTON "Unregister",IDC_AGENT_UNREGISTER,125,206,50,14,
+ WS_DISABLED
+ PUSHBUTTON "Register with a new service...",IDC_MANUAL_REGISTER,7,
+ 233,106,14
+ PUSHBUTTON "Close",IDCLOSE,237,233,50,14
+END
+
+IDD_FORM DIALOGEX 0, 0, 258, 224
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK |
+ DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION |
+ WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Jabber Form"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Instruction:",IDC_STATIC,7,7,243,8,NOT WS_GROUP
+ EDITTEXT IDC_INSTRUCTION,7,17,243,38,ES_MULTILINE | ES_READONLY |
+ WS_VSCROLL
+ LTEXT "",IDC_FRAME,7,60,243,138,NOT WS_GROUP,WS_EX_CLIENTEDGE
+ EDITTEXT IDC_FRAME_TEXT,18,101,220,33,ES_CENTER | ES_MULTILINE |
+ ES_READONLY | NOT WS_BORDER
+ SCROLLBAR IDC_VSCROLL,238,61,11,136,SBS_VERT | WS_DISABLED
+ DEFPUSHBUTTON "Submit",IDC_SUBMIT,146,203,50,14,WS_DISABLED
+ PUSHBUTTON "Cancel",IDCANCEL,200,203,50,14
+END
+
+IDD_PASSWORD DIALOGEX 0, 0, 286, 63
+STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER |
+ WS_POPUP | WS_VISIBLE | WS_CAPTION
+CAPTION "Jabber Password"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ EDITTEXT IDC_JID,7,7,272,12,ES_READONLY | NOT WS_BORDER | NOT
+ WS_TABSTOP
+ EDITTEXT IDC_PASSWORD,7,22,272,12,ES_PASSWORD | ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK",IDOK,23,42,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,77,42,50,14
+END
+
+IDD_VCARD DIALOGEX 0, 0, 238, 210
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK |
+ DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION |
+ WS_SYSMENU
+CAPTION "Personal vCard"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "Close",IDCLOSE,188,190,45,14
+ LTEXT "",IDC_WHITERECT,0,0,238,26
+ ICON IDI_WRITE,IDC_LOGO,7,4,20,20
+ LTEXT "",IDC_NAME,33,5,200,8,0,WS_EX_TRANSPARENT
+ CONTROL "Tab1",IDC_TABS,"SysTabControl32",TCS_HOTTRACK |
+ TCS_MULTILINE | WS_TABSTOP,5,29,228,158
+ LTEXT "View and update Jabber personal vCard",IDC_DESCRIPTION,
+ 44,13,189,8,0,WS_EX_TRANSPARENT
+ CTEXT "Updating",IDC_UPDATING,65,194,49,8,SS_NOPREFIX |
+ SS_CENTERIMAGE | NOT WS_VISIBLE
+ PUSHBUTTON "Update Now",IDC_UPDATE,5,190,55,14,WS_DISABLED
+ PUSHBUTTON "Save Changes",IDC_SAVE,124,190,61,14,WS_DISABLED
+END
+
+IDD_VCARD_HOME DIALOGEX 0, 0, 222, 132
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Address1:",IDC_STATIC,5,7,50,8
+ LTEXT "City:",IDC_STATIC,5,34,50,8
+ LTEXT "State:",IDC_STATIC,5,48,50,8
+ LTEXT "Address2:",IDC_STATIC,5,20,50,8
+ EDITTEXT IDC_ADDRESS1,58,5,148,12,ES_AUTOHSCROLL
+ EDITTEXT IDC_ADDRESS2,58,19,148,12,ES_AUTOHSCROLL
+ EDITTEXT IDC_CITY,58,33,75,12,ES_AUTOHSCROLL
+ EDITTEXT IDC_STATE,58,47,75,12,ES_AUTOHSCROLL
+ LTEXT "ZIP:",IDC_STATIC,5,63,50,8
+ EDITTEXT IDC_ZIP,58,61,58,12,ES_AUTOHSCROLL
+ LTEXT "Country:",IDC_STATIC,5,76,50,8
+ EDITTEXT IDC_COUNTRY,58,75,75,12,ES_AUTOHSCROLL
+END
+
+IDD_VCARD_PERSONAL DIALOGEX 0, 0, 222, 132
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Full name:",IDC_STATIC,5,7,51,8
+ EDITTEXT IDC_FULLNAME,58,5,159,12,ES_AUTOHSCROLL
+ LTEXT "Nick name:",IDC_STATIC,5,20,51,8
+ EDITTEXT IDC_NICKNAME,58,19,82,12,ES_AUTOHSCROLL
+ LTEXT "First name:",IDC_STATIC,5,34,51,8
+ EDITTEXT IDC_FIRSTNAME,58,33,82,12,ES_AUTOHSCROLL
+ LTEXT "Middle:",IDC_STATIC,143,34,25,8
+ EDITTEXT IDC_MIDDLE,174,33,43,12,ES_AUTOHSCROLL
+ LTEXT "Last name:",IDC_STATIC,5,48,51,8
+ EDITTEXT IDC_LASTNAME,58,47,82,12,ES_AUTOHSCROLL
+ LTEXT "Date of birth:",IDC_STATIC,5,63,51,8
+ EDITTEXT IDC_BIRTH,58,61,62,12,ES_AUTOHSCROLL
+ LTEXT "YYYY-MM-DD",IDC_STATIC,124,63,90,8
+ LTEXT "Gender:",IDC_STATIC,5,77,51,8
+ COMBOBOX IDC_GENDER,58,75,62,52,CBS_DROPDOWN | WS_VSCROLL |
+ WS_TABSTOP
+ LTEXT "Occupation:",IDC_STATIC,5,90,51,8
+ EDITTEXT IDC_OCCUPATION,58,89,159,12,ES_AUTOHSCROLL
+ LTEXT "Homepage:",IDC_STATIC,6,104,51,8
+ EDITTEXT IDC_HOMEPAGE,58,102,159,12,ES_AUTOHSCROLL
+END
+
+IDD_VCARD_WORK DIALOGEX 0, 0, 222, 132
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Company:",IDC_STATIC,6,7,50,8
+ EDITTEXT IDC_COMPANY,58,5,148,12,ES_AUTOHSCROLL
+ LTEXT "Department:",IDC_STATIC,6,20,50,8
+ EDITTEXT IDC_DEPARTMENT,58,19,148,12,ES_AUTOHSCROLL
+ LTEXT "Title:",IDC_STATIC,6,33,50,8
+ EDITTEXT IDC_TITLE,58,32,75,12,ES_AUTOHSCROLL
+ LTEXT "Address1:",IDC_STATIC,5,47,50,8
+ EDITTEXT IDC_ADDRESS1,58,45,148,12,ES_AUTOHSCROLL
+ LTEXT "Address2:",IDC_STATIC,5,60,50,8
+ EDITTEXT IDC_ADDRESS2,58,59,148,12,ES_AUTOHSCROLL
+ LTEXT "City:",IDC_STATIC,5,74,50,8
+ EDITTEXT IDC_CITY,58,73,75,12,ES_AUTOHSCROLL
+ LTEXT "State:",IDC_STATIC,5,88,50,8
+ EDITTEXT IDC_STATE,58,87,75,12,ES_AUTOHSCROLL
+ LTEXT "ZIP:",IDC_STATIC,5,103,50,8
+ EDITTEXT IDC_ZIP,58,101,58,12,ES_AUTOHSCROLL
+ LTEXT "Country:",IDC_STATIC,5,116,50,8
+ EDITTEXT IDC_COUNTRY,58,115,75,12,ES_AUTOHSCROLL
+END
+
+IDD_VCARD_CONTACT DIALOGEX 0, 0, 222, 132
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "E-mail:",IDC_STATIC,5,5,212,8
+ CONTROL "List1",IDC_EMAILS,"SysListView32",LVS_REPORT |
+ LVS_SINGLESEL | LVS_NOLABELWRAP | LVS_AUTOARRANGE |
+ LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,5,14,
+ 212,50
+ LTEXT "Phone:",IDC_STATIC,5,68,212,8
+ CONTROL "List1",IDC_PHONES,"SysListView32",LVS_REPORT |
+ LVS_SINGLESEL | LVS_NOLABELWRAP | LVS_AUTOARRANGE |
+ LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,5,77,
+ 212,50
+END
+
+IDD_VCARD_ADDEMAIL DIALOGEX 0, 0, 186, 89
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION |
+ WS_SYSMENU
+CAPTION "Jabber vCard: Add Email Address"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Email address:",IDC_STATIC,7,8,52,8
+ EDITTEXT IDC_EMAIL,61,7,118,12,ES_AUTOHSCROLL
+ CONTROL "Home",IDC_HOME,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,61,
+ 23,110,10
+ CONTROL "Work",IDC_WORK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,61,
+ 33,111,10
+ CONTROL "Internet",IDC_INTERNET,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,61,43,110,10
+ CONTROL "X400",IDC_X400,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,61,
+ 53,110,10
+ DEFPUSHBUTTON "OK",IDOK,40,68,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,96,68,50,14
+END
+
+IDD_VCARD_ADDPHONE DIALOGEX 0, 0, 186, 110
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION |
+ WS_SYSMENU
+CAPTION "Jabber vCard: Add Phone Number"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Phone number:",IDC_STATIC,7,8,49,8
+ EDITTEXT IDC_PHONE,61,7,118,12,ES_AUTOHSCROLL
+ CONTROL "Home",IDC_HOME,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,26,
+ 23,67,10
+ CONTROL "Work",IDC_WORK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,26,
+ 33,67,10
+ CONTROL "Voice",IDC_VOICE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+ 26,43,67,10
+ CONTROL "Fax",IDC_FAX,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,26,
+ 53,67,10
+ DEFPUSHBUTTON "OK",IDOK,40,88,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,96,88,50,14
+ CONTROL "Cellular",IDC_CELL,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,101,23,71,10
+ CONTROL "Video",IDC_VIDEO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+ 101,33,71,10
+ CONTROL "BBS",IDC_BBS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,101,
+ 43,71,10
+ CONTROL "Modem",IDC_MODEM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+ 101,53,71,10
+ CONTROL "Pager",IDC_PAGER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+ 26,63,67,10
+ CONTROL "Text/Messaging",IDC_MSG,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,26,73,67,10
+ CONTROL "ISDN",IDC_ISDN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,
+ 101,63,71,10
+ CONTROL "PCS",IDC_PCS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,101,
+ 73,71,10
+END
+
+IDD_VCARD_PHOTO DIALOGEX 0, 0, 222, 132
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ PUSHBUTTON "",IDC_LOAD,200,5,17,14,BS_ICON
+ PUSHBUTTON "",IDC_SAVE,200,5,17,14,BS_ICON
+ CTEXT "",IDC_CANVAS,5,5,189,122,SS_CENTERIMAGE
+ PUSHBUTTON "",IDC_DELETE,200,23,17,14,BS_ICON | WS_DISABLED
+END
+
+IDD_VCARD_NOTE DIALOGEX 0, 0, 222, 132
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Description:",IDC_STATIC,5,5,212,8
+ EDITTEXT IDC_DESC,5,15,212,112,ES_MULTILINE
+END
+
+IDD_CHANGEPASSWORD DIALOGEX 0, 0, 181, 79
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK |
+ DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION
+CAPTION "Change Password"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Current Password:",IDC_STATIC,7,8,81,8
+ EDITTEXT IDC_OLDPASSWD,95,7,79,12,ES_PASSWORD | ES_AUTOHSCROLL
+ LTEXT "New Password:",IDC_STATIC,7,22,81,8
+ EDITTEXT IDC_NEWPASSWD,95,21,79,12,ES_PASSWORD | ES_AUTOHSCROLL
+ LTEXT "Confirm New Password:",IDC_STATIC,7,36,81,8
+ EDITTEXT IDC_NEWPASSWD2,95,35,79,12,ES_PASSWORD | ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK",IDOK,38,58,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,92,58,50,14
+END
+
+IDD_GROUPCHAT DIALOGEX 0, 0, 306, 208
+STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER |
+ WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Jabber Multi-User Conference"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Conference server:",-1,5,8,70,8
+ COMBOBOX IDC_SERVER,80,7,168,79,CBS_DROPDOWN | CBS_AUTOHSCROLL |
+ WS_VSCROLL | WS_TABSTOP
+ DEFPUSHBUTTON "Browse",IDC_BROWSE,253,7,46,13
+ CONTROL "List1",IDC_ROOM,"SysListView32",LVS_REPORT |
+ LVS_SINGLESEL | LVS_SHOWSELALWAYS | WS_BORDER |
+ WS_TABSTOP,5,24,294,160
+ PUSHBUTTON "Close",IDCLOSE,249,189,50,14
+END
+
+IDD_GROUPCHAT_JOIN DIALOGEX 0, 0, 208, 96
+STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER |
+ WS_POPUP | WS_VISIBLE | WS_CAPTION
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Join Jabber Multi-User Conference Room"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Conference server:",IDC_STATIC,7,8,64,8
+ EDITTEXT IDC_SERVER,74,7,127,12,ES_AUTOHSCROLL
+ LTEXT "Room:",IDC_STATIC,7,22,64,8
+ EDITTEXT IDC_ROOM,74,21,127,12,ES_AUTOHSCROLL
+ LTEXT "Nick name:",IDC_STATIC,7,36,64,8
+ EDITTEXT IDC_NICK,74,35,127,12,ES_AUTOHSCROLL
+ LTEXT "Password:",IDC_STATIC,7,50,64,8
+ EDITTEXT IDC_PASSWORD,74,49,127,12,ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK",IDOK,51,75,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,106,75,50,14
+END
+
+IDD_GROUPCHAT_INPUT DIALOGEX 0, 0, 275, 46
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK |
+ DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ EDITTEXT IDC_TOPIC,7,7,261,12,ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK",IDOK,165,25,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,218,25,50,14
+END
+
+IDD_JIDLIST DIALOGEX 0, 0, 207, 112
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK |
+ DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION |
+ WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "JID List"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "List4",IDC_LIST,"SysListView32",LVS_REPORT |
+ LVS_SINGLESEL | LVS_NOLABELWRAP | LVS_AUTOARRANGE |
+ LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER |
+ WS_TABSTOP,7,7,193,98
+END
+
+IDD_AGENT_MANUAL_REGISTER DIALOGEX 0, 0, 186, 45
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK |
+ DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION |
+ WS_SYSMENU
+CAPTION "Jabber Agent Registration"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "JID:",IDC_STATIC,7,9,17,8
+ EDITTEXT IDC_JID,29,7,150,12,ES_AUTOHSCROLL
+ DEFPUSHBUTTON "Register",IDOK,75,24,50,14,WS_DISABLED
+ PUSHBUTTON "Cancel",IDCANCEL,129,24,50,14
+END
+
+IDD_GROUPCHAT_INVITE DIALOGEX 0, 0, 186, 73
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | WS_POPUP |
+ WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Jabber Groupchat Invite a User"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Room JID:",IDC_STATIC,7,6,46,8
+ EDITTEXT IDC_ROOM,57,4,122,12,ES_AUTOHSCROLL | ES_READONLY
+ LTEXT "User JID:",IDC_STATIC,7,21,46,8
+ COMBOBOX IDC_USER,57,19,122,64,CBS_DROPDOWN | CBS_AUTOHSCROLL |
+ CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Reason:",IDC_STATIC,7,37,46,8
+ EDITTEXT IDC_REASON,57,35,122,12,ES_AUTOHSCROLL
+ DEFPUSHBUTTON "&Invite",IDC_INVITE,75,53,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,129,53,50,14
+END
+
+IDD_GROUPCHAT_INVITE_ACCEPT DIALOGEX 0, 0, 232, 112
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS |
+ DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Multi-User Conference Invitation"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "&Accept",IDC_ACCEPT,124,93,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,178,93,50,14
+ LTEXT "From:",IDC_STATIC,33,24,63,8
+ LTEXT "Room JID:",IDC_STATIC,33,38,63,8
+ LTEXT "Reason:",IDC_STATIC,33,52,63,8
+ LTEXT "Nick:",IDC_STATIC,33,76,62,8
+ LTEXT "The following invitation to join a multi-user conference is received.",
+ IDC_STATIC,3,4,225,8
+ EDITTEXT IDC_FROM,99,22,105,12,ES_AUTOHSCROLL | ES_READONLY
+ EDITTEXT IDC_ROOM,99,36,105,12,ES_AUTOHSCROLL | ES_READONLY
+ EDITTEXT IDC_REASON,99,50,105,12,ES_AUTOHSCROLL | ES_READONLY
+ GROUPBOX "",IDC_STATIC,12,13,211,57
+ EDITTEXT IDC_NICK,99,74,105,12,ES_AUTOHSCROLL
+END
+
+IDD_OPT_SETAVATAR DIALOGEX 0, 0, 222, 131
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "",IDC_AVATAR,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ SS_SUNKEN,9,11,96,96
+ LTEXT "Note: Only JPGs and GIFs\nImage size max 64x64\nFile size max 6kB",
+ IDC_STATIC,112,54,106,34
+ PUSHBUTTON "Set",IDC_SETAVATAR,9,112,45,13
+ PUSHBUTTON "Delete",IDC_DELETEAVATAR,61,112,41,13
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_OPT_JABBER, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 297
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 220
+ END
+
+ IDD_OPT_JABBER2, DIALOG
+ BEGIN
+ LEFTMARGIN, 1
+ RIGHTMARGIN, 296
+ VERTGUIDE, 9
+ TOPMARGIN, 3
+ BOTTOMMARGIN, 191
+ END
+
+ IDD_INFO_JABBER, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 214
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 125
+ END
+
+ IDD_OPT_REGISTER, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 158
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 54
+ END
+
+ IDD_AGENTS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 287
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 247
+ END
+
+ IDD_FORM, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 250
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 217
+ END
+
+ IDD_PASSWORD, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 279
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 56
+ END
+
+ IDD_VCARD, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 233
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 204
+ END
+
+ IDD_VCARD_HOME, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 217
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 127
+ END
+
+ IDD_VCARD_PERSONAL, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 217
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 127
+ END
+
+ IDD_VCARD_WORK, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 217
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 127
+ END
+
+ IDD_VCARD_CONTACT, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 217
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 127
+ END
+
+ IDD_VCARD_ADDEMAIL, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 179
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 82
+ END
+
+ IDD_VCARD_ADDPHONE, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 179
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 102
+ END
+
+ IDD_VCARD_PHOTO, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 217
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 127
+ END
+
+ IDD_VCARD_NOTE, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 217
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 127
+ END
+
+ IDD_CHANGEPASSWORD, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 174
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 72
+ END
+
+ IDD_GROUPCHAT, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 299
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 203
+ END
+
+ IDD_GROUPCHAT_JOIN, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 201
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 89
+ END
+
+ IDD_GROUPCHAT_INPUT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 268
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 39
+ END
+
+ IDD_JIDLIST, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 200
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 105
+ END
+
+ IDD_AGENT_MANUAL_REGISTER, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 179
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 38
+ END
+
+ IDD_GROUPCHAT_INVITE, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 179
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 67
+ END
+
+ IDD_GROUPCHAT_INVITE_ACCEPT, DIALOG
+ BEGIN
+ LEFTMARGIN, 3
+ RIGHTMARGIN, 228
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 107
+ END
+
+ IDD_OPT_SETAVATAR, DIALOG
+ BEGIN
+ LEFTMARGIN, 2
+ RIGHTMARGIN, 218
+ VERTGUIDE, 9
+ TOPMARGIN, 3
+ BOTTOMMARGIN, 126
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_JABBER ICON "icos\\jabber.ico"
+IDI_GROUP ICON "icos\\group.ico"
+IDI_KEYS ICON "icos\\key.ico"
+IDI_ADDCONTACT ICON "icos\\addcontact.ico"
+IDI_ADDROSTER ICON "icos\\add2roster.ico"
+IDI_AGENTS ICON "icos\\block.ico"
+IDI_VCARD ICON "icos\\pages.ico"
+IDI_DELETE ICON "icos\\delete.ico"
+IDI_EDIT ICON "icos\\rename.ico"
+IDI_GRANT ICON "icos\\grant.ico"
+IDI_OPEN ICON "icos\\open.ico"
+IDI_REQUEST ICON "icos\\request.ico"
+IDI_USER2ROOM ICON "icos\\user2room.ico"
+IDI_WRITE ICON "icos\\write.ico"
+IDI_SAVE ICON "icos\\save.ico"
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/miranda-wine/protocols/JabberG/jabber_agent.cpp b/miranda-wine/protocols/JabberG/jabber_agent.cpp new file mode 100644 index 0000000..061cfba --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_agent.cpp @@ -0,0 +1,565 @@ +/*
+
+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_agent.cpp,v $
+Revision : $Revision: 2866 $
+Last change on : $Date: 2006-05-16 20:39:40 +0400 (Втр, 16 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+#include <commctrl.h>
+#include "resource.h"
+#include "jabber_iq.h"
+
+static BOOL CALLBACK JabberAgentsDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam );
+BOOL CALLBACK JabberAgentRegInputDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam );
+static BOOL CALLBACK JabberAgentRegDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam );
+static BOOL CALLBACK JabberAgentManualRegDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam );
+
+int JabberMenuHandleAgents( WPARAM wParam, LPARAM lParam )
+{
+ if ( IsWindow( hwndJabberAgents ))
+ SetForegroundWindow( hwndJabberAgents );
+ else
+ CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_AGENTS ), NULL, JabberAgentsDlgProc, ( LPARAM )NULL );
+
+ return 0;
+}
+
+static void JabberRegisterAgent( HWND hwndDlg, TCHAR* jid )
+{
+ int iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_GETREGISTER, JabberIqResultGetRegister );
+ XmlNodeIq iq( "get", iqId, jid );
+ XmlNode* query = iq.addQuery( "jabber:iq:register" );
+ JabberSend( jabberThreadInfo->s, iq );
+ hwndAgentRegInput = CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_FORM ), hwndDlg, JabberAgentRegInputDlgProc, 0 );
+}
+
+static BOOL CALLBACK JabberAgentsDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ HWND lv;
+ LVCOLUMN lvCol;
+ LVITEM lvItem;
+ JABBER_LIST_ITEM *item;
+ int i;
+ TCHAR text[128];
+ TCHAR* p;
+ int iqId;
+
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ hwndJabberAgents = hwndDlg;
+ SendMessage( hwndDlg, WM_SETICON, ICON_BIG, ( LPARAM )LoadIcon( hInst, MAKEINTRESOURCE( IDI_AGENTS )) );
+ TranslateDialogDefault( hwndDlg );
+ // Add columns to the top list
+ lv = GetDlgItem( hwndDlg, IDC_AGENT_LIST );
+ lvCol.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
+ lvCol.pszText = TranslateT( "JID" );
+ lvCol.cx = 120;
+ lvCol.iSubItem = 0;
+ ListView_InsertColumn( lv, 0, &lvCol );
+ lvCol.pszText = TranslateT( "Description" );
+ lvCol.cx = 250;
+ lvCol.iSubItem = 1;
+ ListView_InsertColumn( lv, 1, &lvCol );
+ // Add columns to the bottom list
+ lv = GetDlgItem( hwndDlg, IDC_AGENT_TRANSPORT );
+ lvCol.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
+ lvCol.pszText = TranslateT( "JID" );
+ lvCol.cx = 120;
+ lvCol.iSubItem = 0;
+ ListView_InsertColumn( lv, 0, &lvCol );
+ lvCol.pszText = TranslateT( "Status" );
+ lvCol.cx = 80;
+ lvCol.iSubItem = 1;
+ ListView_InsertColumn( lv, 1, &lvCol );
+ if ( jabberOnline ) {
+ SetDlgItemTextA( hwndDlg, IDC_AGENT_SERVER, jabberThreadInfo->server );
+ JabberListRemoveList( LIST_AGENT );
+ iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_DISCOAGENTS, JabberIqResultDiscoAgentItems );
+
+ XmlNodeIq iq( "get", iqId, jabberThreadInfo->server );
+ XmlNode* query = iq.addQuery( "http://jabber.org/protocol/disco#items" );
+ JabberSend( jabberThreadInfo->s, iq );
+
+ SendMessage( hwndDlg, WM_JABBER_TRANSPORT_REFRESH, 0, 0 );
+ }
+ return TRUE;
+ case WM_NOTIFY:
+ switch (( ( LPNMHDR ) lParam )->code ) {
+ case LVN_ITEMCHANGED:
+ {
+ LPNMLISTVIEW lpnm;
+
+ lpnm = ( LPNMLISTVIEW ) lParam;
+ if ( lpnm->hdr.idFrom == IDC_AGENT_LIST ) {
+ lv = GetDlgItem( hwndDlg, IDC_AGENT_LIST );
+ if ( lpnm->uChanged & LVIF_STATE ) {
+ if ( lpnm->uNewState & LVIS_SELECTED ) {
+ lvItem.iItem = lpnm->iItem;
+ lvItem.iSubItem = 0;
+ lvItem.mask = LVIF_TEXT;
+ lvItem.pszText = text;
+ lvItem.cchTextMax = SIZEOF( text );
+ ListView_GetItem( lv, &lvItem );
+ if (( item=JabberListGetItemPtr( LIST_AGENT, lvItem.pszText )) != NULL ) {
+ if ( item->cap & AGENT_CAP_REGISTER )
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_REGISTER ), TRUE );
+ //if ( item->canSearch ) EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_SEARCH ), TRUE );
+ if ( item->cap & AGENT_CAP_GROUPCHAT )
+ EnableWindow( GetDlgItem( hwndDlg, IDC_JOIN ), TRUE );
+ }
+ }
+ else {
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_REGISTER ), FALSE );
+ //EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_SEARCH ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_JOIN ), FALSE );
+ }
+ return TRUE;
+ }
+ }
+ else if ( lpnm->hdr.idFrom == IDC_AGENT_TRANSPORT ) {
+ lv = GetDlgItem( hwndDlg, IDC_AGENT_TRANSPORT );
+ if ( lpnm->uChanged & LVIF_STATE ) {
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_LOGON ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_LOGOFF ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_UNREGISTER ), FALSE );
+ if ( lpnm->uNewState & LVIS_SELECTED ) {
+ lvItem.iItem = lpnm->iItem;
+ lvItem.iSubItem = 0;
+ lvItem.mask = LVIF_TEXT;
+ lvItem.pszText = text;
+ lvItem.cchTextMax = SIZEOF( text );
+ ListView_GetItem( lv, &lvItem );
+ if (( item=JabberListGetItemPtr( LIST_ROSTER, lvItem.pszText )) != NULL ) {
+ if ( item->status == ID_STATUS_OFFLINE )
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_LOGON ), TRUE );
+ else
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_LOGOFF ), TRUE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_UNREGISTER ), TRUE );
+ } }
+ return TRUE;
+ } } }
+ break;
+ }
+ break;
+ case WM_JABBER_AGENT_REFRESH:
+ // lParam = server from which agent information is obtained
+ if ( lParam )
+ SetDlgItemText( hwndDlg, IDC_AGENT_SERVER, ( TCHAR* )lParam );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_REGISTER ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_SEARCH ), FALSE );
+ i = 0;
+ lv = GetDlgItem( hwndDlg, IDC_AGENT_LIST );
+ ListView_DeleteAllItems( lv );
+ lvItem.iItem = 0;
+ while (( i=JabberListFindNext( LIST_AGENT, i )) >= 0 ) {
+ if (( item=JabberListGetItemPtrFromIndex( i )) != NULL ) {
+ lvItem.mask = LVIF_TEXT;
+ lvItem.iSubItem = 0;
+ lvItem.pszText = item->jid;
+ ListView_InsertItem( lv, &lvItem );
+ lvItem.iSubItem = 1;
+ lvItem.pszText = item->name;
+ ListView_SetItem( lv, &lvItem );
+ lvItem.iItem++;
+ }
+ i++;
+ }
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_SERVER ), TRUE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_BROWSE ), TRUE );
+ return TRUE;
+ case WM_JABBER_TRANSPORT_REFRESH:
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_LOGON ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_LOGOFF ), FALSE );
+ i = 0;
+ lv = GetDlgItem( hwndDlg, IDC_AGENT_TRANSPORT );
+ ListView_DeleteAllItems( lv );
+ lvItem.iItem = 0;
+ while (( i=JabberListFindNext( LIST_ROSTER, i )) >= 0 ) {
+ if (( item=JabberListGetItemPtrFromIndex( i )) != NULL ) {
+ if ( _tcschr( item->jid, '@' )==NULL && item->subscription!=SUB_NONE ) {
+ _tcscpy( text, item->jid );
+ if (( p=_tcschr( text, '/' )) != NULL )
+ *p = '\0';
+ lvItem.mask = LVIF_TEXT;
+ lvItem.iSubItem = 0;
+ lvItem.pszText = text;
+ ListView_InsertItem( lv, &lvItem );
+ lvItem.iSubItem = 1;
+ if ( item->status != ID_STATUS_OFFLINE )
+ lvItem.pszText = TranslateT( "Online" );
+ else
+ lvItem.pszText = TranslateT( "Offline" );
+ ListView_SetItem( lv, &lvItem );
+ lvItem.iItem++;
+ } }
+ i++;
+ }
+ return TRUE;
+ case WM_JABBER_CHECK_ONLINE:
+ if ( !jabberOnline ) {
+ if ( hwndAgentRegInput )
+ DestroyWindow( hwndAgentRegInput );
+ if ( hwndAgentManualReg )
+ DestroyWindow( hwndAgentManualReg );
+ }
+ break;
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDC_MANUAL_REGISTER:
+ hwndAgentManualReg = CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_AGENT_MANUAL_REGISTER ), hwndDlg, JabberAgentManualRegDlgProc, 0 );
+ return TRUE;
+ case IDC_AGENT_REGISTER:
+ lv = GetDlgItem( hwndDlg, IDC_AGENT_LIST );
+ if (( lvItem.iItem=ListView_GetNextItem( lv, -1, LVNI_SELECTED )) >= 0 ) {
+ lvItem.iSubItem = 0;
+ lvItem.mask = LVIF_TEXT;
+ lvItem.pszText = text;
+ lvItem.cchTextMax = SIZEOF( text );
+ ListView_GetItem( lv, &lvItem );
+ ListView_SetItemState( lv, lvItem.iItem, 0, LVIS_SELECTED ); // Unselect the item
+ if (( item=JabberListGetItemPtr( LIST_AGENT, lvItem.pszText )) != NULL )
+ JabberRegisterAgent( hwndDlg, item->jid );
+ }
+ return TRUE;
+ case IDC_JOIN:
+ lv = GetDlgItem( hwndDlg, IDC_AGENT_LIST );
+ if (( lvItem.iItem=ListView_GetNextItem( lv, -1, LVNI_SELECTED )) >= 0 ) {
+ lvItem.iSubItem = 0;
+ lvItem.mask = LVIF_TEXT;
+ lvItem.pszText = text;
+ lvItem.cchTextMax = SIZEOF( text );
+ ListView_GetItem( lv, &lvItem );
+ ListView_SetItemState( lv, lvItem.iItem, 0, LVIS_SELECTED ); // Unselect the item
+ if (( item=JabberListGetItemPtr( LIST_AGENT, lvItem.pszText )) != NULL )
+ JabberMenuHandleGroupchat( 0, ( LPARAM )item->jid );
+ }
+ return TRUE;
+ case IDC_AGENT_SERVER:
+ GetDlgItemText( hwndDlg, IDC_AGENT_SERVER, text, SIZEOF( text ));
+ if ( jabberOnline && text[0] )
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_BROWSE ), TRUE );
+ else
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_BROWSE ), FALSE );
+ break;
+ case IDC_AGENT_BROWSE:
+ GetDlgItemText( hwndDlg, IDC_AGENT_SERVER, text, SIZEOF( text ));
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_BROWSE ), FALSE );
+ ListView_DeleteAllItems( GetDlgItem( hwndDlg, IDC_AGENT_LIST ));
+ JabberListRemoveList( LIST_AGENT );
+ iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_DISCOAGENTS, JabberIqResultDiscoAgentItems );
+ { XmlNodeIq iq( "get", iqId, text );
+ XmlNode* query = iq.addQuery( "http://jabber.org/protocol/disco#items" );
+ JabberSend( jabberThreadInfo->s, iq );
+ }
+ return TRUE;
+
+ case IDC_AGENT_LOGON:
+ case IDC_AGENT_LOGOFF:
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_UNREGISTER ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_LOGON ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_LOGOFF ), FALSE );
+ lv = GetDlgItem( hwndDlg, IDC_AGENT_TRANSPORT );
+ if (( lvItem.iItem=ListView_GetNextItem( lv, -1, LVNI_SELECTED )) >= 0 ) {
+ lvItem.iSubItem = 0;
+ lvItem.mask = LVIF_TEXT;
+ lvItem.pszText = text;
+ lvItem.cchTextMax = SIZEOF( text );
+ ListView_GetItem( lv, &lvItem );
+ if (( item=JabberListGetItemPtr( LIST_ROSTER, lvItem.pszText )) != NULL ) {
+ XmlNode p( "presence" ); p.addAttr( "to", item->jid );
+ if ( LOWORD( wParam ) != IDC_AGENT_LOGON )
+ p.addAttr( "type", "unavailable" );
+ JabberSend( jabberThreadInfo->s, p );
+ } }
+ return TRUE;
+ case IDC_AGENT_UNREGISTER:
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_UNREGISTER ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_LOGON ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_AGENT_LOGOFF ), FALSE );
+ lv = GetDlgItem( hwndDlg, IDC_AGENT_TRANSPORT );
+ if (( lvItem.iItem=ListView_GetNextItem( lv, -1, LVNI_SELECTED )) >= 0 ) {
+ lvItem.iSubItem = 0;
+ lvItem.mask = LVIF_TEXT;
+ lvItem.pszText = text;
+ lvItem.cchTextMax = SIZEOF( text );
+ ListView_GetItem( lv, &lvItem );
+ if (( item=JabberListGetItemPtr( LIST_ROSTER, lvItem.pszText )) != NULL ) {
+ { XmlNodeIq iq( "set", NOID, item->jid );
+ XmlNode* query = iq.addQuery( "jabber:iq:register" );
+ query->addChild( "remove" );
+ JabberSend( jabberThreadInfo->s, iq );
+ }
+ {
+ XmlNodeIq iq( "set" );
+ XmlNode* query = iq.addQuery( "jabber:iq:roster" );
+ XmlNode* itm = query->addChild( "item" ); itm->addAttr( "jid", item->jid ); itm->addAttr( "subscription", "remove" );
+ JabberSend( jabberThreadInfo->s, iq );
+ } } }
+ return TRUE;
+
+ case IDCLOSE:
+ DestroyWindow( hwndDlg );
+ return TRUE;
+ }
+ break;
+ case WM_CLOSE:
+ DestroyWindow( hwndDlg );
+ break;
+ case WM_DESTROY:
+ hwndJabberAgents = NULL;
+ break;
+ }
+ return FALSE;
+}
+
+BOOL CALLBACK JabberAgentRegInputDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ static XmlNode *agentRegIqNode;
+
+ int id, ypos, i;
+ TCHAR *from, *str, *str2;
+
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ {
+ EnableWindow( GetParent( hwndDlg ), FALSE );
+ TranslateDialogDefault( hwndDlg );
+ agentRegIqNode = NULL;
+ SetWindowText( hwndDlg, TranslateT( "Jabber Agent Registration" ));
+ SetDlgItemText( hwndDlg, IDC_SUBMIT, TranslateT( "Register" ));
+ SetDlgItemText( hwndDlg, IDC_FRAME_TEXT, TranslateT( "Please wait..." ));
+
+ // Enable WS_EX_CONTROLPARENT on IDC_FRAME ( so tab stop goes through all its children )
+ LONG frameExStyle = GetWindowLong( GetDlgItem( hwndDlg, IDC_FRAME ), GWL_EXSTYLE );
+ frameExStyle |= WS_EX_CONTROLPARENT;
+ SetWindowLong( GetDlgItem( hwndDlg, IDC_FRAME ), GWL_EXSTYLE, frameExStyle );
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDC_SUBMIT:
+ {
+ XmlNode *queryNode, *xNode, *n;
+
+ if ( agentRegIqNode == NULL ) return TRUE;
+ if (( from=JabberXmlGetAttrValue( agentRegIqNode, "from" )) == NULL ) return TRUE;
+ if (( queryNode=JabberXmlGetChild( agentRegIqNode, "query" )) == NULL ) return TRUE;
+ HWND hFrame = GetDlgItem( hwndDlg, IDC_FRAME );
+
+ str = ( TCHAR* )alloca( sizeof(TCHAR) * 128 );
+ str2 = ( TCHAR* )alloca( sizeof(TCHAR) * 128 );
+ id = 0;
+
+ int iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_SETREGISTER, JabberIqResultSetRegister );
+
+ XmlNodeIq iq( "set", iqId, from );
+ XmlNode* query = iq.addQuery( "jabber:iq:register" );
+
+ if (( xNode=JabberXmlGetChild( queryNode, "x" )) != NULL ) {
+ // use new jabber:x:data form
+ query->addChild( JabberFormGetData( hFrame, xNode ));
+ }
+ else {
+ // use old registration information form
+ for ( i=0; i<queryNode->numChild; i++ ) {
+ n = queryNode->child[i];
+ if ( n->name ) {
+ if ( !strcmp( n->name, "key" )) {
+ // field that must be passed along with the registration
+ if ( n->text )
+ query->addChild( n->name, n->text );
+ else
+ query->addChild( n->name );
+ }
+ else if ( !strcmp( n->name, "registered" ) || !strcmp( n->name, "instructions" )) {
+ // do nothing, we will skip these
+ }
+ else {
+ GetDlgItemText( hFrame, id, str2, 128 );
+ query->addChild( n->name, str2 );
+ id++;
+ } } } }
+
+ JabberSend( jabberThreadInfo->s, iq );
+ DialogBoxParam( hInst, MAKEINTRESOURCE( IDD_OPT_REGISTER ), hwndDlg, JabberAgentRegDlgProc, 0 );
+ // Fall through to IDCANCEL
+ }
+ case IDCANCEL:
+ if ( agentRegIqNode )
+ delete agentRegIqNode;
+ DestroyWindow( hwndDlg );
+ return TRUE;
+ }
+ break;
+ case WM_JABBER_REGINPUT_ACTIVATE:
+ if ( wParam == 1 ) { // success
+ // lParam = <iq/> node from agent JID as a result of "get jabber:iq:register"
+ HWND hFrame = GetDlgItem( hwndDlg, IDC_FRAME );
+ HFONT hFont = ( HFONT ) SendMessage( hFrame, WM_GETFONT, 0, 0 );
+ ShowWindow( GetDlgItem( hwndDlg, IDC_FRAME_TEXT ), SW_HIDE );
+
+ XmlNode *queryNode, *xNode, *n;
+ if (( agentRegIqNode=( XmlNode * ) lParam ) == NULL ) return TRUE;
+ if (( queryNode=JabberXmlGetChild( agentRegIqNode, "query" )) == NULL ) return TRUE;
+ id = 0;
+ ypos = 14;
+ if (( xNode=JabberXmlGetChild( queryNode, "x" )) != NULL ) {
+ // use new jabber:x:data form
+ if (( n=JabberXmlGetChild( xNode, "instructions" ))!=NULL && n->text!=NULL )
+ SetDlgItemText( hwndDlg, IDC_INSTRUCTION, n->text );
+
+ JabberFormCreateUI( hFrame, xNode, &i /*dummy*/ );
+ }
+ else {
+ // use old registration information form
+ for ( i=0; i<queryNode->numChild; i++ ) {
+ n = queryNode->child[i];
+ if ( n->name ) {
+ if ( !strcmp( n->name, "instructions" )) {
+ SetDlgItemText( hwndDlg, IDC_INSTRUCTION, n->text );
+ }
+ else if ( !strcmp( n->name, "key" ) || !strcmp( n->name, "registered" )) {
+ // do nothing
+ }
+ else if ( !strcmp( n->name, "password" )) {
+ HWND hCtrl = CreateWindowA( "static", n->name, WS_CHILD|WS_VISIBLE|SS_RIGHT, 10, ypos+4, 100, 18, hFrame, ( HMENU ) IDC_STATIC, hInst, NULL );
+ SendMessage( hCtrl, WM_SETFONT, ( WPARAM ) hFont, 0 );
+ hCtrl = CreateWindowEx( WS_EX_CLIENTEDGE, _T("edit"), n->text, WS_CHILD|WS_VISIBLE|WS_BORDER|WS_TABSTOP|ES_LEFT|ES_AUTOHSCROLL|ES_PASSWORD, 120, ypos, 128, 24, hFrame, ( HMENU ) id, hInst, NULL );
+ SendMessage( hCtrl, WM_SETFONT, ( WPARAM ) hFont, 0 );
+ id++;
+ ypos += 24;
+ }
+ else { // everything else is a normal text field
+ HWND hCtrl = CreateWindowA( "static", n->name, WS_CHILD|WS_VISIBLE|SS_RIGHT, 10, ypos+4, 100, 18, hFrame, ( HMENU ) IDC_STATIC, hInst, NULL );
+ SendMessage( hCtrl, WM_SETFONT, ( WPARAM ) hFont, 0 );
+ hCtrl = CreateWindowEx( WS_EX_CLIENTEDGE, _T("edit"), n->text, WS_CHILD|WS_VISIBLE|WS_BORDER|WS_TABSTOP|ES_LEFT|ES_AUTOHSCROLL, 120, ypos, 128, 24, hFrame, ( HMENU ) id, hInst, NULL );
+ SendMessage( hCtrl, WM_SETFONT, ( WPARAM ) hFont, 0 );
+ id++;
+ ypos += 24;
+ } } } }
+
+ EnableWindow( GetDlgItem( hwndDlg, IDC_SUBMIT ), TRUE );
+ }
+ else if ( wParam == 0 ) {
+ // lParam = error message
+ SetDlgItemTextA( hwndDlg, IDC_FRAME_TEXT, ( LPCSTR ) lParam );
+ }
+ return TRUE;
+ case WM_DESTROY:
+ hwndAgentRegInput = NULL;
+ EnableWindow( GetParent( hwndDlg ), TRUE );
+ SetActiveWindow( GetParent( hwndDlg ));
+ break;
+ }
+
+ return FALSE;
+}
+
+static BOOL CALLBACK JabberAgentManualRegDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ static BOOL dontEnableParent; // Very ugly hack
+
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ EnableWindow( GetParent( hwndDlg ), FALSE );
+ dontEnableParent = FALSE;
+ SendMessage( hwndDlg, WM_SETICON, ICON_BIG, ( LPARAM )LoadIcon( hInst, MAKEINTRESOURCE( IDI_AGENTS )) );
+ TranslateDialogDefault( hwndDlg );
+ return TRUE;
+ case WM_COMMAND:
+ {
+ TCHAR jid[256];
+
+ switch ( LOWORD( wParam )) {
+ case IDC_JID:
+ GetDlgItemText( hwndDlg, IDC_JID, jid, SIZEOF( jid ));
+ EnableWindow( GetDlgItem( hwndDlg, IDOK ), ( jid[0]=='\0' )?FALSE:TRUE );
+ break;
+ case IDOK:
+ GetDlgItemText( hwndDlg, IDC_JID, jid, SIZEOF( jid ));
+ JabberRegisterAgent( GetParent( hwndDlg ), jid );
+ dontEnableParent = TRUE;
+ // Fall through
+ case IDCANCEL:
+ case IDCLOSE:
+ DestroyWindow( hwndDlg );
+ return TRUE;
+ } }
+ break;
+ case WM_DESTROY:
+ hwndAgentManualReg = NULL;
+ if ( dontEnableParent == FALSE ) {
+ EnableWindow( GetParent( hwndDlg ), TRUE );
+ SetActiveWindow( GetParent( hwndDlg ));
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+static BOOL CALLBACK JabberAgentRegDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ hwndRegProgress = hwndDlg;
+ SetWindowTextA( hwndDlg, "Jabber Agent Registration" );
+ TranslateDialogDefault( hwndDlg );
+ ShowWindow( GetDlgItem( hwndDlg, IDOK ), SW_HIDE );
+ ShowWindow( GetDlgItem( hwndDlg, IDCANCEL ), SW_HIDE );
+ ShowWindow( GetDlgItem( hwndDlg, IDC_PROGRESS_REG ), SW_SHOW );
+ ShowWindow( GetDlgItem( hwndDlg, IDCANCEL2 ), SW_SHOW );
+ return TRUE;
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDCANCEL2:
+ case IDOK2:
+ hwndRegProgress = NULL;
+ EndDialog( hwndDlg, 0 );
+ return TRUE;
+ }
+ break;
+ case WM_JABBER_REGDLG_UPDATE: // wParam=progress ( 0-100 ), lparam=status string
+ if (( TCHAR* )lParam == NULL )
+ SetDlgItemText( hwndDlg, IDC_REG_STATUS, TranslateT( "No message" ));
+ else
+ SetDlgItemText( hwndDlg, IDC_REG_STATUS, ( TCHAR* )lParam );
+ if ( wParam >= 0 )
+ SendMessage( GetDlgItem( hwndDlg, IDC_PROGRESS_REG ), PBM_SETPOS, wParam, 0 );
+ if ( wParam >= 100 ) {
+ ShowWindow( GetDlgItem( hwndDlg, IDCANCEL2 ), SW_HIDE );
+ ShowWindow( GetDlgItem( hwndDlg, IDOK2 ), SW_SHOW );
+ SetFocus( GetDlgItem( hwndDlg, IDOK2 ));
+ }
+ else
+ SetFocus( GetDlgItem( hwndDlg, IDCANCEL2 ));
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_bitmap.cpp b/miranda-wine/protocols/JabberG/jabber_bitmap.cpp new file mode 100644 index 0000000..68a6fd1 --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_bitmap.cpp @@ -0,0 +1,53 @@ +/*
+
+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_bitmap.cpp,v $
+Revision : $Revision: 3016 $
+Last change on : $Date: 2006-06-04 23:07:43 +0400 (Вск, 04 Июн 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberEnterBitmapName - enters the picture filename
+
+int __stdcall JabberEnterBitmapName( char* szDest )
+{
+ *szDest = 0;
+
+ char szFilter[ 512 ];
+ JCallService( MS_UTILS_GETBITMAPFILTERSTRINGS, sizeof szFilter, ( LPARAM )szFilter );
+
+ char str[ MAX_PATH ]; str[0] = 0;
+ OPENFILENAMEA ofn = {0};
+ ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
+ ofn.lpstrFilter = szFilter;
+ ofn.lpstrFile = szDest;
+ ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
+ ofn.nMaxFile = MAX_PATH;
+ ofn.nMaxFileTitle = MAX_PATH;
+ ofn.lpstrDefExt = "bmp";
+ if ( !GetOpenFileNameA( &ofn ))
+ return 1;
+
+ return ERROR_SUCCESS;
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_byte.cpp b/miranda-wine/protocols/JabberG/jabber_byte.cpp new file mode 100644 index 0000000..049d3fb --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_byte.cpp @@ -0,0 +1,459 @@ +/*
+
+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_byte.cpp,v $
+Revision : $Revision: 3398 $
+Last change on : $Date: 2006-07-31 15:37:09 +0400 (Пнд, 31 Июл 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+#include "jabber_iq.h"
+#include "jabber_byte.h"
+
+#define JABBER_NETWORK_BUFFER_SIZE 4096
+
+///////////////// Bytestream sending /////////////////////////
+
+static void JabberByteInitiateResult( XmlNode *iqNode, void *userdata );
+static void JabberByteSendConnection( HANDLE hNewConnection, DWORD dwRemoteIP );
+static int JabberByteSendParse( HANDLE hConn, JABBER_BYTE_TRANSFER *jbt, char* buffer, int datalen );
+
+void JabberByteFreeJbt( JABBER_BYTE_TRANSFER *jbt )
+{
+ if ( !jbt ) return;
+ if ( jbt->srcJID ) mir_free( jbt->srcJID );
+ if ( jbt->dstJID ) mir_free( jbt->dstJID );
+ if ( jbt->streamhostJID ) mir_free( jbt->streamhostJID );
+ if ( jbt->iqId ) mir_free( jbt->iqId );
+ if ( jbt->sid ) mir_free( jbt->sid );
+ if ( jbt->iqNode ) delete jbt->iqNode;
+ mir_free( jbt );
+}
+
+void __cdecl JabberByteSendThread( JABBER_BYTE_TRANSFER *jbt )
+{
+ BOOL bDirect, bProxy;
+ char* localAddr;
+ struct in_addr in;
+ DBVARIANT dbv;
+ NETLIBBIND nlb = {0};
+ TCHAR szPort[8];
+ int iqId;
+ JABBER_LIST_ITEM *item;
+ HANDLE hEvent;
+
+ JabberLog( "Thread started: type=bytestream_send" );
+
+ bDirect = JGetByte( "BsDirect", TRUE );
+ bProxy = JGetByte( "BsProxy", FALSE );
+
+ iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_NONE, JabberByteInitiateResult );
+ XmlNodeIq iq( "set", iqId, jbt->dstJID );
+ XmlNode* query = iq.addQuery( "http://jabber.org/protocol/bytestreams" );
+ query->addAttr( "sid", jbt->sid );
+
+ if ( bDirect ) {
+ localAddr = NULL;
+ if ( JGetByte( "BsDirectManual", FALSE ) == TRUE ) {
+ if ( !DBGetContactSetting( NULL, jabberProtoName, "BsDirectAddr", &dbv )) {
+ localAddr = mir_strdup( dbv.pszVal );
+ JFreeVariant( &dbv );
+ }
+ }
+ if ( localAddr == NULL ) {
+ in.S_un.S_addr = jabberLocalIP;
+ localAddr = mir_strdup( inet_ntoa( in ));
+ }
+ nlb.cbSize = sizeof( NETLIBBIND );
+ nlb.pfnNewConnection = JabberByteSendConnection;
+ nlb.wPort = 0; // Use user-specified incoming port ranges, if available
+ jbt->hConn = ( HANDLE ) JCallService( MS_NETLIB_BINDPORT, ( WPARAM ) hNetlibUser, ( LPARAM )&nlb );
+ if ( jbt->hConn == NULL ) {
+ JabberLog( "Cannot allocate port for bytestream_send thread, thread ended." );
+ JabberByteFreeJbt( jbt );
+ return;
+ }
+ mir_sntprintf( szPort, SIZEOF( szPort ), _T("%d"), nlb.wPort );
+ item = JabberListAdd( LIST_BYTE, szPort );
+ item->jbt = jbt;
+ hEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+ jbt->hEvent = hEvent;
+ XmlNode* h = query->addChild( "streamhost" );
+ h->addAttr( "jid", jabberThreadInfo->fullJID ); h->addAttr( "host", localAddr ); h->addAttr( "port", nlb.wPort );
+ mir_free( localAddr );
+ }
+ JabberSend( jabberThreadInfo->s, iq );
+
+ if ( bDirect ) {
+ WaitForSingleObject( hEvent, INFINITE );
+ CloseHandle( hEvent );
+ jbt->hEvent = NULL;
+ jbt->pfnFinal(( jbt->state==JBT_DONE )?TRUE:FALSE, jbt->userdata );
+ if ( jbt->hConn != NULL )
+ Netlib_CloseHandle( jbt->hConn );
+ JabberByteFreeJbt( jbt );
+ JabberListRemove( LIST_BYTE, szPort );
+ }
+
+ JabberLog( "Thread ended: type=bytestream_send" );
+}
+
+static void JabberByteInitiateResult( XmlNode *iqNode, void *userdata )
+{
+ TCHAR* type;
+
+ if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return;
+ if ( !lstrcmp( type, _T("result"))) {
+ }
+ else if ( !lstrcmp( type, _T("error"))) {
+ }
+}
+
+static void JabberByteSendConnection( HANDLE hConn, DWORD dwRemoteIP )
+{
+ SOCKET s;
+ SOCKADDR_IN saddr;
+ int len;
+ WORD localPort;
+ TCHAR szPort[8];
+ JABBER_BYTE_TRANSFER *jbt;
+ int recvResult, bytesParsed;
+ HANDLE hListen;
+ JABBER_LIST_ITEM *item;
+ char* buffer;
+ int datalen;
+
+ localPort = 0;
+ if (( s=JCallService( MS_NETLIB_GETSOCKET, ( WPARAM ) hConn, 0 )) != INVALID_SOCKET ) {
+ len = sizeof( saddr );
+ if ( getsockname( s, ( SOCKADDR * ) &saddr, &len ) != SOCKET_ERROR )
+ localPort = ntohs( saddr.sin_port );
+ }
+ if ( localPort == 0 ) {
+ JabberLog( "bytestream_send_connection unable to determine the local port, connection closed." );
+ Netlib_CloseHandle( hConn );
+ return;
+ }
+
+ mir_sntprintf( szPort, SIZEOF( szPort ), _T("%d"), localPort );
+ JabberLog( "bytestream_send_connection incoming connection accepted: local_port=" TCHAR_STR_PARAM, szPort );
+
+ if (( item=JabberListGetItemPtr( LIST_BYTE, szPort )) == NULL ) {
+ JabberLog( "No bytestream session is currently active, connection closed." );
+ Netlib_CloseHandle( hConn );
+ return;
+ }
+
+ jbt = item->jbt;
+
+ if (( buffer=( char* )mir_alloc( JABBER_NETWORK_BUFFER_SIZE )) == NULL ) {
+ JabberLog( "bytestream_send cannot allocate network buffer, connection closed." );
+ jbt->state = JBT_ERROR;
+ Netlib_CloseHandle( hConn );
+ if ( jbt->hEvent != NULL ) SetEvent( jbt->hEvent );
+ return;
+ }
+
+ hListen = jbt->hConn;
+ jbt->hConn = hConn;
+ jbt->state = JBT_INIT;
+ datalen = 0;
+ while ( jbt->state!=JBT_DONE && jbt->state!=JBT_ERROR ) {
+ recvResult = Netlib_Recv( hConn, buffer+datalen, JABBER_NETWORK_BUFFER_SIZE-datalen, 0 );
+ if ( recvResult <= 0 ) break;
+ datalen += recvResult;
+ bytesParsed = JabberByteSendParse( hConn, jbt, buffer, datalen );
+ if ( bytesParsed < datalen )
+ memmove( buffer, buffer+bytesParsed, datalen-bytesParsed );
+ datalen -= bytesParsed;
+ }
+ if ( jbt->hConn ) Netlib_CloseHandle( jbt->hConn );
+ JabberLog( "bytestream_send_connection closing connection" );
+ jbt->hConn = hListen;
+ mir_free( buffer );
+
+ if ( jbt->hEvent != NULL ) SetEvent( jbt->hEvent );
+}
+
+static int JabberByteSendParse( HANDLE hConn, JABBER_BYTE_TRANSFER *jbt, char* buffer, int datalen )
+{
+ int nMethods;
+ BYTE data[10];
+ int i;
+ char* str;
+
+ switch ( jbt->state ) {
+ case JBT_INIT:
+ // received:
+ // 00-00 ver ( 0x05 )
+ // 01-01 nmethods
+ // 02-xx list of methods ( nmethods bytes )
+ // send:
+ // 00-00 ver ( 0x05 )
+ // 01-01 select method ( 0=no auth required )
+ if ( datalen>=2 && buffer[0]==5 && buffer[1]+2==datalen ) {
+ nMethods = buffer[1];
+ for ( i=0; i<nMethods && buffer[2+i]!=0; i++ );
+ if ( i < nMethods ) {
+ data[1] = 0;
+ jbt->state = JBT_CONNECT;
+ }
+ else {
+ data[1] = 0xff;
+ jbt->state = JBT_ERROR;
+ }
+ data[0] = 5;
+ Netlib_Send( hConn, ( char* )data, 2, 0 );
+ }
+ else jbt->state = JBT_ERROR;
+ break;
+ case JBT_CONNECT:
+ // received:
+ // 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 )
+ // send:
+ // 00-00 ver ( 0x05 )
+ // 01-01 reply ( 0=success,2=not allowed )
+ // 02-02 reserved ( 0 )
+ // 03-03 address type ( 1=IPv4 address )
+ // 04-07 bnd.addr server bound address
+ // 08-09 bnd.port server bound port
+ if ( datalen==47 && *(( DWORD* )buffer )==0x03000105 && buffer[4]==40 && *(( WORD* )( buffer+45 ))==0 ) {
+ TCHAR text[256];
+ mir_sntprintf( text, SIZEOF( text ), _T("%s%s%s"), jbt->sid, jbt->srcJID, jbt->dstJID );
+ char* szAuthString = t2a( text );
+ JabberLog( "Auth: '%s'", szAuthString );
+ if (( str = JabberSha1( szAuthString )) != NULL ) {
+ for ( i=0; i<40 && buffer[i+5]==str[i]; i++ );
+ mir_free( str );
+
+ ZeroMemory( data, 10 );
+ data[1] = ( i>=20 )?0:2;
+ data[0] = 5;
+ data[3] = 1;
+ Netlib_Send( hConn, ( char* )data, 10, 0 );
+ if ( i>=20 && jbt->pfnSend( hConn, jbt->userdata )==TRUE )
+ jbt->state = JBT_DONE;
+ else
+ jbt->state = JBT_ERROR;
+ }
+ mir_free( szAuthString );
+ }
+ else
+ jbt->state = JBT_ERROR;
+ break;
+ }
+
+ return datalen;
+}
+
+///////////////// Bytestream receiving /////////////////////////
+
+static int JabberByteReceiveParse( HANDLE hConn, JABBER_BYTE_TRANSFER *jbt, char* buffer, int datalen );
+
+void __cdecl JabberByteReceiveThread( JABBER_BYTE_TRANSFER *jbt )
+{
+ XmlNode *iqNode, *queryNode, *n;
+ TCHAR *from, *to, *sid, *szId, *szHost, *szPort, *str;
+ int i;
+ WORD port;
+ HANDLE hConn;
+ char data[3];
+ char* buffer;
+ int datalen, bytesParsed, recvResult;
+ BOOL validStreamhost;
+
+ if ( jbt == NULL ) return;
+ if (( iqNode=jbt->iqNode )!=NULL &&
+ ( from=JabberXmlGetAttrValue( iqNode, "from" ))!=NULL &&
+ ( to=JabberXmlGetAttrValue( iqNode, "to" ))!=NULL &&
+ ( queryNode=JabberXmlGetChild( iqNode, "query" ))!=NULL &&
+ ( sid=JabberXmlGetAttrValue( queryNode, "sid" ))!=NULL &&
+ ( n=JabberXmlGetChild( queryNode, "streamhost" ))!=NULL ) {
+
+ szId = JabberXmlGetAttrValue( iqNode, "id" );
+ jbt->iqId = ( szId ) ? mir_tstrdup( szId ):NULL;
+ jbt->srcJID = mir_tstrdup( from );
+ jbt->dstJID = mir_tstrdup( to );
+ jbt->sid = mir_tstrdup( sid );
+
+ if (( buffer=( char* )mir_alloc( JABBER_NETWORK_BUFFER_SIZE )) == NULL ) {
+ JabberLog( "bytestream_send cannot allocate network buffer, connection closed." );
+
+ XmlNodeIq iq( "error", jbt->iqId, jbt->srcJID );
+ XmlNode* e = iq.addChild( "error" ); e->addAttr( "code", 406 ); e->addAttr( "type", "auth" );
+ XmlNode* na = e->addChild( "not-acceptable" ); na->addAttr( "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas" );
+ JabberSend( jabberThreadInfo->s, iq );
+
+ JabberByteFreeJbt( jbt );
+ return;
+ }
+
+ jbt->state = JBT_INIT;
+ validStreamhost = FALSE;
+ for ( i=1; ( n=JabberXmlGetNthChild( queryNode, "streamhost", i ))!=NULL; i++ ) {
+ if (( szHost=JabberXmlGetAttrValue( n, "host" ))!=NULL &&
+ ( szPort=JabberXmlGetAttrValue( n, "port" ))!=NULL &&
+ ( str=JabberXmlGetAttrValue( n, "jid" ))!=NULL ) {
+
+ port = ( WORD )_ttoi( szPort );
+ if ( jbt->streamhostJID ) mir_free( jbt->streamhostJID );
+ jbt->streamhostJID = mir_tstrdup( str );
+
+ JabberLog( "bytestream_recv connecting to " TCHAR_STR_PARAM ":%d", szHost, port );
+ NETLIBOPENCONNECTION nloc = { 0 };
+ nloc.cbSize = sizeof( nloc );
+ #if defined( _UNICODE )
+ nloc.szHost = u2a(szHost);
+ #else
+ nloc.szHost = szHost;
+ #endif
+ nloc.wPort = port;
+ hConn = ( HANDLE ) JCallService( MS_NETLIB_OPENCONNECTION, ( WPARAM ) hNetlibUser, ( LPARAM )&nloc );
+ #if defined( _UNICODE )
+ mir_free((void*)nloc.szHost);
+ #endif
+ if ( hConn == NULL ) {
+ JabberLog( "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 = JabberByteReceiveParse( 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 );
+ JabberLog( "bytestream_recv_connection closing connection" );
+ }
+ if ( jbt->state==JBT_ERROR || validStreamhost==TRUE )
+ break;
+ JabberLog( "bytestream_recv_connection stream cannot be established, try next streamhost" );
+ }
+ mir_free( buffer );
+ jbt->pfnFinal(( jbt->state==JBT_DONE )?TRUE:FALSE, jbt->userdata );
+ if ( !validStreamhost ) {
+ JabberLog( "bytestream_recv_connection session not completed" );
+
+ XmlNodeIq iq( "error", jbt->iqId, jbt->srcJID );
+ XmlNode* e = iq.addChild( "error" ); e->addAttr( "code", 404 ); e->addAttr( "type", _T("cancel"));
+ XmlNode* na = e->addChild( "item-not-found" ); na->addAttr( "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas" );
+ JabberSend( jabberThreadInfo->s, iq );
+ } }
+
+ JabberByteFreeJbt( jbt );
+ JabberLog( "Thread ended: type=bytestream_recv" );
+}
+
+static int JabberByteReceiveParse( 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[256];
+ mir_sntprintf( text, SIZEOF( text ), _T("%s%s%s"), jbt->sid, jbt->srcJID, jbt->dstJID );
+ char* szAuthString = t2a( text );
+ JabberLog( "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 )) {
+ if ( buffer[3]==1 && datalen>=10 )
+ num = 10;
+ else if ( buffer[3]==3 && datalen>=buffer[4]+7 )
+ num = buffer[4] + 7;
+ else {
+ jbt->state = JBT_SOCKSERR;
+ break;
+ }
+ jbt->state = JBT_RECVING;
+
+ XmlNodeIq iq( "result", jbt->iqId, jbt->srcJID );
+ XmlNode* query = iq.addQuery( "http://jabber.org/protocol/bytestreams" );
+ XmlNode* stream = query->addChild( "streamhost-used" ); stream->addAttr( "jid", jbt->streamhostJID );
+ JabberSend( jabberThreadInfo->s, iq );
+ }
+ else jbt->state = JBT_SOCKSERR;
+ break;
+
+ case JBT_RECVING:
+ bytesReceived = jbt->pfnRecv( hConn, jbt->userdata, buffer, datalen );
+ if ( bytesReceived < 0 )
+ jbt->state = JBT_ERROR;
+ else if ( bytesReceived == 0 )
+ jbt->state = JBT_DONE;
+ break;
+ }
+
+ return num;
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_byte.h b/miranda-wine/protocols/JabberG/jabber_byte.h new file mode 100644 index 0000000..cd16478 --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_byte.h @@ -0,0 +1,52 @@ +/*
+
+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_byte.h,v $
+Revision : $Revision: 2866 $
+Last change on : $Date: 2006-05-16 20:39:40 +0400 (Втр, 16 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#ifndef _JABBER_BYTE_H_
+#define _JABBER_BYTE_H_
+
+typedef enum { JBT_INIT, JBT_AUTH, JBT_CONNECT, JBT_SOCKSERR, JBT_SENDING, JBT_RECVING, JBT_DONE, JBT_ERROR } JABBER_BYTE_STATE;
+
+typedef struct {
+ TCHAR* sid;
+ TCHAR* srcJID;
+ TCHAR* dstJID;
+ TCHAR* streamhostJID;
+ TCHAR* iqId;
+ JABBER_BYTE_STATE state;
+ HANDLE hConn;
+ HANDLE hEvent;
+ XmlNode *iqNode;
+ BOOL ( *pfnSend )( HANDLE hConn, void *userdata );
+ int ( *pfnRecv )( HANDLE hConn, void *userdata, char* buffer, int datalen );
+ void ( *pfnFinal )( BOOL success, void *userdata );
+ void *userdata;
+} JABBER_BYTE_TRANSFER;
+
+void __cdecl JabberByteSendThread( JABBER_BYTE_TRANSFER *jbt );
+void __cdecl JabberByteReceiveThread( JABBER_BYTE_TRANSFER *jbt );
+
+#endif
diff --git a/miranda-wine/protocols/JabberG/jabber_chat.cpp b/miranda-wine/protocols/JabberG/jabber_chat.cpp new file mode 100644 index 0000000..946e38b --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_chat.cpp @@ -0,0 +1,796 @@ +/*
+
+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_chat.cpp,v $
+Revision : $Revision: 3666 $
+Last change on : $Date: 2006-08-31 16:51:33 +0400 (Чтв, 31 Авг 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+#include "jabber_iq.h"
+#include "resource.h"
+
+extern HANDLE hInitChat;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// One string entry dialog
+
+struct JabberEnterStringParams
+{ TCHAR* result;
+ size_t resultLen;
+};
+
+BOOL CALLBACK JabberEnterStringDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ {
+ TranslateDialogDefault( hwndDlg );
+ JabberEnterStringParams* params = ( JabberEnterStringParams* )lParam;
+ SetWindowLong( hwndDlg, GWL_USERDATA, ( LONG )params );
+ SetWindowText( hwndDlg, params->result );
+ return TRUE;
+ }
+
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDOK:
+ { JabberEnterStringParams* params = ( JabberEnterStringParams* )GetWindowLong( hwndDlg, GWL_USERDATA );
+ GetDlgItemText( hwndDlg, IDC_TOPIC, params->result, params->resultLen );
+ params->result[ params->resultLen-1 ] = 0;
+ EndDialog( hwndDlg, 1 );
+ break;
+ }
+ case IDCANCEL:
+ EndDialog( hwndDlg, 0 );
+ break;
+ } }
+
+ return FALSE;
+}
+
+BOOL JabberEnterString( TCHAR* result, size_t resultLen )
+{
+ JabberEnterStringParams params = { result, resultLen };
+ return DialogBoxParam( hInst, MAKEINTRESOURCE( IDD_GROUPCHAT_INPUT ), NULL, JabberEnterStringDlgProc, LPARAM( ¶ms ));
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberGcInit - initializes the new chat
+
+static char* sttRoles[] = { "Other", "Visitors", "Participants", "Moderators" };
+
+int JabberGcInit( WPARAM wParam, LPARAM lParam )
+{
+ JABBER_LIST_ITEM* item = ( JABBER_LIST_ITEM* )wParam;
+ GCSESSION gcw = {0};
+ GCEVENT gce = {0};
+
+ #if defined( _UNICODE )
+ TCHAR* wszNick = JabberNickFromJID( item->jid );
+ char* szNick = u2a( wszNick );
+ mir_free( wszNick );
+ char* jid = u2a( item->jid );
+ #else
+ char* szNick = JabberNickFromJID( item->jid );
+ char* jid = item->jid;
+ #endif
+ gcw.cbSize = sizeof(GCSESSION);
+ gcw.iType = GCW_CHATROOM;
+ gcw.pszModule = jabberProtoName;
+ gcw.pszName = szNick;
+ gcw.pszID = jid;
+ gcw.pszStatusbarText = NULL;
+ gcw.bDisableNickList = FALSE;
+ JCallService(MS_GC_NEWSESSION, NULL, (LPARAM)&gcw);
+
+ HANDLE hContact = JabberHContactFromJID( item->jid );
+ if ( hContact != NULL ) {
+ DBVARIANT dbv;
+ if ( !DBGetContactSetting( hContact, jabberProtoName, "MyNick", &dbv )) {
+ if ( !strcmp( dbv.pszVal, szNick ))
+ JDeleteSetting( hContact, "MyNick" );
+ else
+ JSetStringT( hContact, "MyNick", item->nick );
+ JFreeVariant( &dbv );
+ }
+ else JSetStringT( hContact, "MyNick", item->nick );
+ }
+ mir_free( szNick );
+
+ item->bChatActive = TRUE;
+
+ GCDEST gcd = { jabberProtoName, jid, GC_EVENT_ADDGROUP };
+ gce.cbSize = sizeof(GCEVENT);
+ gce.pDest = &gcd;
+ for ( int i=sizeof(sttRoles)/sizeof(char*)-1; i >= 0; i-- ) {
+ gce.pszStatus = Translate( sttRoles[i] );
+ JCallService(MS_GC_EVENT, NULL, ( LPARAM )&gce );
+ }
+
+ gce.cbSize = sizeof(GCEVENT);
+ gce.pDest = &gcd;
+ gcd.iType = GC_EVENT_CONTROL;
+ JCallService(MS_GC_EVENT, SESSION_INITDONE, (LPARAM)&gce);
+ JCallService(MS_GC_EVENT, SESSION_ONLINE, (LPARAM)&gce);
+ JCallService(MS_GC_EVENT, WINDOW_VISIBLE, (LPARAM)&gce);
+ #if defined( _UNICODE )
+ mir_free( jid );
+ #endif
+ return 0;
+}
+
+void JabberGcLogCreate( JABBER_LIST_ITEM* item )
+{
+ if ( item->bChatActive )
+ return;
+
+ NotifyEventHooks( hInitChat, (WPARAM)item, 0 );
+}
+
+void JabberGcLogUpdateMemberStatus( JABBER_LIST_ITEM* item, TCHAR* nick, int action, XmlNode* reason )
+{
+ int statusToSet = 0;
+ char* szReason = NULL;
+ if ( reason != NULL && reason->text != NULL ) {
+ #if defined( _UNICODE )
+ szReason = u2a( reason->text );
+ #else
+ szReason = reason->text;
+ #endif
+ }
+
+ TCHAR* myNick = (item->nick == NULL) ? NULL : mir_tstrdup( item->nick );
+ if ( myNick == NULL )
+ myNick = JabberNickFromJID( jabberJID );
+
+ #if defined( _UNICODE )
+ char* dispNick = u2a( nick );
+ char* szNick = u2a( myNick );
+ char* jid = u2a( item->jid );
+ #else
+ char* dispNick = nick;
+ char* szNick = myNick;
+ char* jid = item->jid;
+ #endif
+
+ GCDEST gcd = { jabberProtoName, jid, 0 };
+ GCEVENT gce = {0};
+ gce.cbSize = sizeof(GCEVENT);
+ gce.pszNick = dispNick;
+ gce.pszUID = dispNick;
+ gce.pDest = &gcd;
+ gce.pszText = szReason;
+ if ( item->bChatActive == 2 ) {
+ gce.bAddToLog = TRUE;
+ gce.time = time(0);
+ }
+
+ switch( gcd.iType = action ) {
+ case GC_EVENT_PART: break;
+ case GC_EVENT_KICK: gce.pszStatus = Translate( "Moderator" ); break;
+ default:
+ for ( int i=0; i < item->resourceCount; i++ ) {
+ JABBER_RESOURCE_STATUS& JS = item->resource[i];
+ if ( !lstrcmp( nick, JS.resourceName )) {
+ if ( action != GC_EVENT_JOIN ) {
+ switch( action ) {
+ case 0:
+ gcd.iType = GC_EVENT_ADDSTATUS;
+ case GC_EVENT_REMOVESTATUS:
+ gce.bAddToLog = false;
+ }
+ gce.pszText = Translate( "Moderator" );
+ }
+ gce.pszStatus = JTranslate( sttRoles[ JS.role ] );
+ gce.bIsMe = ( lstrcmpA( szNick, dispNick ) == 0 );
+ statusToSet = JS.status;
+ break;
+ } } }
+
+ JCallService( MS_GC_EVENT, NULL, ( LPARAM )&gce );
+
+ if ( statusToSet != 0 ) {
+ gce.pszText = dispNick;
+ if ( statusToSet == ID_STATUS_AWAY || statusToSet == ID_STATUS_NA || statusToSet == ID_STATUS_DND )
+ gce.dwItemData = 3;
+ else
+ gce.dwItemData = 1;
+ gcd.iType = GC_EVENT_SETSTATUSEX;
+ JCallService( MS_GC_EVENT, NULL, ( LPARAM )&gce );
+ }
+
+ mir_free( myNick );
+ #if defined( _UNICODE )
+ mir_free( dispNick );
+ mir_free( szReason );
+ mir_free( jid );
+ mir_free( szNick );
+ #endif
+}
+
+void JabberGcQuit( JABBER_LIST_ITEM* item, int code, XmlNode* reason )
+{
+ char* szReason = NULL;
+ if ( reason != NULL && reason->text != NULL ) {
+ #if defined( _UNICODE )
+ szReason = u2a( reason->text );
+ #else
+ szReason = reason->text;
+ #endif
+ }
+
+ #if defined( _UNICODE )
+ char* jid = u2a( item->jid );
+ #else
+ char* jid = item->jid;
+ #endif
+
+ GCDEST gcd = { jabberProtoName, jid, GC_EVENT_CONTROL };
+ GCEVENT gce = {0};
+ gce.cbSize = sizeof(GCEVENT);
+ gce.pszUID = jid;
+ gce.pDest = &gcd;
+ gce.pszText = szReason;
+
+ if ( code != 307 ) {
+ JCallService( MS_GC_EVENT, SESSION_TERMINATE, ( LPARAM )&gce );
+ JCallService( MS_GC_EVENT, WINDOW_CLEARLOG, ( LPARAM )&gce );
+ }
+ else {
+ TCHAR* myNick = JabberNickFromJID( jabberJID );
+ JabberGcLogUpdateMemberStatus( item, myNick, GC_EVENT_KICK, reason );
+ mir_free( myNick );
+ JCallService( MS_GC_EVENT, SESSION_OFFLINE, ( LPARAM )&gce );
+ }
+
+ DBDeleteContactSetting( JabberHContactFromJID( item->jid ), "CList", "Hidden" );
+ item->bChatActive = FALSE;
+
+ if ( jabberOnline ) {
+ XmlNode p( "presence" ); p.addAttr( "to", item->jid ); p.addAttr( "type", "unavailable" );
+ JabberSend( jabberThreadInfo->s, p );
+ JabberListRemove( LIST_CHATROOM, item->jid );
+ }
+
+ #if defined( _UNICODE )
+ mir_free( szReason );
+ mir_free( jid );
+ #endif
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Context menu hooks
+
+#define IDM_LEAVE 10
+#define IDM_TOPIC 12
+
+int JabberGcMenuHook( WPARAM wParam, LPARAM lParam )
+{
+ GCMENUITEMS* gcmi= ( GCMENUITEMS* )lParam;
+ if ( gcmi == NULL )
+ return 0;
+
+ if ( lstrcmpiA( gcmi->pszModule, jabberProtoName ))
+ return 0;
+
+ #if defined( _UNICODE )
+ TCHAR* pszID = a2u( gcmi->pszID );
+ #else
+ char* pszID = gcmi->pszID;
+ #endif
+ JABBER_LIST_ITEM* item = JabberListGetItemPtr( LIST_CHATROOM, pszID );
+ #if defined( _UNICODE )
+ mir_free( pszID );
+ #endif
+ if ( item == NULL )
+ return 0;
+
+ #if defined( _UNICODE )
+ TCHAR* pszUID = a2u( gcmi->pszUID );
+ #else
+ char* pszUID = gcmi->pszUID;
+ #endif
+
+ JABBER_RESOURCE_STATUS *me = NULL, *him = NULL;
+ for ( int i=0; i < item->resourceCount; i++ ) {
+ JABBER_RESOURCE_STATUS& p = item->resource[i];
+ if ( !lstrcmp( p.resourceName, item->nick )) me = &p;
+ if ( !lstrcmp( p.resourceName, pszUID )) him = &p;
+ }
+
+ #if defined( _UNICODE )
+ mir_free( pszUID );
+ #endif
+
+ if ( gcmi->Type == MENU_ON_LOG ) {
+ static struct gc_item sttLogListItems[] = {
+ { JTranslate( "&Leave chat session" ), IDM_LEAVE, MENU_ITEM, FALSE },
+ { NULL, 0, MENU_SEPARATOR, FALSE },
+ { JTranslate( "&Voice List..." ), IDM_VOICE, MENU_ITEM, TRUE },
+ { JTranslate( "&Ban List..." ), IDM_BAN, MENU_ITEM, TRUE },
+ { NULL, 0, MENU_SEPARATOR, FALSE },
+ { JTranslate( "&Member List..." ), IDM_MEMBER, MENU_ITEM, TRUE },
+ { JTranslate( "Mo&derator List..." ), IDM_MODERATOR, MENU_ITEM, TRUE },
+ { JTranslate( "&Admin List..." ), IDM_ADMIN, MENU_ITEM, TRUE },
+ { JTranslate( "&Owner List..." ), IDM_OWNER, MENU_ITEM, TRUE },
+ { NULL, 0, MENU_SEPARATOR, FALSE },
+ { JTranslate( "Change &Nickname..." ), IDM_NICK, MENU_ITEM, FALSE },
+ { JTranslate( "Set &Topic..." ), IDM_TOPIC, MENU_ITEM, FALSE },
+ { JTranslate( "&Invite a User..." ), IDM_INVITE, MENU_ITEM, FALSE },
+ { JTranslate( "Room Con&figuration..." ), IDM_CONFIG, MENU_ITEM, TRUE },
+ { NULL, 0, MENU_SEPARATOR, FALSE },
+ { JTranslate( "Destroy Room..." ), IDM_DESTROY, MENU_ITEM, TRUE }};
+
+ gcmi->nItems = sizeof( sttLogListItems ) / sizeof( sttLogListItems[0] );
+ gcmi->Item = sttLogListItems;
+
+ if ( me != NULL ) {
+ if ( me->role == ROLE_MODERATOR )
+ sttLogListItems[2].bDisabled = FALSE;
+
+ if ( me->affiliation == AFFILIATION_ADMIN )
+ sttLogListItems[3].bDisabled = sttLogListItems[5].bDisabled = sttLogListItems[6].bDisabled = FALSE;
+ else if ( me->affiliation == AFFILIATION_OWNER )
+ sttLogListItems[3].bDisabled = sttLogListItems[5].bDisabled =
+ sttLogListItems[6].bDisabled = sttLogListItems[7].bDisabled =
+ sttLogListItems[8].bDisabled = sttLogListItems[13].bDisabled =
+ sttLogListItems[15].bDisabled = FALSE;
+ }
+ }
+ else if ( gcmi->Type == MENU_ON_NICKLIST ) {
+ static struct gc_item sttListItems[] = {
+ { JTranslate( "&Leave chat session" ), IDM_LEAVE, MENU_ITEM, FALSE },
+ { NULL, 0, MENU_SEPARATOR, FALSE },
+ { JTranslate( "Kick" ), IDM_KICK, MENU_ITEM, TRUE },
+ { JTranslate( "Ban" ), IDM_BAN, MENU_ITEM, TRUE },
+ { NULL, 0, MENU_SEPARATOR, FALSE },
+ { JTranslate( "Toggle &Voice" ), IDM_VOICE, MENU_ITEM, TRUE },
+ { JTranslate( "Toggle Moderator" ), IDM_MODERATOR, MENU_ITEM, TRUE },
+ { JTranslate( "Toggle Admin" ), IDM_ADMIN, MENU_ITEM, TRUE },
+ { JTranslate( "Toggle Owner" ), IDM_OWNER, MENU_ITEM, TRUE }};
+
+ gcmi->nItems = sizeof( sttListItems )/sizeof( sttListItems[0] );
+ gcmi->Item = sttListItems;
+
+ if ( me != NULL && him != NULL ) {
+ if ( me->role == ROLE_MODERATOR )
+ if ( him->affiliation != AFFILIATION_ADMIN && him->affiliation != AFFILIATION_OWNER )
+ sttListItems[2].bDisabled = sttListItems[3].bDisabled = FALSE;
+
+ if ( me->affiliation == AFFILIATION_ADMIN ) {
+ if ( him->affiliation != AFFILIATION_ADMIN && him->affiliation != AFFILIATION_OWNER )
+ sttListItems[5].bDisabled = sttListItems[6].bDisabled = FALSE;
+ }
+ else if ( me->affiliation == AFFILIATION_OWNER )
+ sttListItems[5].bDisabled = sttListItems[6].bDisabled =
+ sttListItems[7].bDisabled = sttListItems[8].bDisabled = FALSE;
+ } }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Conference invitation dialog
+
+static BOOL CALLBACK JabberGcLogInviteDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ {
+ TranslateDialogDefault( hwndDlg );
+ SendMessage( hwndDlg, WM_SETICON, ICON_BIG, ( LPARAM )LoadIcon( hInst, MAKEINTRESOURCE( IDI_GROUP )) );
+ SetDlgItemTextA( hwndDlg, IDC_ROOM, ( char* )lParam );
+ HWND hwndComboBox = GetDlgItem( hwndDlg, IDC_USER );
+ int index = 0;
+ while (( index=JabberListFindNext( LIST_ROSTER, index )) >= 0 ) {
+ JABBER_LIST_ITEM* item = JabberListGetItemPtrFromIndex( index );
+ if ( item->status != ID_STATUS_OFFLINE ) {
+ // Add every non-offline users to the combobox
+ int n = SendMessage( hwndComboBox, CB_ADDSTRING, 0, ( LPARAM )item->jid );
+ SendMessage( hwndComboBox, CB_SETITEMDATA, n, ( LPARAM )item->jid );
+ }
+ index++;
+ }
+ SetWindowLong( hwndDlg, GWL_USERDATA, ( LONG ) mir_strdup(( char* )lParam ));
+ }
+ return TRUE;
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDC_INVITE:
+ {
+ char* room = ( char* )GetWindowLong( hwndDlg, GWL_USERDATA );
+ if ( room != NULL ) {
+ TCHAR text[256], user[256], *pUser;
+ HWND hwndComboBox = GetDlgItem( hwndDlg, IDC_USER );
+ int n = SendMessage( hwndComboBox, CB_GETCURSEL, 0, 0 );
+ if ( n < 0 ) {
+ GetWindowText( hwndComboBox, user, SIZEOF( user ));
+ pUser = user;
+ }
+ else pUser = ( TCHAR* )SendMessage( hwndComboBox, CB_GETITEMDATA, n, 0 );
+
+ if ( pUser != NULL ) {
+ GetDlgItemText( hwndDlg, IDC_REASON, text, SIZEOF( text ));
+ int iqId = JabberSerialNext();
+
+ XmlNode m( "message" ); m.addAttr( "from", jabberJID ); m.addAttr( "to", room ); m.addAttrID( iqId );
+ XmlNode* x = m.addChild( "x" ); x->addAttr( "xmlns", _T("http://jabber.org/protocol/muc#user"));
+ XmlNode* i = x->addChild( "invite" ); i->addAttr( "to", pUser );
+ if ( text[0] != 0 )
+ i->addChild( "reason", text );
+ JabberSend( jabberThreadInfo->s, m );
+ } } }
+ // Fall through
+ case IDCANCEL:
+ case IDCLOSE:
+ DestroyWindow( hwndDlg );
+ return TRUE;
+ }
+ break;
+ case WM_CLOSE:
+ DestroyWindow( hwndDlg );
+ break;
+ case WM_DESTROY:
+ {
+ char* str;
+
+ if (( str=( char* )GetWindowLong( hwndDlg, GWL_USERDATA )) != NULL )
+ mir_free( str );
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Context menu processing
+
+static void JabberAdminSet( const TCHAR* to, const char* ns, const char* szItem, const TCHAR* itemVal, const char* var, const TCHAR* varVal )
+{
+ XmlNodeIq iq( "set", NOID, to );
+ XmlNode* query = iq.addQuery( ns );
+ XmlNode* item = query->addChild( "item" ); item->addAttr( szItem, itemVal ); item->addAttr( var, varVal );
+ JabberSend( jabberThreadInfo->s, iq );
+}
+
+static void JabberAdminGet( const TCHAR* to, const char* ns, const char* var, const TCHAR* varVal, JABBER_IQ_PFUNC foo )
+{
+ int id = JabberSerialNext();
+ JabberIqAdd( id, IQ_PROC_NONE, foo );
+
+ XmlNodeIq iq( "get", id, to );
+ XmlNode* query = iq.addQuery( ns );
+ XmlNode* item = query->addChild( "item" ); item->addAttr( var, varVal );
+ JabberSend( jabberThreadInfo->s, iq );
+}
+
+static void sttNickListHook( JABBER_LIST_ITEM* item, GCHOOK* gch )
+{
+ #if defined( _UNICODE )
+ TCHAR* pszUID = a2u( gch->pszUID );
+ #else
+ char* pszUID = gch->pszUID;
+ #endif
+
+ JABBER_RESOURCE_STATUS *me = NULL, *him = NULL;
+ for ( int i=0; i < item->resourceCount; i++ ) {
+ JABBER_RESOURCE_STATUS& p = item->resource[i];
+ if ( !lstrcmp( p.resourceName, item->nick )) me = &p;
+ if ( !lstrcmp( p.resourceName, pszUID )) him = &p;
+ }
+ #if defined( _UNICODE )
+ mir_free( pszUID );
+ #endif
+
+ if ( him == NULL || me == NULL )
+ return;
+
+ TCHAR szBuffer[ 1024 ];
+
+ switch( gch->dwData ) {
+ case IDM_LEAVE:
+ JabberGcQuit( item, 0, 0 );
+ break;
+
+ case IDM_KICK:
+ {
+ mir_sntprintf( szBuffer, SIZEOF(szBuffer), _T("%s %s"), TranslateT( "Reason to kick" ), him->resourceName );
+ if ( JabberEnterString( szBuffer, SIZEOF(szBuffer))) {
+ XmlNodeIq iq( "set", NOID, item->jid );
+ XmlNode* query = iq.addQuery( xmlnsAdmin );
+ XmlNode* item = query->addChild( "item" ); item->addAttr( "nick", him->resourceName ); item->addAttr( "role", "none" );
+ item->addChild( "reason", szBuffer );
+ JabberSend( jabberThreadInfo->s, iq );
+ }
+ break;
+ }
+
+ case IDM_BAN:
+ mir_sntprintf( szBuffer, SIZEOF(szBuffer), _T("%s %s"), TranslateT( "Reason to ban" ), him->resourceName );
+ if ( JabberEnterString( szBuffer, SIZEOF(szBuffer))) {
+ XmlNodeIq iq( "set", NOID, item->jid );
+ XmlNode* query = iq.addQuery( xmlnsAdmin );
+ XmlNode* item = query->addChild( "item" ); item->addAttr( "nick", him->resourceName ); item->addAttr( "affiliation", "outcast" );
+ item->addChild( "reason", szBuffer );
+ JabberSend( jabberThreadInfo->s, iq );
+ }
+ break;
+
+ case IDM_VOICE:
+ JabberAdminSet( item->jid, xmlnsAdmin, "nick", him->resourceName,
+ "role", ( him->role == ROLE_PARTICIPANT ) ? _T("visitor") : _T("participant"));
+ break;
+
+ case IDM_MODERATOR:
+ JabberAdminSet( item->jid, xmlnsAdmin, "nick", him->resourceName,
+ "role", ( him->role == ROLE_MODERATOR ) ? _T("participant") : _T("moderator"));
+ break;
+
+ case IDM_ADMIN:
+ JabberAdminSet( item->jid, xmlnsAdmin, "nick", him->resourceName,
+ "affiliation", ( him->affiliation==AFFILIATION_ADMIN )? _T("member") : _T("admin"));
+ break;
+
+ case IDM_OWNER:
+ JabberAdminSet( item->jid, xmlnsAdmin, "nick", him->resourceName,
+ "affiliation", ( him->affiliation==AFFILIATION_OWNER ) ? _T("admin") : _T("owner"));
+ break;
+} }
+
+static void sttLogListHook( JABBER_LIST_ITEM* item, GCHOOK* gch )
+{
+ TCHAR szBuffer[ 1024 ];
+ #if defined( _UNICODE )
+ TCHAR* pszID = a2u(gch->pDest->pszID);
+ #else
+ TCHAR* pszID = gch->pDest->pszID;
+ #endif
+
+ switch( gch->dwData ) {
+ case IDM_VOICE:
+ JabberAdminGet( pszID, xmlnsAdmin, "role", _T("participant"), JabberIqResultMucGetVoiceList );
+ break;
+
+ case IDM_MEMBER:
+ JabberAdminGet( pszID, xmlnsAdmin, "affiliation", _T("member"), JabberIqResultMucGetMemberList );
+ break;
+
+ case IDM_MODERATOR:
+ JabberAdminGet( pszID, xmlnsAdmin, "role", _T("moderator"), JabberIqResultMucGetModeratorList );
+ break;
+
+ case IDM_BAN:
+ JabberAdminGet( pszID, xmlnsAdmin, "affiliation", _T("outcast"), JabberIqResultMucGetBanList );
+ break;
+
+ case IDM_ADMIN:
+ JabberAdminGet( pszID, xmlnsOwner, "affiliation", _T("admin"), JabberIqResultMucGetAdminList );
+ break;
+
+ case IDM_OWNER:
+ JabberAdminGet( pszID, xmlnsOwner, "affiliation", _T("owner"), JabberIqResultMucGetOwnerList );
+ break;
+
+ case IDM_TOPIC:
+ mir_sntprintf( szBuffer, SIZEOF(szBuffer), _T("%s %s"), TranslateT( "Set topic for" ), pszID );
+ if ( JabberEnterString( szBuffer, SIZEOF(szBuffer))) {
+ XmlNode msg( "message" ); msg.addAttr( "to", pszID ); msg.addAttr( "type", "groupchat" );
+ msg.addChild( "subject", szBuffer );
+ JabberSend( jabberThreadInfo->s, msg );
+ }
+ break;
+
+ case IDM_NICK:
+ mir_sntprintf( szBuffer, SIZEOF(szBuffer), _T("%s %s"), TranslateT( "Change nickname in" ), pszID );
+ if ( JabberEnterString( szBuffer, SIZEOF(szBuffer))) {
+ JABBER_LIST_ITEM* item = JabberListGetItemPtr( LIST_CHATROOM, pszID );
+ if ( item != NULL ) {
+ TCHAR text[ 1024 ];
+ mir_sntprintf( text, SIZEOF( text ), _T("%s/%s"), pszID, szBuffer );
+ JabberSendPresenceTo( jabberStatus, text, NULL );
+ } }
+ break;
+
+ case IDM_INVITE:
+ CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_GROUPCHAT_INVITE ), NULL, JabberGcLogInviteDlgProc, ( LPARAM )gch->pDest->pszID );
+ break;
+
+ case IDM_CONFIG:
+ {
+ int iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_NONE, JabberIqResultGetMuc );
+
+ XmlNodeIq iq( "get", iqId, pszID );
+ XmlNode* query = iq.addQuery( xmlnsOwner );
+ JabberSend( jabberThreadInfo->s, iq );
+ break;
+ }
+ case IDM_DESTROY:
+ mir_sntprintf( szBuffer, SIZEOF(szBuffer), _T("%s %s"), TranslateT( "Reason to destroy" ), pszID );
+ if ( !JabberEnterString( szBuffer, SIZEOF(szBuffer)))
+ break;
+
+ { XmlNodeIq iq( "set", NOID, pszID );
+ XmlNode* query = iq.addQuery( xmlnsOwner );
+ query->addChild( "destroy" )->addChild( "reason", szBuffer );
+ JabberSend( jabberThreadInfo->s, iq );
+ }
+
+ case IDM_LEAVE:
+ JabberGcQuit( item, 0, 0 );
+ break;
+ }
+
+ #if defined( _UNICODE )
+ mir_free( pszID );
+ #endif
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Sends a private message to a chat user
+
+static void sttSendPrivateMessage( JABBER_LIST_ITEM* item, const TCHAR* nick )
+{
+ TCHAR szFullJid[ 256 ];
+ mir_sntprintf( szFullJid, SIZEOF(szFullJid), _T("%s/%s"), item->jid, nick );
+ HANDLE hContact = JabberDBCreateContact( szFullJid, NULL, TRUE, FALSE );
+ if ( hContact != NULL ) {
+ for ( int i=0; i < item->resourceCount; i++ ) {
+ if ( _tcsicmp( item->resource[i].resourceName, nick ) == 0 ) {
+ JSetWord( hContact, "Status", item->resource[i].status );
+ break;
+ } }
+
+ DBWriteContactSettingByte( hContact, "CList", "Hidden", 1 );
+ JSetStringT( hContact, "Nick", nick );
+ DBWriteContactSettingDword( hContact, "Ignore", "Mask1", 0 );
+ JCallService( MS_MSG_SENDMESSAGE, ( WPARAM )hContact, 0 );
+} }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// General chat event processing hook
+
+int JabberGcEventHook(WPARAM wParam,LPARAM lParam)
+{
+ GCHOOK* gch = ( GCHOOK* )lParam;
+ if ( gch == NULL )
+ return 0;
+
+ if ( lstrcmpiA( gch->pDest->pszModule, jabberProtoName ))
+ return 0;
+
+ #if defined( _UNICODE )
+ TCHAR* pszID = a2u(gch->pDest->pszID);
+ #else
+ TCHAR* pszID = gch->pDest->pszID;
+ #endif
+ JABBER_LIST_ITEM* item = JabberListGetItemPtr( LIST_CHATROOM, pszID );
+ #if defined( _UNICODE )
+ mir_free( pszID );
+ #endif
+ if ( item == NULL )
+ return 0;
+
+ switch ( gch->pDest->iType ) {
+ case GC_USER_MESSAGE:
+ if ( gch->pszText && lstrlenA( gch->pszText) > 0 ) {
+ rtrim( gch->pszText );
+
+ if ( jabberOnline ) {
+ XmlNode m( "message" ); m.addAttr( "to", item->jid ); m.addAttr( "type", "groupchat" );
+ XmlNode* b = m.addChild( "body", gch->pszText );
+ if ( b->sendText != NULL )
+ UnEscapeChatTags( b->sendText );
+ JabberSend( jabberThreadInfo->s, m );
+ } }
+ break;
+
+ case GC_USER_PRIVMESS:
+ #if defined( _UNICODE )
+ { TCHAR* id = a2u( gch->pszUID );
+ sttSendPrivateMessage( item, id );
+ mir_free( id );
+ }
+ #else
+ sttSendPrivateMessage( item, gch->pszUID );
+ #endif
+ break;
+
+ case GC_USER_LOGMENU:
+ sttLogListHook( item, gch );
+ break;
+
+ case GC_USER_NICKLISTMENU:
+ sttNickListHook( item, gch );
+ break;
+
+ case GC_USER_CHANMGR:
+ int iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_NONE, JabberIqResultGetMuc );
+
+ XmlNodeIq iq( "get", iqId, item->jid );
+ XmlNode* query = iq.addQuery( xmlnsOwner );
+ JabberSend( jabberThreadInfo->s, iq );
+ break;
+ }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+void JabberAddMucListItem( JABBER_MUC_JIDLIST_INFO* jidListInfo, TCHAR* str )
+{
+ const char* field = _tcschr(str,'@') ? "jid" : "nick";
+ TCHAR* roomJid = jidListInfo->roomJid;
+
+ switch (jidListInfo->type) {
+ case MUC_VOICELIST:
+ JabberAdminSet( roomJid, xmlnsAdmin, field, str, "role", _T("participant"));
+ JabberAdminGet( roomJid, xmlnsAdmin, "role", _T("participant"), JabberIqResultMucGetVoiceList);
+ break;
+ case MUC_MEMBERLIST:
+ JabberAdminSet( roomJid, xmlnsAdmin, field, str, "affiliation", _T("member"));
+ JabberAdminGet( roomJid, xmlnsAdmin, "affiliation", _T("member"), JabberIqResultMucGetMemberList);
+ break;
+ case MUC_MODERATORLIST:
+ JabberAdminSet( roomJid, xmlnsAdmin, field, str, "role", _T("moderator"));
+ JabberAdminGet( roomJid, xmlnsAdmin, "role", _T("moderator"), JabberIqResultMucGetModeratorList);
+ break;
+ case MUC_BANLIST:
+ JabberAdminSet( roomJid, xmlnsAdmin, field, str, "affiliation", _T("outcast"));
+ JabberAdminGet( roomJid, xmlnsAdmin, "affiliation", _T("outcast"), JabberIqResultMucGetBanList);
+ break;
+ case MUC_ADMINLIST:
+ JabberAdminSet( roomJid, xmlnsOwner, field, str, "affiliation", _T("admin"));
+ JabberAdminGet( roomJid, xmlnsOwner, "affiliation", _T("admin"), JabberIqResultMucGetAdminList);
+ break;
+ case MUC_OWNERLIST:
+ JabberAdminSet( roomJid, xmlnsOwner, field, str, "affiliation", _T("owner"));
+ JabberAdminGet( roomJid, xmlnsOwner, "affiliation", _T("owner"), JabberIqResultMucGetOwnerList);
+ break;
+} }
+
+void JabberDeleteMucListItem( JABBER_MUC_JIDLIST_INFO* jidListInfo, TCHAR* jid )
+{
+ TCHAR* roomJid = jidListInfo->roomJid;
+
+ switch ( jidListInfo->type ) {
+ case MUC_VOICELIST: // change role to visitor ( from participant )
+ JabberAdminSet( roomJid, xmlnsAdmin, "jid", jid, "role", _T("visitor"));
+ break;
+ case MUC_BANLIST: // change affiliation to none ( from outcast )
+ case MUC_MEMBERLIST: // change affiliation to none ( from member )
+ JabberAdminSet( roomJid, xmlnsAdmin, "jid", jid, "affiliation", _T("none"));
+ break;
+ case MUC_MODERATORLIST: // change role to participant ( from moderator )
+ JabberAdminSet( roomJid, xmlnsAdmin, "jid", jid, "role", _T("participant"));
+ break;
+ case MUC_ADMINLIST: // change affiliation to member ( from admin )
+ JabberAdminSet( roomJid, xmlnsOwner, "jid", jid, "affiliation", _T("member"));
+ break;
+ case MUC_OWNERLIST: // change affiliation to admin ( from owner )
+ JabberAdminSet( roomJid, xmlnsOwner, "jid", jid, "affiliation", _T("admin"));
+ break;
+} }
diff --git a/miranda-wine/protocols/JabberG/jabber_file.cpp b/miranda-wine/protocols/JabberG/jabber_file.cpp new file mode 100644 index 0000000..56eafd7 --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_file.cpp @@ -0,0 +1,611 @@ +/*
+
+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_file.cpp,v $
+Revision : $Revision: 2961 $
+Last change on : $Date: 2006-05-26 23:39:41 +0400 (Птн, 26 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+#include <io.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+static char* fileBaseName;
+static char* filePathName;
+
+static int JabberFileReceiveParse( filetransfer* ft, char* buffer, int datalen );
+static void JabberFileServerConnection( HANDLE hNewConnection, DWORD dwRemoteIP );
+static int JabberFileSendParse( JABBER_SOCKET s, filetransfer* ft, char* buffer, int datalen );
+
+#define JABBER_NETWORK_BUFFER_SIZE 2048
+
+void __cdecl JabberFileReceiveThread( filetransfer* ft )
+{
+ char* buffer;
+ int datalen;
+ JABBER_SOCKET s;
+
+ JabberLog( "Thread started: type=file_receive server='%s' port='%d'", ft->httpHostName, ft->httpPort );
+
+ ft->type = FT_OOB;
+
+ if (( buffer=( char* )mir_alloc( JABBER_NETWORK_BUFFER_SIZE )) == NULL ) {
+ JabberLog( "Cannot allocate network buffer, thread ended" );
+ JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0 );
+ delete ft;
+ return;
+ }
+
+ NETLIBOPENCONNECTION nloc = { 0 };
+ nloc.cbSize = sizeof( nloc );
+ nloc.cbSize = sizeof( NETLIBOPENCONNECTION );
+ nloc.szHost = ft->httpHostName;
+ nloc.wPort = ft->httpPort;
+ s = ( HANDLE ) JCallService( MS_NETLIB_OPENCONNECTION, ( WPARAM ) hNetlibUser, ( LPARAM )&nloc );
+ if ( s == NULL ) {
+ JabberLog( "Connection failed ( %d ), thread ended", WSAGetLastError());
+ JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0 );
+ mir_free( buffer );
+ delete ft;
+ return;
+ }
+
+ ft->s = s;
+
+ JabberSend( s, "GET /%s HTTP/1.1\r\nHost: %s\r\n\r\n", ft->httpPath, ft->httpHostName );
+ ft->state = FT_CONNECTING;
+
+ JabberLog( "Entering file_receive recv loop" );
+ datalen = 0;
+
+ while ( ft->state != FT_DONE && ft->state != FT_ERROR ) {
+ int recvResult, bytesParsed;
+
+ JabberLog( "Waiting for data..." );
+ recvResult = Netlib_Recv( s, buffer+datalen, JABBER_NETWORK_BUFFER_SIZE-datalen, 0 );
+ if ( recvResult <= 0 )
+ break;
+ datalen += recvResult;
+
+ bytesParsed = JabberFileReceiveParse( ft, buffer, datalen );
+ if ( bytesParsed < datalen )
+ memmove( buffer, buffer+bytesParsed, datalen-bytesParsed );
+ datalen -= bytesParsed;
+ }
+
+ if ( ft->s )
+ Netlib_CloseHandle( s );
+ ft->s = NULL;
+
+ if ( ft->state==FT_RECEIVING || ft->state==FT_DONE )
+ _close( ft->fileId );
+
+ if ( ft->state==FT_DONE || ( ft->state==FT_RECEIVING && ft->std.currentFileSize < 0 ))
+ JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ft, 0 );
+ else
+ JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0 );
+
+ JabberLog( "Thread ended: type=file_receive server='%s'", ft->httpHostName );
+
+ mir_free( buffer );
+ delete ft;
+}
+
+static int JabberFileReceiveParse( filetransfer* ft, char* buffer, int datalen )
+{
+ char* p, *q, *s, *eob;
+ char* str;
+ int num, code;
+
+ eob = buffer + datalen;
+ p = buffer;
+ num = 0;
+ for ( ;; ) {
+ if ( ft->state==FT_CONNECTING || ft->state==FT_INITIALIZING ) {
+ for ( q=p; q+1<eob && ( *q!='\r' || *( q+1 )!='\n' ); q++ );
+ if ( q+1 < eob ) {
+ if (( str=( char* )mir_alloc( q-p+1 )) != NULL ) {
+ strncpy( str, p, q-p );
+ str[q-p] = '\0';
+ JabberLog( "FT Got: %s", str );
+ if ( ft->state == FT_CONNECTING ) {
+ // looking for "HTTP/1.1 200 OK"
+ if ( sscanf( str, "HTTP/%*d.%*d %d %*s", &code )==1 && code==200 ) {
+ ft->state = FT_INITIALIZING;
+ ft->std.currentFileSize = -1;
+ JabberLog( "Change to FT_INITIALIZING" );
+ JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_INITIALISING, ft, 0 );
+ }
+ }
+ else { // FT_INITIALIZING
+ if ( str[0] == '\0' ) {
+ if (( s=strrchr( ft->httpPath, '/' )) != NULL )
+ s++;
+ else
+ s = ft->httpPath;
+ ft->std.currentFile = mir_strdup( s );
+ JabberHttpUrlDecode( ft->std.currentFile );
+ if ( ft->create() == -1 ) {
+ ft->state = FT_ERROR;
+ break;
+ }
+ ft->state = FT_RECEIVING;
+ ft->std.currentFileSize = 0;
+ JabberLog( "Change to FT_RECEIVING" );
+ }
+ else if (( s=strchr( str, ':' )) != NULL ) {
+ *s = '\0';
+ if ( !strcmp( str, "Content-Length" ))
+ ft->std.totalBytes = strtol( s+1, NULL, 10 );
+ } }
+
+ mir_free( str );
+ q += 2;
+ num += ( q-p );
+ p = q;
+ }
+ else {
+ ft->state = FT_ERROR;
+ break;
+ }
+ }
+ else {
+ break;
+ }
+ }
+ else if ( ft->state == FT_RECEIVING ) {
+ int bufferSize, remainingBytes, writeSize;
+
+ if ( ft->std.currentFileSize < 0 || ft->std.currentFileProgress < ft->std.currentFileSize ) {
+ bufferSize = eob - p;
+ remainingBytes = ft->std.currentFileSize - ft->std.currentFileProgress;
+ if ( remainingBytes < bufferSize )
+ writeSize = remainingBytes;
+ else
+ writeSize = bufferSize;
+ if ( _write( ft->fileId, p, writeSize ) != writeSize ) {
+ JabberLog( "_write() error" );
+ ft->state = FT_ERROR;
+ }
+ else {
+ ft->std.currentFileProgress += writeSize;
+ ft->std.totalProgress += writeSize;
+ JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, ( LPARAM )&ft->std );
+ if ( ft->std.currentFileProgress == ft->std.currentFileSize )
+ ft->state = FT_DONE;
+ }
+ }
+ num = datalen;
+ break;
+ }
+ else {
+ break;
+ }
+ }
+
+ return num;
+}
+
+void __cdecl JabberFileServerThread( filetransfer* ft )
+{
+ NETLIBBIND nlb = {0};
+ JABBER_SOCKET s;
+ int i;
+ JABBER_LIST_ITEM *item;
+ struct in_addr in;
+ HANDLE hEvent;
+ TCHAR *p, *resource;
+ char *myAddr;
+ char *pFileName;
+ DBVARIANT dbv;
+ TCHAR szPort[20];
+ int id;
+
+ JabberLog( "Thread started: type=file_send" );
+
+ ft->type = FT_OOB;
+
+ nlb.cbSize = sizeof( NETLIBBIND );
+ nlb.pfnNewConnection = JabberFileServerConnection;
+ nlb.wPort = 0; // Use user-specified incoming port ranges, if available
+ s = ( HANDLE ) JCallService( MS_NETLIB_BINDPORT, ( WPARAM ) hNetlibUser, ( LPARAM )&nlb );
+ if ( s == NULL ) {
+ JabberLog( "Cannot allocate port to bind for file server thread, thread ended." );
+ JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0 );
+ delete ft;
+ return;
+ }
+
+ ft->s = s;
+ JabberLog( "ft->s = %d", s );
+
+ hEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+ ft->hFileEvent = hEvent;
+
+ mir_sntprintf( szPort, SIZEOF( szPort ), _T("%d"), nlb.wPort );
+ item = JabberListAdd( LIST_FILE, szPort );
+ item->ft = ft;
+
+ if (( p=JabberListGetBestClientResourceNamePtr( ft->jid )) == NULL )
+ resource = NULL;
+ else
+ resource = mir_tstrdup( p );
+
+ if ( resource != NULL ) {
+ ft->state = FT_CONNECTING;
+ for ( i=0; i < ft->std.totalFiles && ft->state!=FT_ERROR && ft->state!=FT_DENIED; i++ ) {
+ ft->std.currentFileNumber = i;
+ ft->state = FT_CONNECTING;
+ if ( ft->httpPath ) mir_free( ft->httpPath );
+ ft->httpPath = NULL;
+
+ char* p;
+ if (( p=strrchr( ft->std.files[i], '\\' )) != NULL )
+ p++;
+ else
+ p = ft->std.files[i];
+ in.S_un.S_addr = jabberLocalIP;
+ if (( pFileName=JabberHttpUrlEncode( p )) != NULL ) {
+ id = JabberSerialNext();
+ if ( ft->iqId ) mir_free( ft->iqId );
+ ft->iqId = ( TCHAR* )mir_alloc( sizeof(TCHAR)*( strlen( JABBER_IQID )+20 ));
+ wsprintf( ft->iqId, _T(JABBER_IQID)_T("%d"), id );
+
+ if ( JGetByte( "BsDirect", TRUE ) && JGetByte( "BsDirectManual", FALSE )) {
+ if ( !DBGetContactSetting( NULL, jabberProtoName, "BsDirectAddr", &dbv )) {
+ myAddr = NEWSTR_ALLOCA( dbv.pszVal );
+ JFreeVariant( &dbv );
+ }
+ else myAddr = inet_ntoa( in );
+ }
+ else myAddr = inet_ntoa( in );
+
+ char szAddr[ 256 ];
+ mir_snprintf( szAddr, sizeof(szAddr), "http://%s:%d/%s", myAddr, nlb.wPort, pFileName );
+
+ XmlNodeIq iq( "set", id, ft->jid );
+ XmlNode* query = iq.addQuery( "jabber:iq:oob" );
+ query->addChild( "url", szAddr );
+ query->addChild( "desc", ft->szDescription );
+ JabberSend( jabberThreadInfo->s, iq );
+
+ JabberLog( "Waiting for the file to be sent..." );
+ WaitForSingleObject( hEvent, INFINITE );
+ mir_free( pFileName );
+ }
+ JabberLog( "File sent, advancing to the next file..." );
+ JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ft, 0 );
+ }
+ CloseHandle( hEvent );
+ ft->hFileEvent = NULL;
+ JabberLog( "Finish all files" );
+
+ Netlib_CloseHandle( s );
+
+ mir_free( resource );
+ }
+
+ ft->s = NULL;
+ JabberLog( "ft->s is NULL" );
+
+ JabberListRemove( LIST_FILE, szPort );
+
+ switch ( ft->state ) {
+ case FT_DONE:
+ JabberLog( "Finish successfully" );
+ JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ft, 0 );
+ break;
+ case FT_DENIED:
+ JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DENIED, ft, 0 );
+ break;
+ default: // FT_ERROR:
+ JabberLog( "Finish with errors" );
+ JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0 );
+ break;
+ }
+
+ JabberLog( "Thread ended: type=file_send" );
+
+ delete ft;
+}
+
+static void JabberFileServerConnection( JABBER_SOCKET hConnection, DWORD dwRemoteIP )
+{
+ SOCKET s;
+ JABBER_SOCKET slisten;
+ SOCKADDR_IN saddr;
+ int len;
+ WORD localPort;
+ JABBER_LIST_ITEM *item;
+ char* buffer;
+ int datalen;
+ filetransfer* ft;
+ TCHAR szPort[20];
+
+ localPort = 0;
+ if (( s=JCallService( MS_NETLIB_GETSOCKET, ( WPARAM ) hConnection, 0 )) != INVALID_SOCKET ) {
+ len = sizeof( saddr );
+ if ( getsockname( s, ( SOCKADDR * ) &saddr, &len ) != SOCKET_ERROR ) {
+ localPort = ntohs( saddr.sin_port );
+ }
+ }
+ if ( localPort == 0 ) {
+ JabberLog( "Unable to determine the local port, file server connection closed." );
+ Netlib_CloseHandle( hConnection );
+ return;
+ }
+
+ mir_sntprintf( szPort, sizeof( szPort ), _T("%d"), localPort );
+ JabberLog( "File server incoming connection accepted: local_port=" TCHAR_STR_PARAM, szPort );
+
+ if (( item=JabberListGetItemPtr( LIST_FILE, szPort )) == NULL ) {
+ JabberLog( "No file is currently served, file server connection closed." );
+ Netlib_CloseHandle( hConnection );
+ return;
+ }
+
+ ft = item->ft;
+ slisten = ft->s;
+ ft->s = hConnection;
+ JabberLog( "Set ft->s to %d ( saving %d )", hConnection, slisten );
+
+ if (( buffer=( char* )mir_alloc( JABBER_NETWORK_BUFFER_SIZE+1 )) == NULL ) {
+ JabberLog( "Cannot allocate network buffer, file server connection closed." );
+ Netlib_CloseHandle( hConnection );
+ ft->state = FT_ERROR;
+ if ( ft->hFileEvent != NULL )
+ SetEvent( ft->hFileEvent );
+ return;
+ }
+ JabberLog( "Entering recv loop for this file connection... ( ft->s is hConnection )" );
+ datalen = 0;
+ while ( ft->state!=FT_DONE && ft->state!=FT_ERROR ) {
+ int recvResult, bytesParsed;
+
+ //recvResult = JabberWsRecv( hConnection, buffer+datalen, JABBER_NETWORK_BUFFER_SIZE-datalen );
+ recvResult = Netlib_Recv( hConnection, buffer+datalen, JABBER_NETWORK_BUFFER_SIZE-datalen, 0 );
+ if ( recvResult <= 0 )
+ break;
+ datalen += recvResult;
+
+ buffer[datalen] = '\0';
+ JabberLog( "RECV:%s", buffer );
+
+ bytesParsed = JabberFileSendParse( hConnection, ft, buffer, datalen );
+ if ( bytesParsed < datalen )
+ memmove( buffer, buffer+bytesParsed, datalen-bytesParsed );
+ datalen -= bytesParsed;
+ }
+
+ JabberLog( "Closing connection for this file transfer... ( ft->s is now hBind )" );
+ Netlib_CloseHandle( hConnection );
+ ft->s = slisten;
+ JabberLog( "ft->s is restored to %d", ft->s );
+ if ( ft->hFileEvent != NULL )
+ SetEvent( ft->hFileEvent );
+ mir_free( buffer );
+}
+
+static int JabberFileSendParse( JABBER_SOCKET s, filetransfer* ft, char* buffer, int datalen )
+{
+ char* p, *q, *t, *eob;
+ char* str;
+ int num;
+ int currentFile;
+ int fileId;
+ int numRead;
+
+ eob = buffer + datalen;
+ p = buffer;
+ num = 0;
+ while ( ft->state==FT_CONNECTING || ft->state==FT_INITIALIZING ) {
+ for ( q=p; q+1<eob && ( *q!='\r' || *( q+1 )!='\n' ); q++ );
+ if ( q+1 >= eob )
+ break;
+ if (( str=( char* )mir_alloc( q-p+1 )) == NULL ) {
+ ft->state = FT_ERROR;
+ break;
+ }
+ strncpy( str, p, q-p );
+ str[q-p] = '\0';
+ JabberLog( "FT Got: %s", str );
+ if ( ft->state == FT_CONNECTING ) {
+ // looking for "GET filename.ext HTTP/1.1"
+ if ( !strncmp( str, "GET ", 4 )) {
+ for ( t=str+4; *t!='\0' && *t!=' '; t++ );
+ *t = '\0';
+ for ( t=str+4; *t!='\0' && *t=='/'; t++ );
+ ft->httpPath = mir_strdup( t );
+ JabberHttpUrlDecode( ft->httpPath );
+ ft->state = FT_INITIALIZING;
+ JabberLog( "Change to FT_INITIALIZING" );
+ }
+ }
+ else { // FT_INITIALIZING
+ if ( str[0] == '\0' ) {
+ struct _stat statbuf;
+
+ mir_free( str );
+ num += 2;
+
+ currentFile = ft->std.currentFileNumber;
+ if (( t=strrchr( ft->std.files[ currentFile ], '\\' )) != NULL )
+ t++;
+ else
+ t = ft->std.files[currentFile];
+ if ( ft->httpPath==NULL || strcmp( ft->httpPath, t )) {
+ if ( ft->httpPath == NULL )
+ JabberLog( "Requested file name does not matched ( httpPath==NULL )" );
+ else
+ JabberLog( "Requested file name does not matched ( '%s' vs. '%s' )", ft->httpPath, t );
+ ft->state = FT_ERROR;
+ break;
+ }
+ JabberLog( "Sending [%s]", ft->std.files[ currentFile ] );
+ _stat( ft->std.files[ currentFile ], &statbuf ); // file size in statbuf.st_size
+ if (( fileId=_open( ft->std.files[currentFile], _O_BINARY|_O_RDONLY )) < 0 ) {
+ JabberLog( "File cannot be opened" );
+ ft->state = FT_ERROR;
+ mir_free( ft->httpPath );
+ ft->httpPath = NULL;
+ break;
+ }
+ JabberSend( s, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n\r\n", statbuf.st_size );
+
+ ft->std.sending = TRUE;
+ ft->std.currentFileProgress = 0;
+ JabberLog( "Sending file data..." );
+
+ char fileBuffer[ 2048 ];
+ while (( numRead = _read( fileId, fileBuffer, 2048 )) > 0 ) {
+ if ( Netlib_Send( s, fileBuffer, numRead, 0 ) != numRead ) {
+ ft->state = FT_ERROR;
+ break;
+ }
+ ft->std.currentFileProgress += numRead;
+ ft->std.totalProgress += numRead;
+ JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, ( LPARAM )&ft->std );
+ }
+ _close( fileId );
+ if ( ft->state != FT_ERROR )
+ ft->state = FT_DONE;
+ JabberLog( "Finishing this file..." );
+ mir_free( ft->httpPath );
+ ft->httpPath = NULL;
+ break;
+ } }
+
+ mir_free( str );
+ q += 2;
+ num += ( q-p );
+ p = q;
+ }
+
+ return num;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// filetransfer class members
+
+filetransfer::filetransfer()
+{
+ memset( this, 0, sizeof( filetransfer ));
+ fileId = -1;
+ std.cbSize = sizeof( std );
+}
+
+filetransfer::~filetransfer()
+{
+ JabberLog( "Destroying file transfer session %08p", this );
+
+ if ( !bCompleted )
+ JSendBroadcast( std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, this, 0 );
+
+ close();
+
+ if ( hWaitEvent != INVALID_HANDLE_VALUE )
+ CloseHandle( hWaitEvent );
+
+ if ( jid ) mir_free( jid );
+ if ( sid ) mir_free( sid );
+ if ( iqId ) mir_free( iqId );
+ if ( fileSize ) mir_free( fileSize );
+ if ( httpHostName ) mir_free( httpHostName );
+ if ( httpPath ) mir_free( httpPath );
+ if ( szDescription ) mir_free( szDescription );
+
+ if ( std.workingDir ) mir_free( std.workingDir );
+ if ( std.currentFile ) mir_free( std.currentFile );
+
+ if ( std.files ) {
+ for ( int i=0; i < std.totalFiles; i++ )
+ if ( std.files[i] ) mir_free( std.files[i] );
+
+ mir_free( std.files );
+} }
+
+void filetransfer::close()
+{
+ if ( fileId != -1 ) {
+ _close( fileId );
+ fileId = -1;
+} }
+
+void filetransfer::complete()
+{
+ close();
+
+ bCompleted = true;
+ JSendBroadcast( std.hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, this, 0);
+}
+
+int filetransfer::create()
+{
+ if ( fileId != -1 )
+ return fileId;
+
+ char filefull[ MAX_PATH ];
+ mir_snprintf( filefull, sizeof filefull, "%s\\%s", std.workingDir, std.currentFile );
+ replaceStr( std.currentFile, filefull );
+
+ if ( hWaitEvent != INVALID_HANDLE_VALUE )
+ CloseHandle( hWaitEvent );
+ hWaitEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+
+ if ( JSendBroadcast( std.hContact, ACKTYPE_FILE, ACKRESULT_FILERESUME, this, ( LPARAM )&std ))
+ WaitForSingleObject( hWaitEvent, INFINITE );
+
+ if ( IsWinVerNT() && wszFileName != NULL ) {
+ WCHAR wszTemp[ MAX_PATH ];
+ _snwprintf( wszTemp, sizeof wszTemp, L"%S\\%s", std.workingDir, wszFileName );
+ wszTemp[ MAX_PATH-1 ] = 0;
+ fileId = _wopen( wszTemp, _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY, _S_IREAD | _S_IWRITE);
+ if ( fileId != -1 ) {
+ WIN32_FIND_DATAW data;
+ HANDLE hFind = FindFirstFileW( wszFileName, &data );
+ if ( hFind != INVALID_HANDLE_VALUE ) {
+ mir_free( std.currentFile );
+
+ char tShortName[ 20 ];
+ WideCharToMultiByte( CP_ACP, 0,
+ ( data.cAlternateFileName[0] != 0 ) ? data.cAlternateFileName : data.cFileName,
+ -1, tShortName, sizeof tShortName, 0, 0 );
+ mir_snprintf( filefull, sizeof( filefull ), "%s\\%s", std.workingDir, tShortName );
+ std.currentFile = mir_strdup( filefull );
+ JabberLog( "Saving to [%s]", std.currentFile );
+ FindClose( hFind );
+ } } }
+
+ if ( fileId == -1 ) {
+ JabberLog( "Saving to [%s]", std.currentFile );
+ fileId = _open( std.currentFile, _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY, _S_IREAD | _S_IWRITE );
+ }
+
+ if ( fileId == -1 )
+ JabberLog( "Cannot create file '%s' during a file transfer", filefull );
+ else if ( std.currentFileSize != 0 )
+ _chsize( fileId, std.currentFileSize );
+
+ return fileId;
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_form.cpp b/miranda-wine/protocols/JabberG/jabber_form.cpp new file mode 100644 index 0000000..a676e7c --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_form.cpp @@ -0,0 +1,479 @@ +/*
+
+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_form.cpp,v $
+Revision : $Revision: 2961 $
+Last change on : $Date: 2006-05-26 23:39:41 +0400 (Птн, 26 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+#include "resource.h"
+
+static BOOL CALLBACK JabberFormMultiLineWndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ switch ( msg ) {
+ //case WM_GETDLGCODE:
+ // return DLGC_WANTARROWS|DLGC_WANTCHARS|DLGC_HASSETSEL|DLGC_WANTALLKEYS;
+ case WM_KEYDOWN:
+ if ( wParam == VK_TAB ) {
+ SetFocus( GetNextDlgTabItem( GetParent( GetParent( hwnd )), hwnd, GetKeyState( VK_SHIFT )<0?TRUE:FALSE ));
+ return TRUE;
+ };
+ break;
+ }
+ return CallWindowProc(( WNDPROC ) GetWindowLong( hwnd, GWL_USERDATA ), hwnd, msg, wParam, lParam );
+}
+
+void JabberFormCreateUI( HWND hwndStatic, XmlNode *xNode, int *formHeight )
+{
+ HWND hFrame, hCtrl;
+ HFONT hFont;
+ XmlNode *n, *v, *o, *vs;
+ int id, i, j, k, ypos, index, size;
+ TCHAR* label, *type, *labelStr, *valueStr, *varStr, *str, *p, *valueText;
+ int labelOffset, labelWidth, labelHeight;
+ int ctrlOffset, ctrlWidth;
+ RECT frameRect, strRect;
+
+ if ( xNode==NULL || xNode->name==NULL || strcmp( xNode->name, "x" ) || hwndStatic==NULL ) return;
+ hFrame = hwndStatic;
+ hFont = ( HFONT ) SendMessage( hFrame, WM_GETFONT, 0, 0 );
+
+ GetClientRect( hwndStatic, &frameRect );
+ labelOffset = 10;
+ labelWidth = ( frameRect.right - frameRect.left )/2 - 20 - 20;
+ ctrlOffset = labelWidth + 20;
+ ctrlWidth = frameRect.right - frameRect.left - labelWidth - 20 - 20;
+
+ id = 0;
+ ypos = 14;
+ for ( i=0; i<xNode->numChild; i++ ) {
+ n = xNode->child[i];
+ if ( n->name ) {
+ if ( !strcmp( n->name, "field" )) {
+ if (( varStr=JabberXmlGetAttrValue( n, "var" )) != NULL &&
+ ( type=JabberXmlGetAttrValue( n, "type" )) != NULL ) {
+
+ if (( label=JabberXmlGetAttrValue( n, "label" )) != NULL )
+ labelStr = mir_tstrdup( label );
+ else
+ labelStr = mir_tstrdup( varStr );
+ strRect.top = strRect.left = 0; strRect.right = labelWidth; strRect.bottom = 1;
+ labelHeight = DrawText( GetDC( hFrame ), labelStr, -1, &strRect, DT_CALCRECT|DT_RIGHT|DT_WORDBREAK );
+ //labelHeight = labelHeight * 6 / 7;
+ if ( labelHeight < 18 ) labelHeight = 18;
+
+ if (( v=JabberXmlGetChild( n, "value" )) != NULL ) {
+ valueStr = mir_tstrdup( v->text );
+ valueText = v->text;
+ }
+ else valueStr = valueText = NULL;
+
+ if ( !_tcscmp( type, _T("text-private"))) {
+ if ( labelStr ) {
+ hCtrl = CreateWindow( _T("static"), labelStr, WS_CHILD|WS_VISIBLE|SS_RIGHT, labelOffset, ypos+4, labelWidth, labelHeight, hFrame, ( HMENU ) IDC_STATIC, hInst, NULL );
+ SendMessage( hCtrl, WM_SETFONT, ( WPARAM ) hFont, 0 );
+ }
+ hCtrl = CreateWindowEx( WS_EX_CLIENTEDGE, _T("edit"), valueStr, WS_CHILD|WS_VISIBLE|WS_BORDER|WS_TABSTOP|ES_LEFT|ES_AUTOHSCROLL|ES_PASSWORD, ctrlOffset, ypos, ctrlWidth, 24, hFrame, ( HMENU ) id, hInst, NULL );
+ SendMessage( hCtrl, WM_SETFONT, ( WPARAM ) hFont, 0 );
+ id++;
+ ypos += (( labelHeight>24 )?labelHeight:24 );
+ }
+ else if ( !_tcscmp( type, _T("text-multi")) || !_tcscmp( type, _T("jid-multi"))) {
+ WNDPROC oldWndProc;
+
+ if ( labelStr ) {
+ hCtrl = CreateWindow( _T("static"), labelStr, WS_CHILD|WS_VISIBLE|SS_RIGHT, labelOffset, ypos+4, labelWidth, labelHeight, hFrame, ( HMENU ) IDC_STATIC, hInst, NULL );
+ SendMessage( hCtrl, WM_SETFONT, ( WPARAM ) hFont, 0 );
+ }
+ size = 1;
+ for ( j=0; j<n->numChild; j++ ) {
+ v = n->child[j];
+ if ( v->name && !strcmp( v->name, "value" ) && v->text )
+ size += _tcslen( v->text ) + 2;
+ }
+ str = ( TCHAR* )mir_alloc( sizeof(TCHAR)*size );
+ str[0] = '\0';
+ for ( j=0; j<n->numChild; j++ ) {
+ v = n->child[j];
+ if ( v->name && !strcmp( v->name, "value" ) && v->text ) {
+ if ( str[0] ) _tcscat( str, _T("\r\n"));
+ _tcscat( str, v->text );
+ } }
+
+ hCtrl = CreateWindowEx( WS_EX_CLIENTEDGE, _T("edit"), str, WS_CHILD|WS_VISIBLE|WS_BORDER|WS_TABSTOP|WS_VSCROLL|ES_LEFT|ES_MULTILINE|ES_AUTOVSCROLL|ES_WANTRETURN, ctrlOffset, ypos, ctrlWidth, 24*3, hFrame, ( HMENU ) id, hInst, NULL );
+ SendMessage( hCtrl, WM_SETFONT, ( WPARAM ) hFont, 0 );
+ oldWndProc = ( WNDPROC ) SetWindowLong( hCtrl, GWL_WNDPROC, ( LPARAM )JabberFormMultiLineWndProc );
+ SetWindowLong( hCtrl, GWL_USERDATA, ( LONG ) oldWndProc );
+ id++;
+ ypos += (( labelHeight>24*3 )?labelHeight:24*3 );
+ mir_free( str );
+ }
+ else if ( !_tcscmp( type, _T("boolean"))) {
+ strRect.top = strRect.left = 0;
+ strRect.right = ctrlWidth-20; strRect.bottom = 1;
+ labelHeight = DrawText( GetDC( hFrame ), labelStr, -1, &strRect, DT_CALCRECT|DT_WORDBREAK );
+ if ( labelHeight < 24 ) labelHeight = 24;
+ hCtrl = CreateWindowEx( 0, _T("button"), labelStr, WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_AUTOCHECKBOX|BS_MULTILINE, ctrlOffset, ypos, ctrlWidth, ( labelHeight>24 )?labelHeight:24, hFrame, ( HMENU ) id, hInst, NULL );
+ SendMessage( hCtrl, WM_SETFONT, ( WPARAM ) hFont, 0 );
+ if ( valueStr && !_tcscmp( valueStr, _T("1")))
+ SendMessage( hCtrl, BM_SETCHECK, 1, 0 );
+ id++;
+ ypos += (( labelHeight>24 )?labelHeight:24 );
+ }
+ else if ( !_tcscmp( type, _T("list-single"))) {
+ if ( labelStr ) {
+ hCtrl = CreateWindow( _T("static"), labelStr, WS_CHILD|WS_VISIBLE|SS_RIGHT, labelOffset, ypos+4, labelWidth, labelHeight, hFrame, ( HMENU ) IDC_STATIC, hInst, NULL );
+ SendMessage( hCtrl, WM_SETFONT, ( WPARAM ) hFont, 0 );
+ }
+ hCtrl = CreateWindowExA( WS_EX_CLIENTEDGE, "combobox", NULL, WS_CHILD|WS_VISIBLE|WS_BORDER|WS_TABSTOP|CBS_DROPDOWNLIST, ctrlOffset, ypos, ctrlWidth, 24*4, hFrame, ( HMENU ) id, hInst, NULL );
+ SendMessage( hCtrl, WM_SETFONT, ( WPARAM ) hFont, 0 );
+ for ( j=0; j<n->numChild; j++ ) {
+ o = n->child[j];
+ if ( o->name && !strcmp( o->name, "option" )) {
+ if (( v=JabberXmlGetChild( o, "value" ))!=NULL && v->text ) {
+ if (( str=JabberXmlGetAttrValue( o, "label" )) == NULL )
+ str = v->text;
+ if (( p = mir_tstrdup( str )) != NULL ) {
+ index = SendMessage( hCtrl, CB_ADDSTRING, 0, ( LPARAM )p );
+ mir_free( p );
+ if ( valueText!=NULL && !_tcscmp( valueText, v->text )) {
+ SendMessage( hCtrl, CB_SETCURSEL, index, 0 );
+ } } } } }
+ id++;
+ ypos += (( labelHeight>24 )?labelHeight:24 );
+ }
+ else if ( !_tcscmp( type, _T("list-multi"))) {
+ if ( labelStr ) {
+ hCtrl = CreateWindow( _T("static"), labelStr, WS_CHILD|WS_VISIBLE|SS_RIGHT, labelOffset, ypos+4, labelWidth, labelHeight, hFrame, ( HMENU ) IDC_STATIC, hInst, NULL );
+ SendMessage( hCtrl, WM_SETFONT, ( WPARAM ) hFont, 0 );
+ }
+ hCtrl = CreateWindowExA( WS_EX_CLIENTEDGE, "listbox", NULL, WS_CHILD|WS_VISIBLE|WS_BORDER|WS_TABSTOP|LBS_MULTIPLESEL, ctrlOffset, ypos, ctrlWidth, 24*3, hFrame, ( HMENU ) id, hInst, NULL );
+ SendMessage( hCtrl, WM_SETFONT, ( WPARAM ) hFont, 0 );
+ for ( j=0; j<n->numChild; j++ ) {
+ o = n->child[j];
+ if ( o->name && !strcmp( o->name, "option" )) {
+ if (( v = JabberXmlGetChild( o, "value" ))!=NULL && v->text ) {
+ if (( str=JabberXmlGetAttrValue( o, "label" )) == NULL )
+ str = v->text;
+ if (( p = mir_tstrdup( str )) != NULL ) {
+ index = SendMessage( hCtrl, LB_ADDSTRING, 0, ( LPARAM )p );
+ mir_free( p );
+ for ( k=0; k<n->numChild; k++ ) {
+ vs = n->child[k];
+ if ( vs->name && !strcmp( vs->name, "value" ) && vs->text && !_tcscmp( vs->text, v->text ))
+ SendMessage( hCtrl, LB_SETSEL, TRUE, index );
+ } } } } }
+ id++;
+ ypos += (( labelHeight>24*3 )?labelHeight:24*3 );
+ }
+ else if ( !_tcscmp( type, _T("fixed"))) {
+ if ( valueStr ) {
+ strRect.top = strRect.left = 0;
+ strRect.right = ctrlWidth; strRect.bottom = 1;
+ labelHeight = DrawText( GetDC( hFrame ), labelStr, -1, &strRect, DT_CALCRECT|DT_WORDBREAK );
+ labelHeight = labelHeight * 6 / 7;
+ if ( labelHeight < 24 ) labelHeight = 24;
+ hCtrl = CreateWindow( _T("static"), valueStr, WS_CHILD|WS_VISIBLE|SS_RIGHT, labelOffset, ypos+4, labelWidth+ctrlWidth, labelHeight, hFrame, ( HMENU ) IDC_STATIC, hInst, NULL );
+ SendMessage( hCtrl, WM_SETFONT, ( WPARAM ) hFont, 0 );
+ ypos += labelHeight;
+ }
+ }
+ else if ( !_tcscmp( type, _T("hidden"))) {
+ // skip
+ }
+ else { // everything else is considered "text-single"
+ if ( labelStr ) {
+ hCtrl = CreateWindow( _T("static"), labelStr, WS_CHILD|WS_VISIBLE|SS_RIGHT, labelOffset, ypos+4, labelWidth, labelHeight, hFrame, ( HMENU ) IDC_STATIC, hInst, NULL );
+ SendMessage( hCtrl, WM_SETFONT, ( WPARAM ) hFont, 0 );
+ }
+ hCtrl = CreateWindowEx( WS_EX_CLIENTEDGE, _T("edit"), valueStr, WS_CHILD|WS_VISIBLE|WS_BORDER|WS_TABSTOP|ES_LEFT|ES_AUTOHSCROLL, ctrlOffset, ypos, ctrlWidth, 24, hFrame, ( HMENU ) id, hInst, NULL );
+ SendMessage( hCtrl, WM_SETFONT, ( WPARAM ) hFont, 0 );
+ id++;
+ ypos += (( labelHeight>24 )?labelHeight:24 );
+ }
+ mir_free( labelStr );
+ if ( valueStr ) mir_free( valueStr );
+ } } } }
+
+ *formHeight = ypos;
+}
+
+XmlNode* JabberFormGetData( HWND hwndStatic, XmlNode* xNode )
+{
+ HWND hFrame, hCtrl;
+ XmlNode *n, *v, *o, *x;
+ int id, j, k, len;
+ TCHAR *varName, *type, *fieldStr, *str, *str2, *p, *q, *labelText;
+
+ if ( xNode==NULL || xNode->name==NULL || strcmp( xNode->name, "x" ) || hwndStatic==NULL )
+ return NULL;
+
+ hFrame = hwndStatic;
+ id = 0;
+ x = new XmlNode( "x" ); x->addAttr( "xmlns", "jabber:x:data" ); x->addAttr( "type", "submit" );
+ for ( int i=0; i<xNode->numChild; i++ ) {
+ n = xNode->child[i];
+ fieldStr = NULL;
+ if ( lstrcmpA( n->name, "field" ))
+ continue;
+
+ if (( varName=JabberXmlGetAttrValue( n, "var" )) == NULL || ( type=JabberXmlGetAttrValue( n, "type" )) == NULL )
+ continue;
+
+ hCtrl = GetDlgItem( hFrame, id );
+ XmlNode* field = x->addChild( "field" ); field->addAttr( "var", varName );
+
+ if ( !_tcscmp( type, _T("text-multi")) || !_tcscmp( type, _T("jid-multi"))) {
+ len = GetWindowTextLength( GetDlgItem( hFrame, id ));
+ str = ( TCHAR* )mir_alloc( sizeof(TCHAR)*( len+1 ));
+ GetDlgItemText( hFrame, id, str, len+1 );
+ p = str;
+ while ( p != NULL ) {
+ if (( q = _tcsstr( p, _T("\r\n"))) != NULL )
+ *q = '\0';
+ field->addChild( "value", p );
+ p = q ? q+2 : NULL;
+ }
+ mir_free( str );
+ id++;
+ }
+ else if ( !_tcscmp( type, _T("boolean"))) {
+ TCHAR buf[ 10 ];
+ _itot( IsDlgButtonChecked( hFrame, id ) == BST_CHECKED ? 1 : 0, buf, 10 );
+ field->addChild( "value", buf );
+ id++;
+ }
+ else if ( !_tcscmp( type, _T("list-single"))) {
+ len = GetWindowTextLength( GetDlgItem( hFrame, id ));
+ str = ( TCHAR* )mir_alloc( sizeof( TCHAR )*( len+1 ));
+ GetDlgItemText( hFrame, id, str, len+1 );
+ for ( j=0; j < n->numChild; j++ ) {
+ o = n->child[j];
+ if ( o && o->name && !strcmp( o->name, "option" )) {
+ if (( v=JabberXmlGetChild( o, "value" ))!=NULL && v->text ) {
+ if (( str2=JabberXmlGetAttrValue( o, "label" )) == NULL )
+ str2 = v->text;
+ if ( !lstrcmp( str2, str ))
+ break;
+ } } }
+
+ if ( j < n->numChild )
+ field->addChild( "value", v->text );
+
+ mir_free( str );
+ id++;
+ }
+ else if ( !_tcscmp( type, _T("list-multi"))) {
+ int count = SendMessage( hCtrl, LB_GETCOUNT, 0, 0 );
+ for ( j=0; j<count; j++ ) {
+ if ( SendMessage( hCtrl, LB_GETSEL, j, 0 ) > 0 ) {
+ // an entry is selected
+ len = SendMessage( hCtrl, LB_GETTEXTLEN, 0, 0 );
+ if (( str = ( TCHAR* )mir_alloc(( len+1 )*sizeof( TCHAR ))) != NULL ) {
+ SendMessage( hCtrl, LB_GETTEXT, j, ( LPARAM )str );
+ for ( k=0; k < n->numChild; k++ ) {
+ o = n->child[k];
+ if ( o && o->name && !strcmp( o->name, "option" )) {
+ if (( v=JabberXmlGetChild( o, "value" ))!=NULL && v->text ) {
+ if (( labelText=JabberXmlGetAttrValue( o, "label" )) == NULL )
+ labelText = v->text;
+
+ if ( !lstrcmp( labelText, str ))
+ field->addChild( "value", v->text );
+ } } }
+ mir_free( str );
+ } } }
+ id++;
+ }
+ else if ( !_tcscmp( type, _T("fixed")) || !_tcscmp( type, _T("hidden"))) {
+ v = JabberXmlGetChild( n, "value" );
+ if ( v != NULL && v->text != NULL )
+ field->addChild( "value", v->text );
+ }
+ else { // everything else is considered "text-single" or "text-private"
+ len = GetWindowTextLength( GetDlgItem( hFrame, id ));
+ str = ( TCHAR* )mir_alloc( sizeof(TCHAR)*( len+1 ));
+ GetDlgItemText( hFrame, id, str, len+1 );
+ field->addChild( "value", str );
+ mir_free( str );
+ id++;
+ } }
+
+ return x;
+}
+
+typedef struct {
+ XmlNode *xNode;
+ TCHAR defTitle[128]; // Default title if no <title/> in xNode
+ RECT frameRect; // Clipping region of the frame to scroll
+ int frameHeight; // Height of the frame ( can be eliminated, redundant to frameRect )
+ int formHeight; // Actual height of the form
+ int curPos; // Current scroll position
+ JABBER_FORM_SUBMIT_FUNC pfnSubmit;
+ void *userdata;
+} JABBER_FORM_INFO;
+
+static BOOL CALLBACK JabberFormDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ JABBER_FORM_INFO *jfi;
+
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ {
+ XmlNode *n;
+ LONG frameExStyle;
+
+ // lParam is ( JABBER_FORM_INFO * )
+ TranslateDialogDefault( hwndDlg );
+ ShowWindow( GetDlgItem( hwndDlg, IDC_FRAME_TEXT ), SW_HIDE );
+ jfi = ( JABBER_FORM_INFO * ) lParam;
+ if ( jfi != NULL ) {
+ // Set dialog title
+ if ( jfi->xNode!=NULL && ( n=JabberXmlGetChild( jfi->xNode, "title" ))!=NULL && n->text!=NULL )
+ SetWindowText( hwndDlg, n->text );
+ else if ( jfi->defTitle != NULL )
+ SetWindowText( hwndDlg, TranslateTS( jfi->defTitle ));
+ // Set instruction field
+ if ( jfi->xNode!=NULL && ( n=JabberXmlGetChild( jfi->xNode, "instructions" ))!=NULL && n->text!=NULL )
+ SetDlgItemText( hwndDlg, IDC_INSTRUCTION, n->text );
+
+ // Create form
+ if ( jfi->xNode != NULL ) {
+ RECT rect;
+
+ GetClientRect( GetDlgItem( hwndDlg, IDC_FRAME ), &( jfi->frameRect ));
+ GetClientRect( GetDlgItem( hwndDlg, IDC_VSCROLL ), &rect );
+ jfi->frameRect.right -= ( rect.right - rect.left );
+ GetClientRect( GetDlgItem( hwndDlg, IDC_FRAME ), &rect );
+ jfi->frameHeight = rect.bottom - rect.top;
+ JabberFormCreateUI( GetDlgItem( hwndDlg, IDC_FRAME ), jfi->xNode, &( jfi->formHeight ));
+ }
+ }
+
+ if ( jfi->formHeight > jfi->frameHeight ) {
+ HWND hwndScroll;
+
+ hwndScroll = GetDlgItem( hwndDlg, IDC_VSCROLL );
+ EnableWindow( hwndScroll, TRUE );
+ SetScrollRange( hwndScroll, SB_CTL, 0, jfi->formHeight - jfi->frameHeight, FALSE );
+ jfi->curPos = 0;
+ }
+
+ // Enable WS_EX_CONTROLPARENT on IDC_FRAME ( so tab stop goes through all its children )
+ frameExStyle = GetWindowLong( GetDlgItem( hwndDlg, IDC_FRAME ), GWL_EXSTYLE );
+ frameExStyle |= WS_EX_CONTROLPARENT;
+ SetWindowLong( GetDlgItem( hwndDlg, IDC_FRAME ), GWL_EXSTYLE, frameExStyle );
+
+ SetWindowLong( hwndDlg, GWL_USERDATA, ( LONG ) jfi );
+ if ( jfi->pfnSubmit != NULL )
+ EnableWindow( GetDlgItem( hwndDlg, IDC_SUBMIT ), TRUE );
+ }
+ return TRUE;
+ case WM_VSCROLL:
+ {
+ int pos;
+
+ jfi = ( JABBER_FORM_INFO * ) GetWindowLong( hwndDlg, GWL_USERDATA );
+ if ( jfi != NULL ) {
+ pos = jfi->curPos;
+ switch ( LOWORD( wParam )) {
+ case SB_LINEDOWN:
+ pos += 10;
+ break;
+ case SB_LINEUP:
+ pos -= 10;
+ break;
+ case SB_PAGEDOWN:
+ pos += ( jfi->frameHeight - 10 );
+ break;
+ case SB_PAGEUP:
+ pos -= ( jfi->frameHeight - 10 );
+ break;
+ case SB_THUMBTRACK:
+ pos = HIWORD( wParam );
+ break;
+ }
+ if ( pos > ( jfi->formHeight - jfi->frameHeight ))
+ pos = jfi->formHeight - jfi->frameHeight;
+ if ( pos < 0 )
+ pos = 0;
+ if ( jfi->curPos != pos ) {
+ ScrollWindow( GetDlgItem( hwndDlg, IDC_FRAME ), 0, jfi->curPos - pos, NULL, &( jfi->frameRect ));
+ SetScrollPos( GetDlgItem( hwndDlg, IDC_VSCROLL ), SB_CTL, pos, TRUE );
+ jfi->curPos = pos;
+ }
+ }
+ }
+ break;
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDC_SUBMIT:
+ jfi = ( JABBER_FORM_INFO * ) GetWindowLong( hwndDlg, GWL_USERDATA );
+ if ( jfi != NULL ) {
+ XmlNode* n = JabberFormGetData( GetDlgItem( hwndDlg, IDC_FRAME ), jfi->xNode );
+ ( jfi->pfnSubmit )( n, jfi->userdata );
+ }
+ // fall through
+ case IDCANCEL:
+ DestroyWindow( hwndDlg );
+ return TRUE;
+ }
+ break;
+ case WM_CLOSE:
+ DestroyWindow( hwndDlg );
+ break;
+ case WM_DESTROY:
+ jfi = ( JABBER_FORM_INFO * ) GetWindowLong( hwndDlg, GWL_USERDATA );
+ if ( jfi != NULL ) {
+ if ( jfi->xNode != NULL )
+ delete jfi->xNode;
+ mir_free( jfi );
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+static VOID CALLBACK JabberFormCreateDialogApcProc( DWORD param )
+{
+ CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_FORM ), NULL, JabberFormDlgProc, ( LPARAM )param );
+}
+
+void JabberFormCreateDialog( XmlNode *xNode, TCHAR* defTitle, JABBER_FORM_SUBMIT_FUNC pfnSubmit, void *userdata )
+{
+ JABBER_FORM_INFO *jfi;
+
+ jfi = ( JABBER_FORM_INFO * ) mir_alloc( sizeof( JABBER_FORM_INFO ));
+ memset( jfi, 0, sizeof( JABBER_FORM_INFO ));
+ jfi->xNode = JabberXmlCopyNode( xNode );
+ if ( defTitle )
+ _tcsncpy( jfi->defTitle, defTitle, SIZEOF( jfi->defTitle ));
+ jfi->pfnSubmit = pfnSubmit;
+ jfi->userdata = userdata;
+
+ if ( GetCurrentThreadId() != jabberMainThreadId )
+ QueueUserAPC( JabberFormCreateDialogApcProc, hMainThread, ( DWORD )jfi );
+ else
+ JabberFormCreateDialogApcProc(( DWORD )jfi );
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_ft.cpp b/miranda-wine/protocols/JabberG/jabber_ft.cpp new file mode 100644 index 0000000..1c1897f --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_ft.cpp @@ -0,0 +1,419 @@ +/*
+
+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_ft.cpp,v $
+Revision : $Revision: 2866 $
+Last change on : $Date: 2006-05-16 20:39:40 +0400 (Втр, 16 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+#include <io.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "jabber_iq.h"
+#include "jabber_byte.h"
+
+void JabberFtCancel( filetransfer* ft )
+{
+ JABBER_LIST_ITEM *item;
+ JABBER_BYTE_TRANSFER *jbt;
+ int i;
+
+ JabberLog( "Invoking JabberFtCancel()" );
+
+ // For file sending session that is still in si negotiation phase
+ for ( i=0; ( i=JabberListFindNext( LIST_FTSEND, i ))>=0; i++ ) {
+ item = JabberListGetItemPtrFromIndex( i );
+ if ( item->ft == ft ) {
+ JabberLog( "Canceling file sending session while in si negotiation" );
+ JabberListRemoveByIndex( i );
+ JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0 );
+ delete ft;
+ return;
+ }
+ }
+ // For file receiving session that is still in si negotiation phase
+ for ( i=0; ( i=JabberListFindNext( LIST_FTRECV, i ))>=0; i++ ) {
+ item = JabberListGetItemPtrFromIndex( i );
+ if ( item->ft == ft ) {
+ JabberLog( "Canceling file receiving session while in si negotiation" );
+ JabberListRemoveByIndex( i );
+ JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0 );
+ delete ft;
+ return;
+ }
+ }
+ // For file transfer through bytestream
+ if (( jbt=ft->jbt ) != NULL ) {
+ JabberLog( "Canceling bytestream session" );
+ jbt->state = JBT_ERROR;
+ if ( jbt->hConn ) {
+ JabberLog( "Force closing bytestream session" );
+ Netlib_CloseHandle( jbt->hConn );
+ jbt->hConn = NULL;
+ }
+ if ( jbt->hEvent ) SetEvent( jbt->hEvent );
+ }
+}
+
+///////////////// File sending using stream initiation /////////////////////////
+
+static void JabberFtSiResult( XmlNode *iqNode, void *userdata );
+static BOOL JabberFtSend( HANDLE hConn, void *userdata );
+static void JabberFtSendFinal( BOOL success, void *userdata );
+
+void JabberFtInitiate( TCHAR* jid, filetransfer* ft )
+{
+ int iqId;
+ TCHAR *rs;
+ char *filename, *p;
+ TCHAR idStr[32];
+ JABBER_LIST_ITEM *item;
+ int i;
+ TCHAR sid[9];
+
+ if ( jid==NULL || ft==NULL || !jabberOnline || ( rs=JabberListGetBestClientResourceNamePtr( jid ))==NULL ) {
+ JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0 );
+ delete ft;
+ return;
+ }
+ iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_NONE, JabberFtSiResult );
+ mir_sntprintf( idStr, SIZEOF( idStr ), _T(JABBER_IQID)_T("%d"), iqId );
+ if (( item=JabberListAdd( LIST_FTSEND, idStr )) == NULL ) {
+ JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0 );
+ delete ft;
+ return;
+ }
+ item->ft = ft;
+ ft->type = FT_SI;
+ for ( i=0; i<8; i++ )
+ sid[i] = ( rand()%10 ) + '0';
+ sid[8] = '\0';
+ if ( ft->sid != NULL ) mir_free( ft->sid );
+ ft->sid = mir_tstrdup( sid );
+ filename = ft->std.files[ ft->std.currentFileNumber ];
+ if (( p=strrchr( filename, '\\' )) != NULL )
+ filename = p+1;
+
+ TCHAR tszJid[200];
+ mir_sntprintf( tszJid, SIZEOF(tszJid), _T("%s/%s"), jid, rs );
+
+ XmlNodeIq iq( "set", iqId, tszJid );
+ XmlNode* si = iq.addChild( "si" ); si->addAttr( "xmlns", "http://jabber.org/protocol/si" );
+ si->addAttr( "id", sid ); si->addAttr( "mime-type", "binary/octet-stream" );
+ si->addAttr( "profile", "http://jabber.org/protocol/si/profile/file-transfer" );
+ XmlNode* file = si->addChild( "file" ); file->addAttr( "name", filename ); file->addAttr( "size", ft->fileSize[ ft->std.currentFileNumber ] );
+ file->addAttr( "xmlns", "http://jabber.org/protocol/si/profile/file-transfer" );
+ file->addChild( "desc", ft->szDescription );
+ XmlNode* feature = si->addChild( "feature" ); feature->addAttr( "xmlns", "http://jabber.org/protocol/feature-neg" );
+ XmlNode* x = feature->addChild( "x" ); x->addAttr( "xmlns", "jabber:x:data" ); x->addAttr( "type", "form" );
+ XmlNode* field = x->addChild( "field" ); field->addAttr( "var", "stream-method" ); field->addAttr( "type", "list-single" );
+ XmlNode* option = field->addChild( "option" ); option->addChild( "value", "http://jabber.org/protocol/bytestreams" );
+ JabberSend( jabberThreadInfo->s, iq );
+}
+
+static void JabberFtSiResult( XmlNode *iqNode, void *userdata )
+{
+ TCHAR* type, *from, *to, *idStr, *str;
+ XmlNode *siNode, *fileNode, *rangeNode, *featureNode, *xNode, *fieldNode, *valueNode;
+ JABBER_LIST_ITEM *item;
+ int offset, length;
+ JABBER_BYTE_TRANSFER *jbt;
+
+ if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return;
+ if (( from=JabberXmlGetAttrValue( iqNode, "from" )) == NULL ) return;
+ if (( to=JabberXmlGetAttrValue( iqNode, "to" )) == NULL ) return;
+ idStr = JabberXmlGetAttrValue( iqNode, "id" );
+ if (( item=JabberListGetItemPtr( LIST_FTSEND, idStr )) == NULL ) return;
+
+ if ( !_tcscmp( type, _T("result"))) {
+ if (( siNode=JabberXmlGetChild( iqNode, "si" )) != NULL ) {
+ if (( fileNode=JabberXmlGetChild( siNode, "file" )) != NULL ) {
+ if (( rangeNode=JabberXmlGetChild( fileNode, "range" )) != NULL ) {
+// ************** Need to store offset/length in ft structure **********************
+// but at this tiem, we should not get <range/> tag since we don't sent <range/> on our request
+ if (( str=JabberXmlGetAttrValue( rangeNode, "offset" )) != NULL )
+ offset = _ttoi( str );
+ if (( str=JabberXmlGetAttrValue( rangeNode, "length" )) != NULL )
+ length = _ttoi( str );
+ }
+ }
+ if (( featureNode=JabberXmlGetChild( siNode, "feature" )) != NULL ) {
+ if (( xNode=JabberXmlGetChildWithGivenAttrValue( featureNode, "x", "xmlns", _T("jabber:x:data"))) != NULL ) {
+ if (( fieldNode=JabberXmlGetChildWithGivenAttrValue( xNode, "field", "var", _T("stream-method"))) != NULL ) {
+ if (( valueNode=JabberXmlGetChild( fieldNode, "value" ))!=NULL && valueNode->text!=NULL ) {
+ if ( !_tcscmp( valueNode->text, _T("http://jabber.org/protocol/bytestreams"))) {
+ // Start Bytestream session
+ jbt = ( JABBER_BYTE_TRANSFER * ) mir_alloc( sizeof( JABBER_BYTE_TRANSFER ));
+ ZeroMemory( jbt, sizeof( JABBER_BYTE_TRANSFER ));
+ jbt->srcJID = mir_tstrdup( to );
+ jbt->dstJID = mir_tstrdup( from );
+ jbt->sid = mir_tstrdup( item->ft->sid );
+ jbt->pfnSend = JabberFtSend;
+ jbt->pfnFinal = JabberFtSendFinal;
+ jbt->userdata = item->ft;
+ item->ft->type = FT_BYTESTREAM;
+ item->ft->jbt = jbt;
+ JabberForkThread(( JABBER_THREAD_FUNC )JabberByteSendThread, 0, jbt );
+ } } } } } }
+ }
+ else if ( !_tcscmp( type, _T("error"))) {
+ JabberLog( "File transfer stream initiation request denied" );
+ JSendBroadcast( item->ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DENIED, item->ft, 0 );
+ delete item->ft;
+ item->ft = NULL;
+ }
+
+ JabberListRemove( LIST_FTSEND, idStr );
+}
+
+static BOOL JabberFtSend( HANDLE hConn, void *userdata )
+{
+ filetransfer* ft = ( filetransfer* ) userdata;
+
+ struct _stat statbuf;
+ int fd;
+ char* buffer;
+ int numRead;
+
+ JabberLog( "Sending [%s]", ft->std.files[ ft->std.currentFileNumber ] );
+ _stat( ft->std.files[ ft->std.currentFileNumber ], &statbuf ); // file size in statbuf.st_size
+ if (( fd=_open( ft->std.files[ ft->std.currentFileNumber ], _O_BINARY|_O_RDONLY )) < 0 ) {
+ JabberLog( "File cannot be opened" );
+ return FALSE;
+ }
+
+ ft->std.sending = TRUE;
+ ft->std.currentFileSize = statbuf.st_size;
+ ft->std.currentFileProgress = 0;
+
+ if (( buffer=( char* )mir_alloc( 2048 )) != NULL ) {
+ while (( numRead=_read( fd, buffer, 2048 )) > 0 ) {
+ if ( Netlib_Send( hConn, buffer, numRead, 0 ) != numRead ) {
+ mir_free( buffer );
+ _close( fd );
+ return FALSE;
+ }
+ ft->std.currentFileProgress += numRead;
+ ft->std.totalProgress += numRead;
+ JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, ( LPARAM )&ft->std );
+ }
+ mir_free( buffer );
+ }
+ _close( fd );
+ return TRUE;
+}
+
+static void JabberFtSendFinal( BOOL success, void *userdata )
+{
+ filetransfer* ft = ( filetransfer* )userdata;
+
+ if ( !success ) {
+ JabberLog( "File transfer complete with error" );
+ JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_FAILED, ft, 0 );
+ }
+ else {
+ if ( ft->std.currentFileNumber < ft->std.totalFiles-1 ) {
+ ft->std.currentFileNumber++;
+ replaceStr( ft->std.currentFile, ft->std.files[ ft->std.currentFileNumber ] );
+ JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_NEXTFILE, ft, 0 );
+ JabberFtInitiate( ft->jid, ft );
+ return;
+ }
+
+ JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_SUCCESS, ft, 0 );
+ }
+
+ delete ft;
+}
+
+///////////////// File receiving through stream initiation /////////////////////////
+
+static int JabberFtReceive( HANDLE hConn, void *userdata, char* buffer, int datalen );
+static void JabberFtReceiveFinal( BOOL success, void *userdata );
+
+void JabberFtHandleSiRequest( XmlNode *iqNode )
+{
+ TCHAR* from, *sid, *str, *szId, *filename;
+ XmlNode *siNode, *fileNode, *featureNode, *xNode, *fieldNode, *optionNode, *n;
+ int filesize, i;
+ JABBER_FT_TYPE ftType;
+
+ if ( iqNode==NULL ||
+ ( from=JabberXmlGetAttrValue( iqNode, "from" ))==NULL ||
+ ( str=JabberXmlGetAttrValue( iqNode, "type" ))==NULL || _tcscmp( str, _T("set")) ||
+ ( siNode=JabberXmlGetChildWithGivenAttrValue( iqNode, "si", "xmlns", _T("http://jabber.org/protocol/si"))) == NULL )
+ return;
+
+ szId = JabberXmlGetAttrValue( iqNode, "id" );
+ if (( sid=JabberXmlGetAttrValue( siNode, "id" ))!=NULL &&
+ ( fileNode=JabberXmlGetChildWithGivenAttrValue( siNode, "file", "xmlns", _T("http://jabber.org/protocol/si/profile/file-transfer")))!=NULL &&
+ ( filename=JabberXmlGetAttrValue( fileNode, "name" ))!=NULL &&
+ ( str=JabberXmlGetAttrValue( fileNode, "size" ))!=NULL ) {
+
+ filesize = _ttoi( str );
+ if (( featureNode=JabberXmlGetChildWithGivenAttrValue( siNode, "feature", "xmlns", _T("http://jabber.org/protocol/feature-neg"))) != NULL &&
+ ( xNode=JabberXmlGetChildWithGivenAttrValue( featureNode, "x", "xmlns", _T("jabber:x:data")))!=NULL &&
+ ( fieldNode=JabberXmlGetChildWithGivenAttrValue( xNode, "field", "var", _T("stream-method")))!=NULL ) {
+
+ for ( i=0; i<fieldNode->numChild; i++ ) {
+ optionNode = fieldNode->child[i];
+ if ( optionNode->name && !strcmp( optionNode->name, "option" )) {
+ if (( n=JabberXmlGetChild( optionNode, "value" ))!=NULL && n->text ) {
+ if ( !_tcscmp( n->text, _T("http://jabber.org/protocol/bytestreams"))) {
+ ftType = FT_BYTESTREAM;
+ break;
+ } } } }
+
+ if ( i < fieldNode->numChild ) {
+ // Found known stream mechanism
+ CCSDATA ccs;
+ PROTORECVEVENT pre;
+
+ char *localFilename = t2a( filename );
+ char *desc = (( n=JabberXmlGetChild( fileNode, "desc" ))!=NULL && n->text!=NULL ) ? t2a( n->text ) : mir_strdup( "" );
+
+ filetransfer* ft = new filetransfer;
+ ft->jid = mir_tstrdup( from );
+ ft->std.hContact = JabberHContactFromJID( from );
+ ft->sid = mir_tstrdup( sid );
+ ft->iqId = ( szId ) ? mir_tstrdup( szId ):NULL;
+ ft->type = ftType;
+ ft->std.totalFiles = 1;
+ ft->std.currentFile = localFilename;
+ ft->std.totalBytes = ft->std.currentFileSize = filesize;
+ char* szBlob = ( char* )alloca( sizeof( DWORD )+ strlen( localFilename ) + strlen( desc ) + 2 );
+ *(( PDWORD ) szBlob ) = ( DWORD )ft;
+ strcpy( szBlob + sizeof( DWORD ), localFilename );
+ strcpy( szBlob + sizeof( DWORD )+ strlen( localFilename ) + 1, desc );
+ pre.flags = 0;
+ pre.timestamp = time( NULL );
+ pre.szMessage = szBlob;
+ pre.lParam = 0;
+ ccs.szProtoService = PSR_FILE;
+ ccs.hContact = ft->std.hContact;
+ ccs.wParam = 0;
+ ccs.lParam = ( LPARAM )⪯
+ JCallService( MS_PROTO_CHAINRECV, 0, ( LPARAM )&ccs );
+ mir_free( desc );
+ return;
+ }
+ else {
+ // Unknown stream mechanism
+ XmlNodeIq iq( "error", szId, from );
+ XmlNode* e = iq.addChild( "error" ); e->addAttr( "code", 400 ); e->addAttr( "type", "cancel" );
+ XmlNode* br = e->addChild( "bad-request" ); br->addAttr( "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas" );
+ XmlNode* nvs = e->addChild( "no-valid-streams" ); nvs->addAttr( "xmlns", "http://jabber.org/protocol/si" );
+ JabberSend( jabberThreadInfo->s, iq );
+ return;
+ } } }
+
+ // Bad stream initiation, reply with bad-profile
+ XmlNodeIq iq( "error", szId, from );
+ XmlNode* e = iq.addChild( "error" ); e->addAttr( "code", 400 ); e->addAttr( "type", "cancel" );
+ XmlNode* br = e->addChild( "bad-request" ); br->addAttr( "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas" );
+ XmlNode* nvs = e->addChild( "bad-profile" ); nvs->addAttr( "xmlns", "http://jabber.org/protocol/si" );
+ JabberSend( jabberThreadInfo->s, iq );
+}
+
+void JabberFtAcceptSiRequest( filetransfer* ft )
+{
+ if ( !jabberOnline || ft==NULL || ft->jid==NULL || ft->sid==NULL ) return;
+
+ JABBER_LIST_ITEM *item;
+ if (( item=JabberListAdd( LIST_FTRECV, ft->sid )) != NULL ) {
+ item->ft = ft;
+
+ XmlNodeIq iq( "result", ft->iqId, ft->jid );
+ XmlNode* si = iq.addChild( "si" ); si->addAttr( "xmlns", "http://jabber.org/protocol/si" );
+ XmlNode* f = si->addChild( "feature" ); f->addAttr( "xmlns", "http://jabber.org/protocol/feature-neg" );
+ XmlNode* x = f->addChild( "x" ); x->addAttr( "xmlns", "jabber:x:data" ); x->addAttr( "type", "submit" );
+ XmlNode* fl = x->addChild( "field" ); fl->addAttr( "var", "stream-method" );
+ fl->addChild( "value", "http://jabber.org/protocol/bytestreams" );
+ JabberSend( jabberThreadInfo->s, iq );
+} }
+
+BOOL JabberFtHandleBytestreamRequest( XmlNode *iqNode )
+{
+ XmlNode *queryNode;
+ TCHAR* sid;
+ JABBER_LIST_ITEM *item;
+ JABBER_BYTE_TRANSFER *jbt;
+
+ if ( iqNode == NULL ) return FALSE;
+ if (( queryNode=JabberXmlGetChildWithGivenAttrValue( iqNode, "query", "xmlns", _T("http://jabber.org/protocol/bytestreams")))!=NULL &&
+ ( sid=JabberXmlGetAttrValue( queryNode, "sid" ))!=NULL &&
+ ( item=JabberListGetItemPtr( LIST_FTRECV, sid ))!=NULL ) {
+ // Start Bytestream session
+ jbt = ( JABBER_BYTE_TRANSFER * ) mir_alloc( sizeof( JABBER_BYTE_TRANSFER ));
+ ZeroMemory( jbt, sizeof( JABBER_BYTE_TRANSFER ));
+ jbt->iqNode = JabberXmlCopyNode( iqNode );
+ jbt->pfnRecv = JabberFtReceive;
+ jbt->pfnFinal = JabberFtReceiveFinal;
+ jbt->userdata = item->ft;
+ item->ft->jbt = jbt;
+ JabberForkThread(( JABBER_THREAD_FUNC )JabberByteReceiveThread, 0, jbt );
+ JabberListRemove( LIST_FTRECV, sid );
+ return TRUE;
+ }
+
+ JabberLog( "File transfer invalid bytestream initiation request received" );
+ return FALSE;
+}
+
+static int JabberFtReceive( HANDLE hConn, void *userdata, char* buffer, int datalen )
+{
+ filetransfer* ft = ( filetransfer* )userdata;
+ if ( ft->create() == -1 )
+ return -1;
+
+ int remainingBytes = ft->std.currentFileSize - ft->std.currentFileProgress;
+ if ( remainingBytes > 0 ) {
+ int writeSize = ( remainingBytes<datalen ) ? remainingBytes : datalen;
+ if ( _write( ft->fileId, buffer, writeSize ) != writeSize ) {
+ JabberLog( "_write() error" );
+ return -1;
+ }
+
+ ft->std.currentFileProgress += writeSize;
+ ft->std.totalProgress += writeSize;
+ JSendBroadcast( ft->std.hContact, ACKTYPE_FILE, ACKRESULT_DATA, ft, ( LPARAM )&ft->std );
+ return ( ft->std.currentFileSize == ft->std.currentFileProgress ) ? 0 : writeSize;
+ }
+
+ return 0;
+}
+
+static void JabberFtReceiveFinal( BOOL success, void *userdata )
+{
+ filetransfer* ft = ( filetransfer* )userdata;
+
+ if ( success ) {
+ JabberLog( "File transfer complete successfully" );
+ ft->complete();
+ }
+ else JabberLog( "File transfer complete with error" );
+
+ delete ft;
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_groupchat.cpp b/miranda-wine/protocols/JabberG/jabber_groupchat.cpp new file mode 100644 index 0000000..f12e77a --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_groupchat.cpp @@ -0,0 +1,886 @@ +/*
+
+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_groupchat.cpp,v $
+Revision : $Revision: 3670 $
+Last change on : $Date: 2006-08-31 19:47:56 +0400 (Чтв, 31 Авг 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+#include <commctrl.h>
+#include "resource.h"
+#include "jabber_iq.h"
+
+#define GC_SERVER_LIST_SIZE 5
+
+static BOOL CALLBACK JabberGroupchatDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam );
+static BOOL CALLBACK JabberGroupchatJoinDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam );
+
+int JabberMenuHandleGroupchat( WPARAM wParam, LPARAM lParam )
+{
+ int iqId;
+
+ // lParam is the initial conference server to browse ( if any )
+ if ( IsWindow( hwndJabberGroupchat )) {
+ SetForegroundWindow( hwndJabberGroupchat );
+ if ( lParam != 0 ) {
+ SendMessage( hwndJabberGroupchat, WM_JABBER_ACTIVATE, 0, lParam ); // Just to update the IDC_SERVER and clear the list
+ iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_DISCOROOMSERVER, JabberIqResultDiscoRoomItems );
+
+ XmlNodeIq iq( "get", iqId, ( TCHAR* )lParam );
+ XmlNode* query = iq.addQuery( "http://jabber.org/protocol/disco#items" );
+ JabberSend( jabberThreadInfo->s, iq );
+ // <iq/> result will send WM_JABBER_REFRESH to update the list with real data
+ }
+ }
+ else hwndJabberGroupchat = CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_GROUPCHAT ), NULL, JabberGroupchatDlgProc, lParam );
+
+ return 0;
+}
+
+static BOOL sortAscending;
+static int sortColumn;
+
+static int CALLBACK GroupchatCompare( LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort )
+{
+ JABBER_LIST_ITEM *item1, *item2;
+ int res = 0;
+ item1 = JabberListGetItemPtr( LIST_ROOM, ( TCHAR* )lParam1 );
+ item2 = JabberListGetItemPtr( LIST_ROOM, ( TCHAR* )lParam2 );
+ if ( item1!=NULL && item2!=NULL ) {
+ switch ( lParamSort ) {
+ case 0: // sort by JID column
+ res = lstrcmp( item1->jid, item2->jid );
+ break;
+ case 1: // sort by Name column
+ res = lstrcmp( item1->name, item2->name );
+ break;
+ } }
+
+ if ( !sortAscending )
+ res *= -1;
+
+ return res;
+}
+
+static BOOL CALLBACK JabberGroupchatDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ HWND lv;
+ LVCOLUMN lvCol;
+ LVITEM lvItem;
+ JABBER_LIST_ITEM *item;
+
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ // lParam is the initial conference server ( if any )
+ SendMessage( hwndDlg, WM_SETICON, ICON_BIG, ( LPARAM )LoadIcon( hInst, MAKEINTRESOURCE( IDI_GROUP )) );
+ TranslateDialogDefault( hwndDlg );
+ sortColumn = -1;
+ // Add columns
+ lv = GetDlgItem( hwndDlg, IDC_ROOM );
+ lvCol.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
+ lvCol.pszText = TranslateT( "JID" );
+ lvCol.cx = 210;
+ lvCol.iSubItem = 0;
+ ListView_InsertColumn( lv, 0, &lvCol );
+ lvCol.pszText = TranslateT( "Name" );
+ lvCol.cx = 150;
+ lvCol.iSubItem = 1;
+ ListView_InsertColumn( lv, 1, &lvCol );
+ lvCol.pszText = TranslateT( "Type" );
+ lvCol.cx = 60;
+ lvCol.iSubItem = 2;
+ ListView_InsertColumn( lv, 2, &lvCol );
+ if ( jabberOnline ) {
+ if (( TCHAR* )lParam != NULL ) {
+ SetDlgItemText( hwndDlg, IDC_SERVER, ( TCHAR* )lParam );
+ int iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_DISCOROOMSERVER, JabberIqResultDiscoRoomItems );
+
+ XmlNodeIq iq( "get", iqId, ( TCHAR* )lParam );
+ XmlNode* query = iq.addQuery( "http://jabber.org/protocol/disco#items" );
+ JabberSend( jabberThreadInfo->s, iq );
+ }
+ else {
+ for ( int i=0; i < GC_SERVER_LIST_SIZE; i++ ) {
+ char text[100];
+ mir_snprintf( text, sizeof( text ), "GcServerLast%d", i );
+ DBVARIANT dbv;
+ if ( !JGetStringT( NULL, text, &dbv )) {
+ SendDlgItemMessage( hwndDlg, IDC_SERVER, CB_ADDSTRING, 0, ( LPARAM )dbv.ptszVal );
+ JFreeVariant( &dbv );
+ } } }
+ }
+ else EnableWindow( GetDlgItem( hwndDlg, IDC_JOIN ), FALSE );
+ return TRUE;
+
+ case WM_JABBER_ACTIVATE:
+ // lParam = server from which agent information is obtained
+ if ( lParam )
+ SetDlgItemText( hwndDlg, IDC_SERVER, ( TCHAR* )lParam );
+ ListView_DeleteAllItems( GetDlgItem( hwndDlg, IDC_ROOM ));
+ EnableWindow( GetDlgItem( hwndDlg, IDC_BROWSE ), FALSE );
+ return TRUE;
+
+ case WM_JABBER_REFRESH:
+ // lParam = server from which agent information is obtained
+ {
+ int i;
+ TCHAR szBuffer[256];
+ char text[128];
+
+ if ( lParam ){
+ _tcsncpy( szBuffer, ( TCHAR* )lParam, SIZEOF( szBuffer ));
+ for ( i=0; i<GC_SERVER_LIST_SIZE; i++ ) {
+ mir_snprintf( text, SIZEOF( text ), "GcServerLast%d", i );
+ DBVARIANT dbv;
+ if ( !JGetStringT( NULL, text, &dbv )) {
+ JSetStringT( NULL, text, szBuffer );
+ if ( !_tcsicmp( dbv.ptszVal, ( TCHAR* )lParam )) {
+ JFreeVariant( &dbv );
+ break;
+ }
+ _tcsncpy( szBuffer, dbv.ptszVal, SIZEOF( szBuffer ));
+ JFreeVariant( &dbv );
+ }
+ else {
+ JSetStringT( NULL, text, szBuffer );
+ break;
+ } }
+
+ SendDlgItemMessage( hwndDlg, IDC_SERVER, CB_RESETCONTENT, 0, 0 );
+ for ( i=0; i<GC_SERVER_LIST_SIZE; i++ ) {
+ mir_snprintf( text, SIZEOF( text ), "GcServerLast%d", i );
+ DBVARIANT dbv;
+ if ( !JGetStringT( NULL, text, &dbv )) {
+ SendDlgItemMessage( hwndDlg, IDC_SERVER, CB_ADDSTRING, 0, ( LPARAM )dbv.ptszVal );
+ JFreeVariant( &dbv );
+ }
+ }
+ SetDlgItemText( hwndDlg, IDC_SERVER, ( TCHAR* )lParam );
+ }
+ i = 0;
+ lv = GetDlgItem( hwndDlg, IDC_ROOM );
+ ListView_DeleteAllItems( lv );
+ LVITEM lvItem;
+ lvItem.iItem = 0;
+ while (( i=JabberListFindNext( LIST_ROOM, i )) >= 0 ) {
+ if (( item=JabberListGetItemPtrFromIndex( i )) != NULL ) {
+ lvItem.mask = LVIF_PARAM | LVIF_TEXT;
+ lvItem.iSubItem = 0;
+ _tcsncpy( szBuffer, item->jid, SIZEOF(szBuffer));
+ szBuffer[ SIZEOF(szBuffer)-1 ] = 0;
+ lvItem.lParam = ( LPARAM )item->jid;
+ lvItem.pszText = szBuffer;
+ ListView_InsertItem( lv, &lvItem );
+
+ lvItem.mask = LVIF_TEXT;
+ lvItem.iSubItem = 1;
+ lvItem.pszText = item->name;
+ ListView_SetItem( lv, &lvItem );
+
+ lvItem.iSubItem = 2;
+ lvItem.pszText = item->type;
+ ListView_SetItem( lv, &lvItem );
+ lvItem.iItem++;
+ }
+ i++;
+ }
+ EnableWindow( GetDlgItem( hwndDlg, IDC_BROWSE ), TRUE );
+ }
+ return TRUE;
+ case WM_JABBER_CHECK_ONLINE:
+ {
+ TCHAR text[128];
+ if ( jabberOnline ) {
+ EnableWindow( GetDlgItem( hwndDlg, IDC_JOIN ), TRUE );
+ GetDlgItemText( hwndDlg, IDC_SERVER, text, SIZEOF( text ));
+ EnableWindow( GetDlgItem( hwndDlg, IDC_BROWSE ), ( text[0]!='\0' ));
+ }
+ else {
+ EnableWindow( GetDlgItem( hwndDlg, IDC_JOIN ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_BROWSE ), FALSE );
+ SetDlgItemTextA( hwndDlg, IDC_SERVER, "" );
+ lv = GetDlgItem( hwndDlg, IDC_ROOM );
+ ListView_DeleteAllItems( lv );
+ }
+ break;
+ }
+ case WM_NOTIFY:
+ switch ( wParam ) {
+ case IDC_ROOM:
+ switch (( ( LPNMHDR )lParam )->code ) {
+ case LVN_COLUMNCLICK:
+ {
+ LPNMLISTVIEW pnmlv = ( LPNMLISTVIEW ) lParam;
+
+ if ( pnmlv->iSubItem>=0 && pnmlv->iSubItem<=1 ) {
+ if ( pnmlv->iSubItem == sortColumn )
+ sortAscending = !sortAscending;
+ else {
+ sortAscending = TRUE;
+ sortColumn = pnmlv->iSubItem;
+ }
+ ListView_SortItems( GetDlgItem( hwndDlg, IDC_ROOM ), GroupchatCompare, sortColumn );
+ }
+ }
+ break;
+ }
+ break;
+ }
+ break;
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case WM_JABBER_JOIN:
+ if ( jabberChatDllPresent ) {
+ lv = GetDlgItem( hwndDlg, IDC_ROOM );
+ if (( lvItem.iItem=ListView_GetNextItem( lv, -1, LVNI_SELECTED )) >= 0 ) {
+ lvItem.iSubItem = 0;
+ lvItem.mask = LVIF_PARAM;
+ ListView_GetItem( lv, &lvItem );
+ ListView_SetItemState( lv, lvItem.iItem, 0, LVIS_SELECTED ); // Unselect the item
+ DialogBoxParam( hInst, MAKEINTRESOURCE( IDD_GROUPCHAT_JOIN ), hwndDlg, JabberGroupchatJoinDlgProc, ( LPARAM )lvItem.lParam );
+ }
+ else {
+ TCHAR text[128];
+ GetDlgItemText( hwndDlg, IDC_SERVER, text, SIZEOF( text ));
+ DialogBoxParam( hInst, MAKEINTRESOURCE( IDD_GROUPCHAT_JOIN ), hwndDlg, JabberGroupchatJoinDlgProc, ( LPARAM )text );
+ } }
+ else JabberChatDllError();
+ return TRUE;
+
+ case WM_JABBER_ADD_TO_ROSTER:
+ lv = GetDlgItem( hwndDlg, IDC_ROOM );
+ if (( lvItem.iItem=ListView_GetNextItem( lv, -1, LVNI_SELECTED )) >= 0 ) {
+ lvItem.iSubItem = 0;
+ lvItem.mask = LVIF_PARAM;
+ ListView_GetItem( lv, &lvItem );
+ TCHAR* jid = ( TCHAR* )lvItem.lParam;
+ { GCSESSION gcw = {0};
+ gcw.cbSize = sizeof(GCSESSION);
+ gcw.iType = GCW_CHATROOM;
+ gcw.pszID = t2a(jid);
+ gcw.pszModule = jabberProtoName;
+ gcw.pszName = NEWSTR_ALLOCA(gcw.pszID);
+ char* p = ( char* )strchr( gcw.pszName, '@' );
+ if ( p != NULL )
+ *p = 0;
+ CallService( MS_GC_NEWSESSION, 0, ( LPARAM )&gcw );
+ mir_free((void*)gcw.pszID);
+ }
+ { XmlNodeIq iq( "set" );
+ XmlNode* query = iq.addQuery( "jabber:iq:roster" );
+ XmlNode* item = query->addChild( "item" ); item->addAttr( "jid", jid );
+ JabberSend( jabberThreadInfo->s, iq );
+ }
+ { XmlNode p( "presence" ); p.addAttr( "to", jid ); p.addAttr( "type", "subscribe" );
+ JabberSend( jabberThreadInfo->s, p );
+ } }
+ break;
+
+ case IDC_SERVER:
+ { TCHAR text[ 128 ];
+ GetDlgItemText( hwndDlg, IDC_SERVER, text, SIZEOF( text ));
+ if ( jabberOnline && ( text[0] || HIWORD( wParam )==CBN_SELCHANGE ))
+ EnableWindow( GetDlgItem( hwndDlg, IDC_BROWSE ), TRUE );
+ break;
+ }
+ case IDC_BROWSE:
+ { TCHAR text[ 128 ];
+ GetDlgItemText( hwndDlg, IDC_SERVER, text, SIZEOF( text ));
+ if ( jabberOnline && text[0] ) {
+ EnableWindow( GetDlgItem( hwndDlg, IDC_BROWSE ), FALSE );
+ ListView_DeleteAllItems( GetDlgItem( hwndDlg, IDC_ROOM ));
+ GetDlgItemText( hwndDlg, IDC_SERVER, text, SIZEOF( text ));
+
+ int iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_DISCOROOMSERVER, JabberIqResultDiscoRoomItems );
+
+ XmlNodeIq iq( "get", iqId, text );
+ XmlNode* query = iq.addQuery( "http://jabber.org/protocol/disco#items" );
+ JabberSend( jabberThreadInfo->s, iq );
+ }
+ return TRUE;
+ }
+ case IDCLOSE:
+ DestroyWindow( hwndDlg );
+ return TRUE;
+ }
+ break;
+ case WM_CONTEXTMENU:
+ if (( HWND )wParam == GetDlgItem( hwndDlg, IDC_ROOM )) {
+ HMENU hMenu = CreatePopupMenu();
+ AppendMenu( hMenu, MF_STRING, WM_JABBER_JOIN, TranslateT( "Join" ));
+ AppendMenu( hMenu, MF_STRING, WM_JABBER_ADD_TO_ROSTER, TranslateT( "Add to roster" ));
+ TrackPopupMenu( hMenu, TPM_LEFTALIGN | TPM_NONOTIFY, LOWORD(lParam), HIWORD(lParam), 0, hwndDlg, 0 );
+ ::DestroyMenu( hMenu );
+ return TRUE;
+ }
+ break;
+ case WM_CLOSE:
+ DestroyWindow( hwndDlg );
+ break;
+ case WM_DESTROY:
+ hwndJabberGroupchat = NULL;
+ break;
+ }
+ return FALSE;
+}
+
+void JabberGroupchatJoinRoom( const TCHAR* server, const TCHAR* room, const TCHAR* nick, const TCHAR* password )
+{
+ TCHAR text[128];
+ mir_sntprintf( text, SIZEOF(text), _T("%s@%s/%s"), room, server, nick );
+
+ JABBER_LIST_ITEM* item = JabberListAdd( LIST_CHATROOM, text );
+ replaceStr( item->nick, nick );
+
+ int status = ( jabberStatus == ID_STATUS_INVISIBLE ) ? ID_STATUS_ONLINE : jabberStatus;
+ XmlNode* x = new XmlNode( "x" ); x->addAttr( "xmlns", "http://jabber.org/protocol/muc" );
+ if ( password && password[0]!='\0' )
+ x->addChild( "password", password );
+ JabberSendPresenceTo( status, text, x );
+}
+
+static BOOL CALLBACK JabberGroupchatJoinDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ TCHAR text[128];
+ TCHAR* p;
+
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ {
+ // lParam is the room JID ( room@server ) in UTF-8
+ hwndJabberJoinGroupchat = hwndDlg;
+ TranslateDialogDefault( hwndDlg );
+ if ( lParam ){
+ _tcsncpy( text, ( TCHAR* )lParam, SIZEOF( text ));
+ if (( p = _tcschr( text, '@' )) != NULL ) {
+ *p = '\0';
+ // Need to save room name in UTF-8 in case the room codepage is different
+ // from the local code page
+ TCHAR* room = mir_tstrdup( text );
+ SetWindowLong( hwndDlg, GWL_USERDATA, ( LONG ) room );
+ SetDlgItemText( hwndDlg, IDC_ROOM, room );
+ SetDlgItemText( hwndDlg, IDC_SERVER, p+1 );
+ }
+ else SetDlgItemText( hwndDlg, IDC_SERVER, text );
+ }
+
+ DBVARIANT dbv;
+ if ( !JGetStringT( NULL, "Nick", &dbv )) {
+ SetDlgItemText( hwndDlg, IDC_NICK, dbv.ptszVal );
+ JFreeVariant( &dbv );
+ }
+ else {
+ TCHAR* nick = JabberNickFromJID( jabberJID );
+ SetDlgItemText( hwndDlg, IDC_NICK, nick );
+ mir_free( nick );
+ } }
+ return TRUE;
+
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDC_ROOM:
+ if (( HWND )lParam==GetFocus() && HIWORD( wParam )==EN_CHANGE ) {
+ // Change in IDC_ROOM field is detected,
+ // invalidate the saved UTF-8 room name if any
+ char* str = ( char* )GetWindowLong( hwndDlg, GWL_USERDATA );
+ if ( str != NULL ) {
+ mir_free( str );
+ SetWindowLong( hwndDlg, GWL_USERDATA, ( LONG ) NULL );
+ } }
+ break;
+ case IDOK:
+ {
+ GetDlgItemText( hwndDlg, IDC_SERVER, text, SIZEOF( text ));
+ TCHAR* server = NEWTSTR_ALLOCA( text ), *room;
+
+ if (( room=( TCHAR* )GetWindowLong( hwndDlg, GWL_USERDATA )) != NULL )
+ room = NEWTSTR_ALLOCA( room );
+ else {
+ GetDlgItemText( hwndDlg, IDC_ROOM, text, SIZEOF( text ));
+ room = NEWTSTR_ALLOCA( text );
+ }
+
+ GetDlgItemText( hwndDlg, IDC_NICK, text, SIZEOF( text ));
+ TCHAR* nick = NEWTSTR_ALLOCA( text );
+
+ GetDlgItemText( hwndDlg, IDC_PASSWORD, text, SIZEOF( text ));
+ TCHAR* password = NEWTSTR_ALLOCA( text );
+ JabberGroupchatJoinRoom( server, room, nick, password );
+ }
+ // fall through
+ case IDCANCEL:
+ EndDialog( hwndDlg, 0 );
+ break;
+ }
+ break;
+ case WM_JABBER_CHECK_ONLINE:
+ if ( !jabberOnline ) EndDialog( hwndDlg, 0 );
+ break;
+ case WM_DESTROY:
+ {
+ char* str = ( char* )GetWindowLong( hwndDlg, GWL_USERDATA );
+ if ( str != NULL )
+ mir_free( str );
+
+ hwndJabberJoinGroupchat = NULL;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberGroupchatProcessPresence - handles the group chat presence packet
+
+static int sttGetStatusCode( XmlNode* node )
+{
+ XmlNode* statusNode = JabberXmlGetChild( node, "status" );
+ if ( statusNode == NULL )
+ return -1;
+
+ TCHAR* statusCode = JabberXmlGetAttrValue( statusNode, "code" );
+ if ( statusCode == NULL )
+ return -1;
+
+ return _ttol( statusCode );
+}
+
+void sttRenameParticipantNick( JABBER_LIST_ITEM* item, TCHAR* oldNick, XmlNode *itemNode )
+{
+ TCHAR* newNick = JabberXmlGetAttrValue( itemNode, "nick" );
+ if ( newNick == NULL )
+ return;
+
+ for ( int i=0; i < item->resourceCount; i++ ) {
+ JABBER_RESOURCE_STATUS& RS = item->resource[i];
+ if ( !lstrcmp( RS.resourceName, oldNick )) {
+ replaceStr( RS.resourceName, newNick );
+
+ if ( !lstrcmp( item->nick, oldNick )) {
+ replaceStr( item->nick, newNick );
+
+ HANDLE hContact = JabberHContactFromJID( item->jid );
+ if ( hContact != NULL )
+ JSetStringT( hContact, "MyNick", newNick );
+ }
+
+ #if defined( _UNICODE )
+ char* jid = u2a( item->jid );
+ char* dispNick = u2a( newNick );
+ char* dispOldNick = u2a( oldNick );
+ #else
+ char* jid = item->jid;
+ char* dispNick = NEWSTR_ALLOCA( newNick );
+ char* dispOldNick = NEWSTR_ALLOCA( oldNick );
+ #endif
+
+ GCDEST gcd = { jabberProtoName, jid, GC_EVENT_CHUID };
+ GCEVENT gce = {0};
+ gce.cbSize = sizeof(GCEVENT);
+ gce.pDest = &gcd;
+ gce.pszNick = dispOldNick;
+ gce.pszText = dispNick;
+ gce.time = time(0);
+ JCallService( MS_GC_EVENT, NULL, ( LPARAM )&gce );
+
+ gcd.iType = GC_EVENT_NICK;
+ gce.pszNick = dispOldNick;
+ gce.pszUID = dispNick;
+ gce.pszText = dispNick;
+ JCallService( MS_GC_EVENT, NULL, ( LPARAM )&gce );
+
+ #if defined( _UNICODE )
+ mir_free( jid );
+ mir_free( dispNick );
+ mir_free( dispOldNick );
+ #endif
+ break;
+} } }
+
+void JabberGroupchatProcessPresence( XmlNode *node, void *userdata )
+{
+ struct ThreadData *info;
+ XmlNode *showNode, *statusNode, *errorNode, *itemNode, *n;
+ TCHAR* from;
+ int status, newRes;
+ int i;
+ BOOL roomCreated;
+
+ if ( !node || !node->name || strcmp( node->name, "presence" )) return;
+ if (( info=( struct ThreadData * ) userdata ) == NULL ) return;
+ if (( from=JabberXmlGetAttrValue( node, "from" )) == NULL ) return;
+
+ TCHAR* nick = _tcschr( from, '/' );
+ if ( nick == NULL || nick[1] == '\0' )
+ return;
+ nick++;
+
+ JABBER_LIST_ITEM* item = JabberListGetItemPtr( LIST_CHATROOM, from );
+ if ( item == NULL )
+ return;
+
+ XmlNode* xNode = JabberXmlGetChildWithGivenAttrValue( node, "x", "xmlns", _T("http://jabber.org/protocol/muc#user"));
+
+ TCHAR* type = JabberXmlGetAttrValue( node, "type" );
+ if ( type == NULL || !_tcscmp( type, _T("available"))) {
+ TCHAR* room = JabberNickFromJID( from );
+ if ( room == NULL )
+ return;
+
+ JabberGcLogCreate( item );
+
+ // Update status of room participant
+ status = ID_STATUS_ONLINE;
+ if (( showNode=JabberXmlGetChild( node, "show" )) != NULL ) {
+ if ( showNode->text != NULL ) {
+ if ( !_tcscmp( showNode->text , _T("away"))) status = ID_STATUS_AWAY;
+ else if ( !_tcscmp( showNode->text , _T("xa"))) status = ID_STATUS_NA;
+ else if ( !_tcscmp( showNode->text , _T("dnd"))) status = ID_STATUS_DND;
+ else if ( !_tcscmp( showNode->text , _T("chat"))) status = ID_STATUS_FREECHAT;
+ } }
+
+ TCHAR* str;
+ if (( statusNode=JabberXmlGetChild( node, "status" ))!=NULL && statusNode->text!=NULL )
+ str = statusNode->text;
+ else
+ str = NULL;
+ newRes = ( JabberListAddResource( LIST_CHATROOM, from, status, str ) == 0 ) ? 0 : GC_EVENT_JOIN;
+
+ roomCreated = FALSE;
+
+ // Check additional MUC info for this user
+ if ( xNode != NULL ) {
+ if (( itemNode=JabberXmlGetChild( xNode, "item" )) != NULL ) {
+ JABBER_RESOURCE_STATUS* r = item->resource;
+ for ( i=0; i<item->resourceCount && _tcscmp( r->resourceName, nick ); i++, r++ );
+ if ( i < item->resourceCount ) {
+ if (( str=JabberXmlGetAttrValue( itemNode, "affiliation" )) != NULL ) {
+ if ( !_tcscmp( str, _T("owner"))) r->affiliation = AFFILIATION_OWNER;
+ else if ( !_tcscmp( str, _T("admin"))) r->affiliation = AFFILIATION_ADMIN;
+ else if ( !_tcscmp( str, _T("member"))) r->affiliation = AFFILIATION_MEMBER;
+ else if ( !_tcscmp( str, _T("outcast"))) r->affiliation = AFFILIATION_OUTCAST;
+ }
+ if (( str=JabberXmlGetAttrValue( itemNode, "role" )) != NULL ) {
+ JABBER_GC_ROLE newRole = r->role;
+
+ if ( !_tcscmp( str, _T("moderator"))) newRole = ROLE_MODERATOR;
+ else if ( !_tcscmp( str, _T("participant"))) newRole = ROLE_PARTICIPANT;
+ else if ( !_tcscmp( str, _T("visitor"))) newRole = ROLE_VISITOR;
+ else newRole = ROLE_NONE;
+
+ if ( newRole != r->role && r->role != ROLE_NONE ) {
+ JabberGcLogUpdateMemberStatus( item, nick, GC_EVENT_REMOVESTATUS, NULL );
+ newRes = GC_EVENT_ADDSTATUS;
+ }
+ r->role = newRole;
+ } } }
+
+ if ( sttGetStatusCode( xNode ) == 201 )
+ roomCreated = TRUE;
+ }
+
+ // Update groupchat log window
+ JabberGcLogUpdateMemberStatus( item, nick, newRes, NULL );
+
+ HANDLE hContact = JabberHContactFromJID( from );
+ if ( hContact != NULL )
+ JSetWord( hContact, "Status", status );
+
+ // Update room status
+ //if ( item->status != ID_STATUS_ONLINE ) {
+ // item->status = ID_STATUS_ONLINE;
+ // JSetWord( hContact, "Status", ( WORD )ID_STATUS_ONLINE );
+ // JabberLog( "Room %s online", from );
+ //}
+
+ // Check <created/>
+ if ( roomCreated ||
+ (( n=JabberXmlGetChild( node, "created" ))!=NULL &&
+ ( str=JabberXmlGetAttrValue( n, "xmlns" ))!=NULL &&
+ !_tcscmp( str, _T("http://jabber.org/protocol/muc#owner"))) ) {
+ // A new room just created by me
+ // Request room config
+ int iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_NONE, JabberIqResultGetMuc );
+
+ XmlNodeIq iq( "get", iqId, item->jid );
+ XmlNode* query = iq.addQuery( xmlnsOwner );
+ JabberSend( jabberThreadInfo->s, iq );
+ }
+
+ mir_free( room );
+ }
+ else if ( !lstrcmp( type, _T("unavailable"))) {
+ if ( xNode != NULL && item->nick != NULL ) {
+ itemNode = JabberXmlGetChild( xNode, "item" );
+ XmlNode* reasonNode = JabberXmlGetChild( itemNode, "reason" );
+
+ if ( !lstrcmp( nick, item->nick )) {
+ int iStatus = sttGetStatusCode( xNode );
+ switch( iStatus ) {
+ case 301: case 307:
+ JabberGcQuit( item, iStatus, reasonNode );
+ break;
+
+ case 303:
+ sttRenameParticipantNick( item, nick, itemNode );
+ return;
+ } }
+ else {
+ switch( sttGetStatusCode( xNode )) {
+ case 303:
+ sttRenameParticipantNick( item, nick, itemNode );
+ return;
+
+ case 307:
+ JabberListRemoveResource( LIST_CHATROOM, from );
+ JabberGcLogUpdateMemberStatus( item, nick, GC_EVENT_KICK, reasonNode );
+ return;
+ } } }
+
+ JabberListRemoveResource( LIST_CHATROOM, from );
+ JabberGcLogUpdateMemberStatus( item, nick, GC_EVENT_PART, NULL );
+ }
+ else if ( !lstrcmp( type, _T("error"))) {
+ errorNode = JabberXmlGetChild( node, "error" );
+ TCHAR* str = JabberErrorMsg( errorNode );
+ MessageBox( NULL, str, TranslateT( "Jabber Error Message" ), MB_OK|MB_SETFOREGROUND );
+ //JabberListRemoveResource( LIST_CHATROOM, from );
+ JabberListRemove( LIST_CHATROOM, from );
+ mir_free( str );
+} }
+
+void strdel( char* parBuffer, int len )
+{
+ char* p;
+ for ( p = parBuffer+len; *p != 0; p++ )
+ p[ -len ] = *p;
+
+ p[ -len ] = '\0';
+}
+
+void JabberGroupchatProcessMessage( XmlNode *node, void *userdata )
+{
+ struct ThreadData *info;
+ XmlNode *n, *xNode;
+ TCHAR* from, *type, *p, *nick, *msgText;
+ JABBER_LIST_ITEM *item;
+
+ if ( !node->name || strcmp( node->name, "message" )) return;
+ if (( info=( struct ThreadData * ) userdata ) == NULL ) return;
+ if (( from = JabberXmlGetAttrValue( node, "from" )) == NULL ) return;
+ if (( item = JabberListGetItemPtr( LIST_CHATROOM, from )) == NULL ) return;
+
+ if (( type = JabberXmlGetAttrValue( node, "type" )) == NULL ) return;
+ if ( !lstrcmp( type, _T("error")))
+ return;
+
+ #if defined( _UNICODE )
+ char* jid = u2a( item->jid );
+ #else
+ char* jid = item->jid;
+ #endif
+ GCDEST gcd = { jabberProtoName, jid, 0 };
+
+ if (( n = JabberXmlGetChild( node, "subject" )) != NULL ) {
+ if ( n->text == NULL || n->text[0] == '\0' )
+ return;
+
+ msgText = n->text;
+
+ gcd.iType = GC_EVENT_TOPIC;
+
+ if ( from != NULL ) {
+ nick = _tcschr( from, '/' );
+ if ( nick == NULL || nick[1] == '\0' )
+ nick = NULL;
+ else
+ nick++;
+ }
+ else nick = NULL;
+ }
+ else {
+ if (( n = JabberXmlGetChild( node, "body" )) == NULL ) return;
+ if ( n->text == NULL )
+ return;
+
+ nick = _tcschr( from, '/' );
+ if ( nick == NULL || nick[1] == '\0' )
+ return;
+ nick++;
+
+ msgText = n->text;
+
+ if ( _tcsncmp( msgText, _T("/me "), 4 ) == 0 && _tcslen( msgText ) > 4 ) {
+ msgText += 4;
+ gcd.iType = GC_EVENT_ACTION;
+ }
+ else gcd.iType = GC_EVENT_MESSAGE;
+ }
+
+ JabberGcLogCreate( item );
+
+ time_t msgTime = 0;
+ BOOL delivered = FALSE;
+ for ( int i = 1; ( xNode=JabberXmlGetNthChild( node, "x", i )) != NULL; i++ )
+ if (( p=JabberXmlGetAttrValue( xNode, "xmlns" )) != NULL )
+ if ( !_tcscmp( p, _T("jabber:x:delay")) && msgTime==0 )
+ if (( p=JabberXmlGetAttrValue( xNode, "stamp" )) != NULL )
+ msgTime = JabberIsoToUnixTime( p );
+
+ time_t now = time( NULL );
+ if ( msgTime == 0 || msgTime > now )
+ msgTime = now;
+
+ #if defined( _UNICODE )
+ char* dispNick = u2a( nick );
+ char* dispMsg = u2a( msgText );
+ #else
+ char* dispNick = nick;
+ char* dispMsg = msgText;
+ #endif
+
+ GCEVENT gce = {0};
+ gce.cbSize = sizeof(GCEVENT);
+ gce.pDest = &gcd;
+ gce.pszUID = dispNick;
+ gce.pszNick = dispNick;
+ gce.bAddToLog = TRUE;
+ gce.time = msgTime;
+ gce.pszText = EscapeChatTags( dispMsg );
+ gce.bIsMe = lstrcmp( nick, item->nick ) == 0;
+ JCallService(MS_GC_EVENT, NULL, (LPARAM)&gce);
+
+ item->bChatActive = 2;
+
+ if ( gcd.iType == GC_EVENT_TOPIC ) {
+ gce.bAddToLog = FALSE;
+ gcd.iType = GC_EVENT_SETSBTEXT;
+ JCallService(MS_GC_EVENT, NULL, (LPARAM)&gce);
+ }
+
+ #if defined( _UNICODE )
+ mir_free( dispNick );
+ mir_free( dispMsg );
+ mir_free( jid );
+ #endif
+ mir_free( (void*)gce.pszText ); // Since we processed msgText and created a new string
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Accepting groupchat invitations
+
+typedef struct {
+ TCHAR* roomJid;
+ TCHAR* from;
+ TCHAR* reason;
+ TCHAR* password;
+}
+ JABBER_GROUPCHAT_INVITE_INFO;
+
+static void JabberAcceptGroupchatInvite( TCHAR* roomJid, TCHAR* reason, TCHAR* password )
+{
+ TCHAR room[256], *server, *p;
+ _tcsncpy( room, roomJid, SIZEOF( room ));
+ p = _tcstok( room, _T( "@" ));
+ server = _tcstok( NULL, _T( "@" ));
+ JabberGroupchatJoinRoom( server, p, reason, password );
+}
+
+static BOOL CALLBACK JabberGroupchatInviteAcceptDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ {
+ JABBER_GROUPCHAT_INVITE_INFO *inviteInfo = ( JABBER_GROUPCHAT_INVITE_INFO * ) lParam;
+
+ TranslateDialogDefault( hwndDlg );
+ SetWindowLong( hwndDlg, GWL_USERDATA, ( LONG ) inviteInfo );
+ SetDlgItemText( hwndDlg, IDC_FROM, inviteInfo->from );
+ SetDlgItemText( hwndDlg, IDC_ROOM, inviteInfo->roomJid );
+
+ if ( inviteInfo->reason != NULL )
+ SetDlgItemText( hwndDlg, IDC_REASON, inviteInfo->reason );
+
+ TCHAR* myNick = JabberNickFromJID( jabberJID );
+ SetDlgItemText( hwndDlg, IDC_NICK, myNick );
+ mir_free( myNick );
+
+ SendMessage( hwndDlg, WM_SETICON, ICON_BIG, ( LPARAM )LoadIcon( hInst, MAKEINTRESOURCE( IDI_GROUP )) );
+ }
+ return TRUE;
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDC_ACCEPT:
+ {
+ JABBER_GROUPCHAT_INVITE_INFO *inviteInfo = ( JABBER_GROUPCHAT_INVITE_INFO * ) GetWindowLong( hwndDlg, GWL_USERDATA );
+ TCHAR text[128];
+ GetDlgItemText( hwndDlg, IDC_NICK, text, SIZEOF( text ));
+ JabberAcceptGroupchatInvite( inviteInfo->roomJid, text, inviteInfo->password );
+ }
+ // Fall through
+ case IDCANCEL:
+ case IDCLOSE:
+ EndDialog( hwndDlg, 0 );
+ return TRUE;
+ }
+ break;
+ case WM_CLOSE:
+ EndDialog( hwndDlg, 0 );
+ break;
+ }
+
+ return FALSE;
+}
+
+static void __cdecl JabberGroupchatInviteAcceptThread( JABBER_GROUPCHAT_INVITE_INFO *inviteInfo )
+{
+ DialogBoxParam( hInst, MAKEINTRESOURCE( IDD_GROUPCHAT_INVITE_ACCEPT ), NULL, JabberGroupchatInviteAcceptDlgProc, ( LPARAM )inviteInfo );
+ mir_free( inviteInfo->roomJid );
+ mir_free( inviteInfo->from );
+ mir_free( inviteInfo->reason );
+ mir_free( inviteInfo->password );
+ mir_free( inviteInfo );
+}
+
+void JabberGroupchatProcessInvite( TCHAR* roomJid, TCHAR* from, TCHAR* reason, TCHAR* password )
+{
+ if ( roomJid == NULL )
+ return;
+
+ if ( JGetByte( "AutoAcceptMUC", FALSE ) == FALSE ) {
+ JABBER_GROUPCHAT_INVITE_INFO* inviteInfo = ( JABBER_GROUPCHAT_INVITE_INFO * ) mir_alloc( sizeof( JABBER_GROUPCHAT_INVITE_INFO ));
+ inviteInfo->roomJid = mir_tstrdup( roomJid );
+ inviteInfo->from = mir_tstrdup( from );
+ inviteInfo->reason = mir_tstrdup( reason );
+ inviteInfo->password = mir_tstrdup( password );
+ JabberForkThread(( JABBER_THREAD_FUNC )JabberGroupchatInviteAcceptThread, 0, ( void* )inviteInfo );
+ }
+ else {
+ TCHAR* myNick = JabberNickFromJID( jabberJID );
+ JabberAcceptGroupchatInvite( roomJid, myNick, password );
+ mir_free( myNick );
+} }
diff --git a/miranda-wine/protocols/JabberG/jabber_iq.cpp b/miranda-wine/protocols/JabberG/jabber_iq.cpp new file mode 100644 index 0000000..4b0d90d --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_iq.cpp @@ -0,0 +1,173 @@ +/*
+
+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_iq.cpp,v $
+Revision : $Revision: 2866 $
+Last change on : $Date: 2006-05-16 20:39:40 +0400 (Втр, 16 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+#include "jabber_iq.h"
+#include "jabber_xmlns.h"
+
+static JABBER_IQ_XMLNS_FUNC jabberXmlns[] = {
+ { _T("http://jabber.org/protocol/disco"), JabberXmlnsDisco, TRUE },
+ { _T("jabber:iq:browse"), JabberXmlnsBrowse, FALSE }
+};
+
+typedef struct {
+ int iqId; // id to match IQ get/set with IQ result
+ JABBER_IQ_PROCID procId; // must be unique in the list, except for IQ_PROC_NONE which can have multiple entries
+ JABBER_IQ_PFUNC func; // callback function
+ time_t requestTime; // time the request was sent, used to remove relinquent entries
+} JABBER_IQ_FUNC;
+
+static CRITICAL_SECTION csIqList;
+static JABBER_IQ_FUNC *iqList;
+static int iqCount;
+static int iqAlloced;
+
+void JabberIqInit()
+{
+ InitializeCriticalSection( &csIqList );
+ iqList = NULL;
+ iqCount = 0;
+ iqAlloced = 0;
+}
+
+void JabberIqUninit()
+{
+ if ( iqList ) mir_free( iqList );
+ iqList = NULL;
+ iqCount = 0;
+ iqAlloced = 0;
+ DeleteCriticalSection( &csIqList );
+}
+
+static void JabberIqRemove( int index )
+{
+ EnterCriticalSection( &csIqList );
+ if ( index>=0 && index<iqCount ) {
+ memmove( iqList+index, iqList+index+1, sizeof( JABBER_IQ_FUNC )*( iqCount-index-1 ));
+ iqCount--;
+ }
+ LeaveCriticalSection( &csIqList );
+}
+
+static void JabberIqExpire()
+{
+ int i;
+ time_t expire;
+
+ EnterCriticalSection( &csIqList );
+ expire = time( NULL ) - 120; // 2 minute
+ i = 0;
+ while ( i < iqCount ) {
+ if ( iqList[i].requestTime < expire )
+ JabberIqRemove( i );
+ else
+ i++;
+ }
+ LeaveCriticalSection( &csIqList );
+}
+
+JABBER_IQ_PFUNC JabberIqFetchFunc( int iqId )
+{
+ int i;
+ JABBER_IQ_PFUNC res;
+
+ EnterCriticalSection( &csIqList );
+ JabberIqExpire();
+#ifdef _DEBUG
+ for ( i=0; i<iqCount; i++ )
+ JabberLog( " %04d : %02d : 0x%x", iqList[i].iqId, iqList[i].procId, iqList[i].func );
+#endif
+ for ( i=0; i<iqCount && iqList[i].iqId!=iqId; i++ );
+ if ( i < iqCount ) {
+ res = iqList[i].func;
+ JabberIqRemove( i );
+ }
+ else {
+ res = ( JABBER_IQ_PFUNC ) NULL;
+ }
+ LeaveCriticalSection( &csIqList );
+ return res;
+}
+
+void JabberIqAdd( unsigned int iqId, JABBER_IQ_PROCID procId, JABBER_IQ_PFUNC func )
+{
+ int i;
+
+ EnterCriticalSection( &csIqList );
+ JabberLog( "IqAdd id=%d, proc=%d, func=0x%x", iqId, procId, func );
+ if ( procId == IQ_PROC_NONE )
+ i = iqCount;
+ else
+ for ( i=0; i<iqCount && iqList[i].procId!=procId; i++ );
+
+ if ( i>=iqCount && iqCount>=iqAlloced ) {
+ iqAlloced = iqCount + 8;
+ iqList = ( JABBER_IQ_FUNC * )mir_realloc( iqList, sizeof( JABBER_IQ_FUNC )*iqAlloced );
+ }
+
+ if ( iqList != NULL ) {
+ iqList[i].iqId = iqId;
+ iqList[i].procId = procId;
+ iqList[i].func = func;
+ iqList[i].requestTime = time( NULL );
+ if ( i == iqCount ) iqCount++;
+ }
+ LeaveCriticalSection( &csIqList );
+}
+
+JABBER_IQ_PFUNC JabberIqFetchXmlnsFunc( TCHAR* xmlns )
+{
+ unsigned int len, count, i;
+ TCHAR* p, *q;
+
+ if ( xmlns == NULL )
+ return NULL;
+
+ p = _tcsrchr( xmlns, '/' );
+ q = _tcsrchr( xmlns, '#' );
+ if ( p!=NULL && q!=NULL && q>p )
+ len = q - xmlns;
+ else
+ len = _tcslen( xmlns );
+
+ count = sizeof( jabberXmlns ) / sizeof( jabberXmlns[0] );
+ for ( i=0; i<count; i++ ) {
+ if ( jabberXmlns[i].allowSubNs ) {
+ if ( _tcslen( jabberXmlns[i].xmlns ) == len && !_tcsncmp( jabberXmlns[i].xmlns, xmlns, len ))
+ break;
+ }
+ else {
+ if ( !_tcscmp( jabberXmlns[i].xmlns, xmlns ))
+ break;
+ }
+ }
+
+ if ( i < count )
+ return jabberXmlns[i].func;
+
+ return NULL;
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_iq.h b/miranda-wine/protocols/JabberG/jabber_iq.h new file mode 100644 index 0000000..35a95e5 --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_iq.h @@ -0,0 +1,87 @@ +/*
+
+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_iq.h,v $
+Revision : $Revision: 3703 $
+Last change on : $Date: 2006-09-05 17:54:42 +0400 (Втр, 05 Сен 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#ifndef _JABBER_IQ_H_
+#define _JABBER_IQ_H_
+
+#include "jabber_xml.h"
+
+typedef enum {
+ IQ_PROC_NONE,
+ IQ_PROC_GETAGENTS,
+ IQ_PROC_GETREGISTER,
+ IQ_PROC_SETREGISTER,
+ IQ_PROC_GETVCARD,
+ IQ_PROC_SETVCARD,
+ IQ_PROC_GETSEARCH,
+ IQ_PROC_BROWSEROOMS,
+ IQ_PROC_DISCOROOMSERVER,
+ IQ_PROC_DISCOAGENTS
+} JABBER_IQ_PROCID;
+
+typedef void ( *JABBER_IQ_PFUNC )( XmlNode *iqNode, void *usedata );
+
+typedef struct {
+ TCHAR* xmlns;
+ JABBER_IQ_PFUNC func;
+ BOOL allowSubNs; // e.g. #info in disco#info
+} JABBER_IQ_XMLNS_FUNC;
+
+void JabberIqInit();
+void JabberIqUninit();
+JABBER_IQ_PFUNC JabberIqFetchFunc( int iqId );
+void JabberIqAdd( unsigned int iqId, JABBER_IQ_PROCID procId, JABBER_IQ_PFUNC func );
+JABBER_IQ_PFUNC JabberIqFetchXmlnsFunc( TCHAR* xmlns );
+
+void JabberIqResultBind( XmlNode *iqNode, void *userdata );
+void JabberIqResultBrowseRooms( XmlNode *iqNode, void *userdata );
+void JabberIqResultDiscoAgentInfo( XmlNode *iqNode, void *userdata );
+void JabberIqResultDiscoAgentItems( XmlNode *iqNode, void *userdata );
+void JabberIqResultDiscoClientInfo( XmlNode *iqNode, void *userdata );
+void JabberIqResultDiscoRoomItems( XmlNode *iqNode, void *userdata );
+void JabberIqResultExtSearch( XmlNode *iqNode, void *userdata );
+void JabberIqResultGetAgents( XmlNode *iqNode, void *userdata );
+void JabberIqResultGetAuth( XmlNode *iqNode, void *userdata );
+void JabberIqResultGetAvatar( XmlNode *iqNode, void *userdata );
+void JabberIqResultGetMuc( XmlNode *iqNode, void *userdata );
+void JabberIqResultGetRegister( XmlNode *iqNode, void *userdata );
+void JabberIqResultGetRoster( XmlNode *iqNode, void *userdata );
+void JabberIqResultGetVcard( XmlNode *iqNode, void *userdata );
+void JabberIqResultMucGetAdminList( XmlNode *iqNode, void *userdata );
+void JabberIqResultMucGetBanList( XmlNode *iqNode, void *userdata );
+void JabberIqResultMucGetMemberList( XmlNode *iqNode, void *userdata );
+void JabberIqResultMucGetModeratorList( XmlNode *iqNode, void *userdata );
+void JabberIqResultMucGetOwnerList( XmlNode *iqNode, void *userdata );
+void JabberIqResultMucGetVoiceList( XmlNode *iqNode, void *userdata );
+void JabberIqResultSession( XmlNode *iqNode, void *userdata );
+void JabberIqResultSetAuth( XmlNode *iqNode, void *userdata );
+void JabberIqResultSetPassword( XmlNode *iqNode, void *userdata );
+void JabberIqResultSetRegister( XmlNode *iqNode, void *userdata );
+void JabberIqResultSetSearch( XmlNode *iqNode, void *userdata );
+void JabberIqResultSetVcard( XmlNode *iqNode, void *userdata );
+
+#endif
diff --git a/miranda-wine/protocols/JabberG/jabber_iqid.cpp b/miranda-wine/protocols/JabberG/jabber_iqid.cpp new file mode 100644 index 0000000..67b4808 --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_iqid.cpp @@ -0,0 +1,1429 @@ +/*
+
+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( "<iq/> 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, "</stream:stream>" );
+ return;
+ }
+
+ if ( JabberXmlGetChild( queryNode, "resource" ) != NULL )
+ query->addChild( "resource", info->resource );
+
+ JabberSend( info->s, iq );
+ }
+ else if ( !lstrcmp( type, _T("error"))) {
+ JabberSend( info->s, "</stream:stream>" );
+
+ 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( "<iq/> 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, "</stream:stream>" );
+ 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, "</stream:stream>" );
+ 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( "<iq/> 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( "<iq/> 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; i<queryNode->numChild; 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 <grouchat/> so we will
+ // also treat <service>public</service> 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( "<iq/> 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( "<iq/> 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( "<iq/> 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; i<vCardNode->numChild; 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 <EMAIL/> instead of <USERID/>
+ 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 <COUNTRY/> instead of <CTRY/>
+ 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 <COUNTRY/> instead of <CTRY/>
+ 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 <ORGUNIT/> 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( "<iq/> 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( "<iq/> 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; i<queryNode->numChild; 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( "<iq/> 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; i<queryNode->numChild; 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( "<iq/> 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( "<iq/> 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; i<queryNode->numChild; 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( "<iq/> 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 <identity/> 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; i<queryNode->numChild; 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( "<iq/> 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; i<queryNode->numChild; 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( "<iq/> 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 );
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_iqid_muc.cpp b/miranda-wine/protocols/JabberG/jabber_iqid_muc.cpp new file mode 100644 index 0000000..114931d --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_iqid_muc.cpp @@ -0,0 +1,531 @@ +/*
+
+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_muc.cpp,v $
+Revision : $Revision: 2866 $
+Last change on : $Date: 2006-05-16 20:39:40 +0400 (Втр, 16 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+#include "resource.h"
+#include "jabber_list.h"
+#include "jabber_iq.h"
+#include <commctrl.h>
+
+void JabberAddMucListItem( JABBER_MUC_JIDLIST_INFO* jidListInfo, TCHAR* str );
+void JabberDeleteMucListItem( JABBER_MUC_JIDLIST_INFO* jidListInfo, TCHAR* str );
+BOOL JabberEnterString( TCHAR* result, size_t resultLen );
+
+void JabberIqResultBrowseRooms( XmlNode *iqNode, void *userdata )
+{
+ struct ThreadData *info = ( struct ThreadData * ) userdata;
+ XmlNode *confNode, *roomNode;
+ TCHAR* type, *category, *jid, *str;
+ JABBER_LIST_ITEM *item;
+ int i, j;
+
+ // RECVED: room list
+ // ACTION: refresh groupchat room list dialog
+ JabberLog( "<iq/> iqIdBrowseRooms" );
+ if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return;
+
+ if ( !lstrcmp( type, _T("result"))) {
+ JabberListRemoveList( LIST_ROOM );
+ for ( i=0; i<iqNode->numChild; i++ ) {
+ if (( confNode=iqNode->child[i] )!=NULL && confNode->name!=NULL ) {
+ if ( !strcmp( confNode->name, "item" )) {
+ if (( category=JabberXmlGetAttrValue( confNode, "category" ))!=NULL && !lstrcmp( category, _T("conference"))) {
+ for ( j=0; j<confNode->numChild; j++ ) {
+ if (( roomNode=confNode->child[j] )!=NULL && !strcmp( roomNode->name, "item" )) {
+ if (( category=JabberXmlGetAttrValue( roomNode, "category" ))!=NULL && !lstrcmp( category, _T("conference"))) {
+ if (( jid=JabberXmlGetAttrValue( roomNode, "jid" )) != NULL ) {
+ item = JabberListAdd( LIST_ROOM, jid );
+ if (( str=JabberXmlGetAttrValue( roomNode, "name" )) != NULL )
+ item->name = mir_tstrdup( str );
+ if (( str=JabberXmlGetAttrValue( roomNode, "type" )) != NULL )
+ item->type = mir_tstrdup( str );
+ } } } } }
+ }
+ else if ( !strcmp( confNode->name, "conference" )) {
+ for ( j=0; j<confNode->numChild; j++ ) {
+ if (( roomNode=confNode->child[j] )!=NULL && !strcmp( roomNode->name, "conference" )) {
+ if (( jid=JabberXmlGetAttrValue( roomNode, "jid" )) != NULL ) {
+ item = JabberListAdd( LIST_ROOM, jid );
+ if (( str=JabberXmlGetAttrValue( roomNode, "name" )) != NULL )
+ item->name = mir_tstrdup( str );
+ if (( str=JabberXmlGetAttrValue( roomNode, "type" )) != NULL )
+ item->type = mir_tstrdup( str );
+ } } } } } }
+
+ if ( hwndJabberGroupchat != NULL ) {
+ if (( jid=JabberXmlGetAttrValue( iqNode, "from" )) != NULL )
+ SendMessage( hwndJabberGroupchat, WM_JABBER_REFRESH, 0, ( LPARAM )jid );
+ else
+ SendMessage( hwndJabberGroupchat, WM_JABBER_REFRESH, 0, ( LPARAM )info->server );
+ }
+ }
+}
+
+void JabberSetMucConfig( XmlNode* node, void *from )
+{
+ if ( jabberThreadInfo && from ) {
+ XmlNodeIq iq( "set", NOID, ( TCHAR* )from );
+ XmlNode* query = iq.addQuery( xmlnsOwner );
+ query->addChild( node );
+ JabberSend( jabberThreadInfo->s, iq );
+} }
+
+void JabberIqResultGetMuc( XmlNode *iqNode, void *userdata )
+{
+ XmlNode *queryNode, *xNode;
+ TCHAR *type, *from, *str;
+
+ // RECVED: room config form
+ // ACTION: show the form
+ JabberLog( "<iq/> iqIdGetMuc" );
+ if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return;
+ if (( from=JabberXmlGetAttrValue( iqNode, "from" )) == NULL ) return;
+
+ if ( !_tcscmp( type, _T("result"))) {
+ if (( queryNode=JabberXmlGetChild( iqNode, "query" )) != NULL ) {
+ str = JabberXmlGetAttrValue( queryNode, "xmlns" );
+ if ( !lstrcmp( str, _T("http://jabber.org/protocol/muc#owner" ))) {
+ if (( xNode=JabberXmlGetChild( queryNode, "x" )) != NULL ) {
+ str = JabberXmlGetAttrValue( xNode, "xmlns" );
+ if ( !lstrcmp( str, _T("jabber:x:data" )))
+ JabberFormCreateDialog( xNode, _T("Jabber Conference Room Configuration"), JabberSetMucConfig, mir_tstrdup( from ));
+} } } } }
+
+void JabberIqResultDiscoRoomItems( XmlNode *iqNode, void *userdata )
+{
+ struct ThreadData *info = ( struct ThreadData * ) userdata;
+ XmlNode *queryNode, *itemNode;
+ TCHAR* type, *jid, *from;
+ JABBER_LIST_ITEM *item;
+ int i;
+ int iqId;
+
+ // RECVED: room list
+ // ACTION: refresh groupchat room list dialog
+ JabberLog( "<iq/> iqIdDiscoRoomItems" );
+ 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 ) {
+ JabberListRemoveList( LIST_ROOM );
+ for ( i=0; i<queryNode->numChild; i++ ) {
+ if (( itemNode=queryNode->child[i] )!=NULL && itemNode->name!=NULL && !strcmp( itemNode->name, "item" )) {
+ if (( jid=JabberXmlGetAttrValue( itemNode, "jid" )) != NULL ) {
+ item = JabberListAdd( LIST_ROOM, jid );
+ item->name = mir_tstrdup( JabberXmlGetAttrValue( itemNode, "name" ));
+ } } } }
+
+ if ( hwndJabberGroupchat != NULL ) {
+ if (( jid=JabberXmlGetAttrValue( iqNode, "from" )) != NULL )
+ SendMessage( hwndJabberGroupchat, WM_JABBER_REFRESH, 0, ( LPARAM )jid );
+ else
+ SendMessage( hwndJabberGroupchat, WM_JABBER_REFRESH, 0, ( LPARAM )info->server );
+ }
+ }
+ else if ( !_tcscmp( type, _T("error"))) {
+ // disco is not supported, try browse
+ iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_BROWSEROOMS, JabberIqResultBrowseRooms );
+
+ XmlNodeIq iq( "get", iqId, from );
+ XmlNode* query = iq.addQuery( "jabber:iq:browse" );
+ JabberSend( jabberThreadInfo->s, iq );
+} }
+
+static BOOL CALLBACK JabberMucJidListDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ switch( msg ) {
+ case WM_INITDIALOG:
+ {
+ // lParam is ( JABBER_MUC_JIDLIST_INFO * )
+ LVCOLUMN lvc;
+ RECT rc;
+ HWND hwndList;
+
+ TranslateDialogDefault( hwndDlg );
+ hwndList = GetDlgItem( hwndDlg, IDC_LIST );
+ GetClientRect( hwndList, &rc );
+ rc.right -= GetSystemMetrics( SM_CXVSCROLL );
+ lvc.mask = LVCF_WIDTH;
+ lvc.cx = rc.right - 20;
+ ListView_InsertColumn( hwndList, 0, &lvc );
+ lvc.cx = 20;
+ ListView_InsertColumn( hwndList, 1, &lvc );
+ SendMessage( hwndDlg, WM_JABBER_REFRESH, 0, lParam );
+ }
+ return TRUE;
+ case WM_JABBER_REFRESH:
+ {
+ // lParam is ( JABBER_MUC_JIDLIST_INFO * )
+ JABBER_MUC_JIDLIST_INFO *jidListInfo;
+ XmlNode *iqNode, *queryNode, *itemNode;
+ TCHAR* from, *jid, *localFrom;
+ LVITEM lvi;
+ HWND hwndList;
+ int count, i;
+ TCHAR title[256];
+
+ // Clear current GWL_USERDATA, if any
+ jidListInfo = ( JABBER_MUC_JIDLIST_INFO * ) GetWindowLong( hwndDlg, GWL_USERDATA );
+ if ( jidListInfo != NULL ) {
+ if ( jidListInfo->roomJid != NULL )
+ mir_free( jidListInfo->roomJid );
+ if ( jidListInfo->iqNode != NULL )
+ delete jidListInfo->iqNode;
+ mir_free( jidListInfo );
+ }
+
+ // Clear current displayed list
+ hwndList = GetDlgItem( hwndDlg, IDC_LIST );
+ count = ListView_GetItemCount( hwndList );
+ lvi.mask = LVIF_PARAM;
+ lvi.iSubItem = 0;
+ for ( i=0; i<count; i++ ) {
+ lvi.iItem = i;
+ if ( ListView_GetItem( hwndList, &lvi ) == TRUE ) {
+ if ( lvi.lParam!=( LPARAM )( -1 ) && lvi.lParam!=( LPARAM )( NULL )) {
+ mir_free(( void * ) lvi.lParam );
+ }
+ }
+ }
+ ListView_DeleteAllItems( hwndList );
+
+ // Set new GWL_USERDATA
+ jidListInfo = ( JABBER_MUC_JIDLIST_INFO * ) lParam;
+ SetWindowLong( hwndDlg, GWL_USERDATA, ( LONG ) jidListInfo );
+
+ // Populate displayed list from iqNode
+ lstrcpyn( title, TranslateT( "JID List" ), SIZEOF( title ));
+ if (( jidListInfo=( JABBER_MUC_JIDLIST_INFO * ) lParam ) != NULL ) {
+ if (( iqNode = jidListInfo->iqNode ) != NULL ) {
+ if (( from = JabberXmlGetAttrValue( iqNode, "from" )) != NULL ) {
+ jidListInfo->roomJid = mir_tstrdup( from );
+ localFrom = mir_tstrdup( from );
+ mir_sntprintf( title, SIZEOF( title ), _T("%s ( %s )"),
+ ( jidListInfo->type==MUC_VOICELIST ) ? TranslateT( "Voice List" ) :
+ ( jidListInfo->type==MUC_MEMBERLIST ) ? TranslateT( "Member List" ) :
+ ( jidListInfo->type==MUC_MODERATORLIST ) ? TranslateT( "Moderator List" ) :
+ ( jidListInfo->type==MUC_BANLIST ) ? TranslateT( "Ban List" ) :
+ ( jidListInfo->type==MUC_ADMINLIST ) ? TranslateT( "Admin List" ) :
+ ( jidListInfo->type==MUC_OWNERLIST ) ? TranslateT( "Owner List" ) :
+ TranslateT( "JID List" ),
+ localFrom );
+ mir_free( localFrom );
+ if (( queryNode=JabberXmlGetChild( iqNode, "query" )) != NULL ) {
+ lvi.mask = LVIF_TEXT | LVIF_PARAM;
+ lvi.iSubItem = 0;
+ lvi.iItem = 0;
+ for ( i=0; i<queryNode->numChild; i++ ) {
+ if (( itemNode=queryNode->child[i] ) != NULL ) {
+ if (( jid=JabberXmlGetAttrValue( itemNode, "jid" )) != NULL ) {
+ lvi.pszText = jid;
+ lvi.lParam = ( LPARAM )mir_tstrdup( jid );
+ ListView_InsertItem( hwndList, &lvi );
+ lvi.iItem++;
+ } } } } } }
+
+ lvi.mask = LVIF_PARAM;
+ lvi.lParam = ( LPARAM )( -1 );
+ ListView_InsertItem( hwndList, &lvi );
+ }
+ SetWindowText( hwndDlg, title );
+ }
+ break;
+ case WM_NOTIFY:
+ if (( ( LPNMHDR )lParam )->idFrom == IDC_LIST ) {
+ switch (( ( LPNMHDR )lParam )->code ) {
+ case NM_CUSTOMDRAW:
+ {
+ NMLVCUSTOMDRAW *nm = ( NMLVCUSTOMDRAW * ) lParam;
+
+ switch ( nm->nmcd.dwDrawStage ) {
+ case CDDS_PREPAINT:
+ case CDDS_ITEMPREPAINT:
+ SetWindowLong( hwndDlg, DWL_MSGRESULT, CDRF_NOTIFYSUBITEMDRAW );
+ return TRUE;
+ case CDDS_SUBITEM|CDDS_ITEMPREPAINT:
+ {
+ RECT rc;
+ HICON hIcon;
+
+ ListView_GetSubItemRect( nm->nmcd.hdr.hwndFrom, nm->nmcd.dwItemSpec, nm->iSubItem, LVIR_LABEL, &rc );
+ if ( nm->iSubItem == 1 ) {
+ if( nm->nmcd.lItemlParam == ( LPARAM )( -1 ))
+ hIcon = ( HICON )LoadImage( hInst, MAKEINTRESOURCE( IDI_ADDCONTACT ), IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), 0 );
+ else
+ hIcon = ( HICON )LoadImage( hInst, MAKEINTRESOURCE( IDI_DELETE ), IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), 0 );
+ DrawIconEx( nm->nmcd.hdc, ( rc.left+rc.right-GetSystemMetrics( SM_CXSMICON ))/2, ( rc.top+rc.bottom-GetSystemMetrics( SM_CYSMICON ))/2,hIcon, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), 0, NULL, DI_NORMAL );
+ DestroyIcon( hIcon );
+ SetWindowLong( hwndDlg, DWL_MSGRESULT, CDRF_SKIPDEFAULT );
+ return TRUE;
+ } } } }
+ break;
+ case NM_CLICK:
+ {
+ JABBER_MUC_JIDLIST_INFO *jidListInfo;
+ NMLISTVIEW *nm = ( NMLISTVIEW * ) lParam;
+ LVITEM lvi;
+ LVHITTESTINFO hti;
+ TCHAR text[128];
+
+ if ( nm->iSubItem < 1 ) break;
+ jidListInfo = ( JABBER_MUC_JIDLIST_INFO * ) GetWindowLong( hwndDlg, GWL_USERDATA );
+ hti.pt.x = ( short ) LOWORD( GetMessagePos());
+ hti.pt.y = ( short ) HIWORD( GetMessagePos());
+ ScreenToClient( nm->hdr.hwndFrom, &hti.pt );
+ if ( ListView_SubItemHitTest( nm->hdr.hwndFrom, &hti ) == -1 )
+ break;
+
+ if ( hti.iSubItem != 1 )
+ break;
+
+ lvi.mask = LVIF_PARAM | LVIF_TEXT;
+ lvi.iItem = hti.iItem;
+ lvi.iSubItem = 0;
+ lvi.pszText = text;
+ lvi.cchTextMax = sizeof( text );
+ ListView_GetItem( nm->hdr.hwndFrom, &lvi );
+ if ( lvi.lParam == ( LPARAM )( -1 )) {
+ TCHAR szBuffer[ 1024 ];
+ _tcscpy( szBuffer, jidListInfo->type2str());
+ if ( !JabberEnterString( szBuffer, SIZEOF(szBuffer)))
+ break;
+
+ // Trim leading and trailing whitespaces
+ TCHAR *p = szBuffer, *q;
+ for ( p = szBuffer; *p!='\0' && isspace( BYTE( *p )); p++);
+ for ( q = p; *q!='\0' && !isspace( BYTE( *q )); q++);
+ if (*q != '\0') *q = '\0';
+ if (*p == '\0')
+ break;
+
+ JabberAddMucListItem( jidListInfo, p );
+ }
+ else {
+ //delete
+ TCHAR msgText[128];
+
+ mir_sntprintf( msgText, sizeof( msgText ), _T("%s %s?"), TranslateT( "Removing" ), text );
+ if ( MessageBox( hwndDlg, msgText, jidListInfo->type2str(), MB_YESNO|MB_SETFOREGROUND ) == IDYES ) {
+ JabberDeleteMucListItem( jidListInfo, ( TCHAR* )lvi.lParam );
+ ListView_DeleteItem( nm->hdr.hwndFrom, hti.iItem );
+ } } }
+ break;
+ }
+ break;
+ }
+ break;
+/* case WM_SETCURSOR:
+ if ( LOWORD( LPARAM )!= HTCLIENT ) break;
+ if ( GetForegroundWindow() == GetParent( hwndDlg )) {
+ POINT pt;
+ GetCursorPos( &pt );
+ ScreenToClient( hwndDlg,&pt );
+ SetFocus( ChildWindowFromPoint( hwndDlg,pt )); //ugly hack because listviews ignore their first click
+ }
+ break;
+*/ case WM_CLOSE:
+ {
+ JABBER_MUC_JIDLIST_INFO *jidListInfo;
+ HWND hwndList;
+ int count, i;
+ LVITEM lvi;
+
+ // Free lParam of the displayed list items
+ hwndList = GetDlgItem( hwndDlg, IDC_LIST );
+ count = ListView_GetItemCount( hwndList );
+ lvi.mask = LVIF_PARAM;
+ lvi.iSubItem = 0;
+ for ( i=0; i<count; i++ ) {
+ lvi.iItem = i;
+ if ( ListView_GetItem( hwndList, &lvi ) == TRUE ) {
+ if ( lvi.lParam!=( LPARAM )( -1 ) && lvi.lParam!=( LPARAM )( NULL )) {
+ mir_free(( void * ) lvi.lParam );
+ }
+ }
+ }
+ ListView_DeleteAllItems( hwndList );
+
+ jidListInfo = ( JABBER_MUC_JIDLIST_INFO * ) GetWindowLong( hwndDlg, GWL_USERDATA );
+ switch ( jidListInfo->type ) {
+ case MUC_VOICELIST:
+ hwndMucVoiceList = NULL;
+ break;
+ case MUC_MEMBERLIST:
+ hwndMucMemberList = NULL;
+ break;
+ case MUC_MODERATORLIST:
+ hwndMucModeratorList = NULL;
+ break;
+ case MUC_BANLIST:
+ hwndMucBanList = NULL;
+ break;
+ case MUC_ADMINLIST:
+ hwndMucAdminList = NULL;
+ break;
+ case MUC_OWNERLIST:
+ hwndMucOwnerList = NULL;
+ break;
+ }
+
+ DestroyWindow( hwndDlg );
+ }
+ break;
+ case WM_DESTROY:
+ {
+ JABBER_MUC_JIDLIST_INFO *jidListInfo;
+
+ // Clear GWL_USERDATA
+ jidListInfo = ( JABBER_MUC_JIDLIST_INFO * ) GetWindowLong( hwndDlg, GWL_USERDATA );
+ if ( jidListInfo != NULL ) {
+ if ( jidListInfo->iqNode != NULL )
+ delete jidListInfo->iqNode;
+ if ( jidListInfo->roomJid != NULL )
+ mir_free( jidListInfo->roomJid );
+ mir_free( jidListInfo );
+ }
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static VOID CALLBACK JabberMucJidListCreateDialogApcProc( DWORD param )
+{
+ XmlNode *iqNode, *queryNode;
+ TCHAR* from;
+ JABBER_MUC_JIDLIST_INFO *jidListInfo;
+ HWND *pHwndJidList;
+
+ if (( jidListInfo=( JABBER_MUC_JIDLIST_INFO * ) param ) == NULL ) return;
+ if (( iqNode=jidListInfo->iqNode ) == NULL ) return;
+ if (( from=JabberXmlGetAttrValue( iqNode, "from" )) == NULL ) return;
+ if (( queryNode=JabberXmlGetChild( iqNode, "query" )) == NULL ) return;
+
+ switch ( jidListInfo->type ) {
+ case MUC_VOICELIST:
+ pHwndJidList = &hwndMucVoiceList;
+ break;
+ case MUC_MEMBERLIST:
+ pHwndJidList = &hwndMucMemberList;
+ break;
+ case MUC_MODERATORLIST:
+ pHwndJidList = &hwndMucModeratorList;
+ break;
+ case MUC_BANLIST:
+ pHwndJidList = &hwndMucBanList;
+ break;
+ case MUC_ADMINLIST:
+ pHwndJidList = &hwndMucAdminList;
+ break;
+ case MUC_OWNERLIST:
+ pHwndJidList = &hwndMucOwnerList;
+ break;
+ default:
+ mir_free( jidListInfo );
+ return;
+ }
+
+ if ( *pHwndJidList!=NULL && IsWindow( *pHwndJidList )) {
+ SetForegroundWindow( *pHwndJidList );
+ SendMessage( *pHwndJidList, WM_JABBER_REFRESH, 0, ( LPARAM )jidListInfo );
+ }
+ else *pHwndJidList = CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_JIDLIST ), NULL, JabberMucJidListDlgProc, ( LPARAM )jidListInfo );
+}
+
+static void JabberIqResultMucGetJidList( XmlNode *iqNode, JABBER_MUC_JIDLIST_TYPE listType )
+{
+ TCHAR* type;
+ JABBER_MUC_JIDLIST_INFO *jidListInfo;
+
+ if (( type=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return;
+
+ if ( !lstrcmp( type, _T("result" ))) {
+ if (( jidListInfo=( JABBER_MUC_JIDLIST_INFO * ) mir_alloc( sizeof( JABBER_MUC_JIDLIST_INFO )) ) != NULL ) {
+ jidListInfo->type = listType;
+ jidListInfo->roomJid = NULL; // Set in the dialog procedure
+ if (( ( jidListInfo->iqNode )=JabberXmlCopyNode( iqNode )) != NULL ) {
+ if ( GetCurrentThreadId() != jabberMainThreadId )
+ QueueUserAPC( JabberMucJidListCreateDialogApcProc, hMainThread, ( DWORD )jidListInfo );
+ else
+ JabberMucJidListCreateDialogApcProc(( DWORD )jidListInfo );
+ }
+ else mir_free( jidListInfo );
+} } }
+
+void JabberIqResultMucGetVoiceList( XmlNode *iqNode, void *userdata )
+{
+ JabberLog( "<iq/> iqResultMucGetVoiceList" );
+ JabberIqResultMucGetJidList( iqNode, MUC_VOICELIST );
+}
+
+void JabberIqResultMucGetMemberList( XmlNode *iqNode, void *userdata )
+{
+ JabberLog( "<iq/> iqResultMucGetMemberList" );
+ JabberIqResultMucGetJidList( iqNode, MUC_MEMBERLIST );
+}
+
+void JabberIqResultMucGetModeratorList( XmlNode *iqNode, void *userdata )
+{
+ JabberLog( "<iq/> iqResultMucGetModeratorList" );
+ JabberIqResultMucGetJidList( iqNode, MUC_MODERATORLIST );
+}
+
+void JabberIqResultMucGetBanList( XmlNode *iqNode, void *userdata )
+{
+ JabberLog( "<iq/> iqResultMucGetBanList" );
+ JabberIqResultMucGetJidList( iqNode, MUC_BANLIST );
+}
+
+void JabberIqResultMucGetAdminList( XmlNode *iqNode, void *userdata )
+{
+ JabberLog( "<iq/> iqResultMucGetAdminList" );
+ JabberIqResultMucGetJidList( iqNode, MUC_ADMINLIST );
+}
+
+void JabberIqResultMucGetOwnerList( XmlNode *iqNode, void *userdata )
+{
+ JabberLog( "<iq/> iqResultMucGetOwnerList" );
+ JabberIqResultMucGetJidList( iqNode, MUC_OWNERLIST );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+TCHAR* JABBER_MUC_JIDLIST_INFO::type2str() const
+{
+ switch( type ) {
+ case MUC_VOICELIST: return TranslateT( "Voice List" );
+ case MUC_MEMBERLIST: return TranslateT( "Member List" );
+ case MUC_MODERATORLIST: return TranslateT( "Moderator List" );
+ case MUC_BANLIST: return TranslateT( "Ban List" );
+ case MUC_ADMINLIST: return TranslateT( "Admin List" );
+ case MUC_OWNERLIST: return TranslateT( "Owner List" );
+ }
+
+ return TranslateT( "JID List" );
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_libstr.cpp b/miranda-wine/protocols/JabberG/jabber_libstr.cpp new file mode 100644 index 0000000..b5fd916 --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_libstr.cpp @@ -0,0 +1,76 @@ +/*
+
+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_libstr.cpp,v $
+Revision : $Revision: 2866 $
+Last change on : $Date: 2006-05-16 20:39:40 +0400 (Втр, 16 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+
+void __stdcall replaceStr( char*& dest, const char* src )
+{
+ if ( src != NULL ) {
+ if ( dest != NULL )
+ mir_free( dest );
+ dest = mir_strdup( src );
+ }
+ else dest = NULL;
+}
+
+void __stdcall replaceStr( WCHAR*& dest, const WCHAR* src )
+{
+ if ( src != NULL ) {
+ if ( dest != NULL )
+ mir_free( dest );
+ dest = mir_wstrdup( src );
+ }
+ else dest = NULL;
+}
+
+char* __stdcall rtrim( char *string )
+{
+ char* p = string + strlen( string ) - 1;
+
+ while ( p >= string ) {
+ if ( *p != ' ' && *p != '\t' && *p != '\n' && *p != '\r' )
+ break;
+
+ *p-- = 0;
+ }
+ return string;
+}
+
+#if defined( _UNICODE )
+TCHAR* __stdcall rtrim( TCHAR *string )
+{
+ TCHAR* p = string + _tcslen( string ) - 1;
+
+ while ( p >= string ) {
+ if ( *p != ' ' && *p != '\t' && *p != '\n' && *p != '\r' )
+ break;
+
+ *p-- = 0;
+ }
+ return string;
+}
+#endif
diff --git a/miranda-wine/protocols/JabberG/jabber_list.cpp b/miranda-wine/protocols/JabberG/jabber_list.cpp new file mode 100644 index 0000000..e1dcfe9 --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_list.cpp @@ -0,0 +1,388 @@ +/*
+
+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_list.cpp,v $
+Revision : $Revision: 3651 $
+Last change on : $Date: 2006-08-30 16:54:52 +0400 (Срд, 30 Авг 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+#include "jabber_list.h"
+
+static int count;
+static JABBER_LIST_ITEM *lists;
+static CRITICAL_SECTION csLists;
+
+static void JabberListFreeItemInternal( JABBER_LIST_ITEM *item );
+
+void JabberListInit( void )
+{
+ lists = NULL;
+ count = 0;
+ InitializeCriticalSection( &csLists );
+}
+
+void JabberListUninit( void )
+{
+ JabberListWipe();
+ DeleteCriticalSection( &csLists );
+}
+
+void JabberListWipe( void )
+{
+ int i;
+
+ EnterCriticalSection( &csLists );
+ for( i=0; i<count; i++ )
+ JabberListFreeItemInternal( &( lists[i] ));
+ if ( lists != NULL ) {
+ mir_free( lists );
+ lists = NULL;
+ }
+ count=0;
+ LeaveCriticalSection( &csLists );
+}
+
+static void JabberListFreeItemInternal( JABBER_LIST_ITEM *item )
+{
+ int i;
+
+ if ( item == NULL )
+ return;
+
+ if ( item->jid ) mir_free( item->jid );
+ if ( item->nick ) mir_free( item->nick );
+
+ JABBER_RESOURCE_STATUS* r = item->resource;
+ for ( i=0; i<item->resourceCount; i++, r++ ) {
+ if ( r->resourceName ) mir_free( r->resourceName );
+ if ( r->statusMessage ) mir_free( r->statusMessage );
+ if ( r->software ) mir_free( r->software );
+ if ( r->version ) mir_free( r->version );
+ if ( r->system ) mir_free( r->system );
+ }
+ if ( item->resource ) mir_free( item->resource );
+ if ( item->statusMessage ) mir_free( item->statusMessage );
+ if ( item->group ) mir_free( item->group );
+ if ( item->photoFileName ) {
+ DeleteFileA( item->photoFileName );
+ mir_free( item->photoFileName );
+ }
+ if ( item->messageEventIdStr ) mir_free( item->messageEventIdStr );
+ if ( item->name ) mir_free( item->name );
+ if ( item->type ) mir_free( item->type );
+ if ( item->service ) mir_free( item->service );
+ if ( item->list==LIST_ROSTER && item->ft ) delete item->ft;
+}
+
+int JabberListExist( JABBER_LIST list, const TCHAR* jid )
+{
+ TCHAR szSrc[ JABBER_MAX_JID_LEN ];
+ JabberStripJid( jid, szSrc, sizeof( szSrc ));
+
+ EnterCriticalSection( &csLists );
+ for ( int i=0; i<count; i++ ) {
+ if ( lists[i].list == list ) {
+ TCHAR szTempJid[ JABBER_MAX_JID_LEN ];
+ if ( !_tcsicmp( szSrc, JabberStripJid( lists[i].jid, szTempJid, sizeof( szTempJid )))) {
+ LeaveCriticalSection( &csLists );
+ return i+1;
+ } } }
+
+ LeaveCriticalSection( &csLists );
+ return 0;
+}
+
+JABBER_LIST_ITEM *JabberListAdd( JABBER_LIST list, const TCHAR* jid )
+{
+ TCHAR* s, *p, *q;
+ JABBER_LIST_ITEM *item;
+
+ EnterCriticalSection( &csLists );
+ if (( item=JabberListGetItemPtr( list, jid )) != NULL ) {
+ LeaveCriticalSection( &csLists );
+ return item;
+ }
+
+ s = mir_tstrdup( jid );
+ // strip resource name if any
+ if (( p = _tcschr( s, '@' )) != NULL )
+ if (( q = _tcschr( p, '/' )) != NULL )
+ *q = '\0';
+
+ lists = ( JABBER_LIST_ITEM * ) mir_realloc( lists, sizeof( JABBER_LIST_ITEM )*( count+1 ));
+ item = &( lists[count] );
+ ZeroMemory( item, sizeof( JABBER_LIST_ITEM ));
+ item->list = list;
+ item->jid = s;
+ item->status = ID_STATUS_OFFLINE;
+ item->resource = NULL;
+ item->resourceMode = RSMODE_LASTSEEN;
+ item->defaultResource = -1;
+ if ( list == LIST_ROSTER )
+ item->cap = CLIENT_CAP_CHATSTAT;
+ count++;
+ LeaveCriticalSection( &csLists );
+
+ return item;
+}
+
+void JabberListRemove( JABBER_LIST list, const TCHAR* jid )
+{
+ EnterCriticalSection( &csLists );
+ int i = JabberListExist( list, jid );
+ if ( !i ) {
+ LeaveCriticalSection( &csLists );
+ return;
+ }
+ i--;
+ JabberListFreeItemInternal( &( lists[i] ));
+ count--;
+ memmove( lists+i, lists+i+1, sizeof( JABBER_LIST_ITEM )*( count-i ));
+ lists = ( JABBER_LIST_ITEM * ) mir_realloc( lists, sizeof( JABBER_LIST_ITEM )*count );
+ LeaveCriticalSection( &csLists );
+}
+
+void JabberListRemoveList( JABBER_LIST list )
+{
+ int i = 0;
+ while (( i=JabberListFindNext( list, i )) >= 0 )
+ JabberListRemoveByIndex( i );
+}
+
+void JabberListRemoveByIndex( int index )
+{
+ EnterCriticalSection( &csLists );
+ if ( index>=0 && index<count ) {
+ JabberListFreeItemInternal( &( lists[index] ));
+ count--;
+ memmove( lists+index, lists+index+1, sizeof( JABBER_LIST_ITEM )*( count-index ));
+ lists = ( JABBER_LIST_ITEM * ) mir_realloc( lists, sizeof( JABBER_LIST_ITEM )*count );
+ }
+ LeaveCriticalSection( &csLists );
+}
+
+int JabberListAddResource( JABBER_LIST list, const TCHAR* jid, int status, const TCHAR* statusMessage )
+{
+ int j;
+ const TCHAR* p, *q;
+
+ EnterCriticalSection( &csLists );
+ int i = JabberListExist( list, jid );
+ if ( !i ) {
+ LeaveCriticalSection( &csLists );
+ return 0;
+ }
+ JABBER_LIST_ITEM* LI = &lists[i-1];
+
+ int bIsNewResource = false;
+
+ if (( p = _tcschr( jid, '@' )) != NULL ) {
+ if (( q = _tcschr( p, '/' )) != NULL ) {
+ const TCHAR* resource = q+1;
+ if ( resource[0] ) {
+ JABBER_RESOURCE_STATUS* r = LI->resource;
+ for ( j=0; j < LI->resourceCount; j++, r++ ) {
+ if ( !_tcscmp( r->resourceName, resource )) {
+ // Already exist, update status and statusMessage
+ r->status = status;
+ replaceStr( r->statusMessage, statusMessage );
+ break;
+ } }
+
+ if ( j >= LI->resourceCount ) {
+ // Not already exist, add new resource
+ LI->resource = ( JABBER_RESOURCE_STATUS * ) mir_realloc( LI->resource, ( LI->resourceCount+1 )*sizeof( JABBER_RESOURCE_STATUS ));
+ bIsNewResource = true;
+ r = LI->resource + LI->resourceCount++;
+ memset( r, 0, sizeof( JABBER_RESOURCE_STATUS ));
+ r->status = status;
+ r->affiliation = AFFILIATION_NONE;
+ r->role = ROLE_NONE;
+ r->resourceName = mir_tstrdup( resource );
+ if ( statusMessage )
+ r->statusMessage = mir_tstrdup( statusMessage );
+ } }
+ }
+ // No resource, update the main statusMessage
+ else replaceStr( LI->statusMessage, statusMessage );
+ }
+
+ LeaveCriticalSection( &csLists );
+ return bIsNewResource;
+}
+
+void JabberListRemoveResource( JABBER_LIST list, const TCHAR* jid )
+{
+ int j;
+ const TCHAR* p, *q;
+
+ EnterCriticalSection( &csLists );
+ int i = JabberListExist( list, jid );
+ JABBER_LIST_ITEM* LI = &lists[i-1];
+ if ( !i || LI == NULL ) {
+ LeaveCriticalSection( &csLists );
+ return;
+ }
+
+ if (( p = _tcschr( jid, '@' )) != NULL ) {
+ if (( q = _tcschr( p, '/' )) != NULL ) {
+ const TCHAR* resource = q+1;
+ if ( resource[0] ) {
+ JABBER_RESOURCE_STATUS* r = LI->resource;
+ for ( j=0; j < LI->resourceCount; j++, r++ ) {
+ if ( !_tcsicmp( r->resourceName, resource ))
+ break;
+ }
+ if ( j < LI->resourceCount ) {
+ // Found resource to be removed
+ if ( LI->defaultResource == j )
+ LI->defaultResource = -1;
+ else if ( LI->defaultResource > j )
+ LI->defaultResource--;
+ if ( r->resourceName ) mir_free( r->resourceName );
+ if ( r->statusMessage ) mir_free( r->statusMessage );
+ if ( r->software ) mir_free( r->software );
+ if ( r->version ) mir_free( r->version );
+ if ( r->system ) mir_free( r->system );
+ if ( LI->resourceCount-- == 1 ) {
+ mir_free( r );
+ LI->resource = NULL;
+ }
+ else {
+ memmove( r, r+1, ( LI->resourceCount-j )*sizeof( JABBER_RESOURCE_STATUS ));
+ LI->resource = ( JABBER_RESOURCE_STATUS * )mir_realloc( LI->resource, LI->resourceCount*sizeof( JABBER_RESOURCE_STATUS ));
+ } } } } }
+
+ LeaveCriticalSection( &csLists );
+}
+
+TCHAR* JabberListGetBestResourceNamePtr( const TCHAR* jid )
+{
+ TCHAR* res;
+
+ EnterCriticalSection( &csLists );
+ int i = JabberListExist( LIST_ROSTER, jid );
+ JABBER_LIST_ITEM* LI = &lists[i-1];
+ if ( !i || LI == NULL ) {
+ LeaveCriticalSection( &csLists );
+ return NULL;
+ }
+
+ if ( LI->resourceCount == 1 )
+ res = LI->resource[0].resourceName;
+ else {
+ res = NULL;
+ if ( LI->resourceMode == RSMODE_MANUAL || LI->resourceMode == RSMODE_LASTSEEN ) {
+ if ( LI->defaultResource>=0 && LI->defaultResource < LI->resourceCount )
+ res = LI->resource[ LI->defaultResource ].resourceName;
+ } }
+
+ LeaveCriticalSection( &csLists );
+ return res;
+}
+
+TCHAR* JabberListGetBestClientResourceNamePtr( const TCHAR* jid )
+{
+ EnterCriticalSection( &csLists );
+ int i = JabberListExist( LIST_ROSTER, jid );
+ JABBER_LIST_ITEM* LI = &lists[i-1];
+
+ if ( !i || LI == NULL ) {
+ LeaveCriticalSection( &csLists );
+ return NULL;
+ }
+
+ TCHAR* res = JabberListGetBestResourceNamePtr( jid );
+ if ( res == NULL ) {
+ JABBER_RESOURCE_STATUS* r = LI->resource;
+ int status = ID_STATUS_OFFLINE;
+ res = NULL;
+ for ( i=0; i < LI->resourceCount; i++ ) {
+ int s = r[i].status;
+ BOOL foundBetter = FALSE;
+ switch ( s ) {
+ case ID_STATUS_FREECHAT:
+ foundBetter = TRUE;
+ break;
+ case ID_STATUS_ONLINE:
+ if ( status != ID_STATUS_FREECHAT )
+ foundBetter = TRUE;
+ break;
+ case ID_STATUS_DND:
+ if ( status != ID_STATUS_FREECHAT && status != ID_STATUS_ONLINE )
+ foundBetter = TRUE;
+ break;
+ case ID_STATUS_AWAY:
+ if ( status != ID_STATUS_FREECHAT && status != ID_STATUS_ONLINE && status != ID_STATUS_DND )
+ foundBetter = TRUE;
+ break;
+ case ID_STATUS_NA:
+ if ( status != ID_STATUS_FREECHAT && status != ID_STATUS_ONLINE && status != ID_STATUS_DND && status != ID_STATUS_AWAY )
+ foundBetter = TRUE;
+ break;
+ }
+ if ( foundBetter ) {
+ res = r[i].resourceName;
+ status = s;
+ } } }
+
+ LeaveCriticalSection( &csLists );
+ return res;
+}
+
+int JabberListFindNext( JABBER_LIST list, int fromOffset )
+{
+ EnterCriticalSection( &csLists );
+ int i = ( fromOffset>=0 ) ? fromOffset : 0;
+ for( ; i<count; i++ )
+ if ( lists[i].list == list ) {
+ LeaveCriticalSection( &csLists );
+ return i;
+ }
+ LeaveCriticalSection( &csLists );
+ return -1;
+}
+
+JABBER_LIST_ITEM *JabberListGetItemPtr( JABBER_LIST list, const TCHAR* jid )
+{
+ EnterCriticalSection( &csLists );
+ int i = JabberListExist( list, jid );
+ if ( !i ) {
+ LeaveCriticalSection( &csLists );
+ return NULL;
+ }
+ i--;
+ LeaveCriticalSection( &csLists );
+ return &( lists[i] );
+}
+
+JABBER_LIST_ITEM *JabberListGetItemPtrFromIndex( int index )
+{
+ EnterCriticalSection( &csLists );
+ if ( index>=0 && index<count ) {
+ LeaveCriticalSection( &csLists );
+ return &( lists[index] );
+ }
+ LeaveCriticalSection( &csLists );
+ return NULL;
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_list.h b/miranda-wine/protocols/JabberG/jabber_list.h new file mode 100644 index 0000000..dabd81f --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_list.h @@ -0,0 +1,174 @@ +/*
+
+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_list.h,v $
+Revision : $Revision: 3651 $
+Last change on : $Date: 2006-08-30 16:54:52 +0400 (Срд, 30 Авг 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#ifndef _JABBER_LIST_H_
+#define _JABBER_LIST_H_
+
+typedef enum {
+ LIST_ROSTER, // Roster list
+ LIST_AGENT, // Agent list to show on the Jabber Agents dialog
+ LIST_CHATROOM, // Groupchat room currently joined
+ LIST_ROOM, // Groupchat room list to show on the Jabber groupchat dialog
+ LIST_FILE, // Current file transfer session
+ LIST_BYTE, // Bytestream sending connection
+ LIST_FTSEND,
+ LIST_FTRECV
+} JABBER_LIST;
+
+typedef enum {
+ SUB_NONE,
+ SUB_TO,
+ SUB_FROM,
+ SUB_BOTH
+} JABBER_SUBSCRIPTION;
+
+typedef enum {
+ AFFILIATION_NONE,
+ AFFILIATION_OUTCAST,
+ AFFILIATION_MEMBER,
+ AFFILIATION_ADMIN,
+ AFFILIATION_OWNER
+} JABBER_GC_AFFILIATION;
+
+typedef enum {
+ ROLE_NONE,
+ ROLE_VISITOR,
+ ROLE_PARTICIPANT,
+ ROLE_MODERATOR
+} JABBER_GC_ROLE;
+
+typedef enum { // initial default to RSMODE_LASTSEEN
+ RSMODE_SERVER, // always let server decide ( always send correspondence without resouce name )
+ RSMODE_LASTSEEN, // use the last seen resource ( or let server decide if haven't seen anything yet )
+ RSMODE_MANUAL // specify resource manually ( see the defaultResource field - must not be NULL )
+} JABBER_RESOURCE_MODE;
+
+#define CLIENT_CAP_READY ( 1<<0 ) // have already done disco#info query
+#define CLIENT_CAP_SI ( 1<<1 ) // stream initiation ( si ) profile
+#define CLIENT_CAP_SIFILE ( 1<<2 ) // file transfer si profile
+#define CLIENT_CAP_BYTESTREAM ( 1<<3 ) // socks5 bytestream
+#define CLIENT_CAP_CHATSTAT ( 1<<4 ) // http://jabber.org/protocol/chatstates support (JEP-0085)
+
+#define AGENT_CAP_REGISTER ( 1<<13 )
+#define AGENT_CAP_SEARCH ( 1<<14 )
+#define AGENT_CAP_GROUPCHAT ( 1<<15 )
+
+#define CLIENT_CAP_FILE ( CLIENT_CAP_SI | CLIENT_CAP_SIFILE )
+
+struct JABBER_RESOURCE_STATUS
+{
+ int status;
+ TCHAR* resourceName;
+ TCHAR* statusMessage;
+ TCHAR* software;
+ TCHAR* version;
+ TCHAR* system;
+ unsigned int cap; // 0 = haven't done disco#info yet, see CLIENT_CAP_*
+ JABBER_GC_AFFILIATION affiliation;
+ JABBER_GC_ROLE role;
+};
+
+struct JABBER_LIST_ITEM
+{
+ JABBER_LIST list;
+ TCHAR* jid;
+
+ // LIST_ROSTER
+ // jid = jid of the contact
+ TCHAR* nick;
+ int resourceCount;
+ int status; // Main status, currently useful for transport where no resource information is kept.
+ // On normal contact, this is the same status as shown on contact list.
+ JABBER_RESOURCE_STATUS *resource;
+ int defaultResource; // index to resource[x] which is the default, negative ( -1 ) means no resource is chosen yet
+ JABBER_RESOURCE_MODE resourceMode;
+ JABBER_SUBSCRIPTION subscription;
+ TCHAR* statusMessage; // Status message when the update is to JID with no resource specified ( e.g. transport user )
+ TCHAR* group;
+ char* photoFileName;
+ int idMsgAckPending;
+ TCHAR* messageEventIdStr;
+ BOOL wantComposingEvent;
+ WORD cap; // See CLIENT_CAP_* above
+
+ // LIST_AGENT
+ // jid = jid of the agent
+ // WORD cap; // See AGENT_CAP_* above
+ TCHAR* name;
+ TCHAR* service;
+
+ // LIST_ROOM
+ // jid = room JID
+ // char* name; // room name
+ TCHAR* type; // room type
+
+ // LIST_CHATROOM
+ // jid = room JID
+ // char* nick; // my nick in this chat room ( SPECIAL: in TXT )
+ // JABBER_RESOURCE_STATUS *resource; // participant nicks in this room
+ BOOL bChatActive;
+ HWND hwndGcListBan;
+ HWND hwndGcListAdmin;
+ HWND hwndGcListOwner;
+
+ // LIST_FILE
+ // jid = string representation of port number
+ filetransfer* ft;
+ WORD port;
+
+ // LIST_BYTE
+ // jid = string representation of port number
+ JABBER_BYTE_TRANSFER *jbt;
+
+ // LIST_FTSEND
+ // jid = string representation of iq id
+ // ft = file transfer data
+ // jbt
+
+ // LIST_FTRECV
+ // jid = string representation of stream id ( sid )
+ // ft = file transfer data
+};
+
+void JabberListInit( void );
+void JabberListUninit( void );
+void JabberListWipe( void );
+int JabberListExist( JABBER_LIST list, const TCHAR* jid );
+JABBER_LIST_ITEM *JabberListAdd( JABBER_LIST list, const TCHAR* jid );
+void JabberListRemove( JABBER_LIST list, const TCHAR* jid );
+void JabberListRemoveList( JABBER_LIST list );
+void JabberListRemoveByIndex( int index );
+int JabberListFindNext( JABBER_LIST list, int fromOffset );
+JABBER_LIST_ITEM *JabberListGetItemPtr( JABBER_LIST list, const TCHAR* jid );
+JABBER_LIST_ITEM *JabberListGetItemPtrFromIndex( int index );
+
+int JabberListAddResource( JABBER_LIST list, const TCHAR* jid, int status, const TCHAR* statusMessage );
+void JabberListRemoveResource( JABBER_LIST list, const TCHAR* jid );
+TCHAR* JabberListGetBestResourceNamePtr( const TCHAR* jid );
+TCHAR* JabberListGetBestClientResourceNamePtr( const TCHAR* jid );
+
+#endif
diff --git a/miranda-wine/protocols/JabberG/jabber_menu.cpp b/miranda-wine/protocols/JabberG/jabber_menu.cpp new file mode 100644 index 0000000..a25fe61 --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_menu.cpp @@ -0,0 +1,281 @@ +/*
+
+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_menu.cpp,v $
+Revision : $Revision: 2948 $
+Last change on : $Date: 2006-05-24 23:59:47 +0400 (Срд, 24 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+#include "jabber_list.h"
+#include "resource.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// module data
+
+static HANDLE hMenuRequestAuth = NULL;
+static HANDLE hMenuGrantAuth = NULL;
+static HANDLE hMenuJoinLeave = NULL;
+static HANDLE hMenuConvert = NULL;
+static HANDLE hMenuRosterAdd = NULL;
+
+static void sttEnableMenuItem( HANDLE hMenuItem, BOOL bEnable )
+{
+ CLISTMENUITEM clmi = {0};
+ clmi.cbSize = sizeof( CLISTMENUITEM );
+ clmi.flags = CMIM_FLAGS;
+ if ( !bEnable )
+ clmi.flags |= CMIF_HIDDEN;
+
+ JCallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuItem, ( LPARAM )&clmi );
+}
+
+int JabberMenuPrebuildContactMenu( WPARAM wParam, LPARAM lParam )
+{
+ sttEnableMenuItem( hMenuRequestAuth, FALSE );
+ sttEnableMenuItem( hMenuGrantAuth, FALSE );
+ sttEnableMenuItem( hMenuJoinLeave, FALSE );
+ sttEnableMenuItem( hMenuConvert, FALSE );
+ sttEnableMenuItem( hMenuRosterAdd, FALSE );
+
+ HANDLE hContact;
+ if (( hContact=( HANDLE )wParam ) == NULL )
+ return 0;
+
+ BYTE chatRoomType = (BYTE)JGetByte( hContact, "ChatRoom", 0 );
+
+ if ((chatRoomType == GCW_CHATROOM) || chatRoomType == 0 ) {
+ DBVARIANT dbv;
+ if ( !JGetStringT( hContact, chatRoomType?"ChatRoomID":"jid", &dbv )) {
+ JFreeVariant( &dbv );
+ CLISTMENUITEM clmi = { 0 };
+ sttEnableMenuItem( hMenuConvert, TRUE );
+ clmi.cbSize = sizeof( clmi );
+ clmi.pszName = JTranslate( chatRoomType ? "&Convert to Contact" : "&Convert to Chat Room" );
+ clmi.flags = CMIM_NAME | CMIM_FLAGS;
+ JCallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuConvert, ( LPARAM )&clmi );
+ } }
+
+ if (!jabberOnline)
+ return 0;
+
+ if ( chatRoomType ) {
+ DBVARIANT dbv;
+ if ( !JGetStringT( hContact, "ChatRoomID", &dbv )) {
+ if ( JabberListGetItemPtr( LIST_ROSTER, dbv.ptszVal ) == NULL ) {
+ sttEnableMenuItem( hMenuRosterAdd, TRUE );
+ }
+ JFreeVariant( &dbv );
+ } }
+
+ if ( chatRoomType == GCW_CHATROOM ) {
+ CLISTMENUITEM clmi = { 0 };
+ clmi.cbSize = sizeof( clmi );
+ clmi.pszName = JTranslate(( JGetWord( hContact, "Status", 0 ) == ID_STATUS_ONLINE ) ? "&Leave" : "&Join" );
+ clmi.flags = CMIM_NAME | CMIM_FLAGS;
+ JCallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuJoinLeave, ( LPARAM )&clmi );
+ return 0;
+ }
+
+ DBVARIANT dbv;
+ if ( !JGetStringT( hContact, "jid", &dbv )) {
+ JABBER_LIST_ITEM* item = JabberListGetItemPtr( LIST_ROSTER, dbv.ptszVal );
+ JFreeVariant( &dbv );
+ if ( item != NULL ) {
+ sttEnableMenuItem( hMenuRequestAuth, item->subscription == SUB_FROM || item->subscription == SUB_NONE );
+ sttEnableMenuItem( hMenuGrantAuth, item->subscription == SUB_TO || item->subscription == SUB_NONE );
+ return 0;
+ } }
+
+ return 0;
+}
+
+int JabberMenuConvertChatContact( WPARAM wParam, LPARAM lParam )
+{
+ BYTE chatRoomType = (BYTE)JGetByte( (HANDLE ) wParam, "ChatRoom", 0 );
+ if ((chatRoomType == GCW_CHATROOM) || chatRoomType == 0 ) {
+ DBVARIANT dbv;
+ if ( !JGetStringT( (HANDLE ) wParam, (chatRoomType == GCW_CHATROOM)?"ChatRoomID":"jid", &dbv )) {
+ JDeleteSetting( (HANDLE ) wParam, (chatRoomType == GCW_CHATROOM)?"ChatRoomID":"jid");
+ JSetStringT( (HANDLE ) wParam, (chatRoomType != GCW_CHATROOM)?"ChatRoomID":"jid", dbv.ptszVal);
+ JFreeVariant( &dbv );
+ JSetByte((HANDLE ) wParam, "ChatRoom", (chatRoomType == GCW_CHATROOM)?0:GCW_CHATROOM);
+ } }
+ return 0;
+}
+
+int JabberMenuRosterAdd( WPARAM wParam, LPARAM lParam )
+{
+ DBVARIANT dbv;
+ if ( !wParam ) return 0; // we do not add ourself to the roster. (buggy situation - should not happen)
+ if ( !JGetStringT( ( HANDLE ) wParam, "ChatRoomID", &dbv )) {
+ TCHAR *roomID = mir_tstrdup(dbv.ptszVal);
+ JFreeVariant( &dbv );
+ if ( JabberListGetItemPtr( LIST_ROSTER, roomID ) == NULL ) {
+ TCHAR *nick = 0;
+ TCHAR *group = 0;
+ if ( !DBGetContactSettingTString( ( HANDLE ) wParam, "CList", "Group", &dbv ) ) {
+ group = mir_tstrdup(dbv.ptszVal);
+ JFreeVariant( &dbv );
+ }
+ if ( !JGetStringT( ( HANDLE ) wParam, "Nick", &dbv ) ) {
+ nick = mir_tstrdup(dbv.ptszVal);
+ JFreeVariant( &dbv );
+ }
+ JabberAddContactToRoster(roomID, nick, group, SUB_NONE);
+ if (nick) mir_free(nick);
+ if (nick) mir_free(group);
+ }
+ mir_free(roomID);
+ }
+ return 0;
+}
+
+int JabberMenuHandleRequestAuth( WPARAM wParam, LPARAM lParam )
+{
+ HANDLE hContact;
+ DBVARIANT dbv;
+
+ if (( hContact=( HANDLE ) wParam )!=NULL && jabberOnline ) {
+ if ( !JGetStringT( hContact, "jid", &dbv )) {
+ XmlNode presence( "presence" ); presence.addAttr( "to", dbv.ptszVal ); presence.addAttr( "type", "subscribe" );
+ JabberSend( jabberThreadInfo->s, presence );
+ JFreeVariant( &dbv );
+ } }
+
+ return 0;
+}
+
+int JabberMenuHandleGrantAuth( WPARAM wParam, LPARAM lParam )
+{
+ HANDLE hContact;
+ DBVARIANT dbv;
+
+ if (( hContact=( HANDLE ) wParam )!=NULL && jabberOnline ) {
+ if ( !JGetStringT( hContact, "jid", &dbv )) {
+ XmlNode presence( "presence" ); presence.addAttr( "to", dbv.ptszVal ); presence.addAttr( "type", "subscribed" );
+ JabberSend( jabberThreadInfo->s, presence );
+ JFreeVariant( &dbv );
+ } }
+
+ return 0;
+}
+
+int JabberMenuJoinLeave( WPARAM wParam, LPARAM lParam )
+{
+ DBVARIANT dbv, jid;
+ if ( JGetStringT(( HANDLE )wParam, "ChatRoomID", &jid ))
+ return 0;
+
+ if ( JGetStringT(( HANDLE )wParam, "MyNick", &dbv ))
+ if ( JGetStringT( NULL, "Nick", &dbv )) {
+ JFreeVariant( &jid );
+ return 0;
+ }
+
+ if ( JGetWord(( HANDLE )wParam, "Status", 0 ) != ID_STATUS_ONLINE ) {
+ if ( !jabberChatDllPresent ) {
+ JabberChatDllError();
+ goto LBL_Return;
+ }
+
+ TCHAR* p = _tcschr( jid.ptszVal, '@' );
+ if ( p == NULL )
+ goto LBL_Return;
+
+ *p++ = 0;
+ JabberGroupchatJoinRoom( p, jid.ptszVal, dbv.ptszVal, _T(""));
+ }
+ else {
+ JABBER_LIST_ITEM* item = JabberListGetItemPtr( LIST_CHATROOM, jid.ptszVal );
+ if ( item != NULL )
+ JabberGcQuit( item, 0, NULL );
+ }
+
+LBL_Return:
+ JFreeVariant( &dbv );
+ JFreeVariant( &jid );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// contact menu initialization code
+
+void JabberMenuInit()
+{
+ CLISTMENUITEM mi = { 0 };
+ mi.cbSize = sizeof( CLISTMENUITEM );
+
+ char text[ 200 ];
+ strcpy( text, jabberProtoName );
+ char* tDest = text + strlen( text );
+
+ // "Request authorization"
+ strcpy( tDest, "/RequestAuth" );
+ CreateServiceFunction( text, JabberMenuHandleRequestAuth );
+ mi.pszName = JTranslate( "Request authorization" );
+ mi.position = -2000001001;
+ mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_REQUEST ));
+ mi.pszService = text;
+ mi.pszContactOwner = jabberProtoName;
+ hMenuRequestAuth = ( HANDLE ) JCallService( MS_CLIST_ADDCONTACTMENUITEM, 0, ( LPARAM )&mi );
+
+ // "Grant authorization"
+ strcpy( tDest, "/GrantAuth" );
+ CreateServiceFunction( text, JabberMenuHandleGrantAuth );
+ mi.pszName = JTranslate( "Grant authorization" );
+ mi.position = -2000001000;
+ mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_GRANT ));
+ mi.pszService = text;
+ mi.pszContactOwner = jabberProtoName;
+ hMenuGrantAuth = ( HANDLE ) JCallService( MS_CLIST_ADDCONTACTMENUITEM, 0, ( LPARAM )&mi );
+
+ // "Grant authorization"
+ strcpy( tDest, "/JoinChat" );
+ CreateServiceFunction( text, JabberMenuJoinLeave );
+ mi.pszName = JTranslate( "Join chat" );
+ mi.position = -2000001002;
+ mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_GROUP ));
+ mi.pszService = text;
+ mi.pszContactOwner = jabberProtoName;
+ hMenuJoinLeave = ( HANDLE ) JCallService( MS_CLIST_ADDCONTACTMENUITEM, 0, ( LPARAM )&mi );
+
+ // "Convert Chat/Contact"
+ strcpy( tDest, "/ConvertChatContact" );
+ CreateServiceFunction( text, JabberMenuConvertChatContact );
+ mi.pszName = JTranslate( "Convert" );
+ mi.position = -1999901003;
+ mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_USER2ROOM ));
+ mi.pszService = text;
+ mi.pszContactOwner = jabberProtoName;
+ hMenuConvert = ( HANDLE ) JCallService( MS_CLIST_ADDCONTACTMENUITEM, 0, ( LPARAM )&mi );
+
+ // "Add to roster"
+ strcpy( tDest, "/AddToRoster" );
+ CreateServiceFunction( text, JabberMenuRosterAdd );
+ mi.pszName = JTranslate( "Add to roster" );
+ mi.position = -1999901004;
+ mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_ADDROSTER ));
+ mi.pszService = text;
+ mi.pszContactOwner = jabberProtoName;
+ hMenuRosterAdd = ( HANDLE ) JCallService( MS_CLIST_ADDCONTACTMENUITEM, 0, ( LPARAM )&mi );
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_misc.cpp b/miranda-wine/protocols/JabberG/jabber_misc.cpp new file mode 100644 index 0000000..35e356e --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_misc.cpp @@ -0,0 +1,382 @@ +/*
+
+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_misc.cpp,v $
+Revision : $Revision: 3322 $
+Last change on : $Date: 2006-07-13 16:11:29 +0400 (Чтв, 13 Июл 2006) $
+Last change by : $Author: rainwater $
+
+*/
+
+#include "jabber.h"
+#include "jabber_list.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// JabberAddContactToRoster() - adds a contact to the roster
+
+void JabberAddContactToRoster( const TCHAR* jid, const TCHAR* nick, const TCHAR* grpName, JABBER_SUBSCRIPTION subscription )
+{
+ XmlNodeIq iq( "set" );
+ XmlNode* query = iq.addQuery( "jabber:iq:roster" );
+ XmlNode* item = query->addChild( "item" ); item->addAttr( "name", nick ); item->addAttr( "jid", jid );
+ switch( subscription ) {
+ case SUB_BOTH: item->addAttr( "subscription", "both" ); break;
+ case SUB_TO: item->addAttr( "subscription", "to" ); break;
+ case SUB_FROM: item->addAttr( "subscription", "from" ); break;
+ default: item->addAttr( "subscription", "none" ); break;
+ }
+
+ if ( grpName != NULL )
+ item->addChild( "group", grpName );
+ JabberSend( jabberThreadInfo->s, iq );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// JabberChatDllError() - missing CHAT.DLL
+
+void JabberChatDllError()
+{
+ MessageBox( NULL,
+ TranslateT( "CHAT plugin is required for conferences. Install it before chatting" ),
+ TranslateT( "Jabber Error Message" ), MB_OK|MB_SETFOREGROUND );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// JabberCompareJids
+
+int JabberCompareJids( const TCHAR* jid1, const TCHAR* jid2 )
+{
+ if ( !lstrcmpi( jid1, jid2 ))
+ return 0;
+
+ // match only node@domain part
+ TCHAR szTempJid1[ JABBER_MAX_JID_LEN ], szTempJid2[ JABBER_MAX_JID_LEN ];
+ return lstrcmpi(
+ JabberStripJid( jid1, szTempJid1, sizeof szTempJid1 ),
+ JabberStripJid( jid2, szTempJid2, sizeof szTempJid2 ));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// JabberContactListCreateGroup()
+
+static void JabberContactListCreateClistGroup( TCHAR* groupName )
+{
+ char str[33];
+ int i;
+ DBVARIANT dbv;
+
+ for ( i=0;;i++ ) {
+ itoa( i, str, 10 );
+ if ( DBGetContactSettingTString( NULL, "CListGroups", str, &dbv ))
+ break;
+ TCHAR* name = dbv.ptszVal;
+ if ( name[0]!='\0' && !_tcscmp( name+1, groupName )) {
+ // Already exists, no need to create
+ JFreeVariant( &dbv );
+ return;
+ }
+ JFreeVariant( &dbv );
+ }
+
+ // Create new group with id = i ( str is the text representation of i )
+ TCHAR newName[128];
+ newName[0] = 1 | GROUPF_EXPANDED;
+ _tcsncpy( newName+1, groupName, SIZEOF( newName )-1 );
+ newName[ SIZEOF( newName )-1] = '\0';
+ DBWriteContactSettingTString( NULL, "CListGroups", str, newName );
+ JCallService( MS_CLUI_GROUPADDED, i+1, 0 );
+}
+
+void JabberContactListCreateGroup( TCHAR* groupName )
+{
+ TCHAR name[128], *p;
+
+ if ( groupName==NULL || groupName[0]=='\0' || groupName[0]=='\\' ) return;
+
+ _tcsncpy( name, groupName, SIZEOF( name ));
+ name[ SIZEOF( name )-1] = '\0';
+ for ( p=name; *p!='\0'; p++ ) {
+ if ( *p == '\\' ) {
+ *p = '\0';
+ JabberContactListCreateClistGroup( name );
+ *p = '\\';
+ }
+ }
+ JabberContactListCreateClistGroup( name );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// JabberDBAddAuthRequest()
+
+void JabberDBAddAuthRequest( TCHAR* jid, TCHAR* nick )
+{
+ HANDLE hContact = JabberDBCreateContact( jid, NULL, FALSE, TRUE );
+ JDeleteSetting( hContact, "Hidden" );
+ JSetStringT( hContact, "Nick", nick );
+
+ #if defined( _UNICODE )
+ char* szJid = u2a( jid );
+ char* szNick = u2a( nick );
+ #else
+ char* szJid = jid;
+ char* szNick = nick;
+ #endif
+
+ //blob is: uin( DWORD ), hContact( HANDLE ), nick( ASCIIZ ), first( ASCIIZ ), last( ASCIIZ ), email( ASCIIZ ), reason( ASCIIZ )
+ //blob is: 0( DWORD ), hContact( HANDLE ), nick( ASCIIZ ), ""( ASCIIZ ), ""( ASCIIZ ), email( ASCIIZ ), ""( ASCIIZ )
+ DBEVENTINFO dbei = {0};
+ dbei.cbSize = sizeof( DBEVENTINFO );
+ dbei.szModule = jabberProtoName;
+ dbei.timestamp = ( DWORD )time( NULL );
+ dbei.flags = 0;
+ dbei.eventType = EVENTTYPE_AUTHREQUEST;
+ dbei.cbBlob = sizeof( DWORD )+ sizeof( HANDLE ) + strlen( szNick ) + strlen( szJid ) + 5;
+ PBYTE pCurBlob = dbei.pBlob = ( PBYTE ) mir_alloc( dbei.cbBlob );
+ *(( PDWORD ) pCurBlob ) = 0; pCurBlob += sizeof( DWORD );
+ *(( PHANDLE ) pCurBlob ) = hContact; pCurBlob += sizeof( HANDLE );
+ strcpy(( char* )pCurBlob, szNick ); pCurBlob += strlen( szNick )+1;
+ *pCurBlob = '\0'; pCurBlob++; //firstName
+ *pCurBlob = '\0'; pCurBlob++; //lastName
+ strcpy(( char* )pCurBlob, szJid ); pCurBlob += strlen( szJid )+1;
+ *pCurBlob = '\0'; //reason
+
+ JCallService( MS_DB_EVENT_ADD, ( WPARAM ) ( HANDLE ) NULL, ( LPARAM )&dbei );
+ JabberLog( "Setup DBAUTHREQUEST with nick='" TCHAR_STR_PARAM "' jid='" TCHAR_STR_PARAM "'", szNick, szJid );
+
+ #if defined( _UNICODE )
+ mir_free( szJid );
+ mir_free( szNick );
+ #endif
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// JabberDBCreateContact()
+// jid & nick are passed in TXT
+
+HANDLE JabberDBCreateContact( TCHAR* jid, TCHAR* nick, BOOL temporary, BOOL stripResource )
+{
+ TCHAR* s, *p, *q;
+ int len;
+ char* szProto;
+
+ if ( jid==NULL || jid[0]=='\0' )
+ return NULL;
+
+ s = mir_tstrdup( jid );
+ q = NULL;
+ // strip resource if present
+ if (( p = _tcschr( s, '@' )) != NULL )
+ if (( q = _tcschr( p, '/' )) != NULL )
+ *q = '\0';
+
+ if ( !stripResource && q!=NULL ) // so that resource is not stripped
+ *q = '/';
+ len = _tcslen( s );
+
+ // We can't use JabberHContactFromJID() here because of the stripResource option
+ HANDLE hContact = ( HANDLE ) JCallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ while ( hContact != NULL ) {
+ szProto = ( char* )JCallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 );
+ if ( szProto!=NULL && !strcmp( jabberProtoName, szProto )) {
+ DBVARIANT dbv;
+ if ( !JGetStringT( hContact, "jid", &dbv )) {
+ p = dbv.ptszVal;
+ if ( p && ( int )_tcslen( p )>=len && ( p[len]=='\0'||p[len]=='/' ) && !_tcsnicmp( p, s, len )) {
+ JFreeVariant( &dbv );
+ break;
+ }
+ JFreeVariant( &dbv );
+ } }
+ hContact = ( HANDLE ) JCallService( MS_DB_CONTACT_FINDNEXT, ( WPARAM ) hContact, 0 );
+ }
+
+ if ( hContact == NULL ) {
+ hContact = ( HANDLE ) JCallService( MS_DB_CONTACT_ADD, 0, 0 );
+ JCallService( MS_PROTO_ADDTOCONTACT, ( WPARAM ) hContact, ( LPARAM )jabberProtoName );
+ JSetStringT( hContact, "jid", s );
+ if ( nick != NULL && *nick != '\0' )
+ JSetStringT( hContact, "Nick", nick );
+ if ( temporary )
+ DBWriteContactSettingByte( hContact, "CList", "NotOnList", 1 );
+ JabberLog( "Create Jabber contact jid=" TCHAR_STR_PARAM ", nick=" TCHAR_STR_PARAM, s, nick );
+ }
+
+ mir_free( s );
+ return hContact;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// JabberGetAvatarFileName() - gets a file name for the avatar image
+
+void JabberGetAvatarFileName( HANDLE hContact, char* pszDest, int cbLen )
+{
+ JCallService( MS_DB_GETPROFILEPATH, cbLen, LPARAM( pszDest ));
+
+ int tPathLen = strlen( pszDest );
+ tPathLen += mir_snprintf( pszDest + tPathLen, MAX_PATH - tPathLen, "\\Jabber\\" );
+ CreateDirectoryA( pszDest, NULL );
+
+ char* szFileType;
+ switch( JGetByte( hContact, "AvatarType", PA_FORMAT_PNG )) {
+ case PA_FORMAT_JPEG: szFileType = "jpg"; break;
+ case PA_FORMAT_PNG: szFileType = "png"; break;
+ case PA_FORMAT_GIF: szFileType = "gif"; break;
+ case PA_FORMAT_BMP: szFileType = "bmp"; break;
+ }
+
+ if ( hContact != NULL ) {
+ char str[ 256 ];
+ DBVARIANT dbv;
+ if ( !JGetStringUtf( hContact, "jid", &dbv )) {
+ strncpy( str, dbv.pszVal, sizeof str );
+ str[ sizeof(str)-1 ] = 0;
+ JFreeVariant( &dbv );
+ }
+ else ltoa(( long )hContact, str, 10 );
+
+ char* hash = JabberSha1( str );
+ mir_snprintf( pszDest + tPathLen, MAX_PATH - tPathLen, "%s.%s", hash, szFileType );
+ mir_free( hash );
+ }
+ else if ( jabberThreadInfo != NULL ) {
+ mir_snprintf( pszDest + tPathLen, MAX_PATH - tPathLen, TCHAR_STR_PARAM"@%s avatar.%s", jabberThreadInfo->username, jabberThreadInfo->server, szFileType );
+ }
+ else {
+ DBVARIANT dbv1, dbv2;
+ BOOL res1 = DBGetContactSetting( NULL, jabberProtoName, "LoginName", &dbv1 );
+ BOOL res2 = DBGetContactSetting( NULL, jabberProtoName, "LoginServer", &dbv2 );
+ mir_snprintf( pszDest + tPathLen, MAX_PATH - tPathLen, "%s@%s avatar.%s",
+ res1 ? "noname" : dbv1.pszVal,
+ res2 ? jabberProtoName : dbv2.pszVal,
+ szFileType );
+ if (!res1) JFreeVariant( &dbv1 );
+ if (!res2) JFreeVariant( &dbv2 );
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// JabberForkThread()
+
+struct FORK_ARG {
+ HANDLE hEvent;
+ void ( __cdecl *threadcode )( void* );
+ void *arg;
+};
+
+static void __cdecl forkthread_r( struct FORK_ARG *fa )
+{
+ void ( *callercode )( void* ) = fa->threadcode;
+ void *arg = fa->arg;
+ JabberLog( "Thread started: %08X %d", callercode, GetCurrentThreadId());
+ JCallService( MS_SYSTEM_THREAD_PUSH, 0, 0 );
+ SetEvent( fa->hEvent );
+ __try {
+ callercode( arg );
+ } __finally {
+ JCallService( MS_SYSTEM_THREAD_POP, 0, 0 );
+ }
+ return;
+}
+
+ULONG JabberForkThread( void ( __cdecl *threadcode )( void* ), unsigned long stacksize, void *arg )
+{
+ struct FORK_ARG fa;
+ fa.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+ fa.threadcode = threadcode;
+ fa.arg = arg;
+
+ ULONG rc = _beginthread(( JABBER_THREAD_FUNC )forkthread_r, stacksize, &fa );
+ if (( unsigned long ) -1L != rc )
+ WaitForSingleObject( fa.hEvent, INFINITE );
+
+ CloseHandle( fa.hEvent );
+ return rc;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// JabberSetServerStatus()
+
+void JabberSetServerStatus( int iNewStatus )
+{
+ if ( !jabberConnected )
+ return;
+
+ // change status
+ int oldStatus = jabberStatus;
+ switch ( iNewStatus ) {
+ case ID_STATUS_ONLINE:
+ case ID_STATUS_NA:
+ case ID_STATUS_FREECHAT:
+ case ID_STATUS_INVISIBLE:
+ jabberStatus = iNewStatus;
+ break;
+ case ID_STATUS_AWAY:
+ case ID_STATUS_ONTHEPHONE:
+ case ID_STATUS_OUTTOLUNCH:
+ jabberStatus = ID_STATUS_AWAY;
+ break;
+ case ID_STATUS_DND:
+ case ID_STATUS_OCCUPIED:
+ jabberStatus = ID_STATUS_DND;
+ break;
+ default:
+ return;
+ }
+
+ // send presence update
+ JabberSendPresence( jabberStatus );
+ JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, jabberStatus );
+}
+
+// Process a string, and double all % characters, according to chat.dll's restrictions
+// Returns a pointer to the new string (old one is not freed)
+char* EscapeChatTags(char* pszText)
+{
+ int nChars = 0;
+ for ( char* p = pszText; ( p = strchr( p, '%' )) != NULL; p++ )
+ nChars++;
+
+ if ( nChars == 0 )
+ return mir_strdup( pszText );
+
+ char* pszNewText = (char*)mir_alloc( strlen( pszText ) + 1 + nChars ), *s, *d;
+ if ( pszNewText == NULL )
+ return mir_strdup( pszText );
+
+ for ( s = pszText, d = pszNewText; *s; s++ ) {
+ if ( *s == '%' )
+ *d++ = '%';
+ *d++ = *s;
+ }
+ *d = 0;
+ return pszNewText;
+}
+
+char* UnEscapeChatTags(char* str_in)
+{
+ char* s = str_in, *d = str_in;
+ while ( *s ) {
+ if (( *s == '%' && s[1] == '%' ) || ( *s == '\n' && s[1] == '\n' ))
+ s++;
+ *d++ = *s++;
+ }
+ *d = 0;
+ return str_in;
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_opt.cpp b/miranda-wine/protocols/JabberG/jabber_opt.cpp new file mode 100644 index 0000000..4454671 --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_opt.cpp @@ -0,0 +1,724 @@ +/*
+
+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_opt.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 "jabber_list.h"
+#include <commctrl.h>
+#include "resource.h"
+#include <uxtheme.h>
+
+extern BOOL jabberSendKeepAlive;
+extern UINT jabberCodePage;
+
+static BOOL (WINAPI *pfnEnableThemeDialogTexture)(HANDLE, DWORD) = 0;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberRegisterDlgProc - the dialog proc for registering new account
+
+#if defined( _UNICODE )
+ #define STR_FORMAT _T("%s %s@%S:%d?")
+#else
+ #define STR_FORMAT _T("%s %s@%s:%d?")
+#endif
+
+static BOOL CALLBACK JabberRegisterDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ struct ThreadData *thread, *regInfo;
+
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ {
+ TranslateDialogDefault( hwndDlg );
+ regInfo = ( struct ThreadData * ) lParam;
+ TCHAR text[256];
+ mir_sntprintf( text, SIZEOF(text), STR_FORMAT, TranslateT( "Register" ), regInfo->username, regInfo->server, regInfo->port );
+ SetDlgItemText( hwndDlg, IDC_REG_STATUS, text );
+ SetWindowLong( hwndDlg, GWL_USERDATA, ( LONG )regInfo );
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDOK:
+ ShowWindow( GetDlgItem( hwndDlg, IDOK ), SW_HIDE );
+ ShowWindow( GetDlgItem( hwndDlg, IDCANCEL ), SW_HIDE );
+ ShowWindow( GetDlgItem( hwndDlg, IDC_PROGRESS_REG ), SW_SHOW );
+ ShowWindow( GetDlgItem( hwndDlg, IDCANCEL2 ), SW_SHOW );
+ regInfo = ( struct ThreadData * ) GetWindowLong( hwndDlg, GWL_USERDATA );
+ thread = ( struct ThreadData * ) mir_alloc( sizeof( struct ThreadData ));
+ memset( thread, 0, sizeof( struct ThreadData ));
+ thread->type = JABBER_SESSION_REGISTER;
+ _tcsncpy( thread->username, regInfo->username, SIZEOF( thread->username ));
+ strncpy( thread->password, regInfo->password, SIZEOF( thread->password ));
+ strncpy( thread->server, regInfo->server, SIZEOF( thread->server ));
+ strncpy( thread->manualHost, regInfo->manualHost, SIZEOF( thread->manualHost ));
+ thread->port = regInfo->port;
+ thread->useSSL = regInfo->useSSL;
+ thread->reg_hwndDlg = hwndDlg;
+ JabberForkThread(( JABBER_THREAD_FUNC )JabberServerThread, 0, thread );
+ return TRUE;
+ case IDCANCEL:
+ case IDOK2:
+ EndDialog( hwndDlg, 0 );
+ return TRUE;
+ }
+ break;
+ case WM_JABBER_REGDLG_UPDATE: // wParam=progress ( 0-100 ), lparam=status string
+ if (( TCHAR* )lParam == NULL )
+ SetDlgItemText( hwndDlg, IDC_REG_STATUS, TranslateT( "No message" ));
+ else
+ SetDlgItemText( hwndDlg, IDC_REG_STATUS, ( TCHAR* )lParam );
+ if ( wParam >= 0 )
+ SendMessage( GetDlgItem( hwndDlg, IDC_PROGRESS_REG ), PBM_SETPOS, wParam, 0 );
+ if ( wParam >= 100 ) {
+ ShowWindow( GetDlgItem( hwndDlg, IDCANCEL2 ), SW_HIDE );
+ ShowWindow( GetDlgItem( hwndDlg, IDOK2 ), SW_SHOW );
+ }
+ else SetFocus( GetDlgItem( hwndDlg, IDC_PROGRESS_REG ));
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberOptDlgProc - main options dialog procedure
+
+static HWND msgLangListBox;
+static BOOL CALLBACK JabberMsgLangAdd( LPSTR str )
+{
+ int i, count, index;
+ UINT cp;
+ static struct { UINT cpId; TCHAR* cpName; } cpTable[] = {
+ { 874, _T("Thai") },
+ { 932, _T("Japanese") },
+ { 936, _T("Simplified Chinese") },
+ { 949, _T("Korean") },
+ { 950, _T("Traditional Chinese") },
+ { 1250, _T("Central European") },
+ { 1251, _T("Cyrillic") },
+ { 1252, _T("Latin I") },
+ { 1253, _T("Greek") },
+ { 1254, _T("Turkish") },
+ { 1255, _T("Hebrew") },
+ { 1256, _T("Arabic") },
+ { 1257, _T("Baltic") },
+ { 1258, _T("Vietnamese") },
+ { 1361, _T("Korean ( Johab )") }
+ };
+
+ cp = atoi( str );
+ count = sizeof( cpTable )/sizeof( cpTable[0] );
+ for ( i=0; i<count && cpTable[i].cpId!=cp; i++ );
+ if ( i < count ) {
+ if (( index=SendMessage( msgLangListBox, CB_ADDSTRING, 0, ( LPARAM )TranslateTS( cpTable[i].cpName )) ) >= 0 ) {
+ SendMessage( msgLangListBox, CB_SETITEMDATA, ( WPARAM ) index, ( LPARAM )cp );
+ if ( jabberCodePage == cp )
+ SendMessage( msgLangListBox, CB_SETCURSEL, ( WPARAM ) index, 0 );
+ } }
+
+ return TRUE;
+}
+
+static LRESULT CALLBACK JabberValidateUsernameWndProc( HWND hwndEdit, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ WNDPROC oldProc = ( WNDPROC ) GetWindowLong( hwndEdit, GWL_USERDATA );
+
+ switch ( msg ) {
+ case WM_CHAR:
+ if ( strchr( "\"&'/:<>@", wParam&0xff ) != NULL )
+ return 0;
+ break;
+ }
+ return CallWindowProc( oldProc, hwndEdit, msg, wParam, lParam );
+}
+
+static BOOL CALLBACK JabberOptDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ {
+ DBVARIANT dbv;
+ BOOL enableRegister = TRUE;
+
+ TranslateDialogDefault( hwndDlg );
+ SetDlgItemTextA( hwndDlg, IDC_SIMPLE, jabberModuleName );
+ if ( !DBGetContactSetting( NULL, jabberProtoName, "LoginName", &dbv )) {
+ SetDlgItemTextA( hwndDlg, IDC_EDIT_USERNAME, dbv.pszVal );
+ if ( !dbv.pszVal[0] ) enableRegister = FALSE;
+ JFreeVariant( &dbv );
+ }
+ if ( !DBGetContactSetting( NULL, jabberProtoName, "Password", &dbv )) {
+ JCallService( MS_DB_CRYPT_DECODESTRING, strlen( dbv.pszVal )+1, ( LPARAM )dbv.pszVal );
+ SetDlgItemTextA( hwndDlg, IDC_EDIT_PASSWORD, dbv.pszVal );
+ if ( !dbv.pszVal[0] ) enableRegister = FALSE;
+ JFreeVariant( &dbv );
+ }
+ if ( !DBGetContactSettingTString( NULL, jabberProtoName, "Resource", &dbv )) {
+ SetDlgItemText( hwndDlg, IDC_EDIT_RESOURCE, dbv.ptszVal );
+ JFreeVariant( &dbv );
+ }
+ else SetDlgItemTextA( hwndDlg, IDC_EDIT_RESOURCE, "Miranda" );
+
+ SendMessage( GetDlgItem( hwndDlg, IDC_PRIORITY_SPIN ), UDM_SETRANGE, 0, ( LPARAM )MAKELONG( 100, 0 ));
+
+ char text[256];
+ sprintf( text, "%d", JGetWord( NULL, "Priority", 0 ));
+ SetDlgItemTextA( hwndDlg, IDC_PRIORITY, text );
+ CheckDlgButton( hwndDlg, IDC_SAVEPASSWORD, JGetByte( "SavePassword", TRUE ));
+ if ( !DBGetContactSetting( NULL, jabberProtoName, "LoginServer", &dbv )) {
+ SetDlgItemTextA( hwndDlg, IDC_EDIT_LOGIN_SERVER, dbv.pszVal );
+ if ( !dbv.pszVal[0] ) enableRegister = FALSE;
+ JFreeVariant( &dbv );
+ }
+ else SetDlgItemTextA( hwndDlg, IDC_EDIT_LOGIN_SERVER, "jabber.org" );
+
+ WORD port = ( WORD )JGetWord( NULL, "Port", JABBER_DEFAULT_PORT );
+ SetDlgItemInt( hwndDlg, IDC_PORT, port, FALSE );
+ if ( port <= 0 ) enableRegister = FALSE;
+
+ CheckDlgButton( hwndDlg, IDC_USE_SSL, JGetByte( "UseSSL", FALSE ));
+ CheckDlgButton( hwndDlg, IDC_USE_TLS, JGetByte( "UseTLS", FALSE ));
+ EnableWindow(GetDlgItem( hwndDlg, IDC_USE_TLS ), !JGetByte( "UseSSL", FALSE ));
+
+ EnableWindow( GetDlgItem( hwndDlg, IDC_BUTTON_REGISTER ), enableRegister );
+
+ if ( JGetByte( "ManualConnect", FALSE ) == TRUE ) {
+ CheckDlgButton( hwndDlg, IDC_MANUAL, TRUE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_HOST ), TRUE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_HOSTPORT ), TRUE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_PORT ), FALSE );
+ }
+ if ( !DBGetContactSetting( NULL, jabberProtoName, "ManualHost", &dbv )) {
+ SetDlgItemTextA( hwndDlg, IDC_HOST, dbv.pszVal );
+ JFreeVariant( &dbv );
+ }
+ SetDlgItemInt( hwndDlg, IDC_HOSTPORT, JGetWord( NULL, "ManualPort", JABBER_DEFAULT_PORT ), FALSE );
+
+ CheckDlgButton( hwndDlg, IDC_KEEPALIVE, JGetByte( "KeepAlive", TRUE ));
+ CheckDlgButton( hwndDlg, IDC_ROSTER_SYNC, JGetByte( "RosterSync", FALSE ));
+
+ if ( !DBGetContactSetting( NULL, jabberProtoName, "Jud", &dbv )) {
+ SetDlgItemTextA( hwndDlg, IDC_JUD, dbv.pszVal );
+ JFreeVariant( &dbv );
+ }
+ else SetDlgItemTextA( hwndDlg, IDC_JUD, "users.jabber.org" );
+
+ msgLangListBox = GetDlgItem( hwndDlg, IDC_MSGLANG );
+ TCHAR str[ 256 ];
+ mir_sntprintf( str, SIZEOF(str), _T("== %s =="), TranslateT( "System default" ));
+ SendMessage( msgLangListBox, CB_ADDSTRING, 0, ( LPARAM )str );
+ SendMessage( msgLangListBox, CB_SETITEMDATA, 0, CP_ACP );
+ SendMessage( msgLangListBox, CB_SETCURSEL, 0, 0 );
+ EnumSystemCodePagesA( JabberMsgLangAdd, CP_INSTALLED );
+
+ WNDPROC oldProc = ( WNDPROC ) GetWindowLong( GetDlgItem( hwndDlg, IDC_EDIT_USERNAME ), GWL_WNDPROC );
+ SetWindowLong( GetDlgItem( hwndDlg, IDC_EDIT_USERNAME ), GWL_USERDATA, ( LONG ) oldProc );
+ SetWindowLong( GetDlgItem( hwndDlg, IDC_EDIT_USERNAME ), GWL_WNDPROC, ( LONG ) JabberValidateUsernameWndProc );
+
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDC_EDIT_USERNAME:
+ case IDC_EDIT_PASSWORD:
+ case IDC_EDIT_RESOURCE:
+ case IDC_EDIT_LOGIN_SERVER:
+ case IDC_PORT:
+ case IDC_MANUAL:
+ case IDC_HOST:
+ case IDC_HOSTPORT:
+ case IDC_JUD:
+ case IDC_PRIORITY:
+ {
+ if ( LOWORD( wParam ) == IDC_MANUAL ) {
+ if ( IsDlgButtonChecked( hwndDlg, IDC_MANUAL )) {
+ EnableWindow( GetDlgItem( hwndDlg, IDC_HOST ), TRUE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_HOSTPORT ), TRUE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_PORT ), FALSE );
+ }
+ else {
+ EnableWindow( GetDlgItem( hwndDlg, IDC_HOST ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_HOSTPORT ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_PORT ), TRUE );
+ }
+ SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
+ }
+ else {
+ if (( HWND )lParam==GetFocus() && HIWORD( wParam )==EN_CHANGE )
+ SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
+ }
+
+ ThreadData regInfo;
+ GetDlgItemText( hwndDlg, IDC_EDIT_USERNAME, regInfo.username, SIZEOF( regInfo.username ));
+ GetDlgItemTextA( hwndDlg, IDC_EDIT_PASSWORD, regInfo.password, SIZEOF( regInfo.password ));
+ GetDlgItemTextA( hwndDlg, IDC_EDIT_LOGIN_SERVER, regInfo.server, SIZEOF( regInfo.server ));
+ if ( IsDlgButtonChecked( hwndDlg, IDC_MANUAL )) {
+ regInfo.port = ( WORD )GetDlgItemInt( hwndDlg, IDC_HOSTPORT, NULL, FALSE );
+ GetDlgItemTextA( hwndDlg, IDC_HOST, regInfo.manualHost, SIZEOF( regInfo.manualHost ));
+ }
+ else {
+ regInfo.port = ( WORD )GetDlgItemInt( hwndDlg, IDC_PORT, NULL, FALSE );
+ regInfo.manualHost[0] = '\0';
+ }
+ if ( regInfo.username[0] && regInfo.password[0] && regInfo.server[0] && regInfo.port>0 && ( !IsDlgButtonChecked( hwndDlg, IDC_MANUAL ) || regInfo.manualHost[0] ))
+ EnableWindow( GetDlgItem( hwndDlg, IDC_BUTTON_REGISTER ), TRUE );
+ else
+ EnableWindow( GetDlgItem( hwndDlg, IDC_BUTTON_REGISTER ), FALSE );
+ break;
+ }
+ case IDC_LINK_PUBLIC_SERVER:
+ ShellExecuteA( hwndDlg, "open", "http://www.jabber.org/network", "", "", SW_SHOW );
+ return TRUE;
+ case IDC_BUTTON_REGISTER:
+ {
+ ThreadData regInfo;
+ GetDlgItemText( hwndDlg, IDC_EDIT_USERNAME, regInfo.username, SIZEOF( regInfo.username ));
+ GetDlgItemTextA( hwndDlg, IDC_EDIT_PASSWORD, regInfo.password, SIZEOF( regInfo.password ));
+ GetDlgItemTextA( hwndDlg, IDC_EDIT_LOGIN_SERVER, regInfo.server, SIZEOF( regInfo.server ));
+ if ( IsDlgButtonChecked( hwndDlg, IDC_MANUAL )) {
+ GetDlgItemTextA( hwndDlg, IDC_HOST, regInfo.manualHost, SIZEOF( regInfo.manualHost ));
+ regInfo.port = ( WORD )GetDlgItemInt( hwndDlg, IDC_HOSTPORT, NULL, FALSE );
+ }
+ else {
+ regInfo.manualHost[0] = '\0';
+ regInfo.port = ( WORD )GetDlgItemInt( hwndDlg, IDC_PORT, NULL, FALSE );
+ }
+ regInfo.useSSL = IsDlgButtonChecked( hwndDlg, IDC_USE_SSL );
+
+ if ( regInfo.username[0] && regInfo.password[0] && regInfo.server[0] && regInfo.port>0 && ( !IsDlgButtonChecked( hwndDlg, IDC_MANUAL ) || regInfo.manualHost[0] ))
+ DialogBoxParam( hInst, MAKEINTRESOURCE( IDD_OPT_REGISTER ), hwndDlg, JabberRegisterDlgProc, ( LPARAM )®Info );
+
+ return TRUE;
+ }
+ case IDC_MSGLANG:
+ if ( HIWORD( wParam ) == CBN_SELCHANGE )
+ SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
+ break;
+ case IDC_USE_SSL:
+ if ( !IsDlgButtonChecked( hwndDlg, IDC_MANUAL )) {
+ if ( IsDlgButtonChecked( hwndDlg, IDC_USE_SSL )) {
+ EnableWindow(GetDlgItem( hwndDlg, IDC_USE_TLS ), FALSE );
+ SetDlgItemInt( hwndDlg, IDC_PORT, 5223, FALSE );
+ }
+ else {
+ EnableWindow(GetDlgItem( hwndDlg, IDC_USE_TLS ), TRUE );
+ SetDlgItemInt( hwndDlg, IDC_PORT, 5222, FALSE );
+ } }
+ // Fall through
+ case IDC_USE_TLS:
+ case IDC_SAVEPASSWORD:
+ case IDC_KEEPALIVE:
+ case IDC_ROSTER_SYNC:
+ SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
+ break;
+ default:
+ return 0;
+ }
+ break;
+ case WM_NOTIFY:
+ if (( ( LPNMHDR ) lParam )->code == PSN_APPLY ) {
+ BOOL reconnectRequired = FALSE;
+ DBVARIANT dbv;
+
+ char userName[256], text[256];
+ TCHAR textT [256];
+ GetDlgItemTextA( hwndDlg, IDC_EDIT_USERNAME, userName, sizeof( userName ));
+ if ( DBGetContactSetting( NULL, jabberProtoName, "LoginName", &dbv ) || strcmp( userName, dbv.pszVal ))
+ reconnectRequired = TRUE;
+ if ( dbv.pszVal != NULL ) JFreeVariant( &dbv );
+ JSetString( NULL, "LoginName", userName );
+
+ if ( IsDlgButtonChecked( hwndDlg, IDC_SAVEPASSWORD )) {
+ GetDlgItemTextA( hwndDlg, IDC_EDIT_PASSWORD, text, sizeof( text ));
+ JCallService( MS_DB_CRYPT_ENCODESTRING, sizeof( text ), ( LPARAM )text );
+ if ( DBGetContactSetting( NULL, jabberProtoName, "Password", &dbv ) || strcmp( text, dbv.pszVal ))
+ reconnectRequired = TRUE;
+ if ( dbv.pszVal != NULL ) JFreeVariant( &dbv );
+ JSetString( NULL, "Password", text );
+ }
+ else JDeleteSetting( NULL, "Password" );
+
+ GetDlgItemText( hwndDlg, IDC_EDIT_RESOURCE, textT, SIZEOF( textT ));
+ if ( !JGetStringT( NULL, "Resource", &dbv )) {
+ if ( _tcscmp( textT, dbv.ptszVal ))
+ reconnectRequired = TRUE;
+ JFreeVariant( &dbv );
+ }
+ else reconnectRequired = TRUE;
+ JSetStringT( NULL, "Resource", textT );
+
+ GetDlgItemTextA( hwndDlg, IDC_PRIORITY, text, sizeof( text ));
+ WORD port = ( WORD )atoi( text );
+ if ( port > 100 ) port = 100;
+ if ( port < 0 ) port = 0;
+ if ( JGetWord( NULL, "Priority", 0 ) != port )
+ reconnectRequired = TRUE;
+ JSetWord( NULL, "Priority", ( WORD )port );
+
+ JSetByte( "SavePassword", ( BYTE ) IsDlgButtonChecked( hwndDlg, IDC_SAVEPASSWORD ));
+
+ GetDlgItemTextA( hwndDlg, IDC_EDIT_LOGIN_SERVER, text, sizeof( text ));
+ if ( DBGetContactSetting( NULL, jabberProtoName, "LoginServer", &dbv ) || strcmp( text, dbv.pszVal ))
+ reconnectRequired = TRUE;
+ if ( dbv.pszVal != NULL ) JFreeVariant( &dbv );
+ JSetString( NULL, "LoginServer", text );
+
+ strcat( userName, "@" );
+ strncat( userName, text, sizeof( userName ));
+ userName[ sizeof(userName)-1 ] = 0;
+ JSetString( NULL, "jid", userName );
+
+ port = ( WORD )GetDlgItemInt( hwndDlg, IDC_PORT, NULL, FALSE );
+ if ( JGetWord( NULL, "Port", JABBER_DEFAULT_PORT ) != port )
+ reconnectRequired = TRUE;
+ JSetWord( NULL, "Port", port );
+
+ JSetByte( "UseSSL", ( BYTE ) IsDlgButtonChecked( hwndDlg, IDC_USE_SSL ));
+ JSetByte( "UseTLS", ( BYTE ) IsDlgButtonChecked( hwndDlg, IDC_USE_TLS ));
+
+ JSetByte( "ManualConnect", ( BYTE ) IsDlgButtonChecked( hwndDlg, IDC_MANUAL ));
+
+ GetDlgItemTextA( hwndDlg, IDC_HOST, text, sizeof( text ));
+ if ( DBGetContactSetting( NULL, jabberProtoName, "ManualHost", &dbv ) || strcmp( text, dbv.pszVal ))
+ reconnectRequired = TRUE;
+ if ( dbv.pszVal != NULL ) JFreeVariant( &dbv );
+ JSetString( NULL, "ManualHost", text );
+
+ port = ( WORD )GetDlgItemInt( hwndDlg, IDC_HOSTPORT, NULL, FALSE );
+ if ( JGetWord( NULL, "ManualPort", JABBER_DEFAULT_PORT ) != port )
+ reconnectRequired = TRUE;
+ JSetWord( NULL, "ManualPort", port );
+
+ JSetByte( "KeepAlive", ( BYTE ) IsDlgButtonChecked( hwndDlg, IDC_KEEPALIVE ));
+ jabberSendKeepAlive = IsDlgButtonChecked( hwndDlg, IDC_KEEPALIVE );
+
+ JSetByte( "RosterSync", ( BYTE ) IsDlgButtonChecked( hwndDlg, IDC_ROSTER_SYNC ));
+
+ GetDlgItemTextA( hwndDlg, IDC_JUD, text, sizeof( text ));
+ JSetString( NULL, "Jud", text );
+
+ int index = SendMessage( GetDlgItem( hwndDlg, IDC_MSGLANG ), CB_GETCURSEL, 0, 0 );
+ if ( index >= 0 ) {
+ jabberCodePage = SendMessage( GetDlgItem( hwndDlg, IDC_MSGLANG ), CB_GETITEMDATA, ( WPARAM ) index, 0 );
+ JSetWord( NULL, "CodePage", ( WORD )jabberCodePage );
+ }
+
+ if ( reconnectRequired && jabberConnected )
+ MessageBox( hwndDlg, TranslateT( "These changes will take effect the next time you connect to the Jabber network." ), TranslateT( "Jabber Protocol Option" ), MB_OK|MB_SETFOREGROUND );
+
+ return TRUE;
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberAdvOptDlgProc - advanced options dialog procedure
+
+static BOOL CALLBACK JabberAdvOptDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ char text[256];
+ BOOL bChecked;
+
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ {
+ TranslateDialogDefault( hwndDlg );
+
+ // File transfer options
+ BOOL bDirect = JGetByte( "BsDirect", TRUE );
+ BOOL bManualDirect = JGetByte( "BsDirectManual", FALSE );
+ CheckDlgButton( hwndDlg, IDC_DIRECT, bDirect );
+ CheckDlgButton( hwndDlg, IDC_DIRECT_MANUAL, bManualDirect );
+
+ DBVARIANT dbv;
+ if ( !DBGetContactSetting( NULL, jabberProtoName, "BsDirectAddr", &dbv )) {
+ SetDlgItemTextA( hwndDlg, IDC_DIRECT_ADDR, dbv.pszVal );
+ JFreeVariant( &dbv );
+ }
+ if ( !bDirect )
+ EnableWindow( GetDlgItem( hwndDlg, IDC_DIRECT_MANUAL ), FALSE );
+ if ( !bDirect || !bManualDirect )
+ EnableWindow( GetDlgItem( hwndDlg, IDC_DIRECT_ADDR ), FALSE );
+
+ BOOL bProxy = JGetByte( "BsProxy", FALSE );
+ BOOL bManualProxy = JGetByte( "BsProxyManual", FALSE );
+ CheckDlgButton( hwndDlg, IDC_PROXY, bProxy );
+ CheckDlgButton( hwndDlg, IDC_PROXY_MANUAL, bManualProxy );
+ if ( !DBGetContactSetting( NULL, jabberProtoName, "BsProxyServer", &dbv )) {
+ SetDlgItemTextA( hwndDlg, IDC_PROXY_ADDR, dbv.pszVal );
+ JFreeVariant( &dbv );
+ }
+ if ( !bProxy )
+ EnableWindow( GetDlgItem( hwndDlg, IDC_PROXY_MANUAL ), FALSE );
+ if ( !bProxy || !bManualProxy )
+ EnableWindow( GetDlgItem( hwndDlg, IDC_PROXY_ADDR ), FALSE );
+
+ // Miscellaneous options
+ CheckDlgButton( hwndDlg, IDC_SHOW_TRANSPORT, JGetByte( "ShowTransport", TRUE ));
+ CheckDlgButton( hwndDlg, IDC_AUTO_ADD, JGetByte( "AutoAdd", TRUE ));
+ CheckDlgButton( hwndDlg, IDC_MSG_ACK, JGetByte( "MsgAck", FALSE ));
+ CheckDlgButton( hwndDlg, IDC_DISABLE_MAINMENU, JGetByte( "DisableMainMenu", FALSE ));
+ CheckDlgButton( hwndDlg, IDC_ENABLE_AVATARS, JGetByte( "EnableAvatars", TRUE ));
+ CheckDlgButton( hwndDlg, IDC_AUTO_ACCEPT_MUC, JGetByte( "AutoAcceptMUC", FALSE ));
+ CheckDlgButton( hwndDlg, IDC_AUTOJOIN, JGetByte( "AutoJoinConferences", FALSE ));
+ CheckDlgButton( hwndDlg, IDC_DISABLE_SASL, JGetByte( "Disable3920auth", FALSE ));
+ return TRUE;
+ }
+ case WM_COMMAND:
+ {
+ switch ( LOWORD( wParam )) {
+ case IDC_DIRECT_ADDR:
+ case IDC_PROXY_ADDR:
+ if (( HWND )lParam==GetFocus() && HIWORD( wParam )==EN_CHANGE )
+ goto LBL_Apply;
+ break;
+ case IDC_DIRECT:
+ bChecked = IsDlgButtonChecked( hwndDlg, IDC_DIRECT );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_DIRECT_MANUAL ), bChecked );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_DIRECT_ADDR ), ( bChecked && IsDlgButtonChecked( hwndDlg, IDC_DIRECT_MANUAL )) );
+ goto LBL_Apply;
+ case IDC_DIRECT_MANUAL:
+ bChecked = IsDlgButtonChecked( hwndDlg, IDC_DIRECT_MANUAL );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_DIRECT_ADDR ), bChecked );
+ goto LBL_Apply;
+ case IDC_PROXY:
+ bChecked = IsDlgButtonChecked( hwndDlg, IDC_PROXY );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_PROXY_MANUAL ), bChecked );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_PROXY_ADDR ), ( bChecked && IsDlgButtonChecked( hwndDlg, IDC_PROXY_MANUAL )) );
+ goto LBL_Apply;
+ case IDC_PROXY_MANUAL:
+ bChecked = IsDlgButtonChecked( hwndDlg, IDC_PROXY_MANUAL );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_PROXY_ADDR ), bChecked );
+ default:
+ LBL_Apply:
+ SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
+ break;
+ }
+ break;
+ }
+ case WM_NOTIFY:
+ if (( ( LPNMHDR ) lParam )->code == PSN_APPLY ) {
+ // File transfer options
+ JSetByte( "BsDirect", ( BYTE ) IsDlgButtonChecked( hwndDlg, IDC_DIRECT ));
+ JSetByte( "BsDirectManual", ( BYTE ) IsDlgButtonChecked( hwndDlg, IDC_DIRECT_MANUAL ));
+ GetDlgItemTextA( hwndDlg, IDC_DIRECT_ADDR, text, sizeof( text ));
+ JSetString( NULL, "BsDirectAddr", text );
+ JSetByte( "BsProxy", ( BYTE ) IsDlgButtonChecked( hwndDlg, IDC_PROXY ));
+ JSetByte( "BsProxyManual", ( BYTE ) IsDlgButtonChecked( hwndDlg, IDC_PROXY_MANUAL ));
+ GetDlgItemTextA( hwndDlg, IDC_PROXY_ADDR, text, sizeof( text ));
+ JSetString( NULL, "BsProxyAddr", text );
+
+ // Miscellaneous options
+ bChecked = IsDlgButtonChecked( hwndDlg, IDC_SHOW_TRANSPORT );
+ JSetByte( "ShowTransport", ( BYTE ) bChecked );
+ int index = 0;
+ while (( index=JabberListFindNext( LIST_ROSTER, index )) >= 0 ) {
+ JABBER_LIST_ITEM* item = JabberListGetItemPtrFromIndex( index );
+ if ( item != NULL ) {
+ if ( _tcschr( item->jid, '@' ) == NULL ) {
+ HANDLE hContact = JabberHContactFromJID( item->jid );
+ if ( hContact != NULL ) {
+ if ( bChecked ) {
+ if ( item->status != JGetWord( hContact, "Status", ID_STATUS_OFFLINE )) {
+ JSetWord( hContact, "Status", ( WORD )item->status );
+ } }
+ else if ( JGetWord( hContact, "Status", ID_STATUS_OFFLINE ) != ID_STATUS_OFFLINE )
+ JSetWord( hContact, "Status", ID_STATUS_OFFLINE );
+ } } }
+ index++;
+ }
+
+ JSetByte( "AutoAdd", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_AUTO_ADD ));
+ JSetByte( "MsgAck", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_MSG_ACK ));
+ JSetByte( "DisableMainMenu", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_DISABLE_MAINMENU ));
+ JSetByte( "Disable3920auth", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_DISABLE_SASL ));
+ JSetByte( "EnableAvatars", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_ENABLE_AVATARS ));
+ JSetByte( "AutoAcceptMUC", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_AUTO_ACCEPT_MUC ));
+ JSetByte( "AutoJoinConferences", ( BYTE )IsDlgButtonChecked( hwndDlg, IDC_AUTOJOIN ));
+ return TRUE;
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberOptInit - initializes all options dialogs
+
+static HWND hwndAcc = 0, hwndAdv = 0;
+
+static void SetOptionsDlgToType(HWND hwnd, int iExpert)
+{
+ TCITEM tci;
+ RECT rcClient;
+ HWND hwndTab = GetDlgItem(hwnd, IDC_OPTIONSTAB), hwndEnum;
+ int iPages = 0;
+
+ if(!hwndAcc)
+ hwndAcc = CreateDialog(hInst,MAKEINTRESOURCE(IDD_OPT_JABBER), hwnd, JabberOptDlgProc);
+
+ hwndEnum = GetWindow(hwndAcc, GW_CHILD);
+
+ while(hwndEnum) {
+ ShowWindow(hwndEnum, iExpert ? SW_SHOW : SW_HIDE);
+ hwndEnum = GetWindow(hwndEnum, GW_HWNDNEXT);
+ }
+ if(!iExpert) {
+ hwndEnum = GetDlgItem(hwndAcc, IDC_SIMPLE);
+ ShowWindow(hwndEnum, SW_SHOW);
+ hwndEnum = GetWindow(hwndEnum, GW_HWNDNEXT);
+ do {
+ ShowWindow(hwndEnum, SW_SHOW);
+ hwndEnum = GetWindow(hwndEnum, GW_HWNDNEXT);
+ } while(hwndEnum && hwndEnum != GetDlgItem(hwndAcc, IDC_LINK_PUBLIC_SERVER));
+ }
+ ShowWindow(hwndEnum, SW_SHOW);
+ GetClientRect(hwnd, &rcClient);
+ TabCtrl_DeleteAllItems(hwndTab);
+
+ tci.mask = TCIF_PARAM|TCIF_TEXT;
+ tci.lParam = (LPARAM)hwndAcc;
+ tci.pszText = TranslateT("Account");
+ TabCtrl_InsertItem(hwndTab, 0, &tci);
+ MoveWindow((HWND)tci.lParam,5,26,rcClient.right-8,rcClient.bottom-29,1);
+ iPages++;
+
+ if(!hwndAdv)
+ hwndAdv = CreateDialog(hInst,MAKEINTRESOURCE(IDD_OPT_JABBER2),hwnd,JabberAdvOptDlgProc);
+
+ if(pfnEnableThemeDialogTexture) {
+ if(hwndAcc)
+ pfnEnableThemeDialogTexture(hwndAcc, ETDT_ENABLETAB);
+ if(hwndAdv)
+ pfnEnableThemeDialogTexture(hwndAdv, ETDT_ENABLETAB);
+ }
+
+ ShowWindow(hwndAdv, SW_HIDE);
+ ShowWindow(hwndAcc, SW_SHOW);
+
+ if(iExpert) {
+ tci.lParam = (LPARAM)hwndAdv;
+ tci.pszText = TranslateT("Advanced");
+ TabCtrl_InsertItem(hwndTab, iPages++, &tci);
+ MoveWindow((HWND)tci.lParam,5,26,rcClient.right-8,rcClient.bottom-29,1);
+ }
+ TabCtrl_SetCurSel(hwndTab, 0);
+}
+
+static BOOL CALLBACK OptionsDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static int iInit = TRUE;
+
+ switch(msg) {
+ case WM_INITDIALOG:
+ {
+ iInit = TRUE;
+ int iExpert = SendMessage(GetParent(hwnd), PSM_ISEXPERT, 0, 0);
+ SetOptionsDlgToType(hwnd, iExpert);
+ iInit = FALSE;
+ return FALSE;
+ }
+ case WM_DESTROY:
+ hwndAcc = hwndAdv = 0;
+ break;
+ case PSM_CHANGED: // used so tabs dont have to call SendMessage(GetParent(GetParent(hwnd)), PSM_CHANGED, 0, 0);
+ if(!iInit)
+ SendMessage(GetParent(hwnd), PSM_CHANGED, 0, 0);
+ break;
+ case WM_NOTIFY:
+ switch(((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_APPLY:
+ {
+ TCITEM tci;
+ int i,count = TabCtrl_GetItemCount(GetDlgItem(hwnd,IDC_OPTIONSTAB));
+ tci.mask = TCIF_PARAM;
+ for (i=0;i<count;i++) {
+ TabCtrl_GetItem(GetDlgItem(hwnd,IDC_OPTIONSTAB),i,&tci);
+ SendMessage((HWND)tci.lParam,WM_NOTIFY,0,lParam);
+ }
+ break;
+ }
+ case PSN_EXPERTCHANGED:
+ {
+ int iExpert = SendMessage(GetParent(hwnd), PSM_ISEXPERT, 0, 0);
+ SetOptionsDlgToType(hwnd, iExpert);
+ break;
+ } }
+ break;
+ case IDC_OPTIONSTAB:
+ switch (((LPNMHDR)lParam)->code) {
+ case TCN_SELCHANGING:
+ {
+ TCITEM tci;
+ tci.mask = TCIF_PARAM;
+ TabCtrl_GetItem(GetDlgItem(hwnd,IDC_OPTIONSTAB),TabCtrl_GetCurSel(GetDlgItem(hwnd,IDC_OPTIONSTAB)),&tci);
+ ShowWindow((HWND)tci.lParam,SW_HIDE);
+ }
+ break;
+ case TCN_SELCHANGE:
+ {
+ TCITEM tci;
+ tci.mask = TCIF_PARAM;
+ TabCtrl_GetItem(GetDlgItem(hwnd,IDC_OPTIONSTAB),TabCtrl_GetCurSel(GetDlgItem(hwnd,IDC_OPTIONSTAB)),&tci);
+ ShowWindow((HWND)tci.lParam,SW_SHOW);
+ break;
+ } }
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+int JabberOptInit( WPARAM wParam, LPARAM lParam )
+{
+ OPTIONSDIALOGPAGE odp = { 0 };
+ HMODULE hUxTheme = 0;
+
+ if(IsWinVerXPPlus()) {
+ hUxTheme = GetModuleHandle(_T("uxtheme.dll"));
+
+ if(hUxTheme)
+ pfnEnableThemeDialogTexture = (BOOL (WINAPI *)(HANDLE, DWORD))GetProcAddress(hUxTheme, "EnableThemeDialogTexture");
+ }
+
+ odp.cbSize = sizeof( odp );
+ odp.hInstance = hInst;
+ odp.pszGroup = "Network";
+ odp.pszTemplate = MAKEINTRESOURCEA( IDD_OPT_JABBERMAIN );
+ odp.pszTitle = jabberModuleName;
+ odp.pfnDlgProc = OptionsDlgProc;
+ odp.flags = ODPF_BOLDGROUPS;
+ JCallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
+ return 0;
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_password.cpp b/miranda-wine/protocols/JabberG/jabber_password.cpp new file mode 100644 index 0000000..da4c4c2 --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_password.cpp @@ -0,0 +1,100 @@ +/*
+
+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_password.cpp,v $
+Revision : $Revision: 3351 $
+Last change on : $Date: 2006-07-21 00:31:42 +0400 (Птн, 21 Июл 2006) $
+Last change by : $Author: rainwater $
+
+*/
+
+#include "jabber.h"
+#include "jabber_iq.h"
+#include "resource.h"
+
+static BOOL CALLBACK JabberChangePasswordDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam );
+
+int JabberMenuHandleChangePassword( WPARAM wParam, LPARAM lParam )
+{
+ if ( IsWindow( hwndJabberChangePassword ))
+ SetForegroundWindow( hwndJabberChangePassword );
+ else {
+ hwndJabberChangePassword = CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_CHANGEPASSWORD ), NULL, JabberChangePasswordDlgProc, 0 );
+ }
+
+ return 0;
+}
+
+static BOOL CALLBACK JabberChangePasswordDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ SendMessage( hwndDlg, WM_SETICON, ICON_BIG, ( LPARAM )LoadIcon( hInst, MAKEINTRESOURCE( IDI_KEYS )) );
+ TranslateDialogDefault( hwndDlg );
+ if ( jabberOnline && jabberThreadInfo!=NULL ) {
+ TCHAR text[128];
+ mir_sntprintf( text, SIZEOF( text ), _T("%s %s@") _T(TCHAR_STR_PARAM), TranslateT( "Set New Password for" ), jabberThreadInfo->username, jabberThreadInfo->server );
+ SetWindowText( hwndDlg, text );
+ }
+ return TRUE;
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDOK:
+ if ( jabberOnline && jabberThreadInfo!=NULL ) {
+ char newPasswd[128], text[128];
+ GetDlgItemTextA( hwndDlg, IDC_NEWPASSWD, newPasswd, SIZEOF( newPasswd ));
+ GetDlgItemTextA( hwndDlg, IDC_NEWPASSWD2, text, SIZEOF( text ));
+ if ( strcmp( newPasswd, text )) {
+ MessageBox( hwndDlg, TranslateT( "New password does not match." ), TranslateT( "Change Password" ), MB_OK|MB_ICONSTOP|MB_SETFOREGROUND );
+ break;
+ }
+ GetDlgItemTextA( hwndDlg, IDC_OLDPASSWD, text, SIZEOF( text ));
+ if ( strcmp( text, jabberThreadInfo->password )) {
+ MessageBox( hwndDlg, TranslateT( "Current password is incorrect." ), TranslateT( "Change Password" ), MB_OK|MB_ICONSTOP|MB_SETFOREGROUND );
+ break;
+ }
+ strncpy( jabberThreadInfo->newPassword, newPasswd, SIZEOF( jabberThreadInfo->newPassword ));
+
+ int iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_NONE, JabberIqResultSetPassword );
+
+ XmlNodeIq iq( "set", iqId, jabberThreadInfo->server );
+ XmlNode* q = iq.addQuery( "jabber:iq:register" );
+ q->addChild( "username", jabberThreadInfo->username );
+ q->addChild( "password", newPasswd );
+ JabberSend( jabberThreadInfo->s, iq );
+ }
+ DestroyWindow( hwndDlg );
+ break;
+ case IDCANCEL:
+ DestroyWindow( hwndDlg );
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ DestroyWindow( hwndDlg );
+ break;
+ case WM_DESTROY:
+ hwndJabberChangePassword = NULL;
+ break;
+ }
+
+ return FALSE;
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_proxy.cpp b/miranda-wine/protocols/JabberG/jabber_proxy.cpp new file mode 100644 index 0000000..51fae58 --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_proxy.cpp @@ -0,0 +1,154 @@ +/*
+
+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_proxy.cpp,v $
+Revision : $Revision: 2866 $
+Last change on : $Date: 2006-05-16 20:39:40 +0400 (Втр, 16 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+
+int JabberHttpGatewayInit( HANDLE hConn, NETLIBOPENCONNECTION *nloc, NETLIBHTTPREQUEST *nlhr )
+{
+#ifdef NNNN
+ WORD wLen, wVersion, wType;
+ WORD wIpLen;
+ DWORD dwSid1, dwSid2, dwSid3, dwSid4;
+ BYTE response[300], *buf;
+ int responseBytes, recvResult;
+ char szSid[33], szHttpServer[256], szHttpGetUrl[300], szHttpPostUrl[300];
+ NETLIBHTTPPROXYINFO nlhpi = {0};
+
+ for( responseBytes = 0; ; ) {
+ recvResult = Netlib_Recv( hConn, response + responseBytes, sizeof( response ) - responseBytes, MSG_DUMPPROXY );
+ if( recvResult<=0 ) break;
+ responseBytes += recvResult;
+ if( responseBytes == sizeof( response ))
+ break;
+ }
+ if( responseBytes < 31 )
+ {
+ SetLastError( ERROR_INVALID_DATA );
+ return 0;
+ }
+ buf = response;
+ unpackWord( &buf, &wLen );
+ unpackWord( &buf, &wVersion ); /* always 0x0443 */
+ unpackWord( &buf, &wType );
+ buf += 6; /* dunno */
+ unpackDWord( &buf, &dwSid1 );
+ unpackDWord( &buf, &dwSid2 );
+ unpackDWord( &buf, &dwSid3 );
+ unpackDWord( &buf, &dwSid4 );
+ sprintf( szSid, "%08x%08x%08x%08x", dwSid1, dwSid2, dwSid3, dwSid4 );
+ unpackWord( &buf, &wIpLen );
+ if( responseBytes < 30 + wIpLen || wIpLen == 0 || wIpLen > sizeof( szHttpServer ) - 1 )
+ {
+ SetLastError( ERROR_INVALID_DATA );
+ return 0;
+ }
+ memcpy( szHttpServer, buf, wIpLen );
+ szHttpServer[wIpLen] = '\0';
+
+ nlhpi.cbSize = sizeof( nlhpi );
+ nlhpi.flags = NLHPIF_USEPOSTSEQUENCE;
+ nlhpi.szHttpGetUrl = szHttpGetUrl;
+ nlhpi.szHttpPostUrl = szHttpPostUrl;
+ nlhpi.firstPostSequence = 1;
+ sprintf( szHttpGetUrl, "http://%s/monitor?sid=%s", szHttpServer, szSid );
+ sprintf( szHttpPostUrl, "http://%s/data?sid=%s&seq=", szHttpServer, szSid );
+ return JCallService( MS_NETLIB_SETHTTPPROXYINFO, ( WPARAM )hConn, ( LPARAM )&nlhpi );
+#endif
+ return 1;
+}
+
+int JabberHttpGatewayBegin( HANDLE hConn, NETLIBOPENCONNECTION *nloc )
+{
+ /*
+ icq_packet packet;
+ int serverNameLen;
+
+ serverNameLen = strlen( nloc->szHost );
+
+ packet.wLen = ( WORD )( serverNameLen + 4 );
+ write_httphdr( &packet, HTTP_PACKETTYPE_LOGIN );
+ packWord( &packet, ( WORD )serverNameLen );
+ packString( &packet, nloc->szHost, ( WORD )serverNameLen );
+ packWord( &packet, nloc->wPort );
+ Netlib_Send( hConn, packet.pData, packet.wLen, MSG_DUMPPROXY|MSG_NOHTTPGATEWAYWRAP );
+ mir_free( packet.pData );
+ return 1;
+ */
+ return 1;
+}
+
+#if 0
+int icq_httpGatewayWrapSend( HANDLE hConn, PBYTE buf, int len, int flags, MIRANDASERVICE pfnNetlibSend )
+{
+ icq_packet packet;
+ int sendResult;
+
+ packet.wLen = len;
+ write_httphdr( &packet, HTTP_PACKETTYPE_FLAP );
+ packString( &packet, buf, ( WORD )len );
+ sendResult = Netlib_Send( hConn, packet.pData, packet.wLen, flags );
+ mir_free( packet.pData );
+ if( sendResult <= 0 )
+ return sendResult;
+ if( sendResult < 14 )
+ return 0;
+ return sendResult - 14;
+}
+
+PBYTE icq_httpGatewayUnwrapRecv( NETLIBHTTPREQUEST *nlhr, PBYTE buf, int len, int *outBufLen, void *( *NetlibRealloc )( void *, size_t ))
+{
+ WORD wLen, wType;
+ PBYTE tbuf;
+ int i, copyBytes;
+
+ tbuf = buf;
+ for( i = 0;; )
+ {
+ if ( tbuf - buf + 2 > len ) break;
+ unpackWord( &tbuf, &wLen );
+ if ( wLen < 12 ) break;
+ if ( tbuf - buf + wLen > len ) break;
+ tbuf += 2; /* version */
+ unpackWord( &tbuf, &wType );
+ tbuf += 8; /* flags & subtype */
+ if ( wType == HTTP_PACKETTYPE_FLAP )
+ {
+ copyBytes = wLen - 12;
+ if ( copyBytes > len - i )
+ {
+ /* invalid data - do our best to get something out of it */
+ copyBytes = len - i;
+ }
+ memcpy( buf + i, tbuf, copyBytes );
+ i += copyBytes;
+ }
+ tbuf += wLen - 12;
+ }
+ *outBufLen = i;
+ return buf;
+}
+#endif
diff --git a/miranda-wine/protocols/JabberG/jabber_proxy.h b/miranda-wine/protocols/JabberG/jabber_proxy.h new file mode 100644 index 0000000..02a5d9f --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_proxy.h @@ -0,0 +1,34 @@ +/*
+
+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_proxy.h,v $
+Revision : $Revision: 2866 $
+Last change on : $Date: 2006-05-16 20:39:40 +0400 (Втр, 16 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#ifndef _JABBER_PROXY_H_
+#define _JABBER_PROXY_H_
+
+int JabberHttpGatewayInit( HANDLE hConn, NETLIBOPENCONNECTION *nloc, NETLIBHTTPREQUEST *nlhr );
+int JabberHttpGatewayBegin( HANDLE hConn, NETLIBOPENCONNECTION *nloc );
+
+#endif
\ No newline at end of file diff --git a/miranda-wine/protocols/JabberG/jabber_ssl.cpp b/miranda-wine/protocols/JabberG/jabber_ssl.cpp new file mode 100644 index 0000000..5c7f23b --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_ssl.cpp @@ -0,0 +1,181 @@ +/*
+
+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_ssl.cpp,v $
+Revision : $Revision: 2866 $
+Last change on : $Date: 2006-05-16 20:39:40 +0400 (Втр, 16 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#define _JABBER_SSL_C_
+
+#include "jabber.h"
+#include "jabber_ssl.h"
+
+PFN_SSL_int_void pfn_SSL_library_init; // int SSL_library_init()
+PFN_SSL_pvoid_void pfn_SSLv23_client_method; // SSL_METHOD *SSLv23_client_method()
+PFN_SSL_pvoid_pvoid pfn_SSL_CTX_new; // SSL_CTX *SSL_CTX_new( SSL_METHOD *method )
+PFN_SSL_void_pvoid pfn_SSL_CTX_free; // void SSL_CTX_free( SSL_CTX *ctx );
+PFN_SSL_pvoid_pvoid pfn_SSL_new; // SSL *SSL_new( SSL_CTX *ctx )
+PFN_SSL_void_pvoid pfn_SSL_free; // void SSL_free( SSL *ssl );
+PFN_SSL_int_pvoid_int pfn_SSL_set_fd; // int SSL_set_fd( SSL *ssl, int fd );
+PFN_SSL_int_pvoid pfn_SSL_connect; // int SSL_connect( SSL *ssl );
+PFN_SSL_int_pvoid_pvoid_int pfn_SSL_read; // int SSL_read( SSL *ssl, void *buffer, int bufsize )
+PFN_SSL_int_pvoid_pvoid_int pfn_SSL_write; // int SSL_write( SSL *ssl, void *buffer, int bufsize )
+
+static CRITICAL_SECTION sslHandleMutex;
+static JABBER_SSL_MAPPING *sslHandleList = NULL;
+static int sslHandleCount = 0;
+
+BOOL JabberSslInit()
+{
+ BOOL error = FALSE;
+
+ sslHandleList = NULL;
+ sslHandleCount = 0;
+ InitializeCriticalSection( &sslHandleMutex );
+
+ hLibSSL = LoadLibraryA( "SSLEAY32.DLL" );
+
+ if ( !hLibSSL )
+ hLibSSL = LoadLibraryA( "LIBSSL32.DLL" );
+
+ if ( hLibSSL ) {
+ if (( pfn_SSL_library_init=( PFN_SSL_int_void )GetProcAddress( hLibSSL, "SSL_library_init" )) == NULL )
+ error = TRUE;
+ if (( pfn_SSLv23_client_method=( PFN_SSL_pvoid_void )GetProcAddress( hLibSSL, "SSLv23_client_method" )) == NULL )
+ error = TRUE;
+ if (( pfn_SSL_CTX_new=( PFN_SSL_pvoid_pvoid )GetProcAddress( hLibSSL, "SSL_CTX_new" )) == NULL )
+ error = TRUE;
+ if (( pfn_SSL_CTX_free=( PFN_SSL_void_pvoid )GetProcAddress( hLibSSL, "SSL_CTX_free" )) == NULL )
+ error = TRUE;
+ if (( pfn_SSL_new=( PFN_SSL_pvoid_pvoid )GetProcAddress( hLibSSL, "SSL_new" )) == NULL )
+ error = TRUE;
+ if (( pfn_SSL_free=( PFN_SSL_void_pvoid )GetProcAddress( hLibSSL, "SSL_free" )) == NULL )
+ error = TRUE;
+ if (( pfn_SSL_set_fd=( PFN_SSL_int_pvoid_int )GetProcAddress( hLibSSL, "SSL_set_fd" )) == NULL )
+ error = TRUE;
+ if (( pfn_SSL_connect=( PFN_SSL_int_pvoid )GetProcAddress( hLibSSL, "SSL_connect" )) == NULL )
+ error = TRUE;
+ if (( pfn_SSL_read=( PFN_SSL_int_pvoid_pvoid_int )GetProcAddress( hLibSSL, "SSL_read" )) == NULL )
+ error = TRUE;
+ if (( pfn_SSL_write=( PFN_SSL_int_pvoid_pvoid_int )GetProcAddress( hLibSSL, "SSL_write" )) == NULL )
+ error = TRUE;
+
+ if ( error == TRUE ) {
+ FreeLibrary( hLibSSL );
+ hLibSSL = NULL;
+ }
+ }
+
+
+#ifdef _DEBUG
+ if ( hLibSSL )
+ JabberLog( "SSL library load successful" );
+ else
+ JabberLog( "SSL library cannot load" );
+#endif
+
+ if ( hLibSSL ) {
+ pfn_SSL_library_init();
+ jabberSslCtx = pfn_SSL_CTX_new( pfn_SSLv23_client_method());
+
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+void JabberSslUninit()
+{
+ if ( hLibSSL ) {
+ pfn_SSL_CTX_free( jabberSslCtx );
+
+ JabberLog( "Free SSL library" );
+ FreeLibrary( hLibSSL );
+ hLibSSL = NULL;
+ }
+
+ if ( sslHandleList ) mir_free( sslHandleList );
+ sslHandleCount = 0;
+ DeleteCriticalSection( &sslHandleMutex );
+}
+
+int JabberSslFindHandle( HANDLE hConn )
+{
+ int i;
+
+ EnterCriticalSection( &sslHandleMutex );
+ for ( i=0; i<sslHandleCount; i++ ) {
+ if ( sslHandleList[i].h == hConn ) {
+ LeaveCriticalSection( &sslHandleMutex );
+ return i;
+ }
+ }
+ LeaveCriticalSection( &sslHandleMutex );
+ return -1;
+}
+
+PVOID JabberSslHandleToSsl( HANDLE hConn )
+{
+ int i;
+
+ EnterCriticalSection( &sslHandleMutex );
+ for ( i=0; i<sslHandleCount; i++ ) {
+ if ( sslHandleList[i].h == hConn ) {
+ LeaveCriticalSection( &sslHandleMutex );
+ return sslHandleList[i].ssl;
+ }
+ }
+ LeaveCriticalSection( &sslHandleMutex );
+ return NULL;
+}
+
+void JabberSslAddHandle( HANDLE hConn, PVOID ssl )
+{
+ EnterCriticalSection( &sslHandleMutex );
+ if ( JabberSslFindHandle( hConn ) >= 0 ) {
+ LeaveCriticalSection( &sslHandleMutex );
+ return;
+ }
+
+ sslHandleList = ( JABBER_SSL_MAPPING * ) mir_realloc( sslHandleList, ( sslHandleCount+1 )*sizeof( JABBER_SSL_MAPPING ));
+ sslHandleList[sslHandleCount].h = hConn;
+ sslHandleList[sslHandleCount].ssl = ssl;
+ sslHandleCount++;
+ LeaveCriticalSection( &sslHandleMutex );
+}
+
+void JabberSslRemoveHandle( HANDLE hConn )
+{
+ int i;
+
+ EnterCriticalSection( &sslHandleMutex );
+ if (( i=JabberSslFindHandle( hConn )) < 0 ) {
+ LeaveCriticalSection( &sslHandleMutex );
+ return;
+ }
+
+ sslHandleCount--;
+ memmove( sslHandleList+i, sslHandleList+i+1, ( sslHandleCount-i )*sizeof( JABBER_SSL_MAPPING ));
+ sslHandleList = ( JABBER_SSL_MAPPING * ) mir_realloc( sslHandleList, sslHandleCount*sizeof( JABBER_SSL_MAPPING ));
+ LeaveCriticalSection( &sslHandleMutex );
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_ssl.h b/miranda-wine/protocols/JabberG/jabber_ssl.h new file mode 100644 index 0000000..5832b40 --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_ssl.h @@ -0,0 +1,64 @@ +/*
+
+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_ssl.h,v $
+Revision : $Revision: 2866 $
+Last change on : $Date: 2006-05-16 20:39:40 +0400 (Втр, 16 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#ifndef _JABBER_SSL_H_
+#define _JABBER_SSL_H_
+
+typedef int ( *PFN_SSL_int_void ) ( void );
+typedef PVOID ( *PFN_SSL_pvoid_void ) ( void );
+typedef PVOID ( *PFN_SSL_pvoid_pvoid ) ( PVOID );
+typedef void ( *PFN_SSL_void_pvoid ) ( PVOID );
+typedef int ( *PFN_SSL_int_pvoid_int ) ( PVOID, int );
+typedef int ( *PFN_SSL_int_pvoid ) ( PVOID );
+typedef int ( *PFN_SSL_int_pvoid_pvoid_int ) ( PVOID, PVOID, int );
+
+#ifndef _JABBER_SSL_C_
+extern PFN_SSL_int_void pfn_SSL_library_init; // int SSL_library_init()
+extern PFN_SSL_pvoid_void pfn_SSLv23_client_method; // SSL_METHOD *SSLv23_client_method()
+extern PFN_SSL_pvoid_pvoid pfn_SSL_CTX_new; // SSL_CTX *SSL_CTX_new( SSL_METHOD *method )
+extern PFN_SSL_void_pvoid pfn_SSL_CTX_free; // void SSL_CTX_free( SSL_CTX *ctx );
+extern PFN_SSL_pvoid_pvoid pfn_SSL_new; // SSL *SSL_new( SSL_CTX *ctx )
+extern PFN_SSL_void_pvoid pfn_SSL_free; // void SSL_free( SSL *ssl );
+extern PFN_SSL_int_pvoid_int pfn_SSL_set_fd; // int SSL_set_fd( SSL *ssl, int fd );
+extern PFN_SSL_int_pvoid pfn_SSL_connect; // int SSL_connect( SSL *ssl );
+extern PFN_SSL_int_pvoid_pvoid_int pfn_SSL_read; // int SSL_read( SSL *ssl, void *buffer, int bufsize )
+extern PFN_SSL_int_pvoid_pvoid_int pfn_SSL_write; // int SSL_write( SSL *ssl, void *buffer, int bufsize )
+#endif
+
+typedef struct {
+ HANDLE h;
+ PVOID ssl;
+} JABBER_SSL_MAPPING;
+
+BOOL JabberSslInit();
+void JabberSslUninit();
+int JabberSslFindHandle( HANDLE hConn );
+PVOID JabberSslHandleToSsl( HANDLE hConn );
+void JabberSslAddHandle( HANDLE hConn, PVOID ssl );
+void JabberSslRemoveHandle( HANDLE hConn );
+
+#endif
diff --git a/miranda-wine/protocols/JabberG/jabber_std.cpp b/miranda-wine/protocols/JabberG/jabber_std.cpp new file mode 100644 index 0000000..562beda --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_std.cpp @@ -0,0 +1,171 @@ +/*
+Plugin of Miranda IM for communicating with users of the MSN Messenger protocol.
+Copyright ( c ) 2003-5 George Hazan.
+Copyright ( c ) 2002-3 Richard Hughes ( original version ).
+
+Miranda IM: the mir_free icq client for MS Windows
+Copyright ( C ) 2000-2002 Richard Hughes, Roland Rabien & Tristan Van de Vreede
+
+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_std.cpp,v $
+Revision : $Revision: 2866 $
+Last change on : $Date: 2006-05-16 20:39:40 +0400 (Втр, 16 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+
+HANDLE __stdcall JCreateServiceFunction(
+ const char* szService,
+ MIRANDASERVICE serviceProc )
+{
+ char str[ MAXMODULELABELLENGTH ];
+ strcpy( str, jabberProtoName );
+ strcat( str, szService );
+ return CreateServiceFunction( str, serviceProc );
+}
+
+HANDLE __stdcall JCreateHookableEvent(
+ const char* szService )
+{
+ char str[ MAXMODULELABELLENGTH ];
+ strcpy( str, jabberProtoName );
+ strcat( str, szService );
+ return CreateHookableEvent( str );
+}
+
+#if !defined( _DEBUG )
+int __stdcall JCallService( const char* szSvcName, WPARAM wParam, LPARAM lParam )
+{
+ return CallService( szSvcName, wParam, lParam );
+}
+#endif
+
+void __stdcall JDeleteSetting( HANDLE hContact, const char* valueName )
+{
+ DBDeleteContactSetting( hContact, jabberProtoName, valueName );
+}
+
+DWORD __stdcall JGetByte( const char* valueName, int parDefltValue )
+{
+ return DBGetContactSettingByte( NULL, jabberProtoName, valueName, parDefltValue );
+}
+
+DWORD __stdcall JGetByte( HANDLE hContact, const char* valueName, int parDefltValue )
+{
+ return DBGetContactSettingByte( hContact, jabberProtoName, valueName, parDefltValue );
+}
+
+char* __stdcall JGetContactName( HANDLE hContact )
+{
+ return ( char* )JCallService( MS_CLIST_GETCONTACTDISPLAYNAME, WPARAM( hContact ), 0 );
+}
+
+DWORD __stdcall JGetDword( HANDLE hContact, const char* valueName, DWORD parDefltValue )
+{
+ return DBGetContactSettingDword( hContact, jabberProtoName, valueName, parDefltValue );
+}
+
+int __stdcall JGetStaticString( const char* valueName, HANDLE hContact, char* dest, int dest_len )
+{
+ DBVARIANT dbv;
+ dbv.pszVal = dest;
+ dbv.cchVal = dest_len;
+ dbv.type = DBVT_ASCIIZ;
+
+ DBCONTACTGETSETTING sVal;
+ sVal.pValue = &dbv;
+ sVal.szModule = jabberProtoName;
+ sVal.szSetting = valueName;
+ if ( JCallService( MS_DB_CONTACT_GETSETTINGSTATIC, ( WPARAM )hContact, ( LPARAM )&sVal ) != 0 )
+ return 1;
+
+ return ( dbv.type != DBVT_ASCIIZ );
+}
+
+int __stdcall JGetStringUtf( HANDLE hContact, char* valueName, DBVARIANT* dbv )
+{
+ return DBGetContactSettingStringUtf( hContact, jabberProtoName, valueName, dbv );
+}
+
+int __stdcall JGetStringT( HANDLE hContact, char* valueName, DBVARIANT* dbv )
+{
+ return DBGetContactSettingTString( hContact, jabberProtoName, valueName, dbv );
+}
+
+WORD __stdcall JGetWord( HANDLE hContact, const char* valueName, int parDefltValue )
+{
+ return DBGetContactSettingWord( hContact, jabberProtoName, valueName, parDefltValue );
+}
+
+void __fastcall JFreeVariant( DBVARIANT* dbv )
+{
+ DBFreeVariant( dbv );
+}
+
+int __stdcall JSendBroadcast( HANDLE hContact, int type, int result, HANDLE hProcess, LPARAM lParam )
+{
+ ACKDATA ack = {0};
+ ack.cbSize = sizeof( ACKDATA );
+ ack.szModule = jabberProtoName;
+ ack.hContact = hContact;
+ ack.type = type;
+ ack.result = result;
+ ack.hProcess = hProcess;
+ ack.lParam = lParam;
+ return JCallService( MS_PROTO_BROADCASTACK, 0, ( LPARAM )&ack );
+}
+
+DWORD __stdcall JSetByte( const char* valueName, int parValue )
+{
+ return DBWriteContactSettingByte( NULL, jabberProtoName, valueName, parValue );
+}
+
+DWORD __stdcall JSetByte( HANDLE hContact, const char* valueName, int parValue )
+{
+ return DBWriteContactSettingByte( hContact, jabberProtoName, valueName, parValue );
+}
+
+DWORD __stdcall JSetDword( HANDLE hContact, const char* valueName, DWORD parValue )
+{
+ return DBWriteContactSettingDword( hContact, jabberProtoName, valueName, parValue );
+}
+
+DWORD __stdcall JSetString( HANDLE hContact, const char* valueName, const char* parValue )
+{
+ return DBWriteContactSettingString( hContact, jabberProtoName, valueName, parValue );
+}
+
+DWORD __stdcall JSetStringT( HANDLE hContact, const char* valueName, const TCHAR* parValue )
+{
+ return DBWriteContactSettingTString( hContact, jabberProtoName, valueName, parValue );
+}
+
+DWORD __stdcall JSetStringUtf( HANDLE hContact, const char* valueName, const char* parValue )
+{
+ return DBWriteContactSettingStringUtf( hContact, jabberProtoName, valueName, parValue );
+}
+
+DWORD __stdcall JSetWord( HANDLE hContact, const char* valueName, int parValue )
+{
+ return DBWriteContactSettingWord( hContact, jabberProtoName, valueName, parValue );
+}
+
+char* __stdcall JTranslate( const char* str )
+{
+ return Translate( str );
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_svc.cpp b/miranda-wine/protocols/JabberG/jabber_svc.cpp new file mode 100644 index 0000000..16d25a2 --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_svc.cpp @@ -0,0 +1,1431 @@ +/*
+
+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_svc.cpp,v $
+Revision : $Revision: 3711 $
+Last change on : $Date: 2006-09-06 12:33:14 +0400 (Срд, 06 Сен 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+#include <io.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "resource.h"
+#include "jabber_list.h"
+#include "jabber_iq.h"
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberAddToList - adds a contact to the contact list
+
+static HANDLE AddToListByJID( const TCHAR* newJid, DWORD flags )
+{
+ HANDLE hContact;
+ TCHAR* jid, *nick;
+
+ JabberLog( "AddToListByJID jid = " TCHAR_STR_PARAM, newJid );
+
+ if (( hContact=JabberHContactFromJID( newJid )) == NULL ) {
+ // not already there: add
+ jid = mir_tstrdup( newJid );
+ JabberLog( "Add new jid to contact jid = " TCHAR_STR_PARAM, jid );
+ hContact = ( HANDLE ) JCallService( MS_DB_CONTACT_ADD, 0, 0 );
+ JCallService( MS_PROTO_ADDTOCONTACT, ( WPARAM ) hContact, ( LPARAM )jabberProtoName );
+ JSetStringT( hContact, "jid", jid );
+ if (( nick=JabberNickFromJID( newJid )) == NULL )
+ nick = mir_tstrdup( newJid );
+ JSetStringT( hContact, "Nick", nick );
+ mir_free( nick );
+ mir_free( jid );
+
+ // Note that by removing or disable the "NotOnList" will trigger
+ // the plugin to add a particular contact to the roster list.
+ // See DBSettingChanged hook at the bottom part of this source file.
+ // But the add module will delete "NotOnList". So we will not do it here.
+ // Also because we need "MyHandle" and "Group" info, which are set after
+ // PS_ADDTOLIST is called but before the add dialog issue deletion of
+ // "NotOnList".
+ // If temporary add, "NotOnList" won't be deleted, and that's expected.
+ DBWriteContactSettingByte( hContact, "CList", "NotOnList", 1 );
+ if ( flags & PALF_TEMPORARY )
+ DBWriteContactSettingByte( hContact, "CList", "Hidden", 1 );
+ }
+ else {
+ // already exist
+ // Set up a dummy "NotOnList" when adding permanently only
+ if ( !( flags&PALF_TEMPORARY ))
+ DBWriteContactSettingByte( hContact, "CList", "NotOnList", 1 );
+ }
+
+ return hContact;
+}
+
+int JabberAddToList( WPARAM wParam, LPARAM lParam )
+{
+ JABBER_SEARCH_RESULT* jsr = ( JABBER_SEARCH_RESULT * ) lParam;
+ if ( jsr->hdr.cbSize != sizeof( JABBER_SEARCH_RESULT ))
+ return ( int )NULL;
+
+ return ( int )AddToListByJID( jsr->jid, wParam ); // wParam is flag e.g. PALF_TEMPORARY
+}
+
+int JabberAddToListByEvent( WPARAM wParam, LPARAM lParam )
+{
+ DBEVENTINFO dbei;
+ HANDLE hContact;
+ char* nick, *firstName, *lastName, *jid;
+
+ JabberLog( "AddToListByEvent" );
+ ZeroMemory( &dbei, sizeof( dbei ));
+ dbei.cbSize = sizeof( dbei );
+ if (( dbei.cbBlob=JCallService( MS_DB_EVENT_GETBLOBSIZE, lParam, 0 )) == ( DWORD )( -1 ))
+ return ( int )( HANDLE ) NULL;
+ if (( dbei.pBlob=( PBYTE ) alloca( dbei.cbBlob )) == NULL )
+ return ( int )( HANDLE ) NULL;
+ if ( JCallService( MS_DB_EVENT_GET, lParam, ( LPARAM )&dbei ))
+ return ( int )( HANDLE ) NULL;
+ if ( strcmp( dbei.szModule, jabberProtoName ))
+ return ( int )( HANDLE ) NULL;
+
+/*
+ // EVENTTYPE_CONTACTS is when adding from when we receive contact list ( not used in Jabber )
+ // EVENTTYPE_ADDED is when adding from when we receive "You are added" ( also not used in Jabber )
+ // Jabber will only handle the case of EVENTTYPE_AUTHREQUEST
+ // EVENTTYPE_AUTHREQUEST is when adding from the authorization request dialog
+*/
+
+ if ( dbei.eventType != EVENTTYPE_AUTHREQUEST )
+ return ( int )( HANDLE ) NULL;
+
+ nick = ( char* )( dbei.pBlob + sizeof( DWORD )+ sizeof( HANDLE ));
+ firstName = nick + strlen( nick ) + 1;
+ lastName = firstName + strlen( firstName ) + 1;
+ jid = lastName + strlen( lastName ) + 1;
+
+ #if defined( _UNICODE )
+ TCHAR* newJid = a2u( jid );
+ #else
+ TCHAR* newJid = mir_strdup( jid );
+ #endif
+ hContact = ( HANDLE ) AddToListByJID( newJid, wParam );
+ mir_free( newJid );
+ return ( int ) hContact;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberAuthAllow - processes the successful authorization
+
+int JabberAuthAllow( WPARAM wParam, LPARAM lParam )
+{
+ DBEVENTINFO dbei;
+ char* nick, *firstName, *lastName, *jid;
+
+ if ( !jabberOnline )
+ return 1;
+
+ memset( &dbei, sizeof( dbei ), 0 );
+ dbei.cbSize = sizeof( dbei );
+ if (( dbei.cbBlob=JCallService( MS_DB_EVENT_GETBLOBSIZE, wParam, 0 )) == ( DWORD )( -1 ))
+ return 1;
+ if (( dbei.pBlob=( PBYTE )alloca( dbei.cbBlob )) == NULL )
+ return 1;
+ if ( JCallService( MS_DB_EVENT_GET, wParam, ( LPARAM )&dbei ))
+ return 1;
+ if ( dbei.eventType != EVENTTYPE_AUTHREQUEST )
+ return 1;
+ if ( strcmp( dbei.szModule, jabberProtoName ))
+ return 1;
+
+ nick = ( char* )( dbei.pBlob + sizeof( DWORD )+ sizeof( HANDLE ));
+ firstName = nick + strlen( nick ) + 1;
+ lastName = firstName + strlen( firstName ) + 1;
+ jid = lastName + strlen( lastName ) + 1;
+
+ JabberLog( "Send 'authorization allowed' to " TCHAR_STR_PARAM, jid );
+
+ XmlNode presence( "presence" ); presence.addAttr( "to", jid ); presence.addAttr( "type", "subscribed" );
+ JabberSend( jabberThreadInfo->s, presence );
+
+ #if defined( _UNICODE )
+ TCHAR* newJid = a2u( jid );
+ #else
+ TCHAR* newJid = mir_strdup( jid );
+ #endif
+
+ // Automatically add this user to my roster if option is enabled
+ if ( JGetByte( "AutoAdd", TRUE ) == TRUE ) {
+ HANDLE hContact;
+ JABBER_LIST_ITEM *item;
+
+ if (( item = JabberListGetItemPtr( LIST_ROSTER, newJid )) == NULL || ( item->subscription != SUB_BOTH && item->subscription != SUB_TO )) {
+ JabberLog( "Try adding contact automatically jid = " TCHAR_STR_PARAM, jid );
+ if (( hContact=AddToListByJID( newJid, 0 )) != NULL ) {
+ // Trigger actual add by removing the "NotOnList" added by AddToListByJID()
+ // See AddToListByJID() and JabberDbSettingChanged().
+ DBDeleteContactSetting( hContact, "CList", "NotOnList" );
+ } } }
+
+ mir_free( newJid );
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberAuthDeny - handles the unsuccessful authorization
+
+int JabberAuthDeny( WPARAM wParam, LPARAM lParam )
+{
+ DBEVENTINFO dbei;
+ char* nick, *firstName, *lastName, *jid;
+
+ if ( !jabberOnline )
+ return 1;
+
+ JabberLog( "Entering AuthDeny" );
+ memset( &dbei, sizeof( dbei ), 0 );
+ dbei.cbSize = sizeof( dbei );
+ if (( dbei.cbBlob=JCallService( MS_DB_EVENT_GETBLOBSIZE, wParam, 0 )) == ( DWORD )( -1 ))
+ return 1;
+ if (( dbei.pBlob=( PBYTE ) mir_alloc( dbei.cbBlob )) == NULL )
+ return 1;
+ if ( JCallService( MS_DB_EVENT_GET, wParam, ( LPARAM )&dbei )) {
+ mir_free( dbei.pBlob );
+ return 1;
+ }
+ if ( dbei.eventType != EVENTTYPE_AUTHREQUEST ) {
+ mir_free( dbei.pBlob );
+ return 1;
+ }
+ if ( strcmp( dbei.szModule, jabberProtoName )) {
+ mir_free( dbei.pBlob );
+ return 1;
+ }
+
+ nick = ( char* )( dbei.pBlob + sizeof( DWORD )+ sizeof( HANDLE ));
+ firstName = nick + strlen( nick ) + 1;
+ lastName = firstName + strlen( firstName ) + 1;
+ jid = lastName + strlen( lastName ) + 1;
+
+ JabberLog( "Send 'authorization denied' to " TCHAR_STR_PARAM, jid );
+
+ XmlNode presence( "presence" ); presence.addAttr( "to", jid ); presence.addAttr( "type", "unsubscribed" );
+ JabberSend( jabberThreadInfo->s, presence );
+
+ mir_free( dbei.pBlob );
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberBasicSearch - searches the contact by JID
+
+struct JABBER_SEARCH_BASIC
+{ int hSearch;
+ char jid[128];
+};
+
+static void __cdecl JabberBasicSearchThread( JABBER_SEARCH_BASIC *jsb )
+{
+ SleepEx( 100, TRUE );
+
+ JABBER_SEARCH_RESULT jsr = { 0 };
+ jsr.hdr.cbSize = sizeof( JABBER_SEARCH_RESULT );
+ jsr.hdr.nick = "";
+ jsr.hdr.firstName = "";
+ jsr.hdr.lastName = "";
+ jsr.hdr.email = jsb->jid;
+ #if defined( _UNICODE )
+ TCHAR* jid = a2u(jsb->jid);
+ _tcsncpy( jsr.jid, jid, SIZEOF( jsr.jid ));
+ mir_free( jid );
+ #else
+ strncpy( jsr.jid, jsb->jid, SIZEOF( jsr.jid ));
+ #endif
+ jsr.jid[SIZEOF( jsr.jid )-1] = '\0';
+ JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_DATA, ( HANDLE ) jsb->hSearch, ( LPARAM )&jsr );
+ JSendBroadcast( NULL, ACKTYPE_SEARCH, ACKRESULT_SUCCESS, ( HANDLE ) jsb->hSearch, 0 );
+ mir_free( jsb );
+}
+
+int JabberBasicSearch( WPARAM wParam, LPARAM lParam )
+{
+ char* szJid = ( char* )lParam;
+ JabberLog( "JabberBasicSearch called with lParam = " TCHAR_STR_PARAM, szJid );
+
+ JABBER_SEARCH_BASIC *jsb;
+ if ( !jabberOnline || ( jsb=( JABBER_SEARCH_BASIC * ) mir_alloc( sizeof( JABBER_SEARCH_BASIC )) )==NULL )
+ return 0;
+
+ jsb->hSearch = JabberSerialNext();
+ if ( strchr( szJid, '@' ) == NULL ) {
+ char szServer[ 100 ];
+ if ( JGetStaticString( "LoginServer", NULL, szServer, sizeof szServer ))
+ strcpy( szServer, "jabber.org" );
+
+ mir_snprintf( jsb->jid, SIZEOF(jsb->jid), "%s@%s", szJid, szServer );
+ }
+ else strncpy( jsb->jid, szJid, SIZEOF(jsb->jid));
+
+ JabberForkThread(( JABBER_THREAD_FUNC )JabberBasicSearchThread, 0, jsb );
+ return jsb->hSearch;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberContactDeleted - processes a contact deletion
+
+int JabberContactDeleted( WPARAM wParam, LPARAM lParam )
+{
+ if( !jabberOnline ) // should never happen
+ return 0;
+
+ char* szProto = ( char* )JCallService( MS_PROTO_GETCONTACTBASEPROTO, wParam, 0 );
+ if ( szProto==NULL || strcmp( szProto, jabberProtoName ))
+ return 0;
+
+ DBVARIANT dbv;
+ if ( !JGetStringT(( HANDLE ) wParam, JGetByte( (HANDLE ) wParam, "ChatRoom", 0 )?"ChatRoomID":"jid", &dbv )) {
+ TCHAR* jid, *p, *q = NULL;
+
+ jid = dbv.ptszVal;
+ if (( p = _tcschr( jid, '@' )) != NULL )
+ if (( q = _tcschr( p, '/' )) != NULL )
+ *q = '\0';
+
+ if ( !JabberListExist( LIST_CHATROOM, jid ) || q == NULL )
+ if ( JabberListExist( LIST_ROSTER, jid )) {
+ // Remove from roster, server also handles the presence unsubscription process.
+ XmlNodeIq iq( "set" );
+ XmlNode* query = iq.addQuery( "jabber:iq:roster" );
+ XmlNode* item = query->addChild( "item" ); item->addAttr( "jid", jid ); item->addAttr( "subscription", "remove" );
+ JabberSend( jabberThreadInfo->s, iq );
+ }
+
+ JFreeVariant( &dbv );
+ }
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberDbSettingChanged - process database changes
+
+static TCHAR* sttSettingToTchar( DBCONTACTWRITESETTING* cws )
+{
+ switch( cws->value.type ) {
+ case DBVT_ASCIIZ:
+ #if defined( _UNICODE )
+ return a2u( cws->value.pszVal );
+ #else
+ return mir_strdup( cws->value.pszVal );
+ #endif
+
+ case DBVT_UTF8:
+ #if defined( _UNICODE )
+ { TCHAR* result;
+ JabberUtf8Decode( NEWSTR_ALLOCA(cws->value.pszVal), &result );
+ return result;
+ }
+ #else
+ return mir_strdup( JabberUtf8Decode( NEWSTR_ALLOCA(cws->value.pszVal), NULL ));
+ #endif
+ }
+ return NULL;
+}
+
+static void sttRenameGroup( DBCONTACTWRITESETTING* cws, HANDLE hContact )
+{
+ DBVARIANT jid, dbv;
+ if ( JGetStringT( hContact, "jid", &jid ))
+ return;
+
+ JABBER_LIST_ITEM* item = JabberListGetItemPtr( LIST_ROSTER, jid.ptszVal );
+ JFreeVariant( &jid );
+ if ( item == NULL )
+ return;
+
+ TCHAR* nick;
+ if ( !DBGetContactSettingTString( hContact, "CList", "MyHandle", &dbv )) {
+ nick = mir_tstrdup( dbv.ptszVal );
+ JFreeVariant( &dbv );
+ }
+ else if ( !JGetStringT( hContact, "Nick", &dbv )) {
+ nick = mir_tstrdup( dbv.ptszVal );
+ JFreeVariant( &dbv );
+ }
+ else nick = JabberNickFromJID( item->jid );
+ if ( nick == NULL )
+ return;
+
+ if ( cws->value.type == DBVT_DELETED ) {
+ if ( item->group != NULL ) {
+ JabberLog( "Group set to nothing" );
+ JabberAddContactToRoster( item->jid, nick, NULL, item->subscription );
+ }
+ }
+ else {
+ TCHAR* p = sttSettingToTchar( cws );
+ if ( cws->value.pszVal != NULL && lstrcmp( p, item->group )) {
+ JabberLog( "Group set to " TCHAR_STR_PARAM, p );
+ if ( p )
+ JabberAddContactToRoster( item->jid, nick, p, item->subscription );
+ }
+ mir_free( p );
+ }
+ mir_free( nick );
+}
+
+static void sttRenameContact( DBCONTACTWRITESETTING* cws, HANDLE hContact )
+{
+ DBVARIANT jid;
+ if ( JGetStringT( hContact, "jid", &jid ))
+ return;
+
+ JABBER_LIST_ITEM* item = JabberListGetItemPtr( LIST_ROSTER, jid.ptszVal );
+ JFreeVariant( &jid );
+ if ( item == NULL )
+ return;
+
+ if ( cws->value.type == DBVT_DELETED ) {
+ TCHAR* nick = ( TCHAR* )JCallService( MS_CLIST_GETCONTACTDISPLAYNAME, ( WPARAM )hContact, GCDNF_NOMYHANDLE | GCDNF_TCHAR );
+ JabberAddContactToRoster( item->jid, nick, item->group, item->subscription );
+ mir_free(nick);
+ return;
+ }
+
+ TCHAR* newNick = sttSettingToTchar( cws );
+ if ( newNick ) {
+ if ( lstrcmp( item->nick, newNick )) {
+ JabberLog( "Renaming contact " TCHAR_STR_PARAM ": " TCHAR_STR_PARAM " -> " TCHAR_STR_PARAM, item->jid, item->nick, newNick );
+ JabberAddContactToRoster( item->jid, newNick, item->group, item->subscription );
+ }
+ mir_free( newNick );
+} }
+
+void sttAddContactForever( DBCONTACTWRITESETTING* cws, HANDLE hContact )
+{
+ if ( cws->value.type != DBVT_DELETED && !( cws->value.type==DBVT_BYTE && cws->value.bVal==0 ))
+ return;
+
+ DBVARIANT jid, dbv;
+ if ( JGetStringT( hContact, "jid", &jid ))
+ return;
+
+ TCHAR *nick;
+ JabberLog( "Add " TCHAR_STR_PARAM " permanently to list", jid.pszVal );
+ if ( !DBGetContactSettingTString( hContact, "CList", "MyHandle", &dbv )) {
+ nick = mir_tstrdup( dbv.ptszVal );
+ JFreeVariant( &dbv );
+ }
+ else if ( !JGetStringT( hContact, "Nick", &dbv )) {
+ nick = mir_tstrdup( dbv.ptszVal );
+ JFreeVariant( &dbv );
+ }
+ else nick = JabberNickFromJID( jid.ptszVal );
+ if ( nick == NULL ) {
+ JFreeVariant( &jid );
+ return;
+ }
+
+ JABBER_LIST_ITEM* item = JabberListGetItemPtr( LIST_ROSTER, jid.ptszVal );
+ JABBER_SUBSCRIPTION subscription = ( item == NULL ) ? SUB_NONE : item->subscription;
+
+ if ( !DBGetContactSettingTString( hContact, "CList", "Group", &dbv )) {
+ JabberAddContactToRoster( jid.ptszVal, nick, dbv.ptszVal, subscription );
+ JFreeVariant( &dbv );
+ }
+ else JabberAddContactToRoster( jid.ptszVal, nick, NULL, subscription );
+
+ XmlNode presence( "presence" ); presence.addAttr( "to", jid.ptszVal ); presence.addAttr( "type", "subscribe" );
+ JabberSend( jabberThreadInfo->s, presence );
+
+ mir_free( nick );
+ DBDeleteContactSetting( hContact, "CList", "Hidden" );
+ JFreeVariant( &jid );
+}
+
+int JabberDbSettingChanged( WPARAM wParam, LPARAM lParam )
+{
+ HANDLE hContact = ( HANDLE ) wParam;
+ if ( hContact == NULL || !jabberConnected )
+ return 0;
+
+ DBCONTACTWRITESETTING* cws = ( DBCONTACTWRITESETTING* )lParam;
+ if ( strcmp( cws->szModule, "CList" ))
+ return 0;
+
+ char* szProto = ( char* )JCallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 );
+ if ( szProto == NULL || strcmp( szProto, jabberProtoName ))
+ return 0;
+
+ if ( !strcmp( cws->szSetting, "Group" ))
+ sttRenameGroup( cws, hContact );
+ else if ( !strcmp( cws->szSetting, "MyHandle" ))
+ sttRenameContact( cws, hContact );
+ else if ( !strcmp( cws->szSetting, "NotOnList" ))
+ sttAddContactForever( cws, hContact );
+
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberFileAllow - starts a file transfer
+
+int JabberFileAllow( WPARAM wParam, LPARAM lParam )
+{
+ if ( !jabberOnline ) return 0;
+
+ CCSDATA *ccs = ( CCSDATA * ) lParam;
+ filetransfer* ft = ( filetransfer* ) ccs->wParam;
+ ft->std.workingDir = mir_strdup(( char* )ccs->lParam );
+ int len = strlen( ft->std.workingDir )-1;
+ if ( ft->std.workingDir[len] == '//' || ft->std.workingDir[len] == '\\' )
+ ft->std.workingDir[len] = 0;
+
+ switch ( ft->type ) {
+ case FT_OOB:
+ JabberForkThread(( JABBER_THREAD_FUNC )JabberFileReceiveThread, 0, ft );
+ break;
+ case FT_BYTESTREAM:
+ JabberFtAcceptSiRequest( ft );
+ break;
+ }
+ return ccs->wParam;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberFileCancel - cancels a file transfer
+
+int JabberFileCancel( WPARAM wParam, LPARAM lParam )
+{
+ CCSDATA *ccs = ( CCSDATA * ) lParam;
+ filetransfer* ft = ( filetransfer* ) ccs->wParam;
+ HANDLE hEvent;
+
+ JabberLog( "Invoking FileCancel()" );
+ if ( ft->type == FT_OOB ) {
+ if ( ft->s ) {
+ JabberLog( "FT canceled" );
+ JabberLog( "Closing ft->s = %d", ft->s );
+ ft->state = FT_ERROR;
+ Netlib_CloseHandle( ft->s );
+ ft->s = NULL;
+ if ( ft->hFileEvent != NULL ) {
+ hEvent = ft->hFileEvent;
+ ft->hFileEvent = NULL;
+ SetEvent( hEvent );
+ }
+ JabberLog( "ft->s is now NULL, ft->state is now FT_ERROR" );
+ }
+ }
+ else JabberFtCancel( ft );
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberFileDeny - denies a file transfer
+
+int JabberFileDeny( WPARAM wParam, LPARAM lParam )
+{
+ if ( !jabberOnline ) return 1;
+
+ CCSDATA *ccs = ( CCSDATA * ) lParam;
+ filetransfer* ft = ( filetransfer* )ccs->wParam;
+
+ XmlNodeIq iq( "error", ft->iqId, ft->jid );
+
+ switch ( ft->type ) {
+ case FT_OOB:
+ { XmlNode* e = iq.addChild( "error", _T("File transfer refused"));
+ e->addAttr( "code", 406 );
+ JabberSend( jabberThreadInfo->s, iq );
+ }
+ break;
+ case FT_BYTESTREAM:
+ { XmlNode* e = iq.addChild( "error", _T("File transfer refused"));
+ e->addAttr( "code", 403 ); e->addAttr( "type", "cancel" );
+ XmlNode* f = e->addChild( "forbidden" ); f->addAttr( "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas" );
+ XmlNode* t = f->addChild( "text", "File transfer refused" ); t->addAttr( "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas" );
+ JabberSend( jabberThreadInfo->s, iq );
+ }
+ break;
+ }
+ delete ft;
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberFileResume - processes file renaming etc
+
+int JabberFileResume( WPARAM wParam, LPARAM lParam )
+{
+ filetransfer* ft = ( filetransfer* )wParam;
+ if ( !jabberConnected || ft == NULL )
+ return 1;
+
+ PROTOFILERESUME *pfr = (PROTOFILERESUME*)lParam;
+ if ( pfr->action == FILERESUME_RENAME ) {
+ if ( ft->wszFileName != NULL ) {
+ mir_free( ft->wszFileName );
+ ft->wszFileName = NULL;
+ }
+
+ replaceStr( ft->std.currentFile, pfr->szFilename );
+ }
+
+ SetEvent( ft->hWaitEvent );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberGetAvatarInfo - retrieves the avatar info
+
+static int JabberGetAvatarInfo(WPARAM wParam,LPARAM lParam)
+{
+ if ( !JGetByte( "EnableAvatars", TRUE ))
+ return GAIR_NOAVATAR;
+
+ PROTO_AVATAR_INFORMATION* AI = ( PROTO_AVATAR_INFORMATION* )lParam;
+
+ char szHashValue[ MAX_PATH ];
+ if ( JGetStaticString( "AvatarHash", AI->hContact, szHashValue, sizeof szHashValue )) {
+ JabberLog( "No avatar" );
+ return GAIR_NOAVATAR;
+ }
+
+ JabberGetAvatarFileName( AI->hContact, AI->filename, sizeof AI->filename );
+ AI->format = ( AI->hContact == NULL ) ? PA_FORMAT_PNG : JGetByte( AI->hContact, "AvatarType", 0 );
+
+ if ( ::access( AI->filename, 0 ) == 0 ) {
+ char szSavedHash[ 256 ];
+ if ( !JGetStaticString( "AvatarSaved", AI->hContact, szSavedHash, sizeof szSavedHash )) {
+ if ( !strcmp( szSavedHash, szHashValue )) {
+ JabberLog( "Avatar is Ok: %s == %s", szSavedHash, szHashValue );
+ return GAIR_SUCCESS;
+ } } }
+
+ if (( wParam & GAIF_FORCE ) != 0 && AI->hContact != NULL && jabberOnline ) {
+ DBVARIANT dbv;
+ if ( !JGetStringT( AI->hContact, "jid", &dbv )) {
+ JABBER_LIST_ITEM* item = JabberListGetItemPtr( LIST_ROSTER, dbv.ptszVal );
+ if ( item != NULL ) {
+ TCHAR szJid[ 512 ];
+ BOOL isXVcard = JGetByte(AI->hContact,"AvatarXVcard",0);
+ if ( (item->resourceCount != NULL) & (!isXVcard)){
+ TCHAR *bestResName = JabberListGetBestClientResourceNamePtr(dbv.ptszVal);
+ mir_sntprintf( szJid, SIZEOF( szJid ), bestResName?_T("%s/%s"):_T("%s"), dbv.ptszVal, bestResName );
+ }else
+ lstrcpyn( szJid, dbv.ptszVal, SIZEOF( szJid ));
+
+ JabberLog( "Rereading %s for " TCHAR_STR_PARAM, isXVcard?"vcard-temp":"jabber:iq:avatar", szJid );
+
+ int iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_NONE, JabberIqResultGetAvatar );
+
+ XmlNodeIq iq( "get", iqId, szJid );
+ if (isXVcard) {
+ XmlNode* vs = iq.addChild( "vCard" ); vs->addAttr( "xmlns", "vcard-temp" );
+ } else XmlNode* query = iq.addQuery( isXVcard?"":"jabber:iq:avatar" );
+ JabberSend( jabberThreadInfo->s, iq );
+
+ JFreeVariant( &dbv );
+ return GAIR_WAITFOR;
+ } } }
+
+ JabberLog( "No avatar" );
+ return GAIR_NOAVATAR;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberGetAwayMsg - returns a contact's away message
+
+static void __cdecl JabberGetAwayMsgThread( HANDLE hContact )
+{
+ DBVARIANT dbv;
+ JABBER_LIST_ITEM *item;
+ JABBER_RESOURCE_STATUS *r;
+ int i, len, msgCount;
+
+ if ( !JGetStringT( hContact, "jid", &dbv )) {
+ if (( item=JabberListGetItemPtr( LIST_ROSTER, dbv.ptszVal )) != NULL ) {
+ JFreeVariant( &dbv );
+ if ( item->resourceCount > 0 ) {
+ JabberLog( "resourceCount > 0" );
+ r = item->resource;
+ len = msgCount = 0;
+ for ( i=0; i<item->resourceCount; i++ ) {
+ if ( r[i].statusMessage ) {
+ msgCount++;
+ len += ( _tcslen( r[i].resourceName ) + _tcslen( r[i].statusMessage ) + 8 );
+ } }
+
+ TCHAR* str = ( TCHAR* )alloca( sizeof( TCHAR )*( len+1 ));
+ str[0] = str[len] = '\0';
+ for ( i=0; i < item->resourceCount; i++ ) {
+ if ( r[i].statusMessage ) {
+ if ( str[0] != '\0' ) _tcscat( str, _T("\r\n" ));
+ if ( msgCount > 1 ) {
+ _tcscat( str, _T("( "));
+ _tcscat( str, r[i].resourceName );
+ _tcscat( str, _T(" ): "));
+ }
+ _tcscat( str, r[i].statusMessage );
+ } }
+
+ #if defined( _UNICODE )
+ char* msg = u2a(str);
+ #else
+ char* msg = str;
+ #endif
+ JSendBroadcast( hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, ( HANDLE ) 1, ( LPARAM )msg );
+ #if defined( _UNICODE )
+ mir_free(msg);
+ #endif
+ return;
+ }
+
+ if ( item->statusMessage != NULL ) {
+ #if defined( _UNICODE )
+ char* msg = u2a(item->statusMessage);
+ #else
+ char* msg = item->statusMessage;
+ #endif
+ JSendBroadcast( hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, ( HANDLE ) 1, ( LPARAM )msg );
+ #if defined( _UNICODE )
+ mir_free(msg);
+ #endif
+ return;
+ }
+ }
+ else JFreeVariant( &dbv );
+ }
+
+ JSendBroadcast( hContact, ACKTYPE_AWAYMSG, ACKRESULT_SUCCESS, ( HANDLE ) 1, ( LPARAM )"" );
+}
+
+int JabberGetAwayMsg( WPARAM wParam, LPARAM lParam )
+{
+ CCSDATA *ccs = ( CCSDATA * ) lParam;
+
+ JabberLog( "GetAwayMsg called, wParam=%d lParam=%d", wParam, lParam );
+ JabberForkThread( JabberGetAwayMsgThread, 0, ( void * ) ccs->hContact );
+ return 1;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberGetCaps - return protocol capabilities bits
+
+int JabberGetCaps( WPARAM wParam, LPARAM lParam )
+{
+ switch( wParam ) {
+ case PFLAGNUM_1:
+ return PF1_IM|PF1_AUTHREQ|PF1_SERVERCLIST|PF1_MODEMSG|PF1_BASICSEARCH|PF1_SEARCHBYEMAIL|PF1_SEARCHBYNAME|PF1_FILE|PF1_VISLIST|PF1_INVISLIST;
+ case PFLAGNUM_2:
+ return PF2_ONLINE | PF2_INVISIBLE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_HEAVYDND | PF2_FREECHAT;
+ case PFLAGNUM_3:
+ return PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_HEAVYDND | PF2_FREECHAT;
+ case PFLAGNUM_4:
+ return PF4_FORCEAUTH | PF4_NOCUSTOMAUTH | PF4_SUPPORTTYPING | PF4_AVATARS;
+ case PFLAG_UNIQUEIDTEXT:
+ return ( int ) JTranslate( "JID" );
+ case PFLAG_UNIQUEIDSETTING:
+ return ( int ) "jid";
+ }
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberGetInfo - retrieves a contact info
+
+int JabberGetInfo( WPARAM wParam, LPARAM lParam )
+{
+ if ( !jabberOnline )
+ return 1;
+
+ CCSDATA *ccs = ( CCSDATA * ) lParam;
+ int result = 1;
+ DBVARIANT dbv;
+ if ( !JGetStringT( ccs->hContact, "jid", &dbv )) {
+ result = JabberSendGetVcard( dbv.ptszVal );
+ JFreeVariant( &dbv );
+ }
+
+ return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberGetName - returns the protocol name
+
+int JabberGetName( WPARAM wParam, LPARAM lParam )
+{
+ lstrcpynA(( char* )lParam, jabberModuleName, wParam );
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberGetStatus - returns the protocol status
+
+int JabberGetStatus( WPARAM wParam, LPARAM lParam )
+{
+ return jabberStatus;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberLoadIcon - loads an icon for the contact list
+
+int JabberLoadIcon( WPARAM wParam, LPARAM lParam )
+{
+ if (( wParam&0xffff ) == PLI_PROTOCOL )
+ return ( int ) LoadImage( hInst, MAKEINTRESOURCE( IDI_JABBER ), IMAGE_ICON, GetSystemMetrics( wParam&PLIF_SMALL?SM_CXSMICON:SM_CXICON ), GetSystemMetrics( wParam&PLIF_SMALL?SM_CYSMICON:SM_CYICON ), 0 );
+ else
+ return ( int ) ( HICON ) NULL;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberRecvFile - receives a file
+
+int JabberRecvFile( WPARAM wParam, LPARAM lParam )
+{
+ CCSDATA *ccs = ( CCSDATA * ) lParam;
+ PROTORECVEVENT *pre = ( PROTORECVEVENT * ) ccs->lParam;
+ char* szFile = pre->szMessage + sizeof( DWORD );
+ char* szDesc = szFile + strlen( szFile ) + 1;
+ JabberLog( "Description = %s", szDesc );
+
+ DBDeleteContactSetting( ccs->hContact, "CList", "Hidden" );
+
+ DBEVENTINFO dbei = { 0 };
+ dbei.cbSize = sizeof( dbei );
+ dbei.szModule = jabberProtoName;
+ dbei.timestamp = pre->timestamp;
+ dbei.flags = pre->flags & ( PREF_CREATEREAD ? DBEF_READ : 0 );
+ dbei.eventType = EVENTTYPE_FILE;
+ dbei.cbBlob = sizeof( DWORD )+ strlen( szFile ) + strlen( szDesc ) + 2;
+ dbei.pBlob = ( PBYTE ) pre->szMessage;
+ JCallService( MS_DB_EVENT_ADD, ( WPARAM ) ccs->hContact, ( LPARAM )&dbei );
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberRecvMessage - receives a message
+
+int JabberRecvMessage( WPARAM wParam, LPARAM lParam )
+{
+ CCSDATA *ccs = ( CCSDATA* )lParam;
+ PROTORECVEVENT *pre = ( PROTORECVEVENT* )ccs->lParam;
+
+ DBEVENTINFO dbei = { 0 };
+ dbei.cbSize = sizeof( dbei );
+ dbei.szModule = jabberProtoName;
+ dbei.timestamp = pre->timestamp;
+ dbei.flags = pre->flags&PREF_CREATEREAD?DBEF_READ:0;
+ dbei.eventType = EVENTTYPE_MESSAGE;
+ dbei.cbBlob = strlen( pre->szMessage ) + 1;
+ if ( pre->flags & PREF_UNICODE )
+ dbei.cbBlob *= ( sizeof( wchar_t )+1 );
+
+ dbei.pBlob = ( PBYTE ) pre->szMessage;
+ JCallService( MS_DB_EVENT_ADD, ( WPARAM ) ccs->hContact, ( LPARAM )&dbei );
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberSearchByEmail - searches the contact by its e-mail
+
+int JabberSearchByEmail( WPARAM wParam, LPARAM lParam )
+{
+ if ( !jabberOnline ) return 0;
+ if (( char* )lParam == NULL ) return 0;
+
+ char szServerName[100];
+ if ( JGetStaticString( "Jud", NULL, szServerName, sizeof szServerName ))
+ strcpy( szServerName, "users.jabber.org" );
+
+ int iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_GETSEARCH, JabberIqResultSetSearch );
+
+ XmlNodeIq iq( "set", iqId, szServerName );
+ XmlNode* query = iq.addQuery( "jabber:iq:search" );
+ query->addChild( "email", ( char* )lParam );
+ JabberSend( jabberThreadInfo->s, iq );
+ return iqId;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberSearchByName - searches the contact by its first or last name, or by a nickname
+
+int JabberSearchByName( WPARAM wParam, LPARAM lParam )
+{
+ if ( !jabberOnline ) return 0;
+
+ PROTOSEARCHBYNAME *psbn = ( PROTOSEARCHBYNAME * ) lParam;
+ BOOL bIsExtFormat = JGetByte( "ExtendedSearch", TRUE );
+
+ char szServerName[100];
+ if ( JGetStaticString( "Jud", NULL, szServerName, sizeof szServerName ))
+ strcpy( szServerName, "users.jabber.org" );
+
+ int iqId = JabberSerialNext();
+ XmlNodeIq iq( "set", iqId, szServerName );
+ XmlNode* query = iq.addChild( "query" ), *field, *x;
+ query->addAttr( "xmlns", "jabber:iq:search" );
+
+ if ( bIsExtFormat ) {
+ JabberIqAdd( iqId, IQ_PROC_GETSEARCH, JabberIqResultExtSearch );
+
+ iq.addAttr( "xml:lang", "en" );
+ x = query->addChild( "x" ); x->addAttr( "xmlns", "jabber:x:data" ); x->addAttr( "type", "submit" );
+ }
+ else JabberIqAdd( iqId, IQ_PROC_GETSEARCH, JabberIqResultSetSearch );
+
+ if ( psbn->pszNick[0] != '\0' ) {
+ if ( bIsExtFormat ) {
+ field = x->addChild( "field" ); field->addAttr( "var", "user" );
+ field->addChild( "value", psbn->pszNick );
+ }
+ else query->addChild( "nick", psbn->pszNick );
+ }
+
+ if ( psbn->pszFirstName[0] != '\0' ) {
+ if ( bIsExtFormat ) {
+ field = x->addChild( "field" ); field->addAttr( "var", "fn" );
+ field->addChild( "value", psbn->pszFirstName );
+ }
+ else query->addChild( "first", psbn->pszFirstName );
+ }
+
+ if ( psbn->pszLastName[0] != '\0' ) {
+ if ( bIsExtFormat ) {
+ field = x->addChild( "field" ); field->addAttr( "var", "given" );
+ field->addChild( "value", psbn->pszLastName );
+ }
+ else query->addChild( "last", psbn->pszLastName );
+ }
+
+ JabberSend( jabberThreadInfo->s, iq );
+ return iqId;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberSendFile - sends a file
+
+int JabberSendFile( WPARAM wParam, LPARAM lParam )
+{
+ if ( !jabberOnline ) return 0;
+
+ CCSDATA *ccs = ( CCSDATA * ) lParam;
+ if ( JGetWord( ccs->hContact, "Status", ID_STATUS_OFFLINE ) == ID_STATUS_OFFLINE )
+ return 0;
+
+ DBVARIANT dbv;
+ if ( JGetStringT( ccs->hContact, "jid", &dbv ))
+ return 0;
+
+ char* *files = ( char* * ) ccs->lParam;
+ int i, j;
+ struct _stat statbuf;
+ JABBER_LIST_ITEM* item = JabberListGetItemPtr( LIST_ROSTER, dbv.ptszVal );
+ if ( item == NULL )
+ return 0;
+
+ // Check if another file transfer session request is pending ( waiting for disco result )
+ if ( item->ft != NULL ) return 0;
+
+ filetransfer* ft = new filetransfer;
+ ft->std.hContact = ccs->hContact;
+ while( files[ ft->std.totalFiles ] != NULL )
+ ft->std.totalFiles++;
+
+ ft->std.files = ( char** ) mir_alloc( sizeof( char* )* ft->std.totalFiles );
+ ft->fileSize = ( long* ) mir_alloc( sizeof( long ) * ft->std.totalFiles );
+ for( i=j=0; i < ft->std.totalFiles; i++ ) {
+ if ( _stat( files[i], &statbuf ))
+ JabberLog( "'%s' is an invalid filename", files[i] );
+ else {
+ ft->std.files[j] = mir_strdup( files[i] );
+ ft->fileSize[j] = statbuf.st_size;
+ j++;
+ ft->std.totalBytes += statbuf.st_size;
+ } }
+
+ ft->std.currentFile = mir_strdup( files[0] );
+ ft->szDescription = mir_strdup(( char* )ccs->wParam );
+ ft->jid = mir_tstrdup( dbv.ptszVal );
+ JFreeVariant( &dbv );
+
+ if (( item->cap & CLIENT_CAP_READY ) == 0 ) {
+ int iqId;
+ TCHAR* rs;
+
+ // Probe client capability
+ if (( rs=JabberListGetBestClientResourceNamePtr( item->jid )) != NULL ) {
+ item->ft = ft;
+ iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_NONE, JabberIqResultDiscoClientInfo );
+
+ TCHAR jid[ 200 ];
+ mir_sntprintf( jid, SIZEOF(jid), _T("%s/%s"), item->jid, rs );
+ XmlNodeIq iq( "get", iqId, jid );
+ XmlNode* query = iq.addQuery( "http://jabber.org/protocol/disco#info" );
+ JabberSend( jabberThreadInfo->s, iq );
+ }
+ }
+ else if (( item->cap & CLIENT_CAP_FILE ) && ( item->cap & CLIENT_CAP_BYTESTREAM ))
+ // Use the new standard file transfer
+ JabberFtInitiate( item->jid, ft );
+ else // Use the jabber:iq:oob file transfer
+ JabberForkThread(( JABBER_THREAD_FUNC )JabberFileServerThread, 0, ft );
+
+ return ( int )( HANDLE ) ft;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberSendMessage - sends a message
+
+static void __cdecl JabberSendMessageAckThread( HANDLE hContact )
+{
+ SleepEx( 10, TRUE );
+ JabberLog( "Broadcast ACK" );
+ JSendBroadcast( hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, ( HANDLE ) 1, 0 );
+ JabberLog( "Returning from thread" );
+}
+
+static char PGP_PROLOG[] = "-----BEGIN PGP MESSAGE-----\r\n\r\n";
+static char PGP_EPILOG[] = "\r\n-----END PGP MESSAGE-----\r\n";
+
+int JabberSendMessage( WPARAM wParam, LPARAM lParam )
+{
+ CCSDATA *ccs = ( CCSDATA * ) lParam;
+ JABBER_LIST_ITEM *item;
+ int id;
+
+ DBVARIANT dbv;
+ if ( !jabberOnline || JGetStringT( ccs->hContact, "jid", &dbv )) {
+ JSendBroadcast( ccs->hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, ( HANDLE ) 1, 0 );
+ return 0;
+ }
+
+ char* pszSrc = ( char* )ccs->lParam, *msg;
+ int isEncrypted;
+
+ char* pdest = strstr( pszSrc, PGP_PROLOG );//pdest-string+1 is index of first occurence
+ if ( pdest != NULL ) {
+ pdest = strstr( pszSrc, PGP_EPILOG );
+ int result = ( pdest ) ? strlen( PGP_PROLOG ) : 0;
+
+ char* tempstring = ( char* )alloca( strlen( pszSrc ));
+ strncpy( tempstring, pszSrc+strlen(PGP_PROLOG), strlen(pszSrc)-strlen(PGP_EPILOG)-result );
+ pszSrc = tempstring;
+ isEncrypted = 1;
+ }
+ else isEncrypted = 0;
+
+ if ( ccs->wParam & PREF_UNICODE )
+ msg = JabberTextEncodeW(( wchar_t* )&pszSrc[ strlen( pszSrc )+1 ] );
+ else
+ msg = JabberTextEncode( pszSrc );
+
+ if ( msg != NULL ) {
+ char msgType[ 16 ];
+ if ( JabberListExist( LIST_CHATROOM, dbv.ptszVal ) && _tcschr( dbv.ptszVal, '/' )==NULL )
+ strcpy( msgType, "groupchat" );
+ else
+ strcpy( msgType, "chat" );
+
+ XmlNode m( "message" ); m.addAttr( "type", msgType );
+ if ( !isEncrypted ) {
+ XmlNode* body = m.addChild( "body" );
+ body->sendText = msg;
+ }
+ else {
+ m.addChild( "body", "[This message is encrypted.]" );
+ XmlNode* x = m.addChild( "x" ); x->addAttr( "xmlns", "jabber:x:encrypted" );
+ x->sendText = msg;
+ }
+
+ XmlNode* active = m.addChild( "active" ); active->addAttr( "xmlns", _T("http://jabber.org/protocol/chatstates"));
+
+ if ( !strcmp( msgType, "groupchat" ) || JGetByte( "MsgAck", FALSE ) == FALSE ) {
+ if ( !strcmp( msgType, "groupchat" ))
+ m.addAttr( "to", dbv.ptszVal );
+ else {
+ id = JabberSerialNext();
+ TCHAR szClientJid[ 256 ];
+ JabberGetClientJID( dbv.ptszVal, szClientJid, SIZEOF( szClientJid ));
+
+ m.addAttr( "to", szClientJid ); m.addAttrID( id );
+ XmlNode* x = m.addChild( "x" ); x->addAttr( "xmlns", "jabber:x:event" ); x->addChild( "composing" );
+ }
+
+ JabberSend( jabberThreadInfo->s, m );
+ JabberForkThread( JabberSendMessageAckThread, 0, ( void* )ccs->hContact );
+ }
+ else {
+ id = JabberSerialNext();
+ if (( item=JabberListGetItemPtr( LIST_ROSTER, dbv.ptszVal )) != NULL )
+ item->idMsgAckPending = id;
+
+ TCHAR szClientJid[ 256 ];
+ JabberGetClientJID( dbv.ptszVal, szClientJid, SIZEOF( szClientJid ));
+ m.addAttr( "to", szClientJid ); m.addAttrID( id );
+
+ XmlNode* x = m.addChild( "x" ); x->addAttr( "xmlns", "jabber:x:event" );
+ x->addChild( "composing" ); x->addChild( "delivered" ); x->addChild( "offline" );
+ JabberSend( jabberThreadInfo->s, m );
+ } }
+
+ JFreeVariant( &dbv );
+ return 1;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberSetApparentMode - sets the visibility status
+
+int JabberSetApparentMode( WPARAM wParam, LPARAM lParam )
+{
+ CCSDATA *ccs = ( CCSDATA * ) lParam;
+
+ if ( ccs->wParam!=0 && ccs->wParam!=ID_STATUS_ONLINE && ccs->wParam!=ID_STATUS_OFFLINE ) return 1;
+ int oldMode = JGetWord( ccs->hContact, "ApparentMode", 0 );
+ if (( int ) ccs->wParam == oldMode ) return 1;
+ JSetWord( ccs->hContact, "ApparentMode", ( WORD )ccs->wParam );
+
+ if ( !jabberOnline ) return 0;
+
+ DBVARIANT dbv;
+ if ( !JGetStringT( ccs->hContact, "jid", &dbv )) {
+ TCHAR* jid = dbv.ptszVal;
+ switch ( ccs->wParam ) {
+ case ID_STATUS_ONLINE:
+ if ( jabberStatus == ID_STATUS_INVISIBLE || oldMode == ID_STATUS_OFFLINE ) {
+ XmlNode p( "presence" ); p.addAttr( "to", jid );
+ JabberSend( jabberThreadInfo->s, p );
+ }
+ break;
+ case ID_STATUS_OFFLINE:
+ if ( jabberStatus != ID_STATUS_INVISIBLE || oldMode == ID_STATUS_ONLINE )
+ JabberSendPresenceTo( ID_STATUS_INVISIBLE, jid, NULL );
+ break;
+ case 0:
+ if ( oldMode == ID_STATUS_ONLINE && jabberStatus == ID_STATUS_INVISIBLE )
+ JabberSendPresenceTo( ID_STATUS_INVISIBLE, jid, NULL );
+ else if ( oldMode == ID_STATUS_OFFLINE && jabberStatus != ID_STATUS_INVISIBLE )
+ JabberSendPresenceTo( jabberStatus, jid, NULL );
+ break;
+ }
+ JFreeVariant( &dbv );
+ }
+
+ // TODO: update the zebra list ( jabber:iq:privacy )
+
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberSetAwayMsg - sets the away status message
+
+int JabberSetAwayMsg( WPARAM wParam, LPARAM lParam )
+{
+ JabberLog( "SetAwayMsg called, wParam=%d lParam=%s", wParam, ( char* )lParam );
+
+ EnterCriticalSection( &modeMsgMutex );
+
+ char **szMsg;
+ int desiredStatus = wParam;
+
+ switch ( desiredStatus ) {
+ case ID_STATUS_ONLINE:
+ szMsg = &modeMsgs.szOnline;
+ break;
+ case ID_STATUS_AWAY:
+ case ID_STATUS_ONTHEPHONE:
+ case ID_STATUS_OUTTOLUNCH:
+ szMsg = &modeMsgs.szAway;
+ break;
+ case ID_STATUS_NA:
+ szMsg = &modeMsgs.szNa;
+ break;
+ case ID_STATUS_DND:
+ case ID_STATUS_OCCUPIED:
+ szMsg = &modeMsgs.szDnd;
+ break;
+ case ID_STATUS_FREECHAT:
+ szMsg = &modeMsgs.szFreechat;
+ break;
+ default:
+ LeaveCriticalSection( &modeMsgMutex );
+ return 1;
+ }
+
+ char* newModeMsg = mir_strdup(( char* )lParam );
+
+ if (( *szMsg==NULL && newModeMsg==NULL ) ||
+ ( *szMsg!=NULL && newModeMsg!=NULL && !strcmp( *szMsg, newModeMsg )) ) {
+ // Message is the same, no update needed
+ if ( newModeMsg != NULL ) mir_free( newModeMsg );
+ }
+ else {
+ // Update with the new mode message
+ if ( *szMsg != NULL ) mir_free( *szMsg );
+ *szMsg = newModeMsg;
+ // Send a presence update if needed
+ if ( desiredStatus == jabberStatus ) {
+ JabberSendPresence( jabberStatus );
+ } }
+
+ LeaveCriticalSection( &modeMsgMutex );
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// JabberSetStatus - sets the protocol status
+
+int JabberSetStatus( WPARAM wParam, LPARAM lParam )
+{
+ JabberLog( "PS_SETSTATUS( %d )", wParam );
+ int desiredStatus = wParam;
+ jabberDesiredStatus = desiredStatus;
+
+ if ( desiredStatus == ID_STATUS_OFFLINE ) {
+ if ( jabberThreadInfo ) {
+ HANDLE s = jabberThreadInfo->s;
+ jabberThreadInfo = NULL;
+ if ( jabberConnected ) {
+ JabberSend( s, "</stream:stream>" );
+ jabberConnected = jabberOnline = FALSE;
+ }
+ Netlib_CloseHandle(s); // New Line
+ }
+
+ int oldStatus = jabberStatus;
+ jabberStatus = jabberDesiredStatus = ID_STATUS_OFFLINE;
+ JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, jabberStatus );
+ }
+ else if ( !jabberConnected && !( jabberStatus >= ID_STATUS_CONNECTING && jabberStatus < ID_STATUS_CONNECTING + MAX_CONNECT_RETRIES )) {
+ if ( jabberConnected )
+ return 0;
+
+ ThreadData* thread = ( ThreadData* ) mir_alloc( sizeof( struct ThreadData ));
+
+ ZeroMemory( thread, sizeof( struct ThreadData ));
+ thread->type = JABBER_SESSION_NORMAL;
+ jabberDesiredStatus = desiredStatus;
+
+ int oldStatus = jabberStatus;
+ jabberStatus = ID_STATUS_CONNECTING;
+ JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, jabberStatus );
+ thread->hThread = ( HANDLE ) JabberForkThread(( JABBER_THREAD_FUNC )JabberServerThread, 0, thread );
+ }
+ else JabberSetServerStatus( desiredStatus );
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberUserIsTyping - sends a UTN notification
+
+int JabberUserIsTyping( WPARAM wParam, LPARAM lParam )
+{
+ if ( !jabberOnline ) return 0;
+
+ HANDLE hContact = ( HANDLE ) wParam;
+ DBVARIANT dbv;
+ if ( JGetStringT( hContact, "jid", &dbv )) return 0;
+
+ JABBER_LIST_ITEM *item;
+ if (( item = JabberListGetItemPtr( LIST_ROSTER, dbv.ptszVal )) != NULL ) {
+ TCHAR szClientJid[ 256 ];
+ JabberGetClientJID( dbv.ptszVal, szClientJid, SIZEOF( szClientJid ));
+ XmlNode m( "message" ); m.addAttr( "to", szClientJid );
+
+ if ( item->cap & CLIENT_CAP_CHATSTAT ) {
+ m.addAttr( "type", "chat" );
+ m.addAttrID( JabberSerialNext());
+ switch ( lParam ){
+ case PROTOTYPE_SELFTYPING_OFF:
+ m.addChild( "paused" )->addAttr( "xmlns", _T("http://jabber.org/protocol/chatstates"));
+ JabberSend( jabberThreadInfo->s, m );
+ break;
+ case PROTOTYPE_SELFTYPING_ON:
+ m.addChild( "composing" )->addAttr( "xmlns", _T("http://jabber.org/protocol/chatstates"));
+ JabberSend( jabberThreadInfo->s, m );
+ break;
+ }
+ }
+ else if ( item->wantComposingEvent == TRUE ) {
+ XmlNode* x = m.addChild( "x" ); x->addAttr( "xmlns", "jabber:x:event" );
+ if ( item->messageEventIdStr != NULL )
+ x->addChild( "id", item->messageEventIdStr );
+
+ switch ( lParam ){
+ case PROTOTYPE_SELFTYPING_OFF:
+ JabberSend( jabberThreadInfo->s, m );
+ break;
+ case PROTOTYPE_SELFTYPING_ON:
+ x->addChild( "composing" );
+ JabberSend( jabberThreadInfo->s, m );
+ break;
+ } } }
+
+ JFreeVariant( &dbv );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// "/SendXML" - Allows external plugins to send XML to the server
+
+int ServiceSendXML(WPARAM wParam, LPARAM lParam)
+{
+ return JabberSend( jabberThreadInfo->s, (char*)lParam);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Service initialization code
+
+static HANDLE hEventSettingChanged = NULL;
+static HANDLE hEventContactDeleted = NULL;
+static HANDLE hEventRebuildCMenu = NULL;
+
+static HANDLE hMenuAgent = NULL;
+static HANDLE hMenuChangePassword = NULL;
+static HANDLE hMenuGroupchat = NULL;
+
+int JabberMenuHandleAgents( WPARAM wParam, LPARAM lParam );
+int JabberMenuHandleChangePassword( WPARAM wParam, LPARAM lParam );
+int JabberMenuHandleVcard( WPARAM wParam, LPARAM lParam );
+int JabberMenuHandleRequestAuth( WPARAM wParam, LPARAM lParam );
+int JabberMenuHandleGrantAuth( WPARAM wParam, LPARAM lParam );
+int JabberMenuPrebuildContactMenu( WPARAM wParam, LPARAM lParam );
+
+void JabberEnableMenuItems( BOOL bEnable )
+{
+ CLISTMENUITEM clmi = { 0 };
+ clmi.cbSize = sizeof( CLISTMENUITEM );
+ clmi.flags = CMIM_FLAGS;
+ if ( !bEnable )
+ clmi.flags += CMIF_GRAYED;
+
+ JCallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuAgent, ( LPARAM )&clmi );
+ JCallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuChangePassword, ( LPARAM )&clmi );
+ JCallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hMenuGroupchat, ( LPARAM )&clmi );
+}
+
+int JabberSvcInit( void )
+{
+ hEventSettingChanged = HookEvent( ME_DB_CONTACT_SETTINGCHANGED, JabberDbSettingChanged );
+ hEventContactDeleted = HookEvent( ME_DB_CONTACT_DELETED, JabberContactDeleted );
+ hEventRebuildCMenu = HookEvent( ME_CLIST_PREBUILDCONTACTMENU, JabberMenuPrebuildContactMenu );
+
+ JCreateServiceFunction( PS_GETCAPS, JabberGetCaps );
+ JCreateServiceFunction( PS_GETNAME, JabberGetName );
+ JCreateServiceFunction( PS_LOADICON, JabberLoadIcon );
+ JCreateServiceFunction( PS_BASICSEARCH, JabberBasicSearch );
+ JCreateServiceFunction( PS_SEARCHBYEMAIL, JabberSearchByEmail );
+ JCreateServiceFunction( PS_SEARCHBYNAME, JabberSearchByName );
+ JCreateServiceFunction( PS_ADDTOLIST, JabberAddToList );
+ JCreateServiceFunction( PS_ADDTOLISTBYEVENT, JabberAddToListByEvent );
+ JCreateServiceFunction( PS_AUTHALLOW, JabberAuthAllow );
+ JCreateServiceFunction( PS_AUTHDENY, JabberAuthDeny );
+ JCreateServiceFunction( PS_SETSTATUS, JabberSetStatus );
+ JCreateServiceFunction( PS_GETAVATARINFO, JabberGetAvatarInfo );
+ JCreateServiceFunction( PS_GETSTATUS, JabberGetStatus );
+ JCreateServiceFunction( PS_SETAWAYMSG, JabberSetAwayMsg );
+ JCreateServiceFunction( PS_FILERESUME, JabberFileResume );
+
+ JCreateServiceFunction( PSS_GETINFO, JabberGetInfo );
+ JCreateServiceFunction( PSS_SETAPPARENTMODE, JabberSetApparentMode );
+ JCreateServiceFunction( PSS_MESSAGE, JabberSendMessage );
+ JCreateServiceFunction( PSS_GETAWAYMSG, JabberGetAwayMsg );
+ JCreateServiceFunction( PSS_FILEALLOW, JabberFileAllow );
+ JCreateServiceFunction( PSS_FILECANCEL, JabberFileCancel );
+ JCreateServiceFunction( PSS_FILEDENY, JabberFileDeny );
+ JCreateServiceFunction( PSS_FILE, JabberSendFile );
+ JCreateServiceFunction( PSR_MESSAGE, JabberRecvMessage );
+ JCreateServiceFunction( PSR_FILE, JabberRecvFile );
+ JCreateServiceFunction( PSS_USERISTYPING, JabberUserIsTyping );
+
+ // Protocol services and events...
+ heventRawXMLIn = JCreateHookableEvent( JE_RAWXMLIN );
+ heventRawXMLOut = JCreateHookableEvent( JE_RAWXMLOUT );
+ JCreateServiceFunction( JS_SENDXML, ServiceSendXML );
+
+ // Menu items
+ CLISTMENUITEM mi, clmi;
+ memset( &mi, 0, sizeof( CLISTMENUITEM ));
+ mi.cbSize = sizeof( CLISTMENUITEM );
+ memset( &clmi, 0, sizeof( CLISTMENUITEM ));
+ clmi.cbSize = sizeof( CLISTMENUITEM );
+ clmi.flags = CMIM_FLAGS | CMIF_GRAYED;
+
+ // Add Jabber menu to the main menu
+ char text[_MAX_PATH];
+ strcpy( text, jabberProtoName );
+ char* tDest = text + strlen( text );
+
+ if ( !JGetByte( "DisableMainMenu", FALSE )) {
+ // "Agents..."
+ strcpy( tDest, "/Agents" );
+ CreateServiceFunction( text, JabberMenuHandleAgents );
+
+ mi.pszPopupName = jabberModuleName;
+ mi.popupPosition = 500090000;
+ mi.pszName = JTranslate( "Agents..." );
+ mi.position = 2000050000;
+ mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_AGENTS ));
+ mi.pszService = text;
+ hMenuAgent = ( HANDLE ) JCallService( MS_CLIST_ADDMAINMENUITEM, 0, ( LPARAM )&mi );
+ JCallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM ) hMenuAgent, ( LPARAM )&clmi );
+
+ // "Change Password..."
+ strcpy( tDest, "/ChangePassword" );
+ CreateServiceFunction( text, JabberMenuHandleChangePassword );
+ mi.pszName = JTranslate( "Change Password..." );
+ mi.position = 2000050001;
+ mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_KEYS ));
+ mi.pszService = text;
+ hMenuChangePassword = ( HANDLE ) JCallService( MS_CLIST_ADDMAINMENUITEM, 0, ( LPARAM )&mi );
+ JCallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM ) hMenuChangePassword, ( LPARAM )&clmi );
+
+ // "Multi-User Conference..."
+ strcpy( tDest, "/Groupchat" );
+ CreateServiceFunction( text, JabberMenuHandleGroupchat );
+ mi.pszName = JTranslate( "Multi-User Conference..." );
+ mi.position = 2000050002;
+ mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_GROUP ));
+ mi.pszService = text;
+ hMenuGroupchat = ( HANDLE ) JCallService( MS_CLIST_ADDMAINMENUITEM, 0, ( LPARAM )&mi );
+ JCallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM ) hMenuGroupchat, ( LPARAM )&clmi );
+
+ // "Personal vCard..."
+ strcpy( tDest, "/Vcard" );
+ CreateServiceFunction( text, JabberMenuHandleVcard );
+ mi.pszName = JTranslate( "Personal vCard..." );
+ mi.position = 2000050003;
+ mi.hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDI_VCARD ));
+ mi.pszService = text;
+ JCallService( MS_CLIST_ADDMAINMENUITEM, 0, ( LPARAM )&mi );
+ }
+ return 0;
+}
+
+int JabberSvcUninit()
+{
+ if ( hEventSettingChanged ) UnhookEvent( hEventSettingChanged );
+ if ( hEventContactDeleted ) UnhookEvent( hEventContactDeleted );
+ if ( hEventRebuildCMenu ) UnhookEvent( hEventRebuildCMenu );
+ return 0;
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_thread.cpp b/miranda-wine/protocols/JabberG/jabber_thread.cpp new file mode 100644 index 0000000..84eabb7 --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_thread.cpp @@ -0,0 +1,1793 @@ +/*
+
+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_thread.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 <io.h>
+#include <WinDNS.h> // requires Windows Platform SDK
+
+#include "jabber_ssl.h"
+#include "jabber_list.h"
+#include "jabber_iq.h"
+#include "resource.h"
+
+// <iq/> identification number for various actions
+// for JABBER_REGISTER thread
+unsigned int iqIdRegGetReg;
+unsigned int iqIdRegSetReg;
+
+static void __cdecl JabberKeepAliveThread( JABBER_SOCKET s );
+static void JabberProcessStreamOpening( XmlNode *node, void *userdata );
+static void JabberProcessStreamClosing( XmlNode *node, void *userdata );
+static void JabberProcessProtocol( XmlNode *node, void *userdata );
+static void JabberProcessMessage( XmlNode *node, void *userdata );
+static void JabberProcessPresence( XmlNode *node, void *userdata );
+static void JabberProcessIq( XmlNode *node, void *userdata );
+static void JabberProcessProceed( XmlNode *node, void *userdata );
+static void JabberProcessRegIq( XmlNode *node, void *userdata );
+
+static VOID CALLBACK JabberDummyApcFunc( DWORD param )
+{
+ return;
+}
+
+static char onlinePassword[128];
+static HANDLE hEventPasswdDlg;
+
+static BOOL CALLBACK JabberPasswordDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwndDlg );
+ { TCHAR text[128];
+ mir_sntprintf( text, SIZEOF(text), _T("%s %s"), TranslateT( "Enter password for" ), ( TCHAR* )lParam );
+ SetDlgItemText( hwndDlg, IDC_JID, text );
+ }
+ return TRUE;
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDOK:
+ GetDlgItemTextA( hwndDlg, IDC_PASSWORD, onlinePassword, SIZEOF( onlinePassword ));
+ //EndDialog( hwndDlg, ( int ) onlinePassword );
+ //return TRUE;
+ // Fall through
+ case IDCANCEL:
+ //EndDialog( hwndDlg, 0 );
+ SetEvent( hEventPasswdDlg );
+ DestroyWindow( hwndDlg );
+ return TRUE;
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+static VOID CALLBACK JabberPasswordCreateDialogApcProc( DWORD param )
+{
+ CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_PASSWORD ), NULL, JabberPasswordDlgProc, ( LPARAM )param );
+}
+
+static VOID CALLBACK JabberOfflineChatWindows( DWORD )
+{
+ GCDEST gcd = { jabberProtoName, NULL, GC_EVENT_CONTROL };
+ GCEVENT gce = { 0 };
+ gce.cbSize = sizeof(GCEVENT);
+ gce.pDest = &gcd;
+ CallService( MS_GC_EVENT, SESSION_TERMINATE, (LPARAM)&gce );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+typedef DNS_STATUS (WINAPI *DNSQUERYA)(IN PCSTR pszName, IN WORD wType, IN DWORD Options, IN PIP4_ARRAY aipServers OPTIONAL, IN OUT PDNS_RECORD *ppQueryResults OPTIONAL, IN OUT PVOID *pReserved OPTIONAL);
+typedef void (WINAPI *DNSFREELIST)(IN OUT PDNS_RECORD pRecordList, IN DNS_FREE_TYPE FreeType);
+
+static int xmpp_client_query( char* domain )
+{
+ HINSTANCE hDnsapi = LoadLibraryA( "dnsapi.dll" );
+ if ( hDnsapi == NULL )
+ return 0;
+
+ DNSQUERYA pDnsQuery = (DNSQUERYA)GetProcAddress(hDnsapi, "DnsQuery_A");
+ DNSFREELIST pDnsRecordListFree = (DNSFREELIST)GetProcAddress(hDnsapi, "DnsRecordListFree");
+ if ( pDnsQuery == NULL ) {
+ //dnsapi.dll is not the needed dnsapi ;)
+ FreeLibrary( hDnsapi );
+ return 0;
+ }
+
+ char temp[256];
+ mir_snprintf( temp, SIZEOF(temp), "_xmpp-client._tcp.%s", domain );
+
+ DNS_RECORD *results = NULL;
+ DNS_STATUS status = pDnsQuery(temp, DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &results, NULL);
+ if (FAILED(status)||!results || results[0].Data.Srv.pNameTarget == 0||results[0].wType != DNS_TYPE_SRV) {
+ FreeLibrary(hDnsapi);
+ return NULL;
+ }
+
+ strncpy(domain, (char*)results[0].Data.Srv.pNameTarget, 127);
+ int port = results[0].Data.Srv.wPort;
+ pDnsRecordListFree(results, DnsFreeRecordList);
+ FreeLibrary(hDnsapi);
+ return port;
+}
+
+static XmlState xmlState;
+static char *xmlStreamToBeInitialized = 0;
+static void xmlStreamInitialize(char *which){
+ JabberLog("Stream will be initialized %s",which);
+ xmlStreamToBeInitialized = strdup(which);
+}
+static void xmlStreamInitializeNow(struct ThreadData *info){
+ JabberLog("Stream is initializing %s",xmlStreamToBeInitialized?xmlStreamToBeInitialized:"after connect");
+ if (xmlStreamToBeInitialized){
+ free(xmlStreamToBeInitialized);
+ xmlStreamToBeInitialized = NULL;
+ JabberXmlDestroyState(&xmlState);
+ }
+ JabberXmlInitState( &xmlState );
+ JabberXmlSetCallback( &xmlState, 1, ELEM_OPEN, JabberProcessStreamOpening, info );
+ JabberXmlSetCallback( &xmlState, 1, ELEM_CLOSE, JabberProcessStreamClosing, info );
+ JabberXmlSetCallback( &xmlState, 2, ELEM_CLOSE, JabberProcessProtocol, info );
+ //JabberSend( info->s, "<?xml version=\"1.0\" encoding=\"UTF-8\"?><stream:stream to=\"%s\" xmlns=\"jabber:client\" xmlns:stream=\"http://etherx.jabber.org/streams\" version=\"1.0\">", TXT(info->server) );
+ { XmlNode stream( "stream:stream" );
+ stream.props = "<?xml version='1.0' encoding='UTF-8'?>";
+ stream.addAttr( "to", info->server );
+ stream.addAttr( "xmlns", "jabber:client" );
+ stream.addAttr( "xmlns:stream", "http://etherx.jabber.org/streams" );
+ if ( !JGetByte( "Disable3920auth", 0 ))
+ stream.addAttr( "version", "1.0" );
+ stream.dirtyHack = true; // this is to keep the node open - do not send </stream:stream>
+ JabberSend( info->s, stream );
+} }
+
+static bool wasSaslPerformed = 0;
+
+void __cdecl JabberServerThread( struct ThreadData *info )
+{
+ DBVARIANT dbv;
+ char* buffer;
+ int datalen;
+ int oldStatus;
+ PVOID ssl;
+
+ JabberLog( "Thread started: type=%d", info->type );
+
+ wasSaslPerformed = false;
+ if ( info->type == JABBER_SESSION_NORMAL ) {
+
+ // Normal server connection, we will fetch all connection parameters
+ // e.g. username, password, etc. from the database.
+
+ if ( jabberThreadInfo != NULL ) {
+ // Will not start another connection thread if a thread is already running.
+ // Make APC call to the main thread. This will immediately wake the thread up
+ // in case it is asleep in the reconnect loop so that it will immediately
+ // reconnect.
+ QueueUserAPC( JabberDummyApcFunc, jabberThreadInfo->hThread, 0 );
+ JabberLog( "Thread ended, another normal thread is running" );
+ mir_free( info );
+ return;
+ }
+
+ jabberThreadInfo = info;
+ if ( streamId ) mir_free( streamId );
+ streamId = NULL;
+
+ if ( !JGetStringT( NULL, "LoginName", &dbv )) {
+ _tcsncpy( info->username, dbv.ptszVal, SIZEOF( info->username )-1 );
+ JFreeVariant( &dbv );
+ }
+ else {
+ JabberLog( "Thread ended, login name is not configured" );
+ JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_BADUSERID );
+LBL_FatalError:
+ jabberThreadInfo = NULL;
+ oldStatus = jabberStatus;
+ jabberStatus = ID_STATUS_OFFLINE;
+ JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, jabberStatus );
+LBL_Exit:
+ mir_free( info );
+ return;
+ }
+
+ if ( *rtrim(info->username) == '\0' ) {
+ JabberLog( "Thread ended, login name is not configured" );
+ JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_BADUSERID );
+ goto LBL_FatalError;
+ }
+
+ if ( !DBGetContactSetting( NULL, jabberProtoName, "LoginServer", &dbv )) {
+ strncpy( info->server, dbv.pszVal, SIZEOF( info->server )-1 );
+ JFreeVariant( &dbv );
+ }
+ else {
+ JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NONETWORK );
+ JabberLog( "Thread ended, login server is not configured" );
+ goto LBL_FatalError;
+ }
+
+ if ( !JGetStringT( NULL, "Resource", &dbv )) {
+ _tcsncpy( info->resource, dbv.ptszVal, SIZEOF( info->resource )-1 );
+ JFreeVariant( &dbv );
+ }
+ else _tcscpy( info->resource, _T("Miranda"));
+
+ TCHAR jidStr[128];
+ mir_sntprintf( jidStr, SIZEOF( jidStr ), _T("%s@") _T(TCHAR_STR_PARAM) _T("/%s"), info->username, info->server, info->resource );
+ _tcsncpy( info->fullJID, jidStr, SIZEOF( info->fullJID )-1 );
+
+ if ( JGetByte( "SavePassword", TRUE ) == FALSE ) {
+ mir_sntprintf( jidStr, SIZEOF( jidStr ), _T("%s@") _T(TCHAR_STR_PARAM), info->username, info->server );
+
+ // Ugly hack: continue logging on only the return value is &( onlinePassword[0] )
+ // because if WM_QUIT while dialog box is still visible, p is returned with some
+ // exit code which may not be NULL.
+ // Should be better with modeless.
+ onlinePassword[0] = ( char )-1;
+ hEventPasswdDlg = CreateEvent( NULL, FALSE, FALSE, NULL );
+ QueueUserAPC( JabberPasswordCreateDialogApcProc, hMainThread, ( DWORD )jidStr );
+ WaitForSingleObject( hEventPasswdDlg, INFINITE );
+ CloseHandle( hEventPasswdDlg );
+
+ if ( onlinePassword[0] == ( TCHAR ) -1 ) {
+ JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_BADUSERID );
+ JabberLog( "Thread ended, password request dialog was canceled" );
+ goto LBL_FatalError;
+ }
+ strncpy( info->password, onlinePassword, SIZEOF( info->password ));
+ info->password[ SIZEOF( info->password )-1] = '\0';
+ }
+ else {
+ if ( DBGetContactSetting( NULL, jabberProtoName, "Password", &dbv )) {
+ JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_BADUSERID );
+ JabberLog( "Thread ended, password is not configured" );
+ goto LBL_FatalError;
+ }
+ JCallService( MS_DB_CRYPT_DECODESTRING, strlen( dbv.pszVal )+1, ( LPARAM )dbv.pszVal );
+ strncpy( info->password, dbv.pszVal, SIZEOF( info->password ));
+ info->password[SIZEOF( info->password )-1] = '\0';
+ JFreeVariant( &dbv );
+ }
+
+ if ( JGetByte( "ManualConnect", FALSE ) == TRUE ) {
+ if ( !DBGetContactSetting( NULL, jabberProtoName, "ManualHost", &dbv )) {
+ strncpy( info->manualHost, dbv.pszVal, SIZEOF( info->manualHost ));
+ info->manualHost[sizeof( info->manualHost )-1] = '\0';
+ JFreeVariant( &dbv );
+ }
+ info->port = JGetWord( NULL, "ManualPort", JABBER_DEFAULT_PORT );
+ }
+ else info->port = JGetWord( NULL, "Port", JABBER_DEFAULT_PORT );
+
+ info->useSSL = JGetByte( "UseSSL", FALSE );
+ }
+
+ else if ( info->type == JABBER_SESSION_REGISTER ) {
+ // Register new user connection, all connection parameters are already filled-in.
+ // Multiple thread allowed, although not possible : )
+ // thinking again.. multiple thread should not be allowed
+ info->reg_done = FALSE;
+ SendMessage( info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 25, ( LPARAM )TranslateT( "Connecting..." ));
+ iqIdRegGetReg = -1;
+ iqIdRegSetReg = -1;
+ }
+ else {
+ JabberLog( "Thread ended, invalid session type" );
+ goto LBL_Exit;
+ }
+
+ char connectHost[128];
+ if ( info->manualHost[0] == 0 ) {
+ int port_temp;
+ strncpy( connectHost, info->server, SIZEOF(info->server));
+ if ( port_temp = xmpp_client_query( connectHost )) { // port_temp will be > 0 if resolution is successful
+ JabberLog("%s%s resolved to %s:%d","_xmpp-client._tcp.",info->server,connectHost,port_temp);
+ if (info->port==0 || info->port==5222)
+ info->port = port_temp;
+ }
+ else JabberLog("%s%s not resolved", "_xmpp-client._tcp.", connectHost);
+ }
+ else strncpy( connectHost, info->manualHost, SIZEOF(connectHost)); // do not resolve if manual host is selected
+
+ JabberLog( "Thread type=%d server='%s' port='%d'", info->type, connectHost, info->port );
+
+ int jabberNetworkBufferSize = 2048;
+ if (( buffer=( char* )mir_alloc( jabberNetworkBufferSize+1 )) == NULL ) { // +1 is for '\0' when debug logging this buffer
+ JabberLog( "Cannot allocate network buffer, thread ended" );
+ if ( info->type == JABBER_SESSION_NORMAL ) {
+ oldStatus = jabberStatus;
+ jabberStatus = ID_STATUS_OFFLINE;
+ JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NONETWORK );
+ JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, jabberStatus );
+ jabberThreadInfo = NULL;
+ }
+ else if ( info->type == JABBER_SESSION_REGISTER ) {
+ SendMessage( info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 100, ( LPARAM )TranslateT( "Error: Not enough memory" ));
+ }
+ JabberLog( "Thread ended, network buffer cannot be allocated" );
+ goto LBL_Exit;
+ }
+
+ info->s = JabberWsConnect( connectHost, info->port );
+ if ( info->s == NULL ) {
+ JabberLog( "Connection failed ( %d )", WSAGetLastError());
+ if ( info->type == JABBER_SESSION_NORMAL ) {
+ if ( jabberThreadInfo == info ) {
+ oldStatus = jabberStatus;
+ jabberStatus = ID_STATUS_OFFLINE;
+ JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NONETWORK );
+ JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, jabberStatus );
+ jabberThreadInfo = NULL;
+ } }
+ else if ( info->type == JABBER_SESSION_REGISTER )
+ SendMessage( info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 100, ( LPARAM )TranslateT( "Error: Cannot connect to the server" ));
+
+ JabberLog( "Thread ended, connection failed" );
+ mir_free( buffer );
+ goto LBL_Exit;
+ }
+
+ // Determine local IP
+ int socket = JCallService( MS_NETLIB_GETSOCKET, ( WPARAM ) info->s, 0 );
+ if ( info->type==JABBER_SESSION_NORMAL && socket!=INVALID_SOCKET ) {
+ struct sockaddr_in saddr;
+ int len;
+
+ len = sizeof( saddr );
+ getsockname( socket, ( struct sockaddr * ) &saddr, &len );
+ jabberLocalIP = saddr.sin_addr.S_un.S_addr;
+ JabberLog( "Local IP = %s", inet_ntoa( saddr.sin_addr ));
+ }
+
+ BOOL sslMode = FALSE;
+ if ( info->useSSL ) {
+ JabberLog( "Intializing SSL connection" );
+ if ( hLibSSL!=NULL && socket!=INVALID_SOCKET ) {
+ JabberLog( "SSL using socket = %d", socket );
+ if (( ssl=pfn_SSL_new( jabberSslCtx )) != NULL ) {
+ JabberLog( "SSL create context ok" );
+ if ( pfn_SSL_set_fd( ssl, socket ) > 0 ) {
+ JabberLog( "SSL set fd ok" );
+ if ( pfn_SSL_connect( ssl ) > 0 ) {
+ JabberLog( "SSL negotiation ok" );
+ JabberSslAddHandle( info->s, ssl ); // This make all communication on this handle use SSL
+ sslMode = TRUE; // Used in the receive loop below
+ JabberLog( "SSL enabled for handle = %d", info->s );
+ }
+ else {
+ JabberLog( "SSL negotiation failed" );
+ pfn_SSL_free( ssl );
+ } }
+ else {
+ JabberLog( "SSL set fd failed" );
+ pfn_SSL_free( ssl );
+ } } }
+
+ if ( !sslMode ) {
+ if ( info->type == JABBER_SESSION_NORMAL ) {
+ oldStatus = jabberStatus;
+ jabberStatus = ID_STATUS_OFFLINE;
+ JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, jabberStatus );
+ JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_NONETWORK );
+ if ( jabberThreadInfo == info )
+ jabberThreadInfo = NULL;
+ }
+ else if ( info->type == JABBER_SESSION_REGISTER ) {
+ SendMessage( info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 100, ( LPARAM )TranslateT( "Error: Cannot connect to the server" ));
+ }
+ mir_free( buffer );
+ if ( !hLibSSL )
+ MessageBox( NULL, TranslateT( "The connection requires an OpenSSL library, which is not installed." ), TranslateT( "Jabber Connection Error" ), MB_OK|MB_ICONSTOP|MB_SETFOREGROUND );
+ JabberLog( "Thread ended, SSL connection failed" );
+ goto LBL_Exit;
+ } }
+
+ // User may change status to OFFLINE while we are connecting above
+ if ( jabberDesiredStatus!=ID_STATUS_OFFLINE || info->type==JABBER_SESSION_REGISTER ) {
+
+ if ( info->type == JABBER_SESSION_NORMAL ) {
+ jabberConnected = TRUE;
+ int len = _tcslen( info->username ) + strlen( info->server )+1;
+ jabberJID = ( TCHAR* )mir_alloc( sizeof( TCHAR)*( len+1 ));
+ mir_sntprintf( jabberJID, len+1, _T("%s@") _T(TCHAR_STR_PARAM), info->username, info->server );
+ if ( JGetByte( "KeepAlive", 1 ))
+ jabberSendKeepAlive = TRUE;
+ else
+ jabberSendKeepAlive = FALSE;
+ JabberForkThread( JabberKeepAliveThread, 0, info->s );
+ }
+
+ xmlStreamInitializeNow( info );
+
+ JabberLog( "Entering main recv loop" );
+ datalen = 0;
+
+ for ( ;; ) {
+ int recvResult, bytesParsed;
+
+ if ( !sslMode ) if (info->useSSL) {
+ ssl = JabberSslHandleToSsl( info->s );
+ sslMode = TRUE;
+ }
+
+ if ( sslMode )
+ recvResult = pfn_SSL_read( ssl, buffer+datalen, jabberNetworkBufferSize-datalen );
+ else
+ recvResult = JabberWsRecv( info->s, buffer+datalen, jabberNetworkBufferSize-datalen );
+
+ JabberLog( "recvResult = %d", recvResult );
+ if ( recvResult <= 0 )
+ break;
+ datalen += recvResult;
+
+ buffer[datalen] = '\0';
+ if ( sslMode && DBGetContactSettingByte( NULL, "Netlib", "DumpRecv", TRUE ) == TRUE ) {
+ // Emulate netlib log feature for SSL connection
+ char* szLogBuffer = ( char* )mir_alloc( recvResult+128 );
+ if ( szLogBuffer != NULL ) {
+ strcpy( szLogBuffer, "( SSL ) Data received\n" );
+ memcpy( szLogBuffer+strlen( szLogBuffer ), buffer+datalen-recvResult, recvResult+1 /* also copy \0 */ );
+ Netlib_Logf( hNetlibUser, "%s", szLogBuffer ); // %s to protect against when fmt tokens are in szLogBuffer causing crash
+ mir_free( szLogBuffer );
+ } }
+
+ bytesParsed = JabberXmlParse( &xmlState, buffer );
+ JabberLog( "bytesParsed = %d", bytesParsed );
+ if ( bytesParsed > 0 ) {
+ if ( bytesParsed < datalen )
+ memmove( buffer, buffer+bytesParsed, datalen-bytesParsed );
+ datalen -= bytesParsed;
+ }
+ else if ( datalen == jabberNetworkBufferSize ) {
+ jabberNetworkBufferSize += 65536;
+ JabberLog( "Increasing network buffer size to %d", jabberNetworkBufferSize );
+ if (( buffer=( char* )mir_realloc( buffer, jabberNetworkBufferSize+1 )) == NULL ) {
+ JabberLog( "Cannot reallocate more network buffer, go offline now" );
+ break;
+ } }
+ else JabberLog( "Unknown state: bytesParsed=%d, datalen=%d, jabberNetworkBufferSize=%d", bytesParsed, datalen, jabberNetworkBufferSize );
+
+ if (xmlStreamToBeInitialized) xmlStreamInitializeNow(info);
+ }
+
+ JabberXmlDestroyState(&xmlState);
+
+ if ( info->type == JABBER_SESSION_NORMAL ) {
+ jabberOnline = FALSE;
+ jabberConnected = FALSE;
+ JabberEnableMenuItems( FALSE );
+ if ( hwndJabberChangePassword ) {
+ //DestroyWindow( hwndJabberChangePassword );
+ // Since this is a different thread, simulate the click on the cancel button instead
+ SendMessage( hwndJabberChangePassword, WM_COMMAND, MAKEWORD( IDCANCEL, 0 ), 0 );
+ }
+
+ if ( jabberChatDllPresent )
+ QueueUserAPC( JabberOfflineChatWindows, hMainThread, 0 );
+
+ JabberListRemoveList( LIST_CHATROOM );
+ if ( hwndJabberAgents )
+ SendMessage( hwndJabberAgents, WM_JABBER_CHECK_ONLINE, 0, 0 );
+ if ( hwndJabberGroupchat )
+ SendMessage( hwndJabberGroupchat, WM_JABBER_CHECK_ONLINE, 0, 0 );
+ if ( hwndJabberJoinGroupchat )
+ SendMessage( hwndJabberJoinGroupchat, WM_JABBER_CHECK_ONLINE, 0, 0 );
+
+ // Set status to offline
+ oldStatus = jabberStatus;
+ jabberStatus = ID_STATUS_OFFLINE;
+ JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, jabberStatus );
+
+ // Set all contacts to offline
+ HANDLE hContact = ( HANDLE ) JCallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ while ( hContact != NULL ) {
+ if ( !lstrcmpA(( char* )JCallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 ), jabberProtoName ))
+ if ( JGetWord( hContact, "Status", ID_STATUS_OFFLINE ) != ID_STATUS_OFFLINE )
+ JSetWord( hContact, "Status", ID_STATUS_OFFLINE );
+
+ hContact = ( HANDLE ) JCallService( MS_DB_CONTACT_FINDNEXT, ( WPARAM ) hContact, 0 );
+ }
+
+ mir_free( jabberJID );
+ jabberJID = NULL;
+ jabberLoggedInTime = 0;
+ JabberListWipe();
+ if ( hwndJabberAgents ) {
+ SendMessage( hwndJabberAgents, WM_JABBER_AGENT_REFRESH, 0, ( LPARAM )"" );
+ SendMessage( hwndJabberAgents, WM_JABBER_TRANSPORT_REFRESH, 0, 0 );
+ }
+ if ( hwndJabberVcard )
+ SendMessage( hwndJabberVcard, WM_JABBER_CHECK_ONLINE, 0, 0 );
+ }
+ else if ( info->type==JABBER_SESSION_REGISTER && !info->reg_done ) {
+ SendMessage( info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 100, ( LPARAM )TranslateT( "Error: Connection lost" ));
+ } }
+ else {
+ if ( info->type == JABBER_SESSION_NORMAL ) {
+ oldStatus = jabberStatus;
+ jabberStatus = ID_STATUS_OFFLINE;
+ JSendBroadcast( NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, ( HANDLE ) oldStatus, jabberStatus );
+ } }
+
+ Netlib_CloseHandle( info->s );
+
+ if ( sslMode ) {
+ pfn_SSL_free( ssl );
+ JabberSslRemoveHandle( info->s );
+ }
+
+ JabberLog( "Thread ended: type=%d server='%s'", info->type, info->server );
+
+ if ( info->type==JABBER_SESSION_NORMAL && jabberThreadInfo==info ) {
+ if ( streamId ) mir_free( streamId );
+ streamId = NULL;
+ jabberThreadInfo = NULL;
+ }
+
+ mir_free( buffer );
+ JabberLog( "Exiting ServerThread" );
+ goto LBL_Exit;
+}
+
+static void JabberIqProcessSearch( XmlNode *node, void *userdata )
+{
+}
+
+static void JabberPerformRegistration( ThreadData* info )
+{
+ iqIdRegGetReg = JabberSerialNext();
+ XmlNodeIq iq("get",iqIdRegGetReg,(char*)NULL);
+ XmlNode* query = iq.addQuery("jabber:iq:register");
+ JabberSend(info->s,iq);
+ SendMessage( info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 50, ( LPARAM )TranslateT( "Requesting registration instruction..." ));
+}
+
+static void JabberPerformIqAuth( ThreadData* info )
+{
+ if ( info->type == JABBER_SESSION_NORMAL ) {
+ int iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_NONE, JabberIqResultGetAuth );
+ XmlNodeIq iq( "get", iqId );
+ XmlNode* query = iq.addQuery( "jabber:iq:auth" );
+ query->addChild( "username", info->username );
+ JabberSend( info->s, iq );
+ }
+ else if ( info->type == JABBER_SESSION_REGISTER )
+ JabberPerformRegistration( info );
+}
+
+static void JabberProcessStreamOpening( XmlNode *node, void *userdata )
+{
+ struct ThreadData *info = ( struct ThreadData * ) userdata;
+ TCHAR* sid;
+
+ if ( node->name==NULL || strcmp( node->name, "stream:stream" ))
+ return;
+
+ if ( info->type == JABBER_SESSION_NORMAL ) {
+ if (( sid=JabberXmlGetAttrValue( node, "id" )) != NULL ) {
+ if ( streamId ) mir_free( streamId );
+ streamId = t2a( sid );
+ } }
+
+ if ( JGetByte( "Disable3920auth", 0 ))
+ JabberPerformIqAuth( info );
+}
+
+static void JabberProcessStreamClosing( XmlNode *node, void *userdata )
+{
+ struct ThreadData *info = ( struct ThreadData * ) userdata;
+
+ Netlib_CloseHandle( info->s );
+ if ( node->name && !strcmp( node->name, "stream:error" ) && node->text )
+ MessageBox( NULL, TranslateTS( node->text ), TranslateT( "Jabber Connection Error" ), MB_OK|MB_ICONERROR|MB_SETFOREGROUND );
+}
+
+static void JabberProcessFeatures( XmlNode *node, void *userdata )
+{
+ struct ThreadData *info = ( struct ThreadData * ) userdata;
+ bool isPlainAvailable = false;
+ bool isMd5available = false;
+ bool isAuthAvailable = false;
+ bool isXGoogleTokenAvailable = false;
+ bool isRegisterAvailable = false;
+ bool areMechanismsDefined = false;
+ bool isSessionAvailable = false;
+
+ for ( int i=0; i < node->numChild; i++ ) {
+ XmlNode* n = node->child[i];
+ if ( !strcmp( n->name, "starttls" )) {
+ if ( !info->useSSL && JGetByte( "UseTLS", FALSE )) {
+ JabberLog( "Requesting TLS" );
+ XmlNode stls( n->name ); stls.addAttr( "xmlns", "urn:ietf:params:xml:ns:xmpp-tls" );
+ JabberSend( info->s, stls );
+ return;
+ } }
+ else if ( !strcmp( n->name, "mechanisms" )) {
+ areMechanismsDefined = true;
+ //JabberLog("%d mechanisms\n",n->numChild);
+ for ( int k=0; k < n->numChild; k++ ) {
+ XmlNode* c = n->child[k];
+ if ( !strcmp( c->name, "mechanism" ))
+ //JabberLog("Mechanism: %s",c->text);
+ if ( !_tcscmp( c->text, _T("PLAIN"))) isPlainAvailable = true;
+ else if ( !_tcscmp( c->text, _T("DIGEST-MD5"))) isMd5available = true;
+ else if ( !_tcscmp( c->text, _T("X-GOOGLE-TOKEN"))) isXGoogleTokenAvailable = true;
+ } }
+ else if ( !strcmp( n->name, "register" )) isRegisterAvailable = true;
+ else if ( !strcmp( n->name, "auth" )) isAuthAvailable = true;
+ else if ( !strcmp( n->name, "session" )) isSessionAvailable = true;
+ }
+
+ if ( areMechanismsDefined ) {
+ char *PLAIN = NULL, *mechanism = NULL;
+ /*if ( isMd5available ) {
+ mechanism = NEWSTR_ALLOCA( "DIGEST-MD5" );
+ }
+ else */if ( isPlainAvailable ) {
+ char *temp = t2a(info->username);
+ int size = strlen(temp)*2+strlen(info->server)+strlen(info->password)+3;
+ char *toEncode = ( char* )alloca( size+1 );
+ mir_snprintf( toEncode, size+1, "%s@%s%c%s%c%s", temp, info->server, 0, temp, 0, info->password );
+ PLAIN = JabberBase64Encode( toEncode, size );
+ mir_free(temp);
+ JabberLog( "Never publish the hash below" );
+ mechanism = NEWSTR_ALLOCA( "PLAIN" );
+ }
+ else {
+ if ( isAuthAvailable ) { // no known mechanisms but iq_auth is available
+ JabberPerformIqAuth( info );
+ return;
+ }
+
+ MessageBox( NULL, TranslateT("No known auth methods available. Giving up."), TranslateT( "Jabber Authentication" ), MB_OK|MB_ICONSTOP|MB_SETFOREGROUND );
+ JabberSend( info->s, "</stream:stream>" );
+ JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_WRONGPASSWORD );
+ return;
+ }
+
+ if ( info->type == JABBER_SESSION_NORMAL ) {
+ XmlNode auth( "auth", PLAIN );
+ auth.addAttr( "xmlns", "urn:ietf:params:xml:ns:xmpp-sasl" );
+ auth.addAttr( "mechanism", mechanism );
+ JabberSend(info->s,auth);
+ wasSaslPerformed = true; //sasl was requested, but we dont know the result
+ }
+ else if ( info->type == JABBER_SESSION_REGISTER )
+ JabberPerformRegistration( info );
+ else
+ JabberSend( info->s, "</stream:stream>" );
+ if (PLAIN) mir_free(PLAIN);
+ return;
+ }
+
+ // mechanisms are not defined.
+ if ( wasSaslPerformed ) { //We are already logged-in
+ int iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_NONE, JabberIqResultBind );
+ XmlNodeIq iq("set",iqId);
+ XmlNode* bind = iq.addChild( "bind" ); bind->addAttr( "xmlns", "urn:ietf:params:xml:ns:xmpp-bind" );
+ bind->addChild( "resource", info->resource );
+ JabberSend( info->s, iq );
+
+ if ( isSessionAvailable )
+ info->bIsSessionAvailable = TRUE;
+
+ return;
+ }
+
+ //mechanisms not available and we are not logged in
+ if ( isAuthAvailable )
+ JabberPerformIqAuth( info );
+}
+
+static void __cdecl JabberWaitAndReconnectThread( int unused )
+{
+ JabberLog("Reconnecting after with new X-GOOGLE-TOKEN");
+ Sleep(1000);
+ ThreadData* thread = ( ThreadData* ) mir_alloc( sizeof( struct ThreadData ));
+ ZeroMemory( thread, sizeof( struct ThreadData ));
+ thread->type = JABBER_SESSION_NORMAL;
+ thread->hThread = ( HANDLE ) JabberForkThread(( JABBER_THREAD_FUNC )JabberServerThread, 0, thread );
+}
+
+
+static void JabberProcessFailure( XmlNode *node, void *userdata ){
+// JabberXmlDumpNode( node );
+ struct ThreadData *info = ( struct ThreadData * ) userdata;
+ TCHAR* type;
+//failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\"
+ if (( type=JabberXmlGetAttrValue( node, "xmlns" )) == NULL ) return;
+ if ( !_tcscmp( type, _T("urn:ietf:params:xml:ns:xmpp-sasl") )){
+ JabberSend( info->s, "</stream:stream>" );
+
+ TCHAR text[128];
+ mir_sntprintf( text, sizeof( text ), _T("%s %s@")_T(TCHAR_STR_PARAM)_T("."), TranslateT( "Authentication failed for" ), info->username, info->server );
+ 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
+} }
+
+static void JabberProcessError( XmlNode *node, void *userdata )
+{
+ struct ThreadData *info = ( struct ThreadData * ) userdata;
+ TCHAR *buff;
+ int i;
+ int pos;
+//failure xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\"
+ if ( !node->numChild ) return;
+ buff = (TCHAR *)mir_alloc(1024*SIZEOF(buff));
+ pos=0;
+ for (i=0;i<node->numChild;i++){
+ pos += mir_sntprintf(buff+pos,1024-pos,
+ _T(TCHAR_STR_PARAM)_T(": %s\n"),
+ node->child[i]->name,node->child[i]->text);
+ if (!strcmp(node->child[i]->name,"conflict")) JSendBroadcast( NULL, ACKTYPE_LOGIN, ACKRESULT_FAILED, NULL, LOGINERR_OTHERLOCATION);
+ }
+ MessageBox( NULL, buff, TranslateT( "Jabber Error" ), MB_OK|MB_ICONSTOP|MB_SETFOREGROUND );
+ mir_free(buff);
+ JabberSend( info->s, "</stream:stream>" );
+}
+
+static void JabberProcessSuccess( XmlNode *node, void *userdata )
+{
+ struct ThreadData *info = ( struct ThreadData * ) userdata;
+ TCHAR* type;
+// int iqId;
+ // RECVED: <success ...
+ // ACTION: if successfully logged in, continue by requesting roster list and set my initial status
+ if (( type=JabberXmlGetAttrValue( node, "xmlns" )) == NULL ) return;
+
+ if ( !_tcscmp( type, _T("urn:ietf:params:xml:ns:xmpp-sasl") )){
+ DBVARIANT dbv;
+
+ JabberLog( "Succcess: Logged-in." );
+ if ( DBGetContactSetting( NULL, jabberProtoName, "Nick", &dbv ))
+ JSetStringT( NULL, "Nick", info->username );
+ else
+ JFreeVariant( &dbv );
+ xmlStreamInitialize( "after successful sasl" );
+ }
+ else {
+ JabberLog( "Succcess: unknown action "TCHAR_STR_PARAM".",type);
+} }
+
+
+static void JabberProcessProtocol( XmlNode *node, void *userdata )
+{
+ struct ThreadData *info;
+
+ info = ( struct ThreadData * ) userdata;
+ if ( !strcmp( node->name, "proceed" )){
+ JabberProcessProceed( node, userdata );
+ return;
+ }
+ else if ( !strcmp( node->name, "stream:features" )){
+ JabberProcessFeatures( node, userdata );
+ }
+ else if ( !strcmp( node->name, "success")){
+ JabberProcessSuccess( node, userdata );
+ }
+ else if ( !strcmp( node->name, "failure")){
+ JabberProcessFailure( node, userdata );
+ }
+ else if ( !strcmp( node->name, "stream:error")){
+ JabberProcessError( node, userdata );
+ }
+ else if ( info->type == JABBER_SESSION_NORMAL ) {
+ if ( !strcmp( node->name, "message" ))
+ JabberProcessMessage( node, userdata );
+ else if ( !strcmp( node->name, "presence" ))
+ JabberProcessPresence( node, userdata );
+ else if ( !strcmp( node->name, "iq" ))
+ JabberProcessIq( node, userdata );
+ else
+ JabberLog( "Invalid top-level tag ( only <message/> <presence/> and <iq/> allowed )" );
+ }
+ else if ( info->type == JABBER_SESSION_REGISTER ) {
+ if ( !strcmp( node->name, "iq" ))
+ JabberProcessRegIq( node, userdata );
+ else
+ JabberLog( "Invalid top-level tag ( only <iq/> allowed )" );
+} }
+
+static void JabberProcessProceed( XmlNode *node, void *userdata )
+{
+ struct ThreadData *info;
+ TCHAR* type;
+ node = node;
+ if (( info=( struct ThreadData * ) userdata ) == NULL ) return;
+ if (( type = JabberXmlGetAttrValue( node, "xmlns" )) != NULL && !lstrcmp( type, _T("error")))
+ return;
+
+ if ( !lstrcmp( type, _T("urn:ietf:params:xml:ns:xmpp-tls" ))){
+ JabberLog("Starting TLS...");
+ int socket = JCallService( MS_NETLIB_GETSOCKET, ( WPARAM ) info->s, 0 );
+ PVOID ssl;
+ if (( ssl=pfn_SSL_new( jabberSslCtx )) != NULL ) {
+ JabberLog( "SSL create context ok" );
+ if ( pfn_SSL_set_fd( ssl, socket ) > 0 ) {
+ JabberLog( "SSL set fd ok" );
+ if ( pfn_SSL_connect( ssl ) > 0 ) {
+ JabberLog( "SSL negotiation ok" );
+ JabberSslAddHandle( info->s, ssl ); // This make all communication on this handle use SSL
+ info->useSSL = true;
+ JabberLog( "SSL enabled for handle = %d", info->s );
+ xmlStreamInitialize( "after successful StartTLS" );
+ }
+ else {
+ JabberLog( "SSL negotiation failed" );
+ pfn_SSL_free( ssl );
+ } }
+ else {
+ JabberLog( "SSL set fd failed" );
+ pfn_SSL_free( ssl );
+} } } }
+
+static void JabberProcessMessage( XmlNode *node, void *userdata )
+{
+ struct ThreadData *info;
+ XmlNode *subjectNode, *xNode, *inviteNode, *idNode, *n;
+ TCHAR* from, *type, *nick, *p, *idStr, *fromResource;
+ int id;
+ HANDLE hContact;
+
+ if ( !node->name || strcmp( node->name, "message" )) return;
+ if (( info=( struct ThreadData * ) userdata ) == NULL ) return;
+
+ type = JabberXmlGetAttrValue( node, "type" );
+ if (( from = JabberXmlGetAttrValue( node, "from" )) == NULL )
+ return;
+
+ XmlNode* errorNode = JabberXmlGetChild( node, "error" );
+ if ( errorNode != NULL || !lstrcmp( type, _T("error"))) {
+ //we check if is message delivery failure
+ if (( idStr = JabberXmlGetAttrValue( node, "id" )) != NULL ) {
+ if ( !_tcsncmp( idStr, _T(JABBER_IQID), strlen( JABBER_IQID )) ){
+ JABBER_LIST_ITEM* item = JabberListGetItemPtr( LIST_ROSTER, from );
+ if ( item != NULL ){
+ id = _ttoi(( idStr )+strlen( JABBER_IQID ));
+ if ( id == item->idMsgAckPending ){ // yes, it is
+ char *errText = t2a(JabberErrorMsg(errorNode));
+ JSendBroadcast( JabberHContactFromJID( from ), ACKTYPE_MESSAGE, ACKRESULT_FAILED, ( HANDLE ) 1, (LPARAM)errText );
+ mir_free(errText);
+ } } } }
+ return;
+ }
+
+ JABBER_LIST_ITEM* chatItem = JabberListGetItemPtr( LIST_CHATROOM, from );
+ BOOL isChatRoomJid = ( chatItem != NULL );
+ if ( isChatRoomJid && !lstrcmp( type, _T("groupchat"))) {
+ JabberGroupchatProcessMessage( node, userdata );
+ return;
+ }
+ BOOL isRss = !lstrcmp( type, _T("headline"));
+
+ // If message is from a stranger ( not in roster ), item is NULL
+ JABBER_LIST_ITEM* item = JabberListGetItemPtr( LIST_ROSTER, from );
+
+ TCHAR* szMessage = NULL;
+ XmlNode* bodyNode = JabberXmlGetChild( node, "body" );
+ if ( bodyNode != NULL ) {
+ if (( subjectNode=JabberXmlGetChild( node, "subject" ))!=NULL && subjectNode->text!=NULL && subjectNode->text[0]!='\0' && !isRss ) {
+ p = ( TCHAR* )alloca( sizeof( TCHAR )*( _tcslen( subjectNode->text ) + _tcslen( bodyNode->text ) + 12 ));
+ wsprintf( p, _T("Subject: %s\r\n%s"), subjectNode->text, bodyNode->text );
+ szMessage = p;
+ }
+ else szMessage = bodyNode->text;
+
+ if (( szMessage = JabberUnixToDosT( szMessage )) == NULL )
+ szMessage = mir_tstrdup( _T(""));
+ }
+
+ time_t msgTime = 0;
+ BOOL isChatRoomInvitation = FALSE;
+ TCHAR* inviteRoomJid = NULL;
+ TCHAR* inviteFromJid = NULL;
+ TCHAR* inviteReason = NULL;
+ TCHAR* invitePassword = NULL;
+ BOOL delivered = FALSE, composing = FALSE;
+
+ n = JabberXmlGetChild( node, "active" );
+ if ( item != NULL && bodyNode != NULL ) {
+ if ( n != NULL && !lstrcmp( JabberXmlGetAttrValue( n, "xmlns" ), _T("http://jabber.org/protocol/chatstates")))
+ item->cap |= CLIENT_CAP_CHATSTAT;
+ else
+ item->cap &= ~CLIENT_CAP_CHATSTAT;
+ }
+
+ n = JabberXmlGetChild( node, "composing" );
+ if ( n != NULL && !lstrcmp( JabberXmlGetAttrValue( n, "xmlns" ), _T("http://jabber.org/protocol/chatstates")))
+ if (( hContact = JabberHContactFromJID( from )) != NULL )
+ JCallService( MS_PROTO_CONTACTISTYPING, ( WPARAM ) hContact, 60 );
+
+ n = JabberXmlGetChild( node, "paused" );
+ if ( n != NULL && !lstrcmp( JabberXmlGetAttrValue( n, "xmlns" ), _T("http://jabber.org/protocol/chatstates")))
+ if (( hContact = JabberHContactFromJID( from )) != NULL )
+ JCallService( MS_PROTO_CONTACTISTYPING, ( WPARAM ) hContact, PROTOTYPE_CONTACTTYPING_OFF );
+
+ for ( int i = 1; ( xNode = JabberXmlGetNthChild( node, "x", i )) != NULL; i++ ) {
+ if (( p=JabberXmlGetAttrValue( xNode, "xmlns" )) != NULL ) {
+ if ( !_tcscmp( p, _T("jabber:x:encrypted" ))) {
+ if ( xNode->text == NULL )
+ return;
+
+ TCHAR* prolog = _T("-----BEGIN PGP MESSAGE-----\r\n\r\n");
+ TCHAR* epilog = _T("\r\n-----END PGP MESSAGE-----\r\n");
+ TCHAR* tempstring = ( TCHAR* )alloca( sizeof( TCHAR )*( _tcslen( prolog ) + _tcslen( xNode->text ) + _tcslen( epilog )));
+ _tcsncpy( tempstring, prolog, _tcslen( prolog )+1 );
+ _tcsncpy(tempstring + _tcslen( prolog ), xNode->text, _tcslen( xNode->text )+1);
+ _tcsncpy(tempstring + _tcslen( prolog )+_tcslen(xNode->text ), epilog, _tcslen( epilog )+1);
+ szMessage = tempstring;
+ }
+ else if ( !_tcscmp( p, _T("jabber:x:delay")) && msgTime == 0 ) {
+ if (( p=JabberXmlGetAttrValue( xNode, "stamp" )) != NULL )
+ msgTime = JabberIsoToUnixTime( p );
+ }
+ else if ( !_tcscmp( p, _T("jabber:x:event"))) {
+ if ( bodyNode == NULL ) {
+ idNode = JabberXmlGetChild( xNode, "id" );
+ if ( JabberXmlGetChild( xNode, "delivered" )!=NULL || JabberXmlGetChild( xNode, "offline" )!=NULL ) {
+ id = -1;
+ if ( idNode!=NULL && idNode->text!=NULL )
+ if ( !_tcsncmp( idNode->text, _T(JABBER_IQID), strlen( JABBER_IQID )) )
+ id = _ttoi(( idNode->text )+strlen( JABBER_IQID ));
+
+ if ( item != NULL )
+ if ( id == item->idMsgAckPending )
+ JSendBroadcast( JabberHContactFromJID( from ), ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, ( HANDLE ) 1, 0 );
+ }
+
+ if ( JabberXmlGetChild( xNode, "composing" ) != NULL )
+ if (( hContact = JabberHContactFromJID( from )) != NULL )
+ JCallService( MS_PROTO_CONTACTISTYPING, ( WPARAM ) hContact, 60 );
+
+ if ( xNode->numChild==0 || ( xNode->numChild==1 && idNode != NULL ))
+ // Maybe a cancel to the previous composing
+ if (( hContact = JabberHContactFromJID( from )) != NULL )
+ JCallService( MS_PROTO_CONTACTISTYPING, ( WPARAM ) hContact, PROTOTYPE_CONTACTTYPING_OFF );
+ }
+ else {
+ // Check whether any event is requested
+ if ( !delivered && ( n=JabberXmlGetChild( xNode, "delivered" )) != NULL ) {
+ delivered = TRUE;
+ idStr = JabberXmlGetAttrValue( node, "id" );
+
+ XmlNode m( "message" ); m.addAttr( "to", from );
+ XmlNode* x = m.addChild( "x" ); x->addAttr( "xmlns", "jabber:x:event" ); x->addChild( "delivered" );
+ x->addChild( "id", ( idStr != NULL ) ? idStr : NULL );
+ JabberSend( info->s, m );
+ }
+ if ( item!=NULL && JabberXmlGetChild( xNode, "composing" ) != NULL ) {
+ composing = TRUE;
+ if ( item->messageEventIdStr )
+ mir_free( item->messageEventIdStr );
+ idStr = JabberXmlGetAttrValue( node, "id" );
+ item->messageEventIdStr = ( idStr==NULL )?NULL:mir_tstrdup( idStr );
+ } }
+ }
+ else if ( !_tcscmp( p, _T("jabber:x:oob")) && isRss) {
+ XmlNode* rssUrlNode;
+ if ( (rssUrlNode = JabberXmlGetNthChild( xNode, "url", 1 )) != NULL) {
+ p = ( TCHAR* )alloca( sizeof(TCHAR)*( _tcslen( subjectNode->text ) + _tcslen( bodyNode->text ) + _tcslen( rssUrlNode->text ) + 14 ));
+ wsprintf( p, _T("Subject: %s\r\n%s\r\n%s"), subjectNode->text, rssUrlNode->text, bodyNode->text );
+ szMessage = p;
+ }
+ }
+ else if ( !_tcscmp( p, _T("http://jabber.org/protocol/muc#user"))) {
+ if (( inviteNode=JabberXmlGetChild( xNode, "invite" )) != NULL ) {
+ inviteFromJid = JabberXmlGetAttrValue( inviteNode, "from" );
+ if (( n=JabberXmlGetChild( inviteNode, "reason" )) != NULL )
+ inviteReason = n->text;
+ }
+
+ if (( n=JabberXmlGetChild( xNode, "password" )) != NULL )
+ invitePassword = n->text;
+ }
+ else if ( !_tcscmp( p, _T("jabber:x:conference"))) {
+ inviteRoomJid = JabberXmlGetAttrValue( xNode, "jid" );
+ if ( inviteReason == NULL )
+ inviteReason = xNode->text;
+ isChatRoomInvitation = TRUE;
+ } } }
+
+ if ( isChatRoomInvitation ) {
+ if ( inviteRoomJid != NULL )
+ JabberGroupchatProcessInvite( inviteRoomJid, inviteFromJid, inviteReason, invitePassword );
+ return;
+ }
+
+ if ( bodyNode != NULL ) {
+ if ( bodyNode->text == NULL )
+ return;
+
+ WCHAR* wszMessage;
+ char* szAnsiMsg;
+ int cbAnsiLen, cbWideLen;
+
+ #if defined( _UNICODE )
+ wszMessage = szMessage; cbWideLen = wcslen( szMessage );
+ cbAnsiLen = WideCharToMultiByte( CP_ACP, 0, wszMessage, cbWideLen, NULL, 0, NULL, NULL );
+ szAnsiMsg = ( char* )alloca( cbAnsiLen+1 );
+ WideCharToMultiByte( CP_ACP, 0, wszMessage, cbWideLen, szAnsiMsg, cbAnsiLen, NULL, NULL );
+ szAnsiMsg[ cbAnsiLen ] = 0;
+ #else
+ szAnsiMsg = szMessage; cbAnsiLen = strlen( szMessage );
+ cbWideLen = MultiByteToWideChar( CP_ACP, 0, szAnsiMsg, cbAnsiLen, NULL, 0 );
+ wszMessage = ( WCHAR* )alloca( sizeof(WCHAR)*( cbWideLen+1 ));
+ MultiByteToWideChar( CP_ACP, 0, szAnsiMsg, cbAnsiLen, wszMessage, cbWideLen );
+ wszMessage[ cbWideLen ] = 0;
+ #endif
+
+ char* buf = ( char* )alloca( cbAnsiLen+1 + (cbWideLen+1)*sizeof( WCHAR ));
+ memcpy( buf, szAnsiMsg, cbAnsiLen+1 );
+ memcpy( buf + cbAnsiLen + 1, wszMessage, (cbWideLen+1)*sizeof( WCHAR ));
+
+ HANDLE hContact = JabberHContactFromJID( from );
+
+ if ( item != NULL ) {
+ item->wantComposingEvent = composing;
+ if ( hContact != NULL )
+ JCallService( MS_PROTO_CONTACTISTYPING, ( WPARAM ) hContact, PROTOTYPE_CONTACTTYPING_OFF );
+
+ if ( item->resourceMode==RSMODE_LASTSEEN && ( fromResource = _tcschr( from, '/' ))!=NULL ) {
+ fromResource++;
+ if ( *fromResource != '\0' ) {
+ for ( int i=0; i<item->resourceCount; i++ ) {
+ if ( !lstrcmp( item->resource[i].resourceName, fromResource )) {
+ item->defaultResource = i;
+ break;
+ } } } } }
+
+ if ( hContact == NULL ) {
+ // Create a temporary contact
+ if ( isChatRoomJid ) {
+ if (( p = _tcschr( from, '/' ))!=NULL && p[1]!='\0' )
+ p++;
+ else
+ p = from;
+ hContact = JabberDBCreateContact( from, p, TRUE, FALSE );
+
+ for ( int i=0; i < chatItem->resourceCount; i++ ) {
+ if ( !lstrcmp( chatItem->resource[i].resourceName, p )) {
+ JSetWord( hContact, "Status", chatItem->resource[i].status );
+ break;
+ } }
+ }
+ else {
+ nick = JabberNickFromJID( from );
+ hContact = JabberDBCreateContact( from, nick, TRUE, TRUE );
+ mir_free( nick );
+ } }
+
+ time_t now = time( NULL );
+ if ( msgTime == 0 || now - jabberLoggedInTime > 60 )
+ msgTime = now;
+
+ PROTORECVEVENT recv;
+ recv.flags = PREF_UNICODE;
+ recv.timestamp = ( DWORD )msgTime;
+ recv.szMessage = buf;
+ recv.lParam = 0;
+
+ CCSDATA ccs;
+ ccs.hContact = hContact;
+ ccs.wParam = 0;
+ ccs.szProtoService = PSR_MESSAGE;
+ ccs.lParam = ( LPARAM )&recv;
+ JCallService( MS_PROTO_CHAINRECV, 0, ( LPARAM )&ccs );
+
+ mir_free( szMessage );
+} }
+
+static void JabberProcessPresence( XmlNode *node, void *userdata )
+{
+ struct ThreadData *info;
+ HANDLE hContact;
+ XmlNode *showNode, *statusNode;
+ JABBER_LIST_ITEM *item;
+ TCHAR* from, *nick, *show;
+ int i;
+ TCHAR* p;
+
+ if ( !node || !node->name || strcmp( node->name, "presence" )) return;
+ if (( info=( struct ThreadData * ) userdata ) == NULL ) return;
+ if (( from = JabberXmlGetAttrValue( node, "from" )) == NULL ) return;
+
+ if ( JabberListExist( LIST_CHATROOM, from )) {
+ JabberGroupchatProcessPresence( node, userdata );
+ return;
+ }
+
+ TCHAR* type = JabberXmlGetAttrValue( node, "type" );
+ if ( type == NULL || !_tcscmp( type, _T("available"))) {
+ if (( nick=JabberNickFromJID( from )) == NULL )
+ return;
+ if (( hContact = JabberHContactFromJID( from )) == NULL )
+ hContact = JabberDBCreateContact( from, nick, FALSE, TRUE );
+ if ( !JabberListExist( LIST_ROSTER, from )) {
+ JabberLog("Receive presence online from "TCHAR_STR_PARAM" ( who is not in my roster )", from );
+ JabberListAdd( LIST_ROSTER, from );
+ }
+ int status = ID_STATUS_ONLINE;
+ if (( showNode = JabberXmlGetChild( node, "show" )) != NULL ) {
+ if (( show = showNode->text ) != NULL ) {
+ if ( !_tcscmp( show, _T("away"))) status = ID_STATUS_AWAY;
+ else if ( !_tcscmp( show, _T("xa"))) status = ID_STATUS_NA;
+ else if ( !_tcscmp( show, _T("dnd"))) status = ID_STATUS_DND;
+ else if ( !_tcscmp( show, _T("chat"))) status = ID_STATUS_FREECHAT;
+ } }
+
+ // Send version query if this is the new resource
+ if (( p = _tcschr( from, '@' )) != NULL ) {
+ if (( p = _tcschr( p, '/' ))!=NULL && p[1]!='\0' ) {
+ p++;
+ if (( item = JabberListGetItemPtr( LIST_ROSTER, from )) != NULL ) {
+ JABBER_RESOURCE_STATUS *r = item->resource;
+ for ( i=0; i < item->resourceCount && lstrcmp( r->resourceName, p ); i++, r++ );
+ if ( i >= item->resourceCount || ( r->version == NULL && r->system == NULL && r->software == NULL )) {
+ XmlNodeIq iq( "get", NOID, from );
+ XmlNode* query = iq.addQuery( "jabber:iq:version" );
+ JabberSend( info->s, iq );
+ } } } }
+
+ if (( statusNode = JabberXmlGetChild( node, "status" )) != NULL && statusNode->text != NULL )
+ p = mir_tstrdup( statusNode->text );
+ else
+ p = NULL;
+ JabberListAddResource( LIST_ROSTER, from, status, p );
+ if ( p ) {
+ DBWriteContactSettingTString( hContact, "CList", "StatusMsg", p );
+ mir_free( p );
+ }
+ else DBDeleteContactSetting( hContact, "CList", "StatusMsg" );
+
+ // Determine status to show for the contact
+ if (( item=JabberListGetItemPtr( LIST_ROSTER, from )) != NULL ) {
+ for ( i=0; i < item->resourceCount; i++ )
+ status = JabberCombineStatus( status, item->resource[i].status );
+ item->status = status;
+ }
+
+ if ( _tcschr( from, '@' )!=NULL || JGetByte( "ShowTransport", TRUE )==TRUE )
+ if ( JGetWord( hContact, "Status", ID_STATUS_OFFLINE ) != status )
+ JSetWord( hContact, "Status", ( WORD )status );
+
+ if ( _tcschr( from, '@' )==NULL && hwndJabberAgents )
+ SendMessage( hwndJabberAgents, WM_JABBER_TRANSPORT_REFRESH, 0, 0 );
+ JabberLog( TCHAR_STR_PARAM " ( " TCHAR_STR_PARAM " ) online, set contact status to %s", nick, from, JCallService(MS_CLIST_GETSTATUSMODEDESCRIPTION,(WPARAM)status,0 ));
+ mir_free( nick );
+
+ XmlNode* xNode;
+ BOOL hasXAvatar = false;
+ if (JGetByte( "EnableAvatars", TRUE )){
+ JabberLog( "Avatar enabled" );
+ for ( int i = 1; ( xNode=JabberXmlGetNthChild( node, "x", i )) != NULL; i++ ) {
+ if ( !lstrcmp( JabberXmlGetAttrValue( xNode, "xmlns" ), _T("jabber:x:avatar"))) {
+ if (( xNode = JabberXmlGetChild( xNode, "hash" )) != NULL && xNode->text != NULL ) {
+ JDeleteSetting(hContact,"AvatarXVcard");
+ JabberLog( "AvatarXVcard deleted" );
+ JSetStringT( hContact, "AvatarHash", xNode->text );
+ hasXAvatar = true;
+ DBVARIANT dbv = {0};
+ int result = JGetStringT( hContact, "AvatarSaved", &dbv );
+ if ( !result || lstrcmp( dbv.ptszVal, xNode->text )) {
+ JabberLog( "Avatar was changed" );
+ JSendBroadcast( hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL, NULL );
+ } else JabberLog( "Not broadcasting avatar changed" );
+ if ( !result ) JFreeVariant( &dbv );
+ } } }
+ if (!hasXAvatar){ //no jabber:x:avatar. try vcard-temp:x:update
+ JabberLog( "Not hasXAvatar" );
+ for ( int i = 1; ( xNode=JabberXmlGetNthChild( node, "x", i )) != NULL; i++ ) {
+ if ( !lstrcmp( JabberXmlGetAttrValue( xNode, "xmlns" ), _T("vcard-temp:x:update"))) {
+ if (( xNode = JabberXmlGetChild( xNode, "photo" )) != NULL && xNode->text != NULL ) {
+ JSetByte(hContact,"AvatarXVcard",1);
+ JabberLog( "AvatarXVcard set" );
+ JSetStringT( hContact, "AvatarHash", xNode->text );
+ DBVARIANT dbv = {0};
+ int result = JGetStringT( hContact, "AvatarSaved", &dbv );
+ if ( !result || lstrcmp( dbv.ptszVal, xNode->text )) {
+ JabberLog( "Avatar was changed. Using vcard-temp:x:update" );
+ JSendBroadcast( hContact, ACKTYPE_AVATAR, ACKRESULT_STATUS, NULL, NULL );
+ } JabberLog( "Not broadcasting avatar changed" );
+ if ( !result ) JFreeVariant( &dbv );
+ } } } } }
+ return;
+ }
+
+ if ( !_tcscmp( type, _T("unavailable"))) {
+ if ( !JabberListExist( LIST_ROSTER, from )) {
+ JabberLog( "Receive presence offline from " TCHAR_STR_PARAM " ( who is not in my roster )", from );
+ JabberListAdd( LIST_ROSTER, from );
+ }
+ else JabberListRemoveResource( LIST_ROSTER, from );
+
+ int status = ID_STATUS_OFFLINE;
+ if (( statusNode = JabberXmlGetChild( node, "status" )) != NULL ) {
+ if ( JGetByte( "OfflineAsInvisible", FALSE ) == TRUE )
+ status = ID_STATUS_INVISIBLE;
+
+ if (( hContact = JabberHContactFromJID( from )) != NULL) {
+ if ( statusNode->text )
+ DBWriteContactSettingTString(hContact, "CList", "StatusMsg", statusNode->text );
+ else
+ DBDeleteContactSetting(hContact, "CList", "StatusMsg");
+ } }
+
+ if (( item=JabberListGetItemPtr( LIST_ROSTER, from )) != NULL ) {
+ // Determine status to show for the contact based on the remaining resources
+ status = ID_STATUS_OFFLINE;
+ for ( i=0; i < item->resourceCount; i++ )
+ status = JabberCombineStatus( status, item->resource[i].status );
+ item->status = status;
+ }
+ if (( hContact=JabberHContactFromJID( from )) != NULL ) {
+ if ( _tcschr( from, '@' )!=NULL || JGetByte( "ShowTransport", TRUE )==TRUE )
+ if ( JGetWord( hContact, "Status", ID_STATUS_OFFLINE ) != status )
+ JSetWord( hContact, "Status", ( WORD )status );
+
+ JabberLog( TCHAR_STR_PARAM " offline, set contact status to %d", from, status );
+ }
+ if ( _tcschr( from, '@' )==NULL && hwndJabberAgents )
+ SendMessage( hwndJabberAgents, WM_JABBER_TRANSPORT_REFRESH, 0, 0 );
+ return;
+ }
+
+ if ( !_tcscmp( type, _T("subscribe"))) {
+ if ( _tcschr( from, '@' ) == NULL ) {
+ // automatically send authorization allowed to agent/transport
+ XmlNode p( "presence" ); p.addAttr( "to", from ); p.addAttr( "type", "subscribed" );
+ JabberSend( info->s, p );
+ }
+ else if (( nick=JabberNickFromJID( from )) != NULL ) {
+ JabberLog( TCHAR_STR_PARAM " ( " TCHAR_STR_PARAM " ) requests authorization", nick, from );
+ JabberDBAddAuthRequest( from, nick );
+ mir_free( nick );
+ }
+ return;
+ }
+
+ if ( !_tcscmp( type, _T("subscribed"))) {
+ if (( item=JabberListGetItemPtr( LIST_ROSTER, from )) != NULL ) {
+ if ( item->subscription == SUB_FROM ) item->subscription = SUB_BOTH;
+ else if ( item->subscription == SUB_NONE ) {
+ item->subscription = SUB_TO;
+ if ( hwndJabberAgents && _tcschr( from, '@' )==NULL )
+ SendMessage( hwndJabberAgents, WM_JABBER_TRANSPORT_REFRESH, 0, 0 );
+} } } }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Handles various <iq... requests
+
+static void JabberProcessIqVersion( TCHAR* idStr, XmlNode* node )
+{
+ TCHAR* from;
+ if (( from=JabberXmlGetAttrValue( node, "from" )) == NULL )
+ return;
+
+ char* version = JabberGetVersionText();
+ TCHAR* os = NULL;
+
+ OSVERSIONINFO osvi = { 0 };
+ osvi.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
+ if ( GetVersionEx( &osvi )) {
+ switch ( osvi.dwPlatformId ) {
+ case VER_PLATFORM_WIN32_NT:
+ if ( osvi.dwMajorVersion == 5 ) {
+ if ( osvi.dwMinorVersion == 2 ) os = TranslateT( "Windows Server 2003" );
+ else if ( osvi.dwMinorVersion == 1 ) os = TranslateT( "Windows XP" );
+ else if ( osvi.dwMinorVersion == 0 ) os = TranslateT( "Windows 2000" );
+ }
+ else if ( osvi.dwMajorVersion <= 4 ) {
+ os = TranslateT( "Windows NT" );
+ }
+ break;
+ case VER_PLATFORM_WIN32_WINDOWS:
+ if ( osvi.dwMajorVersion == 4 ) {
+ if ( osvi.dwMinorVersion == 0 ) os = TranslateT( "Windows 95" );
+ if ( osvi.dwMinorVersion == 10 ) os = TranslateT( "Windows 98" );
+ if ( osvi.dwMinorVersion == 90 ) os = TranslateT( "Windows ME" );
+ }
+ break;
+ } }
+
+ if ( os == NULL ) os = TranslateT( "Windows" );
+
+ char mversion[100];
+ strcpy( mversion, "Miranda IM " );
+ JCallService( MS_SYSTEM_GETVERSIONTEXT, sizeof( mversion )-12, ( LPARAM )&mversion[11] );
+
+ XmlNodeIq iq( "result", idStr, from );
+ XmlNode* query = iq.addQuery( "jabber:iq:version" );
+ query->addChild( "name", mversion ); query->addChild( "version", version ); query->addChild( "os", os );
+ JabberSend( jabberThreadInfo->s, iq );
+
+ if ( version ) mir_free( version );
+}
+
+static void JabberProcessIqTime( TCHAR* idStr, XmlNode* node ) //added by Rion (jep-0090)
+{
+ TCHAR* from;
+ struct tm *gmt;
+ time_t ltime;
+ char stime[20],*dtime;
+ if (( from=JabberXmlGetAttrValue( node, "from" )) == NULL )
+ return;
+
+ _tzset();
+ time( <ime );
+ gmt = gmtime( <ime );
+ sprintf (stime,"%.4i%.2i%.2iT%.2i:%.2i:%.2i",gmt->tm_year+1900,gmt->tm_mon,gmt->tm_mday,gmt->tm_hour,gmt->tm_min,gmt->tm_sec);
+ dtime = ctime(<ime);
+ dtime[24]=0;
+
+ XmlNodeIq iq( "result", idStr, from );
+ XmlNode* query = iq.addQuery( "jabber:iq:time" );
+ query->addChild( "utc", stime ); query->addChild( "tz", _tzname[1] ); query->addChild( "display", dtime );
+ JabberSend( jabberThreadInfo->s, iq );
+}
+
+static void JabberProcessIqAvatar( TCHAR* idStr, XmlNode* node )
+{
+ if ( !JGetByte( "EnableAvatars", TRUE ))
+ return;
+
+ TCHAR* from;
+ if (( from = JabberXmlGetAttrValue( node, "from" )) == NULL )
+ return;
+
+ int pictureType = JGetByte( "AvatarType", PA_FORMAT_UNKNOWN );
+ if ( pictureType == PA_FORMAT_UNKNOWN )
+ return;
+
+ char* szMimeType;
+ switch( pictureType ) {
+ case PA_FORMAT_JPEG: szMimeType = "image/jpeg"; break;
+ case PA_FORMAT_GIF: szMimeType = "image/gif"; break;
+ case PA_FORMAT_PNG: szMimeType = "image/png"; break;
+ case PA_FORMAT_BMP: szMimeType = "image/bmp"; break;
+ default: return;
+ }
+
+ char szFileName[ MAX_PATH ];
+ JabberGetAvatarFileName( NULL, szFileName, MAX_PATH );
+
+ FILE* in = fopen( szFileName, "rb" );
+ if ( in == NULL )
+ return;
+
+ long bytes = filelength( fileno( in ));
+ char* buffer = ( char* )mir_alloc( bytes*4/3 + bytes + 1000 );
+ if ( buffer == NULL ) {
+ fclose( in );
+ return;
+ }
+
+ fread( buffer, bytes, 1, in );
+ fclose( in );
+
+ char* str = JabberBase64Encode( buffer, bytes );
+ XmlNodeIq iq( "result", idStr, from );
+ XmlNode* query = iq.addQuery( "jabber:iq:avatar" );
+ XmlNode* data = query->addChild( "data", str ); data->addAttr( "mimetype", szMimeType );
+ JabberSend( jabberThreadInfo->s, iq );
+ mir_free( str );
+ mir_free( buffer );
+}
+
+static void JabberProcessIqResultVersion( TCHAR* type, XmlNode* node, XmlNode* queryNode )
+{
+ TCHAR* from = JabberXmlGetAttrValue( node, "from" );
+ if ( from == NULL ) return;
+
+ JABBER_LIST_ITEM *item = JabberListGetItemPtr( LIST_ROSTER, from );
+ if ( item == NULL ) return;
+
+ JABBER_RESOURCE_STATUS *r = item->resource;
+ if ( r == NULL ) return;
+
+ TCHAR* p = _tcschr( from, '/' );
+ if ( p == NULL ) return;
+ if ( *++p == '\0' ) return;
+
+ int i;
+ for ( i=0; i<item->resourceCount && _tcscmp( r->resourceName, p ); i++, r++ );
+ if ( i >= item->resourceCount )
+ return;
+
+ HANDLE hContact = JabberHContactFromJID( from );
+ if ( hContact == NULL )
+ return;
+
+ if ( !lstrcmp( type, _T("error"))) {
+ if ( r->resourceName != NULL )
+ JSetStringT( hContact, "MirVer", r->resourceName );
+ return;
+ }
+
+ XmlNode* n;
+ if ( r->software ) mir_free( r->software );
+ if (( n=JabberXmlGetChild( queryNode, "name" ))!=NULL && n->text ) {
+ if (( hContact=JabberHContactFromJID( item->jid )) != NULL ) {
+ if (( p = _tcsstr( n->text, _T("Miranda IM"))) != NULL )
+ JSetStringT( hContact, "MirVer", p );
+ else
+ JSetStringT( hContact, "MirVer", n->text );
+ }
+ r->software = mir_tstrdup( n->text );
+ }
+ else r->software = NULL;
+ if ( r->version ) mir_free( r->version );
+ if (( n=JabberXmlGetChild( queryNode, "version" ))!=NULL && n->text )
+ r->version = mir_tstrdup( n->text );
+ else
+ r->version = NULL;
+ if ( r->system ) mir_free( r->system );
+ if (( n=JabberXmlGetChild( queryNode, "os" ))!=NULL && n->text )
+ r->system = mir_tstrdup( n->text );
+ else
+ r->system = NULL;
+}
+
+static void JabberProcessIq( XmlNode *node, void *userdata )
+{
+ struct ThreadData *info;
+ HANDLE hContact;
+ XmlNode *queryNode, *siNode, *n;
+ TCHAR* from, *type, *jid, *nick;
+ TCHAR* xmlns, *profile;
+ TCHAR* idStr, *str, *p, *q;
+ TCHAR text[256];
+ int id;
+ int i;
+ JABBER_IQ_PFUNC pfunc;
+
+ if ( !node->name || strcmp( node->name, "iq" )) return;
+ if (( info=( struct ThreadData * ) userdata ) == NULL ) return;
+ if (( type=JabberXmlGetAttrValue( node, "type" )) == NULL ) return;
+
+ id = -1;
+ if (( idStr=JabberXmlGetAttrValue( node, "id" )) != NULL )
+ if ( !_tcsncmp( idStr, _T(JABBER_IQID), strlen( JABBER_IQID )) )
+ id = _ttoi( idStr+strlen( JABBER_IQID ));
+
+ queryNode = JabberXmlGetChild( node, "query" );
+ xmlns = JabberXmlGetAttrValue( queryNode, "xmlns" );
+
+ /////////////////////////////////////////////////////////////////////////
+ // MATCH BY ID
+ /////////////////////////////////////////////////////////////////////////
+
+ if (( pfunc=JabberIqFetchFunc( id )) != NULL ) {
+ JabberLog( "Handling iq request for id=%d", id );
+ pfunc( node, userdata );
+ }
+
+ /////////////////////////////////////////////////////////////////////////
+ // MORE GENERAL ROUTINES, WHEN ID DOES NOT MATCH
+ /////////////////////////////////////////////////////////////////////////
+
+ else if (( pfunc=JabberIqFetchXmlnsFunc( xmlns )) != NULL ) {
+ JabberLog( "Handling iq request for xmlns = " TCHAR_STR_PARAM, xmlns );
+ pfunc( node, userdata );
+ }
+
+ // RECVED: <iq type='set'><query ...
+ else if ( !_tcscmp( type, _T("set")) && queryNode!=NULL && xmlns != NULL ) {
+
+ // RECVED: roster push
+ // ACTION: similar to iqIdGetRoster above
+ if ( !_tcscmp( xmlns, _T("jabber:iq:roster"))) {
+ XmlNode *itemNode, *groupNode;
+ JABBER_LIST_ITEM *item;
+ TCHAR* name;
+
+ JabberLog( "<iq/> Got roster push, query has %d children", queryNode->numChild );
+ for ( i=0; i<queryNode->numChild; i++ ) {
+ itemNode = queryNode->child[i];
+ if ( strcmp( itemNode->name, "item" ) != 0 )
+ continue;
+ if (( jid = JabberXmlGetAttrValue( itemNode, "jid" )) == NULL )
+ continue;
+ if (( str = JabberXmlGetAttrValue( itemNode, "subscription" )) == NULL )
+ continue;
+
+ // we will not add new account when subscription=remove
+ if ( !_tcscmp( str, _T("to")) || !_tcscmp( str, _T("both")) || !_tcscmp( str, _T("from")) || !_tcscmp( str, _T("none"))) {
+ if (( name=JabberXmlGetAttrValue( itemNode, "name" )) != NULL )
+ nick = mir_tstrdup( name );
+ else
+ nick = JabberNickFromJID( jid );
+
+ if ( nick != NULL ) {
+ if (( item=JabberListAdd( LIST_ROSTER, jid )) != NULL ) {
+ if ( item->nick ) mir_free( item->nick );
+ item->nick = nick;
+
+ if ( item->group ) mir_free( item->group );
+ if (( groupNode=JabberXmlGetChild( itemNode, "group" ))!=NULL && groupNode->text!=NULL )
+ item->group = mir_tstrdup( groupNode->text );
+ else
+ item->group = NULL;
+
+ if (( hContact=JabberHContactFromJID( jid )) == NULL ) {
+ // Received roster has a new JID.
+ // Add the jid ( with empty resource ) to Miranda contact list.
+ hContact = JabberDBCreateContact( jid, nick, FALSE, TRUE );
+ }
+ else JSetStringT( hContact, "jid", jid );
+
+ DBVARIANT dbnick;
+ if ( !JGetStringT( hContact, "Nick", &dbnick )) {
+ if ( _tcscmp( nick, dbnick.ptszVal ) != 0 )
+ DBWriteContactSettingTString( hContact, "CList", "MyHandle", nick );
+ else
+ DBDeleteContactSetting( hContact, "CList", "MyHandle" );
+ JFreeVariant( &dbnick );
+ }
+ else DBWriteContactSettingTString( hContact, "CList", "MyHandle", nick );
+
+ if ( item->group != NULL ) {
+ JabberContactListCreateGroup( item->group );
+ DBWriteContactSettingTString( hContact, "CList", "Group", item->group );
+ }
+ else DBDeleteContactSetting( hContact, "CList", "Group" );
+ }
+ else mir_free( nick );
+ } }
+
+ if (( item=JabberListGetItemPtr( LIST_ROSTER, jid )) != NULL ) {
+ if ( !_tcscmp( str, _T("both"))) item->subscription = SUB_BOTH;
+ else if ( !_tcscmp( str, _T("to"))) item->subscription = SUB_TO;
+ else if ( !_tcscmp( str, _T("from"))) item->subscription = SUB_FROM;
+ else item->subscription = SUB_NONE;
+ JabberLog( "Roster push for jid=" TCHAR_STR_PARAM ", set subscription to %s", jid, str );
+ // subscription = remove is to remove from roster list
+ // but we will just set the contact to offline and not actually
+ // remove, so that history will be retained.
+ if ( !_tcscmp( str, _T("remove"))) {
+ if (( hContact=JabberHContactFromJID( jid )) != NULL ) {
+ if ( JGetWord( hContact, "Status", ID_STATUS_OFFLINE ) != ID_STATUS_OFFLINE )
+ JSetWord( hContact, "Status", ID_STATUS_OFFLINE );
+ JabberListRemove( LIST_ROSTER, jid );
+ } }
+ else if ( JGetByte( hContact, "ChatRoom", 0 ))
+ DBDeleteContactSetting( hContact, "CList", "Hidden" );
+ } }
+
+ if ( hwndJabberAgents )
+ SendMessage( hwndJabberAgents, WM_JABBER_TRANSPORT_REFRESH, 0, 0 );
+ }
+
+ // RECVED: file transfer request
+ // ACTION: notify Miranda throuch CHAINRECV
+ else if ( !_tcscmp( xmlns, _T("jabber:iq:oob"))) {
+ if (( jid=JabberXmlGetAttrValue( node, "from" ))!=NULL && ( n=JabberXmlGetChild( queryNode, "url" ))!=NULL && n->text!=NULL ) {
+ str = n->text; // URL of the file to get
+ filetransfer* ft = new filetransfer;
+ ft->std.totalFiles = 1;
+ ft->jid = mir_tstrdup( jid );
+ ft->std.hContact = JabberHContactFromJID( jid );
+ ft->type = FT_OOB;
+ ft->httpHostName = NULL;
+ ft->httpPort = 80;
+ ft->httpPath = NULL;
+ // Parse the URL
+ if ( !_tcsnicmp( str, _T("http://"), 7 )) {
+ p = str + 7;
+ if (( q = _tcschr( p, '/' )) != NULL ) {
+ if ( q-p < SIZEOF( text )) {
+ _tcsncpy( text, p, q-p );
+ text[q-p] = '\0';
+ if (( p = _tcschr( text, ':' )) != NULL ) {
+ ft->httpPort = ( WORD )_ttoi( p+1 );
+ *p = '\0';
+ }
+ ft->httpHostName = t2a( text );
+ ft->httpPath = t2a( ++q );
+ } } }
+
+ if (( str=JabberXmlGetAttrValue( node, "id" )) != NULL )
+ ft->iqId = mir_tstrdup( str );
+
+ if ( ft->httpHostName && ft->httpPath ) {
+ CCSDATA ccs;
+ PROTORECVEVENT pre;
+ char* szBlob, *desc;
+
+ JabberLog( "Host=%s Port=%d Path=%s", ft->httpHostName, ft->httpPort, ft->httpPath );
+ if (( n=JabberXmlGetChild( queryNode, "desc" ))!=NULL && n->text!=NULL )
+ desc = t2a( n->text );
+ else
+ desc = mir_strdup( "" );
+
+ if ( desc != NULL ) {
+ char* str;
+ JabberLog( "description = %s", desc );
+ if (( str = strrchr( ft->httpPath, '/' )) != NULL )
+ str++;
+ else
+ str = ft->httpPath;
+ str = mir_strdup( str );
+ JabberHttpUrlDecode( str );
+ szBlob = ( char* )mir_alloc( sizeof( DWORD )+ strlen( str ) + strlen( desc ) + 2 );
+ *(( PDWORD ) szBlob ) = ( DWORD )ft;
+ strcpy( szBlob + sizeof( DWORD ), str );
+ strcpy( szBlob + sizeof( DWORD )+ strlen( str ) + 1, desc );
+ pre.flags = 0;
+ pre.timestamp = time( NULL );
+ pre.szMessage = szBlob;
+ pre.lParam = 0;
+ ccs.szProtoService = PSR_FILE;
+ ccs.hContact = ft->std.hContact;
+ ccs.wParam = 0;
+ ccs.lParam = ( LPARAM )⪯
+ JCallService( MS_PROTO_CHAINRECV, 0, ( LPARAM )&ccs );
+ mir_free( szBlob );
+ mir_free( str );
+ mir_free( desc );
+ }
+ }
+ else {
+ // reject
+ XmlNodeIq iq( "error", idStr, ft->jid );
+ XmlNode* e = iq.addChild( "error", "File transfer refused" ); e->addAttr( "code", 406 );
+ JabberSend( jabberThreadInfo->s, iq );
+ delete ft;
+ } } }
+
+ // RECVED: bytestream initiation request
+ // ACTION: check for any stream negotiation that is pending ( now only file transfer is handled )
+ else if ( !_tcscmp( xmlns, _T("http://jabber.org/protocol/bytestreams")))
+ JabberFtHandleBytestreamRequest( node );
+ }
+ // RECVED: <iq type='get'><query ...
+ else if ( !_tcscmp( type, _T("get")) && queryNode!=NULL && xmlns != NULL ) {
+
+ // RECVED: software version query
+ // ACTION: return my software version
+ if ( !_tcscmp( xmlns, _T("jabber:iq:version")))
+ JabberProcessIqVersion( idStr, node );
+ else if ( !_tcscmp( xmlns, _T("jabber:iq:avatar")))
+ JabberProcessIqAvatar( idStr, node );
+ else if ( !_tcscmp( xmlns, _T("jabber:iq:time")))
+ JabberProcessIqTime( idStr, node );
+ }
+ // RECVED: <iq type='result'><query ...
+ else if ( !_tcscmp( type, _T("result")) && queryNode != NULL && xmlns != NULL ) {
+
+ // RECVED: software version result
+ // ACTION: update version information for the specified jid/resource
+ if ( !_tcscmp( xmlns, _T("jabber:iq:version")))
+ JabberProcessIqResultVersion( type, node, queryNode );
+ }
+ // RECVED: <iq type='set'><si xmlns='http://jabber.org/protocol/si' ...
+ else if ( !_tcscmp( type, _T("set")) && ( siNode=JabberXmlGetChildWithGivenAttrValue( node, "si", "xmlns", _T("http://jabber.org/protocol/si")))!=NULL && ( profile=JabberXmlGetAttrValue( siNode, "profile" ))!=NULL ) {
+
+ // RECVED: file transfer request
+ // ACTION: notify Miranda throuch CHAINRECV
+ if ( !_tcscmp( profile, _T("http://jabber.org/protocol/si/profile/file-transfer" ))) {
+ JabberFtHandleSiRequest( node );
+ }
+ // RECVED: unknown profile
+ // ACTION: reply with bad-profile
+ else {
+ if (( from=JabberXmlGetAttrValue( node, "from" )) != NULL ) {
+ idStr = JabberXmlGetAttrValue( node, "id" );
+
+ XmlNodeIq iq( "error", idStr, from );
+ XmlNode* error = iq.addChild( "error" ); error->addAttr( "code", "400" ); error->addAttr( "type", "cancel" );
+ XmlNode* brq = error->addChild( "bad-request" ); brq->addAttr( "xmlns", "urn:ietf:params:xml:ns:xmpp-stanzas" );
+ XmlNode* bp = error->addChild( "bad-profile" ); brq->addAttr( "xmlns", "http://jabber.org/protocol/si" );
+ JabberSend( jabberThreadInfo->s, iq );
+ } }
+ }
+ // RECVED: <iq type='error'> ...
+ else if ( !_tcscmp( type, _T("error"))) {
+ if ( !lstrcmp( xmlns, _T("jabber:iq:version"))) {
+ JabberProcessIqResultVersion( type, node, queryNode );
+ return;
+ }
+ JabberLog( "XXX on entry" );
+ // Check for file transfer deny by comparing idStr with ft->iqId
+ i = 0;
+ while (( i=JabberListFindNext( LIST_FILE, i )) >= 0 ) {
+ JABBER_LIST_ITEM *item = JabberListGetItemPtrFromIndex( i );
+ if ( item->ft != NULL && item->ft->state == FT_CONNECTING && !_tcscmp( idStr, item->ft->iqId )) {
+ JabberLog( "Denying file sending request" );
+ item->ft->state = FT_DENIED;
+ if ( item->ft->hFileEvent != NULL )
+ SetEvent( item->ft->hFileEvent ); // Simulate the termination of file server connection
+ }
+ i++;
+} } }
+
+static void JabberProcessRegIq( XmlNode *node, void *userdata )
+{
+ struct ThreadData *info;
+ XmlNode *errorNode;
+ TCHAR *type, *str;
+
+ if ( !node->name || strcmp( node->name, "iq" )) return;
+ if (( info=( struct ThreadData * ) userdata ) == NULL ) return;
+ if (( type=JabberXmlGetAttrValue( node, "type" )) == NULL ) return;
+
+ unsigned int id = -1;
+ if (( str=JabberXmlGetAttrValue( node, "id" )) != NULL )
+ if ( !_tcsncmp( str, _T(JABBER_IQID), strlen( JABBER_IQID )) )
+ id = _ttoi( str + strlen( JABBER_IQID ));
+
+ if ( !_tcscmp( type, _T("result"))) {
+
+ // RECVED: result of the request for registration mechanism
+ // ACTION: send account registration information
+ if ( id == iqIdRegGetReg ) {
+ iqIdRegSetReg = JabberSerialNext();
+
+ XmlNodeIq iq( "set", iqIdRegSetReg );
+ XmlNode* query = iq.addQuery( "jabber:iq:register" );
+ query->addChild( "password", info->password );
+ query->addChild( "username", info->username );
+ JabberSend( info->s, iq );
+
+ SendMessage( info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 75, ( LPARAM )TranslateT( "Sending registration information..." ));
+ }
+ // RECVED: result of the registration process
+ // ACTION: account registration successful
+ else if ( id == iqIdRegSetReg ) {
+ JabberSend( info->s, "</stream:stream>" );
+ SendMessage( info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 100, ( LPARAM )TranslateT( "Registration successful" ));
+ info->reg_done = TRUE;
+ } }
+
+ else if ( !_tcscmp( type, _T("error"))) {
+ errorNode = JabberXmlGetChild( node, "error" );
+ str = JabberErrorMsg( errorNode );
+ SendMessage( info->reg_hwndDlg, WM_JABBER_REGDLG_UPDATE, 100, ( LPARAM )str );
+ mir_free( str );
+ info->reg_done = TRUE;
+ JabberSend( info->s, "</stream:stream>" );
+} }
+
+static void __cdecl JabberKeepAliveThread( JABBER_SOCKET s )
+{
+ NETLIBSELECT nls = {0};
+
+ nls.cbSize = sizeof( NETLIBSELECT );
+ nls.dwTimeout = 60000; // 60000 millisecond ( 1 minute )
+ nls.hExceptConns[0] = s;
+ for ( ;; ) {
+ if ( JCallService( MS_NETLIB_SELECT, 0, ( LPARAM )&nls ) != 0 )
+ break;
+ if ( jabberSendKeepAlive )
+ JabberSend( s, " \t " );
+ }
+ JabberLog( "Exiting KeepAliveThread" );
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_userinfo.cpp b/miranda-wine/protocols/JabberG/jabber_userinfo.cpp new file mode 100644 index 0000000..f792448 --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_userinfo.cpp @@ -0,0 +1,525 @@ +/*
+
+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_userinfo.cpp,v $
+Revision : $Revision: 3016 $
+Last change on : $Date: 2006-06-04 23:07:43 +0400 (Вск, 04 Июн 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+
+#include <commctrl.h>
+#include "jabber_list.h"
+#include "resource.h"
+#include "sha1.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberUserInfoDlgProc - main user info dialog
+
+static BOOL CALLBACK JabberUserInfoDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ // lParam is hContact
+ TranslateDialogDefault( hwndDlg );
+ SetWindowLong( hwndDlg, GWL_USERDATA, ( LONG )( HANDLE ) lParam );
+ SendMessage( hwndDlg, WM_JABBER_REFRESH, 0, 0 );
+ return TRUE;
+ case WM_JABBER_REFRESH:
+ {
+ DBVARIANT dbv;
+ JABBER_LIST_ITEM *item;
+ JABBER_RESOURCE_STATUS *r;
+
+ HWND hwndList = GetDlgItem( hwndDlg, IDC_INFO_RESOURCE );
+ SendMessage( hwndList, LB_RESETCONTENT, 0, 0 );
+ SetDlgItemTextA( hwndDlg, IDC_INFO_JID, "" );
+ SetDlgItemTextA( hwndDlg, IDC_SUBSCRIPTION, "" );
+ SetDlgItemText( hwndDlg, IDC_SOFTWARE, TranslateT( "<click resource to view>" ));
+ SetDlgItemText( hwndDlg, IDC_VERSION, TranslateT( "<click resource to view>" ));
+ SetDlgItemText( hwndDlg, IDC_SYSTEM, TranslateT( "<click resource to view>" ));
+ EnableWindow( GetDlgItem( hwndDlg, IDC_SOFTWARE ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_VERSION ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_SYSTEM ), FALSE );
+
+ HANDLE hContact = ( HANDLE ) GetWindowLong( hwndDlg, GWL_USERDATA );
+ if ( !JGetStringT( hContact, "jid", &dbv )) {
+ SetDlgItemText( hwndDlg, IDC_INFO_JID, dbv.ptszVal );
+
+ if ( jabberOnline ) {
+ if (( item=JabberListGetItemPtr( LIST_ROSTER, dbv.ptszVal )) != NULL ) {
+ if (( r=item->resource ) != NULL ) {
+ int count = item->resourceCount;
+ for ( int i=0; i<count; i++ ) {
+ int index = SendMessage( hwndList, LB_ADDSTRING, 0, ( LPARAM )r[i].resourceName );
+ SendMessage( hwndList, LB_SETITEMDATA, index, ( LPARAM )r[i].resourceName );
+ } }
+
+ switch ( item->subscription ) {
+ case SUB_BOTH:
+ SetDlgItemText( hwndDlg, IDC_SUBSCRIPTION, TranslateT( "both" ));
+ break;
+ case SUB_TO:
+ SetDlgItemText( hwndDlg, IDC_SUBSCRIPTION, TranslateT( "to" ));
+ break;
+ case SUB_FROM:
+ SetDlgItemText( hwndDlg, IDC_SUBSCRIPTION, TranslateT( "from" ));
+ break;
+ default:
+ SetDlgItemText( hwndDlg, IDC_SUBSCRIPTION, TranslateT( "none" ));
+ break;
+ } }
+ else SetDlgItemText( hwndDlg, IDC_SUBSCRIPTION, TranslateT( "none ( not on roster )" ));
+ }
+ else EnableWindow( hwndList, FALSE );
+ JFreeVariant( &dbv );
+ } }
+ break;
+ case WM_NOTIFY:
+ switch (( ( LPNMHDR )lParam )->idFrom ) {
+ case 0:
+ switch (( ( LPNMHDR )lParam )->code ) {
+ case PSN_INFOCHANGED:
+ {
+ HANDLE hContact = ( HANDLE ) (( LPPSHNOTIFY ) lParam )->lParam;
+ SendMessage( hwndDlg, WM_JABBER_REFRESH, 0, ( LPARAM )hContact );
+ }
+ break;
+ }
+ break;
+ }
+ break;
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDC_INFO_RESOURCE:
+ switch ( HIWORD( wParam )) {
+ case LBN_SELCHANGE:
+ {
+ HWND hwndList = GetDlgItem( hwndDlg, IDC_INFO_RESOURCE );
+ HANDLE hContact = ( HANDLE ) GetWindowLong( hwndDlg, GWL_USERDATA );
+
+ DBVARIANT dbv;
+ if ( !JGetStringT( hContact, "jid", &dbv )) {
+ TCHAR* jid = dbv.ptszVal;
+ int nItem = SendMessage( hwndList, LB_GETCURSEL, 0, 0 );
+ TCHAR* szResource = ( TCHAR* )SendMessage( hwndList, LB_GETITEMDATA, ( WPARAM ) nItem, 0 );
+ JABBER_LIST_ITEM* item = JabberListGetItemPtr( LIST_ROSTER, jid );
+ JABBER_RESOURCE_STATUS *r;
+
+ if ( szResource != ( TCHAR* )LB_ERR && item != NULL && ( r=item->resource ) != NULL ) {
+ int i;
+ for ( i=0; i < item->resourceCount && _tcscmp( r[i].resourceName, szResource ); i++ );
+ if ( i < item->resourceCount ) {
+ if ( r[i].software != NULL ) {
+ SetDlgItemText( hwndDlg, IDC_SOFTWARE, r[i].software );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_SOFTWARE ), TRUE );
+ }
+ else {
+ SetDlgItemText( hwndDlg, IDC_SOFTWARE, TranslateT( "<not specified>" ));
+ EnableWindow( GetDlgItem( hwndDlg, IDC_SOFTWARE ), FALSE );
+ }
+ if ( r[i].version != NULL ) {
+ SetDlgItemText( hwndDlg, IDC_VERSION, r[i].version );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_VERSION ), TRUE );
+ }
+ else {
+ SetDlgItemText( hwndDlg, IDC_VERSION, TranslateT( "<not specified>" ));
+ EnableWindow( GetDlgItem( hwndDlg, IDC_VERSION ), FALSE );
+ }
+ if ( r[i].system != NULL ) {
+ SetDlgItemText( hwndDlg, IDC_SYSTEM, r[i].system );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_SYSTEM ), TRUE );
+ }
+ else {
+ SetDlgItemText( hwndDlg, IDC_SYSTEM, TranslateT( "<not specified>" ));
+ EnableWindow( GetDlgItem( hwndDlg, IDC_SYSTEM ), FALSE );
+ } } }
+ JFreeVariant( &dbv );
+ } } }
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberUserPhotoDlgProc - Jabber photo dialog
+
+typedef struct {
+ HANDLE hContact;
+ HBITMAP hBitmap;
+} USER_PHOTO_INFO;
+
+static BOOL CALLBACK JabberUserPhotoDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ USER_PHOTO_INFO *photoInfo;
+
+ photoInfo = ( USER_PHOTO_INFO * ) GetWindowLong( hwndDlg, GWL_USERDATA );
+
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ // lParam is hContact
+ TranslateDialogDefault( hwndDlg );
+ photoInfo = ( USER_PHOTO_INFO * ) mir_alloc( sizeof( USER_PHOTO_INFO ));
+ photoInfo->hContact = ( HANDLE ) lParam;
+ photoInfo->hBitmap = NULL;
+ SetWindowLong( hwndDlg, GWL_USERDATA, ( LONG ) photoInfo );
+ SendMessage( GetDlgItem( hwndDlg, IDC_SAVE ), BM_SETIMAGE, IMAGE_ICON, ( LPARAM )LoadImage( hInst, MAKEINTRESOURCE( IDI_SAVE ), IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), 0 ));
+ ShowWindow( GetDlgItem( hwndDlg, IDC_LOAD ), SW_HIDE );
+ ShowWindow( GetDlgItem( hwndDlg, IDC_DELETE ), SW_HIDE );
+ SendMessage( hwndDlg, WM_JABBER_REFRESH, 0, 0 );
+ return TRUE;
+ case WM_NOTIFY:
+ switch (( ( LPNMHDR )lParam )->idFrom ) {
+ case 0:
+ switch (( ( LPNMHDR )lParam )->code ) {
+ case PSN_INFOCHANGED:
+ SendMessage( hwndDlg, WM_JABBER_REFRESH, 0, 0 );
+ break;
+ }
+ break;
+ }
+ break;
+ case WM_JABBER_REFRESH:
+ {
+ JABBER_LIST_ITEM *item;
+ DBVARIANT dbv;
+
+ if ( photoInfo->hBitmap ) {
+ DeleteObject( photoInfo->hBitmap );
+ photoInfo->hBitmap = NULL;
+ }
+ ShowWindow( GetDlgItem( hwndDlg, IDC_SAVE ), SW_HIDE );
+ if ( !JGetStringT( photoInfo->hContact, "jid", &dbv )) {
+ TCHAR* jid = dbv.ptszVal;
+ if (( item=JabberListGetItemPtr( LIST_ROSTER, jid )) != NULL ) {
+ if ( item->photoFileName ) {
+ JabberLog( "Showing picture from %s", item->photoFileName );
+ photoInfo->hBitmap = ( HBITMAP ) JCallService( MS_UTILS_LOADBITMAP, 0, ( LPARAM )item->photoFileName );
+ ShowWindow( GetDlgItem( hwndDlg, IDC_SAVE ), SW_SHOW );
+ }
+ }
+ JFreeVariant( &dbv );
+ }
+ InvalidateRect( hwndDlg, NULL, TRUE );
+ UpdateWindow( hwndDlg );
+ }
+ break;
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDC_SAVE:
+ {
+ DBVARIANT dbv;
+ JABBER_LIST_ITEM *item;
+ HANDLE hFile;
+ OPENFILENAMEA ofn;
+ static char szFilter[512];
+ unsigned char buffer[3];
+ char szFileName[_MAX_PATH];
+ DWORD n;
+
+ if ( JGetStringT( photoInfo->hContact, "jid", &dbv ))
+ break;
+
+ TCHAR* jid = dbv.ptszVal;
+ if (( item=JabberListGetItemPtr( LIST_ROSTER, jid )) != NULL ) {
+ if (( hFile=CreateFileA( item->photoFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL )) != INVALID_HANDLE_VALUE ) {
+ if ( ReadFile( hFile, buffer, 3, &n, NULL ) && n==3 ) {
+ if ( !strncmp(( char* )buffer, "BM", 2 )) {
+ mir_snprintf( szFilter, sizeof( szFilter ), "BMP %s ( *.bmp )", JTranslate( "format" ));
+ n = strlen( szFilter );
+ strncpy( szFilter+n+1, "*.BMP", sizeof( szFilter )-n-2 );
+ }
+ else if ( !strncmp(( char* )buffer, "GIF", 3 )) {
+ mir_snprintf( szFilter, sizeof( szFilter ), "GIF %s ( *.gif )", JTranslate( "format" ));
+ n = strlen( szFilter );
+ strncpy( szFilter+n+1, "*.GIF", sizeof( szFilter )-n-2 );
+ }
+ else if ( buffer[0]==0xff && buffer[1]==0xd8 && buffer[2]==0xff ) {
+ mir_snprintf( szFilter, sizeof( szFilter ), "JPEG %s ( *.jpg;*.jpeg )", JTranslate( "format" ));
+ n = strlen( szFilter );
+ strncpy( szFilter+n+1, "*.JPG;*.JPEG", sizeof( szFilter )-n-2 );
+ }
+ else {
+ mir_snprintf( szFilter, sizeof( szFilter ), "%s ( *.* )", JTranslate( "Unknown format" ));
+ n = strlen( szFilter );
+ strncpy( szFilter+n+1, "*.*", sizeof( szFilter )-n-2 );
+ }
+ szFilter[sizeof( szFilter )-1] = '\0';
+
+ ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
+ ofn.hwndOwner = hwndDlg;
+ ofn.hInstance = NULL;
+ ofn.lpstrFilter = szFilter;
+ ofn.lpstrCustomFilter = NULL;
+ ofn.nMaxCustFilter = 0;
+ ofn.nFilterIndex = 0;
+ ofn.lpstrFile = szFileName;
+ ofn.nMaxFile = _MAX_PATH;
+ ofn.lpstrFileTitle = NULL;
+ ofn.nMaxFileTitle = 0;
+ ofn.lpstrInitialDir = NULL;
+ ofn.lpstrTitle = NULL;
+ ofn.Flags = OFN_OVERWRITEPROMPT;
+ ofn.nFileOffset = 0;
+ ofn.nFileExtension = 0;
+ ofn.lpstrDefExt = NULL;
+ ofn.lCustData = 0L;
+ ofn.lpfnHook = NULL;
+ ofn.lpTemplateName = NULL;
+ szFileName[0] = '\0';
+ if ( GetSaveFileNameA( &ofn )) {
+ JabberLog( "File selected is %s", szFileName );
+ CopyFileA( item->photoFileName, szFileName, FALSE );
+ }
+ }
+ CloseHandle( hFile );
+ }
+ }
+ JFreeVariant( &dbv );
+
+ }
+ break;
+ }
+ break;
+ case WM_PAINT:
+ if ( !jabberOnline )
+ SetDlgItemText( hwndDlg, IDC_CANVAS, TranslateT( "<Photo not available while offline>" ));
+ else if ( !photoInfo->hBitmap )
+ SetDlgItemText( hwndDlg, IDC_CANVAS, TranslateT( "<No photo>" ));
+ else {
+ BITMAP bm;
+ POINT ptSize, ptOrg, pt, ptFitSize;
+ RECT rect;
+
+ SetDlgItemTextA( hwndDlg, IDC_CANVAS, "" );
+ HBITMAP hBitmap = photoInfo->hBitmap;
+ HWND hwndCanvas = GetDlgItem( hwndDlg, IDC_CANVAS );
+ HDC hdcCanvas = GetDC( hwndCanvas );
+ HDC hdcMem = CreateCompatibleDC( hdcCanvas );
+ SelectObject( hdcMem, hBitmap );
+ SetMapMode( hdcMem, GetMapMode( hdcCanvas ));
+ GetObject( hBitmap, sizeof( BITMAP ), ( LPVOID ) &bm );
+ ptSize.x = bm.bmWidth;
+ ptSize.y = bm.bmHeight;
+ DPtoLP( hdcCanvas, &ptSize, 1 );
+ ptOrg.x = ptOrg.y = 0;
+ DPtoLP( hdcMem, &ptOrg, 1 );
+ GetClientRect( hwndCanvas, &rect );
+ InvalidateRect( hwndCanvas, NULL, TRUE );
+ UpdateWindow( hwndCanvas );
+ if ( ptSize.x<=rect.right && ptSize.y<=rect.bottom ) {
+ pt.x = ( rect.right - ptSize.x )/2;
+ pt.y = ( rect.bottom - ptSize.y )/2;
+ BitBlt( hdcCanvas, pt.x, pt.y, ptSize.x, ptSize.y, hdcMem, ptOrg.x, ptOrg.y, SRCCOPY );
+ }
+ else {
+ if (( ( float )( ptSize.x-rect.right ))/ptSize.x > (( float )( ptSize.y-rect.bottom ))/ptSize.y ) {
+ ptFitSize.x = rect.right;
+ ptFitSize.y = ( ptSize.y*rect.right )/ptSize.x;
+ pt.x = 0;
+ pt.y = ( rect.bottom - ptFitSize.y )/2;
+ }
+ else {
+ ptFitSize.x = ( ptSize.x*rect.bottom )/ptSize.y;
+ ptFitSize.y = rect.bottom;
+ pt.x = ( rect.right - ptFitSize.x )/2;
+ pt.y = 0;
+ }
+ SetStretchBltMode( hdcCanvas, COLORONCOLOR );
+ StretchBlt( hdcCanvas, pt.x, pt.y, ptFitSize.x, ptFitSize.y, hdcMem, ptOrg.x, ptOrg.y, ptSize.x, ptSize.y, SRCCOPY );
+ }
+ DeleteDC( hdcMem );
+ }
+ break;
+ case WM_DESTROY:
+ if ( photoInfo->hBitmap ) {
+ JabberLog( "Delete bitmap" );
+ DeleteObject( photoInfo->hBitmap );
+ }
+ if ( photoInfo ) mir_free( photoInfo );
+ break;
+ }
+ return FALSE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberSetAvatarDlgProc - avatar options dialog procedure
+
+static HBITMAP hAvatar;
+static char szFileName[ MAX_PATH ];
+
+static void sttSaveAvatar()
+{
+ char tFileName[ MAX_PATH ];
+ JabberGetAvatarFileName( NULL, tFileName, sizeof tFileName );
+
+ if ( CopyFileA( szFileName, tFileName, FALSE ) == FALSE ) {
+ JabberLog( "Copy failed with error %d", GetLastError() );
+ return;
+ }
+
+ SHA1Context ctx;
+ uint8_t digest[20];
+ SHA1Reset( &ctx );
+
+ FILE* in = fopen( tFileName, "rb" );
+ if ( in == NULL )
+ return;
+
+ char buf[ 512 ];
+ bool bIsFirst = true;
+ int pictureType;
+ while( !feof( in )) {
+ int bytes = fread( buf, 1, sizeof buf, in );
+ if ( bIsFirst ) {
+ pictureType = JabberGetPictureType( buf );
+ bIsFirst = false;
+ }
+ SHA1Input( &ctx, ( const unsigned __int8* )buf, bytes );
+ }
+ fclose( in );
+
+ if ( pictureType == PA_FORMAT_UNKNOWN )
+ return;
+
+ SHA1Result( &ctx, digest );
+ for ( int i=0; i<20; i++ )
+ sprintf( buf+( i<<1 ), "%02x", digest[i] );
+ JSetString( NULL, "AvatarHash", buf );
+ JSetByte( "AvatarType", pictureType );
+
+ JabberGetAvatarFileName( NULL, szFileName, MAX_PATH );
+ if ( strcmp( szFileName, tFileName ))
+ MoveFileA( tFileName, szFileName );
+}
+
+static BOOL CALLBACK JabberSetAvatarDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwndDlg );
+ {
+ hAvatar = NULL;
+ szFileName[0] = 0;
+
+ BOOL tValue = JGetByte( "EnableAvatars", 1 );
+ CheckDlgButton( hwndDlg, IDC_ENABLE_AVATARS, tValue );
+ if ( tValue ) {
+ char szAvatar[ MAX_PATH ];
+ JabberGetAvatarFileName( NULL, szAvatar, sizeof szAvatar );
+ hAvatar = (HBITMAP)CallService(MS_UTILS_LOADBITMAP, 0, (WPARAM)szAvatar );
+ if ( hAvatar )
+ SendDlgItemMessage(hwndDlg, IDC_AVATAR, STM_SETIMAGE, IMAGE_BITMAP, (WPARAM)hAvatar );
+ } }
+
+ return TRUE;
+
+ case WM_COMMAND:
+ if ( HIWORD( wParam ) == BN_CLICKED )
+ switch( LOWORD( wParam )) {
+ case IDC_SETAVATAR:
+ if ( JabberEnterBitmapName( szFileName ) == ERROR_SUCCESS ) {
+ HBITMAP hBitmap = (HBITMAP)CallService(MS_UTILS_LOADBITMAP, 0, (WPARAM)szFileName );
+ if ( hBitmap != NULL ) {
+ hAvatar = hBitmap;
+ hBitmap = ( HBITMAP )SendDlgItemMessage(hwndDlg, IDC_AVATAR, STM_SETIMAGE, IMAGE_BITMAP, (WPARAM)hBitmap );
+ if ( hBitmap )
+ DeleteObject( hBitmap );
+
+ sttSaveAvatar();
+ if ( jabberConnected )
+ JabberSendPresence( jabberDesiredStatus );
+ RedrawWindow(GetDlgItem(hwndDlg, IDC_AVATAR), NULL, NULL, RDW_INVALIDATE);
+ } }
+ break;
+
+ case IDC_DELETEAVATAR:
+ char tFileName[ MAX_PATH ];
+ JabberGetAvatarFileName( NULL, tFileName, sizeof tFileName );
+ DeleteFileA( tFileName );
+ JDeleteSetting( NULL, "AvatarHash" );
+ JDeleteSetting( NULL, "AvatarType" );
+
+ DeleteObject( hAvatar ); hAvatar = NULL;
+ HBITMAP hBitmap = (HBITMAP)SendDlgItemMessage(hwndDlg, IDC_AVATAR, STM_SETIMAGE, IMAGE_BITMAP, (WPARAM)NULL );
+ if ( hBitmap )
+ DeleteObject( hBitmap );
+
+ if ( jabberConnected )
+ JabberSendPresence( jabberDesiredStatus );
+ break;
+ }
+ break;
+
+ case WM_DESTROY:
+ if ( hAvatar )
+ DeleteObject( hAvatar );
+ }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberUserInfoInit - initializes user info option dialogs
+
+int JabberUserInfoInit( WPARAM wParam, LPARAM lParam )
+{
+ if ( !JCallService( MS_PROTO_ISPROTOCOLLOADED, 0, ( LPARAM )jabberProtoName ))
+ return 0;
+
+ OPTIONSDIALOGPAGE odp = {0};
+ odp.cbSize = sizeof( odp );
+ odp.hInstance = hInst;
+
+ HANDLE hContact = ( HANDLE )lParam;
+ if ( hContact == NULL ) {
+ if ( JGetByte( "EnableAvatars", TRUE )) {
+ char szTitle[256];
+ mir_snprintf( szTitle, sizeof( szTitle ), "%s %s", jabberProtoName, JTranslate( "Avatar" ));
+
+ odp.pfnDlgProc = JabberSetAvatarDlgProc;
+ odp.position = 2000000001;
+ odp.pszTemplate = MAKEINTRESOURCEA( IDD_OPT_SETAVATAR );
+ odp.pszTitle = szTitle;
+ JCallService( MS_USERINFO_ADDPAGE, wParam, ( LPARAM )&odp );
+ }
+ return 0;
+ }
+
+ char* szProto = ( char* )JCallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 );
+ if ( szProto != NULL && !strcmp( szProto, jabberProtoName )) {
+ odp.pfnDlgProc = JabberUserInfoDlgProc;
+ odp.position = -2000000000;
+ odp.pszTemplate = MAKEINTRESOURCEA( IDD_INFO_JABBER );
+ odp.pszTitle = jabberModuleName;
+ JCallService( MS_USERINFO_ADDPAGE, wParam, ( LPARAM )&odp );
+
+ odp.pfnDlgProc = JabberUserPhotoDlgProc;
+ odp.position = 2000000000;
+ odp.pszTemplate = MAKEINTRESOURCEA( IDD_VCARD_PHOTO );
+ odp.pszTitle = JTranslate( "Photo" );
+ JCallService( MS_USERINFO_ADDPAGE, wParam, ( LPARAM )&odp );
+ }
+ return 0;
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_util.cpp b/miranda-wine/protocols/JabberG/jabber_util.cpp new file mode 100644 index 0000000..d725f98 --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_util.cpp @@ -0,0 +1,1133 @@ +/*
+
+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_util.cpp,v $
+Revision : $Revision: 3667 $
+Last change on : $Date: 2006-08-31 18:10:18 +0400 (Чтв, 31 Авг 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+#include "jabber_ssl.h"
+#include "jabber_list.h"
+#include "sha1.h"
+
+extern CRITICAL_SECTION mutex;
+extern UINT jabberCodePage;
+
+static CRITICAL_SECTION serialMutex;
+static unsigned int serial;
+
+void __stdcall JabberSerialInit( void )
+{
+ InitializeCriticalSection( &serialMutex );
+ serial = 0;
+}
+
+void __stdcall JabberSerialUninit( void )
+{
+ DeleteCriticalSection( &serialMutex );
+}
+
+unsigned int __stdcall JabberSerialNext( void )
+{
+ unsigned int ret;
+
+ EnterCriticalSection( &serialMutex );
+ ret = serial;
+ serial++;
+ LeaveCriticalSection( &serialMutex );
+ return ret;
+}
+
+void __stdcall JabberLog( const char* fmt, ... )
+{
+ va_list vararg;
+ va_start( vararg, fmt );
+ char* str = ( char* )alloca( 32000 );
+ mir_vsnprintf( str, 32000, fmt, vararg );
+ va_end( vararg );
+
+ JCallService( MS_NETLIB_LOG, ( WPARAM )hNetlibUser, ( LPARAM )str );
+}
+
+// Caution: DO NOT use JabberSend() to send binary ( non-string ) data
+int __stdcall JabberSend( HANDLE hConn, XmlNode& node )
+{
+ char* str = node.getText();
+ int size = strlen( str ), result;
+
+ EnterCriticalSection( &mutex );
+
+ PVOID ssl;
+ if (( ssl=JabberSslHandleToSsl( hConn )) != NULL ) {
+ if ( DBGetContactSettingByte( NULL, "Netlib", "DumpSent", TRUE ) == TRUE ) {
+ char* szLogBuffer = ( char* )alloca( size+32 );
+ strcpy( szLogBuffer, "( SSL ) Data sent\n" );
+ memcpy( szLogBuffer+strlen( szLogBuffer ), str, size+1 ); // also copy \0
+ Netlib_Logf( hNetlibUser, "%s", szLogBuffer ); // %s to protect against when fmt tokens are in szLogBuffer causing crash
+ }
+
+ result = pfn_SSL_write( ssl, str, size );
+ }
+ else result = JabberWsSend( hConn, str, size );
+ LeaveCriticalSection( &mutex );
+
+ mir_free( str );
+ return result;
+}
+
+int __stdcall JabberSend( HANDLE hConn, const char* fmt, ... )
+{
+ int result;
+
+ EnterCriticalSection( &mutex );
+
+ va_list vararg;
+ va_start( vararg,fmt );
+ int size = 512;
+ char* str = ( char* )mir_alloc( size );
+ while ( _vsnprintf( str, size, fmt, vararg ) == -1 ) {
+ size += 512;
+ str = ( char* )mir_realloc( str, size );
+ }
+ va_end( vararg );
+
+ size = strlen( str );
+ PVOID ssl;
+ if (( ssl=JabberSslHandleToSsl( hConn )) != NULL ) {
+ if ( DBGetContactSettingByte( NULL, "Netlib", "DumpSent", TRUE ) == TRUE ) {
+ char* szLogBuffer = ( char* )alloca( size+32 );
+ strcpy( szLogBuffer, "( SSL ) Data sent\n" );
+ memcpy( szLogBuffer+strlen( szLogBuffer ), str, size+1 ); // also copy \0
+ Netlib_Logf( hNetlibUser, "%s", szLogBuffer ); // %s to protect against when fmt tokens are in szLogBuffer causing crash
+ }
+
+ result = pfn_SSL_write( ssl, str, size );
+ }
+ else result = JabberWsSend( hConn, str, size );
+ LeaveCriticalSection( &mutex );
+
+ mir_free( str );
+ return result;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// JabberHContactFromJID - looks for the HCONTACT with required JID
+
+HANDLE __stdcall JabberHContactFromJID( const TCHAR* jid )
+{
+ if ( jid == NULL )
+ return ( HANDLE )NULL;
+
+ JABBER_LIST_ITEM* item = JabberListGetItemPtr( LIST_CHATROOM, jid );
+
+ HANDLE hContactMatched = NULL;
+ HANDLE hContact = ( HANDLE ) JCallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ while ( hContact != NULL ) {
+ char* szProto = ( char* )JCallService( MS_PROTO_GETCONTACTBASEPROTO, ( WPARAM ) hContact, 0 );
+ if ( szProto != NULL && !strcmp( jabberProtoName, szProto )) {
+ DBVARIANT dbv;
+ int result = JGetStringT( hContact, "jid", &dbv );
+ if ( result )
+ result = JGetStringT( hContact, "ChatRoomID", &dbv );
+
+ if ( !result ) {
+ int result;
+ if ( item != NULL )
+ result = lstrcmpi( jid, dbv.ptszVal );
+ else
+ result = JabberCompareJids( jid, dbv.ptszVal );
+ JFreeVariant( &dbv );
+ if ( !result ) {
+ hContactMatched = hContact;
+ break;
+ } } }
+
+ hContact = ( HANDLE ) JCallService( MS_DB_CONTACT_FINDNEXT, ( WPARAM ) hContact, 0 );
+ }
+
+ return hContactMatched;
+}
+
+TCHAR* __stdcall JabberNickFromJID( const TCHAR* jid )
+{
+ const TCHAR* p;
+ TCHAR* nick;
+
+ if (( p = _tcschr( jid, '@' )) == NULL )
+ p = _tcschr( jid, '/' );
+
+ if ( p != NULL ) {
+ if (( nick=( TCHAR* )mir_alloc( sizeof(TCHAR)*( int( p-jid )+1 ))) != NULL ) {
+ _tcsncpy( nick, jid, p-jid );
+ nick[p-jid] = '\0';
+ }
+ }
+ else nick = mir_tstrdup( jid );
+ return nick;
+}
+
+char* __stdcall JabberUrlDecode( char* str )
+{
+ char* p, *q;
+
+ if ( str == NULL )
+ return NULL;
+
+ for ( p=q=str; *p!='\0'; p++,q++ ) {
+ if ( *p == '&' ) {
+ if ( !strncmp( p, "&", 5 )) { *q = '&'; p += 4; }
+ else if ( !strncmp( p, "'", 6 )) { *q = '\''; p += 5; }
+ else if ( !strncmp( p, ">", 4 )) { *q = '>'; p += 3; }
+ else if ( !strncmp( p, "<", 4 )) { *q = '<'; p += 3; }
+ else if ( !strncmp( p, """, 6 )) { *q = '"'; p += 5; }
+ else { *q = *p; }
+ }
+ else {
+ *q = *p;
+ }
+ }
+ *q = '\0';
+ return str;
+}
+
+void __stdcall JabberUrlDecodeW( WCHAR* str )
+{
+ if ( str == NULL )
+ return;
+
+ WCHAR* p, *q;
+ for ( p=q=str; *p!='\0'; p++,q++ ) {
+ if ( *p == '&' ) {
+ if ( !wcsncmp( p, L"&", 5 )) { *q = '&'; p += 4; }
+ else if ( !wcsncmp( p, L"'", 6 )) { *q = '\''; p += 5; }
+ else if ( !wcsncmp( p, L">", 4 )) { *q = '>'; p += 3; }
+ else if ( !wcsncmp( p, L"<", 4 )) { *q = '<'; p += 3; }
+ else if ( !wcsncmp( p, L""", 6 )) { *q = '"'; p += 5; }
+ else { *q = *p; }
+ }
+ else {
+ *q = *p;
+ }
+ }
+ *q = '\0';
+}
+
+char* __stdcall JabberUrlEncode( const char* str )
+{
+ char* s, *p, *q;
+ int c;
+
+ if ( str == NULL )
+ return NULL;
+
+ for ( c=0,p=( char* )str; *p!='\0'; p++ ) {
+ switch ( *p ) {
+ case '&': c += 5; break;
+ case '\'': c += 6; break;
+ case '>': c += 4; break;
+ case '<': c += 4; break;
+ case '"': c += 6; break;
+ default: c++; break;
+ }
+ }
+ if (( s=( char* )mir_alloc( c+1 )) != NULL ) {
+ for ( p=( char* )str,q=s; *p!='\0'; p++ ) {
+ switch ( *p ) {
+ case '&': strcpy( q, "&" ); q += 5; break;
+ case '\'': strcpy( q, "'" ); q += 6; break;
+ case '>': strcpy( q, ">" ); q += 4; break;
+ case '<': strcpy( q, "<" ); q += 4; break;
+ case '"': strcpy( q, """ ); q += 6; break;
+ default: *q = *p; q++; break;
+ }
+ }
+ *q = '\0';
+ }
+
+ return s;
+}
+
+static void __stdcall sttUtf8Decode( const BYTE* str, wchar_t* tempBuf )
+{
+ wchar_t* d = tempBuf;
+ BYTE* s = ( BYTE* )str;
+
+ while( *s )
+ {
+ if (( *s & 0x80 ) == 0 ) {
+ *d++ = *s++;
+ continue;
+ }
+
+ if (( s[0] & 0xE0 ) == 0xE0 && ( s[1] & 0xC0 ) == 0x80 && ( s[2] & 0xC0 ) == 0x80 ) {
+ *d++ = (( WORD )( s[0] & 0x0F ) << 12 ) + ( WORD )(( s[1] & 0x3F ) << 6 ) + ( WORD )( s[2] & 0x3F );
+ s += 3;
+ continue;
+ }
+
+ if (( s[0] & 0xE0 ) == 0xC0 && ( s[1] & 0xC0 ) == 0x80 ) {
+ *d++ = ( WORD )(( s[0] & 0x1F ) << 6 ) + ( WORD )( s[1] & 0x3F );
+ s += 2;
+ continue;
+ }
+
+ *d++ = *s++;
+ }
+
+ *d = 0;
+}
+
+
+char* __stdcall JabberUtf8Decode( char* str, WCHAR** ucs2 )
+{
+ if ( str == NULL )
+ return NULL;
+
+ int len = strlen( str );
+ if ( len < 2 ) {
+ if ( ucs2 != NULL ) {
+ *ucs2 = ( wchar_t* )mir_alloc(( len+1 )*sizeof( wchar_t ));
+ MultiByteToWideChar( CP_ACP, 0, str, len, *ucs2, len );
+ ( *ucs2 )[ len ] = 0;
+ }
+ return str;
+ }
+
+ wchar_t* tempBuf = ( wchar_t* )alloca(( len+1 )*sizeof( wchar_t ));
+ sttUtf8Decode(( BYTE* )str, tempBuf );
+
+ if ( ucs2 != NULL ) {
+ int fullLen = ( len+1 )*sizeof( wchar_t );
+ *ucs2 = ( wchar_t* )mir_alloc( fullLen );
+ memcpy( *ucs2, tempBuf, fullLen );
+ }
+
+ WideCharToMultiByte( CP_ACP, 0, tempBuf, -1, str, len, NULL, NULL );
+ return str;
+}
+
+char* __stdcall JabberUtf8EncodeW( const WCHAR* wstr )
+{
+ const WCHAR* w;
+
+ // Convert unicode to utf8
+ int len = 0;
+ for ( w = wstr; *w; w++ ) {
+ if ( *w < 0x0080 ) len++;
+ else if ( *w < 0x0800 ) len += 2;
+ else len += 3;
+ }
+
+ unsigned char* szOut = ( unsigned char* )mir_alloc( len+1 );
+ if ( szOut == NULL )
+ return NULL;
+
+ int i = 0;
+ for ( w = wstr; *w; w++ ) {
+ if ( *w < 0x0080 )
+ szOut[i++] = ( unsigned char ) *w;
+ else if ( *w < 0x0800 ) {
+ szOut[i++] = 0xc0 | (( *w ) >> 6 );
+ szOut[i++] = 0x80 | (( *w ) & 0x3f );
+ }
+ else {
+ szOut[i++] = 0xe0 | (( *w ) >> 12 );
+ szOut[i++] = 0x80 | (( ( *w ) >> 6 ) & 0x3f );
+ szOut[i++] = 0x80 | (( *w ) & 0x3f );
+ } }
+
+ szOut[ i ] = '\0';
+ return ( char* )szOut;
+}
+
+void __stdcall JabberUtfToTchar( const char* pszValue, size_t cbLen, LPTSTR& dest )
+{
+ char* pszCopy = ( char* )alloca( cbLen+1 );
+ memcpy( pszCopy, pszValue, cbLen );
+ pszCopy[ cbLen ] = 0;
+
+ JabberUrlDecode( pszCopy );
+
+ #if defined( _UNICODE )
+ JabberUtf8Decode( pszCopy, &dest );
+ #else
+ JabberUtf8Decode( pszCopy, NULL );
+ dest = mir_strdup( pszCopy );
+ #endif
+}
+
+char* __stdcall JabberUtf8Encode( const char* str )
+{
+ if ( str == NULL )
+ return NULL;
+
+ // Convert local codepage to unicode
+ int len = strlen( str );
+ WCHAR* wszTemp = ( WCHAR* )alloca( sizeof( WCHAR )*( len+1 ));
+ MultiByteToWideChar( jabberCodePage, 0, str, -1, wszTemp, len+1 );
+
+ return JabberUtf8EncodeW( wszTemp );
+}
+
+char* __stdcall JabberSha1( char* str )
+{
+ SHA1Context sha;
+ uint8_t digest[20];
+ char* result;
+ int i;
+
+ if ( str == NULL )
+ return NULL;
+
+ SHA1Reset( &sha );
+ SHA1Input( &sha, ( const unsigned __int8* )str, strlen( str ));
+ SHA1Result( &sha, digest );
+ if (( result=( char* )mir_alloc( 41 )) == NULL )
+ return NULL;
+
+ for ( i=0; i<20; i++ )
+ sprintf( result+( i<<1 ), "%02x", digest[i] );
+ return result;
+}
+
+char* __stdcall JabberUnixToDos( const char* str )
+{
+ char* p, *q, *res;
+ int extra;
+
+ if ( str==NULL || str[0]=='\0' )
+ return NULL;
+
+ extra = 0;
+ for ( p=( char* )str; *p!='\0'; p++ ) {
+ if ( *p == '\n' )
+ extra++;
+ }
+ if (( res=( char* )mir_alloc( strlen( str )+extra+1 )) != NULL ) {
+ for ( p=( char* )str,q=res; *p!='\0'; p++,q++ ) {
+ if ( *p == '\n' ) {
+ *q = '\r';
+ q++;
+ }
+ *q = *p;
+ }
+ *q = '\0';
+ }
+ return res;
+}
+
+WCHAR* __stdcall JabberUnixToDosW( const WCHAR* str )
+{
+ if ( str==NULL || str[0]=='\0' )
+ return NULL;
+
+ const WCHAR* p;
+ WCHAR* q, *res;
+ int extra = 0;
+
+ for ( p = str; *p!='\0'; p++ ) {
+ if ( *p == '\n' )
+ extra++;
+ }
+ if (( res = ( WCHAR* )mir_alloc( sizeof( WCHAR )*( wcslen( str ) + extra + 1 )) ) != NULL ) {
+ for ( p = str,q=res; *p!='\0'; p++,q++ ) {
+ if ( *p == '\n' ) {
+ *q = '\r';
+ q++;
+ }
+ *q = *p;
+ }
+ *q = '\0';
+ }
+ return res;
+}
+
+char* __stdcall JabberHttpUrlEncode( const char* str )
+{
+ unsigned char* p, *q, *res;
+
+ if ( str == NULL ) return NULL;
+ res = ( BYTE* ) mir_alloc( 3*strlen( str ) + 1 );
+ for ( p=( BYTE* )str,q=res; *p!='\0'; p++,q++ ) {
+ if (( *p>='A' && *p<='Z' ) || ( *p>='a' && *p<='z' ) || ( *p>='0' && *p<='9' ) || strchr( "$-_.+!*'(),", *p )!=NULL ) {
+ *q = *p;
+ }
+ else {
+ sprintf(( char* )q, "%%%02X", *p );
+ q += 2;
+ }
+ }
+ *q = '\0';
+ return ( char* )res;
+}
+
+void __stdcall JabberHttpUrlDecode( char* str )
+{
+ unsigned char* p, *q;
+ unsigned int code;
+
+ if ( str == NULL ) return;
+ for ( p=q=( BYTE* )str; *p!='\0'; p++,q++ ) {
+ if ( *p=='%' && *( p+1 )!='\0' && isxdigit( *( p+1 )) && *( p+2 )!='\0' && isxdigit( *( p+2 )) ) {
+ sscanf(( char* )p+1, "%2x", &code );
+ *q = ( unsigned char ) code;
+ p += 2;
+ }
+ else {
+ *q = *p;
+ } }
+
+ *q = '\0';
+}
+
+int __stdcall JabberCombineStatus( int status1, int status2 )
+{
+ // Combine according to the following priority ( high to low )
+ // ID_STATUS_FREECHAT
+ // ID_STATUS_ONLINE
+ // ID_STATUS_DND
+ // ID_STATUS_AWAY
+ // ID_STATUS_NA
+ // ID_STATUS_INVISIBLE ( valid only for TLEN_PLUGIN )
+ // ID_STATUS_OFFLINE
+ // other ID_STATUS in random order ( actually return status1 )
+ if ( status1==ID_STATUS_FREECHAT || status2==ID_STATUS_FREECHAT )
+ return ID_STATUS_FREECHAT;
+ if ( status1==ID_STATUS_ONLINE || status2==ID_STATUS_ONLINE )
+ return ID_STATUS_ONLINE;
+ if ( status1==ID_STATUS_DND || status2==ID_STATUS_DND )
+ return ID_STATUS_DND;
+ if ( status1==ID_STATUS_AWAY || status2==ID_STATUS_AWAY )
+ return ID_STATUS_AWAY;
+ if ( status1==ID_STATUS_NA || status2==ID_STATUS_NA )
+ return ID_STATUS_NA;
+ if ( status1==ID_STATUS_INVISIBLE || status2==ID_STATUS_INVISIBLE )
+ return ID_STATUS_INVISIBLE;
+ if ( status1==ID_STATUS_OFFLINE || status2==ID_STATUS_OFFLINE )
+ return ID_STATUS_OFFLINE;
+ return status1;
+}
+
+struct tagErrorCodeToStr {
+ int code;
+ TCHAR* str;
+}
+static JabberErrorCodeToStrMapping[] = {
+ { JABBER_ERROR_REDIRECT, _T("Redirect") },
+ { JABBER_ERROR_BAD_REQUEST, _T("Bad request") },
+ { JABBER_ERROR_UNAUTHORIZED, _T("Unauthorized") },
+ { JABBER_ERROR_PAYMENT_REQUIRED, _T("Payment required") },
+ { JABBER_ERROR_FORBIDDEN, _T("Forbidden") },
+ { JABBER_ERROR_NOT_FOUND, _T("Not found") },
+ { JABBER_ERROR_NOT_ALLOWED, _T("Not allowed") },
+ { JABBER_ERROR_NOT_ACCEPTABLE, _T("Not acceptable") },
+ { JABBER_ERROR_REGISTRATION_REQUIRED, _T("Registration required") },
+ { JABBER_ERROR_REQUEST_TIMEOUT, _T("Request timeout") },
+ { JABBER_ERROR_CONFLICT, _T("Conflict") },
+ { JABBER_ERROR_INTERNAL_SERVER_ERROR, _T("Internal server error") },
+ { JABBER_ERROR_NOT_IMPLEMENTED, _T("Not implemented") },
+ { JABBER_ERROR_REMOTE_SERVER_ERROR, _T("Remote server error") },
+ { JABBER_ERROR_SERVICE_UNAVAILABLE, _T("Service unavailable") },
+ { JABBER_ERROR_REMOTE_SERVER_TIMEOUT, _T("Remote server timeout") },
+ { -1, _T("Unknown error") }
+};
+
+TCHAR* __stdcall JabberErrorStr( int errorCode )
+{
+ int i;
+
+ for ( i=0; JabberErrorCodeToStrMapping[i].code!=-1 && JabberErrorCodeToStrMapping[i].code!=errorCode; i++ );
+ return JabberErrorCodeToStrMapping[i].str;
+}
+
+TCHAR* __stdcall JabberErrorMsg( XmlNode *errorNode )
+{
+ TCHAR* errorStr, *str;
+ int errorCode;
+
+ errorStr = ( TCHAR* )mir_alloc( 256 * sizeof( TCHAR ));
+ if ( errorNode == NULL ) {
+ mir_sntprintf( errorStr, 256, _T("%s -1: %s"), TranslateT( "Error" ), TranslateT( "Unknown error message" ));
+ return errorStr;
+ }
+
+ errorCode = -1;
+ if (( str=JabberXmlGetAttrValue( errorNode, "code" )) != NULL )
+ errorCode = _ttoi( str );
+ if (( str=errorNode->text ) != NULL )
+ mir_sntprintf( errorStr, 256, _T("%s %d: %s\r\n%s"), TranslateT( "Error" ), errorCode, TranslateTS( JabberErrorStr( errorCode )), str );
+ else
+ mir_sntprintf( errorStr, 256, _T("%s %d: %s"), TranslateT( "Error" ), errorCode, TranslateTS( JabberErrorStr( errorCode )) );
+ return errorStr;
+}
+
+void __stdcall JabberSendVisibleInvisiblePresence( BOOL invisible )
+{
+ if ( !jabberOnline ) return;
+
+ for ( int i = 0; ( i=JabberListFindNext( LIST_ROSTER, i )) >= 0; i++ ) {
+ JABBER_LIST_ITEM *item = JabberListGetItemPtrFromIndex( i );
+ if ( item == NULL )
+ continue;
+
+ HANDLE hContact = JabberHContactFromJID( item->jid );
+ if ( hContact == NULL )
+ continue;
+
+ WORD apparentMode = JGetWord( hContact, "ApparentMode", 0 );
+ if ( invisible==TRUE && apparentMode==ID_STATUS_OFFLINE ) {
+ XmlNode p( "presence" ); p.addAttr( "to", item->jid ); p.addAttr( "type", "invisible" );
+ JabberSend( jabberThreadInfo->s, p );
+ }
+ else if ( invisible==FALSE && apparentMode==ID_STATUS_ONLINE )
+ JabberSendPresenceTo( jabberStatus, item->jid, NULL );
+} }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberTextEncodeW - prepare a string for transmission
+
+char* __stdcall JabberTextEncode( const char* str )
+{
+ if ( str == NULL )
+ return NULL;
+
+ char* s1 = JabberUrlEncode( str );
+ if ( s1 == NULL )
+ return NULL;
+
+ // Convert invalid control characters to space
+ if ( *s1 ) {
+ char* p, *q;
+
+ for ( p = s1; *p != '\0'; p++ )
+ if ( *p > 0 && *p < 0x20 && *p != 0x09 && *p != 0x0a && *p != 0x0d )
+ *p = ( char )0x20;
+
+ for ( p = q = s1; *p!='\0'; p++ ) {
+ if ( *p != '\r' ) {
+ *q = *p;
+ q++;
+ } }
+
+ *q = '\0';
+ }
+
+ char* s2 = JabberUtf8Encode( s1 );
+ mir_free( s1 );
+ return s2;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberTextEncodeW - prepare a string for transmission
+
+char* __stdcall JabberTextEncodeW( const wchar_t* str )
+{
+ if ( str == NULL )
+ return NULL;
+
+ const wchar_t *s;
+ int resLen = 1;
+
+ for ( s = str; *s; s++ ) {
+ switch( *s ) {
+ case '\r': continue;
+ case '&': resLen += 5; break;
+ case '\'': resLen += 6; break;
+ case '>':
+ case '<': resLen += 6; break;
+ case '\"': resLen += 6; break;
+ default: resLen++; break;
+ } }
+
+ wchar_t* tmp = ( wchar_t* )alloca( resLen * sizeof( wchar_t )), *d;
+
+ for ( s = str, d = tmp; *s; s++ ) {
+ switch( *s ) {
+ case '\r': continue;
+ case '&': wcscpy( d, L"&" ); d += 5; break;
+ case '\'': wcscpy( d, L"'" ); d += 6; break;
+ case '>': wcscpy( d, L">" ); d += 4; break;
+ case '<': wcscpy( d, L"<" ); d += 4; break;
+ case '\"': wcscpy( d, L""" ); d += 6; break;
+ default:
+ if ( *s > 0 && *s < 0x20 && *s != 0x09 && *s != 0x0a && *s != 0x0d )
+ *d++ = ' ';
+ else
+ *d++ = *s;
+ } }
+
+ *d = 0;
+
+ return JabberUtf8EncodeW( tmp );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberTextDecode - retrieve a text from the encoded string
+
+char* __stdcall JabberTextDecode( const char* str )
+{
+ if ( str == NULL )
+ return NULL;
+
+ char* s1 = ( char* )alloca( strlen( str )+1 ), *s2;
+ strcpy( s1, str );
+
+ JabberUtf8Decode( s1, NULL );
+ JabberUrlDecode( s1 );
+ if (( s2 = JabberUnixToDos( s1 )) == NULL )
+ return NULL;
+
+ return s2;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberBase64Encode
+
+static char b64table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+char* __stdcall JabberBase64Encode( const char* buffer, int bufferLen )
+{
+ if ( buffer==NULL || bufferLen<=0 )
+ return NULL;
+
+ char* res = (char*)mir_alloc(((( bufferLen+2 )*4 )/3 ) + 1);
+ if ( res == NULL )
+ return NULL;
+
+ unsigned char igroup[3];
+ int nGroups = 0;
+ char *r = res;
+ const char* peob = buffer + bufferLen;
+ for ( const char* p = buffer; p < peob; ) {
+ igroup[ 0 ] = igroup[ 1 ] = igroup[ 2 ] = 0;
+ int n;
+ for ( n=0; n<3; n++ ) {
+ if ( p >= peob ) break;
+ igroup[n] = ( unsigned char ) *p;
+ p++;
+ }
+
+ if ( n > 0 ) {
+ r[0] = b64table[ igroup[0]>>2 ];
+ r[1] = b64table[ (( igroup[0]&3 )<<4 ) | ( igroup[1]>>4 ) ];
+ r[2] = b64table[ (( igroup[1]&0xf )<<2 ) | ( igroup[2]>>6 ) ];
+ r[3] = b64table[ igroup[2]&0x3f ];
+
+ if ( n < 3 ) {
+ r[3] = '=';
+ if ( n < 2 )
+ r[2] = '=';
+ }
+ r += 4;
+ } }
+
+ *r = '\0';
+
+ return res;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberBase64Decode
+
+static unsigned char b64rtable[256];
+
+char* __stdcall JabberBase64Decode( const TCHAR* str, int *resultLen )
+{
+ char* res;
+ unsigned char* r, igroup[4], a[4];
+ int n, num, count;
+
+ if ( str==NULL || resultLen==NULL ) return NULL;
+ if (( res=( char* )mir_alloc(( ( _tcslen( str )+3 )/4 )*3 )) == NULL ) return NULL;
+
+ for ( n=0; n<256; n++ )
+ b64rtable[n] = ( unsigned char ) 0x80;
+ for ( n=0; n<26; n++ )
+ b64rtable['A'+n] = n;
+ for ( n=0; n<26; n++ )
+ b64rtable['a'+n] = n + 26;
+ for ( n=0; n<10; n++ )
+ b64rtable['0'+n] = n + 52;
+ b64rtable['+'] = 62;
+ b64rtable['/'] = 63;
+ b64rtable['='] = 0;
+ count = 0;
+ for ( r=( unsigned char* )res; *str != '\0'; ) {
+ for ( n=0; n<4; n++ ) {
+ if ( BYTE(*str) == '\r' || BYTE(*str) == '\n' ) {
+ n--; str++;
+ continue;
+ }
+
+ if ( BYTE(*str)=='\0' ) {
+ if ( n == 0 )
+ goto LBL_Exit;
+ mir_free( res );
+ return NULL;
+ }
+
+ if ( b64rtable[BYTE(*str)]==0x80 ) {
+ mir_free( res );
+ return NULL;
+ }
+
+ a[n] = BYTE(*str);
+ igroup[n] = b64rtable[BYTE(*str)];
+ str++;
+ }
+ r[0] = igroup[0]<<2 | igroup[1]>>4;
+ r[1] = igroup[1]<<4 | igroup[2]>>2;
+ r[2] = igroup[2]<<6 | igroup[3];
+ r += 3;
+ num = ( a[2]=='='?1:( a[3]=='='?2:3 ));
+ count += num;
+ if ( num < 3 ) break;
+ }
+LBL_Exit:
+ *resultLen = count;
+ return res;
+}
+
+char* __stdcall JabberGetVersionText()
+{
+ char filename[MAX_PATH], *fileVersion, *res;
+ DWORD unused;
+ DWORD verInfoSize;
+ UINT blockSize;
+ PVOID pVerInfo;
+
+ GetModuleFileNameA( hInst, filename, sizeof( filename ));
+ verInfoSize = GetFileVersionInfoSizeA( filename, &unused );
+ if (( pVerInfo=mir_alloc( verInfoSize )) != NULL ) {
+ GetFileVersionInfoA( filename, 0, verInfoSize, pVerInfo );
+ VerQueryValueA( pVerInfo, "\\StringFileInfo\\040904b0\\FileVersion", ( LPVOID* )&fileVersion, &blockSize );
+ if ( strstr( fileVersion, "cvs" )) {
+ res = ( char* )mir_alloc( strlen( fileVersion ) + strlen( __DATE__ ) + 2 );
+ sprintf( res, "%s %s", fileVersion, __DATE__ );
+ }
+ else {
+ res = mir_strdup( fileVersion );
+ }
+ mir_free( pVerInfo );
+ return res;
+ }
+ return NULL;
+}
+
+time_t __stdcall JabberIsoToUnixTime( TCHAR* stamp )
+{
+ struct tm timestamp;
+ TCHAR date[9];
+ TCHAR* p;
+ int i, y;
+ time_t t;
+
+ if ( stamp == NULL ) return ( time_t ) 0;
+
+ p = stamp;
+
+ // Get the date part
+ for ( i=0; *p!='\0' && i<8 && isdigit( *p ); p++,i++ )
+ date[i] = *p;
+
+ // Parse year
+ if ( i == 6 ) {
+ // 2-digit year ( 1970-2069 )
+ y = ( date[0]-'0' )*10 + ( date[1]-'0' );
+ if ( y < 70 ) y += 100;
+ }
+ else if ( i == 8 ) {
+ // 4-digit year
+ y = ( date[0]-'0' )*1000 + ( date[1]-'0' )*100 + ( date[2]-'0' )*10 + date[3]-'0';
+ y -= 1900;
+ }
+ else
+ return ( time_t ) 0;
+ timestamp.tm_year = y;
+ // Parse month
+ timestamp.tm_mon = ( date[i-4]-'0' )*10 + date[i-3]-'0' - 1;
+ // Parse date
+ timestamp.tm_mday = ( date[i-2]-'0' )*10 + date[i-1]-'0';
+
+ // Skip any date/time delimiter
+ for ( ; *p!='\0' && !isdigit( *p ); p++ );
+
+ // Parse time
+ if ( _stscanf( p, _T("%d:%d:%d"), ×tamp.tm_hour, ×tamp.tm_min, ×tamp.tm_sec ) != 3 )
+ return ( time_t ) 0;
+
+ timestamp.tm_isdst = 0; // DST is already present in _timezone below
+ t = mktime( ×tamp );
+
+ _tzset();
+ t -= _timezone;
+
+ if ( t >= 0 )
+ return t;
+ else
+ return ( time_t ) 0;
+}
+
+struct MyCountryListEntry
+{
+ int id;
+ TCHAR* szName;
+}
+static extraCtry[] =
+{
+ { 1, _T("United States") },
+ { 1, _T("United States of America") },
+ { 1, _T("US") },
+ { 44, _T("England") }
+};
+
+int __stdcall JabberCountryNameToId( TCHAR* ctry )
+{
+ int ctryCount, i;
+ MyCountryListEntry *ctryList;
+
+ // Check for some common strings not present in the country list
+ ctryCount = sizeof( extraCtry )/sizeof( extraCtry[0] );
+ for ( i=0; i<ctryCount && _tcsicmp( extraCtry[i].szName, ctry ); i++ );
+ if ( i < ctryCount )
+ return extraCtry[i].id;
+
+ // Check Miranda country list
+ JCallService( MS_UTILS_GETCOUNTRYLIST, ( WPARAM ) &ctryCount, ( LPARAM )&ctryList );
+ for ( i=0; i<ctryCount && _tcsicmp( ctryList[i].szName, ctry ); i++ );
+ if ( i < ctryCount )
+ return ctryList[i].id;
+ else
+ return 0xffff; // Unknown
+}
+
+void __stdcall JabberSendPresenceTo( int status, TCHAR* to, XmlNode* extra )
+{
+ if ( !jabberOnline ) return;
+
+ // Send <presence/> update for status ( we won't handle ID_STATUS_OFFLINE here )
+ // Note: jabberModeMsg is already encoded using JabberTextEncode()
+ EnterCriticalSection( &modeMsgMutex );
+
+ char szPriority[40];
+ itoa( JGetWord( NULL, "Priority", 0 ), szPriority, 10 );
+
+ XmlNode p( "presence" ); p.addChild( "priority", szPriority );
+ if ( to != NULL )
+ p.addAttr( "to", to );
+
+ if ( extra )
+ p.addChild( extra );
+
+ if ( JGetByte( "EnableAvatars", TRUE )) {
+ char hashValue[ 50 ];
+ if ( !JGetStaticString( "AvatarHash", NULL, hashValue, sizeof hashValue )) {
+ XmlNode* x = p.addChild( "x" ); x->addAttr( "xmlns", "jabber:x:avatar" );
+ x->addChild( "hash", hashValue );
+
+ x = p.addChild( "x" ); x->addAttr( "xmlns", "vcard-temp:x:update" );
+ x->addChild( "photo", hashValue );
+ } }
+
+ switch ( status ) {
+ case ID_STATUS_ONLINE:
+ if ( modeMsgs.szOnline )
+ p.addChild( "status", modeMsgs.szOnline );
+ break;
+ case ID_STATUS_INVISIBLE:
+ p.addAttr( "type", "invisible" );
+ break;
+ case ID_STATUS_AWAY:
+ case ID_STATUS_ONTHEPHONE:
+ case ID_STATUS_OUTTOLUNCH:
+ p.addChild( "show", "away" );
+ if ( modeMsgs.szAway )
+ p.addChild( "status", modeMsgs.szAway );
+ break;
+ case ID_STATUS_NA:
+ p.addChild( "show", "xa" );
+ if ( modeMsgs.szNa )
+ p.addChild( "status", modeMsgs.szNa );
+ break;
+ case ID_STATUS_DND:
+ case ID_STATUS_OCCUPIED:
+ p.addChild( "show", "dnd" );
+ if ( modeMsgs.szDnd )
+ p.addChild( "status", modeMsgs.szDnd );
+ break;
+ case ID_STATUS_FREECHAT:
+ p.addChild( "show", "chat" );
+ if ( modeMsgs.szFreechat )
+ p.addChild( "status", modeMsgs.szFreechat );
+ break;
+ default:
+ // Should not reach here
+ break;
+ }
+ JabberSend( jabberThreadInfo->s, p );
+ LeaveCriticalSection( &modeMsgMutex );
+}
+
+void __stdcall JabberSendPresence( int status )
+{
+ JabberSendPresenceTo( status, NULL, NULL );
+ JabberSendVisibleInvisiblePresence( status == ID_STATUS_INVISIBLE );
+
+ // Also update status in all chatrooms
+ for ( int i = 0; ( i=JabberListFindNext( LIST_CHATROOM, i )) >= 0; i++ ) {
+ JABBER_LIST_ITEM *item = JabberListGetItemPtrFromIndex( i );
+ if ( item != NULL )
+ JabberSendPresenceTo( status, item->jid, NULL );
+} }
+
+void __stdcall JabberStringAppend( char* *str, int *sizeAlloced, const char* fmt, ... )
+{
+ va_list vararg;
+ char* p;
+ int size, len;
+
+ if ( str == NULL ) return;
+
+ if ( *str==NULL || *sizeAlloced<=0 ) {
+ *sizeAlloced = size = 2048;
+ *str = ( char* )mir_alloc( size );
+ len = 0;
+ }
+ else {
+ len = strlen( *str );
+ size = *sizeAlloced - strlen( *str );
+ }
+
+ p = *str + len;
+ va_start( vararg, fmt );
+ while ( _vsnprintf( p, size, fmt, vararg ) == -1 ) {
+ size += 2048;
+ ( *sizeAlloced ) += 2048;
+ *str = ( char* )mir_realloc( *str, *sizeAlloced );
+ p = *str + len;
+ }
+ va_end( vararg );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// JabberGetClientJID - adds a resource postfix to a JID
+
+TCHAR* __stdcall JabberGetClientJID( const TCHAR* jid, TCHAR* dest, size_t destLen )
+{
+ if ( jid == NULL )
+ return NULL;
+
+ size_t len = _tcslen( jid );
+ if ( len >= destLen )
+ len = destLen-1;
+
+ _tcsncpy( dest, jid, len );
+ dest[ len ] = '\0';
+
+ TCHAR* p = _tcschr( dest, '/' );
+ if ( p == NULL ) {
+ TCHAR* resource = JabberListGetBestResourceNamePtr( jid );
+ if ( resource != NULL )
+ mir_sntprintf( dest+len, destLen-len-1, _T("/%s"), resource );
+ }
+
+ return dest;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// JabberStripJid - strips a resource postfix from a JID
+
+TCHAR* __stdcall JabberStripJid( const TCHAR* jid, TCHAR* dest, size_t destLen )
+{
+ if ( jid == NULL )
+ *dest = 0;
+ else {
+ size_t len = _tcslen( jid );
+ if ( len >= destLen )
+ len = destLen-1;
+
+ memcpy( dest, jid, len * sizeof( TCHAR ));
+ dest[ len ] = 0;
+
+ TCHAR* p = _tcschr( dest, '/' );
+ if ( p != NULL )
+ *p = 0;
+ }
+
+ return dest;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberGetPictureType - tries to autodetect the picture type from the buffer
+
+int __stdcall JabberGetPictureType( const char* buf )
+{
+ if ( buf != NULL ) {
+ if ( memcmp( buf, "GIF89", 5 ) == 0 ) return PA_FORMAT_GIF;
+ if ( memcmp( buf, "\x89PNG", 4 ) == 0 ) return PA_FORMAT_PNG;
+ if ( memcmp( buf, "BM", 2 ) == 0 ) return PA_FORMAT_BMP;
+ if ( memcmp( buf+6, "JFIF", 4 ) == 0 ) return PA_FORMAT_JPEG;
+ }
+
+ return PA_FORMAT_UNKNOWN;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Unicode functions
+
+char* t2a( const TCHAR* src )
+{
+ #if defined( _UNICODE )
+ return u2a( src );
+ #else
+ return mir_strdup( src );
+ #endif
+}
+
+char* u2a( const wchar_t* src )
+{
+ int codepage = CallService( MS_LANGPACK_GETCODEPAGE, 0, 0 );
+
+ int cbLen = WideCharToMultiByte( codepage, 0, src, -1, NULL, 0, NULL, NULL );
+ char* result = ( char* )mir_alloc( cbLen+1 );
+ if ( result == NULL )
+ return NULL;
+
+ WideCharToMultiByte( codepage, 0, src, -1, result, cbLen, NULL, NULL );
+ result[ cbLen ] = 0;
+ return result;
+}
+
+wchar_t* a2u( const char* src )
+{
+ int codepage = CallService( MS_LANGPACK_GETCODEPAGE, 0, 0 );
+
+ int cbLen = MultiByteToWideChar( codepage, 0, src, -1, NULL, 0 );
+ wchar_t* result = ( wchar_t* )mir_alloc( sizeof( wchar_t )*(cbLen+1));
+ if ( result == NULL )
+ return NULL;
+
+ MultiByteToWideChar( codepage, 0, src, -1, result, cbLen );
+ result[ cbLen ] = 0;
+ return result;
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_vcard.cpp b/miranda-wine/protocols/JabberG/jabber_vcard.cpp new file mode 100644 index 0000000..0f551eb --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_vcard.cpp @@ -0,0 +1,1179 @@ +/*
+
+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_vcard.cpp,v $
+Revision : $Revision: 3016 $
+Last change on : $Date: 2006-06-04 23:07:43 +0400 (Вск, 04 Июн 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <io.h>
+#include <commctrl.h>
+#include "jabber_iq.h"
+#include "resource.h"
+
+extern char* jabberVcardPhotoFileName;
+extern char* jabberVcardPhotoType;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static BOOL CALLBACK JabberVcardDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam );
+
+int JabberMenuHandleVcard( WPARAM wParam, LPARAM lParam )
+{
+ if ( IsWindow( hwndJabberVcard ))
+ SetForegroundWindow( hwndJabberVcard );
+ else {
+ hwndJabberVcard = CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_VCARD ), NULL, JabberVcardDlgProc, ( LPARAM )NULL );
+ }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int JabberSendGetVcard( const TCHAR* jid )
+{
+ int iqId = JabberSerialNext();
+ JabberIqAdd( iqId, ( jid == jabberJID ) ? IQ_PROC_GETVCARD : IQ_PROC_NONE, JabberIqResultGetVcard );
+
+ XmlNodeIq iq( "get", iqId, jid );
+ XmlNode* vs = iq.addChild( "vCard" ); vs->addAttr( "xmlns", "vcard-temp" );
+ vs->addAttr( "prodid", "-//HandGen//NONSGML vGen v1.0//EN" ); vs->addAttr( "version", "2.0" );
+ JabberSend( jabberThreadInfo->s, iq );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+typedef struct {
+ HWND hwnd;
+ int dlgId;
+ DLGPROC dlgProc;
+} VcardPage;
+
+typedef struct {
+ int pageCount;
+ int currentPage;
+ RECT rectTab;
+ VcardPage *page;
+ BOOL changed;
+ int updateAnimFrame;
+ TCHAR* szUpdating;
+ BOOL animating;
+} VcardTab;
+
+static void SetDialogField( HWND hwndDlg, int nDlgItem, char* key )
+{
+ DBVARIANT dbv;
+
+ if ( !DBGetContactSettingTString( NULL, jabberProtoName, key, &dbv )) {
+ SetDlgItemText( hwndDlg, nDlgItem, dbv.ptszVal );
+ JFreeVariant( &dbv );
+ }
+ else SetDlgItemTextA( hwndDlg, nDlgItem, "" );
+}
+
+static BOOL CALLBACK PersonalDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwndDlg );
+ SendMessage( GetDlgItem( hwndDlg, IDC_GENDER ), CB_ADDSTRING, 0, ( LPARAM )TranslateT( "Male" ));
+ SendMessage( GetDlgItem( hwndDlg, IDC_GENDER ), CB_ADDSTRING, 0, ( LPARAM )TranslateT( "Female" ));
+ SendMessage( hwndDlg, WM_JABBER_REFRESH, 0, 0 );
+ return TRUE;
+ case WM_JABBER_REFRESH:
+ SetDialogField( hwndDlg, IDC_FULLNAME, "FullName" );
+ SetDialogField( hwndDlg, IDC_NICKNAME, "Nick" );
+ SetDialogField( hwndDlg, IDC_FIRSTNAME, "FirstName" );
+ SetDialogField( hwndDlg, IDC_MIDDLE, "MiddleName" );
+ SetDialogField( hwndDlg, IDC_LASTNAME, "LastName" );
+ SetDialogField( hwndDlg, IDC_BIRTH, "BirthDate" );
+ SetDialogField( hwndDlg, IDC_GENDER, "GenderString" );
+ SetDialogField( hwndDlg, IDC_OCCUPATION, "Role" );
+ SetDialogField( hwndDlg, IDC_HOMEPAGE, "Homepage" );
+ break;
+ case WM_COMMAND:
+ if (( ( HWND )lParam==GetFocus() && HIWORD( wParam )==EN_CHANGE ) ||
+ (( HWND )lParam==GetDlgItem( hwndDlg, IDC_GENDER ) && ( HIWORD( wParam )==CBN_EDITCHANGE||HIWORD( wParam )==CBN_SELCHANGE )) )
+ SendMessage( GetParent( hwndDlg ), WM_JABBER_CHANGED, 0, 0 );
+ break;
+ }
+ return FALSE;
+}
+
+static BOOL CALLBACK HomeDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwndDlg );
+ SendMessage( hwndDlg, WM_JABBER_REFRESH, 0, 0 );
+ return TRUE;
+ case WM_JABBER_REFRESH:
+ SetDialogField( hwndDlg, IDC_ADDRESS1, "Street" );
+ SetDialogField( hwndDlg, IDC_ADDRESS2, "Street2" );
+ SetDialogField( hwndDlg, IDC_CITY, "City" );
+ SetDialogField( hwndDlg, IDC_STATE, "State" );
+ SetDialogField( hwndDlg, IDC_ZIP, "ZIP" );
+ SetDialogField( hwndDlg, IDC_COUNTRY, "CountryName" );
+ break;
+ case WM_COMMAND:
+ if (( HWND )lParam==GetFocus() && HIWORD( wParam )==EN_CHANGE )
+ SendMessage( GetParent( hwndDlg ), WM_JABBER_CHANGED, 0, 0 );
+ break;
+ }
+ return FALSE;
+}
+
+static BOOL CALLBACK WorkDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwndDlg );
+ SendMessage( hwndDlg, WM_JABBER_REFRESH, 0, 0 );
+ return TRUE;
+ case WM_JABBER_REFRESH:
+ SetDialogField( hwndDlg, IDC_COMPANY, "Company" );
+ SetDialogField( hwndDlg, IDC_DEPARTMENT, "CompanyDepartment" );
+ SetDialogField( hwndDlg, IDC_TITLE, "CompanyPosition" );
+ SetDialogField( hwndDlg, IDC_ADDRESS1, "CompanyStreet" );
+ SetDialogField( hwndDlg, IDC_ADDRESS2, "CompanyStreet2" );
+ SetDialogField( hwndDlg, IDC_CITY, "CompanyCity" );
+ SetDialogField( hwndDlg, IDC_STATE, "CompanyState" );
+ SetDialogField( hwndDlg, IDC_ZIP, "CompanyZIP" );
+ SetDialogField( hwndDlg, IDC_COUNTRY, "CompanyCountryName" );
+ break;
+ case WM_COMMAND:
+ if (( HWND )lParam==GetFocus() && HIWORD( wParam )==EN_CHANGE )
+ SendMessage( GetParent( hwndDlg ), WM_JABBER_CHANGED, 0, 0 );
+ break;
+ }
+ return FALSE;
+}
+
+static char szPhotoFileName[MAX_PATH];
+static char szPhotoType[33];
+static BOOL bPhotoChanged;
+
+static BOOL CALLBACK PhotoDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ static HBITMAP hBitmap;
+ char szTempPath[MAX_PATH], szTempFileName[MAX_PATH];
+
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwndDlg );
+ hBitmap = NULL;
+ SendMessage( GetDlgItem( hwndDlg, IDC_LOAD ), BM_SETIMAGE, IMAGE_ICON, ( LPARAM )LoadImage( hInst, MAKEINTRESOURCE( IDI_OPEN ), IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), 0 ));
+ SendMessage( GetDlgItem( hwndDlg, IDC_DELETE ), BM_SETIMAGE, IMAGE_ICON, ( LPARAM )LoadImage( hInst, MAKEINTRESOURCE( IDI_DELETE ), IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), 0 ));
+ ShowWindow( GetDlgItem( hwndDlg, IDC_SAVE ), SW_HIDE );
+ SendMessage( hwndDlg, WM_JABBER_REFRESH, 0, 0 );
+ return TRUE;
+ case WM_JABBER_REFRESH:
+ if ( hBitmap ) {
+ DeleteObject( hBitmap );
+ hBitmap = NULL;
+ DeleteFileA( szPhotoFileName );
+ szPhotoFileName[0] = '\0';
+ }
+ EnableWindow( GetDlgItem( hwndDlg, IDC_DELETE ), FALSE );
+ if ( jabberVcardPhotoFileName ) {
+ if ( GetTempPathA( sizeof( szTempPath ), szTempPath ) <= 0 )
+ strcpy( szTempPath, ".\\" );
+ if ( GetTempFileNameA( szTempPath, "jab", 0, szTempFileName ) > 0 ) {
+ JabberLog( "Temp file = %s", szTempFileName );
+ if ( CopyFileA( jabberVcardPhotoFileName, szTempFileName, FALSE ) == TRUE ) {
+ if (( hBitmap=( HBITMAP ) JCallService( MS_UTILS_LOADBITMAP, 0, ( LPARAM )szTempFileName )) != NULL ) {
+ strcpy( szPhotoFileName, szTempFileName );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_DELETE ), TRUE );
+ }
+ else DeleteFileA( szTempFileName );
+ }
+ else DeleteFileA( szTempFileName );
+ }
+ }
+ bPhotoChanged = FALSE;
+ InvalidateRect( hwndDlg, NULL, TRUE );
+ UpdateWindow( hwndDlg );
+ break;
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDC_LOAD:
+ {
+ OPENFILENAMEA ofn = {0};
+ static char szFilter[512];
+ char szFileName[_MAX_PATH];
+ char* p;
+ int n;
+
+// JCallService( MS_UTILS_GETBITMAPFILTERSTRINGS, ( WPARAM ) sizeof( szFilter ), ( LPARAM )szFilter );
+ p = szFilter;
+ n = sizeof( szFilter );
+ strncpy( p, JTranslate( "All Bitmaps" ), n ); n = sizeof( szFilter )-strlen( szFilter );
+ strncat( p, " ( *.bmp;*.jpg;*.jpeg;*.gif )", n ); n = sizeof( szFilter )-strlen( szFilter );
+ p += strlen( p )+1; n = sizeof( szFilter )-( p-szFilter );
+ strncpy( p, "*.BMP;*.JPG;*.JPEG;*.GIF", n );
+ szFilter[512-1] = '\0';
+
+
+ ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
+ ofn.hwndOwner = hwndDlg;
+ ofn.lpstrFilter = szFilter;
+ ofn.lpstrCustomFilter = NULL;
+ ofn.lpstrFile = szFileName;
+ ofn.nMaxFile = _MAX_PATH;
+ ofn.Flags = OFN_FILEMUSTEXIST;
+ szFileName[0] = '\0';
+ if ( GetOpenFileNameA( &ofn )) {
+ struct _stat st;
+ HBITMAP hNewBitmap;
+
+ JabberLog( "File selected is %s", szFileName );
+ if ( _stat( szFileName, &st )<0 || st.st_size>40*1024 ) {
+ MessageBox( hwndDlg, TranslateT( "Only JPG, GIF, and BMP image files smaller than 40 KB are supported." ), TranslateT( "Jabber vCard" ), MB_OK|MB_SETFOREGROUND );
+ break;
+ }
+ if ( GetTempPathA( sizeof( szTempPath ), szTempPath ) <= 0 )
+ strcpy( szTempPath, ".\\" );
+ if ( GetTempFileNameA( szTempPath, "jab", 0, szTempFileName ) > 0 ) {
+ JabberLog( "Temp file = %s", szTempFileName );
+ if ( CopyFileA( szFileName, szTempFileName, FALSE ) == TRUE ) {
+ if (( hNewBitmap=( HBITMAP ) JCallService( MS_UTILS_LOADBITMAP, 0, ( LPARAM )szTempFileName )) != NULL ) {
+ if ( hBitmap ) {
+ DeleteObject( hBitmap );
+ DeleteFileA( szPhotoFileName );
+ }
+ if (( p=strrchr( szFileName, '.' )) != NULL ) {
+ if ( !stricmp( p, ".bmp" ))
+ strcpy( szPhotoType, "image/bmp" );
+ else if ( !stricmp( p, ".gif" ))
+ strcpy( szPhotoType, "image/gif" );
+ else
+ strcpy( szPhotoType, "image/jpeg" );
+ }
+ else
+ strcpy( szPhotoType, "image/jpeg" );
+ hBitmap = hNewBitmap;
+ strcpy( szPhotoFileName, szTempFileName );
+ bPhotoChanged = TRUE;
+ EnableWindow( GetDlgItem( hwndDlg, IDC_DELETE ), TRUE );
+ InvalidateRect( hwndDlg, NULL, TRUE );
+ UpdateWindow( hwndDlg );
+ SendMessage( GetParent( hwndDlg ), WM_JABBER_CHANGED, 0, 0 );
+ }
+ else {
+ DeleteFileA( szTempFileName );
+ }
+ }
+ else
+ DeleteFileA( szTempFileName );
+ }
+ }
+ }
+ break;
+ case IDC_DELETE:
+ if ( hBitmap ) {
+ DeleteObject( hBitmap );
+ hBitmap = NULL;
+ DeleteFileA( szPhotoFileName );
+ szPhotoFileName[0] = '\0';
+ bPhotoChanged = TRUE;
+ EnableWindow( GetDlgItem( hwndDlg, IDC_DELETE ), FALSE );
+ InvalidateRect( hwndDlg, NULL, TRUE );
+ UpdateWindow( hwndDlg );
+ SendMessage( GetParent( hwndDlg ), WM_JABBER_CHANGED, 0, 0 );
+ }
+ break;
+ }
+ break;
+ case WM_PAINT:
+ if ( hBitmap ) {
+ BITMAP bm;
+ HDC hdcMem;
+ HWND hwndCanvas;
+ HDC hdcCanvas;
+ POINT ptSize, ptOrg, pt, ptFitSize;
+ RECT rect;
+
+ hwndCanvas = GetDlgItem( hwndDlg, IDC_CANVAS );
+ hdcCanvas = GetDC( hwndCanvas );
+ hdcMem = CreateCompatibleDC( hdcCanvas );
+ SelectObject( hdcMem, hBitmap );
+ SetMapMode( hdcMem, GetMapMode( hdcCanvas ));
+ GetObject( hBitmap, sizeof( BITMAP ), ( LPVOID ) &bm );
+ ptSize.x = bm.bmWidth;
+ ptSize.y = bm.bmHeight;
+ DPtoLP( hdcCanvas, &ptSize, 1 );
+ ptOrg.x = ptOrg.y = 0;
+ DPtoLP( hdcMem, &ptOrg, 1 );
+ GetClientRect( hwndCanvas, &rect );
+ InvalidateRect( hwndCanvas, NULL, TRUE );
+ UpdateWindow( hwndCanvas );
+ if ( ptSize.x<=rect.right && ptSize.y<=rect.bottom ) {
+ pt.x = ( rect.right - ptSize.x )/2;
+ pt.y = ( rect.bottom - ptSize.y )/2;
+ BitBlt( hdcCanvas, pt.x, pt.y, ptSize.x, ptSize.y, hdcMem, ptOrg.x, ptOrg.y, SRCCOPY );
+ }
+ else {
+ if (( ( float )( ptSize.x-rect.right ))/ptSize.x > (( float )( ptSize.y-rect.bottom ))/ptSize.y ) {
+ ptFitSize.x = rect.right;
+ ptFitSize.y = ( ptSize.y*rect.right )/ptSize.x;
+ pt.x = 0;
+ pt.y = ( rect.bottom - ptFitSize.y )/2;
+ }
+ else {
+ ptFitSize.x = ( ptSize.x*rect.bottom )/ptSize.y;
+ ptFitSize.y = rect.bottom;
+ pt.x = ( rect.right - ptFitSize.x )/2;
+ pt.y = 0;
+ }
+ SetStretchBltMode( hdcCanvas, COLORONCOLOR );
+ StretchBlt( hdcCanvas, pt.x, pt.y, ptFitSize.x, ptFitSize.y, hdcMem, ptOrg.x, ptOrg.y, ptSize.x, ptSize.y, SRCCOPY );
+ }
+ DeleteDC( hdcMem );
+ }
+ break;
+ case WM_DESTROY:
+ if ( hBitmap ) {
+ JabberLog( "Delete bitmap" );
+ DeleteObject( hBitmap );
+ DeleteFileA( szPhotoFileName );
+ szPhotoFileName[0] = '\0';
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static BOOL CALLBACK NoteDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwndDlg );
+ SendMessage( hwndDlg, WM_JABBER_REFRESH, 0, 0 );
+ return TRUE;
+ case WM_JABBER_REFRESH:
+ SetDialogField( hwndDlg, IDC_DESC, "About" );
+ break;
+ case WM_COMMAND:
+ if (( HWND )lParam==GetFocus() && HIWORD( wParam )==EN_CHANGE )
+ SendMessage( GetParent( hwndDlg ), WM_JABBER_CHANGED, 0, 0 );
+ break;
+ }
+ return FALSE;
+}
+
+static BOOL CALLBACK EditEmailDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwndDlg );
+ SetWindowLong( hwndDlg, GWL_USERDATA, lParam );
+ if ( lParam >= 0 ) {
+ DBVARIANT dbv;
+ char idstr[33];
+ WORD nFlag;
+
+ SetWindowText( hwndDlg, TranslateT( "Jabber vCard: Edit Email Address" ));
+ wsprintfA( idstr, "e-mail%d", lParam );
+ if ( !DBGetContactSetting( NULL, jabberProtoName, idstr, &dbv )) {
+ SetDlgItemTextA( hwndDlg, IDC_EMAIL, dbv.pszVal );
+ JFreeVariant( &dbv );
+ wsprintfA( idstr, "e-mailFlag%d", lParam );
+ nFlag = DBGetContactSettingWord( NULL, jabberProtoName, idstr, 0 );
+ if ( nFlag & JABBER_VCEMAIL_HOME ) CheckDlgButton( hwndDlg, IDC_HOME, TRUE );
+ if ( nFlag & JABBER_VCEMAIL_WORK ) CheckDlgButton( hwndDlg, IDC_WORK, TRUE );
+ if ( nFlag & JABBER_VCEMAIL_INTERNET ) CheckDlgButton( hwndDlg, IDC_INTERNET, TRUE );
+ if ( nFlag & JABBER_VCEMAIL_X400 ) CheckDlgButton( hwndDlg, IDC_X400, TRUE );
+ }
+ }
+ return TRUE;
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDOK:
+ {
+ TCHAR text[128];
+ char idstr[33];
+ int id = ( int ) GetWindowLong( hwndDlg, GWL_USERDATA );
+ DBVARIANT dbv;
+ WORD nFlag;
+
+ if ( id < 0 ) {
+ for ( id=0;;id++ ) {
+ mir_snprintf( idstr, SIZEOF(idstr), "e-mail%d", id );
+ if ( DBGetContactSetting( NULL, jabberProtoName, idstr, &dbv )) break;
+ JFreeVariant( &dbv );
+ } }
+ GetDlgItemText( hwndDlg, IDC_EMAIL, text, SIZEOF( text ));
+ mir_snprintf( idstr, SIZEOF(idstr), "e-mail%d", id );
+ JSetStringT( NULL, idstr, text );
+
+ nFlag = 0;
+ if ( IsDlgButtonChecked( hwndDlg, IDC_HOME )) nFlag |= JABBER_VCEMAIL_HOME;
+ if ( IsDlgButtonChecked( hwndDlg, IDC_WORK )) nFlag |= JABBER_VCEMAIL_WORK;
+ if ( IsDlgButtonChecked( hwndDlg, IDC_INTERNET )) nFlag |= JABBER_VCEMAIL_INTERNET;
+ if ( IsDlgButtonChecked( hwndDlg, IDC_X400 )) nFlag |= JABBER_VCEMAIL_X400;
+ mir_snprintf( idstr, SIZEOF(idstr), "e-mailFlag%d", id );
+ JSetWord( NULL, idstr, nFlag );
+ }
+ // fall through
+ case IDCANCEL:
+ EndDialog( hwndDlg, wParam );
+ break;
+ }
+ }
+ return FALSE;
+}
+
+static BOOL CALLBACK EditPhoneDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwndDlg );
+ SetWindowLong( hwndDlg, GWL_USERDATA, lParam );
+ if ( lParam >= 0 ) {
+ DBVARIANT dbv;
+ char idstr[33];
+ WORD nFlag;
+
+ SetWindowText( hwndDlg, TranslateT( "Jabber vCard: Edit Phone Number" ));
+ wsprintfA( idstr, "Phone%d", lParam );
+ if ( !DBGetContactSetting( NULL, jabberProtoName, idstr, &dbv )) {
+ SetDlgItemTextA( hwndDlg, IDC_PHONE, dbv.pszVal );
+ JFreeVariant( &dbv );
+ wsprintfA( idstr, "PhoneFlag%d", lParam );
+ nFlag = JGetWord( NULL, idstr, 0 );
+ if ( nFlag & JABBER_VCTEL_HOME ) CheckDlgButton( hwndDlg, IDC_HOME, TRUE );
+ if ( nFlag & JABBER_VCTEL_WORK ) CheckDlgButton( hwndDlg, IDC_WORK, TRUE );
+ if ( nFlag & JABBER_VCTEL_VOICE ) CheckDlgButton( hwndDlg, IDC_VOICE, TRUE );
+ if ( nFlag & JABBER_VCTEL_FAX ) CheckDlgButton( hwndDlg, IDC_FAX, TRUE );
+ if ( nFlag & JABBER_VCTEL_PAGER ) CheckDlgButton( hwndDlg, IDC_PAGER, TRUE );
+ if ( nFlag & JABBER_VCTEL_MSG ) CheckDlgButton( hwndDlg, IDC_MSG, TRUE );
+ if ( nFlag & JABBER_VCTEL_CELL ) CheckDlgButton( hwndDlg, IDC_CELL, TRUE );
+ if ( nFlag & JABBER_VCTEL_VIDEO ) CheckDlgButton( hwndDlg, IDC_VIDEO, TRUE );
+ if ( nFlag & JABBER_VCTEL_BBS ) CheckDlgButton( hwndDlg, IDC_BBS, TRUE );
+ if ( nFlag & JABBER_VCTEL_MODEM ) CheckDlgButton( hwndDlg, IDC_MODEM, TRUE );
+ if ( nFlag & JABBER_VCTEL_ISDN ) CheckDlgButton( hwndDlg, IDC_ISDN, TRUE );
+ if ( nFlag & JABBER_VCTEL_PCS ) CheckDlgButton( hwndDlg, IDC_PCS, TRUE );
+ }
+ }
+ return TRUE;
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDOK:
+ {
+ char text[128];
+ char idstr[33];
+ int id = ( int ) GetWindowLong( hwndDlg, GWL_USERDATA );
+ DBVARIANT dbv;
+ WORD nFlag;
+
+ if ( id < 0 ) {
+ for ( id=0;;id++ ) {
+ wsprintfA( idstr, "Phone%d", id );
+ if ( DBGetContactSetting( NULL, jabberProtoName, idstr, &dbv )) break;
+ JFreeVariant( &dbv );
+ }
+ }
+ GetDlgItemTextA( hwndDlg, IDC_PHONE, text, SIZEOF( text ));
+ wsprintfA( idstr, "Phone%d", id );
+ JSetString( NULL, idstr, text );
+ nFlag = 0;
+ if ( IsDlgButtonChecked( hwndDlg, IDC_HOME )) nFlag |= JABBER_VCTEL_HOME;
+ if ( IsDlgButtonChecked( hwndDlg, IDC_WORK )) nFlag |= JABBER_VCTEL_WORK;
+ if ( IsDlgButtonChecked( hwndDlg, IDC_VOICE )) nFlag |= JABBER_VCTEL_VOICE;
+ if ( IsDlgButtonChecked( hwndDlg, IDC_FAX )) nFlag |= JABBER_VCTEL_FAX;
+ if ( IsDlgButtonChecked( hwndDlg, IDC_PAGER )) nFlag |= JABBER_VCTEL_PAGER;
+ if ( IsDlgButtonChecked( hwndDlg, IDC_MSG )) nFlag |= JABBER_VCTEL_MSG;
+ if ( IsDlgButtonChecked( hwndDlg, IDC_CELL )) nFlag |= JABBER_VCTEL_CELL;
+ if ( IsDlgButtonChecked( hwndDlg, IDC_VIDEO )) nFlag |= JABBER_VCTEL_VIDEO;
+ if ( IsDlgButtonChecked( hwndDlg, IDC_BBS )) nFlag |= JABBER_VCTEL_BBS;
+ if ( IsDlgButtonChecked( hwndDlg, IDC_MODEM )) nFlag |= JABBER_VCTEL_MODEM;
+ if ( IsDlgButtonChecked( hwndDlg, IDC_ISDN )) nFlag |= JABBER_VCTEL_ISDN;
+ if ( IsDlgButtonChecked( hwndDlg, IDC_PCS )) nFlag |= JABBER_VCTEL_PCS;
+ wsprintfA( idstr, "PhoneFlag%d", id );
+ JSetWord( NULL, idstr, nFlag );
+ }
+ // fall through
+ case IDCANCEL:
+ EndDialog( hwndDlg, wParam );
+ break;
+ }
+ }
+ return FALSE;
+}
+
+#define M_REMAKELISTS ( WM_USER+1 )
+static BOOL CALLBACK ContactDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ switch( msg ) {
+ case WM_INITDIALOG:
+ {
+ LVCOLUMN lvc;
+ RECT rc;
+
+ TranslateDialogDefault( hwndDlg );
+ GetClientRect( GetDlgItem( hwndDlg,IDC_EMAILS ), &rc );
+ rc.right -= GetSystemMetrics( SM_CXVSCROLL );
+ lvc.mask = LVCF_WIDTH;
+ lvc.cx = 30;
+ ListView_InsertColumn( GetDlgItem( hwndDlg,IDC_EMAILS ), 0, &lvc );
+ ListView_InsertColumn( GetDlgItem( hwndDlg,IDC_PHONES ), 0, &lvc );
+ lvc.cx = rc.right - 30 - 40;
+ ListView_InsertColumn( GetDlgItem( hwndDlg,IDC_EMAILS ), 1, &lvc );
+ ListView_InsertColumn( GetDlgItem( hwndDlg,IDC_PHONES ), 1, &lvc );
+ lvc.cx = 20;
+ ListView_InsertColumn( GetDlgItem( hwndDlg,IDC_EMAILS ), 2, &lvc );
+ ListView_InsertColumn( GetDlgItem( hwndDlg,IDC_EMAILS ), 3, &lvc );
+ ListView_InsertColumn( GetDlgItem( hwndDlg,IDC_PHONES ), 2, &lvc );
+ ListView_InsertColumn( GetDlgItem( hwndDlg,IDC_PHONES ), 3, &lvc );
+ SendMessage( hwndDlg, M_REMAKELISTS, 0, 0 );
+ }
+ return TRUE;
+ case M_REMAKELISTS:
+ {
+ LVITEM lvi;
+ int i;
+ char idstr[33];
+ TCHAR number[20];
+ DBVARIANT dbv;
+
+ //e-mails
+ ListView_DeleteAllItems( GetDlgItem( hwndDlg, IDC_EMAILS ));
+ lvi.mask = LVIF_TEXT | LVIF_PARAM;
+ lvi.iSubItem = 0;
+ lvi.iItem = 0;
+ for ( i=0;;i++ ) {
+ wsprintfA( idstr, "e-mail%d", i );
+ if ( DBGetContactSettingTString( NULL, jabberProtoName, idstr, &dbv )) break;
+ wsprintf( number, _T("%d"), i+1 );
+ lvi.pszText = number;
+ lvi.lParam = ( LPARAM )i;
+ ListView_InsertItem( GetDlgItem( hwndDlg, IDC_EMAILS ), &lvi );
+ ListView_SetItemText( GetDlgItem( hwndDlg, IDC_EMAILS ), lvi.iItem, 1, dbv.ptszVal );
+ JFreeVariant( &dbv );
+ lvi.iItem++;
+ }
+ lvi.mask = LVIF_PARAM;
+ lvi.lParam = ( LPARAM )( -1 );
+ ListView_InsertItem( GetDlgItem( hwndDlg, IDC_EMAILS ), &lvi );
+ //phones
+ ListView_DeleteAllItems( GetDlgItem( hwndDlg, IDC_PHONES ));
+ lvi.mask = LVIF_TEXT | LVIF_PARAM;
+ lvi.iSubItem = 0;
+ lvi.iItem = 0;
+ for ( i=0;;i++ ) {
+ wsprintfA( idstr, "Phone%d", i );
+ if ( DBGetContactSettingTString( NULL, jabberProtoName, idstr, &dbv )) break;
+ wsprintf( number, _T("%d"), i+1 );
+ lvi.pszText = number;
+ lvi.lParam = ( LPARAM )i;
+ ListView_InsertItem( GetDlgItem( hwndDlg, IDC_PHONES ), &lvi );
+ ListView_SetItemText( GetDlgItem( hwndDlg, IDC_PHONES ), lvi.iItem, 1, dbv.ptszVal );
+ JFreeVariant( &dbv );
+ lvi.iItem++;
+ }
+ lvi.mask = LVIF_PARAM;
+ lvi.lParam = ( LPARAM )( -1 );
+ ListView_InsertItem( GetDlgItem( hwndDlg, IDC_PHONES ), &lvi );
+ }
+ break;
+ case WM_NOTIFY:
+ switch (( ( LPNMHDR )lParam )->idFrom ) {
+ case IDC_EMAILS:
+ case IDC_PHONES:
+ switch (( ( LPNMHDR )lParam )->code ) {
+ case NM_CUSTOMDRAW:
+ {
+ NMLVCUSTOMDRAW *nm = ( NMLVCUSTOMDRAW * ) lParam;
+
+ switch ( nm->nmcd.dwDrawStage ) {
+ case CDDS_PREPAINT:
+ case CDDS_ITEMPREPAINT:
+ SetWindowLong( hwndDlg, DWL_MSGRESULT, CDRF_NOTIFYSUBITEMDRAW );
+ return TRUE;
+ case CDDS_SUBITEM|CDDS_ITEMPREPAINT:
+ {
+ RECT rc;
+ HICON hIcon;
+
+ ListView_GetSubItemRect( nm->nmcd.hdr.hwndFrom, nm->nmcd.dwItemSpec, nm->iSubItem, LVIR_LABEL, &rc );
+ if( nm->nmcd.lItemlParam==( LPARAM )( -1 ) && nm->iSubItem==3 )
+ hIcon = ( HICON )LoadImage( hInst, MAKEINTRESOURCE( IDI_ADDCONTACT ), IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), 0 );
+ else if ( nm->iSubItem==2 && nm->nmcd.lItemlParam!=( LPARAM )( -1 ))
+ hIcon = ( HICON )LoadImage( hInst, MAKEINTRESOURCE( IDI_EDIT ), IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), 0 );
+ else if ( nm->iSubItem==3 && nm->nmcd.lItemlParam!=( LPARAM )( -1 ))
+ hIcon = ( HICON )LoadImage( hInst, MAKEINTRESOURCE( IDI_DELETE ), IMAGE_ICON, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), 0 );
+ else break;
+ DrawIconEx( nm->nmcd.hdc, ( rc.left+rc.right-GetSystemMetrics( SM_CXSMICON ))/2, ( rc.top+rc.bottom-GetSystemMetrics( SM_CYSMICON ))/2,hIcon, GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), 0, NULL, DI_NORMAL );
+ DestroyIcon( hIcon );
+ SetWindowLong( hwndDlg, DWL_MSGRESULT, CDRF_SKIPDEFAULT );
+ }
+ return TRUE;
+ }
+ }
+ break;
+ case NM_CLICK:
+ {
+ NMLISTVIEW *nm = ( NMLISTVIEW * ) lParam;
+ LVITEM lvi;
+ const char* szIdTemplate = nm->hdr.idFrom==IDC_PHONES?"Phone%d":"e-mail%d";
+ const char* szFlagTemplate = nm->hdr.idFrom==IDC_PHONES?"PhoneFlag%d":"e-mailFlag%d";
+ LVHITTESTINFO hti;
+
+ if ( nm->iSubItem < 2 ) break;
+ hti.pt.x = ( short ) LOWORD( GetMessagePos());
+ hti.pt.y = ( short ) HIWORD( GetMessagePos());
+ ScreenToClient( nm->hdr.hwndFrom, &hti.pt );
+ if ( ListView_SubItemHitTest( nm->hdr.hwndFrom, &hti ) == -1 ) break;
+ lvi.mask = LVIF_PARAM;
+ lvi.iItem = hti.iItem;
+ lvi.iSubItem = 0;
+ ListView_GetItem( nm->hdr.hwndFrom, &lvi );
+ if ( lvi.lParam == ( LPARAM )( -1 )) {
+ if ( hti.iSubItem == 3 ) {
+ //add
+ if ( DialogBoxParam( hInst, MAKEINTRESOURCE( nm->hdr.idFrom==IDC_PHONES?IDD_VCARD_ADDPHONE:IDD_VCARD_ADDEMAIL ), hwndDlg, nm->hdr.idFrom==IDC_PHONES?EditPhoneDlgProc:EditEmailDlgProc, ( LPARAM )( -1 )) != IDOK )
+ break;
+ SendMessage( hwndDlg, M_REMAKELISTS, 0, 0 );
+ SendMessage( GetParent( hwndDlg ), WM_JABBER_CHANGED, 0, 0 );
+ }
+ }
+ else {
+ if ( hti.iSubItem == 3 ) {
+ //delete
+ int i;
+ char idstr[33];
+ DBVARIANT dbv;
+
+ for( i=lvi.lParam;;i++ ) {
+ WORD nFlag;
+
+ wsprintfA( idstr, szIdTemplate, i+1 );
+ if ( DBGetContactSetting( NULL, jabberProtoName, idstr, &dbv )) break;
+ wsprintfA( idstr,szIdTemplate,i );
+ JSetString( NULL, idstr, dbv.pszVal );
+ wsprintfA( idstr, szFlagTemplate, i+1 );
+ JFreeVariant( &dbv );
+ nFlag = JGetWord( NULL, idstr, 0 );
+ wsprintfA( idstr, szFlagTemplate, i );
+ JSetWord( NULL, idstr, nFlag );
+ }
+ wsprintfA( idstr, szIdTemplate, i );
+ JDeleteSetting( NULL, idstr );
+ wsprintfA( idstr, szFlagTemplate, i );
+ JDeleteSetting( NULL, idstr );
+ SendMessage( hwndDlg, M_REMAKELISTS, 0, 0 );
+ SendMessage( GetParent( hwndDlg ), WM_JABBER_CHANGED, 0, 0 );
+ }
+ else if ( hti.iSubItem == 2 ) {
+ //edit
+ if ( DialogBoxParam( hInst, MAKEINTRESOURCE( nm->hdr.idFrom==IDC_PHONES?IDD_VCARD_ADDPHONE:IDD_VCARD_ADDEMAIL ), hwndDlg, nm->hdr.idFrom==IDC_PHONES?EditPhoneDlgProc:EditEmailDlgProc, lvi.lParam ) != IDOK )
+ break;
+ SendMessage( hwndDlg,M_REMAKELISTS,0,0 );
+ SendMessage( GetParent( hwndDlg ), WM_JABBER_CHANGED, 0, 0 );
+ }
+ }
+ }
+ break;
+ }
+ break;
+ }
+ break;
+ case WM_SETCURSOR:
+ if ( LOWORD( lParam ) != HTCLIENT ) break;
+ if ( GetForegroundWindow() == GetParent( hwndDlg )) {
+ POINT pt;
+ GetCursorPos( &pt );
+ ScreenToClient( hwndDlg,&pt );
+ SetFocus( ChildWindowFromPoint( hwndDlg,pt )); //ugly hack because listviews ignore their first click
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static void SaveVcardToDB( VcardTab *dat )
+{
+ HWND hwndPage;
+ TCHAR text[2048];
+
+ if ( dat==NULL || dat->page==NULL ) return;
+
+ // Page 0: Personal
+ if (( hwndPage=dat->page[0].hwnd ) != NULL ) {
+ GetDlgItemText( hwndPage, IDC_FULLNAME, text, SIZEOF( text ));
+ JSetStringT( NULL, "FullName", text );
+ GetDlgItemText( hwndPage, IDC_NICKNAME, text, SIZEOF( text ));
+ JSetStringT( NULL, "Nick", text );
+ GetDlgItemText( hwndPage, IDC_FIRSTNAME, text, SIZEOF( text ));
+ JSetStringT( NULL, "FirstName", text );
+ GetDlgItemText( hwndPage, IDC_MIDDLE, text, SIZEOF( text ));
+ JSetStringT( NULL, "MiddleName", text );
+ GetDlgItemText( hwndPage, IDC_LASTNAME, text, SIZEOF( text ));
+ JSetStringT( NULL, "LastName", text );
+ GetDlgItemText( hwndPage, IDC_BIRTH, text, SIZEOF( text ));
+ JSetStringT( NULL, "BirthDate", text );
+ GetDlgItemText( hwndPage, IDC_GENDER, text, SIZEOF( text ));
+ JSetStringT( NULL, "GenderString", text );
+ GetDlgItemText( hwndPage, IDC_OCCUPATION, text, SIZEOF( text ));
+ JSetStringT( NULL, "Role", text );
+ GetDlgItemText( hwndPage, IDC_HOMEPAGE, text, SIZEOF( text ));
+ JSetStringT( NULL, "Homepage", text );
+ }
+ // Page 1: Contacts
+ // no need to save, always in sync with the DB
+ // Page 2: Home
+ if (( hwndPage=dat->page[2].hwnd ) != NULL ) {
+ GetDlgItemText( hwndPage, IDC_ADDRESS1, text, SIZEOF( text ));
+ JSetStringT( NULL, "Street", text );
+ GetDlgItemText( hwndPage, IDC_ADDRESS2, text, SIZEOF( text ));
+ JSetStringT( NULL, "Street2", text );
+ GetDlgItemText( hwndPage, IDC_CITY, text, SIZEOF( text ));
+ JSetStringT( NULL, "City", text );
+ GetDlgItemText( hwndPage, IDC_STATE, text, SIZEOF( text ));
+ JSetStringT( NULL, "State", text );
+ GetDlgItemText( hwndPage, IDC_ZIP, text, SIZEOF( text ));
+ JSetStringT( NULL, "ZIP", text );
+ GetDlgItemText( hwndPage, IDC_COUNTRY, text, SIZEOF( text ));
+ JSetStringT( NULL, "CountryName", text );
+ }
+ // Page 3: Work
+ if (( hwndPage=dat->page[3].hwnd ) != NULL ) {
+ GetDlgItemText( hwndPage, IDC_COMPANY, text, SIZEOF( text ));
+ JSetStringT( NULL, "Company", text );
+ GetDlgItemText( hwndPage, IDC_DEPARTMENT, text, SIZEOF( text ));
+ JSetStringT( NULL, "CompanyDepartment", text );
+ GetDlgItemText( hwndPage, IDC_TITLE, text, SIZEOF( text ));
+ JSetStringT( NULL, "CompanyPosition", text );
+ GetDlgItemText( hwndPage, IDC_ADDRESS1, text, SIZEOF( text ));
+ JSetStringT( NULL, "CompanyStreet", text );
+ GetDlgItemText( hwndPage, IDC_ADDRESS2, text, SIZEOF( text ));
+ JSetStringT( NULL, "CompanyStreet2", text );
+ GetDlgItemText( hwndPage, IDC_CITY, text, SIZEOF( text ));
+ JSetStringT( NULL, "CompanyCity", text );
+ GetDlgItemText( hwndPage, IDC_STATE, text, SIZEOF( text ));
+ JSetStringT( NULL, "CompanyState", text );
+ GetDlgItemText( hwndPage, IDC_ZIP, text, SIZEOF( text ));
+ JSetStringT( NULL, "CompanyZIP", text );
+ GetDlgItemText( hwndPage, IDC_COUNTRY, text, SIZEOF( text ));
+ JSetStringT( NULL, "CompanyCountryName", text );
+ }
+ // Page 4: Photo
+ // not saved in the database
+ // Page 5: Note
+ if (( hwndPage=dat->page[5].hwnd ) != NULL ) {
+ GetDlgItemText( hwndPage, IDC_DESC, text, SIZEOF( text ));
+ JSetStringT( NULL, "About", text );
+ }
+}
+
+static void AppendVcardFromDB( XmlNode* n, char* tag, char* key )
+{
+ if ( n == NULL || tag == NULL || key == NULL )
+ return;
+
+ DBVARIANT dbv;
+ if ( DBGetContactSettingTString( NULL, jabberProtoName, key, &dbv ))
+ n->addChild( tag );
+ else {
+ n->addChild( tag, dbv.ptszVal );
+ JFreeVariant( &dbv );
+} }
+
+static void SetServerVcard()
+{
+ DBVARIANT dbv;
+ int iqId;
+ char *szFileName, *szFileType;
+ int i;
+ char idstr[33];
+ WORD nFlag;
+
+ iqId = JabberSerialNext();
+ JabberIqAdd( iqId, IQ_PROC_SETVCARD, JabberIqResultSetVcard );
+
+ XmlNodeIq iq( "set", iqId );
+ XmlNode* v = iq.addChild( "vCard" ); v->addAttr( "xmlns", "vcard-temp" );
+
+ AppendVcardFromDB( v, "FN", "FullName" );
+
+ XmlNode* n = v->addChild( "N" );
+ AppendVcardFromDB( n, "GIVEN", "FirstName" );
+ AppendVcardFromDB( n, "MIDDLE", "MiddleName" );
+ AppendVcardFromDB( n, "FAMILY", "LastName" );
+
+ AppendVcardFromDB( v, "NICKNAME", "Nick" );
+ AppendVcardFromDB( v, "BDAY", "BirthDate" );
+ AppendVcardFromDB( v, "GENDER", "GenderString" );
+
+ for ( i=0;;i++ ) {
+ wsprintfA( idstr, "e-mail%d", i );
+ if ( DBGetContactSettingTString( NULL, jabberProtoName, idstr, &dbv ))
+ break;
+
+ XmlNode* e = v->addChild( "EMAIL", dbv.ptszVal );
+ JFreeVariant( &dbv );
+ AppendVcardFromDB( e, "USERID", idstr );
+
+ wsprintfA( idstr, "e-mailFlag%d", i );
+ nFlag = DBGetContactSettingWord( NULL, jabberProtoName, idstr, 0 );
+ if ( nFlag & JABBER_VCEMAIL_HOME ) e->addChild( "HOME" );
+ if ( nFlag & JABBER_VCEMAIL_WORK ) e->addChild( "WORK" );
+ if ( nFlag & JABBER_VCEMAIL_INTERNET ) e->addChild( "INTERNET" );
+ if ( nFlag & JABBER_VCEMAIL_X400 ) e->addChild( "X400" );
+ }
+
+ n = v->addChild( "ADR" );
+ n->addChild( "HOME" );
+ AppendVcardFromDB( n, "STREET", "Street" );
+ AppendVcardFromDB( n, "EXTADR", "Street2" );
+ AppendVcardFromDB( n, "EXTADD", "Street2" ); // for compatibility with client using old vcard format
+ AppendVcardFromDB( n, "LOCALITY", "City" );
+ AppendVcardFromDB( n, "REGION", "State" );
+ AppendVcardFromDB( n, "PCODE", "ZIP" );
+ AppendVcardFromDB( n, "CTRY", "CountryName" );
+ AppendVcardFromDB( n, "COUNTRY", "CountryName" ); // for compatibility with client using old vcard format
+
+ n = v->addChild( "ADR" );
+ n->addChild( "WORK" );
+ AppendVcardFromDB( n, "STREET", "CompanyStreet" );
+ AppendVcardFromDB( n, "EXTADR", "CompanyStreet2" );
+ AppendVcardFromDB( n, "EXTADD", "CompanyStreet2" ); // for compatibility with client using old vcard format
+ AppendVcardFromDB( n, "LOCALITY", "CompanyCity" );
+ AppendVcardFromDB( n, "REGION", "CompanyState" );
+ AppendVcardFromDB( n, "PCODE", "CompanyZIP" );
+ AppendVcardFromDB( n, "CTRY", "CompanyCountryName" );
+ AppendVcardFromDB( n, "COUNTRY", "CompanyCountryName" ); // for compatibility with client using old vcard format
+
+ n = v->addChild( "ORG" );
+ AppendVcardFromDB( n, "ORGNAME", "Company" );
+ AppendVcardFromDB( n, "ORGUNIT", "CompanyDepartment" );
+
+ AppendVcardFromDB( v, "TITLE", "CompanyPosition" );
+ AppendVcardFromDB( v, "ROLE", "Role" );
+ AppendVcardFromDB( v, "URL", "Homepage" );
+ AppendVcardFromDB( v, "DESC", "About" );
+
+ for ( i=0;;i++ ) {
+ wsprintfA( idstr, "Phone%d", i );
+ if ( DBGetContactSettingTString( NULL, jabberProtoName, idstr, &dbv )) break;
+ JFreeVariant( &dbv );
+
+ n = v->addChild( "TEL" );
+ AppendVcardFromDB( n, "NUMBER", idstr );
+
+ wsprintfA( idstr, "PhoneFlag%d", i );
+ nFlag = JGetWord( NULL, idstr, 0 );
+ if ( nFlag & JABBER_VCTEL_HOME ) n->addChild( "HOME" );
+ if ( nFlag & JABBER_VCTEL_WORK ) n->addChild( "WORK" );
+ if ( nFlag & JABBER_VCTEL_VOICE ) n->addChild( "VOICE" );
+ if ( nFlag & JABBER_VCTEL_FAX ) n->addChild( "FAX" );
+ if ( nFlag & JABBER_VCTEL_PAGER ) n->addChild( "PAGER" );
+ if ( nFlag & JABBER_VCTEL_MSG ) n->addChild( "MSG" );
+ if ( nFlag & JABBER_VCTEL_CELL ) n->addChild( "CELL" );
+ if ( nFlag & JABBER_VCTEL_VIDEO ) n->addChild( "VIDEO" );
+ if ( nFlag & JABBER_VCTEL_BBS ) n->addChild( "BBS" );
+ if ( nFlag & JABBER_VCTEL_MODEM ) n->addChild( "MODEM" );
+ if ( nFlag & JABBER_VCTEL_ISDN ) n->addChild( "ISDN" );
+ if ( nFlag & JABBER_VCTEL_PCS ) n->addChild( "PCS" );
+ }
+
+ if ( bPhotoChanged ) {
+ if ( szPhotoFileName[0] ) {
+ szFileName = szPhotoFileName;
+ szFileType = szPhotoType;
+ }
+ else szFileName = NULL;
+ }
+ else {
+ szFileName = jabberVcardPhotoFileName;
+ szFileType = jabberVcardPhotoType;
+ }
+
+ // Set photo element, also update the global jabberVcardPhotoFileName to reflect the update
+ JabberLog( "Before update, jabberVcardPhotoFileName = %s", jabberVcardPhotoFileName );
+ if ( szFileName == NULL ) {
+ v->addChild( "PHOTO" );
+ if ( jabberVcardPhotoFileName ) {
+ DeleteFileA( jabberVcardPhotoFileName );
+ mir_free( jabberVcardPhotoFileName );
+ jabberVcardPhotoFileName = NULL;
+ } }
+ else {
+ char szTempPath[MAX_PATH], szTempFileName[MAX_PATH];
+ HANDLE hFile;
+ struct _stat st;
+ char* buffer, *str;
+ DWORD nRead;
+
+ JabberLog( "Saving picture from %s", szFileName );
+ if ( _stat( szFileName, &st ) >= 0 ) {
+ // Note the FILE_SHARE_READ attribute so that the CopyFile can succeed
+ if (( hFile=CreateFileA( szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL )) != INVALID_HANDLE_VALUE ) {
+ if (( buffer=( char* )mir_alloc( st.st_size )) != NULL ) {
+ if ( ReadFile( hFile, buffer, st.st_size, &nRead, NULL )) {
+ if (( str=JabberBase64Encode( buffer, nRead )) != NULL ) {
+ n = v->addChild( "PHOTO" );
+ if ( szFileType ) {
+ n->addChild( "TYPE", szFileType );
+ JabberLog( "File type sent is %s", szFileType );
+ }
+ else {
+ n->addChild( "TYPE", "image/jpeg" );
+ JabberLog( "File type sent is default to image/jpge" );
+ }
+
+ n->addChild( "BINVAL", str );
+ mir_free( str );
+
+ if ( szFileName != jabberVcardPhotoFileName ) {
+ if ( jabberVcardPhotoFileName ) {
+ DeleteFileA( jabberVcardPhotoFileName );
+ mir_free( jabberVcardPhotoFileName );
+ jabberVcardPhotoFileName = NULL;
+ if ( jabberVcardPhotoType ) {
+ mir_free( jabberVcardPhotoType );
+ jabberVcardPhotoType = NULL;
+ } }
+
+ if ( GetTempPathA( sizeof( szTempPath ), szTempPath ) <= 0 )
+ strcpy( szTempPath, ".\\" );
+ if ( GetTempFileNameA( szTempPath, "jab", 0, szTempFileName ) > 0 ) {
+ JabberLog( "New global file is %s", szTempFileName );
+ if ( CopyFileA( szFileName, szTempFileName, FALSE ) == TRUE ) {
+ jabberVcardPhotoFileName = mir_strdup( szTempFileName );
+ if ( jabberVcardPhotoType ) mir_free( jabberVcardPhotoType );
+ if ( szFileType )
+ jabberVcardPhotoType = mir_strdup( szFileType );
+ else
+ jabberVcardPhotoType = NULL;
+ }
+ else DeleteFileA( szTempFileName );
+ } } } }
+ mir_free( buffer );
+ }
+ CloseHandle( hFile );
+ } } }
+
+ JabberSend( jabberThreadInfo->s, iq );
+}
+
+static void ThemeDialogBackground( HWND hwnd ) {
+ if ( IsWinVerXPPlus()) {
+ static HMODULE hThemeAPI = NULL;
+ if ( !hThemeAPI ) hThemeAPI = GetModuleHandleA( "uxtheme" );
+ if ( hThemeAPI ) {
+ HRESULT ( STDAPICALLTYPE *MyEnableThemeDialogTexture )( HWND,DWORD ) = ( HRESULT ( STDAPICALLTYPE* )( HWND,DWORD ))GetProcAddress( hThemeAPI,"EnableThemeDialogTexture" );
+ if ( MyEnableThemeDialogTexture )
+ MyEnableThemeDialogTexture( hwnd,0x00000002|0x00000004 ); //0x00000002|0x00000004=ETDT_ENABLETAB
+} } }
+
+static BOOL CALLBACK JabberVcardDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
+{
+ VcardTab* dat = ( VcardTab* ) GetWindowLong( hwndDlg, GWL_USERDATA );
+
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ {
+ SendMessage( hwndDlg, WM_SETICON, ICON_BIG, ( LPARAM )LoadIcon( hInst, MAKEINTRESOURCE( IDI_VCARD )) );
+ TranslateDialogDefault( hwndDlg );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_UPDATE ), jabberOnline );
+
+ dat = ( VcardTab * ) mir_alloc( sizeof( VcardTab ));
+ memset( dat, 0, sizeof( VcardTab ));
+ dat->pageCount = 6;
+ dat->currentPage = 0;
+ dat->changed = FALSE;
+ dat->updateAnimFrame = 0;
+ dat->animating = FALSE;
+ dat->page = ( VcardPage * ) mir_alloc( dat->pageCount * sizeof( VcardPage ));
+ memset( dat->page, 0, dat->pageCount * sizeof( VcardPage ));
+
+ HWND hwndTabs = GetDlgItem( hwndDlg, IDC_TABS );
+
+ TCITEM tci = { 0 };
+ tci.mask = TCIF_TEXT;
+ // Page 0: Personal
+ dat->page[0].dlgId = IDD_VCARD_PERSONAL;
+ dat->page[0].dlgProc = PersonalDlgProc;
+ tci.pszText = TranslateT( "Personal" );
+ TabCtrl_InsertItem( hwndTabs, 0, &tci );
+ // Page 1: Contacts
+ dat->page[1].dlgId = IDD_VCARD_CONTACT;
+ dat->page[1].dlgProc = ContactDlgProc;
+ tci.pszText = TranslateT( "Contacts" );
+ TabCtrl_InsertItem( hwndTabs, 1, &tci );
+ // Page 2: Home
+ dat->page[2].dlgId = IDD_VCARD_HOME;
+ dat->page[2].dlgProc = HomeDlgProc;
+ tci.pszText = TranslateT( "Home" );
+ TabCtrl_InsertItem( hwndTabs, 2, &tci );
+ // Page 3: Work
+ dat->page[3].dlgId = IDD_VCARD_WORK;
+ dat->page[3].dlgProc = WorkDlgProc;
+ tci.pszText = TranslateT( "Work" );
+ TabCtrl_InsertItem( hwndTabs, 3, &tci );
+ // Page 4: Photo
+ dat->page[4].dlgId = IDD_VCARD_PHOTO;
+ dat->page[4].dlgProc = PhotoDlgProc;
+ tci.pszText = TranslateT( "Photo" );
+ TabCtrl_InsertItem( hwndTabs, 4, &tci );
+ // Page 5: Note
+ dat->page[5].dlgId = IDD_VCARD_NOTE;
+ dat->page[5].dlgProc = NoteDlgProc;
+ tci.pszText = TranslateT( "Note" );
+ TabCtrl_InsertItem( hwndTabs, 5, &tci );
+
+ GetWindowRect( hwndTabs, &( dat->rectTab ));
+ TabCtrl_AdjustRect( hwndTabs, FALSE, &( dat->rectTab ));
+ { POINT pt = {0,0};
+ ClientToScreen( hwndDlg, &pt );
+ OffsetRect( &( dat->rectTab ), -pt.x, -pt.y );
+ }
+
+ TabCtrl_SetCurSel( hwndTabs, dat->currentPage );
+ dat->page[dat->currentPage].hwnd = CreateDialogParam( hInst, MAKEINTRESOURCE( dat->page[dat->currentPage].dlgId ), hwndDlg, dat->page[dat->currentPage].dlgProc, 0 );
+ ThemeDialogBackground( dat->page[dat->currentPage].hwnd );
+ SetWindowPos( dat->page[dat->currentPage].hwnd, HWND_TOP, dat->rectTab.left, dat->rectTab.top, 0, 0, SWP_NOSIZE );
+ ShowWindow( dat->page[dat->currentPage].hwnd, SW_SHOW );
+
+ SetWindowLong( hwndDlg, GWL_USERDATA, ( LONG ) dat );
+
+ bPhotoChanged = FALSE;
+ szPhotoFileName[0] = '\0';
+
+ if ( jabberOnline ) SendMessage( hwndDlg, WM_COMMAND, IDC_UPDATE, 0 );
+ return TRUE;
+ }
+ case WM_CTLCOLORSTATIC:
+ switch (GetDlgCtrlID((HWND)lParam)) {
+ case IDC_WHITERECT:
+ case IDC_LOGO:
+ case IDC_NAME:
+ case IDC_DESCRIPTION:
+ SetBkColor(( HDC ) wParam, RGB( 255, 255, 255 ));
+ return ( BOOL ) GetStockObject( WHITE_BRUSH );
+
+ case IDC_UPDATING:
+ SetBkColor(( HDC )wParam, GetSysColor( COLOR_3DFACE ));
+ return ( BOOL ) GetSysColorBrush( COLOR_3DFACE );
+ }
+ break;
+
+ case WM_NOTIFY:
+ switch ( wParam ) {
+ case IDC_TABS:
+ switch (( ( LPNMHDR ) lParam )->code ) {
+ case TCN_SELCHANGE:
+ if ( dat->currentPage>=0 && dat->page[dat->currentPage].hwnd!=NULL )
+ ShowWindow( dat->page[dat->currentPage].hwnd, SW_HIDE );
+ dat->currentPage = TabCtrl_GetCurSel( GetDlgItem( hwndDlg, IDC_TABS ));
+ if ( dat->currentPage >= 0 ) {
+ if ( dat->page[dat->currentPage].hwnd == NULL ) {
+ dat->page[dat->currentPage].hwnd = CreateDialogParam( hInst, MAKEINTRESOURCE( dat->page[dat->currentPage].dlgId ), hwndDlg, dat->page[dat->currentPage].dlgProc, 0 );
+ ThemeDialogBackground( dat->page[dat->currentPage].hwnd );
+ SetWindowPos( dat->page[dat->currentPage].hwnd, HWND_TOP, dat->rectTab.left, dat->rectTab.top, 0, 0, SWP_NOSIZE );
+ }
+ ShowWindow( dat->page[dat->currentPage].hwnd, SW_SHOW );
+ }
+ break;
+ }
+ break;
+ }
+ break;
+ case WM_JABBER_CHANGED:
+ dat->changed = TRUE;
+ EnableWindow( GetDlgItem( hwndDlg, IDC_SAVE ), jabberOnline );
+ break;
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDC_UPDATE:
+ EnableWindow( GetDlgItem( hwndDlg,IDC_UPDATE ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg,IDC_SAVE ), FALSE );
+ dat->szUpdating = TranslateT( "Updating" );
+ SetDlgItemText( hwndDlg, IDC_UPDATING, dat->szUpdating );
+ ShowWindow( GetDlgItem( hwndDlg, IDC_UPDATING ), SW_SHOW );
+ JabberSendGetVcard( jabberJID );
+ dat->animating = TRUE;
+ SetTimer( hwndDlg, 1, 200, NULL );
+ break;
+ case IDC_SAVE:
+ EnableWindow( GetDlgItem( hwndDlg,IDC_UPDATE ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg,IDC_SAVE ), FALSE );
+ dat->szUpdating = TranslateT( "Saving" );
+ SetDlgItemText( hwndDlg, IDC_UPDATING, dat->szUpdating );
+ ShowWindow( GetDlgItem( hwndDlg, IDC_UPDATING ), SW_SHOW );
+ dat->animating = TRUE;
+ SetTimer( hwndDlg, 1, 200, NULL );
+ SaveVcardToDB( dat );
+ SetServerVcard();
+ break;
+ case IDCLOSE:
+ DestroyWindow( hwndDlg );
+ break;
+ }
+ break;
+ case WM_TIMER:
+ { TCHAR str[128];
+ mir_sntprintf( str, SIZEOF(str), _T("%.*s%s%.*s"), dat->updateAnimFrame%5, _T("...."), dat->szUpdating, dat->updateAnimFrame%5, _T("...."));
+ SetDlgItemText( hwndDlg, IDC_UPDATING, str );
+ if (( ++dat->updateAnimFrame ) >= 5 ) dat->updateAnimFrame = 0;
+ }
+ break;
+ case WM_JABBER_CHECK_ONLINE:
+ EnableWindow( GetDlgItem( hwndDlg, IDC_UPDATE ), jabberOnline );
+ if ( dat->changed )
+ EnableWindow( GetDlgItem( hwndDlg, IDC_SAVE ), jabberOnline );
+ break;
+ case WM_JABBER_REFRESH:
+ if ( dat->animating ) {
+ KillTimer( hwndDlg, 1 );
+ dat->animating = FALSE;
+ ShowWindow( GetDlgItem( hwndDlg, IDC_UPDATING ), FALSE );
+ }
+ { for ( int i=0; i<dat->pageCount; i++ )
+ if ( dat->page[i].hwnd != NULL )
+ SendMessage( dat->page[i].hwnd, WM_JABBER_REFRESH, 0, 0 );
+ }
+ dat->changed = FALSE;
+ EnableWindow( GetDlgItem( hwndDlg, IDC_UPDATE ), TRUE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_SAVE ), FALSE );
+ break;
+ case WM_CLOSE:
+ DestroyWindow( hwndDlg );
+ break;
+ case WM_DESTROY:
+ hwndJabberVcard = NULL;
+ for ( int i=0; i<dat->pageCount; i++ )
+ if ( dat->page[i].hwnd != NULL )
+ DestroyWindow( dat->page[i].hwnd );
+
+ if ( dat->page ) mir_free( dat->page );
+ if ( dat ) mir_free( dat );
+ break;
+ }
+ return FALSE;
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_ws.cpp b/miranda-wine/protocols/JabberG/jabber_ws.cpp new file mode 100644 index 0000000..a2bd1d1 --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_ws.cpp @@ -0,0 +1,92 @@ +/*
+
+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_ws.cpp,v $
+Revision : $Revision: 2866 $
+Last change on : $Date: 2006-05-16 20:39:40 +0400 (Втр, 16 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+
+BOOL JabberWsInit( void )
+{
+ NETLIBUSER nlu = {0};
+ char name[128];
+
+ sprintf( name, "%s %s", jabberModuleName, JTranslate( "connection" ));
+
+ nlu.cbSize = sizeof( nlu );
+ nlu.flags = NUF_OUTGOING | NUF_INCOMING | NUF_HTTPCONNS; // | NUF_HTTPGATEWAY;
+ nlu.szDescriptiveName = name;
+ nlu.szSettingsModule = jabberProtoName;
+ //nlu.szHttpGatewayHello = "http://http.proxy.icq.com/hello";
+ //nlu.szHttpGatewayUserAgent = "Mozilla/4.08 [en] ( WinNT; U ;Nav )";
+ //nlu.pfnHttpGatewayInit = JabberHttpGatewayInit;
+ //nlu.pfnHttpGatewayBegin = JabberHttpGatewayBegin;
+ //nlu.pfnHttpGatewayWrapSend = JabberHttpGatewayWrapSend;
+ //nlu.pfnHttpGatewayUnwrapRecv = JabberHttpGatewayUnwrapRecv;
+ hNetlibUser = ( HANDLE ) JCallService( MS_NETLIB_REGISTERUSER, 0, ( LPARAM )&nlu );
+
+ return ( hNetlibUser!=NULL )?TRUE:FALSE;
+}
+
+void JabberWsUninit( void )
+{
+ Netlib_CloseHandle( hNetlibUser );
+ hNetlibUser = NULL;
+}
+
+JABBER_SOCKET JabberWsConnect( char* host, WORD port )
+{
+ NETLIBOPENCONNECTION nloc = { 0 };
+ nloc.cbSize = sizeof( nloc );
+ nloc.szHost = host;
+ nloc.wPort = port;
+ return ( HANDLE )JCallService( MS_NETLIB_OPENCONNECTION, ( WPARAM ) hNetlibUser, ( LPARAM )&nloc );
+}
+
+int JabberWsSend( JABBER_SOCKET hConn, char* data, int datalen )
+{
+ int len;
+
+ if (( len=Netlib_Send( hConn, data, datalen, MSG_DUMPASTEXT ))==SOCKET_ERROR || len!=datalen ) {
+ JabberLog( "Netlib_Send() failed, error=%d", WSAGetLastError());
+ return FALSE;
+ }
+ return TRUE;
+}
+
+int JabberWsRecv( JABBER_SOCKET hConn, char* data, long datalen )
+{
+ int ret;
+
+ ret = Netlib_Recv( hConn, data, datalen, MSG_DUMPASTEXT );
+ if( ret == SOCKET_ERROR ) {
+ JabberLog( "Netlib_Recv() failed, error=%d", WSAGetLastError());
+ return 0;
+ }
+ if( ret == 0 ) {
+ JabberLog( "Connection closed gracefully" );
+ return 0;
+ }
+ return ret;
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_xml.cpp b/miranda-wine/protocols/JabberG/jabber_xml.cpp new file mode 100644 index 0000000..d3bd155 --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_xml.cpp @@ -0,0 +1,786 @@ +/*
+
+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_xml.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"
+
+static BOOL JabberXmlProcessElem( XmlState *xmlState, XmlElemType elemType, char* elemText, char* elemAttr );
+static void JabberXmlRemoveChild( XmlNode *node, XmlNode *child );
+
+void JabberXmlInitState( XmlState *xmlState )
+{
+ if ( xmlState == NULL ) return;
+ xmlState->root.name = NULL;
+ xmlState->root.depth = 0;
+ xmlState->root.numAttr = 0;
+ xmlState->root.maxNumAttr = 0;
+ xmlState->root.attr = NULL;
+ xmlState->root.numChild = 0;
+ xmlState->root.maxNumChild = 0;
+ xmlState->root.child = NULL;
+ xmlState->root.text = NULL;
+ xmlState->root.state = NODE_OPEN;
+ xmlState->callback1_open = NULL;
+ xmlState->callback1_close = NULL;
+ xmlState->callback2_open = NULL;
+ xmlState->callback2_close = NULL;
+ xmlState->userdata1_open = NULL;
+ xmlState->userdata1_close = NULL;
+ xmlState->userdata2_open = NULL;
+ xmlState->userdata2_close = NULL;
+}
+
+void JabberXmlDestroyState( XmlState *xmlState )
+{
+ int i;
+ XmlNode *node;
+
+ if ( xmlState == NULL ) return;
+ // Note: cannot use JabberXmlFreeNode() to mir_free xmlState->root
+ // because it will do mir_free( xmlState->root ) which is not freeable.
+ node = &( xmlState->root );
+
+ // Free all children first
+ for ( i=0; i<node->numChild; i++ )
+ delete node->child[i];
+ if ( node->child ) mir_free( node->child );
+
+ // Free all attributes
+ for ( i=0; i<node->numAttr; i++ )
+ delete node->attr[i];
+ if ( node->attr ) mir_free( node->attr );
+
+ // Free string field
+ if ( node->text ) mir_free( node->text );
+ if ( node->name ) mir_free( node->name );
+
+ memset( xmlState, 0, sizeof( XmlState ));
+}
+
+BOOL JabberXmlSetCallback( XmlState *xmlState, int depth, XmlElemType type, JABBER_XML_CALLBACK callback, void *userdata )
+{
+ if ( depth==1 && type==ELEM_OPEN ) {
+ xmlState->callback1_open = callback;
+ xmlState->userdata1_open = userdata;
+ }
+ else if ( depth==1 && type==ELEM_CLOSE ) {
+ xmlState->callback1_close = callback;
+ xmlState->userdata1_close = userdata;
+ }
+ else if ( depth==2 && type==ELEM_OPEN ) {
+ xmlState->callback2_open = callback;
+ xmlState->userdata2_open = userdata;
+ }
+ else if ( depth==2 && type==ELEM_CLOSE ) {
+ xmlState->callback2_close = callback;
+ xmlState->userdata2_close = userdata;
+ }
+ else
+ return FALSE;
+
+ return TRUE;
+}
+
+#define TAG_MAX_LEN 50
+#define ATTR_MAX_LEN 1024
+
+static char* skipSpaces( char* p, int* num = NULL )
+{
+ int i;
+
+ for ( i=0; *p != 0 && isspace( BYTE( *p )); i++ )
+ p++;
+
+ if ( num != NULL )
+ num += i;
+ return p;
+}
+
+static char* findClose( char* p )
+{
+ while ( *p != 0 ) {
+ switch( *p ) {
+ case '>': return p;
+
+ case '\'':
+ case '\"':
+ p = strchr( p+1, *p );
+ if ( p == NULL )
+ return NULL;
+ }
+
+ p++;
+ }
+
+ return NULL;
+}
+
+int JabberXmlParse( XmlState *xmlState, char* buffer )
+{
+ char* r;
+ int num = 0;
+ char tag[TAG_MAX_LEN];
+ char attr[ATTR_MAX_LEN];
+ XmlElemType elemType;
+
+ char* p = skipSpaces( buffer, &num );
+
+ while ( *p != 0 ) {
+ // found starting bracket
+ if ( *p == '<' ) {
+ if ( memcmp( p, "<!--", 4 ) == 0 ) {
+ char* q = strstr( p+4, "-->" );
+ if ( q == NULL )
+ break;
+
+ p = q+3;
+ continue;
+ }
+
+ char* q = findClose( p+1 );
+ if ( q == NULL )
+ break;
+
+ // found closing bracket
+ for ( r=p+1; *r!='>' && *r!=' ' && *r!='\t'; r++ );
+ if ( r-( p+1 ) > TAG_MAX_LEN ) {
+ JabberLog( "TAG_MAX_LEN too small, ignore current tag" );
+ }
+ else {
+ if ( *( p+1 ) == '/' ) { // closing tag
+ strncpy( tag, p+2, r-( p+2 ));
+ tag[r-( p+2 )] = '\0';
+ elemType = ELEM_CLOSE;
+ }
+ else {
+ if ( *( r-1 ) == '/' ) { // single open/close tag
+ strncpy( tag, p+1, r-( p+1 )-1 );
+ tag[r-( p+1 )-1] = '\0';
+ elemType = ELEM_OPENCLOSE;
+ }
+ else {
+ strncpy( tag, p+1, r-( p+1 ));
+ tag[r-( p+1 )] = '\0';
+ elemType = ELEM_OPEN;
+ }
+ }
+ for ( ;r<q && ( *r==' ' || *r=='\t' ); r++ );
+ if ( q-r > ATTR_MAX_LEN ) {
+ JabberLog( "ATTR_MAX_LEN too small, ignore current tag" );
+ }
+ else {
+ strncpy( attr, r, q-r );
+ if (( q-r )>0 && attr[q-r-1]=='/' ) {
+ attr[q-r-1] = '\0';
+ elemType = ELEM_OPENCLOSE;
+ }
+ else
+ attr[q-r] = '\0';
+ JabberXmlProcessElem( xmlState, elemType, tag, attr );
+ }
+ }
+ num += ( q-p+1 );
+ p = q + 1;
+ if ( elemType==ELEM_CLOSE || elemType==ELEM_OPENCLOSE )
+ p = skipSpaces( p, &num ); // Skip whitespaces after end tags
+ }
+ else { // found inner text
+ char* q = strchr( p+1, '<' );
+ if ( q == NULL )
+ break;
+
+ // found starting bracket of the next element
+ char* str = ( char* )mir_alloc( q-p+1 );
+ strncpy( str, p, q-p );
+ str[q-p] = '\0';
+ JabberXmlProcessElem( xmlState, ELEM_TEXT, str, NULL );
+ mir_free( str );
+ num += ( q-p );
+ p = q;
+ } }
+
+ return num;
+}
+
+static void JabberXmlParseAttr( XmlNode *node, char* text )
+{
+ char* kstart, *vstart;
+ int klen, vlen;
+ char* p;
+ XmlAttr *a;
+
+ if ( node==NULL || text==NULL || strlen( text )<=0 )
+ return;
+
+ for ( p=text;; ) {
+
+ // Skip leading whitespaces
+ p = skipSpaces( p );
+ if ( *p == '\0' )
+ break;
+
+ // Fetch key
+ kstart = p;
+ for ( ;*p!='\0' && *p!='=' && *p!=' ' && *p!='\t'; p++ );
+ klen = p-kstart;
+
+ if ( node->numAttr >= node->maxNumAttr ) {
+ node->maxNumAttr = node->numAttr + 20;
+ node->attr = ( XmlAttr ** ) mir_realloc( node->attr, node->maxNumAttr*sizeof( XmlAttr * ));
+ }
+ a = node->attr[node->numAttr] = new XmlAttr();
+ node->numAttr++;
+
+ // Skip possible whitespaces between key and '='
+ p = skipSpaces( p );
+
+ if ( *p == '\0' ) {
+ a->name = ( char* )mir_alloc( klen+1 );
+ strncpy( a->name, kstart, klen );
+ a->name[klen] = '\0';
+ a->value = mir_tstrdup( _T(""));
+ break;
+ }
+
+ if ( *p != '=' ) {
+ a->name = ( char* )mir_alloc( klen+1 );
+ strncpy( a->name, kstart, klen );
+ a->name[klen] = '\0';
+ a->value = mir_tstrdup( _T(""));
+ continue;
+ }
+
+ // Found '='
+ p++;
+
+ // Skip possible whitespaces between '=' and value
+ p = skipSpaces( p );
+
+ if ( *p == '\0' ) {
+ a->name = ( char* )mir_alloc( klen+1 );
+ strncpy( a->name, kstart, klen );
+ a->name[klen] = '\0';
+ a->value = mir_tstrdup( _T(""));
+ break;
+ }
+
+ // Fetch value
+ if ( *p=='\'' || *p=='"' ) {
+ p++;
+ vstart = p;
+ for ( ;*p!='\0' && *p!=*( vstart-1 ); p++ );
+ vlen = p-vstart;
+ if ( *p != '\0' ) p++;
+ }
+ else {
+ vstart = p;
+ for ( ;*p!='\0' && *p!=' ' && *p!='\t'; p++ );
+ vlen = p-vstart;
+ }
+
+ a->name = ( char* )mir_alloc( klen+1 );
+ strncpy( a->name, kstart, klen );
+ a->name[klen] = '\0';
+
+ JabberUtfToTchar( vstart, vlen, a->value );
+ }
+}
+
+static BOOL JabberXmlProcessElem( XmlState *xmlState, XmlElemType elemType, char* elemText, char* elemAttr )
+{
+ XmlNode *node, *parentNode, *n;
+ BOOL activateCallback = FALSE;
+ char* text, *attr;
+
+ if ( elemText == NULL ) return FALSE;
+
+ if ( elemType==ELEM_OPEN && !strcmp( elemText, "?xml" )) {
+ JabberLog( "XML: skip <?xml> tag" );
+ return TRUE;
+ }
+
+ // Find active node
+ node = &( xmlState->root );
+ parentNode = NULL;
+ while ( node->numChild>0 && node->child[node->numChild-1]->state==NODE_OPEN ) {
+ parentNode = node;
+ node = node->child[node->numChild-1];
+ }
+
+ if ( node->state != NODE_OPEN ) return FALSE;
+
+ text = NEWSTR_ALLOCA( elemText );
+
+ if ( elemAttr )
+ attr = NEWSTR_ALLOCA( elemAttr );
+ else
+ attr = NULL;
+
+ switch ( elemType ) {
+ case ELEM_OPEN:
+ if ( node->numChild >= node->maxNumChild ) {
+ node->maxNumChild = node->numChild + 20;
+ node->child = ( XmlNode ** ) mir_realloc( node->child, node->maxNumChild*sizeof( XmlNode * ));
+ }
+ n = node->child[node->numChild] = new XmlNode(text);
+ node->numChild++;
+ n->depth = node->depth + 1;
+ n->state = NODE_OPEN;
+ n->numChild = n->maxNumChild = 0;
+ n->child = NULL;
+ n->numAttr = n->maxNumAttr = 0;
+ n->attr = NULL;
+ JabberXmlParseAttr( n, attr );
+ n->text = NULL;
+ if ( n->depth==1 && xmlState->callback1_open!=NULL )
+ ( *( xmlState->callback1_open ))( n, xmlState->userdata1_open );
+ if ( n->depth==2 && xmlState->callback2_open!=NULL )
+ ( *xmlState->callback2_open )( n, xmlState->userdata2_open );
+ break;
+ case ELEM_OPENCLOSE:
+ if ( node->numChild >= node->maxNumChild ) {
+ node->maxNumChild = node->numChild + 20;
+ node->child = ( XmlNode ** ) mir_realloc( node->child, node->maxNumChild*sizeof( XmlNode * ));
+ }
+ n = node->child[node->numChild] = new XmlNode( text );
+ node->numChild++;
+ n->depth = node->depth + 1;
+ n->state = NODE_CLOSE;
+ n->numChild = n->maxNumAttr = 0;
+ n->child = NULL;
+ n->numAttr = n->maxNumAttr = 0;
+ n->attr = NULL;
+ JabberXmlParseAttr( n, attr );
+ n->text = NULL;
+ if ( n->depth==1 && xmlState->callback1_close!=NULL ) {
+ ( *( xmlState->callback1_close ))( n, xmlState->userdata1_close );
+ JabberXmlRemoveChild( node, n );
+ }
+ if ( n->depth==2 && xmlState->callback2_close!=NULL ) {
+ ( *xmlState->callback2_close )( n, xmlState->userdata2_close );
+ JabberXmlRemoveChild( node, n );
+ }
+ break;
+ case ELEM_CLOSE:
+ if ( node->name!=NULL && !strcmp( node->name, text )) {
+ node->state = NODE_CLOSE;
+ if ( node->depth==1 && xmlState->callback1_close!=NULL ) {
+ ( *( xmlState->callback1_close ))( node, xmlState->userdata1_close );
+ JabberXmlRemoveChild( parentNode, node );
+ }
+ else if ( node->depth==2 && xmlState->callback2_close!=NULL ) {
+ ( *xmlState->callback2_close )( node, xmlState->userdata2_close );
+ JabberXmlRemoveChild( parentNode, node );
+ } }
+ else {
+ JabberLog( "XML: Closing </%s> without opening tag", text );
+ return FALSE;
+ }
+ break;
+ case ELEM_TEXT:
+ JabberUtfToTchar( text, strlen( text ), node->text );
+ break;
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+TCHAR* JabberXmlGetAttrValue( XmlNode *node, char* key )
+{
+ if ( node==NULL || node->numAttr<=0 || key==NULL || strlen( key )<=0 )
+ return NULL;
+
+ for ( int i=0; i<node->numAttr; i++ )
+ if ( !lstrcmpA( key, node->attr[i]->name ))
+ return node->attr[i]->value;
+
+ return NULL;
+}
+
+XmlNode *JabberXmlGetChild( XmlNode *node, char* tag )
+{
+ return JabberXmlGetNthChild( node, tag, 1 );
+}
+
+XmlNode *JabberXmlGetNthChild( XmlNode *node, char* tag, int nth )
+{
+ int i, num;
+
+ if ( node==NULL || node->numChild<=0 || tag==NULL || strlen( tag )<=0 || nth<1 )
+ return NULL;
+ num = 1;
+ for ( i=0; i<node->numChild; i++ ) {
+ if ( node->child[i]->name && !strcmp( tag, node->child[i]->name )) {
+ if ( num == nth ) {
+ return node->child[i];
+ }
+ num++;
+ }
+ }
+ return NULL;
+}
+
+XmlNode *JabberXmlGetChildWithGivenAttrValue( XmlNode *node, char* tag, char* attrKey, TCHAR* attrValue )
+{
+ if ( node==NULL || node->numChild<=0 || tag==NULL || strlen( tag )<=0 || attrKey==NULL || strlen( attrKey )<=0 || attrValue==NULL || lstrlen( attrValue )<=0 )
+ return NULL;
+
+ TCHAR* str;
+ for ( int i=0; i<node->numChild; i++ )
+ if ( node->child[i]->name && !strcmp( tag, node->child[i]->name ))
+ if (( str=JabberXmlGetAttrValue( node->child[i], attrKey )) != NULL )
+ if ( !lstrcmp( str, attrValue ))
+ return node->child[i];
+
+ return NULL;
+}
+
+static void JabberXmlRemoveChild( XmlNode *node, XmlNode *child )
+{
+ int i;
+
+ if ( node==NULL || child==NULL || node->numChild<=0 ) return;
+ for ( i=0; i<node->numChild; i++ ) {
+ if ( node->child[i] == child )
+ break;
+ }
+ if ( i < node->numChild ) {
+ for ( ++i; i<node->numChild; i++ )
+ node->child[i-1] = node->child[i];
+ node->numChild--;
+ delete child;
+ }
+}
+
+XmlNode *JabberXmlCopyNode( XmlNode *node )
+{
+ if ( node == NULL )
+ return NULL;
+
+ XmlNode *n = new XmlNode( node->name );
+ // Copy attributes
+ if ( node->numAttr > 0 ) {
+ n->attr = ( XmlAttr ** ) mir_alloc( node->numAttr*sizeof( XmlAttr * ));
+ for ( int i=0; i < node->numAttr; i++ ) {
+ n->attr[i] = new XmlAttr;
+ if ( node->attr[i]->name )
+ n->attr[i]->name = mir_strdup( node->attr[i]->name );
+ if ( node->attr[i]->value )
+ n->attr[i]->value = mir_tstrdup( node->attr[i]->value );
+ }
+ }
+ else
+ n->attr = NULL;
+ // Recursively copy children
+ if ( node->numChild > 0 ) {
+ n->child = ( XmlNode ** ) mir_alloc( node->numChild*sizeof( XmlNode * ));
+ for ( int i=0; i<node->numChild; i++ )
+ n->child[i] = JabberXmlCopyNode( node->child[i] );
+ }
+ else
+ n->child = NULL;
+ // Copy other fields
+ n->numAttr = node->numAttr;
+ n->maxNumAttr = node->numAttr;
+ n->numChild = node->numChild;
+ n->maxNumChild = node->numChild;
+ n->depth = node->depth;
+ n->state = node->state;
+ n->text = ( node->text )?mir_tstrdup( node->text ):NULL;
+ return n;
+}
+
+XmlNode *JabberXmlAddChild( XmlNode *n, char* name )
+{
+ if ( n==NULL || name==NULL )
+ return NULL;
+
+ XmlNode* result = new XmlNode( name );
+ if ( result == NULL )
+ return NULL;
+
+ return n->addChild( result );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// XmlNodeIq class members
+
+XmlNodeIq::XmlNodeIq( const char* type, int id, const TCHAR* to ) :
+ XmlNode( "iq" )
+{
+ if ( type != NULL ) addAttr( "type", type );
+ if ( to != NULL ) addAttr( "to", to );
+ if ( id != NOID ) addAttrID( id );
+}
+
+XmlNodeIq::XmlNodeIq( const char* type, const TCHAR* idStr, const TCHAR* to ) :
+ XmlNode( "iq" )
+{
+ if ( type != NULL ) addAttr( "type", type );
+ if ( to != NULL ) addAttr( "to", to );
+ if ( idStr != NULL ) addAttr( "id", idStr );
+}
+
+#if defined( _UNICODE )
+XmlNodeIq::XmlNodeIq( const char* type, int id, const char* to ) :
+ XmlNode( "iq" )
+{
+ if ( type != NULL ) addAttr( "type", type );
+ if ( to != NULL ) addAttr( "to", to );
+ if ( id != NOID ) addAttrID( id );
+}
+#endif
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// XmlNode class members
+
+XmlNode::XmlNode( const char* pszName )
+{
+ memset( this, 0, sizeof( XmlNode ));
+ name = mir_strdup( pszName );
+}
+
+XmlNode::XmlNode( const char* pszName, const TCHAR* ptszText )
+{
+ memset( this, 0, sizeof( XmlNode ));
+ name = mir_strdup( pszName );
+ #if defined( _UNICODE )
+ sendText = JabberTextEncodeW( ptszText );
+ #else
+ sendText = JabberTextEncode( ptszText );
+ #endif
+}
+
+#if defined( _UNICODE )
+XmlNode::XmlNode( const char* pszName, const char* ptszText )
+{
+ memset( this, 0, sizeof( XmlNode ));
+ name = mir_strdup( pszName );
+ sendText = JabberTextEncode( ptszText );
+}
+#endif
+
+XmlNode::~XmlNode()
+{
+ if ( this == NULL ) return;
+
+ // Free all children first
+ int i;
+ for ( i=0; i < numChild; i++ )
+ delete child[i];
+ if ( child ) mir_free( child );
+
+ // Free all attributes
+ for ( i=0; i < numAttr; i++ )
+ delete attr[i];
+ if ( attr ) mir_free( attr );
+
+ // Free string field
+ if ( text ) mir_free( text );
+ if ( name ) mir_free( name );
+}
+
+XmlAttr* XmlNode::addAttr( XmlAttr* a )
+{
+ if ( this == NULL || a == NULL )
+ return NULL;
+
+ int i = numAttr++;
+ attr = ( XmlAttr ** ) mir_realloc( attr, sizeof( XmlAttr * ) * numAttr );
+ attr[i] = a;
+ return a;
+}
+
+XmlAttr* XmlNode::addAttr( const char* pszName, const TCHAR* ptszValue )
+{
+ return addAttr( new XmlAttr( pszName, ptszValue ));
+}
+
+#if defined( _UNICODE )
+XmlAttr* XmlNode::addAttr( const char* pszName, const char* pszValue )
+{
+ return addAttr( new XmlAttr( pszName, pszValue ));
+}
+#endif
+
+XmlAttr* XmlNode::addAttr( const char* pszName, int value )
+{
+ if ( this == NULL )
+ return NULL;
+
+ TCHAR buf[ 40 ];
+ _itot( value, buf, 10 );
+ return addAttr( new XmlAttr( pszName, buf ));
+}
+
+XmlAttr* XmlNode::addAttrID( int id )
+{
+ if ( this == NULL )
+ return NULL;
+
+ TCHAR text[ 100 ];
+ mir_sntprintf( text, SIZEOF(text), _T("mir_%d"), id );
+ return addAttr( new XmlAttr( "id", text ));
+}
+
+XmlNode* XmlNode::addChild( XmlNode* pNode )
+{
+ if ( this == NULL || pNode == NULL )
+ return NULL;
+
+ int i = numChild++;
+ child = ( XmlNode ** ) mir_realloc( child, sizeof( XmlNode * ) * numChild );
+ child[i] = pNode;
+ pNode->depth = depth+1;
+ return pNode;
+}
+
+XmlNode* XmlNode::addChild( const char* pszName )
+{
+ return addChild( new XmlNode( pszName ));
+}
+
+XmlNode* XmlNode::addChild( const char* pszName, const TCHAR* ptszValue )
+{
+ return addChild( new XmlNode( pszName, ptszValue ));
+}
+
+#if defined( _UNICODE )
+XmlNode* XmlNode::addChild( const char* pszName, const char* pszValue )
+{
+ return addChild( new XmlNode( pszName, pszValue ));
+}
+#endif
+
+XmlNode* XmlNode::addQuery( const char* szNameSpace )
+{
+ XmlNode* n = addChild( "query" );
+ if ( n )
+ n->addAttr( "xmlns", szNameSpace );
+ return n;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// text extraction routines
+
+static char* sttCopyNode( const XmlNode* n, char* dest )
+{
+ if ( n->props ) {
+ lstrcpyA( dest, n->props ); dest += lstrlenA( n->props );
+ }
+
+ *dest++ = '<';
+ lstrcpyA( dest, n->name ); dest += lstrlenA( n->name );
+
+ for ( int i=0; i < n->numAttr; i++ ) {
+ *dest++ = ' ';
+ lstrcpyA( dest, n->attr[i]->name ); dest += lstrlenA( n->attr[i]->name );
+ *dest++ = '=';
+ *dest++ = '\'';
+ lstrcpyA( dest, n->attr[i]->sendValue ); dest += lstrlenA( n->attr[i]->sendValue );
+ *dest++ = '\'';
+ }
+
+ if ( n->numChild != 0 || n->sendText != NULL )
+ *dest++ = '>';
+
+ if ( n->sendText != NULL ) {
+ lstrcpyA( dest, n->sendText ); dest += lstrlenA( n->sendText );
+ }
+
+ if ( n->numChild != 0 )
+ for ( int i=0; i < n->numChild; i++ )
+ dest = sttCopyNode( n->child[i], dest );
+
+ if ( n->numChild != 0 || n->sendText != NULL ) {
+ *dest++ = '<';
+ *dest++ = '/';
+ lstrcpyA( dest, n->name ); dest += lstrlenA( n->name );
+ }
+ else if ( !n->dirtyHack ) *dest++ = '/';
+
+ *dest++ = '>';
+ *dest = 0;
+ return dest;
+}
+
+char* XmlNode::getText() const
+{
+ int cbLen = getTextLen();
+ char* result = ( char* )mir_alloc( cbLen+1 );
+ if ( result == NULL )
+ return NULL;
+
+ sttCopyNode( this, result );
+ return result;
+}
+
+int XmlNode::getTextLen() const
+{
+ int result = 10 + lstrlenA( props ) + lstrlenA( name )*2 + lstrlenA( sendText );
+
+ for ( int i=0; i < numAttr; i++ )
+ result += lstrlenA( attr[i]->name ) + lstrlenA( attr[i]->sendValue ) + 4;
+
+ for ( int j=0; j < numChild; j++ )
+ result += child[j]->getTextLen();
+
+ return result;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// XmlAttr class members
+
+XmlAttr::XmlAttr() :
+ name( NULL ), value( NULL )
+{
+}
+
+XmlAttr::XmlAttr( const char* pszName, const TCHAR* ptszValue )
+{
+ name = mir_strdup( pszName );
+ #if defined( _UNICODE )
+ sendValue = JabberTextEncodeW( ptszValue );
+ #else
+ sendValue = JabberTextEncode( ptszValue );
+ #endif
+}
+
+#if defined( _UNICODE )
+XmlAttr::XmlAttr( const char* pszName, const char* ptszValue )
+{
+ name = mir_strdup( pszName );
+ sendValue = JabberTextEncode( ptszValue );
+}
+#endif
+
+XmlAttr::~XmlAttr()
+{
+ if ( name != NULL ) mir_free( name );
+ if ( value != NULL ) mir_free( value );
+}
diff --git a/miranda-wine/protocols/JabberG/jabber_xml.h b/miranda-wine/protocols/JabberG/jabber_xml.h new file mode 100644 index 0000000..50e3268 --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_xml.h @@ -0,0 +1,152 @@ +/*
+
+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_xml.h,v $
+Revision : $Revision: 3691 $
+Last change on : $Date: 2006-09-04 10:04:06 +0400 (Пнд, 04 Сен 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#ifndef _JABBER_XML_H_
+#define _JABBER_XML_H_
+
+#define NOID (-1)
+
+typedef enum { ELEM_OPEN, ELEM_CLOSE, ELEM_OPENCLOSE, ELEM_TEXT } XmlElemType;
+typedef enum { NODE_OPEN, NODE_CLOSE } XmlNodeType;
+
+struct XmlAttr
+{
+ XmlAttr();
+ XmlAttr( const char* pszName, const TCHAR* ptszValue );
+ #if defined( _UNICODE )
+ XmlAttr( const char* pszName, const char* ptszValue );
+ #endif
+ ~XmlAttr();
+
+ char* name;
+ union {
+ TCHAR* value;
+ char* sendValue;
+ };
+};
+
+struct XmlNode
+{
+ XmlNode( const char* name );
+ XmlNode( const char* pszName, const TCHAR* ptszText );
+ #if defined( _UNICODE )
+ XmlNode( const char* pszName, const char* ptszText );
+ #endif
+ ~XmlNode();
+
+ XmlAttr* addAttr( XmlAttr* );
+ XmlAttr* addAttr( const char* pszName, const TCHAR* ptszValue );
+ #if defined( _UNICODE )
+ XmlAttr* addAttr( const char* pszName, const char* pszValue );
+ #endif
+ XmlAttr* addAttr( const char* pszName, int value );
+ XmlAttr* addAttrID( int id );
+
+ XmlNode* addChild( XmlNode* );
+ XmlNode* addChild( const char* pszName );
+ XmlNode* addChild( const char* pszName, const TCHAR* ptszValue );
+ #if defined( _UNICODE )
+ XmlNode* addChild( const char* pszName, const char* pszValue );
+ #endif
+
+ XmlNode* addQuery( const char* szNameSpace );
+
+ int getTextLen() const;
+ char* getText() const;
+
+ int depth; // depth of the current node ( 1=root )
+ char* name; // tag name of the current node
+ union {
+ TCHAR* text;
+ char* sendText;
+ };
+ int numAttr; // number of attributes
+ int maxNumAttr; // internal use ( num of slots currently allocated to attr )
+ XmlAttr **attr; // attribute list
+ int numChild; // number of direct child nodes
+ int maxNumChild; // internal use ( num of slots currently allocated to child )
+ XmlNode **child; // child node list
+ XmlNodeType state; // internal use by parser
+ char* props;
+ boolean dirtyHack; // to allow generator to issue the unclosed tag
+};
+
+struct XmlNodeIq : public XmlNode
+{
+ XmlNodeIq( const char* type, int id = NOID, const TCHAR* to = NULL );
+ XmlNodeIq( const char* type, const TCHAR* idStr, const TCHAR* to );
+ #if defined( _UNICODE )
+ XmlNodeIq( const char* type, int id, const char* to );
+ #endif
+};
+
+typedef void ( *JABBER_XML_CALLBACK )( XmlNode*, void* );
+
+struct XmlState
+{
+ XmlState() : root(NULL) {}
+
+ XmlNode root; // root is the document ( depth = 0 );
+ // callback for depth=n element on opening/closing
+ JABBER_XML_CALLBACK callback1_open;
+ JABBER_XML_CALLBACK callback1_close;
+ JABBER_XML_CALLBACK callback2_open;
+ JABBER_XML_CALLBACK callback2_close;
+ void *userdata1_open;
+ void *userdata1_close;
+ void *userdata2_open;
+ void *userdata2_close;
+};
+
+void JabberXmlInitState( XmlState *xmlState );
+void JabberXmlDestroyState( XmlState *xmlState );
+BOOL JabberXmlSetCallback( XmlState *xmlState, int depth, XmlElemType type, void ( *callback )(), void *userdata );
+int JabberXmlParse( XmlState *xmlState, char* buffer );
+TCHAR* JabberXmlGetAttrValue( XmlNode *node, char* key );
+XmlNode *JabberXmlGetChild( XmlNode *node, char* tag );
+XmlNode *JabberXmlGetNthChild( XmlNode *node, char* tag, int nth );
+XmlNode *JabberXmlGetChildWithGivenAttrValue( XmlNode *node, char* tag, char* attrKey, TCHAR* attrValue );
+void JabberXmlDumpAll( XmlState *xmlState );
+void JabberXmlDumpNode( XmlNode *node );
+XmlNode *JabberXmlCopyNode( XmlNode *node );
+BOOL JabberXmlSetCallback( XmlState *xmlState, int depth, XmlElemType type, JABBER_XML_CALLBACK callback, void *userdata );
+
+XmlNode *JabberXmlCreateNode( char* name );
+void JabberXmlAddAttr( XmlNode *n, char* name, char* value );
+XmlNode *JabberXmlAddChild( XmlNode *n, char* name );
+
+inline XmlNode& operator+( XmlNode& n1, XmlNode& n2 )
+{ n1.addChild( &n2 );
+ return n1;
+}
+
+inline XmlNode& operator+( XmlNode& n, XmlAttr& a )
+{ n.addAttr( &a );
+ return n;
+}
+
+#endif
diff --git a/miranda-wine/protocols/JabberG/jabber_xmlns.cpp b/miranda-wine/protocols/JabberG/jabber_xmlns.cpp new file mode 100644 index 0000000..2ddcd25 --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_xmlns.cpp @@ -0,0 +1,107 @@ +/*
+
+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_xmlns.cpp,v $
+Revision : $Revision: 3651 $
+Last change on : $Date: 2006-08-30 16:54:52 +0400 (Срд, 30 Авг 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#include "jabber.h"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberXmlnsBrowse
+
+void JabberXmlnsBrowse( XmlNode *iqNode, void *userdata )
+{
+ XmlNode *queryNode;
+ TCHAR *xmlns, *iqFrom, *iqType;
+
+ if ( iqNode == NULL ) return;
+ if (( iqFrom=JabberXmlGetAttrValue( iqNode, "from" )) == NULL ) return;
+ if (( iqType=JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return;
+ if (( queryNode=JabberXmlGetChild( iqNode, "query" )) == NULL ) return;
+ if (( xmlns=JabberXmlGetAttrValue( queryNode, "xmlns" )) == NULL ) return;
+
+ if ( !_tcscmp( iqType, _T("get"))) {
+ XmlNodeIq iq( "result", JabberXmlGetAttrValue( iqNode, "id" ), iqFrom );
+ XmlNode* user = iq.addChild( "user" ); user->addAttr( "jid", jabberJID ); user->addAttr( "type", "client" ); user->addAttr( "xmlns", xmlns );
+ user->addChild( "ns", "http://jabber.org/protocol/disco#info" );
+ user->addChild( "ns", "http://jabber.org/protocol/muc" );
+ user->addChild( "ns", "jabber:iq:agents" );
+ user->addChild( "ns", "jabber:iq:browse" );
+ user->addChild( "ns", "jabber:iq:oob" );
+ user->addChild( "ns", "jabber:iq:version" );
+ user->addChild( "ns", "jabber:x:data" );
+ user->addChild( "ns", "jabber:x:event" );
+ user->addChild( "ns", "vcard-temp" );
+ JabberSend( jabberThreadInfo->s, iq );
+} }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// JabberXmlnsDisco
+
+static void sttAddFeature( XmlNode* n, char* text )
+{
+ XmlNode* f = n->addChild( "feature" ); f->addAttr( "var", text );
+}
+
+void JabberXmlnsDisco( XmlNode *iqNode, void *userdata )
+{
+ XmlNode *queryNode;
+ TCHAR *xmlns, *p, *discoType;
+ TCHAR *iqFrom, *iqType;
+
+ if ( iqNode == NULL ) return;
+ if (( iqFrom = JabberXmlGetAttrValue( iqNode, "from" )) == NULL ) return;
+ if (( iqType = JabberXmlGetAttrValue( iqNode, "type" )) == NULL ) return;
+ if (( queryNode = JabberXmlGetChild( iqNode, "query" )) == NULL ) return;
+ if (( xmlns = JabberXmlGetAttrValue( queryNode, "xmlns" )) == NULL ) return;
+
+ p = _tcsrchr( xmlns, '/' );
+ discoType = _tcsrchr( xmlns, '#' );
+
+ if ( p==NULL || discoType==NULL || discoType < p )
+ return;
+
+ if ( !_tcscmp( iqType, _T("get"))) {
+ XmlNodeIq iq( "result", JabberXmlGetAttrValue( iqNode, "id" ), iqFrom );
+
+ if ( !_tcscmp( discoType, _T("#info"))) {
+ XmlNode* query = iq.addChild( "query" ); query->addAttr( "xmlns", xmlns );
+ XmlNode* ident = query->addChild( "identity" ); ident->addAttr( "category", "user" );
+ ident->addAttr( "type", "client" ); ident->addAttr( "name", "Miranda" );
+ sttAddFeature( query, "http://jabber.org/protocol/disco#info" );
+ sttAddFeature( query, "http://jabber.org/protocol/muc" );
+ sttAddFeature( query, "http://jabber.org/protocol/si" );
+ sttAddFeature( query, "http://jabber.org/protocol/si/profile/file-transfer" );
+ sttAddFeature( query, "http://jabber.org/protocol/bytestreams" );
+ sttAddFeature( query, "http://jabber.org/protocol/chatstates" );
+ sttAddFeature( query, "jabber:iq:agents" );
+ sttAddFeature( query, "jabber:iq:browse" );
+ sttAddFeature( query, "jabber:iq:oob" );
+ sttAddFeature( query, "jabber:iq:version" );
+ sttAddFeature( query, "jabber:x:data" );
+ sttAddFeature( query, "jabber:x:event" );
+ sttAddFeature( query, "vcard-temp" );
+ }
+ JabberSend( jabberThreadInfo->s, iq );
+} }
diff --git a/miranda-wine/protocols/JabberG/jabber_xmlns.h b/miranda-wine/protocols/JabberG/jabber_xmlns.h new file mode 100644 index 0000000..e0bfd49 --- /dev/null +++ b/miranda-wine/protocols/JabberG/jabber_xmlns.h @@ -0,0 +1,34 @@ +/*
+
+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_xmlns.h,v $
+Revision : $Revision: 2866 $
+Last change on : $Date: 2006-05-16 20:39:40 +0400 (Втр, 16 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+#ifndef _JABBER_XMLNS_H_
+#define _JABBER_XMLNS_H_
+
+void JabberXmlnsBrowse( XmlNode *iqNode, void *userdata );
+void JabberXmlnsDisco( XmlNode *iqNode, void *userdata );
+
+#endif
diff --git a/miranda-wine/protocols/JabberG/msvc6.rc b/miranda-wine/protocols/JabberG/msvc6.rc new file mode 100644 index 0000000..da0ebe9 --- /dev/null +++ b/miranda-wine/protocols/JabberG/msvc6.rc @@ -0,0 +1,2 @@ +#include "jabber.rc"
+#include "version.rc"
diff --git a/miranda-wine/protocols/JabberG/resource.h b/miranda-wine/protocols/JabberG/resource.h new file mode 100644 index 0000000..42469ef --- /dev/null +++ b/miranda-wine/protocols/JabberG/resource.h @@ -0,0 +1,232 @@ +//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by jabber.rc
+//
+#define IDCANCEL2 3
+#define IDD_OPT_JABBER 101
+#define IDI_JABBER 102
+#define IDD_INFO_JABBER 103
+#define IDD_OPT_REGISTER 105
+#define IDD_AGENTS 106
+#define IDD_FORM 107
+#define IDI_ADDROSTER 108
+#define IDI_USER2ROOM 109
+#define IDD_PASSWORD 111
+#define IDI_TLEN 121
+#define IDI_ADDCONTACT 122
+#define IDI_DELETE 123
+#define IDI_EDIT 124
+#define IDD_VCARD 125
+#define IDD_VCARD_HOME 126
+#define IDD_VCARD_PERSONAL 127
+#define IDD_VCARD_WORK 128
+#define IDD_VCARD_CONTACT 129
+#define IDD_VCARD_ADDEMAIL 130
+#define IDD_VCARD_ADDPHONE 131
+#define IDI_OPEN 131
+#define IDD_VCARD_PHOTO 132
+#define IDD_VCARD_NOTE 133
+#define IDD_CHANGEPASSWORD 136
+#define IDD_OPT_JABBERMAIN 139
+#define IDD_OPT_JABBER2 140
+#define IDI_REQUEST 141
+#define IDD_GROUPCHAT 141
+#define IDI_GRANT 142
+#define IDI_KEYS 144
+#define IDI_GROUP 147
+#define IDD_GROUPCHAT_JOIN 148
+#define IDI_AGENTS 154
+#define IDI_VCARD 155
+#define IDI_WRITE 162
+#define IDI_SAVE 166
+#define IDD_GROUPCHAT_INPUT 167
+#define IDD_ADVSEARCH_TLEN 169
+#define IDD_JIDLIST 171
+#define IDD_AGENT_MANUAL_REGISTER 182
+#define IDD_GROUPCHAT_INVITE 183
+#define IDD_GROUPCHAT_INVITE_ACCEPT 184
+#define IDD_OPT_JABBER3 185
+#define IDD_OPT_SETAVATAR 185
+#define IDC_EDIT_USERNAME 1000
+#define IDC_SAVE 1000
+#define IDC_EDIT_PASSWORD 1001
+#define IDC_BUTTON_REGISTER 1002
+#define IDC_EDIT_LOGIN_SERVER 1003
+#define IDC_PORT 1004
+#define IDC_EDIT_RESOURCE 1005
+#define IDC_INFO_JID 1007
+#define IDC_INFO_RESOURCE 1008
+#define IDC_LINK_PUBLIC_SERVER 1009
+#define IDC_NAME 1009
+#define IDC_PROGRESS_REG 1011
+#define IDOK2 1012
+#define IDC_AGENT_TRANSPORT 1015
+#define IDC_AGENT_REGISTER 1016
+#define IDC_AGENT_LOGON 1017
+#define IDC_AGENT_UNREGISTER 1018
+#define IDC_AGENT_SERVER 1019
+#define IDC_AGENT_LOGOFF 1020
+#define IDC_AGENT_LIST 1021
+#define IDC_AGENT_SEARCH 1022
+#define IDC_SUBMIT 1023
+#define IDC_LOGO 1024
+#define IDC_AGENT_BROWSE 1029
+#define IDC_INSTRUCTION 1030
+#define IDC_DESCRIPTION 1031
+#define IDC_FRAME 1037
+#define IDC_FRAME_TEXT 1038
+#define IDC_SUBSCRIPTION 1039
+#define IDC_SIMPLE 1041
+#define IDC_KEEPALIVE 1042
+#define IDC_HOST 1043
+#define IDC_HOSTPORT 1044
+#define IDC_USE_SSL 1045
+#define IDC_MANUAL 1046
+#define IDC_RESOURCE_T 1047
+#define IDC_SAVEPASSWORD 1048
+#define IDC_MSGLANG 1049
+#define IDC_PASSWORD 1050
+#define IDC_JID 1051
+#define IDC_NEWPASSWD2 1052
+#define IDC_ROSTER_SYNC 1052
+#define IDC_OLDPASSWD 1053
+#define IDC_ADDRESS1 1056
+#define IDC_ADDRESS2 1057
+#define IDC_CITY 1058
+#define IDC_STATE 1059
+#define IDC_COUNTRY 1060
+#define IDC_FULLNAME 1061
+#define IDC_ZIP 1061
+#define IDC_NICKNAME 1062
+#define IDC_COMPANY 1062
+#define IDC_FIRSTNAME 1063
+#define IDC_DEPARTMENT 1063
+#define IDC_LASTNAME 1064
+#define IDC_BIRTH 1065
+#define IDC_OCCUPATION 1066
+#define IDC_HOMEPAGE 1067
+#define IDC_AVATAR 1068
+#define IDC_ENABLE_AVATARS 1069
+#define IDC_SETAVATAR 1070
+#define IDC_DELETEAVATAR 1071
+#define IDC_MIDDLE 1072
+#define IDC_EMAIL 1073
+#define IDC_HOME 1074
+#define IDC_INTERNET 1075
+#define IDC_X400 1076
+#define IDC_WORK 1077
+#define IDC_PHONE 1078
+#define IDC_CELL 1079
+#define IDC_VIDEO 1080
+#define IDC_BBS 1081
+#define IDC_MODEM 1082
+#define IDC_PAGER 1083
+#define IDC_MSG 1084
+#define IDC_ISDN 1085
+#define IDC_PCS 1086
+#define IDC_VOICE 1087
+#define IDC_FAX 1088
+#define IDC_TITLE 1089
+#define IDC_DESC 1090
+#define IDC_DELETE 1092
+#define IDC_LOAD 1093
+#define IDC_CANVAS 1094
+#define IDC_OPTIONSTAB 1095
+#define IDC_GENDER 1096
+#define IDC_JUD 1097
+#define IDC_JUD_LABEL 1098
+#define IDC_MSGLANG_LABEL 1099
+#define IDC_SOFTWARE 1101
+#define IDC_VERSION 1102
+#define IDC_SYSTEM 1103
+#define IDC_PRIORITY_SPIN 1104
+#define IDC_PRIORITY 1105
+#define IDC_PRIORITY_LABEL 1106
+#define IDC_NEWPASSWD 1107
+#define IDC_PASS_SERVER 1112
+#define IDC_PROXY_ADDR 1112
+#define IDC_PASS_PORT 1113
+#define IDC_EXT_ADDRESS 1114
+#define IDC_DIRECT_ADDR 1114
+#define IDC_SHOW_TRANSPORT 1115
+#define IDC_AUTO_ADD 1116
+#define IDC_PASS_SERVER_LABEL 1117
+#define IDC_EXT_ADDRESS_LABEL 1118
+#define IDC_PASS_PORT_LABEL 1119
+#define IDC_USE_PASS 1120
+#define IDC_PROXY 1120
+#define IDC_USE_EXT_ADDRESS 1121
+#define IDC_DIRECT_MANUAL 1121
+#define IDC_REG_STATUS 1122
+#define IDC_MSG_ACK 1122
+#define IDC_JOIN 1123
+#define IDC_DIRECT 1123
+#define IDC_ROOM 1124
+#define IDC_PROXY_MANUAL 1124
+#define IDC_SERVER 1125
+#define IDC_BROWSE 1126
+#define IDC_VSCROLL 1128
+#define IDC_NICK 1129
+#define IDC_EDIT 1131
+#define IDC_LIST 1133
+#define IDC_HSPLIT 1134
+#define IDC_LOG 1136
+#define IDC_VSPLIT 1137
+#define IDC_SET 1140
+#define IDC_TABS 1141
+#define IDC_TOPIC 1141
+#define IDC_FONT 1143
+#define IDC_ENTER 1144
+#define IDC_CTRLENTER 1145
+#define IDC_FONTSHOW 1146
+#define IDC_FLASH 1148
+#define IDC_AGEFROM 1152
+#define IDC_AGETO 1153
+#define IDC_LOOKFOR 1154
+#define IDC_SCHOOL 1155
+#define IDC_TIME 1156
+#define IDC_DATE 1157
+#define IDC_MANUAL_REGISTER 1167
+#define IDC_REASON 1171
+#define IDC_USER 1172
+#define IDC_INVITE 1173
+#define IDC_ACCEPT 1174
+#define IDC_FROM 1175
+#define IDC_AUTOJOIN 1176
+#define IDC_DISABLE_MAINMENU 1178
+#define IDC_USE_TLS 1179
+#define IDC_AUTO_ACCEPT_MUC 1180
+#define IDC_DISABLE_SASL 1182
+#define IDC_WHITERECT 1221
+#define IDC_UPDATING 1231
+#define IDC_EMAILS 1306
+#define IDC_PHONES 1308
+#define IDC_UPDATE 1313
+#define IDC_STATUS 1414
+#define IDC_PLAN 1415
+#define IDC_PERSONALGROUP 1434
+#define IDC_EXTRAGROUP 1436
+#define IDM_MESSAGE 10002
+#define IDM_CLEAR 10003
+#define IDM_VOICE 10005
+#define IDM_BAN 10006
+#define IDM_ADMIN 10007
+#define IDM_OWNER 10008
+#define IDM_CONFIG 10009
+#define IDM_KICK 10011
+#define IDM_NICK 10012
+#define IDM_MODERATOR 10013
+#define IDM_DESTROY 10014
+#define IDM_MEMBER 10015
+#define IDM_INVITE 10016
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 185
+#define _APS_NEXT_COMMAND_VALUE 40017
+#define _APS_NEXT_CONTROL_VALUE 1183
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/miranda-wine/protocols/JabberG/sdk/m_smileyadd.h b/miranda-wine/protocols/JabberG/sdk/m_smileyadd.h new file mode 100644 index 0000000..83b2dbb --- /dev/null +++ b/miranda-wine/protocols/JabberG/sdk/m_smileyadd.h @@ -0,0 +1,78 @@ +/*
+Miranda SmileyAdd Plugin
+Plugin support header file
+Copyright ( C ) 2003 Rein-Peter de Boer ( peacow )
+
+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.
+*/
+
+
+//replace smiley tags in a rich edit control...
+//wParam = ( WPARAM ) 0; not used
+//lParam = ( LPARAM )( SMADD_RICHEDIT* ) &smre; //pointer to SmAddRicheditStructure
+//return: TRUE if replacement succeeded, FALSE if not ( disable by user? ).
+typedef struct
+{
+ int cbSize; //size of the structure
+ HWND hwndRichEditControl; //handle to the rich edit control
+ CHARRANGE* rangeToReplace; //same meaning as for normal Richedit use ( NULL = replaceall )
+ char* Protocolname; //protocol to use... if you have defined a protocol, u can
+ //use your own protocol name. Smiley add wil automatically
+ //select the smileypack that is defined for your protocol.
+ //Or, use "Standard" for standard smiley set. Or "ICQ", "MSN"
+ //if you prefer those icons.
+ //If not found or NULL: "Standard" will be used
+ } SMADD_RICHEDIT;
+
+//new version from smileyadd 1.2
+typedef struct
+{
+ int cbSize; //size of the structure
+ HWND hwndRichEditControl; //handle to the rich edit control
+ CHARRANGE* rangeToReplace; //same meaning as for normal Richedit use ( NULL = replaceall )
+ char* Protocolname; //protocol to use... if you have defined a protocol, u can
+ //use your own protocol name. Smiley add wil automatically
+ //select the smileypack that is defined for your protocol.
+ //Or, use "Standard" for standard smiley set. Or "ICQ", "MSN"
+ //if you prefer those icons.
+ //If not found or NULL: "Standard" will be used
+ BOOL useSounds; //NOT IMPLEMENTED YET, set to FALSE
+ BOOL disableRedraw; //If true then you have to restore scrollbars, selection
+ //etc and redraw yourself
+ //everything will be screwed up and not restored.
+
+} SMADD_RICHEDIT2;
+
+#define MS_SMILEYADD_REPLACESMILEYS "SmileyAdd/ReplaceSmileys"
+
+
+
+
+//replace smiley tags in a rich edit control...
+//wParam = ( WPARAM ) 0; not used
+//lParam = ( LPARAM )( SMADD_GETICON* ) &smgi; //pointer to SmAddRicheditStructure
+//return: TRUE if found, FALSE if not
+//NOTE: the
+typedef struct
+{
+ int cbSize; //same as in SMADD_RICHEDIT
+ char* Protocolname; // " "
+ char* SmileySequence; //character string containing the smiley
+ HICON SmileyIcon; //RETURN VALUE: this is filled with the icon handle...
+ //do not destroy!
+ int Smileylength; //length of the smiley that is found.
+} SMADD_GETICON;
+#define MS_SMILEYADD_GETSMILEYICON "SmileyAdd/GetSmileyIcon"
+
diff --git a/miranda-wine/protocols/JabberG/sha1.cpp b/miranda-wine/protocols/JabberG/sha1.cpp new file mode 100644 index 0000000..107c4cd --- /dev/null +++ b/miranda-wine/protocols/JabberG/sha1.cpp @@ -0,0 +1,446 @@ +/*
+
+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/sha1.cpp,v $
+Revision : $Revision: 2866 $
+Last change on : $Date: 2006-05-16 20:39:40 +0400 (Втр, 16 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+/*
+
+ Copyright ( C ) The Internet Society ( 2001 ). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+*/
+
+/*
+ * sha1.c
+ *
+ * Description:
+ * This file implements the Secure Hashing Algorithm 1 as
+ * defined in FIPS PUB 180-1 published April 17, 1995.
+ *
+ * The SHA-1, produces a 160-bit message digest for a given
+ * data stream. It should take about 2**n steps to find a
+ * message with the same digest as a given message and
+ * 2**( n/2 ) to find any two messages with the same digest,
+ * when n is the digest size in bits. Therefore, this
+ * algorithm can serve as a means of providing a
+ * "fingerprint" for a message.
+ *
+ * Portability Issues:
+ * SHA-1 is defined in terms of 32-bit "words". This code
+ * uses <stdint.h> ( included via "sha1.h" to define 32 and 8
+ * bit unsigned integer types. If your C compiler does not
+ * support 32 bit unsigned integers, this code is not
+ * appropriate.
+ *
+ * Caveats:
+ * SHA-1 is designed to work with messages less than 2^64 bits
+ * long. Although SHA-1 allows a message digest to be generated
+ * for messages of any number of bits less than 2^64, this
+ * implementation only works with messages with a length that is
+ * a multiple of the size of an 8-bit character.
+ *
+ */
+
+#include "sha1.h"
+
+/*
+ * Define the SHA1 circular left shift macro
+ */
+#define SHA1CircularShift( bits,word ) \
+ (( ( word ) << ( bits )) | (( word ) >> ( 32-( bits )) ))
+
+/* Local Function Prototyptes */
+void SHA1PadMessage( SHA1Context * );
+void SHA1ProcessMessageBlock( SHA1Context * );
+
+/*
+ * SHA1Reset
+ *
+ * Description:
+ * This function will initialize the SHA1Context in preparation
+ * for computing a new SHA1 message digest.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to reset.
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int SHA1Reset( SHA1Context *context )
+{
+ if ( !context )
+ {
+ return shaNull;
+ }
+
+ context->Length_Low = 0;
+ context->Length_High = 0;
+ context->Message_Block_Index = 0;
+
+ context->Intermediate_Hash[0] = 0x67452301;
+ context->Intermediate_Hash[1] = 0xEFCDAB89;
+ context->Intermediate_Hash[2] = 0x98BADCFE;
+ context->Intermediate_Hash[3] = 0x10325476;
+ context->Intermediate_Hash[4] = 0xC3D2E1F0;
+
+ context->Computed = 0;
+ context->Corrupted = 0;
+
+ return shaSuccess;
+}
+
+/*
+ * SHA1Result
+ *
+ * Description:
+ * This function will return the 160-bit message digest into the
+ * Message_Digest array provided by the caller.
+ * NOTE: The first octet of hash is stored in the 0th element,
+ * the last octet of hash in the 19th element.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to use to calculate the SHA-1 hash.
+ * Message_Digest: [out]
+ * Where the digest is returned.
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int SHA1Result( SHA1Context *context,
+ uint8_t Message_Digest[SHA1HashSize] )
+{
+ int i;
+
+ if ( !context || !Message_Digest )
+ {
+ return shaNull;
+ }
+
+ if ( context->Corrupted )
+ {
+ return context->Corrupted;
+ }
+
+ if ( !context->Computed )
+ {
+ SHA1PadMessage( context );
+ for( i=0; i<64; ++i )
+ {
+ /* message may be sensitive, clear it out */
+ context->Message_Block[i] = 0;
+ }
+ context->Length_Low = 0; /* and clear length */
+ context->Length_High = 0;
+ context->Computed = 1;
+
+ }
+
+ for( i = 0; i < SHA1HashSize; ++i )
+ {
+ Message_Digest[i] = ( uint8_t ) ( context->Intermediate_Hash[i>>2]
+ >> 8 * ( 3 - ( i & 0x03 )) );
+ }
+
+ return shaSuccess;
+}
+
+/*
+ * SHA1Input
+ *
+ * Description:
+ * This function accepts an array of octets as the next portion
+ * of the message.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The SHA context to update
+ * message_array: [in]
+ * An array of characters representing the next portion of
+ * the message.
+ * length: [in]
+ * The length of the message in message_array
+ *
+ * Returns:
+ * sha Error Code.
+ *
+ */
+int SHA1Input( SHA1Context *context,
+ const uint8_t *message_array,
+ unsigned length )
+{
+ if ( !length )
+ {
+ return shaSuccess;
+ }
+
+ if ( !context || !message_array )
+ {
+ return shaNull;
+ }
+
+ if ( context->Computed )
+ {
+ context->Corrupted = shaStateError;
+
+ return shaStateError;
+ }
+
+ if ( context->Corrupted )
+ {
+ return context->Corrupted;
+ }
+ while( length-- && !context->Corrupted )
+ {
+ context->Message_Block[context->Message_Block_Index++] =
+ ( *message_array & 0xFF );
+
+ context->Length_Low += 8;
+ if ( context->Length_Low == 0 )
+ {
+ context->Length_High++;
+ if ( context->Length_High == 0 )
+ {
+ /* Message is too long */
+ context->Corrupted = 1;
+ }
+ }
+
+ if ( context->Message_Block_Index == 64 )
+ {
+ SHA1ProcessMessageBlock( context );
+ }
+
+ message_array++;
+ }
+
+ return shaSuccess;
+}
+
+/*
+ * SHA1ProcessMessageBlock
+ *
+ * Description:
+ * This function will process the next 512 bits of the message
+ * stored in the Message_Block array.
+ *
+ * Parameters:
+ * None.
+ *
+ * Returns:
+ * Nothing.
+ *
+ * Comments:
+
+ * Many of the variable names in this code, especially the
+ * single character names, were used because those were the
+ * names used in the publication.
+ *
+ *
+ */
+void SHA1ProcessMessageBlock( SHA1Context *context )
+{
+ const uint32_t K[] = { /* Constants defined in SHA-1 */
+ 0x5A827999,
+ 0x6ED9EBA1,
+ 0x8F1BBCDC,
+ 0xCA62C1D6
+ };
+ int t; /* Loop counter */
+ uint32_t temp; /* Temporary word value */
+ uint32_t W[80]; /* Word sequence */
+ uint32_t A, B, C, D, E; /* Word buffers */
+
+ /*
+ * Initialize the first 16 words in the array W
+ */
+ for( t = 0; t < 16; t++ )
+ {
+ W[t] = context->Message_Block[t * 4] << 24;
+ W[t] |= context->Message_Block[t * 4 + 1] << 16;
+ W[t] |= context->Message_Block[t * 4 + 2] << 8;
+ W[t] |= context->Message_Block[t * 4 + 3];
+ }
+
+ for( t = 16; t < 80; t++ )
+ {
+ W[t] = SHA1CircularShift( 1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16] );
+ }
+
+ A = context->Intermediate_Hash[0];
+ B = context->Intermediate_Hash[1];
+ C = context->Intermediate_Hash[2];
+ D = context->Intermediate_Hash[3];
+ E = context->Intermediate_Hash[4];
+
+ for( t = 0; t < 20; t++ )
+ {
+ temp = SHA1CircularShift( 5,A ) +
+ (( B & C ) | (( ~B ) & D )) + E + W[t] + K[0];
+ E = D;
+ D = C;
+ C = SHA1CircularShift( 30,B );
+
+ B = A;
+ A = temp;
+ }
+
+ for( t = 20; t < 40; t++ )
+ {
+ temp = SHA1CircularShift( 5,A ) + ( B ^ C ^ D ) + E + W[t] + K[1];
+ E = D;
+ D = C;
+ C = SHA1CircularShift( 30,B );
+ B = A;
+ A = temp;
+ }
+
+ for( t = 40; t < 60; t++ )
+ {
+ temp = SHA1CircularShift( 5,A ) +
+ (( B & C ) | ( B & D ) | ( C & D )) + E + W[t] + K[2];
+ E = D;
+ D = C;
+ C = SHA1CircularShift( 30,B );
+ B = A;
+ A = temp;
+ }
+
+ for( t = 60; t < 80; t++ )
+ {
+ temp = SHA1CircularShift( 5,A ) + ( B ^ C ^ D ) + E + W[t] + K[3];
+ E = D;
+ D = C;
+ C = SHA1CircularShift( 30,B );
+ B = A;
+ A = temp;
+ }
+
+ context->Intermediate_Hash[0] += A;
+ context->Intermediate_Hash[1] += B;
+ context->Intermediate_Hash[2] += C;
+ context->Intermediate_Hash[3] += D;
+ context->Intermediate_Hash[4] += E;
+
+ context->Message_Block_Index = 0;
+}
+
+/*
+ * SHA1PadMessage
+ *
+
+ * Description:
+ * According to the standard, the message must be padded to an even
+ * 512 bits. The first padding bit must be a '1'. The last 64
+ * bits represent the length of the original message. All bits in
+ * between should be 0. This function will pad the message
+ * according to those rules by filling the Message_Block array
+ * accordingly. It will also call the ProcessMessageBlock function
+ * provided appropriately. When it returns, it can be assumed that
+ * the message digest has been computed.
+ *
+ * Parameters:
+ * context: [in/out]
+ * The context to pad
+ * ProcessMessageBlock: [in]
+ * The appropriate SHA*ProcessMessageBlock function
+ * Returns:
+ * Nothing.
+ *
+ */
+
+void SHA1PadMessage( SHA1Context *context )
+{
+ /*
+ * Check to see if the current message block is too small to hold
+ * the initial padding bits and length. If so, we will pad the
+ * block, process it, and then continue padding into a second
+ * block.
+ */
+ if ( context->Message_Block_Index > 55 )
+ {
+ context->Message_Block[context->Message_Block_Index++] = 0x80;
+ while( context->Message_Block_Index < 64 )
+ {
+ context->Message_Block[context->Message_Block_Index++] = 0;
+ }
+
+ SHA1ProcessMessageBlock( context );
+
+ while( context->Message_Block_Index < 56 )
+ {
+ context->Message_Block[context->Message_Block_Index++] = 0;
+ }
+ }
+ else
+ {
+ context->Message_Block[context->Message_Block_Index++] = 0x80;
+ while( context->Message_Block_Index < 56 )
+ {
+
+ context->Message_Block[context->Message_Block_Index++] = 0;
+ }
+ }
+
+ /*
+ * Store the message length as the last 8 octets
+ */
+ context->Message_Block[56] = ( uint8_t ) ( context->Length_High >> 24 );
+ context->Message_Block[57] = ( uint8_t ) ( context->Length_High >> 16 );
+ context->Message_Block[58] = ( uint8_t ) ( context->Length_High >> 8 );
+ context->Message_Block[59] = ( uint8_t ) ( context->Length_High );
+ context->Message_Block[60] = ( uint8_t ) ( context->Length_Low >> 24 );
+ context->Message_Block[61] = ( uint8_t ) ( context->Length_Low >> 16 );
+ context->Message_Block[62] = ( uint8_t ) ( context->Length_Low >> 8 );
+ context->Message_Block[63] = ( uint8_t ) ( context->Length_Low );
+
+ SHA1ProcessMessageBlock( context );
+}
diff --git a/miranda-wine/protocols/JabberG/sha1.h b/miranda-wine/protocols/JabberG/sha1.h new file mode 100644 index 0000000..b7a96ae --- /dev/null +++ b/miranda-wine/protocols/JabberG/sha1.h @@ -0,0 +1,133 @@ +/*
+
+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/sha1.h,v $
+Revision : $Revision: 2866 $
+Last change on : $Date: 2006-05-16 20:39:40 +0400 (Втр, 16 Май 2006) $
+Last change by : $Author: ghazan $
+
+*/
+
+/*
+
+ Copyright ( C ) The Internet Society ( 2001 ). All Rights Reserved.
+
+ This document and translations of it may be copied and furnished to
+ others, and derivative works that comment on or otherwise explain it
+ or assist in its implementation may be prepared, copied, published
+ and distributed, in whole or in part, without restriction of any
+ kind, provided that the above copyright notice and this paragraph are
+ included on all such copies and derivative works. However, this
+ document itself may not be modified in any way, such as by removing
+ the copyright notice or references to the Internet Society or other
+ Internet organizations, except as needed for the purpose of
+ developing Internet standards in which case the procedures for
+ copyrights defined in the Internet Standards process must be
+ followed, or as required to translate it into languages other than
+ English.
+
+ The limited permissions granted above are perpetual and will not be
+ revoked by the Internet Society or its successors or assigns.
+
+ This document and the information contained herein is provided on an
+ "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+*/
+
+/*
+ * sha1.h
+ *
+ * Description:
+ * This is the header file for code which implements the Secure
+ * Hashing Algorithm 1 as defined in FIPS PUB 180-1 published
+ * April 17, 1995.
+ *
+ * Many of the variable names in this code, especially the
+ * single character names, were used because those were the names
+ * used in the publication.
+ *
+ * Please read the file sha1.c for more information.
+ *
+ */
+
+#ifndef _SHA1_H_
+#define _SHA1_H_
+
+//#include <stdint.h>
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int8 uint8_t;
+typedef __int32 int_least16_t;
+/*
+ * If you do not have the ISO standard stdint.h header file, then you
+ * must typdef the following:
+ * name meaning
+ * uint32_t unsigned 32 bit integer
+ * uint8_t unsigned 8 bit integer ( i.e., unsigned char )
+ * int_least16_t integer of >= 16 bits
+ *
+ */
+
+#ifndef _SHA_enum_
+#define _SHA_enum_
+enum
+{
+ shaSuccess = 0,
+ shaNull, /* Null pointer parameter */
+ shaInputTooLong, /* input data too long */
+ shaStateError /* called Input after Result */
+};
+#endif
+#define SHA1HashSize 20
+
+/*
+ * This structure will hold context information for the SHA-1
+ * hashing operation
+ */
+typedef struct SHA1Context
+{
+ uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */
+
+ uint32_t Length_Low; /* Message length in bits */
+ uint32_t Length_High; /* Message length in bits */
+
+ /* Index into message block array */
+ int_least16_t Message_Block_Index;
+ uint8_t Message_Block[64]; /* 512-bit message blocks */
+
+ int Computed; /* Is the digest computed? */
+ int Corrupted; /* Is the message digest corrupted? */
+} SHA1Context;
+
+/*
+ * Function Prototypes
+ */
+
+int SHA1Reset( SHA1Context * );
+int SHA1Input( SHA1Context *,
+ const uint8_t *,
+ unsigned int );
+int SHA1Result( SHA1Context *,
+ uint8_t Message_Digest[SHA1HashSize] );
+
+#endif
diff --git a/miranda-wine/protocols/JabberG/version.h b/miranda-wine/protocols/JabberG/version.h new file mode 100644 index 0000000..def2e71 --- /dev/null +++ b/miranda-wine/protocols/JabberG/version.h @@ -0,0 +1,3 @@ +#define __FILEVERSION_STRING 0,6,0,1
+#define __VERSION_STRING "0.6.0.1"
+#define __VERSION_DWORD 0x00060001
diff --git a/miranda-wine/protocols/JabberG/version.rc b/miranda-wine/protocols/JabberG/version.rc new file mode 100644 index 0000000..6ca3961 --- /dev/null +++ b/miranda-wine/protocols/JabberG/version.rc @@ -0,0 +1,52 @@ +#include "version.h"
+#include "winres.h"
+
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page( 1252)
+#endif //_WIN32
+
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION __FILEVERSION_STRING
+ PRODUCTVERSION __FILEVERSION_STRING
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "Comments", "\0"
+ VALUE "CompanyName", "Miranda\0"
+ VALUE "FileDescription", "Jabber Protocol Plugin for Miranda IM\0"
+ VALUE "FileVersion", __VERSION_STRING
+ VALUE "InternalName", "jabber\0"
+ VALUE "LegalCopyright", "Copyright ( c) 2002-04 Santithorn Bunchua, 2005 George Hazan \0"
+ VALUE "LegalTrademarks", "\0"
+ VALUE "OriginalFilename", "jabber.dll\0"
+ VALUE "PrivateBuild", "\0"
+ VALUE "ProductName", "Jabber Protocol Plugin for Miranda IM\0"
+ VALUE "ProductVersion", __VERSION_STRING
+ VALUE "SpecialBuild", "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+#endif // !_MAC
|