summaryrefslogtreecommitdiff
path: root/src/modules/protocols
diff options
context:
space:
mode:
authorVadim Dashevskiy <watcherhd@gmail.com>2012-05-15 10:38:20 +0000
committerVadim Dashevskiy <watcherhd@gmail.com>2012-05-15 10:38:20 +0000
commit48540940b6c28bb4378abfeb500ec45a625b37b6 (patch)
tree2ef294c0763e802f91d868bdef4229b6868527de /src/modules/protocols
parent5c350913f011e119127baeb32a6aedeb4f0d33bc (diff)
initial commit
git-svn-id: http://svn.miranda-ng.org/main/trunk@2 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'src/modules/protocols')
-rw-r--r--src/modules/protocols/protoaccs.cpp638
-rw-r--r--src/modules/protocols/protochains.cpp274
-rw-r--r--src/modules/protocols/protocols.cpp844
-rw-r--r--src/modules/protocols/protodir.cpp248
-rw-r--r--src/modules/protocols/protoint.cpp271
-rw-r--r--src/modules/protocols/protoopts.cpp1084
6 files changed, 3359 insertions, 0 deletions
diff --git a/src/modules/protocols/protoaccs.cpp b/src/modules/protocols/protoaccs.cpp
new file mode 100644
index 0000000000..b4a2b64f4f
--- /dev/null
+++ b/src/modules/protocols/protoaccs.cpp
@@ -0,0 +1,638 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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.
+*/
+
+#include "commonheaders.h"
+
+#include "../clist/clc.h"
+
+bool CheckProtocolOrder(void);
+void BuildProtoMenus();
+
+static BOOL bModuleInitialized = FALSE;
+
+static int CompareAccounts( const PROTOACCOUNT* p1, const PROTOACCOUNT* p2 )
+{
+ return lstrcmpA( p1->szModuleName, p2->szModuleName );
+}
+
+LIST<PROTOACCOUNT> accounts( 10, CompareAccounts );
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static int EnumDbModules(const char *szModuleName, DWORD ofsModuleName, LPARAM lParam)
+{
+ DBVARIANT dbv;
+ if ( !DBGetContactSettingString( NULL, szModuleName, "AM_BaseProto", &dbv )) {
+ if (!Proto_GetAccount( szModuleName )) {
+ PROTOACCOUNT* pa = ( PROTOACCOUNT* )mir_calloc( sizeof( PROTOACCOUNT ));
+ pa->cbSize = sizeof( *pa );
+ pa->type = PROTOTYPE_PROTOCOL;
+ pa->szModuleName = mir_strdup( szModuleName );
+ pa->szProtoName = mir_strdup( dbv.pszVal );
+ pa->tszAccountName = mir_a2t( szModuleName );
+ pa->bIsVisible = TRUE;
+ pa->bIsEnabled = FALSE;
+ pa->iOrder = accounts.getCount();
+ accounts.insert( pa );
+ }
+ DBFreeVariant( &dbv );
+ }
+ return 0;
+}
+
+void LoadDbAccounts(void)
+{
+ DBVARIANT dbv;
+ int ver = DBGetContactSettingDword( NULL, "Protocols", "PrVer", -1 );
+ int count = DBGetContactSettingDword( NULL, "Protocols", "ProtoCount", 0 ), i;
+
+ for ( i=0; i < count; i++ ) {
+ char buf[10];
+ _itoa( i, buf, 10 );
+ if ( DBGetContactSettingString( NULL, "Protocols", buf, &dbv ))
+ continue;
+
+ PROTOACCOUNT* pa = ( PROTOACCOUNT* )mir_calloc( sizeof( PROTOACCOUNT ));
+ if ( pa == NULL ) {
+ DBFreeVariant( &dbv );
+ continue;
+ }
+ pa->cbSize = sizeof( *pa );
+ pa->type = PROTOTYPE_PROTOCOL;
+ pa->szModuleName = mir_strdup( dbv.pszVal );
+ DBFreeVariant( &dbv );
+
+ _itoa( OFFSET_VISIBLE+i, buf, 10 );
+ pa->bIsVisible = DBGetContactSettingDword( NULL, "Protocols", buf, 1 );
+
+ _itoa( OFFSET_PROTOPOS+i, buf, 10 );
+ pa->iOrder = DBGetContactSettingDword( NULL, "Protocols", buf, 1 );
+
+ if ( ver >= 4 ) {
+ DBFreeVariant( &dbv );
+ _itoa( OFFSET_NAME+i, buf, 10 );
+ if ( !DBGetContactSettingTString( NULL, "Protocols", buf, &dbv )) {
+ pa->tszAccountName = mir_tstrdup( dbv.ptszVal );
+ DBFreeVariant( &dbv );
+ }
+
+ _itoa( OFFSET_ENABLED+i, buf, 10 );
+ pa->bIsEnabled = DBGetContactSettingDword( NULL, "Protocols", buf, 1 );
+
+ if ( !DBGetContactSettingString( NULL, pa->szModuleName, "AM_BaseProto", &dbv )) {
+ pa->szProtoName = mir_strdup( dbv.pszVal );
+ DBFreeVariant( &dbv );
+ }
+ }
+ else pa->bIsEnabled = TRUE;
+
+ if ( !pa->szProtoName ) {
+ pa->szProtoName = mir_strdup( pa->szModuleName );
+ DBWriteContactSettingString( NULL, pa->szModuleName, "AM_BaseProto", pa->szProtoName );
+ }
+
+ if ( !pa->tszAccountName )
+ pa->tszAccountName = mir_a2t( pa->szModuleName );
+
+ accounts.insert( pa );
+ }
+
+ if (CheckProtocolOrder()) WriteDbAccounts();
+
+ int anum = accounts.getCount();
+ CallService(MS_DB_MODULES_ENUM, 0, (LPARAM)EnumDbModules);
+ if (anum != accounts.getCount()) WriteDbAccounts();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+typedef struct
+{
+ int arrlen;
+ char **pszSettingName;
+}
+ enumDB_ProtoProcParam;
+
+static int enumDB_ProtoProc( const char* szSetting, LPARAM lParam )
+{
+ if ( szSetting ) {
+ enumDB_ProtoProcParam* p = ( enumDB_ProtoProcParam* )lParam;
+
+ p->arrlen++;
+ p->pszSettingName = ( char** )mir_realloc( p->pszSettingName, p->arrlen*sizeof( char* ));
+ p->pszSettingName[ p->arrlen-1 ] = mir_strdup( szSetting );
+ }
+ return 0;
+}
+
+void WriteDbAccounts()
+{
+ int i;
+
+ // enum all old settings to delete
+ enumDB_ProtoProcParam param = { 0, NULL };
+
+ DBCONTACTENUMSETTINGS dbces;
+ dbces.pfnEnumProc = enumDB_ProtoProc;
+ dbces.szModule = "Protocols";
+ dbces.ofsSettings = 0;
+ dbces.lParam = ( LPARAM )&param;
+ CallService( MS_DB_CONTACT_ENUMSETTINGS, 0, ( LPARAM )&dbces );
+
+ // delete all settings
+ if ( param.arrlen ) {
+ int i;
+ for ( i=0; i < param.arrlen; i++ ) {
+ DBDeleteContactSetting( 0, "Protocols", param.pszSettingName[i] );
+ mir_free( param.pszSettingName[i] );
+ }
+ mir_free( param.pszSettingName );
+ }
+
+ // write new data
+ for ( i=0; i < accounts.getCount(); i++ ) {
+ PROTOACCOUNT* pa = accounts[i];
+
+ char buf[ 20 ];
+ _itoa( i, buf, 10 );
+ DBWriteContactSettingString( NULL, "Protocols", buf, pa->szModuleName );
+
+ _itoa( OFFSET_PROTOPOS+i, buf, 10 );
+ DBWriteContactSettingDword( NULL, "Protocols", buf, pa->iOrder );
+
+ _itoa( OFFSET_VISIBLE+i, buf, 10 );
+ DBWriteContactSettingDword( NULL, "Protocols", buf, pa->bIsVisible );
+
+ _itoa( OFFSET_ENABLED+i, buf, 10 );
+ DBWriteContactSettingDword( NULL, "Protocols", buf, pa->bIsEnabled );
+
+ _itoa( OFFSET_NAME+i, buf, 10 );
+ DBWriteContactSettingTString( NULL, "Protocols", buf, pa->tszAccountName );
+ }
+
+ DBDeleteContactSetting( 0, "Protocols", "ProtoCount" );
+ DBWriteContactSettingDword( 0, "Protocols", "ProtoCount", accounts.getCount() );
+ DBWriteContactSettingDword( 0, "Protocols", "PrVer", 4 );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+static int OnContactDeleted(WPARAM wParam, LPARAM lParam)
+{
+ const HANDLE hContact = (HANDLE)wParam;
+ if (hContact)
+ {
+ PROTOACCOUNT* pa = Proto_GetAccount(hContact);
+
+ if (Proto_IsAccountEnabled(pa) && pa->ppro)
+ pa->ppro->OnEvent(EV_PROTO_ONCONTACTDELETED, wParam, lParam);
+ }
+ return 0;
+}
+
+static int OnDbSettingsChanged(WPARAM wParam, LPARAM lParam)
+{
+ const HANDLE hContact = (HANDLE)wParam;
+ if (hContact)
+ {
+ PROTOACCOUNT* pa = Proto_GetAccount(hContact);
+ if (Proto_IsAccountEnabled(pa) && pa->ppro)
+ pa->ppro->OnEvent(EV_PROTO_DBSETTINGSCHANGED, wParam, lParam);
+ }
+ return 0;
+}
+
+static int InitializeStaticAccounts( WPARAM, LPARAM )
+{
+ int count = 0;
+
+ for ( int i = 0; i < accounts.getCount(); i++ ) {
+ PROTOACCOUNT* pa = accounts[i];
+ if ( !pa->ppro || !Proto_IsAccountEnabled( pa ))
+ continue;
+
+ pa->ppro->OnEvent( EV_PROTO_ONLOAD, 0, 0 );
+
+ if ( !pa->bOldProto )
+ count++;
+ }
+
+ BuildProtoMenus();
+
+ if ( count == 0 && !DBGetContactSettingByte( NULL, "FirstRun", "AccManager", 0 )) {
+ DBWriteContactSettingByte( NULL, "FirstRun", "AccManager", 1 );
+ CallService( MS_PROTO_SHOWACCMGR, 0, 0 );
+ }
+ return 0;
+}
+
+static int UninitializeStaticAccounts( WPARAM, LPARAM )
+{
+ for ( int i = 0; i < accounts.getCount(); i++ ) {
+ PROTOACCOUNT* pa = accounts[i];
+ if ( !pa->ppro || !Proto_IsAccountEnabled( pa ))
+ continue;
+
+ pa->ppro->OnEvent( EV_PROTO_ONREADYTOEXIT, 0, 0 );
+ pa->ppro->OnEvent( EV_PROTO_ONEXIT, 0, 0 );
+ }
+ return 0;
+}
+
+int LoadAccountsModule( void )
+{
+ int i;
+
+ bModuleInitialized = TRUE;
+
+ for ( i = 0; i < accounts.getCount(); i++ ) {
+ PROTOACCOUNT* pa = accounts[i];
+ pa->bDynDisabled = !Proto_IsProtocolLoaded( pa->szProtoName );
+ if ( pa->ppro )
+ continue;
+
+ if (!Proto_IsAccountEnabled( pa )) {
+ pa->type = PROTOTYPE_DISPROTO;
+ continue;
+ }
+
+ if ( !ActivateAccount( pa )) {
+ pa->bDynDisabled = TRUE;
+ pa->type = PROTOTYPE_DISPROTO;
+ } }
+
+ HookEvent( ME_SYSTEM_MODULESLOADED, InitializeStaticAccounts );
+ HookEvent( ME_SYSTEM_PRESHUTDOWN, UninitializeStaticAccounts );
+ HookEvent( ME_DB_CONTACT_DELETED, OnContactDeleted );
+ HookEvent( ME_DB_CONTACT_SETTINGCHANGED, OnDbSettingsChanged );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static INT_PTR stub1( PROTO_INTERFACE* ppi, WPARAM wParam, LPARAM lParam )
+{ return ( INT_PTR )ppi->AddToList( wParam, (PROTOSEARCHRESULT*)lParam );
+}
+
+static INT_PTR stub2( PROTO_INTERFACE* ppi, WPARAM wParam, LPARAM lParam )
+{ return ( INT_PTR )ppi->AddToListByEvent( HIWORD(wParam), LOWORD(wParam), (HANDLE)lParam );
+}
+
+static INT_PTR stub3( PROTO_INTERFACE* ppi, WPARAM wParam, LPARAM )
+{ return ( INT_PTR )ppi->Authorize(( HANDLE )wParam );
+}
+
+static INT_PTR stub4( PROTO_INTERFACE* ppi, WPARAM wParam, LPARAM lParam )
+{ return ( INT_PTR )ppi->AuthDeny(( HANDLE )wParam, StrConvT(( const char* )lParam ));
+}
+
+static INT_PTR stub7( PROTO_INTERFACE* ppi, WPARAM wParam, LPARAM lParam )
+{ return ( INT_PTR )ppi->ChangeInfo( wParam, ( void* )lParam );
+}
+
+static INT_PTR stub11( PROTO_INTERFACE* ppi, WPARAM wParam, LPARAM lParam )
+{ PROTOFILERESUME* pfr = ( PROTOFILERESUME* )lParam;
+ return ( INT_PTR )ppi->FileResume(( HANDLE )wParam, &pfr->action, (const PROTOCHAR**)&pfr->szFilename );
+}
+
+static INT_PTR stub12( PROTO_INTERFACE* ppi, WPARAM wParam, LPARAM lParam )
+{ return ( INT_PTR )ppi->GetCaps( wParam, (HANDLE)lParam );
+}
+
+static INT_PTR stub13( PROTO_INTERFACE* ppi, WPARAM wParam, LPARAM )
+{ return ( INT_PTR )ppi->GetIcon( wParam );
+}
+
+static INT_PTR stub15( PROTO_INTERFACE* ppi, WPARAM, LPARAM lParam )
+{ return ( INT_PTR )ppi->SearchBasic( StrConvT(( char* )lParam ));
+}
+
+static INT_PTR stub16( PROTO_INTERFACE* ppi, WPARAM, LPARAM lParam )
+{ return ( INT_PTR )ppi->SearchByEmail( StrConvT(( char* )lParam ));
+}
+
+static INT_PTR stub17( PROTO_INTERFACE* ppi, WPARAM, LPARAM lParam )
+{ PROTOSEARCHBYNAME* psbn = ( PROTOSEARCHBYNAME* )lParam;
+ return ( INT_PTR )ppi->SearchByName( StrConvT(( char* )psbn->pszNick ),
+ StrConvT(( char* )psbn->pszFirstName ), StrConvT(( char* )psbn->pszLastName ));
+}
+
+static INT_PTR stub18( PROTO_INTERFACE* ppi, WPARAM, LPARAM lParam )
+{ return ( INT_PTR )ppi->SearchAdvanced(( HWND )lParam );
+}
+
+static INT_PTR stub19( PROTO_INTERFACE* ppi, WPARAM, LPARAM lParam )
+{ return ( INT_PTR )ppi->CreateExtendedSearchUI (( HWND )lParam );
+}
+
+static INT_PTR stub22( PROTO_INTERFACE* ppi, WPARAM, LPARAM lParam )
+{ CCSDATA *ccs = ( CCSDATA* )lParam;
+ ppi->RecvMsg( ccs->hContact, ( PROTORECVEVENT* )ccs->lParam );
+ return 0;
+}
+
+static INT_PTR stub29( PROTO_INTERFACE* ppi, WPARAM wParam, LPARAM )
+{ return ( INT_PTR )ppi->SetStatus( wParam );
+}
+
+static INT_PTR stub33( PROTO_INTERFACE* ppi, WPARAM wParam, LPARAM lParam )
+{ return ( INT_PTR )ppi->SetAwayMsg( wParam, StrConvT(( const char* )lParam ));
+}
+
+static INT_PTR stub41( PROTO_INTERFACE* ppi, WPARAM wParam, LPARAM lParam )
+{ lstrcpynA(( char* )lParam, ppi->m_szModuleName, wParam );
+ return 0;
+}
+
+static INT_PTR stub42( PROTO_INTERFACE* ppi, WPARAM wParam, LPARAM lParam )
+{ return ppi->m_iStatus;
+}
+
+#ifdef _UNICODE
+
+static INT_PTR stub43( PROTO_INTERFACE* ppi, WPARAM wParam, LPARAM lParam )
+{
+ PROTO_AVATAR_INFORMATION* p = ( PROTO_AVATAR_INFORMATION* )lParam;
+
+ PROTO_AVATAR_INFORMATIONW tmp = { 0 };
+ tmp.cbSize = sizeof( tmp );
+ tmp.hContact = p->hContact;
+ int result = CallProtoService( ppi->m_szModuleName, PS_GETAVATARINFOW, wParam, ( LPARAM )&tmp );
+
+ p->format = tmp.format;
+
+ wchar_t filename[MAX_PATH];
+ wcscpy(filename, tmp.filename);
+ GetShortPathNameW(tmp.filename, filename, SIZEOF(filename));
+
+ WideCharToMultiByte( CP_ACP, 0, filename, -1, p->filename, MAX_PATH, 0, 0 );
+ return result;
+}
+
+static INT_PTR stub44( PROTO_INTERFACE* ppi, WPARAM wParam, LPARAM lParam )
+{
+ wchar_t* buf = ( wchar_t* )_alloca( sizeof(wchar_t) * (lParam + 1));
+ int result = CallProtoService( ppi->m_szModuleName, PS_GETMYAVATARW, WPARAM( buf ), lParam );
+ if ( result == 0 )
+ {
+ wchar_t* filename = ( wchar_t* )_alloca( sizeof(wchar_t) * (lParam + 1));
+ wcscpy(filename, buf);
+ GetShortPathNameW(buf, filename, lParam + 1);
+
+ WideCharToMultiByte( CP_ACP, 0, filename, -1, ( char* )wParam, lParam, 0, 0 );
+ }
+
+ return result;
+}
+
+static INT_PTR stub45( PROTO_INTERFACE* ppi, WPARAM wParam, LPARAM lParam )
+{
+ return CallProtoService( ppi->m_szModuleName, PS_SETMYAVATARW, wParam, ( LPARAM )( LPCTSTR )StrConvT(( char* )lParam ));
+}
+
+#endif
+
+static HANDLE CreateProtoServiceEx( const char* szModule, const char* szService, MIRANDASERVICEOBJ pFunc, void* param )
+{
+ char tmp[100];
+ mir_snprintf( tmp, sizeof( tmp ), "%s%s", szModule, szService );
+ return CreateServiceFunctionObj( tmp, pFunc, param );
+}
+
+BOOL ActivateAccount( PROTOACCOUNT* pa )
+{
+ PROTO_INTERFACE* ppi;
+ PROTOCOLDESCRIPTOR* ppd = Proto_IsProtocolLoaded( pa->szProtoName );
+ if ( ppd == NULL )
+ return FALSE;
+
+ if ( ppd->fnInit == NULL )
+ return FALSE;
+
+ ppi = ppd->fnInit( pa->szModuleName, pa->tszAccountName );
+ if ( ppi == NULL )
+ return FALSE;
+
+ pa->type = PROTOTYPE_PROTOCOL;
+ pa->ppro = ppi;
+ ppi->m_iDesiredStatus = ppi->m_iStatus = ID_STATUS_OFFLINE;
+ CreateProtoServiceEx( pa->szModuleName, PS_ADDTOLIST, (MIRANDASERVICEOBJ)stub1, pa->ppro );
+ CreateProtoServiceEx( pa->szModuleName, PS_ADDTOLISTBYEVENT, (MIRANDASERVICEOBJ)stub2, pa->ppro );
+ CreateProtoServiceEx( pa->szModuleName, PS_AUTHALLOW, (MIRANDASERVICEOBJ)stub3, pa->ppro );
+ CreateProtoServiceEx( pa->szModuleName, PS_AUTHDENY, (MIRANDASERVICEOBJ)stub4, pa->ppro );
+ CreateProtoServiceEx( pa->szModuleName, PS_CHANGEINFO, (MIRANDASERVICEOBJ)stub7, pa->ppro );
+ CreateProtoServiceEx( pa->szModuleName, PS_FILERESUME, (MIRANDASERVICEOBJ)stub11, pa->ppro );
+ CreateProtoServiceEx( pa->szModuleName, PS_GETCAPS, (MIRANDASERVICEOBJ)stub12, pa->ppro );
+ CreateProtoServiceEx( pa->szModuleName, PS_LOADICON, (MIRANDASERVICEOBJ)stub13, pa->ppro );
+ CreateProtoServiceEx( pa->szModuleName, PS_BASICSEARCH, (MIRANDASERVICEOBJ)stub15, pa->ppro );
+ CreateProtoServiceEx( pa->szModuleName, PS_SEARCHBYEMAIL, (MIRANDASERVICEOBJ)stub16, pa->ppro );
+ CreateProtoServiceEx( pa->szModuleName, PS_SEARCHBYNAME, (MIRANDASERVICEOBJ)stub17, pa->ppro );
+ CreateProtoServiceEx( pa->szModuleName, PS_SEARCHBYADVANCED, (MIRANDASERVICEOBJ)stub18, pa->ppro );
+ CreateProtoServiceEx( pa->szModuleName, PS_CREATEADVSEARCHUI, (MIRANDASERVICEOBJ)stub19, pa->ppro );
+ CreateProtoServiceEx( pa->szModuleName, PSR_MESSAGE, (MIRANDASERVICEOBJ)stub22, pa->ppro );
+ CreateProtoServiceEx( pa->szModuleName, PS_SETSTATUS, (MIRANDASERVICEOBJ)stub29, pa->ppro );
+ CreateProtoServiceEx( pa->szModuleName, PS_SETAWAYMSG, (MIRANDASERVICEOBJ)stub33, pa->ppro );
+ CreateProtoServiceEx( pa->szModuleName, PS_GETNAME, (MIRANDASERVICEOBJ)stub41, pa->ppro );
+ CreateProtoServiceEx( pa->szModuleName, PS_GETSTATUS, (MIRANDASERVICEOBJ)stub42, pa->ppro );
+
+#ifdef _UNICODE
+ char szServiceName[ 200 ];
+ mir_snprintf( szServiceName, SIZEOF(szServiceName), "%s%s", pa->szModuleName, PS_GETAVATARINFO );
+ if ( !ServiceExists( szServiceName )) {
+ mir_snprintf( szServiceName, SIZEOF(szServiceName), "%s%s", pa->szModuleName, PS_GETAVATARINFOW );
+ if ( ServiceExists( szServiceName ))
+ CreateProtoServiceEx( pa->szModuleName, PS_GETAVATARINFO, (MIRANDASERVICEOBJ)stub43, pa->ppro );
+ }
+
+ mir_snprintf( szServiceName, SIZEOF(szServiceName), "%s%s", pa->szModuleName, PS_GETMYAVATAR );
+ if ( !ServiceExists( szServiceName )) {
+ mir_snprintf( szServiceName, SIZEOF(szServiceName), "%s%s", pa->szModuleName, PS_GETMYAVATARW );
+ if ( ServiceExists( szServiceName ))
+ CreateProtoServiceEx( pa->szModuleName, PS_GETMYAVATAR, (MIRANDASERVICEOBJ)stub44, pa->ppro );
+ }
+
+ mir_snprintf( szServiceName, SIZEOF(szServiceName), "%s%s", pa->szModuleName, PS_SETMYAVATAR );
+ if ( !ServiceExists( szServiceName )) {
+ mir_snprintf( szServiceName, SIZEOF(szServiceName), "%s%s", pa->szModuleName, PS_SETMYAVATARW );
+ if ( ServiceExists( szServiceName ))
+ CreateProtoServiceEx( pa->szModuleName, PS_SETMYAVATAR, (MIRANDASERVICEOBJ)stub45, pa->ppro );
+ }
+ #endif
+ return TRUE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+struct DeactivationThreadParam
+{
+ tagPROTO_INTERFACE* ppro;
+ pfnUninitProto fnUninit;
+ bool bIsDynamic;
+ bool bErase;
+};
+
+pfnUninitProto GetProtocolDestructor( char* szProto );
+
+static int DeactivationThread( DeactivationThreadParam* param )
+{
+ tagPROTO_INTERFACE* p = ( tagPROTO_INTERFACE* )param->ppro;
+ p->SetStatus(ID_STATUS_OFFLINE);
+
+ char * szModuleName = NEWSTR_ALLOCA(p->m_szModuleName);
+
+ if ( param->bIsDynamic ) {
+ p->OnEvent( EV_PROTO_ONREADYTOEXIT, 0, 0 );
+ p->OnEvent( EV_PROTO_ONEXIT, 0, 0 );
+ }
+
+ KillObjectThreads( p ); // waits for them before terminating
+ KillObjectEventHooks( p ); // untie an object from the outside world
+
+ if ( param->bErase )
+ p->OnEvent( EV_PROTO_ONERASE, 0, 0 );
+
+ if ( param->fnUninit )
+ param->fnUninit( p );
+
+ KillObjectServices( p );
+
+ if ( param->bErase )
+ EraseAccount( szModuleName );
+
+ delete param;
+ return 0;
+}
+
+void DeactivateAccount( PROTOACCOUNT* pa, bool bIsDynamic, bool bErase )
+{
+ if ( pa->ppro == NULL ) {
+ if ( bErase )
+ EraseAccount( pa->szModuleName );
+ return;
+ }
+
+ if ( pa->hwndAccMgrUI ) {
+ DestroyWindow(pa->hwndAccMgrUI);
+ pa->hwndAccMgrUI = NULL;
+ pa->bAccMgrUIChanged = FALSE;
+ }
+
+ DeactivationThreadParam* param = new DeactivationThreadParam;
+ param->ppro = pa->ppro;
+ param->fnUninit = GetProtocolDestructor( pa->szProtoName );
+ param->bIsDynamic = bIsDynamic;
+ param->bErase = bErase;
+ pa->ppro = NULL;
+ pa->type = PROTOTYPE_DISPROTO;
+ if ( bIsDynamic )
+ mir_forkthread(( pThreadFunc )DeactivationThread, param );
+ else
+ DeactivationThread( param );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void EraseAccount( const char* pszModuleName )
+{
+ DBVARIANT dbv;
+ DBCONTACTGETSETTING dbcgs;
+ char szProtoName[32];
+
+ dbcgs.pValue = &dbv;
+ dbcgs.szModule = "Protocol";
+ dbcgs.szSetting = "p";
+
+ // remove protocol contacts first
+ HANDLE hContact = ( HANDLE )CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 );
+ while ( hContact != NULL ) {
+ HANDLE h1 = hContact;
+ hContact = ( HANDLE )CallService( MS_DB_CONTACT_FINDNEXT, ( WPARAM )h1, 0 );
+
+ dbv.type = DBVT_ASCIIZ;
+ dbv.pszVal = szProtoName;
+ dbv.cchVal = SIZEOF(szProtoName);
+
+ if ( CallService( MS_DB_CONTACT_GETSETTINGSTATIC, ( WPARAM )h1, ( LPARAM )&dbcgs ))
+ continue;
+
+ if ( !lstrcmpA( szProtoName, pszModuleName ))
+ CallService( MS_DB_CONTACT_DELETE, ( WPARAM )h1, 0 );
+ }
+
+ // remove all protocol settings
+ CallService( MS_DB_MODULE_DELETE, 0, ( LPARAM )pszModuleName );
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void UnloadAccount( PROTOACCOUNT* pa, bool bIsDynamic, bool bErase )
+{
+ DeactivateAccount( pa, bIsDynamic, bErase );
+
+ mir_free( pa->tszAccountName );
+ mir_free( pa->szProtoName );
+ // szModuleName should be freed only on a program's exit.
+ // otherwise many plugins dependand on static protocol names will crash!
+ // do NOT fix this 'leak', please
+ if ( !bIsDynamic ) {
+ mir_free( pa->szModuleName );
+ mir_free( pa );
+ }
+}
+
+void UnloadAccountsModule()
+{
+ int i;
+
+ if ( !bModuleInitialized ) return;
+
+ for( i=accounts.getCount()-1; i >= 0; i-- ) {
+ PROTOACCOUNT* pa = accounts[ i ];
+ UnloadAccount( pa, false, false );
+ accounts.remove(i);
+ }
+
+ accounts.destroy();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void BuildProtoMenus()
+{
+ for ( int i = 0; i < accounts.getCount(); i++ ) {
+ PROTOACCOUNT* pa = accounts[ i ];
+ if ( cli.pfnGetProtocolVisibility( pa->szModuleName ) == 0 )
+ continue;
+
+ if ( pa->ppro )
+ pa->ppro->OnEvent( EV_PROTO_ONMENU, 0, 0 );
+ }
+}
+
+void RebuildProtoMenus( int iNewValue )
+{
+ DBWriteContactSettingByte( NULL, "CList", "MoveProtoMenus", iNewValue );
+
+ RebuildMenuOrder();
+ BuildProtoMenus();
+}
diff --git a/src/modules/protocols/protochains.cpp b/src/modules/protocols/protochains.cpp
new file mode 100644
index 0000000000..f7f3729806
--- /dev/null
+++ b/src/modules/protocols/protochains.cpp
@@ -0,0 +1,274 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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.
+*/
+#include "commonheaders.h"
+#include <m_protomod.h>
+
+//Protocol chain is list of integers "0".."n", with network protocol named "p"
+INT_PTR Proto_CallContactService(WPARAM wParam,LPARAM lParam)
+//note that this is ChainSend() too, due to a quirk of function definitions
+{
+ CCSDATA *ccs=(CCSDATA*)lParam;
+ int i;
+ char str[10];
+ DBVARIANT dbv;
+ INT_PTR ret;
+ PROTOACCOUNT* pa;
+
+ if ( wParam == (WPARAM)(-1))
+ return 1;
+
+ for ( i = wParam;; i++ ) {
+ _itoa( i, str, 10 );
+ if ( DBGetContactSettingString( ccs->hContact, "_Filter", str, &dbv ))
+ break;
+
+ if (( ret = CallProtoService( dbv.pszVal, ccs->szProtoService, i+1, lParam )) != CALLSERVICE_NOTFOUND ) {
+ //chain was started, exit
+ mir_free( dbv.pszVal );
+ return ret;
+ }
+ mir_free( dbv.pszVal );
+ }
+ if ( DBGetContactSettingString( ccs->hContact, "Protocol", "p", &dbv ))
+ return 1;
+
+ pa = Proto_GetAccount( dbv.pszVal );
+ if ( pa == NULL || pa->ppro == NULL )
+ ret = 1;
+ else {
+ if ( pa->bOldProto )
+ ret = CallProtoServiceInt( ccs->hContact, dbv.pszVal, ccs->szProtoService, (WPARAM)(-1), ( LPARAM)ccs );
+ else
+ ret = CallProtoServiceInt( ccs->hContact, dbv.pszVal, ccs->szProtoService, ccs->wParam, ccs->lParam );
+ if ( ret == CALLSERVICE_NOTFOUND )
+ ret = 1;
+ }
+
+ mir_free(dbv.pszVal);
+ return ret;
+}
+
+static INT_PTR CallRecvChain(WPARAM wParam,LPARAM lParam)
+{
+ CCSDATA *ccs=(CCSDATA*)lParam;
+ int i;
+ INT_PTR ret;
+ char str[10];
+ DBVARIANT dbv;
+ PROTOACCOUNT* pa;
+
+ if ( wParam == (WPARAM)(-1)) return 1; //shouldn't happen - sanity check
+ if ( wParam == 0 ) { //begin processing by finding end of chain
+ for( ;;wParam++ ) {
+ _itoa( wParam, str, 10 );
+ if ( DBGetContactSettingString( ccs->hContact, "_Filter", str, &dbv ))
+ break;
+ mir_free(dbv.pszVal);
+ }
+ }
+ else wParam--;
+
+ for ( i = wParam-1; i >= 0; i-- ) {
+ _itoa( i, str, 10 );
+ if ( DBGetContactSettingString( ccs->hContact, "_Filter", str, &dbv )) //never happens
+ return 1;
+
+ if (( ret = CallProtoService( dbv.pszVal, ccs->szProtoService, i+1, lParam )) != CALLSERVICE_NOTFOUND ) {
+ //chain was started, exit
+ mir_free( dbv.pszVal );
+ return ret;
+ }
+ mir_free( dbv.pszVal );
+ }
+
+ //end of chain, call network protocol again
+ if ( DBGetContactSettingString( ccs->hContact, "Protocol", "p", &dbv ))
+ return 1;
+
+ pa = Proto_GetAccount( dbv.pszVal );
+ if ( pa == NULL || pa->ppro == NULL )
+ ret = 1;
+ else {
+ if ( pa->bOldProto )
+ ret = CallProtoServiceInt( ccs->hContact, dbv.pszVal, ccs->szProtoService, (WPARAM)(-1), ( LPARAM)ccs );
+ else
+ ret = CallProtoServiceInt( ccs->hContact, dbv.pszVal, ccs->szProtoService, ccs->wParam, ccs->lParam );
+ if ( ret == CALLSERVICE_NOTFOUND )
+ ret = 1;
+ }
+
+ mir_free( dbv.pszVal );
+ return ret;
+}
+
+static INT_PTR Proto_ChainRecv(WPARAM wParam,LPARAM lParam)
+{
+ /* this will switch threads just like before */
+ return CallServiceSync(MS_PROTO_CHAINRECV "ThreadSafe",wParam,lParam);
+}
+
+PROTOACCOUNT* __fastcall Proto_GetAccount(HANDLE hContact)
+{
+ DBVARIANT dbv;
+ DBCONTACTGETSETTING dbcgs;
+ char name[32];
+
+ dbv.type = DBVT_ASCIIZ;
+ dbv.pszVal = name;
+ dbv.cchVal = SIZEOF(name);
+ dbcgs.pValue = &dbv;
+ dbcgs.szModule = "Protocol";
+ dbcgs.szSetting = "p";
+ if (CallService(MS_DB_CONTACT_GETSETTINGSTATIC, (WPARAM)hContact, (LPARAM)&dbcgs))
+ return 0;
+
+ return Proto_GetAccount((char* )dbv.pszVal);
+}
+
+static INT_PTR Proto_GetContactBaseProto(WPARAM wParam, LPARAM)
+{
+ PROTOACCOUNT* pa = Proto_GetAccount((HANDLE)wParam);
+ return (INT_PTR)(Proto_IsAccountEnabled( pa ) ? pa->szModuleName : NULL);
+}
+
+static INT_PTR Proto_GetContactBaseAccount(WPARAM wParam, LPARAM)
+{
+ PROTOACCOUNT* pa = Proto_GetAccount((HANDLE)wParam);
+ return (INT_PTR)(pa ? pa->szModuleName : NULL);
+}
+
+static INT_PTR Proto_IsProtoOnContact(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+ char str[10];
+ DBVARIANT dbv;
+
+ if (!lParam) return 0;
+
+ if(!DBGetContactSettingString((HANDLE)wParam,"Protocol","p",&dbv)) {
+ if(!_stricmp((char*)lParam,dbv.pszVal)) {
+ mir_free(dbv.pszVal);
+ return -1;
+ }
+ mir_free(dbv.pszVal);
+ }
+ for(i=0;;i++) {
+ _itoa(i,str,10);
+ if(DBGetContactSettingString((HANDLE)wParam,"_Filter",str,&dbv)) break;
+ if(!strcmp((char*)lParam,dbv.pszVal)) {
+ mir_free(dbv.pszVal);
+ return i+1;
+ }
+ mir_free(dbv.pszVal);
+ }
+ return 0;
+}
+
+static INT_PTR Proto_AddToContact(WPARAM wParam,LPARAM lParam)
+{
+ PROTOCOLDESCRIPTOR *pd,*pdCompare;
+
+ pd = Proto_IsProtocolLoaded(( char* )lParam );
+ if ( pd == NULL ) {
+ PROTOACCOUNT* pa = Proto_GetAccount(( char* )lParam );
+ if ( pa ) {
+ DBWriteContactSettingString((HANDLE)wParam,"Protocol","p",(char*)lParam);
+ return 0;
+ }
+ return 1;
+ }
+
+ if ( pd->type == PROTOTYPE_PROTOCOL ) {
+ DBWriteContactSettingString((HANDLE)wParam,"Protocol","p",(char*)lParam);
+ return 0;
+ }
+ if(Proto_IsProtoOnContact(wParam,lParam)) return 1;
+ { /* v:0.3.3 + PROTO FILTERS ARE NOW KEPT IN THEIR OWN DB MODULE! */
+ int i;
+ char str[10],*lastProto;
+ DBVARIANT dbv;
+
+ for(i=0;;i++) {
+ _itoa(i,str,10);
+ if(DBGetContactSettingString((HANDLE)wParam,"_Filter",str,&dbv)) break;
+ pdCompare = Proto_IsProtocolLoaded(( char* )dbv.pszVal );
+ mir_free(dbv.pszVal);
+ if(pdCompare==NULL) continue;
+ if(pd->type > pdCompare->type) break;
+ }
+ //put the new module at position i
+ lastProto=mir_strdup((char*)lParam);
+ for(;;i++) {
+ _itoa(i,str,10);
+ if(DBGetContactSettingString((HANDLE)wParam,"_Filter",str,&dbv)) {
+ DBWriteContactSettingString((HANDLE)wParam,"_Filter",str,lastProto);
+ mir_free(lastProto);
+ break;
+ }
+ DBWriteContactSettingString((HANDLE)wParam,"_Filter",str,lastProto);
+ mir_free(lastProto);
+ lastProto=dbv.pszVal;
+ }
+ }
+ return 0;
+}
+
+static INT_PTR Proto_RemoveFromContact(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+ DBVARIANT dbv;
+ char str[10];
+
+ i = Proto_IsProtoOnContact(wParam,lParam);
+ if(!i) return 1;
+ if(i==-1)
+ DBDeleteContactSetting((HANDLE)wParam,"Protocol","p");
+ else {
+ for(i--;;i++) { //we have to decrease i, as Proto_IsOnContact returns +1 more number than read from database
+ _itoa(i+1,str,10);
+ if(0!=DBGetContactSettingString((HANDLE)wParam,"_Filter",str,&dbv)) {
+ _itoa(i,str,10);
+ DBDeleteContactSetting((HANDLE)wParam,"_Filter",str);
+ break;
+ }
+ _itoa(i,str,10);
+ DBWriteContactSettingString((HANDLE)wParam,"_Filter",str,dbv.pszVal);
+ mir_free(dbv.pszVal);
+ }
+ }
+ return 0;
+}
+
+int LoadProtoChains(void)
+{
+ CreateServiceFunction(MS_PROTO_CALLCONTACTSERVICE,Proto_CallContactService);
+ CreateServiceFunction(MS_PROTO_CHAINSEND,Proto_CallContactService);
+ CreateServiceFunction(MS_PROTO_CHAINRECV,Proto_ChainRecv);
+ CreateServiceFunction(MS_PROTO_CHAINRECV "ThreadSafe",CallRecvChain);
+ CreateServiceFunction(MS_PROTO_GETCONTACTBASEPROTO,Proto_GetContactBaseProto);
+ CreateServiceFunction(MS_PROTO_GETCONTACTBASEACCOUNT,Proto_GetContactBaseAccount);
+ CreateServiceFunction(MS_PROTO_ISPROTOONCONTACT,Proto_IsProtoOnContact);
+ CreateServiceFunction(MS_PROTO_ADDTOCONTACT,Proto_AddToContact);
+ CreateServiceFunction(MS_PROTO_REMOVEFROMCONTACT,Proto_RemoveFromContact);
+ return 0;
+}
diff --git a/src/modules/protocols/protocols.cpp b/src/modules/protocols/protocols.cpp
new file mode 100644
index 0000000000..60b53aeaf4
--- /dev/null
+++ b/src/modules/protocols/protocols.cpp
@@ -0,0 +1,844 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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.
+*/
+#include "commonheaders.h"
+
+int LoadProtoChains(void);
+int LoadProtoOptions( void );
+
+HANDLE hAccListChanged;
+static HANDLE hAckEvent,hTypeEvent;
+static BOOL bModuleInitialized = FALSE;
+
+typedef struct
+{
+ const char* name;
+ int id;
+}
+ TServiceListItem;
+
+static int CompareServiceItems( const TServiceListItem* p1, const TServiceListItem* p2 )
+{ return strcmp( p1->name, p2->name );
+}
+
+static LIST<TServiceListItem> serviceItems( 10, CompareServiceItems );
+
+//------------------------------------------------------------------------------------
+
+static int CompareProtos( const PROTOCOLDESCRIPTOR* p1, const PROTOCOLDESCRIPTOR* p2 )
+{ return strcmp( p1->szName, p2->szName );
+}
+
+static LIST<PROTOCOLDESCRIPTOR> protos( 10, CompareProtos );
+
+static INT_PTR Proto_BroadcastAck(WPARAM wParam, LPARAM lParam)
+{
+#ifdef _UNICODE
+ ACKDATA *ack = (ACKDATA*)lParam;
+ if (ack && ack->type == ACKTYPE_AVATAR && ack->hProcess)
+ {
+ PROTO_AVATAR_INFORMATION* ai = (PROTO_AVATAR_INFORMATION*)ack->hProcess;
+ if (ai->cbSize == sizeof(PROTO_AVATAR_INFORMATION))
+ {
+ PROTO_AVATAR_INFORMATIONW aiw = { sizeof(aiw), ai->hContact, ai->format };
+ MultiByteToWideChar(CP_ACP, 0, ai->filename, -1, aiw.filename, SIZEOF(aiw.filename));
+
+ ack->hProcess = &aiw;
+ }
+ }
+#endif
+
+ return NotifyEventHooks(hAckEvent, wParam, lParam);
+}
+
+INT_PTR __fastcall MyCallProtoService( const char *szModule, const char *szService, WPARAM wParam, LPARAM lParam );
+void FreeFilesMatrix( TCHAR ***files );
+
+PROTOCOLDESCRIPTOR* __fastcall Proto_IsProtocolLoaded( const char* szProtoName )
+{
+ if ( szProtoName ) {
+ PROTOCOLDESCRIPTOR tmp;
+ tmp.szName = ( char* )szProtoName;
+ return protos.find( &tmp );
+ }
+ return NULL;
+}
+
+INT_PTR srvProto_IsLoaded(WPARAM, LPARAM lParam)
+{
+ return (INT_PTR)Proto_GetAccount(( char* )lParam );
+}
+
+INT_PTR Proto_EnumProtocols(WPARAM wParam,LPARAM lParam)
+{
+ *( int* )wParam = protos.getCount();
+ *( PROTOCOLDESCRIPTOR*** )lParam = protos.getArray();
+ return 0;
+}
+
+static PROTO_INTERFACE* defInitProto( const char* szModuleName, const TCHAR* )
+{
+ return AddDefaultAccount( szModuleName );
+}
+
+static INT_PTR Proto_RegisterModule(WPARAM, LPARAM lParam)
+{
+ PROTOCOLDESCRIPTOR* pd = ( PROTOCOLDESCRIPTOR* )lParam, *p;
+ if ( pd->cbSize != sizeof( PROTOCOLDESCRIPTOR ) && pd->cbSize != PROTOCOLDESCRIPTOR_V3_SIZE )
+ return 1;
+
+ p = ( PROTOCOLDESCRIPTOR* )mir_alloc( sizeof( PROTOCOLDESCRIPTOR ));
+ if ( !p )
+ return 2;
+
+ if ( pd->cbSize == PROTOCOLDESCRIPTOR_V3_SIZE ) {
+ memset( p, 0, sizeof( PROTOCOLDESCRIPTOR ));
+ p->cbSize = PROTOCOLDESCRIPTOR_V3_SIZE;
+ p->type = pd->type;
+ if ( p->type == PROTOTYPE_PROTOCOL ) {
+ // let's create a new container
+ PROTO_INTERFACE* ppi = AddDefaultAccount( pd->szName );
+ if ( ppi ) {
+ PROTOACCOUNT* pa = Proto_GetAccount( pd->szName );
+ if ( pa == NULL ) {
+ pa = (PROTOACCOUNT*)mir_calloc( sizeof( PROTOACCOUNT ));
+ pa->cbSize = sizeof(PROTOACCOUNT);
+ pa->type = PROTOTYPE_PROTOCOL;
+ pa->szModuleName = mir_strdup( pd->szName );
+ pa->szProtoName = mir_strdup( pd->szName );
+ pa->tszAccountName = mir_a2t( pd->szName );
+ pa->bIsVisible = pa->bIsEnabled = TRUE;
+ pa->iOrder = accounts.getCount();
+ accounts.insert( pa );
+ }
+ pa->bOldProto = TRUE;
+ pa->ppro = ppi;
+ p->fnInit = defInitProto;
+ p->fnUninit = FreeDefaultAccount;
+ }
+ }
+ }
+ else *p = *pd;
+ p->szName = mir_strdup( pd->szName );
+ protos.insert( p );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Basic core services
+
+static INT_PTR Proto_RecvFile(WPARAM,LPARAM lParam)
+{
+ CCSDATA* ccs = ( CCSDATA* )lParam;
+ PROTORECVEVENT* pre = ( PROTORECVEVENT* )ccs->lParam;
+ char* szFile = pre->szMessage + sizeof( DWORD );
+ char* szDescr = szFile + strlen( szFile ) + 1;
+
+ // Suppress the standard event filter
+ if ( pre->lParam != NULL )
+ *( DWORD* )pre->szMessage = 0;
+
+ DBEVENTINFO dbei = { 0 };
+ dbei.cbSize = sizeof( dbei );
+ dbei.szModule = ( char* )CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)ccs->hContact, 0);
+ dbei.timestamp = pre->timestamp;
+ dbei.flags = ( pre->flags & PREF_CREATEREAD ) ? DBEF_READ : 0;
+ dbei.flags |= ( pre->flags & PREF_UTF ) ? DBEF_UTF : 0;
+ dbei.eventType = EVENTTYPE_FILE;
+ dbei.cbBlob = (DWORD)(sizeof( DWORD ) + strlen( szFile ) + strlen( szDescr ) + 2);
+ dbei.pBlob = ( PBYTE )pre->szMessage;
+ HANDLE hdbe = ( HANDLE )CallService( MS_DB_EVENT_ADD, ( WPARAM )ccs->hContact, ( LPARAM )&dbei );
+
+ if ( pre->lParam != NULL )
+ PushFileEvent( ccs->hContact, hdbe, pre->lParam );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static void sttRecvCreateBlob( DBEVENTINFO& dbei, int fileCount, char** pszFiles, char* szDescr )
+{
+ dbei.cbBlob = sizeof( DWORD );
+ {
+ for ( int i=0; i < fileCount; i++ )
+ dbei.cbBlob += lstrlenA( pszFiles[i] ) + 1;
+ }
+
+ dbei.cbBlob += lstrlenA( szDescr ) + 1;
+
+ if (( dbei.pBlob = ( BYTE* )mir_alloc( dbei.cbBlob )) == 0 )
+ return;
+
+ *( DWORD* )dbei.pBlob = 0;
+ BYTE* p = dbei.pBlob + sizeof( DWORD );
+ for ( int i=0; i < fileCount; i++ ) {
+ strcpy(( char* )p, pszFiles[i] );
+ p += lstrlenA( pszFiles[i] ) + 1;
+ }
+ strcpy(( char* )p, ( szDescr == NULL ) ? "" : szDescr );
+}
+
+static INT_PTR Proto_RecvFileT(WPARAM,LPARAM lParam)
+{
+ CCSDATA* ccs = ( CCSDATA* )lParam;
+ PROTORECVFILET* pre = ( PROTORECVFILET* )ccs->lParam;
+ if ( pre->fileCount == 0 )
+ return 0;
+
+ DBEVENTINFO dbei = { 0 };
+ dbei.cbSize = sizeof( dbei );
+ dbei.szModule = ( char* )CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)ccs->hContact, 0);
+ dbei.timestamp = pre->timestamp;
+ dbei.flags = ( pre->flags & PREF_CREATEREAD ) ? DBEF_READ : 0;
+ dbei.eventType = EVENTTYPE_FILE;
+
+ char** pszFiles = ( char** )alloca( pre->fileCount * sizeof(char*));
+ {
+ for ( int i=0; i < pre->fileCount; i++ )
+ pszFiles[i] = Utf8EncodeT( pre->ptszFiles[i] );
+ }
+ char* szDescr = Utf8EncodeT( pre->tszDescription );
+ dbei.flags |= DBEF_UTF;
+ sttRecvCreateBlob( dbei, pre->fileCount, pszFiles, szDescr );
+ {
+ for ( int i=0; i < pre->fileCount; i++ )
+ mir_free( pszFiles[i] );
+ }
+ mir_free( szDescr );
+
+ HANDLE hdbe = ( HANDLE )CallService( MS_DB_EVENT_ADD, ( WPARAM )ccs->hContact, ( LPARAM )&dbei );
+
+ PushFileEvent( ccs->hContact, hdbe, pre->lParam );
+ mir_free( dbei.pBlob );
+ return 0;
+}
+
+static INT_PTR Proto_RecvMessage(WPARAM,LPARAM lParam)
+{
+ CCSDATA *ccs = ( CCSDATA* )lParam;
+ PROTORECVEVENT *pre = ( PROTORECVEVENT* )ccs->lParam;
+
+ if (pre->szMessage == NULL) return NULL;
+
+ DBEVENTINFO dbei = { 0 };
+ dbei.cbSize = sizeof( dbei );
+ dbei.szModule = ( char* )CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)ccs->hContact, 0);
+ dbei.timestamp = pre->timestamp;
+ dbei.eventType = EVENTTYPE_MESSAGE;
+ dbei.cbBlob = (DWORD)strlen( pre->szMessage ) + 1;
+ if ( pre->flags & PREF_CREATEREAD )
+ dbei.flags |= DBEF_READ;
+ if ( pre->flags & PREF_UTF )
+ dbei.flags |= DBEF_UTF;
+ if ( pre->flags & PREF_UNICODE )
+ dbei.cbBlob += sizeof( wchar_t )*( (DWORD)wcslen(( wchar_t* )&pre->szMessage[dbei.cbBlob+1] )+1 );
+
+ dbei.pBlob = ( PBYTE ) pre->szMessage;
+ return CallService( MS_DB_EVENT_ADD, ( WPARAM ) ccs->hContact, ( LPARAM )&dbei );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// User Typing Notification services
+
+static int Proto_ValidTypingContact(HANDLE hContact, char *szProto)
+{
+ if ( !hContact || !szProto )
+ return 0;
+
+ return ( CallProtoService(szProto,PS_GETCAPS,PFLAGNUM_4,0) & PF4_SUPPORTTYPING ) ? 1 : 0;
+}
+
+static INT_PTR Proto_SelfIsTyping(WPARAM wParam,LPARAM lParam)
+{
+ if ( lParam == PROTOTYPE_SELFTYPING_OFF || lParam == PROTOTYPE_SELFTYPING_ON ) {
+ char* szProto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, wParam, 0 );
+ if ( !szProto )
+ return 0;
+
+ if ( Proto_ValidTypingContact(( HANDLE )wParam, szProto ))
+ CallProtoService( szProto, PSS_USERISTYPING, wParam, lParam );
+ }
+
+ return 0;
+}
+
+static INT_PTR Proto_ContactIsTyping(WPARAM wParam,LPARAM lParam)
+{
+ int type = (int)lParam;
+ char *szProto = ( char* )CallService( MS_PROTO_GETCONTACTBASEPROTO, wParam, 0 );
+ if ( !szProto )
+ return 0;
+
+ if ( CallService( MS_IGNORE_ISIGNORED, wParam, IGNOREEVENT_TYPINGNOTIFY ))
+ return 0;
+
+ if ( type < PROTOTYPE_CONTACTTYPING_OFF )
+ return 0;
+
+ if ( Proto_ValidTypingContact(( HANDLE )wParam, szProto ))
+ NotifyEventHooks( hTypeEvent, wParam, lParam );
+
+ return 0;
+}
+
+void Proto_SetStatus(const char* szProto, unsigned status)
+{
+ if (CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_MODEMSGSEND)
+ {
+ TCHAR* awayMsg = (TCHAR* )CallService(MS_AWAYMSG_GETSTATUSMSGW, (WPARAM) status, (LPARAM) szProto);
+ if ((INT_PTR)awayMsg == CALLSERVICE_NOTFOUND)
+ {
+ char* awayMsgA = (char*)CallService(MS_AWAYMSG_GETSTATUSMSG, (WPARAM) status, (LPARAM) szProto);
+ if ((INT_PTR)awayMsgA != CALLSERVICE_NOTFOUND)
+ {
+ awayMsg = mir_a2t(awayMsgA);
+ mir_free(awayMsgA);
+ }
+ }
+ if ((INT_PTR)awayMsg != CALLSERVICE_NOTFOUND)
+ {
+ CallProtoService(szProto, PS_SETAWAYMSGT, status, (LPARAM) awayMsg);
+ mir_free(awayMsg);
+ } }
+ CallProtoService(szProto, PS_SETSTATUS, status, 0);
+}
+
+#ifdef _UNICODE
+char** __fastcall Proto_FilesMatrixA( wchar_t **files )
+{
+ if ( files == NULL ) return NULL;
+
+ int count = 0;
+ while( files[ count++ ] );
+
+ char** filesA = ( char** )mir_alloc( count * sizeof( char* ));
+ for( int i = 0; i < count; ++i )
+ filesA[ i ] = mir_u2a( files[ i ] );
+
+ return filesA;
+}
+
+static wchar_t** __fastcall Proto_FilesMatrixU( char **files )
+{
+ if ( files == NULL ) return NULL;
+
+ int count = 0;
+ while( files[ count++ ] );
+
+ wchar_t** filesU = ( wchar_t** )mir_alloc( count * sizeof( wchar_t* ));
+ for( int i = 0; i < count; ++i )
+ filesU[ i ] = mir_a2u( files[ i ] );
+
+ return filesU;
+}
+#endif
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// 0.8.0+ - accounts
+
+PROTOACCOUNT* __fastcall Proto_GetAccount( const char* accName )
+{
+ int idx;
+ PROTOACCOUNT temp;
+ temp.szModuleName = ( char* )accName;
+ if (( idx = accounts.getIndex( &temp )) == -1 )
+ return NULL;
+
+ return accounts[idx];
+}
+
+static INT_PTR srvProto_GetAccount(WPARAM, LPARAM lParam)
+{
+ return ( INT_PTR )Proto_GetAccount(( char* )lParam );
+}
+
+static INT_PTR Proto_EnumAccounts(WPARAM wParam, LPARAM lParam)
+{
+ *( int* )wParam = accounts.getCount();
+ *( PROTOACCOUNT*** )lParam = accounts.getArray();
+ return 0;
+}
+
+bool __fastcall Proto_IsAccountEnabled( PROTOACCOUNT* pa )
+{
+ return pa && (( pa->bIsEnabled && !pa->bDynDisabled ) || pa->bOldProto );
+}
+
+static INT_PTR srvProto_IsAccountEnabled(WPARAM, LPARAM lParam)
+{
+ return ( INT_PTR )Proto_IsAccountEnabled(( PROTOACCOUNT* )lParam);
+}
+
+bool __fastcall Proto_IsAccountLocked( PROTOACCOUNT* pa )
+{
+ return pa && DBGetContactSettingByte(NULL, pa->szModuleName, "LockMainStatus", 0) != 0;
+}
+
+static INT_PTR srvProto_IsAccountLocked(WPARAM, LPARAM lParam)
+{
+ return ( INT_PTR )Proto_IsAccountLocked( Proto_GetAccount(( char* )lParam ));
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+INT_PTR CallProtoServiceInt( HANDLE hContact, const char *szModule, const char *szService, WPARAM wParam, LPARAM lParam )
+{
+ PROTOACCOUNT* pa = Proto_GetAccount( szModule );
+ if ( pa && !pa->bOldProto ) {
+ PROTO_INTERFACE* ppi;
+ if (( ppi = pa->ppro ) == NULL )
+ return CALLSERVICE_NOTFOUND;
+ else {
+ TServiceListItem *item = serviceItems.find(( TServiceListItem* )&szService );
+ if ( item ) {
+ switch( item->id ) {
+ case 1:
+#ifdef _UNICODE
+ if ( ppi->m_iVersion > 1 || !((( PROTOSEARCHRESULT* )lParam)->flags & PSR_UNICODE))
+ return ( INT_PTR )ppi->AddToList( wParam, (PROTOSEARCHRESULT*)lParam );
+ else {
+ PROTOSEARCHRESULT *psr = ( PROTOSEARCHRESULT* )lParam;
+ PROTOSEARCHRESULT *psra =( PROTOSEARCHRESULT* )mir_alloc( psr->cbSize );
+ memcpy( psra, psr, psr->cbSize );
+ psra->nick = ( PROTOCHAR* )mir_u2a( psr->nick );
+ psra->firstName = ( PROTOCHAR* )mir_u2a( psr->firstName );
+ psra->lastName = ( PROTOCHAR* )mir_u2a( psr->lastName );
+ psra->email = ( PROTOCHAR* )mir_u2a( psr->email );
+
+ INT_PTR res = ( INT_PTR )ppi->AddToList( wParam, psra );
+
+ mir_free( psra->nick );
+ mir_free( psra->firstName );
+ mir_free( psra->lastName );
+ mir_free( psra->email );
+ mir_free( psra );
+
+ return res;
+ }
+#else
+ return ( INT_PTR )ppi->AddToList( wParam, (PROTOSEARCHRESULT*)lParam );
+#endif
+ case 2: return ( INT_PTR )ppi->AddToListByEvent( LOWORD(wParam), HIWORD(wParam), (HANDLE)lParam );
+ case 3: return ( INT_PTR )ppi->Authorize( ( HANDLE )wParam );
+ case 4:
+ if ( ppi->m_iVersion > 1 )
+ return ( INT_PTR )ppi->AuthDeny(( HANDLE )wParam, StrConvT(( char* )lParam ));
+ else
+ return ( INT_PTR )ppi->AuthDeny(( HANDLE )wParam, ( PROTOCHAR* )lParam );
+ case 5: return ( INT_PTR )ppi->AuthRecv( hContact, ( PROTORECVEVENT* )lParam );
+ case 6:
+ if ( ppi->m_iVersion > 1 )
+ return ( INT_PTR )ppi->AuthRequest( hContact, StrConvT(( char* )lParam ));
+ else
+ return ( INT_PTR )ppi->AuthRequest( hContact, ( PROTOCHAR* )lParam );
+ case 7: return ( INT_PTR )ppi->ChangeInfo( wParam, ( void* )lParam );
+ case 8:
+ if ( ppi->m_iVersion > 1 )
+ return ( INT_PTR )ppi->FileAllow( hContact, ( HANDLE )wParam, StrConvT(( char* )lParam ));
+ else
+ return ( INT_PTR )ppi->FileAllow( hContact, ( HANDLE )wParam, ( PROTOCHAR* )lParam );
+ case 9: return ( INT_PTR )ppi->FileCancel( hContact, ( HANDLE )wParam );
+ case 10:
+ if ( ppi->m_iVersion > 1 )
+ return ( INT_PTR )ppi->FileDeny( hContact, ( HANDLE )wParam, StrConvT(( char* )lParam ));
+ else
+ return ( INT_PTR )ppi->FileDeny( hContact, ( HANDLE )wParam, ( PROTOCHAR* )lParam );
+ case 11: {
+ PROTOFILERESUME* pfr = ( PROTOFILERESUME* )lParam;
+#ifdef _UNICODE
+ if ( ppi->m_iVersion > 1 ) {
+ PROTOCHAR* szFname = mir_a2t(( char* )pfr->szFilename );
+ INT_PTR res = ( INT_PTR )ppi->FileResume(( HANDLE )wParam, &pfr->action,
+ ( const PROTOCHAR** )&szFname);
+ mir_free(( PROTOCHAR* )pfr->szFilename );
+ pfr->szFilename = ( PROTOCHAR* )mir_t2a( szFname ); mir_free( szFname );
+ }
+ else
+#endif
+ return ( INT_PTR )ppi->FileResume(( HANDLE )wParam, &pfr->action,
+ ( const PROTOCHAR** )&pfr->szFilename );
+ }
+ case 12: return ( INT_PTR )ppi->GetCaps( wParam, (HANDLE)lParam );
+ case 13: return ( INT_PTR )ppi->GetIcon( wParam );
+ case 14: return ( INT_PTR )ppi->GetInfo( hContact, wParam );;
+ case 15:
+ if ( ppi->m_iVersion > 1 )
+ return ( INT_PTR )ppi->SearchBasic( StrConvT(( char* )lParam ));
+ else
+ return ( INT_PTR )ppi->SearchBasic(( TCHAR* )lParam );
+ case 16:
+ if ( ppi->m_iVersion > 1 )
+ return ( INT_PTR )ppi->SearchByEmail( StrConvT(( char* )lParam ));
+ else
+ return ( INT_PTR )ppi->SearchByEmail(( TCHAR* )lParam );
+ case 17: {
+ PROTOSEARCHBYNAME* psbn = ( PROTOSEARCHBYNAME* )lParam;
+ if ( ppi->m_iVersion > 1 )
+ return ( INT_PTR )ppi->SearchByName( StrConvT(( char* )psbn->pszNick ),
+ StrConvT(( char* )psbn->pszFirstName ), StrConvT(( char* )psbn->pszLastName ));
+ else
+ return ( INT_PTR )ppi->SearchByName( psbn->pszNick, psbn->pszFirstName, psbn->pszLastName );
+ }
+ case 18: return ( INT_PTR )ppi->SearchAdvanced( ( HWND )lParam );
+ case 19: return ( INT_PTR )ppi->CreateExtendedSearchUI ( ( HWND )lParam );
+ case 20: return ( INT_PTR )ppi->RecvContacts( hContact, ( PROTORECVEVENT* )lParam );
+ case 21: return ( INT_PTR )ppi->RecvFile( hContact, ( PROTOFILEEVENT* )lParam );
+ case 22: return ( INT_PTR )ppi->RecvMsg( hContact, ( PROTORECVEVENT* )lParam );
+ case 23: return ( INT_PTR )ppi->RecvUrl( hContact, ( PROTORECVEVENT* )lParam );
+ case 24: return ( INT_PTR )ppi->SendContacts( hContact, LOWORD( wParam ), HIWORD( wParam ),
+ ( HANDLE* )lParam );
+ case 25:
+#ifdef _UNICODE
+ if ( ppi->m_iVersion > 1 ) {
+ TCHAR** files = Proto_FilesMatrixU(( char** )lParam );
+ INT_PTR res = ( INT_PTR )ppi->SendFile( hContact, StrConvT(( char* )wParam ), ( TCHAR** )files );
+ if ( res == 0 ) FreeFilesMatrix( &files );
+ return res;
+ }
+ else
+#endif
+ return ( INT_PTR )ppi->SendFile( hContact, ( TCHAR* )wParam, ( TCHAR** )lParam );
+ case 26: return ( INT_PTR )ppi->SendMsg( hContact, wParam, ( const char* )lParam );
+ case 27: return ( INT_PTR )ppi->SendUrl( hContact, wParam, ( const char* )lParam );
+ case 28: return ( INT_PTR )ppi->SetApparentMode( hContact, wParam );
+ case 29: return ( INT_PTR )ppi->SetStatus( wParam );
+ case 30: return ( INT_PTR )ppi->GetAwayMsg( hContact );
+ case 31: return ( INT_PTR )ppi->RecvAwayMsg( hContact, wParam, ( PROTORECVEVENT* )lParam );
+ case 32: return ( INT_PTR )ppi->SendAwayMsg( hContact, ( HANDLE )wParam, ( const char* )lParam );
+ case 33:
+ if ( ppi->m_iVersion > 1 )
+ return ( INT_PTR )ppi->SetAwayMsg( wParam, StrConvT(( char* )lParam ));
+ else
+ return ( INT_PTR )ppi->SetAwayMsg( wParam, ( TCHAR* )lParam );
+ case 34: return ( INT_PTR )ppi->UserIsTyping( ( HANDLE )wParam, lParam );
+ case 35: lstrcpynA(( char* )lParam, ppi->m_szModuleName, wParam ); return 0;
+ case 36: return ppi->m_iStatus;
+
+#ifdef _UNICODE
+ case 100:
+ if ( ppi->m_iVersion > 1 )
+ return ( INT_PTR )ppi->SetAwayMsg( wParam, ( TCHAR* )lParam );
+ else
+ return ( INT_PTR )ppi->SetAwayMsg( wParam, StrConvA(( TCHAR* )lParam ));
+ case 102:
+ if ( ppi->m_iVersion > 1 )
+ return ( INT_PTR )ppi->SendFile( hContact, ( TCHAR* )wParam, ( TCHAR** )lParam );
+ else {
+ char** files = Proto_FilesMatrixA(( TCHAR** )lParam );
+ INT_PTR res = ( INT_PTR )ppi->SendFile( hContact, StrConvA(( TCHAR* )wParam ), ( TCHAR** )files );
+ if ( res == 0 ) FreeFilesMatrix(( TCHAR*** )&files );
+ return res;
+ }
+ case 103:
+ if ( ppi->m_iVersion > 1 )
+ return ( INT_PTR )ppi->FileAllow( hContact, ( HANDLE )wParam, ( TCHAR* )lParam );
+ else
+ return ( INT_PTR )ppi->FileAllow( hContact, ( HANDLE )wParam, StrConvA(( TCHAR* )lParam ));
+ case 104:
+ if ( ppi->m_iVersion > 1 )
+ return ( INT_PTR )ppi->FileDeny( hContact, ( HANDLE )wParam, ( TCHAR* )lParam );
+ else
+ return ( INT_PTR )ppi->FileDeny( hContact, ( HANDLE )wParam, StrConvA(( TCHAR* )lParam ));
+ case 105: {
+ PROTOFILERESUME* pfr = ( PROTOFILERESUME* )lParam;
+ if ( ppi->m_iVersion > 1 )
+ return ( INT_PTR )ppi->FileResume(( HANDLE )wParam, &pfr->action,
+ ( const PROTOCHAR** )&pfr->szFilename );
+ else {
+ char* szFname = mir_t2a( pfr->szFilename );
+ INT_PTR res = ( INT_PTR )ppi->FileResume(( HANDLE )wParam, &pfr->action,
+ ( const PROTOCHAR** )&szFname);
+ mir_free( szFname );
+ } }
+ case 106:
+ if ( ppi->m_iVersion > 1 )
+ return ( INT_PTR )ppi->AuthRequest( hContact, ( const TCHAR* )lParam );
+ else
+ return ( INT_PTR )ppi->AuthRequest( hContact, StrConvA(( const TCHAR* )lParam ));
+ case 107:
+ if ( ppi->m_iVersion > 1 )
+ return ( INT_PTR )ppi->AuthDeny(( HANDLE )wParam, ( const TCHAR* )lParam );
+ else
+ return ( INT_PTR )ppi->AuthDeny(( HANDLE )wParam, StrConvA(( const TCHAR* )lParam ));
+ case 108:
+ if ( ppi->m_iVersion > 1 )
+ return ( INT_PTR )ppi->SearchBasic(( const TCHAR* )lParam );
+ else
+ return ( INT_PTR )ppi->SearchBasic(StrConvA(( const TCHAR* )lParam ));
+ case 109: {
+ PROTOSEARCHBYNAME* psbn = ( PROTOSEARCHBYNAME* )lParam;
+ if ( ppi->m_iVersion > 1 )
+ return ( INT_PTR )ppi->SearchByName( psbn->pszNick, psbn->pszFirstName, psbn->pszLastName );
+ else
+ return ( INT_PTR )ppi->SearchByName( StrConvA(( TCHAR* )psbn->pszNick ),
+ StrConvA(( TCHAR* )psbn->pszFirstName ), StrConvA(( TCHAR* )psbn->pszLastName ));
+ }
+ case 110:
+ if ( ppi->m_iVersion > 1 )
+ return ( INT_PTR )ppi->SearchByEmail(( const TCHAR* )lParam );
+ else
+ return ( INT_PTR )ppi->SearchByEmail(StrConvA(( const TCHAR* )lParam ));
+#endif
+ } } } }
+
+#ifdef _UNICODE
+ if ( strcmp( szService, PS_ADDTOLIST ) == 0 ) {
+ PROTOSEARCHRESULT *psr = ( PROTOSEARCHRESULT* )lParam;
+ PROTOSEARCHRESULT *psra =( PROTOSEARCHRESULT* )mir_alloc( psr->cbSize );
+ memcpy( psra, psr, psr->cbSize );
+ psra->nick = ( PROTOCHAR* )mir_u2a( psr->nick );
+ psra->firstName = ( PROTOCHAR* )mir_u2a( psr->firstName );
+ psra->lastName = ( PROTOCHAR* )mir_u2a( psr->lastName );
+ psra->email = ( PROTOCHAR* )mir_u2a( psr->email );
+
+ INT_PTR res = MyCallProtoService( szModule, szService, wParam, ( LPARAM )psra );
+
+ mir_free( psra->nick );
+ mir_free( psra->firstName );
+ mir_free( psra->lastName );
+ mir_free( psra->email );
+ mir_free( psra );
+
+ return res;
+ }
+#endif
+
+ INT_PTR res = MyCallProtoService( szModule, szService, wParam, lParam );
+
+#ifdef _UNICODE
+ if ( res == CALLSERVICE_NOTFOUND && pa && pa->bOldProto && pa->ppro && strchr( szService, 'W' )) {
+ TServiceListItem *item = serviceItems.find(( TServiceListItem* )&szService );
+ if ( !item ) return res;
+
+ switch( item->id ) {
+ case 100:
+ return ( INT_PTR )pa->ppro->SetAwayMsg( wParam, ( TCHAR* )lParam );
+ case 102: {
+ CCSDATA *ccs = ( CCSDATA* )lParam;
+ return ( INT_PTR )pa->ppro->SendFile( ccs->hContact, ( TCHAR* )ccs->wParam, ( TCHAR** )ccs->lParam );
+ }
+ case 103: {
+ CCSDATA *ccs = ( CCSDATA* )lParam;
+ return ( INT_PTR )pa->ppro->FileAllow( ccs->hContact, ( HANDLE )ccs->wParam, ( TCHAR* )ccs->lParam );
+ }
+ case 104: {
+ CCSDATA *ccs = ( CCSDATA* )lParam;
+ return ( INT_PTR )pa->ppro->FileDeny( ccs->hContact, ( HANDLE )ccs->wParam, ( TCHAR* )ccs->lParam );
+ }
+ case 105: {
+ PROTOFILERESUME* pfr = ( PROTOFILERESUME* )lParam;
+ return ( INT_PTR )pa->ppro->FileResume(( HANDLE )wParam, &pfr->action, &pfr->szFilename );
+ }
+ case 106: {
+ CCSDATA *ccs = ( CCSDATA* )lParam;
+ return ( INT_PTR )pa->ppro->AuthRequest( ccs->hContact, ( const TCHAR* )ccs->lParam );
+ }
+ case 107:
+ return ( INT_PTR )pa->ppro->AuthDeny(( HANDLE )wParam, ( const TCHAR* )lParam );
+ case 108:
+ return ( INT_PTR )pa->ppro->SearchBasic(( const TCHAR* )lParam );
+ case 109: {
+ PROTOSEARCHBYNAME* psbn = ( PROTOSEARCHBYNAME* )lParam;
+ return ( INT_PTR )pa->ppro->SearchByName( psbn->pszNick, psbn->pszFirstName, psbn->pszLastName );
+ }
+ case 110:
+ return ( INT_PTR )pa->ppro->SearchByEmail(( const TCHAR* )lParam );
+ } }
+#endif
+
+ return res;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+INT_PTR CallContactService( HANDLE hContact, const char *szProtoService, WPARAM wParam, LPARAM lParam )
+{
+ int i;
+ DBVARIANT dbv;
+ INT_PTR ret;
+ PROTOACCOUNT* pa;
+ CCSDATA ccs = { hContact, szProtoService, wParam, lParam };
+
+ for ( i = 0;; i++ ) {
+ char str[10];
+ _itoa( i, str, 10 );
+ if ( DBGetContactSettingString( hContact, "_Filter", str, &dbv ))
+ break;
+
+ if (( ret = CallProtoServiceInt( hContact, dbv.pszVal, szProtoService, i+1, ( LPARAM)&ccs )) != CALLSERVICE_NOTFOUND ) {
+ //chain was started, exit
+ mir_free( dbv.pszVal );
+ return ret;
+ }
+ mir_free( dbv.pszVal );
+ }
+ if ( DBGetContactSettingString( hContact, "Protocol", "p", &dbv ))
+ return 1;
+
+ pa = Proto_GetAccount( dbv.pszVal );
+ if ( pa == NULL || pa->ppro == NULL )
+ ret = 1;
+ else {
+ if ( pa->bOldProto )
+ ret = CallProtoServiceInt( hContact, dbv.pszVal, szProtoService, (WPARAM)(-1), ( LPARAM)&ccs );
+ else
+ ret = CallProtoServiceInt( hContact, dbv.pszVal, szProtoService, wParam, lParam );
+ if ( ret == CALLSERVICE_NOTFOUND )
+ ret = 1;
+ }
+
+ mir_free( dbv.pszVal );
+ return ret;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static void InsertServiceListItem( int id, const char* szName )
+{
+ TServiceListItem* p = ( TServiceListItem* )mir_alloc( sizeof( TServiceListItem ));
+ p->id = id;
+ p->name = szName;
+ serviceItems.insert( p );
+}
+
+int LoadProtocolsModule(void)
+{
+ bModuleInitialized = TRUE;
+
+ if ( LoadProtoChains() )
+ return 1;
+
+ InsertServiceListItem( 1, PS_ADDTOLIST );
+ InsertServiceListItem( 2, PS_ADDTOLISTBYEVENT );
+ InsertServiceListItem( 3, PS_AUTHALLOW );
+ InsertServiceListItem( 4, PS_AUTHDENY );
+ InsertServiceListItem( 5, PSR_AUTH );
+ InsertServiceListItem( 6, PSS_AUTHREQUEST );
+ InsertServiceListItem( 7, PS_CHANGEINFO );
+ InsertServiceListItem( 8, PSS_FILEALLOW );
+ InsertServiceListItem( 9, PSS_FILECANCEL );
+ InsertServiceListItem( 10, PSS_FILEDENY );
+ InsertServiceListItem( 11, PS_FILERESUME );
+ InsertServiceListItem( 12, PS_GETCAPS );
+ InsertServiceListItem( 13, PS_LOADICON );
+ InsertServiceListItem( 14, PSS_GETINFO );
+ InsertServiceListItem( 15, PS_BASICSEARCH );
+ InsertServiceListItem( 16, PS_SEARCHBYEMAIL );
+ InsertServiceListItem( 17, PS_SEARCHBYNAME );
+ InsertServiceListItem( 18, PS_SEARCHBYADVANCED );
+ InsertServiceListItem( 19, PS_CREATEADVSEARCHUI );
+ InsertServiceListItem( 20, PSR_CONTACTS );
+ InsertServiceListItem( 21, PSR_FILE );
+ InsertServiceListItem( 22, PSR_MESSAGE );
+ InsertServiceListItem( 23, PSR_URL );
+ InsertServiceListItem( 24, PSS_CONTACTS );
+ InsertServiceListItem( 25, PSS_FILE );
+ InsertServiceListItem( 26, PSS_MESSAGE );
+ InsertServiceListItem( 27, PSS_URL );
+ InsertServiceListItem( 28, PSS_SETAPPARENTMODE );
+ InsertServiceListItem( 29, PS_SETSTATUS );
+ InsertServiceListItem( 30, PSS_GETAWAYMSG );
+ InsertServiceListItem( 31, PSR_AWAYMSG );
+ InsertServiceListItem( 32, PSS_AWAYMSG );
+ InsertServiceListItem( 33, PS_SETAWAYMSG );
+ InsertServiceListItem( 34, PSS_USERISTYPING );
+ InsertServiceListItem( 35, PS_GETNAME );
+ InsertServiceListItem( 36, PS_GETSTATUS );
+
+#ifdef _UNICODE
+ InsertServiceListItem( 100, PS_SETAWAYMSGW );
+ InsertServiceListItem( 102, PSS_FILEW );
+ InsertServiceListItem( 103, PSS_FILEALLOWW );
+ InsertServiceListItem( 104, PSS_FILEDENYW );
+ InsertServiceListItem( 105, PS_FILERESUMEW );
+ InsertServiceListItem( 106, PSS_AUTHREQUESTW );
+ InsertServiceListItem( 107, PS_AUTHDENYW );
+ InsertServiceListItem( 108, PS_BASICSEARCHW );
+ InsertServiceListItem( 109, PS_SEARCHBYNAMEW );
+ InsertServiceListItem( 110, PS_SEARCHBYEMAILW );
+#endif
+
+ hAckEvent = CreateHookableEvent(ME_PROTO_ACK);
+ hTypeEvent = CreateHookableEvent(ME_PROTO_CONTACTISTYPING);
+ hAccListChanged = CreateHookableEvent(ME_PROTO_ACCLISTCHANGED);
+
+ CreateServiceFunction( MS_PROTO_BROADCASTACK, Proto_BroadcastAck );
+ CreateServiceFunction( MS_PROTO_ISPROTOCOLLOADED, srvProto_IsLoaded );
+ CreateServiceFunction( MS_PROTO_ENUMPROTOS, Proto_EnumProtocols );
+ CreateServiceFunction( MS_PROTO_REGISTERMODULE, Proto_RegisterModule );
+ CreateServiceFunction( MS_PROTO_SELFISTYPING, Proto_SelfIsTyping );
+ CreateServiceFunction( MS_PROTO_CONTACTISTYPING, Proto_ContactIsTyping );
+
+ CreateServiceFunction( MS_PROTO_RECVFILE, Proto_RecvFile );
+ CreateServiceFunction( MS_PROTO_RECVFILET, Proto_RecvFileT );
+ CreateServiceFunction( MS_PROTO_RECVMSG, Proto_RecvMessage );
+
+ CreateServiceFunction( "Proto/EnumProtocols", Proto_EnumAccounts );
+ CreateServiceFunction( MS_PROTO_ENUMACCOUNTS, Proto_EnumAccounts );
+ CreateServiceFunction( MS_PROTO_GETACCOUNT, srvProto_GetAccount );
+
+ CreateServiceFunction( MS_PROTO_ISACCOUNTENABLED, srvProto_IsAccountEnabled );
+ CreateServiceFunction( MS_PROTO_ISACCOUNTLOCKED, srvProto_IsAccountLocked );
+
+ return LoadProtoOptions();
+}
+
+void UnloadProtocolsModule()
+{
+ int i;
+
+ if ( !bModuleInitialized ) return;
+
+ if ( hAckEvent ) {
+ DestroyHookableEvent(hAckEvent);
+ hAckEvent = NULL;
+ }
+ if ( hAccListChanged ) {
+ DestroyHookableEvent(hAccListChanged);
+ hAccListChanged = NULL;
+ }
+
+ if ( protos.getCount() ) {
+ for( i=0; i < protos.getCount(); i++ ) {
+ mir_free( protos[i]->szName);
+ mir_free( protos[i] );
+ }
+ protos.destroy();
+ }
+
+ for ( i=0; i < serviceItems.getCount(); i++ )
+ mir_free( serviceItems[i] );
+ serviceItems.destroy();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+pfnUninitProto GetProtocolDestructor( char* szProto )
+{
+ int idx;
+ PROTOCOLDESCRIPTOR temp;
+ temp.szName = szProto;
+ if (( idx = protos.getIndex( &temp )) != -1 )
+ return protos[idx]->fnUninit;
+
+ return NULL;
+}
diff --git a/src/modules/protocols/protodir.cpp b/src/modules/protocols/protodir.cpp
new file mode 100644
index 0000000000..7a110268ef
--- /dev/null
+++ b/src/modules/protocols/protodir.cpp
@@ -0,0 +1,248 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2005 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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.
+*/
+
+#include "commonheaders.h"
+
+#if 0
+
+extern HANDLE hCacheHeap;
+
+/*
+
+ the id cache has id/proto against hContact to lookup ID's fast to resolve to hContact,
+ the protoBaseCache has hContact's sorted, so can lookup hContact->proto fast, these two caches
+ share the same data, they're indexes, each entry might not have an "id" set.
+
+ There is a small cache which maintains a protocol list
+
+*/
+
+/*
+
+ The information we need to cache is not readily available, data has to be gathered at startup
+ when a new contact is created/deleted, when a new proto registers and so on.
+
+ The information we get at startup includes walking the contact chain and reading Protocol/p which
+ will give us the protocol the contact is on, all this info is stored in contactEntry's within
+ protoCache ONLY - contactCache is EMPTY at this point.
+
+ We can not fetch the id of the contact because this information is only in SOME protocol plugins,
+ this is a problem but we'll hook all proto registrations and ask each proto if it supports the
+ returning this ID name, if not - it won't even use our id <-> contact look so no biggie!
+
+*/
+
+typedef struct {
+ char * proto; // within proto cache
+ char * id; // optional
+ HANDLE hContact;
+} contactEntry;
+
+typedef struct {
+ CRITICAL_SECTION csLock;
+ SortedList contactCache; // index for id/proto -> hContact
+ SortedList protoCache; // index for hContact -> proto/id
+ SortedList protoNameCache; // index of protocol names
+} contactDir;
+
+static contactDir condir;
+
+// compare's id/proto and return's hContact's
+int contactCacheCompare(void * a, void * b)
+{
+ contactEntry * x = (contactEntry *) a;
+ contactEntry * y = (contactEntry *) b;
+ int rc=0;
+ // same protocol?
+ rc = strcmp(x->proto, y->proto);
+ if ( rc == 0 ) {
+ // same id? id's might be missing
+ if ( x->id && y->id ) rc = strcmp(x->id, y->id);
+ }
+ return rc;
+}
+
+// compares hContact's and returns associated data
+int protoCacheCompare(void * a, void * b)
+{
+ contactEntry * x = (contactEntry *) a;
+ contactEntry * y = (contactEntry *) b;
+ if ( x->hContact < y->hContact ) return -1;
+ if ( x->hContact > y->hContact ) return 1;
+ return 0;
+}
+
+// keeps a list of protocol names
+int protoNameCacheCompare(void * a, void * b)
+{
+ return strcmp( (char *)a, (char*)b );
+}
+
+// cache the protocol string so that its not allocated per contact but shared
+char * contactDir_Proto_Add(contactDir * cd, char * proto)
+{
+ int index = 0 ;
+ char * szCache = 0;
+ EnterCriticalSection(&cd->csLock);
+ if ( List_GetIndex(&cd->protoNameCache, proto, &index) ) szCache = cd->protoNameCache.items[index];
+ else {
+ szCache = HeapAlloc(hCacheHeap, HEAP_NO_SERIALIZE, strlen(proto)+1);
+ strcpy(szCache, proto);
+ List_Insert(&cd->protoNameCache, szCache, index);
+ }
+ LeaveCriticalSection(&cd->csLock);
+ return szCache;
+}
+
+// thread safe
+char * contactDir_Proto_Get(contactDir * cd, HANDLE hContact)
+{
+ char * szCache = 0;
+ int index = 0;
+ contactEntry e;
+ e.hContact=hContact;
+ e.proto="";
+ e.id="";
+ EnterCriticalSection(&cd->csLock);
+ if ( List_GetIndex(&cd->protoCache, &e, &index) ) {
+ contactEntry * p = cd->protoCache.items[index];
+ szCache = p->proto;
+ }
+ LeaveCriticalSection(&cd->csLock);
+ return szCache;
+}
+
+// thread tolerant, if updating id dont pass proto, if updating proto dont pass id
+void contactDir_Contact_Add(contactDir * cd, HANDLE hContact, char * proto, char * id)
+{
+ // if a contact is gonna exist anywhere it's going to be in the ->protoCache which has a key of hContact
+ // if id is not null then the contact should be indexed via the ->contactCache instead
+ if ( id == NULL ) {
+ int index = 0;
+ contactEntry e;
+ e.hContact=hContact;
+ e.proto = proto;
+ e.id = "";
+ EnterCriticalSection(&cd->csLock);
+ if ( List_GetIndex(&cd->protoCache, &e, &index) ) {
+ contactEntry * p = cd->protoCache.items[index];
+ // this hContact is in the cache, protcol changing?
+ p->proto = contactDir_Proto_Add(cd, proto); // just replace the old pointer
+ } else {
+ contactEntry * p = 0;
+ // this hContact isn't in the cache, add it
+ p = HeapAlloc(hCacheHeap, HEAP_NO_SERIALIZE, sizeof(contactEntry));
+ p->proto = contactDir_Proto_Add(cd, proto);
+ p->id = 0;
+ p->hContact = hContact;
+ // add it
+ List_Insert(&cd->protoCache, p, index);
+ }
+ LeaveCriticalSection(&cd->csLock);
+ } else {
+ // this contact HAS to be in ->protoCache since it was added during startup
+ // need to find the contactEntry* that should already exist for it
+ } //if
+}
+
+// only expected to be called at startup.
+void contactDir_Proto_Walk(contactDir * cd)
+{
+ HANDLE hContact;
+ char buf[128];
+ DBCONTACTGETSETTING gsProto;
+ DBVARIANT dbvProto;
+ // setup the read structure
+ gsProto.szModule="Protocol";
+ gsProto.szSetting="p";
+ gsProto.pValue = &dbvProto;
+ // this might not work
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while ( hContact ) {
+ // and how we'll get the reset
+ dbvProto.type=DBVT_ASCIIZ;
+ dbvProto.pszVal = (char *) &buf;
+ dbvProto.cchVal = SIZEOF(buf);
+ // figure out what hContact/Protocol/p is
+ if ( CallService(MS_DB_CONTACT_GETSETTINGSTATIC,(WPARAM)hContact, (LPARAM)&gsProto) == 0 ) {
+ contactDir_Contact_Add(cd, hContact, buf, NULL);
+ }
+ // find next
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0);
+ }
+}
+
+// ctor/dtor
+
+void contactDir_Init(contactDir * cd)
+{
+ InitializeCriticalSection(&cd->csLock);
+ cd->contactCache.increment=50;
+ cd->contactCache.sortFunc=contactCacheCompare;
+ cd->protoCache.increment=50;
+ cd->protoCache.sortFunc=protoCacheCompare;
+ cd->protoNameCache.increment=5;
+ cd->protoNameCache.sortFunc=protoNameCacheCompare;
+ // build a list of all hContact's and what proto's they are on
+ contactDir_Proto_Walk(cd);
+}
+
+void contactDir_Deinit(contactDir * cd)
+{
+ List_Destroy(&cd->contactCache);
+ List_Destroy(&cd->protoCache);
+ List_Destroy(&cd->protoNameCache);
+ DeleteCriticalSection(&cd->csLock);
+}
+
+static int contactDirGetProto(WPARAM wParam, LPARAM lParam)
+{
+ return (int) contactDir_Proto_Get(&condir,(HANDLE)wParam);
+}
+
+#endif
+
+void InitContactDir(void)
+{
+ return;
+ //contactDir_Init(&condir);
+ //CreateServiceFunction(MS_PROTODIR_PROTOFROMCONTACT, contactDirGetProto);
+}
+
+
+void UninitContactDir(void)
+{
+ return;
+#if 0
+ {
+ int j;
+ for ( j = 0; j< condir.protoCache.realCount; j++) {
+ char buf[128];
+ contactEntry * p = condir.protoCache.items[j];
+ mir_snprintf(buf,SIZEOF(buf)," [%s] %s @ %x \n", p->proto, p->id ? p->id : "", p->hContact);
+ OutputDebugString(buf);
+ }
+ }
+ contactDir_Deinit(&condir);
+#endif
+}
diff --git a/src/modules/protocols/protoint.cpp b/src/modules/protocols/protoint.cpp
new file mode 100644
index 0000000000..dec59cce98
--- /dev/null
+++ b/src/modules/protocols/protoint.cpp
@@ -0,0 +1,271 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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.
+*/
+
+#include "commonheaders.h"
+
+char** __fastcall Proto_FilesMatrixA( TCHAR **files );
+void FreeFilesMatrix( TCHAR ***files );
+
+INT_PTR __fastcall MyCallProtoService( const char *szModule, const char *szService, WPARAM wParam, LPARAM lParam )
+{
+ char str[MAXMODULELABELLENGTH];
+ mir_snprintf( str, sizeof(str), "%s%s", szModule, szService );
+ return CallService(str,wParam,lParam);
+}
+
+struct DEFAULT_PROTO_INTERFACE : public PROTO_INTERFACE
+{
+ HANDLE __cdecl AddToList( int flags, PROTOSEARCHRESULT* psr )
+ { return ( HANDLE )MyCallProtoService( m_szModuleName, PS_ADDTOLIST, flags, (LPARAM)psr );
+ }
+
+ HANDLE __cdecl AddToListByEvent( int flags, int iContact, HANDLE hDbEvent )
+ { return ( HANDLE )MyCallProtoService( m_szModuleName, PS_ADDTOLISTBYEVENT, MAKELONG(flags, iContact), (LPARAM)hDbEvent );
+ }
+
+ int __cdecl Authorize( HANDLE hContact )
+ { return ( int )MyCallProtoService( m_szModuleName, PS_AUTHALLOW, (WPARAM)hContact, 0 );
+ }
+
+ int __cdecl AuthDeny( HANDLE hContact, const TCHAR* szReason )
+ { return ( int )MyCallProtoService( m_szModuleName, PS_AUTHDENY, (WPARAM)hContact, (LPARAM)StrConvA(szReason));
+ }
+
+ int __cdecl AuthRecv( HANDLE hContact, PROTORECVEVENT* evt )
+ { CCSDATA ccs = { hContact, PSR_AUTH, 0, (LPARAM)evt };
+ return ( int )MyCallProtoService( m_szModuleName, PSR_AUTH, 0, (LPARAM)&ccs );
+ }
+
+ int __cdecl AuthRequest( HANDLE hContact, const TCHAR* szMessage )
+ { CCSDATA ccs = { hContact, PSS_AUTHREQUEST, 0, (LPARAM)szMessage };
+ ccs.lParam = ( LPARAM )mir_t2a( szMessage );
+ int res = ( int )MyCallProtoService( m_szModuleName, PSS_AUTHREQUEST, 0, (LPARAM)&ccs );
+ mir_free(( char* )ccs.lParam );
+ return res;
+ }
+
+ HANDLE __cdecl ChangeInfo( int iInfoType, void* pInfoData )
+ { return ( HANDLE )MyCallProtoService( m_szModuleName, PS_CHANGEINFO, iInfoType, ( LPARAM )pInfoData );
+ }
+
+ HANDLE __cdecl FileAllow( HANDLE hContact, HANDLE hTransfer, const PROTOCHAR* szPath )
+ { CCSDATA ccs = { hContact, PSS_FILEALLOW, (WPARAM)hTransfer, (LPARAM)szPath };
+#ifdef _UNICODE
+ ccs.lParam = ( LPARAM )mir_t2a( szPath );
+ HANDLE res = ( HANDLE )MyCallProtoService( m_szModuleName, PSS_FILEALLOW, 0, (LPARAM)&ccs );
+ mir_free(( char* )ccs.lParam );
+ return res;
+#else
+ return ( HANDLE )MyCallProtoService( m_szModuleName, PSS_FILEALLOW, 0, (LPARAM)&ccs );
+#endif
+ }
+
+ int __cdecl FileCancel( HANDLE hContact, HANDLE hTransfer )
+ { CCSDATA ccs = { hContact, PSS_FILECANCEL, (WPARAM)hTransfer, 0 };
+ return ( int )MyCallProtoService( m_szModuleName, PSS_FILECANCEL, 0, (LPARAM)&ccs );
+ }
+
+ int __cdecl FileDeny( HANDLE hContact, HANDLE hTransfer, const PROTOCHAR* szReason )
+ { CCSDATA ccs = { hContact, PSS_FILEDENY, (WPARAM)hTransfer, (LPARAM)szReason };
+#ifdef _UNICODE
+ ccs.lParam = ( LPARAM )mir_t2a( szReason );
+ int res = ( int )MyCallProtoService( m_szModuleName, PSS_FILEDENY, 0, (LPARAM)&ccs );
+ mir_free(( char* )ccs.lParam );
+ return res;
+#else
+ return ( int )MyCallProtoService( m_szModuleName, PSS_FILEDENY, 0, (LPARAM)&ccs );
+#endif
+ }
+
+ int __cdecl FileResume( HANDLE hTransfer, int* action, const PROTOCHAR** szFilename )
+ { PROTOFILERESUME pfr = { *action, *szFilename };
+#ifdef _UNICODE
+ pfr.szFilename = ( PROTOCHAR* )mir_t2a( pfr.szFilename );
+ int res = ( int )MyCallProtoService( m_szModuleName, PS_FILERESUME, ( WPARAM )hTransfer, ( LPARAM )&pfr);
+ mir_free(( PROTOCHAR* )*szFilename );
+ *action = pfr.action; *szFilename = (PROTOCHAR*)pfr.szFilename;
+#else
+ int res = ( int )MyCallProtoService( m_szModuleName, PS_FILERESUME, ( WPARAM )hTransfer, ( LPARAM )&pfr );
+ *action = pfr.action; *szFilename = (PROTOCHAR*)pfr.szFilename;
+#endif
+ return res;
+ }
+
+ DWORD_PTR __cdecl GetCaps( int type, HANDLE hContact )
+ { return ( DWORD_PTR )MyCallProtoService( m_szModuleName, PS_GETCAPS, type, (LPARAM)hContact );
+ }
+
+ HICON __cdecl GetIcon( int iconIndex )
+ { return ( HICON )MyCallProtoService( m_szModuleName, PS_LOADICON, iconIndex, 0 );
+ }
+
+ int __cdecl GetInfo( HANDLE hContact, int flags )
+ { CCSDATA ccs = { hContact, PSS_GETINFO, flags, 0 };
+ return MyCallProtoService( m_szModuleName, PSS_GETINFO, 0, (LPARAM)&ccs );
+ }
+
+ HANDLE __cdecl SearchBasic( const PROTOCHAR* id )
+ { return ( HANDLE )MyCallProtoService( m_szModuleName, PS_BASICSEARCH, 0, ( LPARAM )StrConvA( id ));
+ }
+
+ HANDLE __cdecl SearchByEmail( const PROTOCHAR* email )
+ { return ( HANDLE )MyCallProtoService( m_szModuleName, PS_SEARCHBYEMAIL, 0, ( LPARAM )StrConvA( email ));
+ }
+
+ HANDLE __cdecl SearchByName( const PROTOCHAR* nick, const PROTOCHAR* firstName, const PROTOCHAR* lastName )
+ { PROTOSEARCHBYNAME psn;
+#ifdef _UNICODE
+ psn.pszNick = ( PROTOCHAR* )mir_t2a( nick );
+ psn.pszFirstName = ( PROTOCHAR* )mir_t2a( firstName );
+ psn.pszLastName = ( PROTOCHAR* )mir_t2a( lastName );
+ HANDLE res = ( HANDLE )MyCallProtoService( m_szModuleName, PS_SEARCHBYNAME, 0, ( LPARAM )&psn );
+ mir_free( psn.pszNick );
+ mir_free( psn.pszFirstName );
+ mir_free( psn.pszLastName );
+ return res;
+#else
+ psn.pszNick = ( char* )nick;
+ psn.pszFirstName = ( char* )firstName;
+ psn.pszLastName = ( char* )lastName;
+ return ( HANDLE )MyCallProtoService( m_szModuleName, PS_SEARCHBYNAME, 0, ( LPARAM )&psn );
+#endif
+ }
+
+ HWND __cdecl SearchAdvanced( HWND owner )
+ { return ( HWND )MyCallProtoService( m_szModuleName, PS_SEARCHBYADVANCED, 0, ( LPARAM )owner );
+ }
+
+ HWND __cdecl CreateExtendedSearchUI( HWND owner )
+ { return ( HWND )MyCallProtoService( m_szModuleName, PS_CREATEADVSEARCHUI, 0, ( LPARAM )owner );
+ }
+
+ int __cdecl RecvContacts( HANDLE hContact, PROTORECVEVENT* evt )
+ { CCSDATA ccs = { hContact, PSR_CONTACTS, 0, (LPARAM)evt };
+ return ( int )MyCallProtoService( m_szModuleName, PSR_CONTACTS, 0, (LPARAM)&ccs );
+ }
+
+ int __cdecl RecvFile( HANDLE hContact, PROTOFILEEVENT* evt )
+ { CCSDATA ccs = { hContact, PSR_FILE, 0, (LPARAM)evt };
+ return MyCallProtoService( m_szModuleName, PSR_FILE, 0, (LPARAM)&ccs );
+ }
+
+ int __cdecl RecvMsg( HANDLE hContact, PROTORECVEVENT* evt )
+ { CCSDATA ccs = { hContact, PSR_MESSAGE, 0, (LPARAM)evt };
+ return ( int )MyCallProtoService( m_szModuleName, PSR_MESSAGE, 0, (LPARAM)&ccs );
+ }
+
+ int __cdecl RecvUrl( HANDLE hContact, PROTORECVEVENT* evt )
+ { CCSDATA ccs = { hContact, PSR_URL, 0, (LPARAM)evt };
+ return ( int )MyCallProtoService( m_szModuleName, PSR_URL, 0, (LPARAM)&ccs );
+ }
+
+ int __cdecl SendContacts( HANDLE hContact, int flags, int nContacts, HANDLE* hContactsList )
+ { CCSDATA ccs = { hContact, PSS_CONTACTS, MAKEWPARAM(flags,nContacts), (LPARAM)hContactsList };
+ return ( int )MyCallProtoService( m_szModuleName, PSS_CONTACTS, 0, (LPARAM)&ccs );
+ }
+
+ HANDLE __cdecl SendFile( HANDLE hContact, const PROTOCHAR* szDescription, PROTOCHAR** ppszFiles )
+ { CCSDATA ccs = { hContact, PSS_FILE, (WPARAM)szDescription, (LPARAM)ppszFiles };
+#ifdef _UNICODE
+ ccs.wParam = ( WPARAM )mir_t2a( szDescription );
+ ccs.lParam = ( LPARAM )Proto_FilesMatrixA( ppszFiles );
+ HANDLE res = ( HANDLE )MyCallProtoService( m_szModuleName, PSS_FILE, 0, ( LPARAM )&ccs );
+ if ( res == 0 ) FreeFilesMatrix(( TCHAR*** )&ccs.lParam );
+ mir_free(( char* )ccs.wParam );
+ return res;
+#else
+ return ( HANDLE )MyCallProtoService( m_szModuleName, PSS_FILE, 0, (LPARAM)&ccs );
+#endif
+ }
+
+ int __cdecl SendMsg( HANDLE hContact, int flags, const char* msg )
+ { CCSDATA ccs = { hContact, PSS_MESSAGE, flags, (LPARAM)msg };
+ return ( int )MyCallProtoService( m_szModuleName, PSS_MESSAGE, 0, (LPARAM)&ccs );
+ }
+
+ int __cdecl SendUrl( HANDLE hContact, int flags, const char* url )
+ { CCSDATA ccs = { hContact, PSS_URL, flags, (LPARAM)url };
+ return ( int )MyCallProtoService( m_szModuleName, PSS_URL, 0, (LPARAM)&ccs );
+ }
+
+ int __cdecl SetApparentMode( HANDLE hContact, int mode )
+ { CCSDATA ccs = { hContact, PSS_SETAPPARENTMODE, mode, 0 };
+ return ( int )MyCallProtoService( m_szModuleName, PSS_SETAPPARENTMODE, 0, (LPARAM)&ccs );
+ }
+
+ int __cdecl SetStatus( int iNewStatus )
+ { return ( int )MyCallProtoService( m_szModuleName, PS_SETSTATUS, iNewStatus, 0 );
+ }
+
+ HANDLE __cdecl GetAwayMsg( HANDLE hContact )
+ { CCSDATA ccs = { hContact, PSS_GETAWAYMSG, 0, 0 };
+ return ( HANDLE )MyCallProtoService( m_szModuleName, PSS_GETAWAYMSG, 0, (LPARAM)&ccs );
+ }
+
+ int __cdecl RecvAwayMsg( HANDLE hContact, int statusMode, PROTORECVEVENT* evt )
+ { CCSDATA ccs = { hContact, PSR_AWAYMSG, statusMode, (LPARAM)evt };
+ return ( int )MyCallProtoService( m_szModuleName, PSR_AWAYMSG, 0, (LPARAM)&ccs );
+ }
+
+ int __cdecl SendAwayMsg( HANDLE hContact, HANDLE hProcess, const char* msg )
+ { CCSDATA ccs = { hContact, PSS_AWAYMSG, (WPARAM)hProcess, (LPARAM)msg };
+ return ( int )MyCallProtoService( m_szModuleName, PSS_AWAYMSG, 0, (LPARAM)&ccs );
+ }
+
+ int __cdecl SetAwayMsg( int iStatus, const TCHAR* msg )
+ { return ( int )MyCallProtoService( m_szModuleName, PS_SETAWAYMSG, iStatus, (LPARAM)StrConvA(msg));
+ }
+
+ int __cdecl UserIsTyping( HANDLE hContact, int type )
+ { CCSDATA ccs = { hContact, PSS_USERISTYPING, (WPARAM)hContact, type };
+ return MyCallProtoService( m_szModuleName, PSS_USERISTYPING, 0, (LPARAM)&ccs );
+ }
+
+ int __cdecl OnEvent( PROTOEVENTTYPE, WPARAM, LPARAM )
+ {
+ return 0;
+ }
+};
+
+// creates the default protocol container for compatibility with the old plugins
+
+PROTO_INTERFACE* AddDefaultAccount( const char* szProtoName )
+{
+ PROTO_INTERFACE* ppi = new DEFAULT_PROTO_INTERFACE;
+ if ( ppi != NULL ) {
+ ppi->m_iVersion = 1;
+ ppi->m_szModuleName = mir_strdup( szProtoName );
+ ppi->m_szProtoName = mir_strdup( szProtoName );
+ ppi->m_tszUserName = mir_a2t( szProtoName );
+ }
+ return ppi;
+}
+
+int FreeDefaultAccount( PROTO_INTERFACE* ppi )
+{
+ mir_free( ppi->m_szModuleName );
+ mir_free( ppi->m_szProtoName );
+ mir_free( ppi->m_tszUserName );
+ delete ppi;
+ return 0;
+}
diff --git a/src/modules/protocols/protoopts.cpp b/src/modules/protocols/protoopts.cpp
new file mode 100644
index 0000000000..3d9c0a2b36
--- /dev/null
+++ b/src/modules/protocols/protoopts.cpp
@@ -0,0 +1,1084 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2009 Miranda ICQ/IM project,
+all portions of this codebase are copyrighted to the people
+listed in contributors.txt.
+
+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.
+*/
+
+#include "commonheaders.h"
+
+#define LBN_MY_CHECK 0x1000
+#define LBN_MY_RENAME 0x1001
+
+#define WM_MY_REFRESH (WM_USER+0x1000)
+#define WM_MY_RENAME (WM_USER+0x1001)
+
+INT_PTR Proto_EnumProtocols( WPARAM, LPARAM );
+bool CheckProtocolOrder(void);
+
+#define errMsg \
+"WARNING! The account is going to be deleted. It means that all its \
+settings, contacts and histories will be also erased.\n\n\
+Are you absolutely sure?"
+
+#define upgradeMsg \
+"Your account was successfully upgraded. \
+To activate it, restart of Miranda is needed.\n\n\
+If you want to restart Miranda now, press Yes, if you want to upgrade another account, press No"
+
+#define legacyMsg \
+"This account uses legacy protocol plugin. \
+Use Miranda IM options dialogs to change it's preferences."
+
+#define welcomeMsg \
+"Welcome to Miranda IM's account manager!\n \
+Here you can set up your IM accounts.\n\n \
+Select an account from the list on the left to see the available options. \
+Alternatively, just click on the Plus sign underneath the list to set up a new IM account."
+
+static HWND hAccMgr = NULL;
+
+extern HANDLE hAccListChanged;
+
+int UnloadPlugin( TCHAR* buf, int bufLen );
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Account edit form
+// Gets PROTOACCOUNT* as a parameter, or NULL to edit a new one
+
+typedef struct
+{
+ int action;
+ PROTOACCOUNT* pa;
+}
+ AccFormDlgParam;
+
+static INT_PTR CALLBACK AccFormDlgProc(HWND hwndDlg,UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch( message ) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ {
+ PROTOCOLDESCRIPTOR** proto;
+ int protoCount, i, cnt = 0;
+ Proto_EnumProtocols(( WPARAM )&protoCount, ( LPARAM )&proto );
+ for ( i=0; i < protoCount; i++ ) {
+ PROTOCOLDESCRIPTOR* pd = proto[i];
+ if ( pd->type == PROTOTYPE_PROTOCOL && pd->cbSize == sizeof( *pd )) {
+ SendDlgItemMessageA( hwndDlg, IDC_PROTOTYPECOMBO, CB_ADDSTRING, 0, (LPARAM)proto[i]->szName );
+ ++cnt;
+ }
+ }
+ SendDlgItemMessage( hwndDlg, IDC_PROTOTYPECOMBO, CB_SETCURSEL, 0, 0 );
+ EnableWindow( GetDlgItem( hwndDlg, IDOK ), cnt != 0 );
+
+ SetWindowLongPtr( hwndDlg, GWLP_USERDATA, lParam );
+ AccFormDlgParam* param = ( AccFormDlgParam* )lParam;
+
+ if ( param->action == PRAC_ADDED ) // new account
+ SetWindowText( hwndDlg, TranslateT( "Create new account" ));
+ else {
+ TCHAR str[200];
+ if ( param->action == PRAC_CHANGED ) { // update
+ EnableWindow( GetDlgItem( hwndDlg, IDC_PROTOTYPECOMBO ), FALSE );
+ mir_sntprintf( str, SIZEOF(str), _T("%s: %s"), TranslateT( "Editing account" ), param->pa->tszAccountName );
+ }
+ else mir_sntprintf( str, SIZEOF(str), _T("%s: %s"), TranslateT( "Upgrading account" ), param->pa->tszAccountName );
+
+ SetWindowText( hwndDlg, str );
+ SetDlgItemText( hwndDlg, IDC_ACCNAME, param->pa->tszAccountName );
+ SetDlgItemTextA( hwndDlg, IDC_ACCINTERNALNAME, param->pa->szModuleName );
+ SendDlgItemMessageA( hwndDlg, IDC_PROTOTYPECOMBO, CB_SELECTSTRING, -1, (LPARAM)param->pa->szProtoName );
+
+ EnableWindow( GetDlgItem( hwndDlg, IDC_ACCINTERNALNAME ), FALSE );
+ }
+ SendDlgItemMessage( hwndDlg, IDC_ACCINTERNALNAME, EM_LIMITTEXT, 40, 0 );
+ }
+ return TRUE;
+
+ case WM_COMMAND:
+ switch( LOWORD(wParam)) {
+ case IDOK:
+ {
+ AccFormDlgParam* param = ( AccFormDlgParam* )GetWindowLongPtr( hwndDlg, GWLP_USERDATA );
+ PROTOACCOUNT* pa = param->pa;
+
+ if ( param->action == PRAC_ADDED ) {
+ char buf[200];
+ GetDlgItemTextA( hwndDlg, IDC_ACCINTERNALNAME, buf, SIZEOF( buf ));
+ rtrim( buf );
+ if ( buf[0] ) {
+ for (int i = 0; i < accounts.getCount(); ++i)
+ if (_stricmp(buf, accounts[i]->szModuleName) == 0)
+ return FALSE;
+ } }
+
+ switch( param->action ) {
+ case PRAC_UPGRADED:
+ {
+ int idx;
+ BOOL oldProto = pa->bOldProto;
+ TCHAR szPlugin[MAX_PATH];
+ mir_sntprintf(szPlugin, SIZEOF(szPlugin), _T("%s.dll"), StrConvT(pa->szProtoName));
+ idx = accounts.getIndex(pa);
+ UnloadAccount(pa, false, false);
+ accounts.remove(idx);
+ if (oldProto && UnloadPlugin(szPlugin, SIZEOF(szPlugin)))
+ {
+ TCHAR szNewName[MAX_PATH];
+ mir_sntprintf(szNewName, SIZEOF(szNewName), _T("%s~"), szPlugin);
+ MoveFile(szPlugin, szNewName);
+ }
+ }
+ // fall through
+
+ case PRAC_ADDED:
+ pa = (PROTOACCOUNT*)mir_calloc( sizeof( PROTOACCOUNT ));
+ pa->cbSize = sizeof( PROTOACCOUNT );
+ pa->bIsEnabled = TRUE;
+ pa->bIsVisible = TRUE;
+
+ pa->iOrder = accounts.getCount();
+ pa->type = PROTOTYPE_PROTOCOL;
+ break;
+ }
+ {
+ TCHAR buf[256];
+ GetDlgItemText( hwndDlg, IDC_ACCNAME, buf, SIZEOF( buf ));
+ mir_free(pa->tszAccountName);
+ pa->tszAccountName = mir_tstrdup( buf );
+ }
+ if ( param->action == PRAC_ADDED || param->action == PRAC_UPGRADED )
+ {
+ char buf[200];
+ GetDlgItemTextA( hwndDlg, IDC_PROTOTYPECOMBO, buf, SIZEOF( buf ));
+ pa->szProtoName = mir_strdup( buf );
+ GetDlgItemTextA( hwndDlg, IDC_ACCINTERNALNAME, buf, SIZEOF( buf ));
+ rtrim( buf );
+ if ( buf[0] == 0 ) {
+ int count = 1;
+ for( ;; ) {
+ DBVARIANT dbv;
+ mir_snprintf( buf, SIZEOF(buf), "%s_%d", pa->szProtoName, count++ );
+ if ( DBGetContactSettingString( NULL, buf, "AM_BaseProto", &dbv ))
+ break;
+ DBFreeVariant( &dbv );
+ } }
+ pa->szModuleName = mir_strdup( buf );
+
+ if ( !pa->tszAccountName[0] ) {
+ mir_free(pa->tszAccountName);
+ pa->tszAccountName = mir_a2t(buf);
+ }
+
+ DBWriteContactSettingString( NULL, pa->szModuleName, "AM_BaseProto", pa->szProtoName );
+ accounts.insert( pa );
+
+ if ( ActivateAccount( pa )) {
+ pa->ppro->OnEvent( EV_PROTO_ONLOAD, 0, 0 );
+ if (!DBGetContactSettingByte(NULL, "CList", "MoveProtoMenus", FALSE))
+ pa->ppro->OnEvent( EV_PROTO_ONMENU, 0, 0 );
+ }
+ else pa->type = PROTOTYPE_DISPROTO;
+ }
+
+ WriteDbAccounts();
+ NotifyEventHooks( hAccListChanged, param->action, ( LPARAM )pa );
+
+ SendMessage( GetParent(hwndDlg), WM_MY_REFRESH, 0, 0 );
+ }
+
+ EndDialog( hwndDlg, TRUE );
+ break;
+
+ case IDCANCEL:
+ EndDialog( hwndDlg, FALSE );
+ break;
+ }
+ }
+
+ return FALSE;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Accounts manager
+
+struct TAccMgrData
+{
+ HFONT hfntTitle, hfntText;
+ int titleHeight, textHeight;
+ int selectedHeight, normalHeight;
+ int iSelected;
+};
+
+struct TAccListData
+{
+ WNDPROC oldWndProc;
+ int iItem;
+ RECT rcCheck;
+
+ HWND hwndEdit;
+ WNDPROC oldEditProc;
+};
+
+static void sttClickButton(HWND hwndDlg, int idcButton)
+{
+ if (IsWindowEnabled(GetDlgItem(hwndDlg, idcButton)))
+ PostMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(idcButton, BN_CLICKED), (LPARAM)GetDlgItem(hwndDlg, idcButton));
+}
+
+static LRESULT CALLBACK sttEditSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+ case WM_KEYDOWN:
+ switch (wParam) {
+ case VK_RETURN:
+ DestroyWindow(hwnd);
+ return 0;
+
+ case VK_ESCAPE:
+ SetWindowLongPtr(hwnd, GWLP_WNDPROC, GetWindowLongPtr(hwnd, GWLP_USERDATA));
+ DestroyWindow(hwnd);
+ return 0;
+ }
+ break;
+
+ case WM_GETDLGCODE:
+ if (wParam == VK_RETURN || wParam == VK_ESCAPE)
+ return DLGC_WANTMESSAGE;
+ break;
+
+ case WM_KILLFOCUS:
+ {
+ int length = GetWindowTextLength(hwnd) + 1;
+ TCHAR *str = ( TCHAR* )mir_alloc(sizeof(TCHAR) * length);
+ GetWindowText(hwnd, str, length);
+ SendMessage(GetParent(GetParent(hwnd)), WM_COMMAND, MAKEWPARAM(GetWindowLongPtr(GetParent(hwnd), GWL_ID), LBN_MY_RENAME), (LPARAM)str);
+ }
+ DestroyWindow(hwnd);
+ return 0;
+ }
+ return CallWindowProc((WNDPROC)GetWindowLongPtr(hwnd, GWLP_USERDATA), hwnd, msg, wParam, lParam);
+}
+
+static LRESULT CALLBACK AccListWndProc(HWND hwnd,UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct TAccListData *dat = (struct TAccListData *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ if ( !dat )
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+
+ switch (msg) {
+ case WM_LBUTTONDOWN:
+ {
+ POINT pt = {LOWORD(lParam), HIWORD(lParam)};
+ int iItem = LOWORD(SendMessage(hwnd, LB_ITEMFROMPOINT, 0, lParam));
+ ListBox_GetItemRect(hwnd, iItem, &dat->rcCheck);
+
+ dat->rcCheck.right = dat->rcCheck.left + GetSystemMetrics(SM_CXSMICON) + 4;
+ dat->rcCheck.bottom = dat->rcCheck.top + GetSystemMetrics(SM_CYSMICON) + 4;
+ if (PtInRect(&dat->rcCheck, pt))
+ dat->iItem = iItem;
+ else
+ dat->iItem = -1;
+ }
+ break;
+
+ case WM_LBUTTONUP:
+ {
+ POINT pt = {LOWORD(lParam), HIWORD(lParam)};
+ if ((dat->iItem >= 0) && PtInRect(&dat->rcCheck, pt))
+ PostMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(GetWindowLongPtr(hwnd, GWL_ID), LBN_MY_CHECK), (LPARAM)dat->iItem);
+ dat->iItem = -1;
+ }
+ break;
+
+ case WM_CHAR:
+ if (wParam == ' ') {
+ int iItem = ListBox_GetCurSel(hwnd);
+ if (iItem >= 0)
+ PostMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(GetWindowLongPtr(hwnd, GWL_ID), LBN_MY_CHECK), (LPARAM)iItem);
+ return 0;
+ }
+
+ if (wParam == 10 /* enter */)
+ return 0;
+
+ break;
+
+ case WM_GETDLGCODE:
+ if (wParam == VK_RETURN)
+ return DLGC_WANTMESSAGE;
+ break;
+
+ case WM_MY_RENAME:
+ {
+ RECT rc;
+ struct TAccMgrData *parentDat = (struct TAccMgrData *)GetWindowLongPtr(GetParent(hwnd), GWLP_USERDATA);
+ PROTOACCOUNT *pa = (PROTOACCOUNT *)ListBox_GetItemData(hwnd, ListBox_GetCurSel(hwnd));
+ if (!pa || pa->bOldProto || pa->bDynDisabled)
+ return 0;
+
+ ListBox_GetItemRect(hwnd, ListBox_GetCurSel(hwnd), &rc);
+ rc.left += 2*GetSystemMetrics(SM_CXSMICON) + 4;
+ rc.bottom = rc.top + max(GetSystemMetrics(SM_CXSMICON), parentDat->titleHeight) + 4 - 1;
+ ++rc.top; --rc.right;
+
+ dat->hwndEdit = CreateWindow(_T("EDIT"), pa->tszAccountName, WS_CHILD|WS_BORDER|ES_AUTOHSCROLL, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, hwnd, NULL, hMirandaInst, NULL);
+ SetWindowLongPtr(dat->hwndEdit, GWLP_USERDATA, SetWindowLongPtr(dat->hwndEdit, GWLP_WNDPROC, (LONG_PTR)sttEditSubclassProc));
+ SendMessage(dat->hwndEdit, WM_SETFONT, (WPARAM)parentDat->hfntTitle, 0);
+ SendMessage(dat->hwndEdit, EM_SETMARGINS, EC_LEFTMARGIN|EC_RIGHTMARGIN|EC_USEFONTINFO, 0);
+ SendMessage(dat->hwndEdit, EM_SETSEL, 0, (LPARAM) (-1));
+ ShowWindow(dat->hwndEdit, SW_SHOW);
+ }
+ SetFocus(dat->hwndEdit);
+ break;
+
+ case WM_KEYDOWN:
+ switch (wParam) {
+ case VK_F2:
+ PostMessage(hwnd, WM_MY_RENAME, 0, 0);
+ return 0;
+
+ case VK_INSERT:
+ sttClickButton(GetParent(hwnd), IDC_ADD);
+ return 0;
+
+ case VK_DELETE:
+ sttClickButton(GetParent(hwnd), IDC_REMOVE);
+ return 0;
+
+ case VK_RETURN:
+ if (GetAsyncKeyState(VK_CONTROL))
+ sttClickButton(GetParent(hwnd), IDC_EDIT);
+ else
+ sttClickButton(GetParent(hwnd), IDOK);
+ return 0;
+ }
+ break;
+ }
+
+ return CallWindowProc(dat->oldWndProc, hwnd, msg, wParam, lParam);
+}
+
+static void sttSubclassAccList(HWND hwnd, BOOL subclass)
+{
+ if (subclass) {
+ struct TAccListData *dat = (struct TAccListData *)mir_alloc(sizeof(struct TAccListData));
+ dat->iItem = -1;
+ dat->oldWndProc = (WNDPROC)GetWindowLongPtr(hwnd, GWLP_WNDPROC);
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)dat);
+ SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)AccListWndProc);
+ }
+ else {
+ struct TAccListData *dat = (struct TAccListData *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)dat->oldWndProc);
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, 0);
+ mir_free(dat);
+} }
+
+static void sttSelectItem(struct TAccMgrData *dat, HWND hwndList, int iItem)
+{
+ if ((dat->iSelected != iItem) && (dat->iSelected >= 0))
+ ListBox_SetItemHeight(hwndList, dat->iSelected, dat->normalHeight);
+
+ dat->iSelected = iItem;
+ ListBox_SetItemHeight(hwndList, dat->iSelected, dat->selectedHeight);
+ RedrawWindow(hwndList, NULL, NULL, RDW_INVALIDATE);
+}
+
+static void sttUpdateAccountInfo(HWND hwndDlg, struct TAccMgrData *dat)
+{
+ HWND hwndList = GetDlgItem(hwndDlg, IDC_ACCLIST);
+ int curSel = ListBox_GetCurSel( hwndList );
+ if ( curSel != LB_ERR ) {
+ HWND hwnd;
+ char svc[MAXMODULELABELLENGTH];
+
+ PROTOACCOUNT *pa = (PROTOACCOUNT *)ListBox_GetItemData(hwndList, curSel);
+ if ( pa ) {
+ EnableWindow( GetDlgItem( hwndDlg, IDC_UPGRADE ), pa->bOldProto || pa->bDynDisabled );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_EDIT ), !pa->bOldProto && !pa->bDynDisabled );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_REMOVE ), TRUE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_OPTIONS ), pa->ppro != 0 );
+
+ if ( dat->iSelected >= 0 ) {
+ PROTOACCOUNT *pa_old = (PROTOACCOUNT *)ListBox_GetItemData(hwndList, dat->iSelected);
+ if (pa_old && pa_old != pa && pa_old->hwndAccMgrUI)
+ ShowWindow(pa_old->hwndAccMgrUI, SW_HIDE);
+ }
+
+ if ( pa->hwndAccMgrUI ) {
+ ShowWindow(GetDlgItem(hwndDlg, IDC_TXT_INFO), SW_HIDE);
+ ShowWindow(pa->hwndAccMgrUI, SW_SHOW);
+ }
+ else if ( !pa->ppro ) {
+ ShowWindow(GetDlgItem(hwndDlg, IDC_TXT_INFO), SW_SHOW);
+ SetWindowText(GetDlgItem(hwndDlg, IDC_TXT_INFO), TranslateT("Account is disabled. Please activate it to access options."));
+ }
+ else {
+ mir_snprintf(svc, SIZEOF(svc), "%s%s", pa->szModuleName, PS_CREATEACCMGRUI);
+ hwnd = (HWND)CallService(svc, 0, (LPARAM)hwndDlg);
+ if (hwnd && (hwnd != (HWND)CALLSERVICE_NOTFOUND)) {
+ RECT rc;
+
+ ShowWindow(GetDlgItem(hwndDlg, IDC_TXT_INFO), SW_HIDE);
+
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_TXT_INFO), &rc);
+ MapWindowPoints(NULL, hwndDlg, (LPPOINT)&rc, 2);
+ SetWindowPos(hwnd, hwndList, rc.left, rc.top, 0, 0, SWP_NOSIZE|SWP_SHOWWINDOW);
+
+ pa->hwndAccMgrUI = hwnd;
+ }
+ else {
+ ShowWindow(GetDlgItem(hwndDlg, IDC_TXT_INFO), SW_SHOW);
+ SetWindowText(GetDlgItem(hwndDlg, IDC_TXT_INFO), TranslateT(legacyMsg));
+ } }
+ return;
+ } }
+
+ EnableWindow( GetDlgItem( hwndDlg, IDC_UPGRADE ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_EDIT ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_REMOVE ), FALSE );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_OPTIONS ), FALSE );
+
+ ShowWindow(GetDlgItem(hwndDlg, IDC_TXT_INFO), SW_SHOW);
+ SetWindowText(GetDlgItem(hwndDlg, IDC_TXT_INFO), TranslateT(welcomeMsg));
+}
+
+INT_PTR CALLBACK AccMgrDlgProc(HWND hwndDlg,UINT message, WPARAM wParam, LPARAM lParam)
+{
+ struct TAccMgrData *dat = (struct TAccMgrData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+
+ switch(message) {
+ case WM_INITDIALOG:
+ {
+ TAccMgrData *dat = (TAccMgrData *)mir_alloc(sizeof(TAccMgrData));
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)dat);
+
+ TranslateDialogDefault(hwndDlg);
+ Window_SetIcon_IcoLib( hwndDlg, SKINICON_OTHER_ACCMGR );
+
+ Button_SetIcon_IcoLib(hwndDlg, IDC_ADD, SKINICON_OTHER_ADDCONTACT, LPGEN("New account"));
+ Button_SetIcon_IcoLib(hwndDlg, IDC_EDIT, SKINICON_OTHER_RENAME, LPGEN("Edit"));
+ Button_SetIcon_IcoLib(hwndDlg, IDC_REMOVE, SKINICON_OTHER_DELETE, LPGEN("Remove account"));
+ Button_SetIcon_IcoLib(hwndDlg, IDC_OPTIONS, SKINICON_OTHER_OPTIONS, LPGEN( "Configure..."));
+ Button_SetIcon_IcoLib(hwndDlg, IDC_UPGRADE, SKINICON_OTHER_ACCMGR, LPGEN("Upgrade account"));
+
+ EnableWindow(GetDlgItem(hwndDlg, IDC_EDIT), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_REMOVE), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_OPTIONS), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_UPGRADE), FALSE);
+
+ {
+ LOGFONT lf;
+ HDC hdc;
+ HFONT hfnt;
+ TEXTMETRIC tm;
+
+ GetObject((HFONT)SendMessage(hwndDlg, WM_GETFONT, 0, 0), sizeof(lf), &lf);
+ dat->hfntText = CreateFontIndirect(&lf);
+
+ GetObject((HFONT)SendMessage(hwndDlg, WM_GETFONT, 0, 0), sizeof(lf), &lf);
+ lf.lfWeight = FW_BOLD;
+ dat->hfntTitle = CreateFontIndirect(&lf);
+
+ hdc = GetDC(hwndDlg);
+ hfnt = ( HFONT )SelectObject(hdc, dat->hfntTitle);
+ GetTextMetrics(hdc, &tm);
+ dat->titleHeight = tm.tmHeight;
+ SelectObject(hdc, dat->hfntText);
+ GetTextMetrics(hdc, &tm);
+ dat->textHeight = tm.tmHeight;
+ SelectObject(hdc, hfnt);
+ ReleaseDC(hwndDlg, hdc);
+
+ dat->normalHeight = 4 + max(dat->titleHeight, GetSystemMetrics(SM_CYSMICON));
+ dat->selectedHeight = dat->normalHeight + 4 + 2 * dat->textHeight;
+
+ SendDlgItemMessage(hwndDlg, IDC_NAME, WM_SETFONT, (WPARAM)dat->hfntTitle, 0);
+ SendDlgItemMessage(hwndDlg, IDC_TXT_ACCOUNT, WM_SETFONT, (WPARAM)dat->hfntTitle, 0);
+ SendDlgItemMessage(hwndDlg, IDC_TXT_ADDITIONAL, WM_SETFONT, (WPARAM)dat->hfntTitle, 0);
+ }
+
+ dat->iSelected = -1;
+ sttSubclassAccList(GetDlgItem(hwndDlg, IDC_ACCLIST), TRUE);
+ SendMessage( hwndDlg, WM_MY_REFRESH, 0, 0 );
+
+ Utils_RestoreWindowPositionNoSize(hwndDlg, NULL, "AccMgr", "");
+ }
+ return TRUE;
+
+ case WM_CTLCOLORSTATIC:
+ switch ( GetDlgCtrlID(( HWND )lParam )) {
+ case IDC_WHITERECT:
+ case IDC_NAME:
+ SetBkColor(( HDC )wParam, GetSysColor( COLOR_WINDOW ));
+ return ( INT_PTR )GetSysColorBrush( COLOR_WINDOW );
+ }
+ break;
+
+ case WM_MEASUREITEM:
+ {
+ LPMEASUREITEMSTRUCT lps = (LPMEASUREITEMSTRUCT)lParam;
+ PROTOACCOUNT *acc = (PROTOACCOUNT *)lps->itemData;
+
+ if ((lps->CtlID != IDC_ACCLIST) || !acc)
+ break;
+
+ lps->itemWidth = 10;
+ lps->itemHeight = dat->normalHeight;
+ }
+ return TRUE;
+
+ case WM_DRAWITEM:
+ {
+ int tmp, size, length;
+ TCHAR *text;
+ HICON hIcon;
+ HBRUSH hbrBack;
+ SIZE sz;
+
+ int cxIcon = GetSystemMetrics(SM_CXSMICON);
+ int cyIcon = GetSystemMetrics(SM_CYSMICON);
+
+ LPDRAWITEMSTRUCT lps = (LPDRAWITEMSTRUCT)lParam;
+ PROTOACCOUNT *acc = (PROTOACCOUNT *)lps->itemData;
+
+ if ((lps->CtlID != IDC_ACCLIST) || (lps->itemID == -1) || !acc)
+ break;
+
+ SetBkMode(lps->hDC, TRANSPARENT);
+ if (lps->itemState & ODS_SELECTED) {
+ hbrBack = GetSysColorBrush(COLOR_HIGHLIGHT);
+ SetTextColor(lps->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
+ }
+ else {
+ hbrBack = GetSysColorBrush(COLOR_WINDOW);
+ SetTextColor(lps->hDC, GetSysColor(COLOR_WINDOWTEXT));
+ }
+ FillRect(lps->hDC, &lps->rcItem, hbrBack);
+
+ lps->rcItem.left += 2;
+ lps->rcItem.top += 2;
+ lps->rcItem.bottom -= 2;
+
+ if ( acc->bOldProto )
+ tmp = SKINICON_OTHER_ON;
+ else if ( acc->bDynDisabled )
+ tmp = SKINICON_OTHER_OFF;
+ else
+ tmp = acc->bIsEnabled ? SKINICON_OTHER_TICK : SKINICON_OTHER_NOTICK;
+
+ hIcon = LoadSkinnedIcon(tmp);
+ DrawIconEx(lps->hDC, lps->rcItem.left, lps->rcItem.top, hIcon, cxIcon, cyIcon, 0, hbrBack, DI_NORMAL);
+ IconLib_ReleaseIcon(hIcon, 0);
+
+ lps->rcItem.left += cxIcon + 2;
+
+ if (acc->ppro) {
+ hIcon = acc->ppro->GetIcon( PLI_PROTOCOL | PLIF_SMALL );
+ DrawIconEx(lps->hDC, lps->rcItem.left, lps->rcItem.top, hIcon, cxIcon, cyIcon, 0, hbrBack, DI_NORMAL);
+ DestroyIcon(hIcon);
+ }
+ lps->rcItem.left += cxIcon + 2;
+
+ length = SendDlgItemMessage(hwndDlg, IDC_ACCLIST, LB_GETTEXTLEN, lps->itemID, 0);
+ size = max(length+1, 256);
+ text = (TCHAR *)_alloca(sizeof(TCHAR) * size);
+ SendDlgItemMessage(hwndDlg, IDC_ACCLIST, LB_GETTEXT, lps->itemID, (LPARAM)text);
+
+ SelectObject(lps->hDC, dat->hfntTitle);
+ tmp = lps->rcItem.bottom;
+ lps->rcItem.bottom = lps->rcItem.top + max(cyIcon, dat->titleHeight);
+ DrawText(lps->hDC, text, -1, &lps->rcItem, DT_LEFT|DT_NOPREFIX|DT_SINGLELINE|DT_END_ELLIPSIS|DT_VCENTER);
+ lps->rcItem.bottom = tmp;
+ GetTextExtentPoint32(lps->hDC, text, length, &sz);
+ lps->rcItem.top += max(cxIcon, sz.cy) + 2;
+
+ if (lps->itemID == (unsigned)dat->iSelected) {
+ SelectObject(lps->hDC, dat->hfntText);
+ mir_sntprintf(text, size, _T("%s: ") _T(TCHAR_STR_PARAM), TranslateT("Protocol"), acc->szProtoName);
+ length = lstrlen(text);
+ DrawText(lps->hDC, text, -1, &lps->rcItem, DT_LEFT|DT_NOPREFIX|DT_SINGLELINE|DT_END_ELLIPSIS);
+ GetTextExtentPoint32(lps->hDC, text, length, &sz);
+ lps->rcItem.top += sz.cy + 2;
+
+ if (acc->ppro && Proto_IsProtocolLoaded(acc->szProtoName)) {
+ char *szIdName;
+ TCHAR *tszIdName;
+ CONTACTINFO ci = { 0 };
+
+ szIdName = (char *)acc->ppro->GetCaps( PFLAG_UNIQUEIDTEXT, 0 );
+ tszIdName = szIdName ? mir_a2t(szIdName) : mir_tstrdup(TranslateT("Account ID"));
+
+ ci.cbSize = sizeof(ci);
+ ci.hContact = NULL;
+ ci.szProto = acc->szModuleName;
+ ci.dwFlag = CNF_UNIQUEID | CNF_TCHAR;
+ if ( !CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) {
+ switch (ci.type) {
+ case CNFT_ASCIIZ:
+ mir_sntprintf( text, size, _T("%s: %s"), tszIdName, ci.pszVal );
+ mir_free(ci.pszVal);
+ break;
+ case CNFT_DWORD:
+ mir_sntprintf( text, size, _T("%s: %d"), tszIdName, ci.dVal );
+ break;
+ }
+ }
+ else mir_sntprintf(text, size, _T("%s: %s"), tszIdName, TranslateT("<unknown>"));
+ mir_free(tszIdName);
+ }
+ else mir_sntprintf(text, size, TranslateT("Protocol is not loaded."));
+
+ length = lstrlen(text);
+ DrawText(lps->hDC, text, -1, &lps->rcItem, DT_LEFT|DT_NOPREFIX|DT_SINGLELINE|DT_END_ELLIPSIS);
+ GetTextExtentPoint32(lps->hDC, text, length, &sz);
+ lps->rcItem.top += sz.cy + 2;
+ } }
+ return TRUE;
+
+ case WM_MY_REFRESH:
+ {
+ HWND hList = GetDlgItem(hwndDlg, IDC_ACCLIST);
+ int i = ListBox_GetCurSel(hList);
+ PROTOACCOUNT *acc = (i == LB_ERR) ? NULL : (PROTOACCOUNT *)ListBox_GetItemData(hList, i);
+
+ dat->iSelected = -1;
+ SendMessage( hList, LB_RESETCONTENT, 0, 0 );
+ for (i = 0; i < accounts.getCount(); ++i) {
+ int iItem = SendMessage(hList, LB_ADDSTRING, 0, (LPARAM)accounts[i]->tszAccountName);
+ SendMessage(hList, LB_SETITEMDATA, iItem, (LPARAM)accounts[i]);
+
+ if (accounts[i] == acc)
+ ListBox_SetCurSel(hList, iItem);
+ }
+
+ dat->iSelected = ListBox_GetCurSel(hList); // -1 if error => nothing selected in our case
+ if (dat->iSelected >= 0)
+ sttSelectItem(dat, hList, dat->iSelected);
+ else if (acc && acc->hwndAccMgrUI)
+ ShowWindow(acc->hwndAccMgrUI, SW_HIDE);
+
+ sttUpdateAccountInfo(hwndDlg, dat);
+ }
+ break;
+
+ case WM_CONTEXTMENU:
+ if ( GetWindowLongPtr(( HWND )wParam, GWL_ID ) == IDC_ACCLIST ) {
+ HWND hwndList = GetDlgItem( hwndDlg, IDC_ACCLIST );
+ POINT pt = { (signed short)LOWORD( lParam ), (signed short)HIWORD( lParam ) };
+ int iItem = ListBox_GetCurSel( hwndList );
+
+ if (( pt.x == -1 ) && ( pt.y == -1 )) {
+ if (iItem != LB_ERR) {
+ RECT rc;
+ ListBox_GetItemRect( hwndList, iItem, &rc );
+ pt.x = rc.left + GetSystemMetrics(SM_CXSMICON) + 4;
+ pt.y = rc.top + 4 + max(GetSystemMetrics(SM_CXSMICON), dat->titleHeight);
+ ClientToScreen( hwndList, &pt );
+ }
+ }
+ else {
+ // menu was activated with mouse => find item under cursor & set focus to our control.
+ POINT ptItem = pt;
+ ScreenToClient( hwndList, &ptItem );
+ iItem = (short)LOWORD(SendMessage(hwndList, LB_ITEMFROMPOINT, 0, MAKELPARAM(ptItem.x, ptItem.y)));
+ if (iItem != LB_ERR)
+ {
+ ListBox_SetCurSel(hwndList, iItem);
+ sttUpdateAccountInfo(hwndDlg, dat);
+ sttSelectItem(dat, hwndList, iItem);
+ SetFocus(hwndList);
+ }
+ }
+
+ if ( iItem != LB_ERR ) {
+ PROTOACCOUNT* pa = (PROTOACCOUNT*)ListBox_GetItemData(hwndList, iItem);
+ HMENU hMenu = CreatePopupMenu();
+ if ( !pa->bOldProto && !pa->bDynDisabled )
+ AppendMenu(hMenu, MF_STRING, 1, TranslateT("Rename"));
+
+ AppendMenu(hMenu, MF_STRING, 3, TranslateT("Delete"));
+
+ if ( Proto_IsAccountEnabled( pa ))
+ AppendMenu(hMenu, MF_STRING, 4, TranslateT("Configure"));
+
+ if ( pa->bOldProto || pa->bDynDisabled )
+ AppendMenu(hMenu, MF_STRING, 5, TranslateT("Upgrade"));
+
+ AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
+ AppendMenu(hMenu, MF_STRING, 0, TranslateT("Cancel"));
+ switch (TrackPopupMenu( hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwndDlg, NULL )) {
+ case 1:
+ PostMessage(hwndList, WM_MY_RENAME, 0, 0);
+ break;
+
+ case 2:
+ sttClickButton(hwndDlg, IDC_EDIT);
+ break;
+
+ case 3:
+ sttClickButton(hwndDlg, IDC_REMOVE);
+ break;
+
+ case 4:
+ sttClickButton(hwndDlg, IDC_OPTIONS);
+ break;
+
+ case 5:
+ sttClickButton(hwndDlg, IDC_UPGRADE);
+ break;
+ }
+ DestroyMenu( hMenu );
+ }
+ }
+ break;
+
+ case WM_COMMAND:
+ switch( LOWORD(wParam)) {
+ case IDC_ACCLIST:
+ {
+ HWND hwndList = GetDlgItem(hwndDlg, IDC_ACCLIST);
+ switch (HIWORD(wParam)) {
+ case LBN_SELCHANGE:
+ sttUpdateAccountInfo(hwndDlg, dat);
+ sttSelectItem(dat, hwndList, ListBox_GetCurSel(hwndList));
+ SetFocus(hwndList);
+ break;
+
+ case LBN_DBLCLK:
+ PostMessage(hwndList, WM_MY_RENAME, 0, 0);
+ break;
+
+ case LBN_MY_CHECK:
+ {
+ PROTOACCOUNT *pa = (PROTOACCOUNT *)ListBox_GetItemData(hwndList, lParam);
+ if ( pa ) {
+ if ( pa->bOldProto || pa->bDynDisabled)
+ break;
+
+ pa->bIsEnabled = !pa->bIsEnabled;
+ if ( pa->bIsEnabled ) {
+ if ( ActivateAccount( pa )) {
+ pa->ppro->OnEvent( EV_PROTO_ONLOAD, 0, 0 );
+ if (!DBGetContactSettingByte(NULL, "CList", "MoveProtoMenus", FALSE))
+ pa->ppro->OnEvent( EV_PROTO_ONMENU, 0, 0 );
+ }
+ else pa->type = PROTOTYPE_DISPROTO;
+ }
+ else {
+ DWORD dwStatus = CallProtoService(pa->szModuleName, PS_GETSTATUS, 0, 0);
+ if (dwStatus >= ID_STATUS_ONLINE) {
+ if (IDCANCEL == ::MessageBox(hwndDlg,
+ TranslateT("Account is online. Disable account?"),
+ TranslateT("Accounts"), MB_OKCANCEL)) {
+ pa->bIsEnabled = 1; //stay enabled
+ }
+ }
+
+ if ( !pa->bIsEnabled )
+ DeactivateAccount( pa, true, false );
+ }
+
+ WriteDbAccounts();
+ NotifyEventHooks( hAccListChanged, PRAC_CHECKED, ( LPARAM )pa );
+ sttUpdateAccountInfo(hwndDlg, dat);
+ RedrawWindow(hwndList, NULL, NULL, RDW_INVALIDATE);
+ } }
+ break;
+
+ case LBN_MY_RENAME:
+ {
+ int iItem = ListBox_GetCurSel(hwndList);
+ PROTOACCOUNT *pa = (PROTOACCOUNT *)ListBox_GetItemData(hwndList, iItem);
+ if ( pa ) {
+ mir_free(pa->tszAccountName);
+ pa->tszAccountName = (TCHAR*)lParam;
+ WriteDbAccounts();
+ NotifyEventHooks(hAccListChanged, PRAC_CHANGED, (LPARAM)pa);
+
+ ListBox_DeleteString(hwndList, iItem);
+ iItem = ListBox_AddString(hwndList, pa->tszAccountName);
+ ListBox_SetItemData(hwndList, iItem, (LPARAM)pa);
+ ListBox_SetCurSel(hwndList, iItem);
+
+ sttSelectItem(dat, hwndList, iItem);
+
+ RedrawWindow(hwndList, NULL, NULL, RDW_INVALIDATE);
+ }
+ else mir_free((TCHAR*)lParam);
+ }
+ break;
+ } }
+ break;
+
+ case IDC_ADD:
+ {
+ AccFormDlgParam param = { PRAC_ADDED, NULL };
+ if ( IDOK == DialogBoxParam( hMirandaInst, MAKEINTRESOURCE(IDD_ACCFORM), hwndDlg, AccFormDlgProc, (LPARAM)&param ))
+ SendMessage( hwndDlg, WM_MY_REFRESH, 0, 0 );
+ }
+ break;
+
+ case IDC_EDIT:
+ {
+ HWND hList = GetDlgItem( hwndDlg, IDC_ACCLIST );
+ int idx = ListBox_GetCurSel( hList );
+ if ( idx != -1 )
+ PostMessage(hList, WM_MY_RENAME, 0, 0);
+ }
+ break;
+
+ case IDC_REMOVE:
+ {
+ HWND hList = GetDlgItem( hwndDlg, IDC_ACCLIST );
+ int idx = ListBox_GetCurSel( hList );
+ if ( idx != -1 ) {
+ PROTOACCOUNT* pa = ( PROTOACCOUNT* )ListBox_GetItemData( hList, idx );
+ TCHAR buf[ 200 ];
+ mir_sntprintf( buf, SIZEOF(buf), TranslateT( "Account %s is being deleted" ), pa->tszAccountName );
+ if (pa->bOldProto) {
+ MessageBox( NULL, TranslateT( "You need to disable plugin to delete this account" ), buf,
+ MB_ICONERROR | MB_OK );
+ break;
+ }
+ if ( IDYES == MessageBox( NULL, TranslateT( errMsg ), buf, MB_ICONSTOP | MB_DEFBUTTON2 | MB_YESNO )) {
+ // lock controls to avoid changes during remove process
+ ListBox_SetCurSel( hList, -1 );
+ sttUpdateAccountInfo( hwndDlg, dat );
+ EnableWindow( hList, FALSE );
+ EnableWindow( GetDlgItem(hwndDlg, IDC_ADD), FALSE );
+
+ ListBox_SetItemData( hList, idx, 0 );
+
+ accounts.remove( pa );
+
+ CheckProtocolOrder();
+
+ WriteDbAccounts();
+ NotifyEventHooks( hAccListChanged, PRAC_REMOVED, ( LPARAM )pa );
+
+ UnloadAccount( pa, true, true );
+ SendMessage( hwndDlg, WM_MY_REFRESH, 0, 0 );
+
+ EnableWindow( hList, TRUE );
+ EnableWindow( GetDlgItem(hwndDlg, IDC_ADD), TRUE );
+ } } }
+ break;
+
+ case IDC_OPTIONS:
+ {
+ HWND hList = GetDlgItem( hwndDlg, IDC_ACCLIST );
+ int idx = ListBox_GetCurSel( hList );
+ if ( idx != -1 ) {
+ PROTOACCOUNT* pa = ( PROTOACCOUNT* )ListBox_GetItemData( hList, idx );
+ if ( pa->bOldProto ) {
+ OPENOPTIONSDIALOG ood;
+ ood.cbSize = sizeof(ood);
+ ood.pszGroup = "Network";
+ ood.pszPage = pa->szModuleName;
+ ood.pszTab = NULL;
+ CallService( MS_OPT_OPENOPTIONS, 0, (LPARAM)&ood );
+ }
+ else OpenAccountOptions( pa );
+ } }
+ break;
+
+ case IDC_UPGRADE:
+ {
+ HWND hList = GetDlgItem( hwndDlg, IDC_ACCLIST );
+ int idx = ListBox_GetCurSel( hList );
+ if ( idx != -1 ) {
+ AccFormDlgParam param = { PRAC_UPGRADED, ( PROTOACCOUNT* )ListBox_GetItemData( hList, idx ) };
+ DialogBoxParam( hMirandaInst, MAKEINTRESOURCE(IDD_ACCFORM), hwndDlg, AccFormDlgProc, (LPARAM)&param );
+ } }
+ break;
+
+ case IDC_LNK_NETWORK:
+ {
+ PSHNOTIFY pshn = {0};
+ pshn.hdr.code = PSN_APPLY;
+ pshn.hdr.hwndFrom = hwndDlg;
+ SendMessage(hwndDlg, WM_NOTIFY, 0, (LPARAM)&pshn);
+
+ OPENOPTIONSDIALOG ood = {0};
+ ood.cbSize = sizeof(ood);
+ ood.pszPage = "Network";
+ CallService( MS_OPT_OPENOPTIONS, 0, (LPARAM)&ood );
+ break;
+ }
+
+ case IDC_LNK_ADDONS:
+ CallService(MS_UTILS_OPENURL, TRUE, (LPARAM)"http://addons.miranda-im.org/");
+ break;
+
+ case IDOK:
+ {
+ PSHNOTIFY pshn = {0};
+ pshn.hdr.code = PSN_APPLY;
+ pshn.hdr.hwndFrom = hwndDlg;
+ SendMessage(hwndDlg, WM_NOTIFY, 0, (LPARAM)&pshn);
+ DestroyWindow(hwndDlg);
+ break;
+ }
+
+ case IDCANCEL:
+ {
+ PSHNOTIFY pshn = {0};
+ pshn.hdr.code = PSN_RESET;
+ pshn.hdr.hwndFrom = hwndDlg;
+ SendMessage(hwndDlg, WM_NOTIFY, 0, (LPARAM)&pshn);
+ DestroyWindow(hwndDlg);
+ break;
+ }
+ }
+ case PSM_CHANGED:
+ {
+ HWND hList = GetDlgItem( hwndDlg, IDC_ACCLIST );
+ int idx = ListBox_GetCurSel( hList );
+ if ( idx != -1 ) {
+ PROTOACCOUNT *acc = (PROTOACCOUNT *)ListBox_GetItemData(hList, idx);
+ if (acc)
+ {
+ acc->bAccMgrUIChanged = TRUE;
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ }
+ break;
+ }
+ case WM_NOTIFY:
+ switch(((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_APPLY:
+ {
+ int i;
+ PSHNOTIFY pshn = {0};
+ pshn.hdr.code = PSN_APPLY;
+ for (i = 0; i < accounts.getCount(); ++i) {
+ if ( accounts[i]->hwndAccMgrUI && accounts[i]->bAccMgrUIChanged ) {
+ pshn.hdr.hwndFrom = accounts[i]->hwndAccMgrUI;
+ SendMessage(accounts[i]->hwndAccMgrUI, WM_NOTIFY, 0, (LPARAM)&pshn);
+ accounts[i]->bAccMgrUIChanged = FALSE;
+ } }
+ return TRUE;
+ }
+ case PSN_RESET:
+ {
+ int i;
+ PSHNOTIFY pshn = {0};
+ pshn.hdr.code = PSN_RESET;
+ for (i = 0; i < accounts.getCount(); ++i) {
+ if ( accounts[i]->hwndAccMgrUI && accounts[i]->bAccMgrUIChanged ) {
+ pshn.hdr.hwndFrom = accounts[i]->hwndAccMgrUI;
+ SendMessage(accounts[i]->hwndAccMgrUI, WM_NOTIFY, 0, (LPARAM)&pshn);
+ accounts[i]->bAccMgrUIChanged = FALSE;
+ } }
+ return TRUE;
+ }
+ }
+ break;
+ }
+ break;
+ case WM_DESTROY:
+ {
+ for (int i = 0; i < accounts.getCount(); ++i) {
+ accounts[i]->bAccMgrUIChanged = FALSE;
+ if (accounts[i]->hwndAccMgrUI) {
+ DestroyWindow(accounts[i]->hwndAccMgrUI);
+ accounts[i]->hwndAccMgrUI = NULL;
+ } } }
+
+ Window_FreeIcon_IcoLib( hwndDlg );
+ Button_FreeIcon_IcoLib( hwndDlg, IDC_ADD );
+ Button_FreeIcon_IcoLib( hwndDlg, IDC_EDIT );
+ Button_FreeIcon_IcoLib( hwndDlg, IDC_REMOVE );
+ Button_FreeIcon_IcoLib( hwndDlg, IDC_OPTIONS );
+ Button_FreeIcon_IcoLib( hwndDlg, IDC_UPGRADE );
+ Utils_SaveWindowPosition( hwndDlg, NULL, "AccMgr", "");
+ sttSubclassAccList(GetDlgItem(hwndDlg, IDC_ACCLIST), FALSE);
+ DeleteObject(dat->hfntTitle);
+ DeleteObject(dat->hfntText);
+ mir_free(dat);
+ hAccMgr = NULL;
+ break;
+ }
+
+ return FALSE;
+}
+
+static INT_PTR OptProtosShow(WPARAM, LPARAM)
+{
+ if ( !hAccMgr )
+ hAccMgr = CreateDialogParam( hMirandaInst, MAKEINTRESOURCE(IDD_ACCMGR), NULL, AccMgrDlgProc, 0 );
+
+ ShowWindow( hAccMgr, SW_RESTORE );
+ SetForegroundWindow( hAccMgr );
+ SetActiveWindow( hAccMgr );
+ return 0;
+}
+
+int OptProtosLoaded(WPARAM, LPARAM)
+{
+ CLISTMENUITEM mi = { 0 };
+ mi.cbSize = sizeof(mi);
+ mi.flags = CMIF_ICONFROMICOLIB;
+ mi.icolibItem = GetSkinIconHandle( SKINICON_OTHER_ACCMGR );
+ mi.position = 1900000000;
+ mi.pszName = LPGEN("&Accounts...");
+ mi.pszService = MS_PROTO_SHOWACCMGR;
+ CallService( MS_CLIST_ADDMAINMENUITEM, 0, ( LPARAM )&mi );
+ return 0;
+}
+
+static int OnAccListChanged( WPARAM eventCode, LPARAM lParam )
+{
+ PROTOACCOUNT* pa = (PROTOACCOUNT*)lParam;
+
+ switch( eventCode ) {
+ case PRAC_CHANGED:
+ if ( pa->ppro ) {
+ mir_free( pa->ppro->m_tszUserName );
+ pa->ppro->m_tszUserName = mir_tstrdup( pa->tszAccountName );
+ pa->ppro->OnEvent( EV_PROTO_ONRENAME, 0, lParam );
+ }
+ }
+
+ return 0;
+}
+
+static int ShutdownAccMgr(WPARAM, LPARAM)
+{
+ if ( IsWindow( hAccMgr ))
+ DestroyWindow( hAccMgr );
+ hAccMgr = NULL;
+ return 0;
+}
+
+int LoadProtoOptions( void )
+{
+ CreateServiceFunction( MS_PROTO_SHOWACCMGR, OptProtosShow );
+
+ HookEvent( ME_SYSTEM_MODULESLOADED, OptProtosLoaded );
+ HookEvent( ME_PROTO_ACCLISTCHANGED, OnAccListChanged );
+ HookEvent( ME_SYSTEM_PRESHUTDOWN, ShutdownAccMgr );
+ return 0;
+}