summaryrefslogtreecommitdiff
path: root/src
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
parent5c350913f011e119127baeb32a6aedeb4f0d33bc (diff)
initial commit
git-svn-id: http://svn.miranda-ng.org/main/trunk@2 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'src')
-rw-r--r--src/core/commonheaders.cpp2
-rw-r--r--src/core/commonheaders.h102
-rw-r--r--src/core/forkthread.h63
-rw-r--r--src/core/memory.cpp280
-rw-r--r--src/core/miranda.cpp941
-rw-r--r--src/core/miranda.h370
-rw-r--r--src/core/modules.cpp784
-rw-r--r--src/core/modules.h268
-rw-r--r--src/manifest.rc8
-rw-r--r--src/miranda32.def7
-rw-r--r--src/miranda32.dep857
-rw-r--r--src/miranda32.dsp962
-rw-r--r--src/miranda32.dsw44
-rw-r--r--src/miranda32.exe.manifest48
-rw-r--r--src/miranda32.mak3007
-rw-r--r--src/miranda32.vcproj3275
-rw-r--r--src/miranda32_10.vcxproj759
-rw-r--r--src/miranda32_10.vcxproj.filters814
-rw-r--r--src/miranda32_8.vcproj1531
-rw-r--r--src/miranda32_9.vcproj1963
-rw-r--r--src/modules/addcontact/addcontact.cpp271
-rw-r--r--src/modules/autoaway/autoaway.cpp74
-rw-r--r--src/modules/button/button.cpp614
-rw-r--r--src/modules/clist/Docking.cpp392
-rw-r--r--src/modules/clist/clc.cpp1350
-rw-r--r--src/modules/clist/clc.h248
-rw-r--r--src/modules/clist/clcfiledrop.cpp278
-rw-r--r--src/modules/clist/clcidents.cpp201
-rw-r--r--src/modules/clist/clcitems.cpp707
-rw-r--r--src/modules/clist/clcmsgs.cpp472
-rw-r--r--src/modules/clist/clcutils.cpp879
-rw-r--r--src/modules/clist/clistcore.cpp224
-rw-r--r--src/modules/clist/clistevents.cpp441
-rw-r--r--src/modules/clist/clistmenus.cpp1443
-rw-r--r--src/modules/clist/clistmod.cpp569
-rw-r--r--src/modules/clist/clistsettings.cpp331
-rw-r--r--src/modules/clist/clisttray.cpp980
-rw-r--r--src/modules/clist/clui.cpp1136
-rw-r--r--src/modules/clist/cluiservices.cpp221
-rw-r--r--src/modules/clist/contact.cpp193
-rw-r--r--src/modules/clist/genmenu.cpp1294
-rw-r--r--src/modules/clist/genmenu.h146
-rw-r--r--src/modules/clist/genmenuopt.cpp870
-rw-r--r--src/modules/clist/groups.cpp577
-rw-r--r--src/modules/clist/keyboard.cpp173
-rw-r--r--src/modules/clist/movetogroup.cpp160
-rw-r--r--src/modules/clist/protocolorder.cpp351
-rw-r--r--src/modules/contacts/contacts.cpp513
-rw-r--r--src/modules/database/database.cpp563
-rw-r--r--src/modules/database/dbini.cpp490
-rw-r--r--src/modules/database/dblists.cpp282
-rw-r--r--src/modules/database/dblists.h39
-rw-r--r--src/modules/database/dbutils.cpp365
-rw-r--r--src/modules/database/profilemanager.cpp850
-rw-r--r--src/modules/database/profilemanager.h43
-rw-r--r--src/modules/findadd/findadd.cpp1033
-rw-r--r--src/modules/findadd/findadd.h59
-rw-r--r--src/modules/findadd/searchresults.cpp398
-rw-r--r--src/modules/fonts/FontOptions.cpp1523
-rw-r--r--src/modules/fonts/FontService.cpp126
-rw-r--r--src/modules/fonts/FontService.h112
-rw-r--r--src/modules/fonts/services.cpp534
-rw-r--r--src/modules/help/about.cpp148
-rw-r--r--src/modules/help/help.cpp117
-rw-r--r--src/modules/history/history.cpp434
-rw-r--r--src/modules/icolib/IcoLib.h83
-rw-r--r--src/modules/icolib/extracticon.cpp280
-rw-r--r--src/modules/icolib/skin2icons.cpp1992
-rw-r--r--src/modules/idle/idle.cpp520
-rw-r--r--src/modules/ignore/ignore.cpp481
-rw-r--r--src/modules/keybindings/keybindings.cpp616
-rw-r--r--src/modules/keybindings/keybindings.h43
-rw-r--r--src/modules/langpack/langpack.cpp569
-rw-r--r--src/modules/langpack/lpservices.cpp168
-rw-r--r--src/modules/netlib/netlib.cpp640
-rw-r--r--src/modules/netlib/netlib.h209
-rw-r--r--src/modules/netlib/netlibautoproxy.cpp460
-rw-r--r--src/modules/netlib/netlibbind.cpp287
-rw-r--r--src/modules/netlib/netlibhttp.cpp1331
-rw-r--r--src/modules/netlib/netlibhttpproxy.cpp522
-rw-r--r--src/modules/netlib/netliblog.cpp637
-rw-r--r--src/modules/netlib/netlibopenconn.cpp944
-rw-r--r--src/modules/netlib/netlibopts.cpp556
-rw-r--r--src/modules/netlib/netlibpktrecver.cpp85
-rw-r--r--src/modules/netlib/netlibsecurity.cpp570
-rw-r--r--src/modules/netlib/netlibsock.cpp203
-rw-r--r--src/modules/netlib/netlibssl.cpp981
-rw-r--r--src/modules/netlib/netlibupnp.cpp885
-rw-r--r--src/modules/options/descbutton.cpp332
-rw-r--r--src/modules/options/filter.cpp217
-rw-r--r--src/modules/options/filter.h108
-rw-r--r--src/modules/options/headerbar.cpp372
-rw-r--r--src/modules/options/iconheader.cpp545
-rw-r--r--src/modules/options/options.cpp1521
-rw-r--r--src/modules/plugins/newplugins.cpp1204
-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
-rw-r--r--src/modules/skin/hotkeys.cpp1465
-rw-r--r--src/modules/skin/skinicons.cpp489
-rw-r--r--src/modules/skin/sounds.cpp469
-rw-r--r--src/modules/srauth/auth.cpp129
-rw-r--r--src/modules/srauth/authdialogs.cpp312
-rw-r--r--src/modules/srawaymsg/awaymsg.cpp194
-rw-r--r--src/modules/srawaymsg/sendmsg.cpp637
-rw-r--r--src/modules/sremail/email.cpp89
-rw-r--r--src/modules/srfile/file.cpp392
-rw-r--r--src/modules/srfile/file.h115
-rw-r--r--src/modules/srfile/fileexistsdlg.cpp354
-rw-r--r--src/modules/srfile/fileopts.cpp247
-rw-r--r--src/modules/srfile/filerecvdlg.cpp446
-rw-r--r--src/modules/srfile/filesenddlg.cpp363
-rw-r--r--src/modules/srfile/filexferdlg.cpp799
-rw-r--r--src/modules/srfile/ftmanager.cpp592
-rw-r--r--src/modules/srurl/url.cpp182
-rw-r--r--src/modules/srurl/url.h41
-rw-r--r--src/modules/srurl/urldialogs.cpp664
-rw-r--r--src/modules/updatenotify/updatenotify.cpp680
-rw-r--r--src/modules/userinfo/contactinfo.cpp515
-rw-r--r--src/modules/userinfo/stdinfo.cpp613
-rw-r--r--src/modules/userinfo/userinfo.cpp636
-rw-r--r--src/modules/useronline/useronline.cpp117
-rw-r--r--src/modules/utils/bmpfilter.cpp242
-rw-r--r--src/modules/utils/colourpicker.cpp107
-rw-r--r--src/modules/utils/hyperlink.cpp274
-rw-r--r--src/modules/utils/imgconv.cpp152
-rw-r--r--src/modules/utils/md5.cpp374
-rw-r--r--src/modules/utils/openurl.cpp228
-rw-r--r--src/modules/utils/path.cpp600
-rw-r--r--src/modules/utils/resizer.cpp152
-rw-r--r--src/modules/utils/sha1.cpp175
-rw-r--r--src/modules/utils/timeutils.cpp277
-rw-r--r--src/modules/utils/timezones.cpp662
-rw-r--r--src/modules/utils/utf.cpp413
-rw-r--r--src/modules/utils/utils.cpp587
-rw-r--r--src/modules/utils/windowlist.cpp101
-rw-r--r--src/modules/visibility/visibility.cpp297
-rw-r--r--src/modules/xml/xmlApi.cpp446
-rw-r--r--src/modules/xml/xmlParser.cpp3061
-rw-r--r--src/modules/xml/xmlParser.h746
-rw-r--r--src/res/Icon_exit.icobin0 -> 2550 bytes
-rw-r--r--src/res/Icon_show_hide.icobin0 -> 2550 bytes
-rw-r--r--src/res/Off.icobin0 -> 2550 bytes
-rw-r--r--src/res/On.icobin0 -> 2550 bytes
-rw-r--r--src/res/_blank.icobin0 -> 318 bytes
-rw-r--r--src/res/arrow_sort_column_down.bmpbin0 -> 150 bytes
-rw-r--r--src/res/arrow_sort_column_up.bmpbin0 -> 150 bytes
-rw-r--r--src/res/chat_join.icobin0 -> 2550 bytes
-rw-r--r--src/res/chat_leave.icobin0 -> 2550 bytes
-rw-r--r--src/res/check_off.icobin0 -> 2550 bytes
-rw-r--r--src/res/check_on.icobin0 -> 2550 bytes
-rw-r--r--src/res/contact_add.icobin0 -> 2550 bytes
-rw-r--r--src/res/contact_delete.icobin0 -> 2550 bytes
-rw-r--r--src/res/contact_groups.icobin0 -> 2550 bytes
-rw-r--r--src/res/contact_rename.icobin0 -> 2550 bytes
-rw-r--r--src/res/contact_view_details.icobin0 -> 6830 bytes
-rw-r--r--src/res/cursor_drag_copy.curbin0 -> 326 bytes
-rw-r--r--src/res/cursor_drop_user.curbin0 -> 1086 bytes
-rw-r--r--src/res/cursor_hyperlink.curbin0 -> 326 bytes
-rw-r--r--src/res/group_closed.icobin0 -> 2550 bytes
-rw-r--r--src/res/group_opened.icobin0 -> 2550 bytes
-rw-r--r--src/res/icon_accmgr.icobin0 -> 6830 bytes
-rw-r--r--src/res/icon_all.icobin0 -> 2550 bytes
-rw-r--r--src/res/icon_ansi.icobin0 -> 2550 bytes
-rw-r--r--src/res/icon_auth_request.icobin0 -> 2550 bytes
-rw-r--r--src/res/icon_changefont.icobin0 -> 2550 bytes
-rw-r--r--src/res/icon_connecting.icobin0 -> 2550 bytes
-rw-r--r--src/res/icon_down_arrow.icobin0 -> 2550 bytes
-rw-r--r--src/res/icon_file.icobin0 -> 6830 bytes
-rw-r--r--src/res/icon_find_user.icobin0 -> 6830 bytes
-rw-r--r--src/res/icon_help.icobin0 -> 2550 bytes
-rw-r--r--src/res/icon_history.icobin0 -> 6830 bytes
-rw-r--r--src/res/icon_loaded.icobin0 -> 2550 bytes
-rw-r--r--src/res/icon_mail.icobin0 -> 2550 bytes
-rw-r--r--src/res/icon_message.icobin0 -> 6830 bytes
-rw-r--r--src/res/icon_notloaded.icobin0 -> 2550 bytes
-rw-r--r--src/res/icon_options.icobin0 -> 6830 bytes
-rw-r--r--src/res/icon_search_all.icobin0 -> 2550 bytes
-rw-r--r--src/res/icon_small_dot.icobin0 -> 2550 bytes
-rw-r--r--src/res/icon_sms.icobin0 -> 2550 bytes
-rw-r--r--src/res/icon_typing.icobin0 -> 2550 bytes
-rw-r--r--src/res/icon_undo.icobin0 -> 2550 bytes
-rw-r--r--src/res/icon_unicode.icobin0 -> 2550 bytes
-rw-r--r--src/res/icon_url.icobin0 -> 2550 bytes
-rw-r--r--src/res/icon_window.icobin0 -> 2550 bytes
-rw-r--r--src/res/icon_windows.icobin0 -> 2550 bytes
-rw-r--r--src/res/miranda_home.icobin0 -> 2550 bytes
-rw-r--r--src/res/miranda_logo.icobin0 -> 22486 bytes
-rw-r--r--src/res/miranda_manager.icobin0 -> 6830 bytes
-rw-r--r--src/res/status_DND.icobin0 -> 6830 bytes
-rw-r--r--src/res/status_NA.icobin0 -> 6830 bytes
-rw-r--r--src/res/status_away.icobin0 -> 6830 bytes
-rw-r--r--src/res/status_free4chat.icobin0 -> 6830 bytes
-rw-r--r--src/res/status_invisible.icobin0 -> 6830 bytes
-rw-r--r--src/res/status_locked.icobin0 -> 2550 bytes
-rw-r--r--src/res/status_occupied.icobin0 -> 6830 bytes
-rw-r--r--src/res/status_offline.icobin0 -> 6830 bytes
-rw-r--r--src/res/status_on_the_phone.icobin0 -> 6830 bytes
-rw-r--r--src/res/status_online.icobin0 -> 6830 bytes
-rw-r--r--src/res/status_out2lunch.icobin0 -> 6830 bytes
-rw-r--r--src/res/status_user_online.icobin0 -> 6830 bytes
-rw-r--r--src/resource.h528
-rw-r--r--src/resource.rc2042
-rw-r--r--src/vc6.rc3
-rw-r--r--src/version.rc50
208 files changed, 81086 insertions, 0 deletions
diff --git a/src/core/commonheaders.cpp b/src/core/commonheaders.cpp
new file mode 100644
index 0000000000..95b2201163
--- /dev/null
+++ b/src/core/commonheaders.cpp
@@ -0,0 +1,2 @@
+#include "commonheaders.h"
+
diff --git a/src/core/commonheaders.h b/src/core/commonheaders.h
new file mode 100644
index 0000000000..8aec3a5dc5
--- /dev/null
+++ b/src/core/commonheaders.h
@@ -0,0 +1,102 @@
+/*
+
+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.
+*/
+
+// to enable all 0.9.0 core functions
+#define MIRANDA_VER 0x1000
+
+#define _ALPHA_BASE_ 1 // defined for CVS builds
+#define _ALPHA_FUSE_ 1 // defined for fuse powered core
+
+#define WINVER 0x0700
+#define _WIN32_WINNT 0x0700
+#define _WIN32_IE 0x0601
+
+#include "m_stdhdr.h"
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <windows.h>
+#include <windowsx.h>
+#include <shlobj.h>
+#include <uxtheme.h>
+#include <commctrl.h>
+#include <vssym32.h>
+
+#include <stdio.h>
+#include <time.h>
+#include <stddef.h>
+#include <process.h>
+#include <io.h>
+#include <limits.h>
+#include <string.h>
+#include <locale.h>
+#include <direct.h>
+
+#include <win2k.h>
+
+#include "modules.h"
+
+#include <m_system.h>
+#include <m_system_cpp.h>
+#include <newpluginapi.h>
+#include <m_database.h>
+#include <m_clc.h>
+#include <m_clui.h>
+#include <m_crypto.h>
+#include <m_langpack.h>
+#include <m_clist.h>
+#include <m_clistint.h>
+#include <m_avatars.h>
+#include <m_button.h>
+#include <m_protosvc.h>
+#include <m_protomod.h>
+#include <m_protocols.h>
+#include <m_protoint.h>
+#include <m_plugins.h>
+#include <m_options.h>
+#include <m_skin.h>
+#include <m_contacts.h>
+#include <m_message.h>
+#include <m_userinfo.h>
+#include <m_history.h>
+#include <m_addcontact.h>
+#include <m_findadd.h>
+#include <m_file.h>
+#include <m_email.h>
+#include <m_awaymsg.h>
+#include <m_idle.h>
+#include <m_ignore.h>
+#include <m_icolib.h>
+#include <m_modernopt.h>
+#include <m_help.h>
+#include <m_timezones.h>
+
+#include "forkthread.h"
+#include "miranda.h"
+#include "../modules/database/dblists.h"
+
+#include <m_ssl.h>
+#include <m_netlib.h>
+#include <m_xml.h>
+
+#include "../resource.h" \ No newline at end of file
diff --git a/src/core/forkthread.h b/src/core/forkthread.h
new file mode 100644
index 0000000000..d920b7867e
--- /dev/null
+++ b/src/core/forkthread.h
@@ -0,0 +1,63 @@
+/*
+
+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.
+*/
+
+/*
+
+Purpose:
+
+ A safe version of _beginthread()
+
+Description:
+
+ A new thread is created and the source thread is paused until
+ internal code to call MS_SYSTEM_THREAD_PUSH is made in the context
+ if the new thread.
+
+ The source thread is then released and then the user supplied
+ code is called, when that function returns -- MS_SYSTEM_THREAD_POP
+ is called and then the thread returns.
+
+ This insures that Miranda will not exit whilst new threads
+ are trying to be born; and the unwind wait stack will unsure
+ that Miranda will wait for all created threads to return as well.
+
+Cavets:
+
+ The function must be reimplemented across MT plugins, since thread
+ creation depends on CRT which can not be shared.
+
+*/
+UINT_PTR forkthread (
+ void (__cdecl *threadcode)(void*),
+ unsigned long stacksize,
+ void *arg
+);
+
+UINT_PTR forkthreadex(
+ void *sec,
+ unsigned stacksize,
+ unsigned (__stdcall *threadcode)(void*),
+ void *owner,
+ void *arg,
+ unsigned *thraddr
+);
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
new file mode 100644
index 0000000000..04252e1c34
--- /dev/null
+++ b/src/core/memory.cpp
@@ -0,0 +1,280 @@
+/*
+
+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 BLOCK_ALLOCED 0xABBABABA
+#define BLOCK_FREED 0xDEADBEEF
+
+static int CheckBlock( void* blk )
+{
+ int result = FALSE;
+ char* p = ( char* )blk - sizeof(DWORD)*2;
+ DWORD size, *b, *e;
+
+ __try
+ {
+ size = *( DWORD* )p;
+ b = ( DWORD* )&p[ sizeof( DWORD ) ];
+ e = ( DWORD* )&p[ sizeof( DWORD )*2 + size ];
+
+ if ( *b != BLOCK_ALLOCED || *e != BLOCK_ALLOCED )
+ {
+ if ( *b == BLOCK_FREED && *e == BLOCK_FREED )
+ OutputDebugStringA( "memory block is already deleted\n" );
+ else
+ OutputDebugStringA( "memory block is corrupted\n" );
+ #if defined( _DEBUG )
+ DebugBreak();
+ #endif
+ }
+ else result = TRUE;
+ }
+ __except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ OutputDebugStringA( "access violation during checking memory block\n" );
+ #if defined( _DEBUG )
+ DebugBreak();
+ #endif
+ }
+
+ return result;
+}
+
+/******************************************************************************/
+
+void* mir_alloc( size_t size )
+{
+ if ( size == 0 )
+ return NULL;
+ {
+ char* p = (char*)malloc( size + sizeof(DWORD)*3 );
+ if ( p == NULL ) {
+ OutputDebugStringA( "memory overflow\n" );
+ #if defined( _DEBUG )
+ DebugBreak();
+ #endif
+ return NULL;
+ }
+
+ *( DWORD* )p = ( DWORD )size;
+ *( DWORD* )&p[ sizeof(DWORD) ] = BLOCK_ALLOCED;
+ *( DWORD* )&p[ size + sizeof(DWORD)*2 ] = BLOCK_ALLOCED;
+ return p + sizeof( DWORD )*2;
+} }
+
+/******************************************************************************/
+
+void* mir_calloc( size_t size )
+{
+ void* p = mir_alloc( size );
+ if ( p != NULL )
+ memset( p, 0, size );
+ return p;
+}
+
+/******************************************************************************/
+
+void* mir_realloc( void* ptr, size_t size )
+{
+ char* p;
+
+ if ( ptr != NULL ) {
+ if ( !CheckBlock( ptr ))
+ return NULL;
+ p = ( char* )ptr - sizeof(DWORD)*2;
+ }
+ else p = NULL;
+
+ p = ( char* )realloc( p, size + sizeof(DWORD)*3 );
+ if ( p == NULL ) {
+ OutputDebugStringA( "memory overflow\n" );
+ #if defined( _DEBUG )
+ DebugBreak();
+ #endif
+ return NULL;
+ }
+
+ *( DWORD* )p = ( DWORD )size;
+ *( DWORD* )&p[ sizeof(DWORD) ] = BLOCK_ALLOCED;
+ *( DWORD* )&p[ size + sizeof(DWORD)*2 ] = BLOCK_ALLOCED;
+ return p + sizeof( DWORD )*2;
+}
+
+/******************************************************************************/
+
+void mir_free( void* ptr )
+{
+ char* p;
+ DWORD size;
+
+ if ( ptr == NULL )
+ return;
+ if ( !CheckBlock( ptr ))
+ return;
+
+ p = ( char* )ptr - sizeof(DWORD)*2;
+ size = *( DWORD* )p;
+ *( DWORD* )&p[ sizeof(DWORD) ] = BLOCK_FREED;
+ *( DWORD* )&p[ size + sizeof(DWORD)*2 ] = BLOCK_FREED;
+ free( p );
+}
+
+/******************************************************************************/
+
+char* mir_strdup( const char* str )
+{
+ if ( str != NULL ) {
+ char* p = ( char* )mir_alloc( strlen( str )+1 );
+ if ( p )
+ strcpy( p, str );
+ return p;
+ }
+ return NULL;
+}
+
+/******************************************************************************/
+
+char* mir_strndup( const char* str, size_t len )
+{
+ if ( str != NULL && len != 0 ) {
+ char* p = ( char* )mir_alloc( len + 1 );
+ if ( !p ) {
+ memcpy( p, str, len );
+ p[ len ] = 0;
+ }
+ return p;
+ }
+ return NULL;
+}
+
+/******************************************************************************/
+
+WCHAR* mir_wstrdup( const WCHAR* str )
+{
+ if ( str != NULL ) {
+ WCHAR* p = ( WCHAR* )mir_alloc( sizeof( WCHAR )*( wcslen( str )+1 ));
+ if ( p )
+ wcscpy( p, str );
+ return p;
+ }
+ return NULL;
+}
+
+/******************************************************************************/
+
+int mir_snprintf(char *buffer, size_t count, const char* fmt, ...)
+{
+ va_list va;
+ int len;
+
+ va_start(va, fmt);
+ len = _vsnprintf(buffer, count-1, fmt, va);
+ va_end(va);
+ buffer[count-1] = 0;
+ return len;
+}
+
+/******************************************************************************/
+
+int mir_sntprintf(TCHAR *buffer, size_t count, const TCHAR* fmt, ...)
+{
+ va_list va;
+ int len;
+
+ va_start(va, fmt);
+ len = _vsntprintf(buffer, count-1, fmt, va);
+ va_end(va);
+ buffer[count-1] = 0;
+ return len;
+}
+
+/******************************************************************************/
+
+int mir_vsnprintf(char *buffer, size_t count, const char* fmt, va_list va)
+{
+ int len;
+
+ len = _vsnprintf(buffer, count-1, fmt, va);
+ buffer[count-1] = 0;
+ return len;
+}
+
+/******************************************************************************/
+
+int mir_vsntprintf(TCHAR *buffer, size_t count, const TCHAR* fmt, va_list va)
+{
+ int len;
+
+ len = _vsntprintf(buffer, count-1, fmt, va);
+ buffer[count-1] = 0;
+ return len;
+}
+
+/******************************************************************************/
+
+wchar_t* mir_a2u_cp( const char* src, int codepage )
+{
+ if ( src == NULL )
+ return NULL;
+
+ int cbLen = MultiByteToWideChar( codepage, 0, src, -1, NULL, 0 );
+ wchar_t* result = ( wchar_t* )mir_alloc( sizeof( wchar_t )*(cbLen+1));
+ if ( result == NULL )
+ return NULL;
+
+ MultiByteToWideChar( codepage, 0, src, -1, result, cbLen );
+ result[ cbLen ] = 0;
+ return result;
+}
+
+/******************************************************************************/
+
+wchar_t* mir_a2u( const char* src )
+{
+ return mir_a2u_cp( src, LangPackGetDefaultCodePage());
+}
+
+/******************************************************************************/
+
+char* mir_u2a_cp( const wchar_t* src, int codepage )
+{
+ if ( src == NULL )
+ return NULL;
+
+ int cbLen = WideCharToMultiByte( codepage, 0, src, -1, NULL, 0, NULL, NULL );
+ char* result = ( char* )mir_alloc( cbLen+1 );
+ if ( result == NULL )
+ return NULL;
+
+ WideCharToMultiByte( codepage, 0, src, -1, result, cbLen, NULL, NULL );
+ result[ cbLen ] = 0;
+ return result;
+}
+
+/******************************************************************************/
+
+char* mir_u2a( const wchar_t* src )
+{
+ return mir_u2a_cp( src, LangPackGetDefaultCodePage());
+}
diff --git a/src/core/miranda.cpp b/src/core/miranda.cpp
new file mode 100644
index 0000000000..fe38d096e1
--- /dev/null
+++ b/src/core/miranda.cpp
@@ -0,0 +1,941 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2012 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 MMI_SIZE_V1 (4*sizeof(void*))
+#define MMI_SIZE_V2 (7*sizeof(void*))
+
+int InitPathUtils(void);
+int InitialiseModularEngine(void);
+int LoadDefaultModules(void);
+void DestroyModularEngine(void);
+void UnloadNewPluginsModule(void);
+void UnloadDefaultModules(void);
+void RecalculateTime(void);
+
+HINSTANCE GetInstByAddress( void* codePtr );
+
+pfnMyMonitorFromPoint MyMonitorFromPoint;
+pfnMyMonitorFromRect MyMonitorFromRect;
+pfnMyMonitorFromWindow MyMonitorFromWindow;
+pfnMyGetMonitorInfo MyGetMonitorInfo;
+
+typedef DWORD (WINAPI *pfnMsgWaitForMultipleObjectsEx)(DWORD,CONST HANDLE*,DWORD,DWORD,DWORD);
+pfnMsgWaitForMultipleObjectsEx msgWaitForMultipleObjectsEx;
+
+pfnSHAutoComplete shAutoComplete;
+pfnSHGetSpecialFolderPathA shGetSpecialFolderPathA;
+pfnSHGetSpecialFolderPathW shGetSpecialFolderPathW;
+
+pfnOpenInputDesktop openInputDesktop;
+pfnCloseDesktop closeDesktop;
+
+pfnAnimateWindow animateWindow;
+pfnSetLayeredWindowAttributes setLayeredWindowAttributes;
+
+pfnOpenThemeData openThemeData;
+pfnIsThemeBackgroundPartiallyTransparent isThemeBackgroundPartiallyTransparent;
+pfnDrawThemeParentBackground drawThemeParentBackground;
+pfnDrawThemeBackground drawThemeBackground;
+pfnDrawThemeText drawThemeText;
+pfnDrawThemeTextEx drawThemeTextEx;
+pfnGetThemeBackgroundContentRect getThemeBackgroundContentRect;
+pfnGetThemeFont getThemeFont;
+pfnCloseThemeData closeThemeData;
+pfnEnableThemeDialogTexture enableThemeDialogTexture;
+pfnSetWindowTheme setWindowTheme;
+pfnSetWindowThemeAttribute setWindowThemeAttribute;
+pfnIsThemeActive isThemeActive;
+pfnBufferedPaintInit bufferedPaintInit;
+pfnBufferedPaintUninit bufferedPaintUninit;
+pfnBeginBufferedPaint beginBufferedPaint;
+pfnEndBufferedPaint endBufferedPaint;
+pfnGetBufferedPaintBits getBufferedPaintBits;
+
+pfnDwmExtendFrameIntoClientArea dwmExtendFrameIntoClientArea;
+pfnDwmIsCompositionEnabled dwmIsCompositionEnabled;
+
+pfnGetaddrinfo MyGetaddrinfo;
+pfnFreeaddrinfo MyFreeaddrinfo;
+
+ITaskbarList3 * pTaskbarInterface;
+
+static DWORD MsgWaitForMultipleObjectsExWorkaround(DWORD nCount, const HANDLE *pHandles,
+ DWORD dwMsecs, DWORD dwWakeMask, DWORD dwFlags);
+
+static HANDLE hOkToExitEvent,hModulesLoadedEvent;
+static HANDLE hShutdownEvent,hPreShutdownEvent;
+static HANDLE hWaitObjects[MAXIMUM_WAIT_OBJECTS-1];
+static char *pszWaitServices[MAXIMUM_WAIT_OBJECTS-1];
+static int waitObjectCount=0;
+HANDLE hStackMutex,hMirandaShutdown,hThreadQueueEmpty;
+HINSTANCE hMirandaInst;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// exception handling
+
+static DWORD __cdecl sttDefaultFilter( DWORD, EXCEPTION_POINTERS* )
+{
+ return EXCEPTION_EXECUTE_HANDLER;
+}
+
+pfnExceptionFilter pMirandaExceptFilter = sttDefaultFilter;
+
+static INT_PTR GetExceptionFilter( WPARAM, LPARAM )
+{
+ return ( INT_PTR )pMirandaExceptFilter;
+}
+
+static INT_PTR SetExceptionFilter( WPARAM, LPARAM lParam )
+{
+ pfnExceptionFilter oldOne = pMirandaExceptFilter;
+ if ( lParam != 0 )
+ pMirandaExceptFilter = ( pfnExceptionFilter )lParam;
+ return ( INT_PTR )oldOne;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// thread support functions
+
+typedef struct
+{
+ DWORD dwThreadId; // valid if hThread isn't signalled
+ HANDLE hThread;
+ HINSTANCE hOwner;
+ void* pObject;
+ PVOID addr;
+}
+THREAD_WAIT_ENTRY;
+
+static LIST<THREAD_WAIT_ENTRY> threads( 10, NumericKeySortT );
+
+struct FORK_ARG {
+ HANDLE hEvent;
+ pThreadFunc threadcode;
+ pThreadFuncEx threadcodeex;
+ void *arg, *owner;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// forkthread - starts a new thread
+
+void __cdecl forkthread_r(void * arg)
+{
+ struct FORK_ARG * fa = (struct FORK_ARG *) arg;
+ void (*callercode)(void*)=fa->threadcode;
+ void * cookie=fa->arg;
+ CallService(MS_SYSTEM_THREAD_PUSH,0,(LPARAM)callercode);
+ SetEvent(fa->hEvent);
+ __try
+ {
+ callercode(cookie);
+ }
+ __except( pMirandaExceptFilter( GetExceptionCode(), GetExceptionInformation()))
+ {
+ Netlib_Logf( NULL, "Unhandled exception in thread %x", GetCurrentThreadId());
+ }
+
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
+ CallService(MS_SYSTEM_THREAD_POP,0,0);
+ return;
+}
+
+UINT_PTR forkthread (
+ void (__cdecl *threadcode)(void*),
+ unsigned long stacksize,
+ void *arg
+ )
+{
+ UINT_PTR rc;
+ struct FORK_ARG fa;
+ fa.hEvent=CreateEvent(NULL,FALSE,FALSE,NULL);
+ fa.threadcode=threadcode;
+ fa.arg=arg;
+ rc=_beginthread(forkthread_r,stacksize,&fa);
+ if ((UINT_PTR)-1L != rc)
+ WaitForSingleObject(fa.hEvent,INFINITE);
+
+ CloseHandle(fa.hEvent);
+ return rc;
+}
+
+static INT_PTR ForkThreadService(WPARAM wParam, LPARAM lParam)
+{
+ return (INT_PTR)forkthread(( pThreadFunc )wParam, 0, ( void* )lParam );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// forkthreadex - starts a new thread with the extended info and returns the thread id
+
+unsigned __stdcall forkthreadex_r(void * arg)
+{
+ struct FORK_ARG *fa = (struct FORK_ARG *)arg;
+ pThreadFuncEx threadcode = fa->threadcodeex;
+ pThreadFuncOwner threadcodeex = ( pThreadFuncOwner )fa->threadcodeex;
+ void *cookie = fa->arg;
+ void *owner = fa->owner;
+ unsigned long rc = 0;
+
+ CallService(MS_SYSTEM_THREAD_PUSH, (WPARAM)fa->owner, (LPARAM)threadcode);
+ SetEvent(fa->hEvent);
+ __try
+ {
+ if ( owner )
+ rc = threadcodeex( owner, cookie );
+ else
+ rc = threadcode( cookie );
+ }
+ __except( pMirandaExceptFilter( GetExceptionCode(), GetExceptionInformation()))
+ {
+ Netlib_Logf( NULL, "Unhandled exception in thread %x", GetCurrentThreadId());
+ }
+
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
+ CallService(MS_SYSTEM_THREAD_POP,0,0);
+ return rc;
+}
+
+UINT_PTR forkthreadex(
+ void *sec,
+ unsigned stacksize,
+ unsigned (__stdcall *threadcode)(void*),
+ void* owner,
+ void *arg,
+ unsigned *thraddr )
+{
+ UINT_PTR rc;
+ struct FORK_ARG fa = { 0 };
+ fa.threadcodeex = threadcode;
+ fa.arg = arg;
+ fa.owner = owner;
+ fa.hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
+ rc = _beginthreadex(sec,stacksize,forkthreadex_r,(void *)&fa,0,thraddr);
+ if (rc)
+ WaitForSingleObject(fa.hEvent,INFINITE);
+
+ CloseHandle(fa.hEvent);
+ return rc;
+}
+
+static INT_PTR ForkThreadServiceEx(WPARAM wParam, LPARAM lParam)
+{
+ FORK_THREADEX_PARAMS* params = (FORK_THREADEX_PARAMS*)lParam;
+ if ( params == NULL )
+ return 0;
+
+ UINT threadID;
+ return forkthreadex( NULL, params->iStackSize, params->pFunc, ( void* )wParam, params->arg, params->threadID ? params->threadID : &threadID );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// APC and mutex functions
+
+static void __stdcall DummyAPCFunc(ULONG_PTR)
+{
+ /* called in the context of thread that cleared it's APC queue */
+ return;
+}
+
+static int MirandaWaitForMutex(HANDLE hEvent)
+{
+ for (;;) {
+ // will get WAIT_IO_COMPLETE for QueueUserAPC() which isnt a result
+ DWORD rc = MsgWaitForMultipleObjectsExWorkaround(1, &hEvent, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE);
+ if ( rc == WAIT_OBJECT_0 + 1 ) {
+ MSG msg;
+ while ( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ) {
+ if ( IsDialogMessage(msg.hwnd, &msg) ) continue;
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ } else if ( rc==WAIT_OBJECT_0 ) {
+ // got object
+ return 1;
+ } else if ( rc==WAIT_ABANDONED_0 || rc == WAIT_FAILED ) return 0;
+ }
+}
+
+VOID CALLBACK KillAllThreads(HWND, UINT, UINT_PTR, DWORD)
+{
+ if ( MirandaWaitForMutex( hStackMutex )) {
+ for ( int j=0; j < threads.getCount(); j++ ) {
+ THREAD_WAIT_ENTRY* p = threads[j];
+ char szModuleName[ MAX_PATH ];
+ GetModuleFileNameA( p->hOwner, szModuleName, sizeof(szModuleName));
+ Netlib_Logf( NULL, "Thread %p was abnormally terminated because module '%s' didn't release it. Entry point: %p",
+ p->hThread, szModuleName, p->addr );
+ TerminateThread( p->hThread, 9999 );
+ CloseHandle(p->hThread);
+ mir_free( p );
+ }
+
+ threads.destroy();
+
+ ReleaseMutex( hStackMutex );
+ SetEvent( hThreadQueueEmpty );
+ }
+}
+
+void KillObjectThreads( void* owner )
+{
+ if ( owner == NULL )
+ return;
+
+ WaitForSingleObject( hStackMutex, INFINITE );
+
+ HANDLE* threadPool = ( HANDLE* )alloca( threads.getCount()*sizeof( HANDLE ));
+ int threadCount = 0;
+
+ for ( int j = threads.getCount(); j--; ) {
+ THREAD_WAIT_ENTRY* p = threads[j];
+ if ( p->pObject == owner )
+ threadPool[ threadCount++ ] = p->hThread;
+ }
+ ReleaseMutex(hStackMutex);
+
+ // is there anything to kill?
+ if ( threadCount > 0 ) {
+ if ( WaitForMultipleObjects( threadCount, threadPool, TRUE, 5000 ) == WAIT_TIMEOUT ) {
+ // forcibly kill all remaining threads after 5 secs
+ WaitForSingleObject( hStackMutex, INFINITE );
+ for ( int j = threads.getCount()-1; j >= 0; j-- ) {
+ THREAD_WAIT_ENTRY* p = threads[j];
+ if ( p->pObject == owner ) {
+ TerminateThread( p->hThread, 9999 );
+ CloseHandle( p->hThread );
+ threads.remove( j );
+ mir_free( p );
+ }
+ }
+ ReleaseMutex(hStackMutex);
+ }
+ }
+}
+
+static void UnwindThreadWait(void)
+{
+ // acquire the list and wake up any alertable threads
+ if ( MirandaWaitForMutex(hStackMutex) ) {
+ int j;
+ for ( j=0; j < threads.getCount(); j++ )
+ QueueUserAPC(DummyAPCFunc,threads[j]->hThread, 0);
+ ReleaseMutex(hStackMutex);
+ }
+
+ // give all unclosed threads 5 seconds to close
+ SetTimer( NULL, 0, 5000, KillAllThreads );
+
+ // wait til the thread list is empty
+ MirandaWaitForMutex(hThreadQueueEmpty);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+typedef LONG (WINAPI *pNtQIT)(HANDLE, LONG, PVOID, ULONG, PULONG);
+#define ThreadQuerySetWin32StartAddress 9
+
+void* GetCurrentThreadEntryPoint()
+{
+ LONG ntStatus;
+ HANDLE hDupHandle, hCurrentProcess;
+ DWORD_PTR dwStartAddress;
+
+ pNtQIT NtQueryInformationThread = (pNtQIT)GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "NtQueryInformationThread" );
+ if(NtQueryInformationThread == NULL) return 0;
+
+ hCurrentProcess = GetCurrentProcess();
+ if(!DuplicateHandle(hCurrentProcess, GetCurrentThread(), hCurrentProcess, &hDupHandle, THREAD_QUERY_INFORMATION, FALSE, 0)){
+ SetLastError(ERROR_ACCESS_DENIED);
+ return NULL;
+ }
+ ntStatus = NtQueryInformationThread(hDupHandle, ThreadQuerySetWin32StartAddress, &dwStartAddress, sizeof(DWORD_PTR), NULL);
+ CloseHandle(hDupHandle);
+
+ if(ntStatus != ERROR_SUCCESS) return 0;
+ return ( void* )dwStartAddress;
+}
+
+INT_PTR UnwindThreadPush(WPARAM wParam,LPARAM lParam)
+{
+ ResetEvent(hThreadQueueEmpty); // thread list is not empty
+ if (WaitForSingleObject(hStackMutex, INFINITE) == WAIT_OBJECT_0)
+ {
+ THREAD_WAIT_ENTRY* p = (THREAD_WAIT_ENTRY*)mir_calloc(sizeof(THREAD_WAIT_ENTRY));
+
+ DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &p->hThread, 0, FALSE, DUPLICATE_SAME_ACCESS);
+ p->dwThreadId = GetCurrentThreadId();
+ p->pObject = (void*)wParam;
+ p->hOwner = GetInstByAddress((void*)lParam);
+ p->addr = (void*)lParam;
+ threads.insert(p);
+
+ //Netlib_Logf( NULL, "*** pushing thread %x[%x] (%d)", hThread, GetCurrentThreadId(), threads.count );
+ ReleaseMutex(hStackMutex);
+ } //if
+ return 0;
+}
+
+INT_PTR UnwindThreadPop(WPARAM,LPARAM)
+{
+ if (WaitForSingleObject(hStackMutex,INFINITE)==WAIT_OBJECT_0)
+ {
+ DWORD dwThreadId=GetCurrentThreadId();
+ int j;
+ //Netlib_Logf( NULL, "*** popping thread %x, %d threads left", dwThreadId, threads.count);
+ for ( j=0; j < threads.getCount(); j++ ) {
+ THREAD_WAIT_ENTRY* p = threads[j];
+ if ( p->dwThreadId == dwThreadId ) {
+ SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL );
+ CloseHandle( p->hThread );
+ threads.remove( j );
+ mir_free( p );
+
+ if ( !threads.getCount()) {
+ threads.destroy();
+ ReleaseMutex( hStackMutex );
+ SetEvent(hThreadQueueEmpty); // thread list is empty now
+ return 0;
+ }
+
+ ReleaseMutex(hStackMutex);
+ return 0;
+ } //if
+ } //for
+ ReleaseMutex(hStackMutex);
+ } //if
+ return 1;
+}
+
+INT_PTR MirandaIsTerminated(WPARAM, LPARAM)
+{
+ return WaitForSingleObject(hMirandaShutdown,0)==WAIT_OBJECT_0;
+}
+
+static void __cdecl compactHeapsThread(void*)
+{
+ while (!Miranda_Terminated())
+ {
+ HANDLE hHeaps[256];
+ DWORD hc;
+ SleepEx((1000*60)*5,TRUE); // every 5 minutes
+ hc=GetProcessHeaps(255,(PHANDLE)&hHeaps);
+ if (hc != 0 && hc < 256) {
+ DWORD j;
+ for (j=0;j<hc;j++) HeapCompact(hHeaps[j],0);
+ }
+ } //while
+}
+
+LRESULT CALLBACK APCWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ if (msg==WM_NULL) SleepEx(0,TRUE);
+ if (msg == WM_TIMECHANGE) RecalculateTime();
+ return DefWindowProc(hwnd,msg,wParam,lParam);
+}
+
+HWND hAPCWindow=NULL;
+void (*SetIdleCallback) (void)=NULL;
+
+static INT_PTR SystemSetIdleCallback(WPARAM, LPARAM lParam)
+{
+ if (lParam && SetIdleCallback==NULL) {
+ SetIdleCallback=(void (*)(void))lParam;
+ return 1;
+ }
+ return 0;
+}
+
+static DWORD dwEventTime=0;
+void checkIdle(MSG * msg)
+{
+ switch(msg->message) {
+ case WM_MOUSEACTIVATE:
+ case WM_MOUSEMOVE:
+ case WM_CHAR:
+ dwEventTime = GetTickCount();
+ }
+}
+
+static INT_PTR SystemGetIdle(WPARAM, LPARAM lParam)
+{
+ if ( lParam ) *(DWORD*)lParam = dwEventTime;
+ return 0;
+}
+
+static DWORD MsgWaitForMultipleObjectsExWorkaround(DWORD nCount, const HANDLE *pHandles,
+ DWORD dwMsecs, DWORD dwWakeMask, DWORD dwFlags)
+{
+ DWORD rc;
+ if ( msgWaitForMultipleObjectsEx != NULL )
+ return msgWaitForMultipleObjectsEx(nCount, pHandles, dwMsecs, dwWakeMask, dwFlags);
+ rc=MsgWaitForMultipleObjects(nCount, pHandles, FALSE, 50, QS_ALLINPUT);
+ if ( rc == WAIT_TIMEOUT ) rc=WaitForMultipleObjectsEx(nCount, pHandles, FALSE, 20, TRUE);
+ return rc;
+}
+
+static int SystemShutdownProc(WPARAM, LPARAM)
+{
+ UnloadDefaultModules();
+ return 0;
+}
+
+#define MIRANDA_PROCESS_WAIT_TIMEOUT 60000
+#define MIRANDA_PROCESS_WAIT_RESOLUTION 1000
+#define MIRANDA_PROCESS_WAIT_STEPS (MIRANDA_PROCESS_WAIT_TIMEOUT/MIRANDA_PROCESS_WAIT_RESOLUTION)
+static INT_PTR CALLBACK WaitForProcessDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwnd );
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam);
+ SendDlgItemMessage(hwnd, IDC_PROGRESSBAR, PBM_SETRANGE, 0, MAKELPARAM(0, MIRANDA_PROCESS_WAIT_STEPS));
+ SendDlgItemMessage(hwnd, IDC_PROGRESSBAR, PBM_SETSTEP, 1, 0);
+ SetTimer(hwnd, 1, MIRANDA_PROCESS_WAIT_RESOLUTION, NULL);
+ break;
+
+ case WM_TIMER:
+ if (SendDlgItemMessage(hwnd, IDC_PROGRESSBAR, PBM_STEPIT, 0, 0) == MIRANDA_PROCESS_WAIT_STEPS)
+ EndDialog(hwnd, 0);
+ if (WaitForSingleObject((HANDLE)GetWindowLongPtr(hwnd, GWLP_USERDATA), 1) != WAIT_TIMEOUT)
+ {
+ SendDlgItemMessage(hwnd, IDC_PROGRESSBAR, PBM_SETPOS, MIRANDA_PROCESS_WAIT_STEPS, 0);
+ EndDialog(hwnd, 0);
+ }
+ break;
+
+ case WM_COMMAND:
+ if (HIWORD(wParam) == IDCANCEL)
+ {
+ SendDlgItemMessage(hwnd, IDC_PROGRESSBAR, PBM_SETPOS, MIRANDA_PROCESS_WAIT_STEPS, 0);
+ EndDialog(hwnd, 0);
+ }
+ break;
+ }
+ return FALSE;
+}
+
+void ParseCommandLine()
+{
+ char* cmdline = GetCommandLineA();
+ char* p = strstr( cmdline, "/restart:" );
+ if ( p ) {
+ HANDLE hProcess = OpenProcess( SYNCHRONIZE, FALSE, atol( p+9 ));
+ if ( hProcess ) {
+ DialogBoxParam(hMirandaInst, MAKEINTRESOURCE(IDD_WAITRESTART), NULL, WaitForProcessDlgProc, (LPARAM)hProcess);
+ CloseHandle( hProcess );
+ }
+ }
+}
+
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int )
+{
+ DWORD myPid=0;
+ int messageloop=1;
+ HMODULE hUser32, hThemeAPI, hDwmApi, hShFolder = NULL;
+ int result = 0;
+
+ hMirandaInst = hInstance;
+
+ setlocale(LC_ALL, "");
+
+#ifdef _DEBUG
+ _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
+#endif
+
+ hUser32 = GetModuleHandleA("user32");
+ openInputDesktop = (pfnOpenInputDesktop)GetProcAddress (hUser32, "OpenInputDesktop");
+ closeDesktop = (pfnCloseDesktop)GetProcAddress (hUser32, "CloseDesktop");
+ msgWaitForMultipleObjectsEx = (pfnMsgWaitForMultipleObjectsEx)GetProcAddress(hUser32, "MsgWaitForMultipleObjectsEx");
+ animateWindow =(pfnAnimateWindow)GetProcAddress(hUser32, "AnimateWindow");
+ setLayeredWindowAttributes =(pfnSetLayeredWindowAttributes)GetProcAddress(hUser32, "SetLayeredWindowAttributes");
+
+ MyMonitorFromPoint = (pfnMyMonitorFromPoint)GetProcAddress(hUser32, "MonitorFromPoint");
+ MyMonitorFromRect = (pfnMyMonitorFromRect)GetProcAddress(hUser32, "MonitorFromRect");
+ MyMonitorFromWindow = (pfnMyMonitorFromWindow)GetProcAddress(hUser32, "MonitorFromWindow");
+#ifdef _UNICODE
+ MyGetMonitorInfo = (pfnMyGetMonitorInfo)GetProcAddress(hUser32, "GetMonitorInfoW");
+#else
+ MyGetMonitorInfo = (pfnMyGetMonitorInfo)GetProcAddress(hUser32, "GetMonitorInfoA");
+#endif
+
+ hShFolder = GetModuleHandleA("shell32");
+ shGetSpecialFolderPathA = (pfnSHGetSpecialFolderPathA)GetProcAddress(hShFolder,"SHGetSpecialFolderPathA");
+ shGetSpecialFolderPathW = (pfnSHGetSpecialFolderPathW)GetProcAddress(hShFolder,"SHGetSpecialFolderPathW");
+ if (shGetSpecialFolderPathA == NULL)
+ {
+ hShFolder = LoadLibraryA("ShFolder.dll");
+ shGetSpecialFolderPathA = (pfnSHGetSpecialFolderPathA)GetProcAddress(hShFolder,"SHGetSpecialFolderPathA");
+ shGetSpecialFolderPathW = (pfnSHGetSpecialFolderPathW)GetProcAddress(hShFolder,"SHGetSpecialFolderPathW");
+ }
+
+ shAutoComplete = (pfnSHAutoComplete)GetProcAddress(GetModuleHandleA("shlwapi"),"SHAutoComplete");
+
+ if (IsWinVerXPPlus())
+ {
+ hThemeAPI = LoadLibraryA("uxtheme.dll");
+ if (hThemeAPI)
+ {
+ openThemeData = (pfnOpenThemeData)GetProcAddress(hThemeAPI, "OpenThemeData");
+ isThemeBackgroundPartiallyTransparent = (pfnIsThemeBackgroundPartiallyTransparent)GetProcAddress(hThemeAPI, "IsThemeBackgroundPartiallyTransparent");
+ drawThemeParentBackground = (pfnDrawThemeParentBackground)GetProcAddress(hThemeAPI, "DrawThemeParentBackground");
+ drawThemeBackground = (pfnDrawThemeBackground)GetProcAddress(hThemeAPI, "DrawThemeBackground");
+ drawThemeText = (pfnDrawThemeText)GetProcAddress(hThemeAPI, "DrawThemeText");
+ drawThemeTextEx = (pfnDrawThemeTextEx)GetProcAddress(hThemeAPI, "DrawThemeTextEx");
+ getThemeBackgroundContentRect = (pfnGetThemeBackgroundContentRect)GetProcAddress(hThemeAPI ,"GetThemeBackgroundContentRect");
+ getThemeFont = (pfnGetThemeFont)GetProcAddress(hThemeAPI, "GetThemeFont");
+ closeThemeData = (pfnCloseThemeData)GetProcAddress(hThemeAPI, "CloseThemeData");
+ enableThemeDialogTexture = (pfnEnableThemeDialogTexture)GetProcAddress(hThemeAPI, "EnableThemeDialogTexture");
+ setWindowTheme = (pfnSetWindowTheme)GetProcAddress(hThemeAPI, "SetWindowTheme");
+ setWindowThemeAttribute = (pfnSetWindowThemeAttribute)GetProcAddress(hThemeAPI, "SetWindowThemeAttribute");
+ isThemeActive = (pfnIsThemeActive)GetProcAddress(hThemeAPI, "IsThemeActive");
+ bufferedPaintInit = (pfnBufferedPaintInit)GetProcAddress(hThemeAPI, "BufferedPaintInit");
+ bufferedPaintUninit = (pfnBufferedPaintUninit)GetProcAddress(hThemeAPI, "BufferedPaintUninit");
+ beginBufferedPaint = (pfnBeginBufferedPaint)GetProcAddress(hThemeAPI, "BeginBufferedPaint");
+ endBufferedPaint = (pfnEndBufferedPaint)GetProcAddress(hThemeAPI, "EndBufferedPaint");
+ getBufferedPaintBits = (pfnGetBufferedPaintBits)GetProcAddress(hThemeAPI, "GetBufferedPaintBits");
+ }
+ }
+
+ if (IsWinVerVistaPlus())
+ {
+ hDwmApi = LoadLibraryA("dwmapi.dll");
+ if (hDwmApi)
+ {
+ dwmExtendFrameIntoClientArea = (pfnDwmExtendFrameIntoClientArea)GetProcAddress(hDwmApi,"DwmExtendFrameIntoClientArea");
+ dwmIsCompositionEnabled = (pfnDwmIsCompositionEnabled)GetProcAddress(hDwmApi,"DwmIsCompositionEnabled");
+ }
+ }
+
+ HMODULE hWinSock = GetModuleHandleA("ws2_32");
+ MyGetaddrinfo = (pfnGetaddrinfo)GetProcAddress(hWinSock, "getaddrinfo");
+ MyFreeaddrinfo = (pfnFreeaddrinfo)GetProcAddress(hWinSock, "freeaddrinfo");
+
+ if (bufferedPaintInit) bufferedPaintInit();
+
+ OleInitialize(NULL);
+
+ if (IsWinVer7Plus())
+ CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_ALL, IID_ITaskbarList3, (void**)&pTaskbarInterface);
+
+ InitialiseModularEngine();
+// ParseCommandLine();
+
+ if (LoadDefaultModules()) {
+ NotifyEventHooks(hShutdownEvent,0,0);
+ UnloadDefaultModules();
+
+ result = 1;
+ goto exit;
+ }
+ NotifyEventHooks(hModulesLoadedEvent,0,0);
+
+ // ensure that the kernel hooks the SystemShutdownProc() after all plugins
+ HookEvent(ME_SYSTEM_SHUTDOWN,SystemShutdownProc);
+
+ forkthread(compactHeapsThread,0,NULL);
+ CreateServiceFunction(MS_SYSTEM_SETIDLECALLBACK,SystemSetIdleCallback);
+ CreateServiceFunction(MS_SYSTEM_GETIDLE, SystemGetIdle);
+ dwEventTime=GetTickCount();
+ myPid=GetCurrentProcessId();
+ for(;messageloop;) {
+ MSG msg;
+ DWORD rc;
+ BOOL dying=FALSE;
+ rc=MsgWaitForMultipleObjectsExWorkaround(waitObjectCount, hWaitObjects, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE);
+ if ( rc >= WAIT_OBJECT_0 && rc < WAIT_OBJECT_0 + waitObjectCount) {
+ rc -= WAIT_OBJECT_0;
+ CallService(pszWaitServices[rc], (WPARAM) hWaitObjects[rc], 0);
+ }
+ //
+ while ( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ) {
+ if ( msg.message != WM_QUIT ) {
+ HWND h=GetForegroundWindow();
+ DWORD pid = 0;
+ checkIdle(&msg);
+ if ( h != NULL && GetWindowThreadProcessId(h, &pid) && pid == myPid &&
+ GetClassLongPtr(h, GCW_ATOM)==32770 )
+ {
+ if ( IsDialogMessage(h, &msg) )
+ continue;
+ }
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ if ( SetIdleCallback != NULL )
+ SetIdleCallback();
+ } else if ( !dying ) {
+ dying++;
+ SetEvent(hMirandaShutdown);
+ NotifyEventHooks(hPreShutdownEvent, 0, 0);
+
+ // this spins and processes the msg loop, objects and APC.
+ UnwindThreadWait();
+ NotifyEventHooks(hShutdownEvent, 0, 0);
+ // if the hooks generated any messages, it'll get processed before the second WM_QUIT
+ PostQuitMessage(0);
+ } else if ( dying ) {
+ messageloop=0;
+ }
+ } // while
+ }
+
+exit:
+ UnloadNewPluginsModule();
+ DestroyModularEngine();
+ CloseHandle(hStackMutex);
+ CloseHandle(hMirandaShutdown);
+ CloseHandle(hThreadQueueEmpty);
+ DestroyWindow(hAPCWindow);
+
+ if (pTaskbarInterface)
+ pTaskbarInterface->Release();
+
+ OleUninitialize();
+
+ if (bufferedPaintUninit) bufferedPaintUninit();
+
+ if (hDwmApi) FreeLibrary(hDwmApi);
+ if (hThemeAPI) FreeLibrary(hThemeAPI);
+ if (hShFolder) FreeLibrary(hShFolder);
+
+ return result;
+}
+
+static INT_PTR OkToExit(WPARAM, LPARAM)
+{
+ return NotifyEventHooks(hOkToExitEvent,0,0)==0;
+}
+
+static INT_PTR GetMirandaVersion(WPARAM, LPARAM)
+{
+ TCHAR filename[MAX_PATH];
+ DWORD unused;
+ DWORD verInfoSize;
+ UINT blockSize;
+ PVOID pVerInfo;
+ VS_FIXEDFILEINFO *vsffi;
+ DWORD ver;
+
+ GetModuleFileName(NULL,filename,SIZEOF(filename));
+ verInfoSize=GetFileVersionInfoSize(filename,&unused);
+ pVerInfo=mir_alloc(verInfoSize);
+ GetFileVersionInfo(filename,0,verInfoSize,pVerInfo);
+ VerQueryValue(pVerInfo,_T("\\"),(PVOID*)&vsffi,&blockSize);
+ ver=(((vsffi->dwProductVersionMS>>16)&0xFF)<<24)|
+ ((vsffi->dwProductVersionMS&0xFF)<<16)|
+ (((vsffi->dwProductVersionLS>>16)&0xFF)<<8)|
+ (vsffi->dwProductVersionLS&0xFF);
+ mir_free(pVerInfo);
+ return (INT_PTR)ver;
+}
+
+static INT_PTR GetMirandaVersionText(WPARAM wParam,LPARAM lParam)
+{
+ TCHAR filename[MAX_PATH], *productVersion;
+ DWORD unused;
+ DWORD verInfoSize;
+ UINT blockSize;
+ PVOID pVerInfo;
+
+ GetModuleFileName(NULL,filename,SIZEOF(filename));
+ verInfoSize=GetFileVersionInfoSize(filename,&unused);
+ pVerInfo=mir_alloc(verInfoSize);
+ GetFileVersionInfo(filename,0,verInfoSize,pVerInfo);
+ VerQueryValue(pVerInfo,_T("\\StringFileInfo\\000004b0\\ProductVersion"),(LPVOID*)&productVersion,&blockSize);
+#if defined( _WIN64 )
+ mir_snprintf(( char* )lParam, wParam, "%S x64 Unicode", productVersion );
+#elif defined( _UNICODE )
+ mir_snprintf(( char* )lParam, wParam, "%S Unicode", productVersion );
+#else
+ lstrcpyn((char*)lParam,productVersion,wParam);
+#endif
+ mir_free(pVerInfo);
+ return 0;
+}
+
+INT_PTR WaitOnHandle(WPARAM wParam,LPARAM lParam)
+{
+ if(waitObjectCount>=MAXIMUM_WAIT_OBJECTS-1) return 1;
+ hWaitObjects[waitObjectCount]=(HANDLE)wParam;
+ pszWaitServices[waitObjectCount]=(char*)lParam;
+ waitObjectCount++;
+ return 0;
+}
+
+static INT_PTR RemoveWait(WPARAM wParam, LPARAM)
+{
+ int i;
+
+ for(i=0;i<waitObjectCount;i++)
+ if(hWaitObjects[i]==(HANDLE)wParam) break;
+ if(i==waitObjectCount) return 1;
+ waitObjectCount--;
+ MoveMemory(&hWaitObjects[i],&hWaitObjects[i+1],sizeof(HANDLE)*(waitObjectCount-i));
+ MoveMemory(&pszWaitServices[i],&pszWaitServices[i+1],sizeof(char*)*(waitObjectCount-i));
+ return 0;
+}
+
+INT_PTR GetMemoryManagerInterface(WPARAM, LPARAM lParam)
+{
+ struct MM_INTERFACE *mmi = (struct MM_INTERFACE*) lParam;
+ if ( mmi == NULL )
+ return 1;
+
+ mmi->mmi_malloc = mir_alloc;
+ mmi->mmi_realloc = mir_realloc;
+ mmi->mmi_free = mir_free;
+
+ switch( mmi->cbSize ) {
+ case sizeof(struct MM_INTERFACE):
+ mmi->mir_snprintf = mir_snprintf;
+ mmi->mir_sntprintf = mir_sntprintf;
+ mmi->mir_vsnprintf = mir_vsnprintf;
+ mmi->mir_vsntprintf = mir_vsntprintf;
+ mmi->mir_a2u_cp = mir_a2u_cp;
+ mmi->mir_a2u = mir_a2u;
+ mmi->mir_u2a_cp = mir_u2a_cp;
+ mmi->mir_u2a = mir_u2a;
+ // fall through
+
+ case MMI_SIZE_V2:
+ mmi->mmi_calloc = mir_calloc;
+ mmi->mmi_strdup = mir_strdup;
+ mmi->mmi_wstrdup = mir_wstrdup;
+ // fall through
+
+ case MMI_SIZE_V1:
+ break;
+
+ default:
+#if defined( _DEBUG )
+ DebugBreak();
+#endif
+ return 1;
+ }
+
+ return 0;
+}
+
+INT_PTR GetListInterface(WPARAM, LPARAM lParam)
+{
+ struct LIST_INTERFACE *li = (struct LIST_INTERFACE*) lParam;
+ if ( li == NULL )
+ return 1;
+
+ switch(li->cbSize) {
+ case LIST_INTERFACE_V3_SIZE:
+ li->List_Copy = List_Copy;
+ li->List_ObjCopy = List_ObjCopy;
+
+ case LIST_INTERFACE_V2_SIZE:
+ li->List_InsertPtr = List_InsertPtr;
+ li->List_RemovePtr = List_RemovePtr;
+
+ case LIST_INTERFACE_V1_SIZE:
+ li->List_Create = List_Create;
+ li->List_Destroy = List_Destroy;
+ li->List_Find = List_Find;
+ li->List_GetIndex = List_GetIndex;
+ li->List_Insert = List_Insert;
+ li->List_Remove = List_Remove;
+ li->List_IndexOf = List_IndexOf;
+ return 0;
+ }
+ return 1;
+}
+
+INT_PTR GetUtfInterface(WPARAM, LPARAM lParam)
+{
+ struct UTF8_INTERFACE *utfi = (struct UTF8_INTERFACE*) lParam;
+ if ( utfi == NULL )
+ return 1;
+
+ switch( utfi->cbSize ) {
+ case UTF8_INTERFACE_SIZEOF_V1:
+ case UTF8_INTERFACE_SIZEOF_V2:
+ case sizeof( struct UTF8_INTERFACE ):
+ break;
+
+ default:
+ return 1;
+ }
+
+ utfi->utf8_decode = Utf8Decode;
+ utfi->utf8_decodecp = Utf8DecodeCP;
+ utfi->utf8_encode = Utf8Encode;
+ utfi->utf8_encodecp = Utf8EncodeCP;
+ utfi->utf8_encodeW = Utf8EncodeUcs2;
+ if (utfi->cbSize > UTF8_INTERFACE_SIZEOF_V1)
+ utfi->utf8_decodeW = Utf8DecodeUcs2;
+ if (utfi->cbSize > UTF8_INTERFACE_SIZEOF_V2)
+ utfi->utf8_lenW = Ucs2toUtf8Len;
+
+ return 0;
+}
+
+int LoadSystemModule(void)
+{
+ INITCOMMONCONTROLSEX icce = {0};
+ icce.dwSize = sizeof(icce);
+ icce.dwICC = ICC_WIN95_CLASSES | ICC_USEREX_CLASSES;
+ InitCommonControlsEx(&icce);
+
+ if (IsWinVerXPPlus()) {
+ hAPCWindow=CreateWindowEx(0,_T("ComboLBox"),NULL,0, 0,0,0,0, NULL,NULL,NULL,NULL);
+ SetClassLongPtr(hAPCWindow, GCL_STYLE, GetClassLongPtr(hAPCWindow, GCL_STYLE) | CS_DROPSHADOW);
+ DestroyWindow(hAPCWindow);
+ hAPCWindow = NULL;
+ }
+
+ hAPCWindow=CreateWindowEx(0,_T("STATIC"),NULL,0, 0,0,0,0, NULL,NULL,NULL,NULL); // lame
+ SetWindowLongPtr(hAPCWindow,GWLP_WNDPROC,(LONG_PTR)APCWndProc);
+ hStackMutex=CreateMutex(NULL,FALSE,NULL);
+ hMirandaShutdown=CreateEvent(NULL,TRUE,FALSE,NULL);
+ hThreadQueueEmpty=CreateEvent(NULL,TRUE,TRUE,NULL);
+
+ hShutdownEvent=CreateHookableEvent(ME_SYSTEM_SHUTDOWN);
+ hPreShutdownEvent=CreateHookableEvent(ME_SYSTEM_PRESHUTDOWN);
+ hModulesLoadedEvent=CreateHookableEvent(ME_SYSTEM_MODULESLOADED);
+ hOkToExitEvent=CreateHookableEvent(ME_SYSTEM_OKTOEXIT);
+
+ CreateServiceFunction(MS_SYSTEM_FORK_THREAD,ForkThreadService);
+ CreateServiceFunction(MS_SYSTEM_FORK_THREAD_EX,ForkThreadServiceEx);
+ CreateServiceFunction(MS_SYSTEM_THREAD_PUSH,UnwindThreadPush);
+ CreateServiceFunction(MS_SYSTEM_THREAD_POP,UnwindThreadPop);
+ CreateServiceFunction(MS_SYSTEM_TERMINATED,MirandaIsTerminated);
+ CreateServiceFunction(MS_SYSTEM_OKTOEXIT,OkToExit);
+ CreateServiceFunction(MS_SYSTEM_GETVERSION,GetMirandaVersion);
+ CreateServiceFunction(MS_SYSTEM_GETVERSIONTEXT,GetMirandaVersionText);
+ CreateServiceFunction(MS_SYSTEM_WAITONHANDLE,WaitOnHandle);
+ CreateServiceFunction(MS_SYSTEM_REMOVEWAIT,RemoveWait);
+ CreateServiceFunction(MS_SYSTEM_GET_LI,GetListInterface);
+ CreateServiceFunction(MS_SYSTEM_GET_MMI,GetMemoryManagerInterface);
+ CreateServiceFunction(MS_SYSTEM_GET_UTFI,GetUtfInterface);
+ CreateServiceFunction(MS_SYSTEM_GETEXCEPTFILTER,GetExceptionFilter);
+ CreateServiceFunction(MS_SYSTEM_SETEXCEPTFILTER,SetExceptionFilter);
+
+ InitPathUtils();
+ return 0;
+}
diff --git a/src/core/miranda.h b/src/core/miranda.h
new file mode 100644
index 0000000000..850e2a78c8
--- /dev/null
+++ b/src/core/miranda.h
@@ -0,0 +1,370 @@
+/*
+
+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.
+*/
+
+#define NEWSTR_ALLOCA(A) (A==NULL)?NULL:strcpy((char*)alloca(strlen(A)+1),A)
+#define NEWTSTR_ALLOCA(A) (A==NULL)?NULL:_tcscpy((TCHAR*)alloca((_tcslen(A)+1)* sizeof(TCHAR)),A)
+
+typedef HMONITOR (WINAPI *pfnMyMonitorFromPoint)(POINT, DWORD);
+extern pfnMyMonitorFromPoint MyMonitorFromPoint;
+
+typedef HMONITOR (WINAPI *pfnMyMonitorFromRect)(LPCRECT, DWORD);
+extern pfnMyMonitorFromRect MyMonitorFromRect;
+
+typedef HMONITOR(WINAPI *pfnMyMonitorFromWindow) (HWND, DWORD);
+extern pfnMyMonitorFromWindow MyMonitorFromWindow;
+
+typedef BOOL(WINAPI *pfnMyGetMonitorInfo) (HMONITOR, LPMONITORINFO);
+extern pfnMyGetMonitorInfo MyGetMonitorInfo;
+
+typedef HRESULT (STDAPICALLTYPE *pfnSHAutoComplete)(HWND,DWORD);
+extern pfnSHAutoComplete shAutoComplete;
+
+typedef HRESULT (STDAPICALLTYPE *pfnSHGetSpecialFolderPathA)(HWND, LPSTR, int, BOOL );
+typedef HRESULT (STDAPICALLTYPE *pfnSHGetSpecialFolderPathW)(HWND, LPWSTR, int, BOOL );
+extern pfnSHGetSpecialFolderPathA shGetSpecialFolderPathA;
+extern pfnSHGetSpecialFolderPathW shGetSpecialFolderPathW;
+
+#ifdef _UNICODE
+#define shGetSpecialFolderPath shGetSpecialFolderPathW
+#else
+#define shGetSpecialFolderPath shGetSpecialFolderPathA
+#endif
+
+typedef HDESK (WINAPI* pfnOpenInputDesktop)(DWORD, BOOL, DWORD);
+extern pfnOpenInputDesktop openInputDesktop;
+
+typedef HDESK (WINAPI* pfnCloseDesktop)(HDESK);
+extern pfnCloseDesktop closeDesktop;
+
+typedef BOOL (WINAPI* pfnAnimateWindow)(HWND, DWORD, DWORD);
+extern pfnAnimateWindow animateWindow;
+
+typedef BOOL (WINAPI * pfnSetLayeredWindowAttributes) (HWND, COLORREF, BYTE, DWORD);
+extern pfnSetLayeredWindowAttributes setLayeredWindowAttributes;
+
+typedef HTHEME ( STDAPICALLTYPE *pfnOpenThemeData )( HWND, LPCWSTR );
+typedef HRESULT ( STDAPICALLTYPE *pfnIsThemeBackgroundPartiallyTransparent )( HTHEME, int, int );
+typedef HRESULT ( STDAPICALLTYPE *pfnDrawThemeParentBackground )( HWND, HDC, const RECT * );
+typedef HRESULT ( STDAPICALLTYPE *pfnDrawThemeBackground )( HTHEME, HDC, int, int, const RECT *, const RECT * );
+typedef HRESULT ( STDAPICALLTYPE *pfnDrawThemeText)( HTHEME, HDC, int, int, LPCWSTR, int, DWORD, DWORD, const RECT *);
+typedef HRESULT ( STDAPICALLTYPE *pfnDrawThemeTextEx)( HTHEME, HDC, int, int, LPCWSTR, int, DWORD, LPRECT, const struct _DTTOPTS * );
+typedef HRESULT ( STDAPICALLTYPE *pfnGetThemeBackgroundContentRect)( HTHEME, HDC, int, int, LPCRECT, LPRECT );
+typedef HRESULT ( STDAPICALLTYPE *pfnGetThemeFont)( HTHEME, HDC, int, int, int, LOGFONT * );
+typedef HRESULT ( STDAPICALLTYPE *pfnCloseThemeData )( HTHEME );
+typedef HRESULT ( STDAPICALLTYPE *pfnEnableThemeDialogTexture )( HWND hwnd, DWORD dwFlags );
+typedef HRESULT ( STDAPICALLTYPE *pfnSetWindowTheme )( HWND, LPCWSTR, LPCWSTR );
+typedef HRESULT ( STDAPICALLTYPE *pfnSetWindowThemeAttribute )( HWND, enum WINDOWTHEMEATTRIBUTETYPE, PVOID, DWORD );
+typedef BOOL ( STDAPICALLTYPE *pfnIsThemeActive )();
+typedef HRESULT (STDAPICALLTYPE *pfnBufferedPaintInit)(void);
+typedef HRESULT (STDAPICALLTYPE *pfnBufferedPaintUninit)(void);
+typedef HANDLE (STDAPICALLTYPE *pfnBeginBufferedPaint)(HDC, RECT *, BP_BUFFERFORMAT, BP_PAINTPARAMS *, HDC *);
+typedef HRESULT (STDAPICALLTYPE *pfnEndBufferedPaint)(HANDLE, BOOL);
+typedef HRESULT (STDAPICALLTYPE *pfnGetBufferedPaintBits)(HANDLE, RGBQUAD **, int *);
+
+extern pfnOpenThemeData openThemeData;
+extern pfnIsThemeBackgroundPartiallyTransparent isThemeBackgroundPartiallyTransparent;
+extern pfnDrawThemeParentBackground drawThemeParentBackground;
+extern pfnDrawThemeBackground drawThemeBackground;
+extern pfnDrawThemeText drawThemeText;
+extern pfnDrawThemeTextEx drawThemeTextEx;
+extern pfnGetThemeBackgroundContentRect getThemeBackgroundContentRect;
+extern pfnGetThemeFont getThemeFont;
+extern pfnCloseThemeData closeThemeData;
+extern pfnEnableThemeDialogTexture enableThemeDialogTexture;
+extern pfnSetWindowTheme setWindowTheme;
+extern pfnSetWindowThemeAttribute setWindowThemeAttribute;
+extern pfnIsThemeActive isThemeActive;
+extern pfnBufferedPaintInit bufferedPaintInit;
+extern pfnBufferedPaintUninit bufferedPaintUninit;
+extern pfnBeginBufferedPaint beginBufferedPaint;
+extern pfnEndBufferedPaint endBufferedPaint;
+extern pfnGetBufferedPaintBits getBufferedPaintBits;
+
+extern ITaskbarList3 * pTaskbarInterface;
+
+typedef HRESULT ( STDAPICALLTYPE *pfnDwmExtendFrameIntoClientArea )( HWND hwnd, const MARGINS *margins );
+typedef HRESULT ( STDAPICALLTYPE *pfnDwmIsCompositionEnabled )( BOOL * );
+
+extern pfnDwmExtendFrameIntoClientArea dwmExtendFrameIntoClientArea;
+extern pfnDwmIsCompositionEnabled dwmIsCompositionEnabled;
+
+typedef INT (STDAPICALLTYPE *pfnGetaddrinfo)(PCSTR pNodeName, PCSTR pServiceName, const ADDRINFOA * pHints, PADDRINFOA * ppResult);
+typedef INT (STDAPICALLTYPE *pfnFreeaddrinfo)(PADDRINFOA pAddrInfo);
+
+extern pfnGetaddrinfo MyGetaddrinfo;
+extern pfnFreeaddrinfo MyFreeaddrinfo;
+
+/**** file.c ***************************************************************************/
+
+void PushFileEvent( HANDLE hContact, HANDLE hdbe, LPARAM lParam );
+
+/**** memory.c *************************************************************************/
+
+#ifdef _STATIC
+void* mir_alloc( size_t );
+void* mir_calloc( size_t );
+void* mir_realloc( void* ptr, size_t );
+void mir_free( void* ptr );
+char* mir_strdup( const char* str );
+WCHAR* mir_wstrdup( const WCHAR* str );
+char* mir_strndup( const char* str, size_t len );
+
+int mir_snprintf(char *buffer, size_t count, const char* fmt, ...);
+int mir_sntprintf(TCHAR *buffer, size_t count, const TCHAR* fmt, ...);
+int mir_vsnprintf(char *buffer, size_t count, const char* fmt, va_list va);
+int mir_vsntprintf(TCHAR *buffer, size_t count, const TCHAR* fmt, va_list va);
+
+WCHAR* mir_a2u_cp(const char* src, int codepage);
+WCHAR* mir_a2u(const char* src);
+char* mir_u2a_cp(const wchar_t* src, int codepage);
+char* mir_u2a( const wchar_t* src);
+#endif
+
+/**** miranda.c ************************************************************************/
+
+extern HINSTANCE hMirandaInst;
+extern pfnExceptionFilter pMirandaExceptFilter;
+
+/**** modules.c ************************************************************************/
+
+void KillModuleEventHooks( HINSTANCE );
+void KillModuleServices( HINSTANCE );
+
+void KillObjectEventHooks( void* pObject );
+void KillObjectServices( void* pObject );
+void KillObjectThreads( void* pObject );
+
+/**** utf.c ****************************************************************************/
+
+char* Utf8Decode( char* str, wchar_t** ucs2 );
+char* Utf8DecodeCP( char* str, int codepage, wchar_t** ucs2 );
+
+wchar_t* Utf8DecodeUcs2( const char* str );
+
+__forceinline char* Utf8DecodeA(const char* src)
+{
+ char* tmp = mir_strdup(src);
+ Utf8Decode(tmp, NULL);
+ return tmp;
+}
+
+
+char* Utf8Encode( const char* str );
+char* Utf8EncodeCP( const char* src, int codepage );
+
+char* Utf8EncodeUcs2( const wchar_t* str );
+
+int Ucs2toUtf8Len(const wchar_t *src);
+
+#if defined( _UNICODE )
+ #define Utf8DecodeT Utf8DecodeUcs2
+ #define Utf8EncodeT Utf8EncodeUcs2
+#else
+ #define Utf8DecodeT Utf8DecodeA
+ #define Utf8EncodeT Utf8Encode
+#endif
+
+/**** langpack.c ***********************************************************************/
+
+int LangPackGetDefaultCodePage();
+int LangPackGetDefaultLocale();
+TCHAR* LangPackPcharToTchar( const char* pszStr );
+char* LangPackTranslateString(struct LangPackMuuid* pUuid, const char *szEnglish, const int W);
+
+unsigned int __fastcall hash(const void * key, unsigned int len);
+
+#pragma optimize( "gt", on )
+__inline unsigned int hashstr(const char * key)
+{
+ if (key == NULL) return 0;
+ const unsigned int len = (unsigned int)strlen((const char*)key);
+ return hash(key, len);
+}
+
+__inline unsigned int hashstr(const wchar_t * key)
+{
+ if (key == NULL) return 0;
+ const unsigned int len = (unsigned int)wcslen((const wchar_t*)key);
+ return hash(key, len * sizeof(wchar_t));
+}
+#pragma optimize( "", on )
+
+/**** path.c ***************************************************************************/
+
+int pathToAbsolute(const char *pSrc, char *pOut, char* base);
+void CreatePathToFile( char* wszFilePath );
+int CreateDirectoryTree(const char *szDir);
+#if defined( _UNICODE )
+ void CreatePathToFileW( WCHAR* wszFilePath );
+ int CreateDirectoryTreeW(const WCHAR *szDir);
+ int pathToAbsoluteW(const TCHAR *pSrc, TCHAR *pOut, TCHAR* base);
+ #define pathToAbsoluteT pathToAbsoluteW
+ #define CreatePathToFileT CreatePathToFileW
+ #define CreateDirectoryTreeT CreateDirectoryTreeW
+#else
+ #define pathToAbsoluteT pathToAbsolute
+ #define CreatePathToFileT CreatePathToFile
+ #define CreateDirectoryTreeT CreateDirectoryTree
+#endif
+
+/**** skin2icons.c *********************************************************************/
+
+HANDLE IcoLib_AddNewIcon( SKINICONDESC* sid );
+HICON IcoLib_GetIcon( const char* pszIconName, bool big );
+HICON IcoLib_GetIconByHandle( HANDLE hItem, bool big );
+HANDLE IcoLib_IsManaged( HICON hIcon );
+int IcoLib_ReleaseIcon( HICON hIcon, char* szIconName, bool big );
+
+/**** skinicons.c **********************************************************************/
+
+HICON LoadSkinProtoIcon( const char* szProto, int status, bool big = false );
+HICON LoadSkinIcon( int idx, bool big = false );
+HANDLE GetSkinIconHandle( int idx );
+
+HICON LoadIconEx(HINSTANCE hInstance, LPCTSTR lpIconName, BOOL bShared);
+int ImageList_AddIcon_NotShared(HIMAGELIST hIml, LPCTSTR szResource);
+int ImageList_ReplaceIcon_NotShared(HIMAGELIST hIml, int iIndex, HINSTANCE hInstance, LPCTSTR szResource);
+
+int ImageList_AddIcon_IconLibLoaded(HIMAGELIST hIml, int iconId);
+int ImageList_AddIcon_ProtoIconLibLoaded(HIMAGELIST hIml, const char* szProto, int iconId);
+int ImageList_ReplaceIcon_IconLibLoaded(HIMAGELIST hIml, int nIndex, HICON hIcon);
+
+void Button_SetIcon_IcoLib(HWND hDlg, int itemId, int iconId, const char* tooltip);
+void Button_FreeIcon_IcoLib(HWND hDlg, int itemId);
+
+void Window_SetIcon_IcoLib(HWND hWnd, int iconId);
+void Window_SetProtoIcon_IcoLib(HWND hWnd, const char* szProto, int iconId);
+void Window_FreeIcon_IcoLib(HWND hWnd);
+
+#define IconLib_ReleaseIcon(hIcon, szName) IcoLib_ReleaseIcon(hIcon, szName, false);
+#define Safe_DestroyIcon(hIcon) if (hIcon) DestroyIcon(hIcon)
+
+/**** clistmenus.c **********************************************************************/
+
+extern HANDLE hMainMenuObject, hContactMenuObject, hStatusMenuObject;
+extern HANDLE hPreBuildMainMenuEvent, hPreBuildContactMenuEvent;
+
+extern const int statusModeList[ MAX_STATUS_COUNT ];
+extern const int skinIconStatusList[ MAX_STATUS_COUNT ];
+extern const int skinIconStatusFlags[ MAX_STATUS_COUNT ];
+
+int TryProcessDoubleClick( HANDLE hContact );
+
+/**** protocols.c ***********************************************************************/
+
+#define OFFSET_PROTOPOS 200
+#define OFFSET_VISIBLE 400
+#define OFFSET_ENABLED 600
+#define OFFSET_NAME 800
+
+extern LIST<PROTOACCOUNT> accounts;
+
+PROTOACCOUNT* __fastcall Proto_GetAccount( const char* accName );
+PROTOACCOUNT* __fastcall Proto_GetAccount( HANDLE hContact );
+PROTOCOLDESCRIPTOR* __fastcall Proto_IsProtocolLoaded( const char* szProtoName );
+
+bool __fastcall Proto_IsAccountEnabled( PROTOACCOUNT* pa );
+bool __fastcall Proto_IsAccountLocked( PROTOACCOUNT* pa );
+
+PROTO_INTERFACE* AddDefaultAccount( const char* szProtoName );
+int FreeDefaultAccount( PROTO_INTERFACE* ppi );
+
+BOOL ActivateAccount( PROTOACCOUNT* pa );
+void EraseAccount( const char* pszProtoName );
+void DeactivateAccount( PROTOACCOUNT* pa, bool bIsDynamic, bool bErase );
+void UnloadAccount( PROTOACCOUNT* pa, bool bIsDynamic, bool bErase );
+void OpenAccountOptions( PROTOACCOUNT* pa );
+
+void LoadDbAccounts( void );
+void WriteDbAccounts( void );
+
+INT_PTR CallProtoServiceInt( HANDLE hContact, const char* szModule, const char* szService, WPARAM, LPARAM );
+INT_PTR CallContactService( HANDLE hContact, const char *szProtoService, WPARAM, LPARAM );
+
+__inline static INT_PTR CallProtoService( const char* szModule, const char* szService, WPARAM wParam, LPARAM lParam )
+{
+ return CallProtoServiceInt( NULL, szModule, szService, wParam, lParam );
+}
+
+/**** utils.c **************************************************************************/
+
+#if defined( _UNICODE )
+ char* __fastcall rtrim(char* str);
+#endif
+TCHAR* __fastcall rtrim(TCHAR* str);
+char* __fastcall ltrim(char* str);
+char* __fastcall ltrimp(char* str);
+__inline char* lrtrim(char* str) { return ltrim(rtrim(str)); };
+__inline char* lrtrimp(char* str) { return ltrimp(rtrim(str)); };
+
+bool __fastcall wildcmp(char * name, char * mask);
+
+void HotkeyToName(TCHAR *buf, int size, BYTE shift, BYTE key);
+WORD GetHotkeyValue( INT_PTR idHotkey );
+
+HBITMAP ConvertIconToBitmap(HICON hIcon, HIMAGELIST hIml, int iconId);
+
+class StrConvUT
+{
+private:
+ wchar_t* m_body;
+
+public:
+ StrConvUT( const char* pSrc ) :
+ m_body( mir_a2u( pSrc )) {}
+
+ ~StrConvUT() { mir_free( m_body ); }
+ operator const wchar_t* () const { return m_body; }
+};
+
+class StrConvAT
+{
+private:
+ char* m_body;
+
+public:
+ StrConvAT( const wchar_t* pSrc ) :
+ m_body( mir_u2a( pSrc )) {}
+
+ ~StrConvAT() { mir_free( m_body ); }
+ operator const char* () const { return m_body; }
+ operator const wchar_t* () const { return ( wchar_t* )m_body; } // type cast to fake the interface definition
+ operator const LPARAM () const { return ( LPARAM )m_body; }
+};
+
+#ifdef _UNICODE
+
+#define StrConvT( x ) StrConvUT( x )
+#define StrConvTu( x ) x
+#define StrConvA( x ) StrConvAT( x )
+#define StrConvU( x ) x
+
+#else
+
+#define StrConvT( x ) x
+#define StrConvTu( x ) StrConvAT( x )
+#define StrConvA( x ) x
+#define StrConvU( x ) StrConvUT( x )
+
+#endif
+
diff --git a/src/core/modules.cpp b/src/core/modules.cpp
new file mode 100644
index 0000000000..c8d173f9a7
--- /dev/null
+++ b/src/core/modules.cpp
@@ -0,0 +1,784 @@
+/*
+
+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_plugins.h>
+
+// list of hooks
+
+static int compareHooks( const THook* p1, const THook* p2 )
+{
+ return strcmp( p1->name, p2->name );
+}
+
+static LIST<THook> hooks( 50, compareHooks );
+
+struct THookToMainThreadItem
+{
+ THook* hook;
+ HANDLE hDoneEvent;
+ WPARAM wParam;
+ LPARAM lParam;
+ int result;
+};
+
+// list of services
+
+struct TService
+{
+ DWORD nameHash;
+ HINSTANCE hOwner;
+ union {
+ MIRANDASERVICE pfnService;
+ MIRANDASERVICEPARAM pfnServiceParam;
+ MIRANDASERVICEOBJ pfnServiceObj;
+ MIRANDASERVICEOBJPARAM pfnServiceObjParam;
+ };
+ int flags;
+ LPARAM lParam;
+ void* object;
+ char name[1];
+};
+
+LIST<TService> services( 100, NumericKeySortT );
+
+typedef struct
+{
+ HANDLE hDoneEvent;
+ WPARAM wParam;
+ LPARAM lParam;
+ int result;
+ const char *name;
+}
+ TServiceToMainThreadItem;
+
+// other static variables
+static BOOL bServiceMode = FALSE;
+static CRITICAL_SECTION csHooks,csServices;
+static DWORD mainThreadId;
+static int hookId = 1;
+static HANDLE hMainThread;
+static HANDLE hMissingService;
+static THook *pLastHook = NULL;
+
+HINSTANCE GetInstByAddress( void* codePtr );
+
+void LangPackDropUnusedItems( void );
+
+void ParseCommandLine(); // core: IDD_WAITRESTART
+int LoadSystemModule(void); // core: m_system.h services
+int LoadNewPluginsModuleInfos(void); // core: preloading plugins
+int LoadNewPluginsModule(void); // core: N.O. plugins
+int LoadSslModule(void);
+int LoadNetlibModule(void); // core: network
+void NetlibInitSsl(void);
+int LoadLangPackModule(void); // core: translation
+int LoadProtocolsModule(void); // core: protocol manager
+int LoadAccountsModule(void); // core: account manager
+int LoadIgnoreModule(void); // protocol filter: ignore
+
+int LoadSendRecvUrlModule(void); //send/recv
+int LoadSendRecvEMailModule(void); //send/recv
+int LoadSendRecvAuthModule(void); //send/recv
+int LoadSendRecvFileModule(void); //send/recv
+
+int LoadContactListModule(void);// ui: clist
+int LoadOptionsModule(void); // ui: options dialog
+int LoadFindAddModule(void); // ui: search/add users
+int LoadSkinIcons(void);
+int LoadSkinSounds(void);
+int LoadSkinHotkeys(void);
+int LoadHelpModule(void); // ui: help stuff
+int LoadUserInfoModule(void); // ui: user info
+int LoadHistoryModule(void); // ui: history viewer
+int LoadAwayMsgModule(void); // ui: setting away messages
+int LoadVisibilityModule(void); // ui: visibility control
+int LoadCLUIModule(void); // ui: CList UI
+int LoadPluginOptionsModule(void); // ui: plugin viewer
+int LoadAddContactModule(void); // ui: authcontrol contacts
+int LoadIdleModule(void); // rnd: report idle information
+int LoadAutoAwayModule(void); // ui: away
+int LoadUserOnlineModule(void); // ui: online alert
+int LoadUtilsModule(void); // ui: utils (has a few window classes, like HyperLink)
+int LoadCLCModule(void); // window class: CLC control
+int LoadButtonModule(void); // window class: button class
+int LoadContactsModule(void); // random: contact
+int LoadFontserviceModule(void); // ui: font manager
+int LoadIcoLibModule(void); // ui: icons manager
+int LoadUpdateNotifyModule(void); // random: update notification
+int LoadServiceModePlugin(void);
+int LoadErrorsModule();
+
+void UnloadUtilsModule(void);
+void UnloadButtonModule(void);
+void UnloadClcModule(void);
+void UnloadContactListModule(void);
+void UnloadEventsModule(void);
+void UnloadIdleModule(void);
+void UnloadLangPackModule(void);
+void UnloadSslModule(void);
+void UnloadNetlibModule(void);
+void UnloadNewPlugins(void);
+void UnloadUpdateNotifyModule(void);
+void UnloadIcoLibModule(void);
+void UnloadSkinSounds(void);
+void UnloadSkinHotkeys(void);
+void UnloadProtocolsModule(void);
+void UnloadAccountsModule(void);
+void UnloadErrorsModule(void);
+
+int LoadIcoTabsModule();
+int LoadHeaderbarModule();
+int LoadDescButtonModule();
+int LoadDefaultModules(void)
+{
+ //load order is very important for these
+ if (LoadSystemModule()) return 1;
+ if (LoadLangPackModule()) return 1; // langpack will be a system module in the new order so this is moved here
+ ParseCommandLine(); // IDD_WAITRESTART need langpack so this is moved here
+ if (LoadUtilsModule()) return 1; //order not important for this, but no dependencies and no point in pluginising
+ if (LoadIcoTabsModule()) return 1;
+ if (LoadHeaderbarModule()) return 1;
+ if (LoadNewPluginsModuleInfos()) return 1;
+
+ // database is available here
+ if (LoadButtonModule()) return 1;
+ if (LoadIcoLibModule()) return 1;
+ if (LoadSkinIcons()) return 1;
+
+// if (LoadErrorsModule()) return 1;
+
+ bServiceMode = LoadServiceModePlugin();
+ switch ( bServiceMode )
+ {
+ case 1: return 0; // stop loading here
+ case 0: break;
+ default: return 1;
+ }
+
+ //this info will be available at LoadNewPluginsModule()
+ INT_PTR *disableDefaultModule=(INT_PTR*)CallService(MS_PLUGINS_GETDISABLEDEFAULTARRAY,0,0);
+
+ if (LoadSkinSounds()) return 1;
+ if (LoadSkinHotkeys()) return 1;
+ if (LoadFontserviceModule()) return 1;
+
+ if (LoadDescButtonModule()) return 1;
+ if (LoadOptionsModule()) return 1;
+ if (LoadNetlibModule()) return 1;
+ if (LoadProtocolsModule()) return 1;
+ LoadDbAccounts(); // retrieves the account array from a database
+ if (LoadContactsModule()) return 1;
+ if (LoadContactListModule()) return 1;
+ if (LoadAddContactModule()) return 1;
+ if (LoadNewPluginsModule()) return 1; // will call Load() on everything, clist will load first
+
+ LangPackDropUnusedItems();
+
+ if (!disableDefaultModule[DEFMOD_SSL]) if (LoadSslModule()) return 1;
+ NetlibInitSsl();
+
+ if (LoadAccountsModule()) return 1;
+
+ //order becomes less important below here
+ if (!disableDefaultModule[DEFMOD_UIFINDADD]) if (LoadFindAddModule()) return 1;
+ if (!disableDefaultModule[DEFMOD_UIUSERINFO]) if (LoadUserInfoModule()) return 1;
+ if (!disableDefaultModule[DEFMOD_SRURL]) if (LoadSendRecvUrlModule()) return 1;
+ if (!disableDefaultModule[DEFMOD_SREMAIL]) if (LoadSendRecvEMailModule()) return 1;
+ if (!disableDefaultModule[DEFMOD_SRAUTH]) if (LoadSendRecvAuthModule()) return 1;
+ if (!disableDefaultModule[DEFMOD_SRFILE]) if (LoadSendRecvFileModule()) return 1;
+ if (!disableDefaultModule[DEFMOD_UIHELP]) if (LoadHelpModule()) return 1;
+ if (!disableDefaultModule[DEFMOD_UIHISTORY]) if (LoadHistoryModule()) return 1;
+ if (!disableDefaultModule[DEFMOD_RNDIDLE]) if (LoadIdleModule()) return 1;
+ if (!disableDefaultModule[DEFMOD_RNDAUTOAWAY]) if (LoadAutoAwayModule()) return 1;
+ if (!disableDefaultModule[DEFMOD_RNDUSERONLINE]) if (LoadUserOnlineModule()) return 1;
+ if (!disableDefaultModule[DEFMOD_SRAWAY]) if (LoadAwayMsgModule()) return 1;
+ if (!disableDefaultModule[DEFMOD_RNDIGNORE]) if (LoadIgnoreModule()) return 1;
+ if (!disableDefaultModule[DEFMOD_UIVISIBILITY]) if (LoadVisibilityModule()) return 1;
+ if (!disableDefaultModule[DEFMOD_UPDATENOTIFY]) if (LoadUpdateNotifyModule()) return 1;
+ return 0;
+}
+
+void UnloadDefaultModules(void)
+{
+ UnloadAccountsModule();
+ UnloadNewPlugins();
+ UnloadProtocolsModule();
+ UnloadSkinSounds();
+ UnloadSkinHotkeys();
+// UnloadErrorsModule();
+ UnloadIcoLibModule();
+ UnloadUtilsModule();
+ UnloadButtonModule();
+ UnloadClcModule();
+ UnloadContactListModule();
+ UnloadEventsModule();
+ UnloadIdleModule();
+ UnloadUpdateNotifyModule();
+ UnloadNetlibModule();
+ UnloadSslModule();
+ UnloadLangPackModule();
+}
+
+int InitialiseModularEngine(void)
+{
+ InitializeCriticalSection(&csHooks);
+ InitializeCriticalSection(&csServices);
+
+ mainThreadId=GetCurrentThreadId();
+ DuplicateHandle(GetCurrentProcess(),GetCurrentThread(),GetCurrentProcess(),&hMainThread,0,FALSE,DUPLICATE_SAME_ACCESS);
+
+ hMissingService = CreateHookableEvent(ME_SYSTEM_MISSINGSERVICE);
+ return 0;
+}
+
+void DestroyModularEngine(void)
+{
+ int i;
+ THook* p;
+ EnterCriticalSection( &csHooks );
+ for( i=0; i < hooks.getCount(); i++ ) {
+ p = hooks[i];
+ if ( p->subscriberCount )
+ mir_free( p->subscriber );
+ DeleteCriticalSection( &p->csHook );
+ mir_free( p );
+ }
+ hooks.destroy();
+ LeaveCriticalSection( &csHooks );
+ DeleteCriticalSection( &csHooks );
+
+ EnterCriticalSection( &csServices );
+ for ( i=0; i < services.getCount(); i++ )
+ mir_free( services[i] );
+
+ services.destroy();
+ LeaveCriticalSection( &csServices );
+ DeleteCriticalSection( &csServices );
+ CloseHandle( hMainThread );
+}
+
+///////////////////////////////HOOKS
+
+HANDLE CreateHookableEvent(const char *name)
+{
+ THook* ret;
+ int idx;
+
+ if ( name == NULL )
+ return NULL;
+
+ EnterCriticalSection( &csHooks );
+ if (( idx = hooks.getIndex(( THook* )name )) != -1 ) {
+ LeaveCriticalSection( &csHooks );
+ return NULL;
+ }
+
+ ret = ( THook* )mir_alloc( sizeof( THook ));
+ strncpy( ret->name, name, sizeof( ret->name )); ret->name[ MAXMODULELABELLENGTH-1 ] = 0;
+ ret->id = hookId++;
+ ret->subscriberCount = 0;
+ ret->subscriber = NULL;
+ ret->pfnHook = NULL;
+ InitializeCriticalSection( &ret->csHook );
+ hooks.insert( ret );
+
+ LeaveCriticalSection( &csHooks );
+ return ( HANDLE )ret;
+}
+
+int DestroyHookableEvent( HANDLE hEvent )
+{
+ int idx;
+ THook* p;
+
+ EnterCriticalSection( &csHooks );
+ if ( pLastHook == ( THook* )hEvent )
+ pLastHook = NULL;
+
+ if (( idx = hooks.getIndex(( THook* )hEvent )) == -1 ) {
+ LeaveCriticalSection(&csHooks);
+ return 1;
+ }
+ p = hooks[idx];
+ if ( p->subscriberCount ) {
+ mir_free( p->subscriber );
+ p->subscriber = NULL;
+ p->subscriberCount = 0;
+ }
+ hooks.remove( idx );
+ DeleteCriticalSection( &p->csHook );
+ mir_free( p );
+
+ LeaveCriticalSection( &csHooks );
+ return 0;
+}
+
+int SetHookDefaultForHookableEvent(HANDLE hEvent, MIRANDAHOOK pfnHook)
+{
+ THook* p = ( THook* )hEvent;
+
+ EnterCriticalSection(&csHooks);
+ if ( hooks.getIndex( p ) != -1 )
+ p->pfnHook = pfnHook;
+ LeaveCriticalSection(&csHooks);
+ return 0;
+}
+
+int CallHookSubscribers( HANDLE hEvent, WPARAM wParam, LPARAM lParam )
+{
+ int i, returnVal = 0;
+ THook* p = ( THook* )hEvent;
+ if ( p == NULL )
+ return -1;
+
+ EnterCriticalSection( &p->csHook );
+
+ // NOTE: We've got the critical section while all this lot are called. That's mostly safe, though.
+ for ( i = 0; i < p->subscriberCount; i++ ) {
+ THookSubscriber* s = &p->subscriber[i];
+ switch ( s->type ) {
+ case 1: returnVal = s->pfnHook( wParam, lParam ); break;
+ case 2: returnVal = s->pfnHookParam( wParam, lParam, s->lParam ); break;
+ case 3: returnVal = s->pfnHookObj( s->object, wParam, lParam ); break;
+ case 4: returnVal = s->pfnHookObjParam( s->object, wParam, lParam, s->lParam ); break;
+ case 5: returnVal = SendMessage( s->hwnd, s->message, wParam, lParam ); break;
+ default: continue;
+ }
+ if ( returnVal )
+ break;
+ }
+
+ // check for no hooks and call the default hook if any
+ if ( p->subscriberCount == 0 && p->pfnHook != 0 )
+ returnVal = p->pfnHook( wParam, lParam );
+
+ LeaveCriticalSection( &p->csHook );
+ return returnVal;
+}
+
+static int checkHook( HANDLE hHook )
+{
+ if ( hHook == NULL )
+ return -1;
+
+ EnterCriticalSection( &csHooks );
+ if ( pLastHook != hHook || !pLastHook ) {
+ if ( hooks.getIndex(( THook* )hHook ) == -1 ) {
+ LeaveCriticalSection( &csHooks );
+ return -1;
+ }
+ pLastHook = ( THook* )hHook;
+ }
+ LeaveCriticalSection( &csHooks );
+ return 0;
+}
+
+static void CALLBACK HookToMainAPCFunc(ULONG_PTR dwParam)
+{
+ THookToMainThreadItem* item = ( THookToMainThreadItem* )dwParam;
+
+ if ( checkHook( item->hook ) == -1 )
+ item->result = -1;
+ else
+ item->result = CallHookSubscribers( item->hook, item->wParam, item->lParam );
+ SetEvent( item->hDoneEvent );
+}
+
+int NotifyEventHooks( HANDLE hEvent, WPARAM wParam, LPARAM lParam )
+{
+ extern HWND hAPCWindow;
+
+ if ( GetCurrentThreadId() != mainThreadId ) {
+ THookToMainThreadItem item;
+
+ item.hDoneEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
+ item.hook = ( THook* )hEvent;
+ item.wParam = wParam;
+ item.lParam = lParam;
+
+ QueueUserAPC( HookToMainAPCFunc, hMainThread, ( ULONG_PTR )&item );
+ PostMessage( hAPCWindow, WM_NULL, 0, 0 ); // let it process APC even if we're in a common dialog
+ WaitForSingleObject( item.hDoneEvent, INFINITE );
+ CloseHandle( item.hDoneEvent );
+ return item.result;
+ }
+
+ return ( checkHook( hEvent ) == -1 ) ? -1 : CallHookSubscribers( hEvent, wParam, lParam );
+}
+
+static HANDLE HookEventInt( int type, const char* name, MIRANDAHOOK hookProc, void* object, LPARAM lParam )
+{
+ int idx;
+ THook* p;
+ HANDLE ret;
+
+ EnterCriticalSection( &csHooks );
+ if (( idx = hooks.getIndex(( THook* )name )) == -1 ) {
+ #ifdef _DEBUG
+ OutputDebugStringA("Attempt to hook: \t");
+ OutputDebugStringA(name);
+ OutputDebugStringA("\n");
+ #endif
+ LeaveCriticalSection(&csHooks);
+ return NULL;
+ }
+
+ p = hooks[ idx ];
+ p->subscriber = ( THookSubscriber* )mir_realloc( p->subscriber, sizeof( THookSubscriber )*( p->subscriberCount+1 ));
+ p->subscriber[ p->subscriberCount ].type = type;
+ p->subscriber[ p->subscriberCount ].pfnHook = hookProc;
+ p->subscriber[ p->subscriberCount ].object = object;
+ p->subscriber[ p->subscriberCount ].lParam = lParam;
+ p->subscriber[ p->subscriberCount ].hOwner = GetInstByAddress( hookProc );
+ p->subscriberCount++;
+
+ ret = ( HANDLE )(( p->id << 16 ) | p->subscriberCount );
+ LeaveCriticalSection( &csHooks );
+ return ret;
+}
+
+HANDLE HookEvent( const char* name, MIRANDAHOOK hookProc )
+{
+ return HookEventInt( 1, name, hookProc, 0, 0 );
+}
+
+HANDLE HookEventParam( const char* name, MIRANDAHOOKPARAM hookProc, LPARAM lParam )
+{
+ return HookEventInt( 2, name, (MIRANDAHOOK)hookProc, 0, lParam );
+}
+
+HANDLE HookEventObj( const char* name, MIRANDAHOOKOBJ hookProc, void* object)
+{
+ return HookEventInt( 3, name, (MIRANDAHOOK)hookProc, object, 0 );
+}
+
+HANDLE HookEventObjParam( const char* name, MIRANDAHOOKOBJPARAM hookProc, void* object, LPARAM lParam )
+{
+ return HookEventInt( 4, name, (MIRANDAHOOK)hookProc, object, lParam );
+}
+
+HANDLE HookEventMessage( const char* name, HWND hwnd, UINT message )
+{
+ int idx;
+ THook* p;
+ HANDLE ret;
+
+ EnterCriticalSection( &csHooks );
+ if (( idx = hooks.getIndex(( THook* )name )) == -1 ) {
+ #ifdef _DEBUG
+ MessageBoxA(NULL,"Attempt to hook non-existant event",name,MB_OK);
+ #endif
+ LeaveCriticalSection(&csHooks);
+ return NULL;
+ }
+
+ p = hooks[ idx ];
+ p->subscriber = ( THookSubscriber* )mir_realloc( p->subscriber, sizeof( THookSubscriber )*( p->subscriberCount+1 ));
+ p->subscriber[ p->subscriberCount ].type = 5;
+ p->subscriber[ p->subscriberCount ].hwnd = hwnd;
+ p->subscriber[ p->subscriberCount ].message = message;
+ p->subscriberCount++;
+
+ ret = ( HANDLE )(( p->id << 16 ) | p->subscriberCount );
+ LeaveCriticalSection( &csHooks );
+ return ret;
+}
+
+int UnhookEvent( HANDLE hHook )
+{
+ int i;
+ THook* p = NULL;
+
+ int hookId = ( int )hHook >> 16;
+ int subscriberId = (( int )hHook & 0xFFFF ) - 1;
+
+ if (hHook == NULL) return 0;
+
+ EnterCriticalSection( &csHooks );
+ for ( i = 0; i < hooks.getCount(); i++ ) {
+ if ( hooks[i]->id == hookId ) {
+ p = hooks[i];
+ break;
+ } }
+
+ if ( p == NULL ) {
+ LeaveCriticalSection( &csHooks );
+ return 1;
+ }
+
+ if ( subscriberId >= p->subscriberCount || subscriberId < 0 ) {
+ LeaveCriticalSection( &csHooks );
+ return 1;
+ }
+
+ p->subscriber[subscriberId].type = 0;
+ p->subscriber[subscriberId].pfnHook = NULL;
+ p->subscriber[subscriberId].hOwner = NULL;
+ while( p->subscriberCount && p->subscriber[p->subscriberCount-1].type == 0 )
+ p->subscriberCount--;
+ if ( p->subscriberCount == 0 ) {
+ if ( p->subscriber ) mir_free( p->subscriber );
+ p->subscriber = NULL;
+ }
+ LeaveCriticalSection( &csHooks );
+ return 0;
+}
+
+void KillModuleEventHooks( HINSTANCE hInst )
+{
+ int i, j;
+
+ EnterCriticalSection(&csHooks);
+ for ( i = hooks.getCount()-1; i >= 0; i-- ) {
+ if ( hooks[i]->subscriberCount == 0 )
+ continue;
+
+ for ( j = hooks[i]->subscriberCount-1; j >= 0; j-- ) {
+ if ( hooks[i]->subscriber[j].hOwner == hInst ) {
+ char szModuleName[ MAX_PATH ];
+ GetModuleFileNameA( hooks[i]->subscriber[j].hOwner, szModuleName, sizeof(szModuleName));
+ Netlib_Logf( NULL, "A hook %08x for event '%s' was abnormally deleted because module '%s' didn't released it",
+ hooks[i]->subscriber[j].pfnHook, hooks[i]->name, szModuleName );
+ UnhookEvent(( HANDLE )(( hooks[i]->id << 16 ) + j + 1 ));
+ if ( hooks[i]->subscriberCount == 0 )
+ break;
+ } } }
+
+ LeaveCriticalSection(&csHooks);
+}
+
+void KillObjectEventHooks( void* pObject )
+{
+ int i, j;
+
+ EnterCriticalSection(&csHooks);
+ for ( i = hooks.getCount()-1; i >= 0; i-- ) {
+ if ( hooks[i]->subscriberCount == 0 )
+ continue;
+
+ for ( j = hooks[i]->subscriberCount-1; j >= 0; j-- ) {
+ if ( hooks[i]->subscriber[j].object == pObject ) {
+ UnhookEvent(( HANDLE )(( hooks[i]->id << 16 ) + j + 1 ));
+ if ( hooks[i]->subscriberCount == 0 )
+ break;
+ } } }
+
+ LeaveCriticalSection(&csHooks);
+}
+
+/////////////////////SERVICES
+
+static __inline TService* FindServiceByName( const char *name )
+{
+ unsigned hash = hashstr( name );
+ return services.find(( TService* )&hash );
+}
+
+static HANDLE CreateServiceInt( int type, const char *name, MIRANDASERVICE serviceProc, void* object, LPARAM lParam)
+{
+ if ( name == NULL ) {
+#ifdef _DEBUG
+ MessageBoxA(0,"Someone tried to create a NULL'd service, see call stack for more info","",0);
+ DebugBreak();
+#endif
+ return NULL;
+ }
+
+ TService tmp;
+ tmp.nameHash = hashstr( name );
+
+ EnterCriticalSection( &csServices );
+
+ if ( services.getIndex( &tmp ) != -1 ) {
+ LeaveCriticalSection( &csServices );
+ return NULL;
+ }
+
+ TService* p = ( TService* )mir_alloc( sizeof( *p ) + strlen( name ));
+ strcpy( p->name, name );
+ p->nameHash = tmp.nameHash;
+ p->pfnService = serviceProc;
+ p->hOwner = GetInstByAddress( serviceProc );
+ p->flags = type;
+ p->lParam = lParam;
+ p->object = object;
+ services.insert( p );
+
+ LeaveCriticalSection( &csServices );
+ return ( HANDLE )tmp.nameHash;
+}
+
+HANDLE CreateServiceFunction( const char *name, MIRANDASERVICE serviceProc )
+{
+ return CreateServiceInt( 0, name, serviceProc, 0, 0 );
+}
+
+HANDLE CreateServiceFunctionParam(const char *name,MIRANDASERVICEPARAM serviceProc,LPARAM lParam)
+{
+ return CreateServiceInt( 1, name, (MIRANDASERVICE)serviceProc, 0, lParam );
+}
+
+HANDLE CreateServiceFunctionObj(const char *name,MIRANDASERVICEOBJ serviceProc,void* object)
+{
+ return CreateServiceInt( 2, name, (MIRANDASERVICE)serviceProc, object, 0 );
+}
+
+HANDLE CreateServiceFunctionObjParam(const char *name,MIRANDASERVICEOBJPARAM serviceProc,void* object,LPARAM lParam)
+{
+ return CreateServiceInt( 3, name, (MIRANDASERVICE)serviceProc, object, lParam );
+}
+
+int DestroyServiceFunction(HANDLE hService)
+{
+ int idx;
+
+ EnterCriticalSection( &csServices );
+ if (( idx = services.getIndex(( TService* )&hService )) != -1 ) {
+ mir_free( services[idx] );
+ services.remove( idx );
+ }
+
+ LeaveCriticalSection(&csServices);
+ return 0;
+}
+
+int ServiceExists(const char *name)
+{
+ if ( name == NULL )
+ return FALSE;
+
+ EnterCriticalSection( &csServices );
+ int ret = FindServiceByName( name ) != NULL;
+ LeaveCriticalSection( &csServices );
+ return ret;
+}
+
+INT_PTR CallService(const char *name,WPARAM wParam,LPARAM lParam)
+{
+ #ifdef _DEBUG
+ if (name==NULL) {
+ MessageBoxA(0,"Someone tried to CallService(NULL,..) see stack trace for details","",0);
+ DebugBreak();
+ return CALLSERVICE_NOTFOUND;
+ }
+ #else
+ if (name==NULL) return CALLSERVICE_NOTFOUND;
+ #endif
+
+ EnterCriticalSection(&csServices);
+ TService *pService = FindServiceByName(name);
+ if (pService==NULL) {
+ LeaveCriticalSection(&csServices);
+ #ifdef _DEBUG
+ //MessageBoxA(NULL,"Attempt to call non-existant service",name,MB_OK);
+ OutputDebugStringA("Missing service called: \t");
+ OutputDebugStringA(name);
+ OutputDebugStringA("\n");
+ #endif
+/* { MISSING_SERVICE_PARAMS params = { name, wParam, lParam };
+ int result = NotifyEventHooks(hMissingService,0,(LPARAM)&params);
+ if (result != 0)
+ return params.lParam;
+ } */
+ return CALLSERVICE_NOTFOUND;
+ }
+
+ MIRANDASERVICE pfnService = pService->pfnService;
+ int flags = pService->flags;
+ LPARAM fnParam = pService->lParam;
+ void* object = pService->object;
+ LeaveCriticalSection(&csServices);
+ switch( flags ) {
+ case 1: return ((MIRANDASERVICEPARAM)pfnService)(wParam,lParam,fnParam);
+ case 2: return ((MIRANDASERVICEOBJ)pfnService)(object,wParam,lParam);
+ case 3: return ((MIRANDASERVICEOBJPARAM)pfnService)(object,wParam,lParam,fnParam);
+ default: return pfnService(wParam,lParam);
+} }
+
+static void CALLBACK CallServiceToMainAPCFunc(ULONG_PTR dwParam)
+{
+ TServiceToMainThreadItem *item = (TServiceToMainThreadItem*) dwParam;
+ item->result = CallService(item->name, item->wParam, item->lParam);
+ SetEvent(item->hDoneEvent);
+}
+
+INT_PTR CallServiceSync(const char *name, WPARAM wParam, LPARAM lParam)
+{
+ extern HWND hAPCWindow;
+
+ if (name==NULL) return CALLSERVICE_NOTFOUND;
+ // the service is looked up within the main thread, since the time it takes
+ // for the APC queue to clear the service being called maybe removed.
+ // even thou it may exists before the call, the critsec can't be locked between calls.
+ if (GetCurrentThreadId() != mainThreadId) {
+ TServiceToMainThreadItem item;
+ item.wParam = wParam;
+ item.lParam = lParam;
+ item.name = name;
+ item.hDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ QueueUserAPC(CallServiceToMainAPCFunc, hMainThread, (ULONG_PTR) &item);
+ PostMessage(hAPCWindow,WM_NULL,0,0); // let this get processed in its own time
+ WaitForSingleObject(item.hDoneEvent, INFINITE);
+ CloseHandle(item.hDoneEvent);
+ return item.result;
+ }
+
+ return CallService(name, wParam, lParam);
+}
+
+int CallFunctionAsync( void (__stdcall *func)(void *), void *arg)
+{
+ extern HWND hAPCWindow;
+ int r = QueueUserAPC(( void (__stdcall *)( ULONG_PTR ))func, hMainThread, ( ULONG_PTR )arg );
+ PostMessage(hAPCWindow,WM_NULL,0,0);
+ return r;
+}
+
+void KillModuleServices( HINSTANCE hInst )
+{
+ int i;
+
+ EnterCriticalSection(&csServices);
+ for ( i = services.getCount()-1; i >= 0; i-- ) {
+ if ( services[i]->hOwner == hInst ) {
+ char szModuleName[ MAX_PATH ];
+ GetModuleFileNameA( services[i]->hOwner, szModuleName, sizeof(szModuleName));
+ Netlib_Logf( NULL, "A service function '%s' was abnormally deleted because module '%s' didn't released it",
+ services[i]->name, szModuleName );
+ DestroyServiceFunction(( HANDLE )services[i]->nameHash );
+ } }
+
+ LeaveCriticalSection(&csServices);
+}
+
+void KillObjectServices( void* pObject )
+{
+ int i;
+
+ EnterCriticalSection(&csServices);
+ for ( i = services.getCount()-1; i >= 0; i-- )
+ if ( services[i]->object == pObject )
+ DestroyServiceFunction(( HANDLE )services[i]->nameHash );
+
+ LeaveCriticalSection(&csServices);
+}
diff --git a/src/core/modules.h b/src/core/modules.h
new file mode 100644
index 0000000000..f40fc885e6
--- /dev/null
+++ b/src/core/modules.h
@@ -0,0 +1,268 @@
+/*
+
+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.
+*/
+//Modules Core - Richard
+#ifndef MODULES_H_
+#define MODULES_H_
+
+#ifdef _MSC_VER
+ #pragma warning(disable:4201)
+#endif
+
+/* MAXMODULELABELLENGTH
+The maximum allowed length of a 'name' parameter. Very likely to change with
+restructuring modules.c for performance.
+*/
+#define MAXMODULELABELLENGTH 64
+
+typedef int (*MIRANDAHOOK)(WPARAM,LPARAM);
+typedef int (*MIRANDAHOOKPARAM)(WPARAM,LPARAM,LPARAM);
+typedef int (*MIRANDAHOOKOBJ)(void*,WPARAM,LPARAM);
+typedef int (*MIRANDAHOOKOBJPARAM)(void*,WPARAM,LPARAM,LPARAM);
+
+typedef INT_PTR (*MIRANDASERVICE)(WPARAM,LPARAM);
+typedef INT_PTR (*MIRANDASERVICEPARAM)(WPARAM,LPARAM,LPARAM);
+typedef INT_PTR (*MIRANDASERVICEOBJ)(void*,LPARAM,LPARAM);
+typedef INT_PTR (*MIRANDASERVICEOBJPARAM)(void*,WPARAM,LPARAM,LPARAM);
+
+typedef struct
+{
+ HINSTANCE hOwner;
+ int type;
+ union {
+ struct {
+ union {
+ MIRANDAHOOK pfnHook;
+ MIRANDAHOOKPARAM pfnHookParam;
+ MIRANDAHOOKOBJ pfnHookObj;
+ MIRANDAHOOKOBJPARAM pfnHookObjParam;
+ };
+ void* object;
+ LPARAM lParam;
+ };
+ struct {
+ HWND hwnd;
+ UINT message;
+ };
+ };
+}
+ THookSubscriber;
+
+typedef struct
+{
+ char name[ MAXMODULELABELLENGTH ];
+ int id;
+ int subscriberCount;
+ THookSubscriber* subscriber;
+ MIRANDAHOOK pfnHook;
+ CRITICAL_SECTION csHook;
+}
+ THook;
+
+/**************************hook functions****************************/
+/* CreateHookableEvent
+Adds an named event to the list and returns a handle referring to it, or NULL
+on failure. Will be automatically destroyed on exit, or can be removed from the
+list earlier using DestroyHookableEvent()
+Will fail if the given name has already been used
+*/
+HANDLE CreateHookableEvent(const char *name);
+
+/* DestroyHookableEvent
+Removes the event hEvent from the list of events. All modules hooked to it are
+automatically unhooked. NotifyEventHooks() will fail if called with this hEvent
+again. hEvent must have been returned by CreateHookableEvent()
+Returns 0 on success, or nonzero if hEvent is invalid
+*/
+int DestroyHookableEvent(HANDLE hEvent);
+
+/* NotifyEventHooks
+Calls every module in turn that has hooked hEvent, using the parameters wParam
+and lParam. hEvent must have been returned by CreateHookableEvent()
+Returns 0 on success
+ -1 if hEvent is invalid
+ If one of the hooks returned nonzero to indicate abort, returns that abort
+ value immediately, without calling the rest of the hooks in the chain
+
+Notes on calling NotifyEventHooks() from a thread other than that which owns
+the main Miranda window:
+It works. The call is routed to the main thread and all hook subcribers are
+called in the context of the main thread. The thread which called
+NotifyHookEvents() is paused until all the processing is complete at which
+point it returns with the correct return value.
+This procedure requires more than one wait object so naturally there are
+possibilities for deadlocks, but not many.
+Calling NotifyEventHooks() from other than the main thread will be
+considerably slower than from the main thread, but will consume only slightly
+more actual CPU time, the rest will mostly be spent waiting for the main thread
+to return to the message loop so it can be interrupted neatly.
+*/
+int NotifyEventHooks(HANDLE hEvent,WPARAM wParam,LPARAM lParam);
+
+/* CallHookSubscribers
+Works precisely like NotifyEventHooks, but without switching to the first thread
+It guarantees that the execution time for these events is always tiny
+*/
+
+int CallHookSubscribers( HANDLE hEvent, WPARAM wParam, LPARAM lParam );
+
+/*
+ hEvent : a HANDLE which has been returned by CreateHookableEvent()
+ pfnHook: a function pointer (MIRANDAHOOK) which is called when there are no hooks.
+ Affect: This core service allows hooks to have a 'default' hook which is called
+ when no one has hooked the given event, this allows hook creators to add default
+ processing which is ONLY CALLED when no one else has HookEvent()'d
+ Notes: The return value from pfnHook() is returned to NotifyEventHooks()
+ Returns: 0 on success, non zero on failure
+ Version: 0.3.4+ (2004/09/15)
+*/
+int SetHookDefaultForHookableEvent(HANDLE hEvent, MIRANDAHOOK pfnHook);
+
+/* HookEvent
+Adds a new hook to the chain 'name', to be called when the hook owner calls
+NotifyEventHooks(). Returns NULL if name is not a valid event or a handle
+referring to the hook otherwise. Note that debug builds will warn with a
+MessageBoxA if a hook is attempted on an unknown event. All hooks will be
+automatically destroyed when their parent event is destroyed or the programme
+ends, but can be unhooked earlier using UnhookEvent(). hookProc() is defined as
+ int HookProc(WPARAM wParam,LPARAM lParam)
+where you can substitute your own name for HookProc. wParam and lParam are
+defined by the creator of the event when NotifyEventHooks() is called.
+The return value is 0 to continue processing the other hooks, or nonzero
+to stop immediately. This abort value is returned to the caller of
+NotifyEventHooks() and should not be -1 since that is a special return code
+for NotifyEventHooks() (see above)
+*/
+HANDLE HookEvent(const char *name,MIRANDAHOOK hookProc);
+HANDLE HookEventParam(const char *name, MIRANDAHOOKPARAM hookProc, LPARAM lParam);
+HANDLE HookEventObj(const char *name,MIRANDAHOOKOBJ hookProc, void* object);
+HANDLE HookEventObjParam(const char *name, MIRANDAHOOKOBJPARAM hookProc, void* object, LPARAM lParam);
+
+/* HookEventMessage
+Works as for HookEvent(), except that when the notifier is called a message is
+sent to a window, rather than a function being called.
+Note that SendMessage() is a decidedly slow function so please limit use of
+this function to events that are not called frequently, or to hooks that are
+only installed briefly
+The window procedure is called with the message 'message' and the wParam and
+lParam given to NotifyEventHooks(). The return value of SendMessage() is used
+in the same way as the return value in HookEvent().
+*/
+HANDLE HookEventMessage(const char *name,HWND hwnd,UINT message);
+
+/* UnhookEvent
+Removes a hook from its event chain. It will no longer receive any events.
+hHook must have been returned by HookEvent() or HookEventMessage().
+Returns 0 on success or nonzero if hHook is invalid.
+*/
+int UnhookEvent(HANDLE hHook);
+
+
+/*************************service functions**************************/
+/* CreateServiceFunction
+Adds a new service function called 'name' to the global list and returns a
+handle referring to it. Service function handles are destroyed automatically
+on exit, but can be removed from the list earlier using
+DestroyServiceFunction()
+Returns NULL if name has already been used. serviceProc is defined by the
+caller as
+ int ServiceProc(WPARAM wParam,LPARAM lParam)
+where the creator publishes the meanings of wParam, lParam and the return value
+Service functions must not return CALLSERVICE_NOTFOUND since that would confuse
+callers of CallService().
+*/
+HANDLE CreateServiceFunction(const char *name,MIRANDASERVICE serviceProc);
+
+/* CreateServiceFunctionParam
+Same as CreateServiceFunction - adds new parameter, to pass to service handler function.
+serviceProc is defined by the caller as
+ int ServiceProc(WPARAM wParam,LPARAM lParam,LPARAM fnParam)
+where fnParam does not need to be publicly known. Gives the ability to handle multiple services
+with the same function.
+
+added during 0.7+ (2007/04/24)
+*/
+HANDLE CreateServiceFunctionParam(const char *name,MIRANDASERVICEPARAM serviceProc,LPARAM lParam);
+
+/* CreateServiceFunctionObj
+ CreateServiceFunctionObjParam
+Same as CreateServiceFunction - adds new parameter, an object, to pass to service handler function.
+serviceProc is defined by the caller as
+ int ServiceProc(void* object, WPARAM wParam,LPARAM lParam[,LPARAM fnParam])
+where fnParam does not need to be publicly known. Gives the ability to handle multiple services
+with the same function.
+
+added during 0.7+ (2007/04/24)
+*/
+
+HANDLE CreateServiceFunctionObj(const char *name,MIRANDASERVICEOBJ serviceProc,void* object);
+HANDLE CreateServiceFunctionObjParam(const char *name,MIRANDASERVICEOBJPARAM serviceProc,void* object,LPARAM lParam);
+
+/* DestroyServiceFunction
+Removes the function associated with hService from the global service function
+list. Modules calling CallService() will fail if they try to call this
+service's name. hService must have been returned by CreateServiceFunction().
+Returns 0 on success or non-zero if hService is invalid.
+*/
+int DestroyServiceFunction(HANDLE hService);
+
+/* CallService
+Finds and calls the service function 'name' using the parameters wParam and
+lParam.
+Returns CALLSERVICE_NOTFOUND if no service function called 'name' has been
+created, or the value the service function returned otherwise.
+*/
+#ifdef _WIN64
+ #define CALLSERVICE_NOTFOUND ((INT_PTR)0x8000000000000000)
+#else
+ #define CALLSERVICE_NOTFOUND ((int)0x80000000)
+#endif
+INT_PTR CallService(const char *name,WPARAM wParam,LPARAM lParam);
+
+/* ServiceExists
+Finds if a service with the given name exists
+Returns nonzero if the service was found, and zero if it was not
+*/
+int ServiceExists(const char *name);
+
+/* CallServiceSync
+Calls a given service executed within the context of the main thread
+only useful to multi threaded modules calling thread unsafe services!
+*/
+INT_PTR CallServiceSync(const char *name, WPARAM wParam, LPARAM lParam);
+
+/* CallFunctionAsync
+Calls a given function pointer, it doesn't go thru the core at all, it is
+just a wrapper around QueueUserAPC() and other workarounds to make APC
+work even if there are non APC message loops, this allows plugins who
+need this feature to get it without recoding it themselves.
+
+The function 'func' will always be called from the main thread in idle time even
+if it is invokved from a worker thread, 'arg' must not be on the stack.
+
+Returns nonzero on success, zero on failure
+
+added during 0.3.4+ (2004/08/14)
+*/
+int CallFunctionAsync( void (__stdcall *func)(void *), void *arg);
+
+#endif // MODULES_H_
diff --git a/src/manifest.rc b/src/manifest.rc
new file mode 100644
index 0000000000..d23fb3f71e
--- /dev/null
+++ b/src/manifest.rc
@@ -0,0 +1,8 @@
+/////////////////////////////////////////////////////////////////////////////
+//
+// RT_MANIFEST
+//
+
+#include <winres.h>
+
+1 RT_MANIFEST "miranda32.exe.manifest"
diff --git a/src/miranda32.def b/src/miranda32.def
new file mode 100644
index 0000000000..2148d20b8e
--- /dev/null
+++ b/src/miranda32.def
@@ -0,0 +1,7 @@
+EXPORTS
+
+AccMgrDlgProc @1
+IdleOptsDlgProc @2
+DlgProcAwayMsgOpts @3
+DlgPluginOpt @4
+DlgProcIgnoreOpts @5
diff --git a/src/miranda32.dep b/src/miranda32.dep
new file mode 100644
index 0000000000..097d08f0f6
--- /dev/null
+++ b/src/miranda32.dep
@@ -0,0 +1,857 @@
+# Microsoft Developer Studio Generated Dependency File, included by miranda32.mak
+
+.\core\commonheaders.cpp : \
+ "..\include\m_addcontact.h"\
+ "..\include\m_awaymsg.h"\
+ "..\include\m_button.h"\
+ "..\include\m_clc.h"\
+ "..\include\m_clist.h"\
+ "..\include\m_clistint.h"\
+ "..\include\m_clui.h"\
+ "..\include\m_contacts.h"\
+ "..\include\m_database.h"\
+ "..\include\m_email.h"\
+ "..\include\m_file.h"\
+ "..\include\m_findadd.h"\
+ "..\include\m_genmenu.h"\
+ "..\include\m_help.h"\
+ "..\include\m_history.h"\
+ "..\include\m_icolib.h"\
+ "..\include\m_idle.h"\
+ "..\include\m_ignore.h"\
+ "..\include\m_langpack.h"\
+ "..\include\m_message.h"\
+ "..\include\m_modernopt.h"\
+ "..\include\m_netlib.h"\
+ "..\include\m_options.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protocols.h"\
+ "..\include\m_protoint.h"\
+ "..\include\m_protomod.h"\
+ "..\include\m_protosvc.h"\
+ "..\include\m_skin.h"\
+ "..\include\m_ssl.h"\
+ "..\include\m_stdhdr.h"\
+ "..\include\m_system.h"\
+ "..\include\m_system_cpp.h"\
+ "..\include\m_timezones.h"\
+ "..\include\m_userinfo.h"\
+ "..\include\m_utils.h"\
+ "..\include\m_xml.h"\
+ "..\include\msapi\vsstyle.h"\
+ "..\include\msapi\vssym32.h"\
+ "..\include\newpluginapi.h"\
+ "..\include\statusmodes.h"\
+ "..\include\win2k.h"\
+ ".\core\commonheaders.h"\
+ ".\core\forkthread.h"\
+ ".\core\miranda.h"\
+ ".\core\modules.h"\
+ ".\modules\database\dblists.h"\
+
+
+.\core\memory.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\core\miranda.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\core\modules.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\addcontact\addcontact.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\autoaway\autoaway.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\button\button.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\contacts\contacts.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\database\database.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\database\profilemanager.h"\
+ ".\modules\srfile\file.h"\
+
+
+.\modules\database\dbini.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\srfile\file.h"\
+
+
+.\modules\database\dblists.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\database\dbutils.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\database\profilemanager.h"\
+
+
+.\modules\database\profilemanager.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\database\profilemanager.h"\
+
+
+.\modules\findadd\findadd.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\findadd\findadd.h"\
+
+
+.\modules\findadd\searchresults.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\findadd\findadd.h"\
+
+
+.\modules\help\about.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\help\help.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\history\history.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\idle\idle.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\ignore\ignore.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\langpack\langpack.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\langpack\lpservices.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\netlib\netlib.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\netlib\netlib.h"\
+
+
+.\modules\netlib\netlibautoproxy.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\netlib\netlib.h"\
+
+
+.\modules\netlib\netlibbind.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\netlib\netlib.h"\
+
+
+.\modules\netlib\netlibhttp.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ "..\plugins\zlib\zconf.h"\
+ "..\plugins\zlib\zlib.h"\
+ ".\modules\netlib\netlib.h"\
+
+
+.\modules\netlib\netlibhttpproxy.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\netlib\netlib.h"\
+
+
+.\modules\netlib\netliblog.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\netlib\netlib.h"\
+ ".\modules\srfile\file.h"\
+
+
+.\modules\netlib\netlibopenconn.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\netlib\netlib.h"\
+
+
+.\modules\netlib\netlibopts.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\netlib\netlib.h"\
+
+
+.\modules\netlib\netlibpktrecver.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\netlib\netlib.h"\
+
+
+.\modules\netlib\netlibsecurity.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\netlib\netlib.h"\
+
+
+.\modules\netlib\netlibsock.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\netlib\netlib.h"\
+
+
+.\modules\netlib\netlibssl.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\netlib\netlib.h"\
+
+
+.\modules\netlib\netlibupnp.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\netlib\netlib.h"\
+
+
+.\modules\options\descbutton.cpp : \
+ "..\include\m_descbutton.h"\
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\options\filter.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\options\headerbar.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_iconheader.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\options\iconheader.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_iconheader.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\options\options.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\plugins\newplugins.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\protocols\protoaccs.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\clist\clc.h"\
+
+
+.\modules\protocols\protochains.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\protocols\protocols.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\protocols\protoint.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\protocols\protoopts.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\skin\hotkeys.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_hotkeys.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\skin\skinicons.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\skin\sounds.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\srauth\auth.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\srauth\authdialogs.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\srawaymsg\awaymsg.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\srawaymsg\sendmsg.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\sremail\email.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\srfile\file.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\srfile\file.h"\
+
+
+.\modules\srfile\fileexistsdlg.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\srfile\file.h"\
+
+
+.\modules\srfile\fileopts.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\srfile\file.h"\
+
+
+.\modules\srfile\filerecvdlg.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\srfile\file.h"\
+
+
+.\modules\srfile\filesenddlg.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\srfile\file.h"\
+
+
+.\modules\srfile\filexferdlg.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\srfile\file.h"\
+
+
+.\modules\srfile\ftmanager.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\srfile\file.h"\
+
+
+.\modules\srurl\url.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ "..\include\m_url.h"\
+ ".\modules\srurl\url.h"\
+
+
+.\modules\srurl\urldialogs.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\srurl\url.h"\
+
+
+.\modules\userinfo\contactinfo.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\userinfo\stdinfo.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\userinfo\userinfo.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\useronline\useronline.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\utils\bmpfilter.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_png.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\utils\colourpicker.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\utils\hyperlink.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\utils\imgconv.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\utils\md5.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\utils\openurl.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\utils\path.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\database\profilemanager.h"\
+ ".\modules\srfile\file.h"\
+
+
+.\modules\utils\resizer.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\utils\sha1.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\utils\timezones.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\utils\utf.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\utils\utils.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\utils\windowlist.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\visibility\visibility.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\clist\clc.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\clist\clc.h"\
+
+
+.\modules\clist\clcfiledrop.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\clist\clc.h"\
+
+
+.\modules\clist\clcidents.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\clist\clc.h"\
+
+
+.\modules\clist\clcitems.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\clist\clc.h"\
+
+
+.\modules\clist\clcmsgs.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\clist\clc.h"\
+
+
+.\modules\clist\clcutils.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\clist\clc.h"\
+
+
+.\modules\clist\clistcore.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\clist\clc.h"\
+ ".\modules\clist\genmenu.h"\
+
+
+.\modules\clist\clistevents.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\clist\clc.h"\
+
+
+.\modules\clist\clistmenus.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_hotkeys.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\clist\clc.h"\
+ ".\modules\clist\genmenu.h"\
+
+
+.\modules\clist\clistmod.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\clist\clc.h"\
+
+
+.\modules\clist\clistsettings.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\clist\clc.h"\
+
+
+.\modules\clist\clisttray.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\clist\clc.h"\
+
+
+.\modules\clist\clui.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\clist\clc.h"\
+ ".\modules\database\profilemanager.h"\
+
+
+.\modules\clist\cluiservices.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\clist\clc.h"\
+
+
+.\modules\clist\contact.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\clist\clc.h"\
+
+
+.\modules\clist\Docking.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\clist\clc.h"\
+
+
+.\modules\clist\genmenu.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\clist\genmenu.h"\
+
+
+.\modules\clist\genmenuopt.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\clist\genmenu.h"\
+
+
+.\modules\clist\groups.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\clist\clc.h"\
+
+
+.\modules\clist\keyboard.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_hotkeys.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\clist\clc.h"\
+
+
+.\modules\clist\movetogroup.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\clist\protocolorder.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\clist\clc.h"\
+
+
+.\modules\fonts\FontOptions.cpp : \
+ "..\include\m_fontservice.h"\
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\fonts\FontService.h"\
+
+
+.\modules\fonts\FontService.cpp : \
+ "..\include\m_fontservice.h"\
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\fonts\FontService.h"\
+
+
+.\modules\fonts\services.cpp : \
+ "..\include\m_fontservice.h"\
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\fonts\FontService.h"\
+
+
+.\modules\icolib\extracticon.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\icolib\skin2icons.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\icolib\IcoLib.h"\
+
+
+.\modules\updatenotify\updatenotify.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+
+
+.\modules\xml\xmlApi.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\xml\xmlParser.h"\
+
+
+.\modules\xml\xmlParser.cpp : \
+ "..\include\m_genmenu.h"\
+ "..\include\m_plugins.h"\
+ "..\include\m_protomod.h"\
+ ".\modules\xml\xmlParser.h"\
+
+
+.\vc6.rc : \
+ "..\docs\contributors.txt"\
+ "..\include\m_version.h"\
+ "..\include\statusmodes.h"\
+ ".\manifest.rc"\
+ ".\miranda32.exe.manifest"\
+ ".\res\_blank.ico"\
+ ".\res\arrow_sort_column_down.bmp"\
+ ".\res\arrow_sort_column_up.bmp"\
+ ".\res\chat_join.ico"\
+ ".\res\chat_leave.ico"\
+ ".\res\check_off.ico"\
+ ".\res\check_on.ico"\
+ ".\res\contact_add.ico"\
+ ".\res\contact_delete.ico"\
+ ".\res\contact_groups.ico"\
+ ".\res\contact_rename.ico"\
+ ".\res\contact_view_details.ico"\
+ ".\res\cursor_drag_copy.cur"\
+ ".\res\cursor_drop_user.cur"\
+ ".\res\cursor_hyperlink.cur"\
+ ".\res\group_closed.ico"\
+ ".\res\group_opened.ico"\
+ ".\res\icon_accmgr.ico"\
+ ".\res\icon_all.ico"\
+ ".\res\icon_ansi.ico"\
+ ".\res\icon_auth_request.ico"\
+ ".\res\icon_connecting.ico"\
+ ".\res\icon_down_arrow.ico"\
+ ".\res\Icon_exit.ico"\
+ ".\res\icon_file.ico"\
+ ".\res\icon_find_user.ico"\
+ ".\res\icon_help.ico"\
+ ".\res\icon_history.ico"\
+ ".\res\icon_loaded.ico"\
+ ".\res\icon_mail.ico"\
+ ".\res\icon_message.ico"\
+ ".\res\icon_notloaded.ico"\
+ ".\res\icon_options.ico"\
+ ".\res\icon_search_all.ico"\
+ ".\res\Icon_show_hide.ico"\
+ ".\res\icon_small_dot.ico"\
+ ".\res\icon_sms.ico"\
+ ".\res\icon_typing.ico"\
+ ".\res\icon_undo.ico"\
+ ".\res\icon_unicode.ico"\
+ ".\res\icon_url.ico"\
+ ".\res\icon_window.ico"\
+ ".\res\icon_windows.ico"\
+ ".\res\miranda_home.ico"\
+ ".\res\miranda_logo.ico"\
+ ".\res\miranda_manager.ico"\
+ ".\res\Off.ico"\
+ ".\res\On.ico"\
+ ".\res\status_away.ico"\
+ ".\res\status_DND.ico"\
+ ".\res\status_free4chat.ico"\
+ ".\res\status_invisible.ico"\
+ ".\res\status_locked.ico"\
+ ".\res\status_NA.ico"\
+ ".\res\status_occupied.ico"\
+ ".\res\status_offline.ico"\
+ ".\res\status_on_the_phone.ico"\
+ ".\res\status_online.ico"\
+ ".\res\status_out2lunch.ico"\
+ ".\res\status_user_online.ico"\
+ ".\resource.rc"\
+ ".\version.rc"\
+
diff --git a/src/miranda32.dsp b/src/miranda32.dsp
new file mode 100644
index 0000000000..8cec43ab60
--- /dev/null
+++ b/src/miranda32.dsp
@@ -0,0 +1,962 @@
+# Microsoft Developer Studio Project File - Name="miranda32" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=miranda32 - Win32 Debug Unicode
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "miranda32.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "miranda32.mak" CFG="miranda32 - Win32 Debug Unicode"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "miranda32 - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "miranda32 - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE "miranda32 - Win32 Release Unicode" (based on "Win32 (x86) Application")
+!MESSAGE "miranda32 - Win32 Debug Unicode" (based on "Win32 (x86) Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "miranda32 - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 1
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /Zi /O1 /I "../include" /I "../include/msapi" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_NOSDK" /D "_STATIC" /Fr /Yu"commonheaders.h" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /i "../include" /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 ws2_32.lib kernel32.lib user32.lib gdi32.lib shell32.lib comdlg32.lib advapi32.lib ole32.lib oleaut32.lib uuid.lib comctl32.lib winmm.lib version.lib crypt32.lib /nologo /subsystem:windows /debug /machine:I386 /out:"../bin/release/miranda32.exe" /fixed /ALIGN:4096 /ignore:4108
+# SUBTRACT LINK32 /pdb:none /incremental:yes /map
+
+!ELSEIF "$(CFG)" == "miranda32 - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 1
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /MDd /W3 /Gm /ZI /Od /I "../include" /I "../include/msapi" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_NOSDK" /D "_STATIC" /Fr /Yu"commonheaders.h" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /i "../include" /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 ws2_32.lib kernel32.lib user32.lib gdi32.lib shell32.lib comdlg32.lib advapi32.lib ole32.lib oleaut32.lib uuid.lib comctl32.lib winmm.lib version.lib crypt32.lib /nologo /subsystem:windows /debug /machine:I386 /out:"../bin/debug/miranda32.exe"
+# SUBTRACT LINK32 /profile /pdb:none /incremental:no /map
+
+!ELSEIF "$(CFG)" == "miranda32 - Win32 Release Unicode"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "miranda32___Win32_Release_Unicode"
+# PROP BASE Intermediate_Dir "miranda32___Win32_Release_Unicode"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ".\Release_Unicode"
+# PROP Intermediate_Dir ".\Release_Unicode"
+# PROP Ignore_Export_Lib 1
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /GX /Zi /O1 /I "../include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_NOSDK" /Fr /Yu"../../core/commonheaders.h" /FD /c
+# ADD CPP /nologo /MD /W3 /Zi /O1 /I "../include/msapi" /I "../include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_NOSDK" /D "UNICODE" /D "_STATIC" /Fr /Yu"commonheaders.h" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /i "../include" /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 ws2_32.lib comctl32.lib winmm.lib version.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /map /machine:I386 /out:"../bin/release/miranda32.exe" /fixed /ALIGN:4096 /ignore:4108
+# SUBTRACT BASE LINK32 /pdb:none /debug
+# ADD LINK32 ws2_32.lib kernel32.lib user32.lib gdi32.lib shell32.lib comdlg32.lib advapi32.lib ole32.lib oleaut32.lib uuid.lib comctl32.lib winmm.lib version.lib crypt32.lib /nologo /subsystem:windows /debug /machine:I386 /out:"../bin/Release Unicode/miranda32.exe" /fixed /ALIGN:4096 /ignore:4108
+# SUBTRACT LINK32 /pdb:none /incremental:yes /map
+
+!ELSEIF "$(CFG)" == "miranda32 - Win32 Debug Unicode"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "miranda32___Win32_Debug_Unicode"
+# PROP BASE Intermediate_Dir "miranda32___Win32_Debug_Unicode"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir ".\Debug_Unicode"
+# PROP Intermediate_Dir ".\Debug_Unicode"
+# PROP Ignore_Export_Lib 1
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_NOSDK" /Fr /FD /c
+# SUBTRACT BASE CPP /YX
+# ADD CPP /nologo /MDd /W3 /Gm /ZI /Od /I "../include" /I "../include/msapi" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_NOSDK" /D "UNICODE" /D "_STATIC" /Fr /Yu"commonheaders.h" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /i "../include" /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib winmm.lib version.lib /nologo /subsystem:windows /map /debug /machine:I386 /out:"../bin/debug/miranda32.exe"
+# SUBTRACT BASE LINK32 /profile
+# ADD LINK32 ws2_32.lib kernel32.lib user32.lib gdi32.lib shell32.lib comdlg32.lib advapi32.lib ole32.lib oleaut32.lib uuid.lib comctl32.lib winmm.lib version.lib crypt32.lib /nologo /subsystem:windows /debug /machine:I386 /out:"../bin/Debug Unicode/miranda32.exe"
+# SUBTRACT LINK32 /profile /pdb:none /incremental:no /map
+
+!ENDIF
+
+# Begin Target
+
+# Name "miranda32 - Win32 Release"
+# Name "miranda32 - Win32 Debug"
+# Name "miranda32 - Win32 Release Unicode"
+# Name "miranda32 - Win32 Debug Unicode"
+# Begin Group "SDK"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\include\m_addcontact.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\m_awaymsg.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\m_button.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\m_clc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\m_clist.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\m_clui.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\m_contacts.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\m_database.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\m_email.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\m_file.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\m_findadd.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\m_fuse.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\m_help.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\m_history.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\m_icq.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\m_idle.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\m_ignore.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\m_langpack.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\m_message.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\m_netlib.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\m_options.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\m_plugins.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\m_popup.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\m_protocols.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\m_protomod.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\m_protosvc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\m_sessions.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\m_skin.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\m_system.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\m_timezones.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\m_url.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\m_userinfo.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\m_utils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\m_version.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\newpluginapi.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\statusmodes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\include\win2k.h
+# End Source File
+# End Group
+# Begin Group "Core"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\core\commonheaders.cpp
+# ADD CPP /Yc"commonheaders.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\core\commonheaders.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\core\forkthread.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\core\memory.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\core\miranda.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\core\miranda.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\core\modules.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\core\modules.h
+# End Source File
+# End Group
+# Begin Group "Modules"
+
+# PROP Default_Filter ""
+# Begin Group "addcontact"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\modules\addcontact\addcontact.cpp
+# End Source File
+# End Group
+# Begin Group "autoaway"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\modules\autoaway\autoaway.cpp
+# End Source File
+# End Group
+# Begin Group "button"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\modules\button\button.cpp
+# End Source File
+# End Group
+# Begin Group "contacts"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\modules\contacts\contacts.cpp
+# End Source File
+# End Group
+# Begin Group "database"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\modules\database\database.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\database\dbini.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\database\dblists.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\database\dblists.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\database\dbutils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\database\profilemanager.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\database\profilemanager.h
+# End Source File
+# End Group
+# Begin Group "findadd"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\modules\findadd\findadd.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\findadd\findadd.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\findadd\searchresults.cpp
+# End Source File
+# End Group
+# Begin Group "help"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\modules\help\about.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\help\help.cpp
+# End Source File
+# End Group
+# Begin Group "history"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\modules\history\history.cpp
+# End Source File
+# End Group
+# Begin Group "idle"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\modules\idle\idle.cpp
+# End Source File
+# End Group
+# Begin Group "ignore"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\modules\ignore\ignore.cpp
+# End Source File
+# End Group
+# Begin Group "langpack"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\modules\langpack\langpack.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\langpack\lpservices.cpp
+# End Source File
+# End Group
+# Begin Group "netlib"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\modules\netlib\netlib.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\netlib\netlib.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\netlib\netlibautoproxy.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\netlib\netlibbind.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\netlib\netlibhttp.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\netlib\netlibhttpproxy.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\netlib\netliblog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\netlib\netlibopenconn.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\netlib\netlibopts.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\netlib\netlibpktrecver.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\netlib\netlibsecurity.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\netlib\netlibsock.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\netlib\netlibssl.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\netlib\netlibupnp.cpp
+# End Source File
+# End Group
+# Begin Group "options"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\modules\options\descbutton.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\options\filter.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\options\filter.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\options\headerbar.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\options\iconheader.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\options\options.cpp
+# End Source File
+# End Group
+# Begin Group "plugins"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\modules\plugins\newplugins.cpp
+# End Source File
+# End Group
+# Begin Group "protocols"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\modules\protocols\protoaccs.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\protocols\protochains.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\protocols\protocols.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\protocols\protoint.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\protocols\protoopts.cpp
+# End Source File
+# End Group
+# Begin Group "skin"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\modules\skin\hotkeys.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\skin\skinicons.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\skin\sounds.cpp
+# End Source File
+# End Group
+# Begin Group "srauth"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\modules\srauth\auth.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\srauth\authdialogs.cpp
+# End Source File
+# End Group
+# Begin Group "srawaymsg"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\modules\srawaymsg\awaymsg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\srawaymsg\sendmsg.cpp
+# End Source File
+# End Group
+# Begin Group "sremail"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\modules\sremail\email.cpp
+# End Source File
+# End Group
+# Begin Group "srfile"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\modules\srfile\file.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\srfile\file.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\srfile\fileexistsdlg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\srfile\fileopts.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\srfile\filerecvdlg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\srfile\filesenddlg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\srfile\filexferdlg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\srfile\ftmanager.cpp
+# End Source File
+# End Group
+# Begin Group "srurl"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\modules\srurl\url.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\srurl\url.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\srurl\urldialogs.cpp
+# End Source File
+# End Group
+# Begin Group "userinfo"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\modules\userinfo\contactinfo.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\userinfo\stdinfo.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\userinfo\userinfo.cpp
+# End Source File
+# End Group
+# Begin Group "useronline"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\modules\useronline\useronline.cpp
+# End Source File
+# End Group
+# Begin Group "utils"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\modules\utils\bmpfilter.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\utils\colourpicker.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\utils\hyperlink.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\utils\imgconv.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\utils\md5.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\utils\openurl.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\utils\path.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\utils\resizer.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\utils\sha1.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\utils\timeutils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\utils\timezones.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\utils\utf.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\utils\utils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\utils\windowlist.cpp
+# End Source File
+# End Group
+# Begin Group "visibility"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\modules\visibility\visibility.cpp
+# End Source File
+# End Group
+# Begin Group "clist"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\modules\clist\clc.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\clist\clc.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\clist\clcfiledrop.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\clist\clcidents.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\clist\clcitems.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\clist\clcmsgs.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\clist\clcutils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\clist\clistcore.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\clist\clistevents.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\clist\clistmenus.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\clist\clistmod.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\clist\clistsettings.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\clist\clisttray.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\clist\clui.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\clist\cluiservices.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\clist\contact.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\clist\Docking.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\clist\genmenu.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\clist\genmenu.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\clist\genmenuopt.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\clist\groups.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\clist\keyboard.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\clist\movetogroup.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\clist\protocolorder.cpp
+# End Source File
+# End Group
+# Begin Group "fontservice"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\modules\fonts\FontOptions.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\fonts\FontService.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\fonts\FontService.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\fonts\services.cpp
+# End Source File
+# End Group
+# Begin Group "icolib"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\modules\icolib\extracticon.cpp
+# ADD CPP /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\icolib\IcoLib.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\icolib\skin2icons.cpp
+# End Source File
+# End Group
+# Begin Group "updatenotify"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\modules\updatenotify\updatenotify.cpp
+# End Source File
+# End Group
+# Begin Group "xml"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\modules\xml\xmlApi.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\xml\xmlParser.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\modules\xml\xmlParser.h
+# End Source File
+# End Group
+# End Group
+# Begin Group "Resources"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\miranda32.exe.manifest
+# End Source File
+# Begin Source File
+
+SOURCE=.\vc6.rc
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/src/miranda32.dsw b/src/miranda32.dsw
new file mode 100644
index 0000000000..b15b2dfcf9
--- /dev/null
+++ b/src/miranda32.dsw
@@ -0,0 +1,44 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "miranda32"=.\miranda32.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name zlib
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "zlib"=..\plugins\zlib\zlib.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/src/miranda32.exe.manifest b/src/miranda32.exe.manifest
new file mode 100644
index 0000000000..976a4f0231
--- /dev/null
+++ b/src/miranda32.exe.manifest
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+ <assemblyIdentity
+ version="1.0.0.0"
+ processorArchitecture="X86"
+ name="Miranda.Miranda.Miranda"
+ type="win32"
+ />
+ <description>Miranda</description>
+ <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
+ <security>
+ <requestedPrivileges>
+ <requestedExecutionLevel
+ level="asInvoker"
+ uiAccess="false"/>
+ </requestedPrivileges>
+ </security>
+ </trustInfo>
+ <dependency>
+ <dependentAssembly>
+ <assemblyIdentity
+ type="win32"
+ name="Microsoft.Windows.Common-Controls"
+ version="6.0.0.0"
+ processorArchitecture="X86"
+ publicKeyToken="6595b64144ccf1df"
+ language="*"
+ />
+ </dependentAssembly>
+ </dependency>
+ <dependency>
+ <dependentAssembly>
+ <assemblyIdentity
+ type="win32"
+ name="Microsoft.Windows.Gdiplus"
+ version="1.0.0.0"
+ processorArchitecture="X86"
+ publicKeyToken="6595b64144ccf1df"
+ language="*"
+ />
+ </dependentAssembly>
+ </dependency>
+ <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+ <application>
+ <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+ </application>
+ </compatibility>
+</assembly>
diff --git a/src/miranda32.mak b/src/miranda32.mak
new file mode 100644
index 0000000000..0353cad4fb
--- /dev/null
+++ b/src/miranda32.mak
@@ -0,0 +1,3007 @@
+# Microsoft Developer Studio Generated NMAKE File, Based on miranda32.dsp
+!IF "$(CFG)" == ""
+CFG=miranda32 - Win32 Debug Unicode
+!MESSAGE No configuration specified. Defaulting to miranda32 - Win32 Debug Unicode.
+!ENDIF
+
+!IF "$(CFG)" != "miranda32 - Win32 Release" && "$(CFG)" != "miranda32 - Win32 Debug" && "$(CFG)" != "miranda32 - Win32 Release Unicode" && "$(CFG)" != "miranda32 - Win32 Debug Unicode"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "miranda32.mak" CFG="miranda32 - Win32 Debug Unicode"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "miranda32 - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "miranda32 - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE "miranda32 - Win32 Release Unicode" (based on "Win32 (x86) Application")
+!MESSAGE "miranda32 - Win32 Debug Unicode" (based on "Win32 (x86) Application")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+!IF "$(CFG)" == "miranda32 - Win32 Release"
+
+OUTDIR=.\Release
+INTDIR=.\Release
+# Begin Custom Macros
+OutDir=.\Release
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "..\bin\release\miranda32.exe" "$(OUTDIR)\miranda32.bsc"
+
+!ELSE
+
+ALL : "zlib - Win32 Release" "..\bin\release\miranda32.exe" "$(OUTDIR)\miranda32.bsc"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"zlib - Win32 ReleaseCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\about.obj"
+ -@erase "$(INTDIR)\about.sbr"
+ -@erase "$(INTDIR)\addcontact.obj"
+ -@erase "$(INTDIR)\addcontact.sbr"
+ -@erase "$(INTDIR)\auth.obj"
+ -@erase "$(INTDIR)\auth.sbr"
+ -@erase "$(INTDIR)\authdialogs.obj"
+ -@erase "$(INTDIR)\authdialogs.sbr"
+ -@erase "$(INTDIR)\autoaway.obj"
+ -@erase "$(INTDIR)\autoaway.sbr"
+ -@erase "$(INTDIR)\awaymsg.obj"
+ -@erase "$(INTDIR)\awaymsg.sbr"
+ -@erase "$(INTDIR)\bmpfilter.obj"
+ -@erase "$(INTDIR)\bmpfilter.sbr"
+ -@erase "$(INTDIR)\button.obj"
+ -@erase "$(INTDIR)\button.sbr"
+ -@erase "$(INTDIR)\clc.obj"
+ -@erase "$(INTDIR)\clc.sbr"
+ -@erase "$(INTDIR)\clcfiledrop.obj"
+ -@erase "$(INTDIR)\clcfiledrop.sbr"
+ -@erase "$(INTDIR)\clcidents.obj"
+ -@erase "$(INTDIR)\clcidents.sbr"
+ -@erase "$(INTDIR)\clcitems.obj"
+ -@erase "$(INTDIR)\clcitems.sbr"
+ -@erase "$(INTDIR)\clcmsgs.obj"
+ -@erase "$(INTDIR)\clcmsgs.sbr"
+ -@erase "$(INTDIR)\clcutils.obj"
+ -@erase "$(INTDIR)\clcutils.sbr"
+ -@erase "$(INTDIR)\clistcore.obj"
+ -@erase "$(INTDIR)\clistcore.sbr"
+ -@erase "$(INTDIR)\clistevents.obj"
+ -@erase "$(INTDIR)\clistevents.sbr"
+ -@erase "$(INTDIR)\clistmenus.obj"
+ -@erase "$(INTDIR)\clistmenus.sbr"
+ -@erase "$(INTDIR)\clistmod.obj"
+ -@erase "$(INTDIR)\clistmod.sbr"
+ -@erase "$(INTDIR)\clistsettings.obj"
+ -@erase "$(INTDIR)\clistsettings.sbr"
+ -@erase "$(INTDIR)\clisttray.obj"
+ -@erase "$(INTDIR)\clisttray.sbr"
+ -@erase "$(INTDIR)\clui.obj"
+ -@erase "$(INTDIR)\clui.sbr"
+ -@erase "$(INTDIR)\cluiservices.obj"
+ -@erase "$(INTDIR)\cluiservices.sbr"
+ -@erase "$(INTDIR)\colourpicker.obj"
+ -@erase "$(INTDIR)\colourpicker.sbr"
+ -@erase "$(INTDIR)\commonheaders.obj"
+ -@erase "$(INTDIR)\commonheaders.sbr"
+ -@erase "$(INTDIR)\contact.obj"
+ -@erase "$(INTDIR)\contact.sbr"
+ -@erase "$(INTDIR)\contactinfo.obj"
+ -@erase "$(INTDIR)\contactinfo.sbr"
+ -@erase "$(INTDIR)\contacts.obj"
+ -@erase "$(INTDIR)\contacts.sbr"
+ -@erase "$(INTDIR)\database.obj"
+ -@erase "$(INTDIR)\database.sbr"
+ -@erase "$(INTDIR)\dbini.obj"
+ -@erase "$(INTDIR)\dbini.sbr"
+ -@erase "$(INTDIR)\dblists.obj"
+ -@erase "$(INTDIR)\dblists.sbr"
+ -@erase "$(INTDIR)\dbutils.obj"
+ -@erase "$(INTDIR)\dbutils.sbr"
+ -@erase "$(INTDIR)\descbutton.obj"
+ -@erase "$(INTDIR)\descbutton.sbr"
+ -@erase "$(INTDIR)\Docking.obj"
+ -@erase "$(INTDIR)\Docking.sbr"
+ -@erase "$(INTDIR)\email.obj"
+ -@erase "$(INTDIR)\email.sbr"
+ -@erase "$(INTDIR)\extracticon.obj"
+ -@erase "$(INTDIR)\extracticon.sbr"
+ -@erase "$(INTDIR)\file.obj"
+ -@erase "$(INTDIR)\file.sbr"
+ -@erase "$(INTDIR)\fileexistsdlg.obj"
+ -@erase "$(INTDIR)\fileexistsdlg.sbr"
+ -@erase "$(INTDIR)\fileopts.obj"
+ -@erase "$(INTDIR)\fileopts.sbr"
+ -@erase "$(INTDIR)\filerecvdlg.obj"
+ -@erase "$(INTDIR)\filerecvdlg.sbr"
+ -@erase "$(INTDIR)\filesenddlg.obj"
+ -@erase "$(INTDIR)\filesenddlg.sbr"
+ -@erase "$(INTDIR)\filexferdlg.obj"
+ -@erase "$(INTDIR)\filexferdlg.sbr"
+ -@erase "$(INTDIR)\filter.obj"
+ -@erase "$(INTDIR)\filter.sbr"
+ -@erase "$(INTDIR)\findadd.obj"
+ -@erase "$(INTDIR)\findadd.sbr"
+ -@erase "$(INTDIR)\FontOptions.obj"
+ -@erase "$(INTDIR)\FontOptions.sbr"
+ -@erase "$(INTDIR)\FontService.obj"
+ -@erase "$(INTDIR)\FontService.sbr"
+ -@erase "$(INTDIR)\ftmanager.obj"
+ -@erase "$(INTDIR)\ftmanager.sbr"
+ -@erase "$(INTDIR)\genmenu.obj"
+ -@erase "$(INTDIR)\genmenu.sbr"
+ -@erase "$(INTDIR)\genmenuopt.obj"
+ -@erase "$(INTDIR)\genmenuopt.sbr"
+ -@erase "$(INTDIR)\groups.obj"
+ -@erase "$(INTDIR)\groups.sbr"
+ -@erase "$(INTDIR)\headerbar.obj"
+ -@erase "$(INTDIR)\headerbar.sbr"
+ -@erase "$(INTDIR)\help.obj"
+ -@erase "$(INTDIR)\help.sbr"
+ -@erase "$(INTDIR)\history.obj"
+ -@erase "$(INTDIR)\history.sbr"
+ -@erase "$(INTDIR)\hotkeys.obj"
+ -@erase "$(INTDIR)\hotkeys.sbr"
+ -@erase "$(INTDIR)\hyperlink.obj"
+ -@erase "$(INTDIR)\hyperlink.sbr"
+ -@erase "$(INTDIR)\iconheader.obj"
+ -@erase "$(INTDIR)\iconheader.sbr"
+ -@erase "$(INTDIR)\idle.obj"
+ -@erase "$(INTDIR)\idle.sbr"
+ -@erase "$(INTDIR)\ignore.obj"
+ -@erase "$(INTDIR)\ignore.sbr"
+ -@erase "$(INTDIR)\imgconv.obj"
+ -@erase "$(INTDIR)\imgconv.sbr"
+ -@erase "$(INTDIR)\keyboard.obj"
+ -@erase "$(INTDIR)\keyboard.sbr"
+ -@erase "$(INTDIR)\langpack.obj"
+ -@erase "$(INTDIR)\langpack.sbr"
+ -@erase "$(INTDIR)\lpservices.obj"
+ -@erase "$(INTDIR)\lpservices.sbr"
+ -@erase "$(INTDIR)\md5.obj"
+ -@erase "$(INTDIR)\md5.sbr"
+ -@erase "$(INTDIR)\memory.obj"
+ -@erase "$(INTDIR)\memory.sbr"
+ -@erase "$(INTDIR)\miranda.obj"
+ -@erase "$(INTDIR)\miranda.sbr"
+ -@erase "$(INTDIR)\miranda32.pch"
+ -@erase "$(INTDIR)\modules.obj"
+ -@erase "$(INTDIR)\modules.sbr"
+ -@erase "$(INTDIR)\movetogroup.obj"
+ -@erase "$(INTDIR)\movetogroup.sbr"
+ -@erase "$(INTDIR)\netlib.obj"
+ -@erase "$(INTDIR)\netlib.sbr"
+ -@erase "$(INTDIR)\netlibautoproxy.obj"
+ -@erase "$(INTDIR)\netlibautoproxy.sbr"
+ -@erase "$(INTDIR)\netlibbind.obj"
+ -@erase "$(INTDIR)\netlibbind.sbr"
+ -@erase "$(INTDIR)\netlibhttp.obj"
+ -@erase "$(INTDIR)\netlibhttp.sbr"
+ -@erase "$(INTDIR)\netlibhttpproxy.obj"
+ -@erase "$(INTDIR)\netlibhttpproxy.sbr"
+ -@erase "$(INTDIR)\netliblog.obj"
+ -@erase "$(INTDIR)\netliblog.sbr"
+ -@erase "$(INTDIR)\netlibopenconn.obj"
+ -@erase "$(INTDIR)\netlibopenconn.sbr"
+ -@erase "$(INTDIR)\netlibopts.obj"
+ -@erase "$(INTDIR)\netlibopts.sbr"
+ -@erase "$(INTDIR)\netlibpktrecver.obj"
+ -@erase "$(INTDIR)\netlibpktrecver.sbr"
+ -@erase "$(INTDIR)\netlibsecurity.obj"
+ -@erase "$(INTDIR)\netlibsecurity.sbr"
+ -@erase "$(INTDIR)\netlibsock.obj"
+ -@erase "$(INTDIR)\netlibsock.sbr"
+ -@erase "$(INTDIR)\netlibssl.obj"
+ -@erase "$(INTDIR)\netlibssl.sbr"
+ -@erase "$(INTDIR)\netlibupnp.obj"
+ -@erase "$(INTDIR)\netlibupnp.sbr"
+ -@erase "$(INTDIR)\newplugins.obj"
+ -@erase "$(INTDIR)\newplugins.sbr"
+ -@erase "$(INTDIR)\openurl.obj"
+ -@erase "$(INTDIR)\openurl.sbr"
+ -@erase "$(INTDIR)\options.obj"
+ -@erase "$(INTDIR)\options.sbr"
+ -@erase "$(INTDIR)\path.obj"
+ -@erase "$(INTDIR)\path.sbr"
+ -@erase "$(INTDIR)\profilemanager.obj"
+ -@erase "$(INTDIR)\profilemanager.sbr"
+ -@erase "$(INTDIR)\protoaccs.obj"
+ -@erase "$(INTDIR)\protoaccs.sbr"
+ -@erase "$(INTDIR)\protochains.obj"
+ -@erase "$(INTDIR)\protochains.sbr"
+ -@erase "$(INTDIR)\protocolorder.obj"
+ -@erase "$(INTDIR)\protocolorder.sbr"
+ -@erase "$(INTDIR)\protocols.obj"
+ -@erase "$(INTDIR)\protocols.sbr"
+ -@erase "$(INTDIR)\protoint.obj"
+ -@erase "$(INTDIR)\protoint.sbr"
+ -@erase "$(INTDIR)\protoopts.obj"
+ -@erase "$(INTDIR)\protoopts.sbr"
+ -@erase "$(INTDIR)\resizer.obj"
+ -@erase "$(INTDIR)\resizer.sbr"
+ -@erase "$(INTDIR)\searchresults.obj"
+ -@erase "$(INTDIR)\searchresults.sbr"
+ -@erase "$(INTDIR)\sendmsg.obj"
+ -@erase "$(INTDIR)\sendmsg.sbr"
+ -@erase "$(INTDIR)\services.obj"
+ -@erase "$(INTDIR)\services.sbr"
+ -@erase "$(INTDIR)\sha1.obj"
+ -@erase "$(INTDIR)\sha1.sbr"
+ -@erase "$(INTDIR)\skin2icons.obj"
+ -@erase "$(INTDIR)\skin2icons.sbr"
+ -@erase "$(INTDIR)\skinicons.obj"
+ -@erase "$(INTDIR)\skinicons.sbr"
+ -@erase "$(INTDIR)\sounds.obj"
+ -@erase "$(INTDIR)\sounds.sbr"
+ -@erase "$(INTDIR)\stdinfo.obj"
+ -@erase "$(INTDIR)\stdinfo.sbr"
+ -@erase "$(INTDIR)\timeutils.obj"
+ -@erase "$(INTDIR)\timeutils.sbr"
+ -@erase "$(INTDIR)\timezones.obj"
+ -@erase "$(INTDIR)\timezones.sbr"
+ -@erase "$(INTDIR)\updatenotify.obj"
+ -@erase "$(INTDIR)\updatenotify.sbr"
+ -@erase "$(INTDIR)\url.obj"
+ -@erase "$(INTDIR)\url.sbr"
+ -@erase "$(INTDIR)\urldialogs.obj"
+ -@erase "$(INTDIR)\urldialogs.sbr"
+ -@erase "$(INTDIR)\userinfo.obj"
+ -@erase "$(INTDIR)\userinfo.sbr"
+ -@erase "$(INTDIR)\useronline.obj"
+ -@erase "$(INTDIR)\useronline.sbr"
+ -@erase "$(INTDIR)\utf.obj"
+ -@erase "$(INTDIR)\utf.sbr"
+ -@erase "$(INTDIR)\utils.obj"
+ -@erase "$(INTDIR)\utils.sbr"
+ -@erase "$(INTDIR)\vc6.res"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(INTDIR)\vc60.pdb"
+ -@erase "$(INTDIR)\visibility.obj"
+ -@erase "$(INTDIR)\visibility.sbr"
+ -@erase "$(INTDIR)\windowlist.obj"
+ -@erase "$(INTDIR)\windowlist.sbr"
+ -@erase "$(INTDIR)\xmlApi.obj"
+ -@erase "$(INTDIR)\xmlApi.sbr"
+ -@erase "$(INTDIR)\xmlParser.obj"
+ -@erase "$(INTDIR)\xmlParser.sbr"
+ -@erase "$(OUTDIR)\miranda32.bsc"
+ -@erase "$(OUTDIR)\miranda32.pdb"
+ -@erase "..\bin\release\miranda32.exe"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MD /W3 /Zi /O1 /I "../include" /I "../include/msapi" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_NOSDK" /D "_STATIC" /Fr"$(INTDIR)\\" /Fp"$(INTDIR)\miranda32.pch" /Yu"commonheaders.h" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+MTL=midl.exe
+MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\vc6.res" /i "../include" /d "NDEBUG"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\miranda32.bsc"
+BSC32_SBRS= \
+ "$(INTDIR)\commonheaders.sbr" \
+ "$(INTDIR)\memory.sbr" \
+ "$(INTDIR)\miranda.sbr" \
+ "$(INTDIR)\modules.sbr" \
+ "$(INTDIR)\addcontact.sbr" \
+ "$(INTDIR)\autoaway.sbr" \
+ "$(INTDIR)\button.sbr" \
+ "$(INTDIR)\contacts.sbr" \
+ "$(INTDIR)\database.sbr" \
+ "$(INTDIR)\dbini.sbr" \
+ "$(INTDIR)\dblists.sbr" \
+ "$(INTDIR)\dbutils.sbr" \
+ "$(INTDIR)\profilemanager.sbr" \
+ "$(INTDIR)\findadd.sbr" \
+ "$(INTDIR)\searchresults.sbr" \
+ "$(INTDIR)\about.sbr" \
+ "$(INTDIR)\help.sbr" \
+ "$(INTDIR)\history.sbr" \
+ "$(INTDIR)\idle.sbr" \
+ "$(INTDIR)\ignore.sbr" \
+ "$(INTDIR)\langpack.sbr" \
+ "$(INTDIR)\lpservices.sbr" \
+ "$(INTDIR)\netlib.sbr" \
+ "$(INTDIR)\netlibautoproxy.sbr" \
+ "$(INTDIR)\netlibbind.sbr" \
+ "$(INTDIR)\netlibhttp.sbr" \
+ "$(INTDIR)\netlibhttpproxy.sbr" \
+ "$(INTDIR)\netliblog.sbr" \
+ "$(INTDIR)\netlibopenconn.sbr" \
+ "$(INTDIR)\netlibopts.sbr" \
+ "$(INTDIR)\netlibpktrecver.sbr" \
+ "$(INTDIR)\netlibsecurity.sbr" \
+ "$(INTDIR)\netlibsock.sbr" \
+ "$(INTDIR)\netlibssl.sbr" \
+ "$(INTDIR)\netlibupnp.sbr" \
+ "$(INTDIR)\descbutton.sbr" \
+ "$(INTDIR)\filter.sbr" \
+ "$(INTDIR)\headerbar.sbr" \
+ "$(INTDIR)\iconheader.sbr" \
+ "$(INTDIR)\options.sbr" \
+ "$(INTDIR)\newplugins.sbr" \
+ "$(INTDIR)\protoaccs.sbr" \
+ "$(INTDIR)\protochains.sbr" \
+ "$(INTDIR)\protocols.sbr" \
+ "$(INTDIR)\protoint.sbr" \
+ "$(INTDIR)\protoopts.sbr" \
+ "$(INTDIR)\hotkeys.sbr" \
+ "$(INTDIR)\skinicons.sbr" \
+ "$(INTDIR)\sounds.sbr" \
+ "$(INTDIR)\auth.sbr" \
+ "$(INTDIR)\authdialogs.sbr" \
+ "$(INTDIR)\awaymsg.sbr" \
+ "$(INTDIR)\sendmsg.sbr" \
+ "$(INTDIR)\email.sbr" \
+ "$(INTDIR)\file.sbr" \
+ "$(INTDIR)\fileexistsdlg.sbr" \
+ "$(INTDIR)\fileopts.sbr" \
+ "$(INTDIR)\filerecvdlg.sbr" \
+ "$(INTDIR)\filesenddlg.sbr" \
+ "$(INTDIR)\filexferdlg.sbr" \
+ "$(INTDIR)\ftmanager.sbr" \
+ "$(INTDIR)\url.sbr" \
+ "$(INTDIR)\urldialogs.sbr" \
+ "$(INTDIR)\contactinfo.sbr" \
+ "$(INTDIR)\stdinfo.sbr" \
+ "$(INTDIR)\userinfo.sbr" \
+ "$(INTDIR)\useronline.sbr" \
+ "$(INTDIR)\bmpfilter.sbr" \
+ "$(INTDIR)\colourpicker.sbr" \
+ "$(INTDIR)\hyperlink.sbr" \
+ "$(INTDIR)\imgconv.sbr" \
+ "$(INTDIR)\md5.sbr" \
+ "$(INTDIR)\openurl.sbr" \
+ "$(INTDIR)\path.sbr" \
+ "$(INTDIR)\resizer.sbr" \
+ "$(INTDIR)\sha1.sbr" \
+ "$(INTDIR)\timeutils.sbr" \
+ "$(INTDIR)\timezones.sbr" \
+ "$(INTDIR)\utf.sbr" \
+ "$(INTDIR)\utils.sbr" \
+ "$(INTDIR)\windowlist.sbr" \
+ "$(INTDIR)\visibility.sbr" \
+ "$(INTDIR)\clc.sbr" \
+ "$(INTDIR)\clcfiledrop.sbr" \
+ "$(INTDIR)\clcidents.sbr" \
+ "$(INTDIR)\clcitems.sbr" \
+ "$(INTDIR)\clcmsgs.sbr" \
+ "$(INTDIR)\clcutils.sbr" \
+ "$(INTDIR)\clistcore.sbr" \
+ "$(INTDIR)\clistevents.sbr" \
+ "$(INTDIR)\clistmenus.sbr" \
+ "$(INTDIR)\clistmod.sbr" \
+ "$(INTDIR)\clistsettings.sbr" \
+ "$(INTDIR)\clisttray.sbr" \
+ "$(INTDIR)\clui.sbr" \
+ "$(INTDIR)\cluiservices.sbr" \
+ "$(INTDIR)\contact.sbr" \
+ "$(INTDIR)\Docking.sbr" \
+ "$(INTDIR)\genmenu.sbr" \
+ "$(INTDIR)\genmenuopt.sbr" \
+ "$(INTDIR)\groups.sbr" \
+ "$(INTDIR)\keyboard.sbr" \
+ "$(INTDIR)\movetogroup.sbr" \
+ "$(INTDIR)\protocolorder.sbr" \
+ "$(INTDIR)\FontOptions.sbr" \
+ "$(INTDIR)\FontService.sbr" \
+ "$(INTDIR)\services.sbr" \
+ "$(INTDIR)\extracticon.sbr" \
+ "$(INTDIR)\skin2icons.sbr" \
+ "$(INTDIR)\updatenotify.sbr" \
+ "$(INTDIR)\xmlApi.sbr" \
+ "$(INTDIR)\xmlParser.sbr"
+
+"$(OUTDIR)\miranda32.bsc" : "$(OUTDIR)" $(BSC32_SBRS)
+ $(BSC32) @<<
+ $(BSC32_FLAGS) $(BSC32_SBRS)
+<<
+
+LINK32=link.exe
+LINK32_FLAGS=ws2_32.lib kernel32.lib user32.lib gdi32.lib shell32.lib comdlg32.lib advapi32.lib ole32.lib oleaut32.lib uuid.lib comctl32.lib winmm.lib version.lib crypt32.lib /nologo /subsystem:windows /incremental:no /pdb:"$(OUTDIR)\miranda32.pdb" /debug /machine:I386 /out:"../bin/release/miranda32.exe" /fixed /ALIGN:4096 /ignore:4108
+LINK32_OBJS= \
+ "$(INTDIR)\commonheaders.obj" \
+ "$(INTDIR)\memory.obj" \
+ "$(INTDIR)\miranda.obj" \
+ "$(INTDIR)\modules.obj" \
+ "$(INTDIR)\addcontact.obj" \
+ "$(INTDIR)\autoaway.obj" \
+ "$(INTDIR)\button.obj" \
+ "$(INTDIR)\contacts.obj" \
+ "$(INTDIR)\database.obj" \
+ "$(INTDIR)\dbini.obj" \
+ "$(INTDIR)\dblists.obj" \
+ "$(INTDIR)\dbutils.obj" \
+ "$(INTDIR)\profilemanager.obj" \
+ "$(INTDIR)\findadd.obj" \
+ "$(INTDIR)\searchresults.obj" \
+ "$(INTDIR)\about.obj" \
+ "$(INTDIR)\help.obj" \
+ "$(INTDIR)\history.obj" \
+ "$(INTDIR)\idle.obj" \
+ "$(INTDIR)\ignore.obj" \
+ "$(INTDIR)\langpack.obj" \
+ "$(INTDIR)\lpservices.obj" \
+ "$(INTDIR)\netlib.obj" \
+ "$(INTDIR)\netlibautoproxy.obj" \
+ "$(INTDIR)\netlibbind.obj" \
+ "$(INTDIR)\netlibhttp.obj" \
+ "$(INTDIR)\netlibhttpproxy.obj" \
+ "$(INTDIR)\netliblog.obj" \
+ "$(INTDIR)\netlibopenconn.obj" \
+ "$(INTDIR)\netlibopts.obj" \
+ "$(INTDIR)\netlibpktrecver.obj" \
+ "$(INTDIR)\netlibsecurity.obj" \
+ "$(INTDIR)\netlibsock.obj" \
+ "$(INTDIR)\netlibssl.obj" \
+ "$(INTDIR)\netlibupnp.obj" \
+ "$(INTDIR)\descbutton.obj" \
+ "$(INTDIR)\filter.obj" \
+ "$(INTDIR)\headerbar.obj" \
+ "$(INTDIR)\iconheader.obj" \
+ "$(INTDIR)\options.obj" \
+ "$(INTDIR)\newplugins.obj" \
+ "$(INTDIR)\protoaccs.obj" \
+ "$(INTDIR)\protochains.obj" \
+ "$(INTDIR)\protocols.obj" \
+ "$(INTDIR)\protoint.obj" \
+ "$(INTDIR)\protoopts.obj" \
+ "$(INTDIR)\hotkeys.obj" \
+ "$(INTDIR)\skinicons.obj" \
+ "$(INTDIR)\sounds.obj" \
+ "$(INTDIR)\auth.obj" \
+ "$(INTDIR)\authdialogs.obj" \
+ "$(INTDIR)\awaymsg.obj" \
+ "$(INTDIR)\sendmsg.obj" \
+ "$(INTDIR)\email.obj" \
+ "$(INTDIR)\file.obj" \
+ "$(INTDIR)\fileexistsdlg.obj" \
+ "$(INTDIR)\fileopts.obj" \
+ "$(INTDIR)\filerecvdlg.obj" \
+ "$(INTDIR)\filesenddlg.obj" \
+ "$(INTDIR)\filexferdlg.obj" \
+ "$(INTDIR)\ftmanager.obj" \
+ "$(INTDIR)\url.obj" \
+ "$(INTDIR)\urldialogs.obj" \
+ "$(INTDIR)\contactinfo.obj" \
+ "$(INTDIR)\stdinfo.obj" \
+ "$(INTDIR)\userinfo.obj" \
+ "$(INTDIR)\useronline.obj" \
+ "$(INTDIR)\bmpfilter.obj" \
+ "$(INTDIR)\colourpicker.obj" \
+ "$(INTDIR)\hyperlink.obj" \
+ "$(INTDIR)\imgconv.obj" \
+ "$(INTDIR)\md5.obj" \
+ "$(INTDIR)\openurl.obj" \
+ "$(INTDIR)\path.obj" \
+ "$(INTDIR)\resizer.obj" \
+ "$(INTDIR)\sha1.obj" \
+ "$(INTDIR)\timeutils.obj" \
+ "$(INTDIR)\timezones.obj" \
+ "$(INTDIR)\utf.obj" \
+ "$(INTDIR)\utils.obj" \
+ "$(INTDIR)\windowlist.obj" \
+ "$(INTDIR)\visibility.obj" \
+ "$(INTDIR)\clc.obj" \
+ "$(INTDIR)\clcfiledrop.obj" \
+ "$(INTDIR)\clcidents.obj" \
+ "$(INTDIR)\clcitems.obj" \
+ "$(INTDIR)\clcmsgs.obj" \
+ "$(INTDIR)\clcutils.obj" \
+ "$(INTDIR)\clistcore.obj" \
+ "$(INTDIR)\clistevents.obj" \
+ "$(INTDIR)\clistmenus.obj" \
+ "$(INTDIR)\clistmod.obj" \
+ "$(INTDIR)\clistsettings.obj" \
+ "$(INTDIR)\clisttray.obj" \
+ "$(INTDIR)\clui.obj" \
+ "$(INTDIR)\cluiservices.obj" \
+ "$(INTDIR)\contact.obj" \
+ "$(INTDIR)\Docking.obj" \
+ "$(INTDIR)\genmenu.obj" \
+ "$(INTDIR)\genmenuopt.obj" \
+ "$(INTDIR)\groups.obj" \
+ "$(INTDIR)\keyboard.obj" \
+ "$(INTDIR)\movetogroup.obj" \
+ "$(INTDIR)\protocolorder.obj" \
+ "$(INTDIR)\FontOptions.obj" \
+ "$(INTDIR)\FontService.obj" \
+ "$(INTDIR)\services.obj" \
+ "$(INTDIR)\extracticon.obj" \
+ "$(INTDIR)\skin2icons.obj" \
+ "$(INTDIR)\updatenotify.obj" \
+ "$(INTDIR)\xmlApi.obj" \
+ "$(INTDIR)\xmlParser.obj" \
+ "$(INTDIR)\vc6.res" \
+ "..\plugins\zlib\Release\zlib.lib"
+
+"..\bin\release\miranda32.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "miranda32 - Win32 Debug"
+
+OUTDIR=.\Debug
+INTDIR=.\Debug
+# Begin Custom Macros
+OutDir=.\Debug
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "..\bin\debug\miranda32.exe" "$(OUTDIR)\miranda32.bsc"
+
+!ELSE
+
+ALL : "zlib - Win32 Debug" "..\bin\debug\miranda32.exe" "$(OUTDIR)\miranda32.bsc"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"zlib - Win32 DebugCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\about.obj"
+ -@erase "$(INTDIR)\about.sbr"
+ -@erase "$(INTDIR)\addcontact.obj"
+ -@erase "$(INTDIR)\addcontact.sbr"
+ -@erase "$(INTDIR)\auth.obj"
+ -@erase "$(INTDIR)\auth.sbr"
+ -@erase "$(INTDIR)\authdialogs.obj"
+ -@erase "$(INTDIR)\authdialogs.sbr"
+ -@erase "$(INTDIR)\autoaway.obj"
+ -@erase "$(INTDIR)\autoaway.sbr"
+ -@erase "$(INTDIR)\awaymsg.obj"
+ -@erase "$(INTDIR)\awaymsg.sbr"
+ -@erase "$(INTDIR)\bmpfilter.obj"
+ -@erase "$(INTDIR)\bmpfilter.sbr"
+ -@erase "$(INTDIR)\button.obj"
+ -@erase "$(INTDIR)\button.sbr"
+ -@erase "$(INTDIR)\clc.obj"
+ -@erase "$(INTDIR)\clc.sbr"
+ -@erase "$(INTDIR)\clcfiledrop.obj"
+ -@erase "$(INTDIR)\clcfiledrop.sbr"
+ -@erase "$(INTDIR)\clcidents.obj"
+ -@erase "$(INTDIR)\clcidents.sbr"
+ -@erase "$(INTDIR)\clcitems.obj"
+ -@erase "$(INTDIR)\clcitems.sbr"
+ -@erase "$(INTDIR)\clcmsgs.obj"
+ -@erase "$(INTDIR)\clcmsgs.sbr"
+ -@erase "$(INTDIR)\clcutils.obj"
+ -@erase "$(INTDIR)\clcutils.sbr"
+ -@erase "$(INTDIR)\clistcore.obj"
+ -@erase "$(INTDIR)\clistcore.sbr"
+ -@erase "$(INTDIR)\clistevents.obj"
+ -@erase "$(INTDIR)\clistevents.sbr"
+ -@erase "$(INTDIR)\clistmenus.obj"
+ -@erase "$(INTDIR)\clistmenus.sbr"
+ -@erase "$(INTDIR)\clistmod.obj"
+ -@erase "$(INTDIR)\clistmod.sbr"
+ -@erase "$(INTDIR)\clistsettings.obj"
+ -@erase "$(INTDIR)\clistsettings.sbr"
+ -@erase "$(INTDIR)\clisttray.obj"
+ -@erase "$(INTDIR)\clisttray.sbr"
+ -@erase "$(INTDIR)\clui.obj"
+ -@erase "$(INTDIR)\clui.sbr"
+ -@erase "$(INTDIR)\cluiservices.obj"
+ -@erase "$(INTDIR)\cluiservices.sbr"
+ -@erase "$(INTDIR)\colourpicker.obj"
+ -@erase "$(INTDIR)\colourpicker.sbr"
+ -@erase "$(INTDIR)\commonheaders.obj"
+ -@erase "$(INTDIR)\commonheaders.sbr"
+ -@erase "$(INTDIR)\contact.obj"
+ -@erase "$(INTDIR)\contact.sbr"
+ -@erase "$(INTDIR)\contactinfo.obj"
+ -@erase "$(INTDIR)\contactinfo.sbr"
+ -@erase "$(INTDIR)\contacts.obj"
+ -@erase "$(INTDIR)\contacts.sbr"
+ -@erase "$(INTDIR)\database.obj"
+ -@erase "$(INTDIR)\database.sbr"
+ -@erase "$(INTDIR)\dbini.obj"
+ -@erase "$(INTDIR)\dbini.sbr"
+ -@erase "$(INTDIR)\dblists.obj"
+ -@erase "$(INTDIR)\dblists.sbr"
+ -@erase "$(INTDIR)\dbutils.obj"
+ -@erase "$(INTDIR)\dbutils.sbr"
+ -@erase "$(INTDIR)\descbutton.obj"
+ -@erase "$(INTDIR)\descbutton.sbr"
+ -@erase "$(INTDIR)\Docking.obj"
+ -@erase "$(INTDIR)\Docking.sbr"
+ -@erase "$(INTDIR)\email.obj"
+ -@erase "$(INTDIR)\email.sbr"
+ -@erase "$(INTDIR)\extracticon.obj"
+ -@erase "$(INTDIR)\extracticon.sbr"
+ -@erase "$(INTDIR)\file.obj"
+ -@erase "$(INTDIR)\file.sbr"
+ -@erase "$(INTDIR)\fileexistsdlg.obj"
+ -@erase "$(INTDIR)\fileexistsdlg.sbr"
+ -@erase "$(INTDIR)\fileopts.obj"
+ -@erase "$(INTDIR)\fileopts.sbr"
+ -@erase "$(INTDIR)\filerecvdlg.obj"
+ -@erase "$(INTDIR)\filerecvdlg.sbr"
+ -@erase "$(INTDIR)\filesenddlg.obj"
+ -@erase "$(INTDIR)\filesenddlg.sbr"
+ -@erase "$(INTDIR)\filexferdlg.obj"
+ -@erase "$(INTDIR)\filexferdlg.sbr"
+ -@erase "$(INTDIR)\filter.obj"
+ -@erase "$(INTDIR)\filter.sbr"
+ -@erase "$(INTDIR)\findadd.obj"
+ -@erase "$(INTDIR)\findadd.sbr"
+ -@erase "$(INTDIR)\FontOptions.obj"
+ -@erase "$(INTDIR)\FontOptions.sbr"
+ -@erase "$(INTDIR)\FontService.obj"
+ -@erase "$(INTDIR)\FontService.sbr"
+ -@erase "$(INTDIR)\ftmanager.obj"
+ -@erase "$(INTDIR)\ftmanager.sbr"
+ -@erase "$(INTDIR)\genmenu.obj"
+ -@erase "$(INTDIR)\genmenu.sbr"
+ -@erase "$(INTDIR)\genmenuopt.obj"
+ -@erase "$(INTDIR)\genmenuopt.sbr"
+ -@erase "$(INTDIR)\groups.obj"
+ -@erase "$(INTDIR)\groups.sbr"
+ -@erase "$(INTDIR)\headerbar.obj"
+ -@erase "$(INTDIR)\headerbar.sbr"
+ -@erase "$(INTDIR)\help.obj"
+ -@erase "$(INTDIR)\help.sbr"
+ -@erase "$(INTDIR)\history.obj"
+ -@erase "$(INTDIR)\history.sbr"
+ -@erase "$(INTDIR)\hotkeys.obj"
+ -@erase "$(INTDIR)\hotkeys.sbr"
+ -@erase "$(INTDIR)\hyperlink.obj"
+ -@erase "$(INTDIR)\hyperlink.sbr"
+ -@erase "$(INTDIR)\iconheader.obj"
+ -@erase "$(INTDIR)\iconheader.sbr"
+ -@erase "$(INTDIR)\idle.obj"
+ -@erase "$(INTDIR)\idle.sbr"
+ -@erase "$(INTDIR)\ignore.obj"
+ -@erase "$(INTDIR)\ignore.sbr"
+ -@erase "$(INTDIR)\imgconv.obj"
+ -@erase "$(INTDIR)\imgconv.sbr"
+ -@erase "$(INTDIR)\keyboard.obj"
+ -@erase "$(INTDIR)\keyboard.sbr"
+ -@erase "$(INTDIR)\langpack.obj"
+ -@erase "$(INTDIR)\langpack.sbr"
+ -@erase "$(INTDIR)\lpservices.obj"
+ -@erase "$(INTDIR)\lpservices.sbr"
+ -@erase "$(INTDIR)\md5.obj"
+ -@erase "$(INTDIR)\md5.sbr"
+ -@erase "$(INTDIR)\memory.obj"
+ -@erase "$(INTDIR)\memory.sbr"
+ -@erase "$(INTDIR)\miranda.obj"
+ -@erase "$(INTDIR)\miranda.sbr"
+ -@erase "$(INTDIR)\miranda32.pch"
+ -@erase "$(INTDIR)\modules.obj"
+ -@erase "$(INTDIR)\modules.sbr"
+ -@erase "$(INTDIR)\movetogroup.obj"
+ -@erase "$(INTDIR)\movetogroup.sbr"
+ -@erase "$(INTDIR)\netlib.obj"
+ -@erase "$(INTDIR)\netlib.sbr"
+ -@erase "$(INTDIR)\netlibautoproxy.obj"
+ -@erase "$(INTDIR)\netlibautoproxy.sbr"
+ -@erase "$(INTDIR)\netlibbind.obj"
+ -@erase "$(INTDIR)\netlibbind.sbr"
+ -@erase "$(INTDIR)\netlibhttp.obj"
+ -@erase "$(INTDIR)\netlibhttp.sbr"
+ -@erase "$(INTDIR)\netlibhttpproxy.obj"
+ -@erase "$(INTDIR)\netlibhttpproxy.sbr"
+ -@erase "$(INTDIR)\netliblog.obj"
+ -@erase "$(INTDIR)\netliblog.sbr"
+ -@erase "$(INTDIR)\netlibopenconn.obj"
+ -@erase "$(INTDIR)\netlibopenconn.sbr"
+ -@erase "$(INTDIR)\netlibopts.obj"
+ -@erase "$(INTDIR)\netlibopts.sbr"
+ -@erase "$(INTDIR)\netlibpktrecver.obj"
+ -@erase "$(INTDIR)\netlibpktrecver.sbr"
+ -@erase "$(INTDIR)\netlibsecurity.obj"
+ -@erase "$(INTDIR)\netlibsecurity.sbr"
+ -@erase "$(INTDIR)\netlibsock.obj"
+ -@erase "$(INTDIR)\netlibsock.sbr"
+ -@erase "$(INTDIR)\netlibssl.obj"
+ -@erase "$(INTDIR)\netlibssl.sbr"
+ -@erase "$(INTDIR)\netlibupnp.obj"
+ -@erase "$(INTDIR)\netlibupnp.sbr"
+ -@erase "$(INTDIR)\newplugins.obj"
+ -@erase "$(INTDIR)\newplugins.sbr"
+ -@erase "$(INTDIR)\openurl.obj"
+ -@erase "$(INTDIR)\openurl.sbr"
+ -@erase "$(INTDIR)\options.obj"
+ -@erase "$(INTDIR)\options.sbr"
+ -@erase "$(INTDIR)\path.obj"
+ -@erase "$(INTDIR)\path.sbr"
+ -@erase "$(INTDIR)\profilemanager.obj"
+ -@erase "$(INTDIR)\profilemanager.sbr"
+ -@erase "$(INTDIR)\protoaccs.obj"
+ -@erase "$(INTDIR)\protoaccs.sbr"
+ -@erase "$(INTDIR)\protochains.obj"
+ -@erase "$(INTDIR)\protochains.sbr"
+ -@erase "$(INTDIR)\protocolorder.obj"
+ -@erase "$(INTDIR)\protocolorder.sbr"
+ -@erase "$(INTDIR)\protocols.obj"
+ -@erase "$(INTDIR)\protocols.sbr"
+ -@erase "$(INTDIR)\protoint.obj"
+ -@erase "$(INTDIR)\protoint.sbr"
+ -@erase "$(INTDIR)\protoopts.obj"
+ -@erase "$(INTDIR)\protoopts.sbr"
+ -@erase "$(INTDIR)\resizer.obj"
+ -@erase "$(INTDIR)\resizer.sbr"
+ -@erase "$(INTDIR)\searchresults.obj"
+ -@erase "$(INTDIR)\searchresults.sbr"
+ -@erase "$(INTDIR)\sendmsg.obj"
+ -@erase "$(INTDIR)\sendmsg.sbr"
+ -@erase "$(INTDIR)\services.obj"
+ -@erase "$(INTDIR)\services.sbr"
+ -@erase "$(INTDIR)\sha1.obj"
+ -@erase "$(INTDIR)\sha1.sbr"
+ -@erase "$(INTDIR)\skin2icons.obj"
+ -@erase "$(INTDIR)\skin2icons.sbr"
+ -@erase "$(INTDIR)\skinicons.obj"
+ -@erase "$(INTDIR)\skinicons.sbr"
+ -@erase "$(INTDIR)\sounds.obj"
+ -@erase "$(INTDIR)\sounds.sbr"
+ -@erase "$(INTDIR)\stdinfo.obj"
+ -@erase "$(INTDIR)\stdinfo.sbr"
+ -@erase "$(INTDIR)\timeutils.obj"
+ -@erase "$(INTDIR)\timeutils.sbr"
+ -@erase "$(INTDIR)\timezones.obj"
+ -@erase "$(INTDIR)\timezones.sbr"
+ -@erase "$(INTDIR)\updatenotify.obj"
+ -@erase "$(INTDIR)\updatenotify.sbr"
+ -@erase "$(INTDIR)\url.obj"
+ -@erase "$(INTDIR)\url.sbr"
+ -@erase "$(INTDIR)\urldialogs.obj"
+ -@erase "$(INTDIR)\urldialogs.sbr"
+ -@erase "$(INTDIR)\userinfo.obj"
+ -@erase "$(INTDIR)\userinfo.sbr"
+ -@erase "$(INTDIR)\useronline.obj"
+ -@erase "$(INTDIR)\useronline.sbr"
+ -@erase "$(INTDIR)\utf.obj"
+ -@erase "$(INTDIR)\utf.sbr"
+ -@erase "$(INTDIR)\utils.obj"
+ -@erase "$(INTDIR)\utils.sbr"
+ -@erase "$(INTDIR)\vc6.res"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(INTDIR)\vc60.pdb"
+ -@erase "$(INTDIR)\visibility.obj"
+ -@erase "$(INTDIR)\visibility.sbr"
+ -@erase "$(INTDIR)\windowlist.obj"
+ -@erase "$(INTDIR)\windowlist.sbr"
+ -@erase "$(INTDIR)\xmlApi.obj"
+ -@erase "$(INTDIR)\xmlApi.sbr"
+ -@erase "$(INTDIR)\xmlParser.obj"
+ -@erase "$(INTDIR)\xmlParser.sbr"
+ -@erase "$(OUTDIR)\miranda32.bsc"
+ -@erase "$(OUTDIR)\miranda32.pdb"
+ -@erase "..\bin\debug\miranda32.exe"
+ -@erase "..\bin\debug\miranda32.ilk"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MDd /W3 /Gm /ZI /Od /I "../include" /I "../include/msapi" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_NOSDK" /D "_STATIC" /Fr"$(INTDIR)\\" /Fp"$(INTDIR)\miranda32.pch" /Yu"commonheaders.h" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+MTL=midl.exe
+MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\vc6.res" /i "../include" /d "_DEBUG"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\miranda32.bsc"
+BSC32_SBRS= \
+ "$(INTDIR)\commonheaders.sbr" \
+ "$(INTDIR)\memory.sbr" \
+ "$(INTDIR)\miranda.sbr" \
+ "$(INTDIR)\modules.sbr" \
+ "$(INTDIR)\addcontact.sbr" \
+ "$(INTDIR)\autoaway.sbr" \
+ "$(INTDIR)\button.sbr" \
+ "$(INTDIR)\contacts.sbr" \
+ "$(INTDIR)\database.sbr" \
+ "$(INTDIR)\dbini.sbr" \
+ "$(INTDIR)\dblists.sbr" \
+ "$(INTDIR)\dbutils.sbr" \
+ "$(INTDIR)\profilemanager.sbr" \
+ "$(INTDIR)\findadd.sbr" \
+ "$(INTDIR)\searchresults.sbr" \
+ "$(INTDIR)\about.sbr" \
+ "$(INTDIR)\help.sbr" \
+ "$(INTDIR)\history.sbr" \
+ "$(INTDIR)\idle.sbr" \
+ "$(INTDIR)\ignore.sbr" \
+ "$(INTDIR)\langpack.sbr" \
+ "$(INTDIR)\lpservices.sbr" \
+ "$(INTDIR)\netlib.sbr" \
+ "$(INTDIR)\netlibautoproxy.sbr" \
+ "$(INTDIR)\netlibbind.sbr" \
+ "$(INTDIR)\netlibhttp.sbr" \
+ "$(INTDIR)\netlibhttpproxy.sbr" \
+ "$(INTDIR)\netliblog.sbr" \
+ "$(INTDIR)\netlibopenconn.sbr" \
+ "$(INTDIR)\netlibopts.sbr" \
+ "$(INTDIR)\netlibpktrecver.sbr" \
+ "$(INTDIR)\netlibsecurity.sbr" \
+ "$(INTDIR)\netlibsock.sbr" \
+ "$(INTDIR)\netlibssl.sbr" \
+ "$(INTDIR)\netlibupnp.sbr" \
+ "$(INTDIR)\descbutton.sbr" \
+ "$(INTDIR)\filter.sbr" \
+ "$(INTDIR)\headerbar.sbr" \
+ "$(INTDIR)\iconheader.sbr" \
+ "$(INTDIR)\options.sbr" \
+ "$(INTDIR)\newplugins.sbr" \
+ "$(INTDIR)\protoaccs.sbr" \
+ "$(INTDIR)\protochains.sbr" \
+ "$(INTDIR)\protocols.sbr" \
+ "$(INTDIR)\protoint.sbr" \
+ "$(INTDIR)\protoopts.sbr" \
+ "$(INTDIR)\hotkeys.sbr" \
+ "$(INTDIR)\skinicons.sbr" \
+ "$(INTDIR)\sounds.sbr" \
+ "$(INTDIR)\auth.sbr" \
+ "$(INTDIR)\authdialogs.sbr" \
+ "$(INTDIR)\awaymsg.sbr" \
+ "$(INTDIR)\sendmsg.sbr" \
+ "$(INTDIR)\email.sbr" \
+ "$(INTDIR)\file.sbr" \
+ "$(INTDIR)\fileexistsdlg.sbr" \
+ "$(INTDIR)\fileopts.sbr" \
+ "$(INTDIR)\filerecvdlg.sbr" \
+ "$(INTDIR)\filesenddlg.sbr" \
+ "$(INTDIR)\filexferdlg.sbr" \
+ "$(INTDIR)\ftmanager.sbr" \
+ "$(INTDIR)\url.sbr" \
+ "$(INTDIR)\urldialogs.sbr" \
+ "$(INTDIR)\contactinfo.sbr" \
+ "$(INTDIR)\stdinfo.sbr" \
+ "$(INTDIR)\userinfo.sbr" \
+ "$(INTDIR)\useronline.sbr" \
+ "$(INTDIR)\bmpfilter.sbr" \
+ "$(INTDIR)\colourpicker.sbr" \
+ "$(INTDIR)\hyperlink.sbr" \
+ "$(INTDIR)\imgconv.sbr" \
+ "$(INTDIR)\md5.sbr" \
+ "$(INTDIR)\openurl.sbr" \
+ "$(INTDIR)\path.sbr" \
+ "$(INTDIR)\resizer.sbr" \
+ "$(INTDIR)\sha1.sbr" \
+ "$(INTDIR)\timeutils.sbr" \
+ "$(INTDIR)\timezones.sbr" \
+ "$(INTDIR)\utf.sbr" \
+ "$(INTDIR)\utils.sbr" \
+ "$(INTDIR)\windowlist.sbr" \
+ "$(INTDIR)\visibility.sbr" \
+ "$(INTDIR)\clc.sbr" \
+ "$(INTDIR)\clcfiledrop.sbr" \
+ "$(INTDIR)\clcidents.sbr" \
+ "$(INTDIR)\clcitems.sbr" \
+ "$(INTDIR)\clcmsgs.sbr" \
+ "$(INTDIR)\clcutils.sbr" \
+ "$(INTDIR)\clistcore.sbr" \
+ "$(INTDIR)\clistevents.sbr" \
+ "$(INTDIR)\clistmenus.sbr" \
+ "$(INTDIR)\clistmod.sbr" \
+ "$(INTDIR)\clistsettings.sbr" \
+ "$(INTDIR)\clisttray.sbr" \
+ "$(INTDIR)\clui.sbr" \
+ "$(INTDIR)\cluiservices.sbr" \
+ "$(INTDIR)\contact.sbr" \
+ "$(INTDIR)\Docking.sbr" \
+ "$(INTDIR)\genmenu.sbr" \
+ "$(INTDIR)\genmenuopt.sbr" \
+ "$(INTDIR)\groups.sbr" \
+ "$(INTDIR)\keyboard.sbr" \
+ "$(INTDIR)\movetogroup.sbr" \
+ "$(INTDIR)\protocolorder.sbr" \
+ "$(INTDIR)\FontOptions.sbr" \
+ "$(INTDIR)\FontService.sbr" \
+ "$(INTDIR)\services.sbr" \
+ "$(INTDIR)\extracticon.sbr" \
+ "$(INTDIR)\skin2icons.sbr" \
+ "$(INTDIR)\updatenotify.sbr" \
+ "$(INTDIR)\xmlApi.sbr" \
+ "$(INTDIR)\xmlParser.sbr"
+
+"$(OUTDIR)\miranda32.bsc" : "$(OUTDIR)" $(BSC32_SBRS)
+ $(BSC32) @<<
+ $(BSC32_FLAGS) $(BSC32_SBRS)
+<<
+
+LINK32=link.exe
+LINK32_FLAGS=ws2_32.lib kernel32.lib user32.lib gdi32.lib shell32.lib comdlg32.lib advapi32.lib ole32.lib oleaut32.lib uuid.lib comctl32.lib winmm.lib version.lib crypt32.lib /nologo /subsystem:windows /incremental:yes /pdb:"$(OUTDIR)\miranda32.pdb" /debug /machine:I386 /out:"../bin/debug/miranda32.exe"
+LINK32_OBJS= \
+ "$(INTDIR)\commonheaders.obj" \
+ "$(INTDIR)\memory.obj" \
+ "$(INTDIR)\miranda.obj" \
+ "$(INTDIR)\modules.obj" \
+ "$(INTDIR)\addcontact.obj" \
+ "$(INTDIR)\autoaway.obj" \
+ "$(INTDIR)\button.obj" \
+ "$(INTDIR)\contacts.obj" \
+ "$(INTDIR)\database.obj" \
+ "$(INTDIR)\dbini.obj" \
+ "$(INTDIR)\dblists.obj" \
+ "$(INTDIR)\dbutils.obj" \
+ "$(INTDIR)\profilemanager.obj" \
+ "$(INTDIR)\findadd.obj" \
+ "$(INTDIR)\searchresults.obj" \
+ "$(INTDIR)\about.obj" \
+ "$(INTDIR)\help.obj" \
+ "$(INTDIR)\history.obj" \
+ "$(INTDIR)\idle.obj" \
+ "$(INTDIR)\ignore.obj" \
+ "$(INTDIR)\langpack.obj" \
+ "$(INTDIR)\lpservices.obj" \
+ "$(INTDIR)\netlib.obj" \
+ "$(INTDIR)\netlibautoproxy.obj" \
+ "$(INTDIR)\netlibbind.obj" \
+ "$(INTDIR)\netlibhttp.obj" \
+ "$(INTDIR)\netlibhttpproxy.obj" \
+ "$(INTDIR)\netliblog.obj" \
+ "$(INTDIR)\netlibopenconn.obj" \
+ "$(INTDIR)\netlibopts.obj" \
+ "$(INTDIR)\netlibpktrecver.obj" \
+ "$(INTDIR)\netlibsecurity.obj" \
+ "$(INTDIR)\netlibsock.obj" \
+ "$(INTDIR)\netlibssl.obj" \
+ "$(INTDIR)\netlibupnp.obj" \
+ "$(INTDIR)\descbutton.obj" \
+ "$(INTDIR)\filter.obj" \
+ "$(INTDIR)\headerbar.obj" \
+ "$(INTDIR)\iconheader.obj" \
+ "$(INTDIR)\options.obj" \
+ "$(INTDIR)\newplugins.obj" \
+ "$(INTDIR)\protoaccs.obj" \
+ "$(INTDIR)\protochains.obj" \
+ "$(INTDIR)\protocols.obj" \
+ "$(INTDIR)\protoint.obj" \
+ "$(INTDIR)\protoopts.obj" \
+ "$(INTDIR)\hotkeys.obj" \
+ "$(INTDIR)\skinicons.obj" \
+ "$(INTDIR)\sounds.obj" \
+ "$(INTDIR)\auth.obj" \
+ "$(INTDIR)\authdialogs.obj" \
+ "$(INTDIR)\awaymsg.obj" \
+ "$(INTDIR)\sendmsg.obj" \
+ "$(INTDIR)\email.obj" \
+ "$(INTDIR)\file.obj" \
+ "$(INTDIR)\fileexistsdlg.obj" \
+ "$(INTDIR)\fileopts.obj" \
+ "$(INTDIR)\filerecvdlg.obj" \
+ "$(INTDIR)\filesenddlg.obj" \
+ "$(INTDIR)\filexferdlg.obj" \
+ "$(INTDIR)\ftmanager.obj" \
+ "$(INTDIR)\url.obj" \
+ "$(INTDIR)\urldialogs.obj" \
+ "$(INTDIR)\contactinfo.obj" \
+ "$(INTDIR)\stdinfo.obj" \
+ "$(INTDIR)\userinfo.obj" \
+ "$(INTDIR)\useronline.obj" \
+ "$(INTDIR)\bmpfilter.obj" \
+ "$(INTDIR)\colourpicker.obj" \
+ "$(INTDIR)\hyperlink.obj" \
+ "$(INTDIR)\imgconv.obj" \
+ "$(INTDIR)\md5.obj" \
+ "$(INTDIR)\openurl.obj" \
+ "$(INTDIR)\path.obj" \
+ "$(INTDIR)\resizer.obj" \
+ "$(INTDIR)\sha1.obj" \
+ "$(INTDIR)\timeutils.obj" \
+ "$(INTDIR)\timezones.obj" \
+ "$(INTDIR)\utf.obj" \
+ "$(INTDIR)\utils.obj" \
+ "$(INTDIR)\windowlist.obj" \
+ "$(INTDIR)\visibility.obj" \
+ "$(INTDIR)\clc.obj" \
+ "$(INTDIR)\clcfiledrop.obj" \
+ "$(INTDIR)\clcidents.obj" \
+ "$(INTDIR)\clcitems.obj" \
+ "$(INTDIR)\clcmsgs.obj" \
+ "$(INTDIR)\clcutils.obj" \
+ "$(INTDIR)\clistcore.obj" \
+ "$(INTDIR)\clistevents.obj" \
+ "$(INTDIR)\clistmenus.obj" \
+ "$(INTDIR)\clistmod.obj" \
+ "$(INTDIR)\clistsettings.obj" \
+ "$(INTDIR)\clisttray.obj" \
+ "$(INTDIR)\clui.obj" \
+ "$(INTDIR)\cluiservices.obj" \
+ "$(INTDIR)\contact.obj" \
+ "$(INTDIR)\Docking.obj" \
+ "$(INTDIR)\genmenu.obj" \
+ "$(INTDIR)\genmenuopt.obj" \
+ "$(INTDIR)\groups.obj" \
+ "$(INTDIR)\keyboard.obj" \
+ "$(INTDIR)\movetogroup.obj" \
+ "$(INTDIR)\protocolorder.obj" \
+ "$(INTDIR)\FontOptions.obj" \
+ "$(INTDIR)\FontService.obj" \
+ "$(INTDIR)\services.obj" \
+ "$(INTDIR)\extracticon.obj" \
+ "$(INTDIR)\skin2icons.obj" \
+ "$(INTDIR)\updatenotify.obj" \
+ "$(INTDIR)\xmlApi.obj" \
+ "$(INTDIR)\xmlParser.obj" \
+ "$(INTDIR)\vc6.res" \
+ "..\plugins\zlib\Debug\zlib.lib"
+
+"..\bin\debug\miranda32.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "miranda32 - Win32 Release Unicode"
+
+OUTDIR=.\Release_Unicode
+INTDIR=.\Release_Unicode
+# Begin Custom Macros
+OutDir=.\Release_Unicode
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "..\bin\Release Unicode\miranda32.exe" "$(OUTDIR)\miranda32.bsc"
+
+!ELSE
+
+ALL : "zlib - Win32 Release Unicode" "..\bin\Release Unicode\miranda32.exe" "$(OUTDIR)\miranda32.bsc"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"zlib - Win32 Release UnicodeCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\about.obj"
+ -@erase "$(INTDIR)\about.sbr"
+ -@erase "$(INTDIR)\addcontact.obj"
+ -@erase "$(INTDIR)\addcontact.sbr"
+ -@erase "$(INTDIR)\auth.obj"
+ -@erase "$(INTDIR)\auth.sbr"
+ -@erase "$(INTDIR)\authdialogs.obj"
+ -@erase "$(INTDIR)\authdialogs.sbr"
+ -@erase "$(INTDIR)\autoaway.obj"
+ -@erase "$(INTDIR)\autoaway.sbr"
+ -@erase "$(INTDIR)\awaymsg.obj"
+ -@erase "$(INTDIR)\awaymsg.sbr"
+ -@erase "$(INTDIR)\bmpfilter.obj"
+ -@erase "$(INTDIR)\bmpfilter.sbr"
+ -@erase "$(INTDIR)\button.obj"
+ -@erase "$(INTDIR)\button.sbr"
+ -@erase "$(INTDIR)\clc.obj"
+ -@erase "$(INTDIR)\clc.sbr"
+ -@erase "$(INTDIR)\clcfiledrop.obj"
+ -@erase "$(INTDIR)\clcfiledrop.sbr"
+ -@erase "$(INTDIR)\clcidents.obj"
+ -@erase "$(INTDIR)\clcidents.sbr"
+ -@erase "$(INTDIR)\clcitems.obj"
+ -@erase "$(INTDIR)\clcitems.sbr"
+ -@erase "$(INTDIR)\clcmsgs.obj"
+ -@erase "$(INTDIR)\clcmsgs.sbr"
+ -@erase "$(INTDIR)\clcutils.obj"
+ -@erase "$(INTDIR)\clcutils.sbr"
+ -@erase "$(INTDIR)\clistcore.obj"
+ -@erase "$(INTDIR)\clistcore.sbr"
+ -@erase "$(INTDIR)\clistevents.obj"
+ -@erase "$(INTDIR)\clistevents.sbr"
+ -@erase "$(INTDIR)\clistmenus.obj"
+ -@erase "$(INTDIR)\clistmenus.sbr"
+ -@erase "$(INTDIR)\clistmod.obj"
+ -@erase "$(INTDIR)\clistmod.sbr"
+ -@erase "$(INTDIR)\clistsettings.obj"
+ -@erase "$(INTDIR)\clistsettings.sbr"
+ -@erase "$(INTDIR)\clisttray.obj"
+ -@erase "$(INTDIR)\clisttray.sbr"
+ -@erase "$(INTDIR)\clui.obj"
+ -@erase "$(INTDIR)\clui.sbr"
+ -@erase "$(INTDIR)\cluiservices.obj"
+ -@erase "$(INTDIR)\cluiservices.sbr"
+ -@erase "$(INTDIR)\colourpicker.obj"
+ -@erase "$(INTDIR)\colourpicker.sbr"
+ -@erase "$(INTDIR)\commonheaders.obj"
+ -@erase "$(INTDIR)\commonheaders.sbr"
+ -@erase "$(INTDIR)\contact.obj"
+ -@erase "$(INTDIR)\contact.sbr"
+ -@erase "$(INTDIR)\contactinfo.obj"
+ -@erase "$(INTDIR)\contactinfo.sbr"
+ -@erase "$(INTDIR)\contacts.obj"
+ -@erase "$(INTDIR)\contacts.sbr"
+ -@erase "$(INTDIR)\database.obj"
+ -@erase "$(INTDIR)\database.sbr"
+ -@erase "$(INTDIR)\dbini.obj"
+ -@erase "$(INTDIR)\dbini.sbr"
+ -@erase "$(INTDIR)\dblists.obj"
+ -@erase "$(INTDIR)\dblists.sbr"
+ -@erase "$(INTDIR)\dbutils.obj"
+ -@erase "$(INTDIR)\dbutils.sbr"
+ -@erase "$(INTDIR)\descbutton.obj"
+ -@erase "$(INTDIR)\descbutton.sbr"
+ -@erase "$(INTDIR)\Docking.obj"
+ -@erase "$(INTDIR)\Docking.sbr"
+ -@erase "$(INTDIR)\email.obj"
+ -@erase "$(INTDIR)\email.sbr"
+ -@erase "$(INTDIR)\extracticon.obj"
+ -@erase "$(INTDIR)\extracticon.sbr"
+ -@erase "$(INTDIR)\file.obj"
+ -@erase "$(INTDIR)\file.sbr"
+ -@erase "$(INTDIR)\fileexistsdlg.obj"
+ -@erase "$(INTDIR)\fileexistsdlg.sbr"
+ -@erase "$(INTDIR)\fileopts.obj"
+ -@erase "$(INTDIR)\fileopts.sbr"
+ -@erase "$(INTDIR)\filerecvdlg.obj"
+ -@erase "$(INTDIR)\filerecvdlg.sbr"
+ -@erase "$(INTDIR)\filesenddlg.obj"
+ -@erase "$(INTDIR)\filesenddlg.sbr"
+ -@erase "$(INTDIR)\filexferdlg.obj"
+ -@erase "$(INTDIR)\filexferdlg.sbr"
+ -@erase "$(INTDIR)\filter.obj"
+ -@erase "$(INTDIR)\filter.sbr"
+ -@erase "$(INTDIR)\findadd.obj"
+ -@erase "$(INTDIR)\findadd.sbr"
+ -@erase "$(INTDIR)\FontOptions.obj"
+ -@erase "$(INTDIR)\FontOptions.sbr"
+ -@erase "$(INTDIR)\FontService.obj"
+ -@erase "$(INTDIR)\FontService.sbr"
+ -@erase "$(INTDIR)\ftmanager.obj"
+ -@erase "$(INTDIR)\ftmanager.sbr"
+ -@erase "$(INTDIR)\genmenu.obj"
+ -@erase "$(INTDIR)\genmenu.sbr"
+ -@erase "$(INTDIR)\genmenuopt.obj"
+ -@erase "$(INTDIR)\genmenuopt.sbr"
+ -@erase "$(INTDIR)\groups.obj"
+ -@erase "$(INTDIR)\groups.sbr"
+ -@erase "$(INTDIR)\headerbar.obj"
+ -@erase "$(INTDIR)\headerbar.sbr"
+ -@erase "$(INTDIR)\help.obj"
+ -@erase "$(INTDIR)\help.sbr"
+ -@erase "$(INTDIR)\history.obj"
+ -@erase "$(INTDIR)\history.sbr"
+ -@erase "$(INTDIR)\hotkeys.obj"
+ -@erase "$(INTDIR)\hotkeys.sbr"
+ -@erase "$(INTDIR)\hyperlink.obj"
+ -@erase "$(INTDIR)\hyperlink.sbr"
+ -@erase "$(INTDIR)\iconheader.obj"
+ -@erase "$(INTDIR)\iconheader.sbr"
+ -@erase "$(INTDIR)\idle.obj"
+ -@erase "$(INTDIR)\idle.sbr"
+ -@erase "$(INTDIR)\ignore.obj"
+ -@erase "$(INTDIR)\ignore.sbr"
+ -@erase "$(INTDIR)\imgconv.obj"
+ -@erase "$(INTDIR)\imgconv.sbr"
+ -@erase "$(INTDIR)\keyboard.obj"
+ -@erase "$(INTDIR)\keyboard.sbr"
+ -@erase "$(INTDIR)\langpack.obj"
+ -@erase "$(INTDIR)\langpack.sbr"
+ -@erase "$(INTDIR)\lpservices.obj"
+ -@erase "$(INTDIR)\lpservices.sbr"
+ -@erase "$(INTDIR)\md5.obj"
+ -@erase "$(INTDIR)\md5.sbr"
+ -@erase "$(INTDIR)\memory.obj"
+ -@erase "$(INTDIR)\memory.sbr"
+ -@erase "$(INTDIR)\miranda.obj"
+ -@erase "$(INTDIR)\miranda.sbr"
+ -@erase "$(INTDIR)\miranda32.pch"
+ -@erase "$(INTDIR)\modules.obj"
+ -@erase "$(INTDIR)\modules.sbr"
+ -@erase "$(INTDIR)\movetogroup.obj"
+ -@erase "$(INTDIR)\movetogroup.sbr"
+ -@erase "$(INTDIR)\netlib.obj"
+ -@erase "$(INTDIR)\netlib.sbr"
+ -@erase "$(INTDIR)\netlibautoproxy.obj"
+ -@erase "$(INTDIR)\netlibautoproxy.sbr"
+ -@erase "$(INTDIR)\netlibbind.obj"
+ -@erase "$(INTDIR)\netlibbind.sbr"
+ -@erase "$(INTDIR)\netlibhttp.obj"
+ -@erase "$(INTDIR)\netlibhttp.sbr"
+ -@erase "$(INTDIR)\netlibhttpproxy.obj"
+ -@erase "$(INTDIR)\netlibhttpproxy.sbr"
+ -@erase "$(INTDIR)\netliblog.obj"
+ -@erase "$(INTDIR)\netliblog.sbr"
+ -@erase "$(INTDIR)\netlibopenconn.obj"
+ -@erase "$(INTDIR)\netlibopenconn.sbr"
+ -@erase "$(INTDIR)\netlibopts.obj"
+ -@erase "$(INTDIR)\netlibopts.sbr"
+ -@erase "$(INTDIR)\netlibpktrecver.obj"
+ -@erase "$(INTDIR)\netlibpktrecver.sbr"
+ -@erase "$(INTDIR)\netlibsecurity.obj"
+ -@erase "$(INTDIR)\netlibsecurity.sbr"
+ -@erase "$(INTDIR)\netlibsock.obj"
+ -@erase "$(INTDIR)\netlibsock.sbr"
+ -@erase "$(INTDIR)\netlibssl.obj"
+ -@erase "$(INTDIR)\netlibssl.sbr"
+ -@erase "$(INTDIR)\netlibupnp.obj"
+ -@erase "$(INTDIR)\netlibupnp.sbr"
+ -@erase "$(INTDIR)\newplugins.obj"
+ -@erase "$(INTDIR)\newplugins.sbr"
+ -@erase "$(INTDIR)\openurl.obj"
+ -@erase "$(INTDIR)\openurl.sbr"
+ -@erase "$(INTDIR)\options.obj"
+ -@erase "$(INTDIR)\options.sbr"
+ -@erase "$(INTDIR)\path.obj"
+ -@erase "$(INTDIR)\path.sbr"
+ -@erase "$(INTDIR)\profilemanager.obj"
+ -@erase "$(INTDIR)\profilemanager.sbr"
+ -@erase "$(INTDIR)\protoaccs.obj"
+ -@erase "$(INTDIR)\protoaccs.sbr"
+ -@erase "$(INTDIR)\protochains.obj"
+ -@erase "$(INTDIR)\protochains.sbr"
+ -@erase "$(INTDIR)\protocolorder.obj"
+ -@erase "$(INTDIR)\protocolorder.sbr"
+ -@erase "$(INTDIR)\protocols.obj"
+ -@erase "$(INTDIR)\protocols.sbr"
+ -@erase "$(INTDIR)\protoint.obj"
+ -@erase "$(INTDIR)\protoint.sbr"
+ -@erase "$(INTDIR)\protoopts.obj"
+ -@erase "$(INTDIR)\protoopts.sbr"
+ -@erase "$(INTDIR)\resizer.obj"
+ -@erase "$(INTDIR)\resizer.sbr"
+ -@erase "$(INTDIR)\searchresults.obj"
+ -@erase "$(INTDIR)\searchresults.sbr"
+ -@erase "$(INTDIR)\sendmsg.obj"
+ -@erase "$(INTDIR)\sendmsg.sbr"
+ -@erase "$(INTDIR)\services.obj"
+ -@erase "$(INTDIR)\services.sbr"
+ -@erase "$(INTDIR)\sha1.obj"
+ -@erase "$(INTDIR)\sha1.sbr"
+ -@erase "$(INTDIR)\skin2icons.obj"
+ -@erase "$(INTDIR)\skin2icons.sbr"
+ -@erase "$(INTDIR)\skinicons.obj"
+ -@erase "$(INTDIR)\skinicons.sbr"
+ -@erase "$(INTDIR)\sounds.obj"
+ -@erase "$(INTDIR)\sounds.sbr"
+ -@erase "$(INTDIR)\stdinfo.obj"
+ -@erase "$(INTDIR)\stdinfo.sbr"
+ -@erase "$(INTDIR)\timeutils.obj"
+ -@erase "$(INTDIR)\timeutils.sbr"
+ -@erase "$(INTDIR)\timezones.obj"
+ -@erase "$(INTDIR)\timezones.sbr"
+ -@erase "$(INTDIR)\updatenotify.obj"
+ -@erase "$(INTDIR)\updatenotify.sbr"
+ -@erase "$(INTDIR)\url.obj"
+ -@erase "$(INTDIR)\url.sbr"
+ -@erase "$(INTDIR)\urldialogs.obj"
+ -@erase "$(INTDIR)\urldialogs.sbr"
+ -@erase "$(INTDIR)\userinfo.obj"
+ -@erase "$(INTDIR)\userinfo.sbr"
+ -@erase "$(INTDIR)\useronline.obj"
+ -@erase "$(INTDIR)\useronline.sbr"
+ -@erase "$(INTDIR)\utf.obj"
+ -@erase "$(INTDIR)\utf.sbr"
+ -@erase "$(INTDIR)\utils.obj"
+ -@erase "$(INTDIR)\utils.sbr"
+ -@erase "$(INTDIR)\vc6.res"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(INTDIR)\vc60.pdb"
+ -@erase "$(INTDIR)\visibility.obj"
+ -@erase "$(INTDIR)\visibility.sbr"
+ -@erase "$(INTDIR)\windowlist.obj"
+ -@erase "$(INTDIR)\windowlist.sbr"
+ -@erase "$(INTDIR)\xmlApi.obj"
+ -@erase "$(INTDIR)\xmlApi.sbr"
+ -@erase "$(INTDIR)\xmlParser.obj"
+ -@erase "$(INTDIR)\xmlParser.sbr"
+ -@erase "$(OUTDIR)\miranda32.bsc"
+ -@erase "$(OUTDIR)\miranda32.pdb"
+ -@erase "..\bin\Release Unicode\miranda32.exe"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MD /W3 /Zi /O1 /I "../include/msapi" /I "../include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_NOSDK" /D "UNICODE" /D "_STATIC" /Fr"$(INTDIR)\\" /Fp"$(INTDIR)\miranda32.pch" /Yu"commonheaders.h" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+MTL=midl.exe
+MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\vc6.res" /i "../include" /d "NDEBUG"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\miranda32.bsc"
+BSC32_SBRS= \
+ "$(INTDIR)\commonheaders.sbr" \
+ "$(INTDIR)\memory.sbr" \
+ "$(INTDIR)\miranda.sbr" \
+ "$(INTDIR)\modules.sbr" \
+ "$(INTDIR)\addcontact.sbr" \
+ "$(INTDIR)\autoaway.sbr" \
+ "$(INTDIR)\button.sbr" \
+ "$(INTDIR)\contacts.sbr" \
+ "$(INTDIR)\database.sbr" \
+ "$(INTDIR)\dbini.sbr" \
+ "$(INTDIR)\dblists.sbr" \
+ "$(INTDIR)\dbutils.sbr" \
+ "$(INTDIR)\profilemanager.sbr" \
+ "$(INTDIR)\findadd.sbr" \
+ "$(INTDIR)\searchresults.sbr" \
+ "$(INTDIR)\about.sbr" \
+ "$(INTDIR)\help.sbr" \
+ "$(INTDIR)\history.sbr" \
+ "$(INTDIR)\idle.sbr" \
+ "$(INTDIR)\ignore.sbr" \
+ "$(INTDIR)\langpack.sbr" \
+ "$(INTDIR)\lpservices.sbr" \
+ "$(INTDIR)\netlib.sbr" \
+ "$(INTDIR)\netlibautoproxy.sbr" \
+ "$(INTDIR)\netlibbind.sbr" \
+ "$(INTDIR)\netlibhttp.sbr" \
+ "$(INTDIR)\netlibhttpproxy.sbr" \
+ "$(INTDIR)\netliblog.sbr" \
+ "$(INTDIR)\netlibopenconn.sbr" \
+ "$(INTDIR)\netlibopts.sbr" \
+ "$(INTDIR)\netlibpktrecver.sbr" \
+ "$(INTDIR)\netlibsecurity.sbr" \
+ "$(INTDIR)\netlibsock.sbr" \
+ "$(INTDIR)\netlibssl.sbr" \
+ "$(INTDIR)\netlibupnp.sbr" \
+ "$(INTDIR)\descbutton.sbr" \
+ "$(INTDIR)\filter.sbr" \
+ "$(INTDIR)\headerbar.sbr" \
+ "$(INTDIR)\iconheader.sbr" \
+ "$(INTDIR)\options.sbr" \
+ "$(INTDIR)\newplugins.sbr" \
+ "$(INTDIR)\protoaccs.sbr" \
+ "$(INTDIR)\protochains.sbr" \
+ "$(INTDIR)\protocols.sbr" \
+ "$(INTDIR)\protoint.sbr" \
+ "$(INTDIR)\protoopts.sbr" \
+ "$(INTDIR)\hotkeys.sbr" \
+ "$(INTDIR)\skinicons.sbr" \
+ "$(INTDIR)\sounds.sbr" \
+ "$(INTDIR)\auth.sbr" \
+ "$(INTDIR)\authdialogs.sbr" \
+ "$(INTDIR)\awaymsg.sbr" \
+ "$(INTDIR)\sendmsg.sbr" \
+ "$(INTDIR)\email.sbr" \
+ "$(INTDIR)\file.sbr" \
+ "$(INTDIR)\fileexistsdlg.sbr" \
+ "$(INTDIR)\fileopts.sbr" \
+ "$(INTDIR)\filerecvdlg.sbr" \
+ "$(INTDIR)\filesenddlg.sbr" \
+ "$(INTDIR)\filexferdlg.sbr" \
+ "$(INTDIR)\ftmanager.sbr" \
+ "$(INTDIR)\url.sbr" \
+ "$(INTDIR)\urldialogs.sbr" \
+ "$(INTDIR)\contactinfo.sbr" \
+ "$(INTDIR)\stdinfo.sbr" \
+ "$(INTDIR)\userinfo.sbr" \
+ "$(INTDIR)\useronline.sbr" \
+ "$(INTDIR)\bmpfilter.sbr" \
+ "$(INTDIR)\colourpicker.sbr" \
+ "$(INTDIR)\hyperlink.sbr" \
+ "$(INTDIR)\imgconv.sbr" \
+ "$(INTDIR)\md5.sbr" \
+ "$(INTDIR)\openurl.sbr" \
+ "$(INTDIR)\path.sbr" \
+ "$(INTDIR)\resizer.sbr" \
+ "$(INTDIR)\sha1.sbr" \
+ "$(INTDIR)\timeutils.sbr" \
+ "$(INTDIR)\timezones.sbr" \
+ "$(INTDIR)\utf.sbr" \
+ "$(INTDIR)\utils.sbr" \
+ "$(INTDIR)\windowlist.sbr" \
+ "$(INTDIR)\visibility.sbr" \
+ "$(INTDIR)\clc.sbr" \
+ "$(INTDIR)\clcfiledrop.sbr" \
+ "$(INTDIR)\clcidents.sbr" \
+ "$(INTDIR)\clcitems.sbr" \
+ "$(INTDIR)\clcmsgs.sbr" \
+ "$(INTDIR)\clcutils.sbr" \
+ "$(INTDIR)\clistcore.sbr" \
+ "$(INTDIR)\clistevents.sbr" \
+ "$(INTDIR)\clistmenus.sbr" \
+ "$(INTDIR)\clistmod.sbr" \
+ "$(INTDIR)\clistsettings.sbr" \
+ "$(INTDIR)\clisttray.sbr" \
+ "$(INTDIR)\clui.sbr" \
+ "$(INTDIR)\cluiservices.sbr" \
+ "$(INTDIR)\contact.sbr" \
+ "$(INTDIR)\Docking.sbr" \
+ "$(INTDIR)\genmenu.sbr" \
+ "$(INTDIR)\genmenuopt.sbr" \
+ "$(INTDIR)\groups.sbr" \
+ "$(INTDIR)\keyboard.sbr" \
+ "$(INTDIR)\movetogroup.sbr" \
+ "$(INTDIR)\protocolorder.sbr" \
+ "$(INTDIR)\FontOptions.sbr" \
+ "$(INTDIR)\FontService.sbr" \
+ "$(INTDIR)\services.sbr" \
+ "$(INTDIR)\extracticon.sbr" \
+ "$(INTDIR)\skin2icons.sbr" \
+ "$(INTDIR)\updatenotify.sbr" \
+ "$(INTDIR)\xmlApi.sbr" \
+ "$(INTDIR)\xmlParser.sbr"
+
+"$(OUTDIR)\miranda32.bsc" : "$(OUTDIR)" $(BSC32_SBRS)
+ $(BSC32) @<<
+ $(BSC32_FLAGS) $(BSC32_SBRS)
+<<
+
+LINK32=link.exe
+LINK32_FLAGS=ws2_32.lib kernel32.lib user32.lib gdi32.lib shell32.lib comdlg32.lib advapi32.lib ole32.lib oleaut32.lib uuid.lib comctl32.lib winmm.lib version.lib crypt32.lib /nologo /subsystem:windows /incremental:no /pdb:"$(OUTDIR)\miranda32.pdb" /debug /machine:I386 /out:"../bin/Release Unicode/miranda32.exe" /fixed /ALIGN:4096 /ignore:4108
+LINK32_OBJS= \
+ "$(INTDIR)\commonheaders.obj" \
+ "$(INTDIR)\memory.obj" \
+ "$(INTDIR)\miranda.obj" \
+ "$(INTDIR)\modules.obj" \
+ "$(INTDIR)\addcontact.obj" \
+ "$(INTDIR)\autoaway.obj" \
+ "$(INTDIR)\button.obj" \
+ "$(INTDIR)\contacts.obj" \
+ "$(INTDIR)\database.obj" \
+ "$(INTDIR)\dbini.obj" \
+ "$(INTDIR)\dblists.obj" \
+ "$(INTDIR)\dbutils.obj" \
+ "$(INTDIR)\profilemanager.obj" \
+ "$(INTDIR)\findadd.obj" \
+ "$(INTDIR)\searchresults.obj" \
+ "$(INTDIR)\about.obj" \
+ "$(INTDIR)\help.obj" \
+ "$(INTDIR)\history.obj" \
+ "$(INTDIR)\idle.obj" \
+ "$(INTDIR)\ignore.obj" \
+ "$(INTDIR)\langpack.obj" \
+ "$(INTDIR)\lpservices.obj" \
+ "$(INTDIR)\netlib.obj" \
+ "$(INTDIR)\netlibautoproxy.obj" \
+ "$(INTDIR)\netlibbind.obj" \
+ "$(INTDIR)\netlibhttp.obj" \
+ "$(INTDIR)\netlibhttpproxy.obj" \
+ "$(INTDIR)\netliblog.obj" \
+ "$(INTDIR)\netlibopenconn.obj" \
+ "$(INTDIR)\netlibopts.obj" \
+ "$(INTDIR)\netlibpktrecver.obj" \
+ "$(INTDIR)\netlibsecurity.obj" \
+ "$(INTDIR)\netlibsock.obj" \
+ "$(INTDIR)\netlibssl.obj" \
+ "$(INTDIR)\netlibupnp.obj" \
+ "$(INTDIR)\descbutton.obj" \
+ "$(INTDIR)\filter.obj" \
+ "$(INTDIR)\headerbar.obj" \
+ "$(INTDIR)\iconheader.obj" \
+ "$(INTDIR)\options.obj" \
+ "$(INTDIR)\newplugins.obj" \
+ "$(INTDIR)\protoaccs.obj" \
+ "$(INTDIR)\protochains.obj" \
+ "$(INTDIR)\protocols.obj" \
+ "$(INTDIR)\protoint.obj" \
+ "$(INTDIR)\protoopts.obj" \
+ "$(INTDIR)\hotkeys.obj" \
+ "$(INTDIR)\skinicons.obj" \
+ "$(INTDIR)\sounds.obj" \
+ "$(INTDIR)\auth.obj" \
+ "$(INTDIR)\authdialogs.obj" \
+ "$(INTDIR)\awaymsg.obj" \
+ "$(INTDIR)\sendmsg.obj" \
+ "$(INTDIR)\email.obj" \
+ "$(INTDIR)\file.obj" \
+ "$(INTDIR)\fileexistsdlg.obj" \
+ "$(INTDIR)\fileopts.obj" \
+ "$(INTDIR)\filerecvdlg.obj" \
+ "$(INTDIR)\filesenddlg.obj" \
+ "$(INTDIR)\filexferdlg.obj" \
+ "$(INTDIR)\ftmanager.obj" \
+ "$(INTDIR)\url.obj" \
+ "$(INTDIR)\urldialogs.obj" \
+ "$(INTDIR)\contactinfo.obj" \
+ "$(INTDIR)\stdinfo.obj" \
+ "$(INTDIR)\userinfo.obj" \
+ "$(INTDIR)\useronline.obj" \
+ "$(INTDIR)\bmpfilter.obj" \
+ "$(INTDIR)\colourpicker.obj" \
+ "$(INTDIR)\hyperlink.obj" \
+ "$(INTDIR)\imgconv.obj" \
+ "$(INTDIR)\md5.obj" \
+ "$(INTDIR)\openurl.obj" \
+ "$(INTDIR)\path.obj" \
+ "$(INTDIR)\resizer.obj" \
+ "$(INTDIR)\sha1.obj" \
+ "$(INTDIR)\timeutils.obj" \
+ "$(INTDIR)\timezones.obj" \
+ "$(INTDIR)\utf.obj" \
+ "$(INTDIR)\utils.obj" \
+ "$(INTDIR)\windowlist.obj" \
+ "$(INTDIR)\visibility.obj" \
+ "$(INTDIR)\clc.obj" \
+ "$(INTDIR)\clcfiledrop.obj" \
+ "$(INTDIR)\clcidents.obj" \
+ "$(INTDIR)\clcitems.obj" \
+ "$(INTDIR)\clcmsgs.obj" \
+ "$(INTDIR)\clcutils.obj" \
+ "$(INTDIR)\clistcore.obj" \
+ "$(INTDIR)\clistevents.obj" \
+ "$(INTDIR)\clistmenus.obj" \
+ "$(INTDIR)\clistmod.obj" \
+ "$(INTDIR)\clistsettings.obj" \
+ "$(INTDIR)\clisttray.obj" \
+ "$(INTDIR)\clui.obj" \
+ "$(INTDIR)\cluiservices.obj" \
+ "$(INTDIR)\contact.obj" \
+ "$(INTDIR)\Docking.obj" \
+ "$(INTDIR)\genmenu.obj" \
+ "$(INTDIR)\genmenuopt.obj" \
+ "$(INTDIR)\groups.obj" \
+ "$(INTDIR)\keyboard.obj" \
+ "$(INTDIR)\movetogroup.obj" \
+ "$(INTDIR)\protocolorder.obj" \
+ "$(INTDIR)\FontOptions.obj" \
+ "$(INTDIR)\FontService.obj" \
+ "$(INTDIR)\services.obj" \
+ "$(INTDIR)\extracticon.obj" \
+ "$(INTDIR)\skin2icons.obj" \
+ "$(INTDIR)\updatenotify.obj" \
+ "$(INTDIR)\xmlApi.obj" \
+ "$(INTDIR)\xmlParser.obj" \
+ "$(INTDIR)\vc6.res" \
+ "..\plugins\zlib\Release_Unicode\zlib.lib"
+
+"..\bin\Release Unicode\miranda32.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "miranda32 - Win32 Debug Unicode"
+
+OUTDIR=.\Debug_Unicode
+INTDIR=.\Debug_Unicode
+# Begin Custom Macros
+OutDir=.\Debug_Unicode
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "..\bin\Debug Unicode\miranda32.exe" "$(OUTDIR)\miranda32.bsc"
+
+!ELSE
+
+ALL : "zlib - Win32 Debug Unicode" "..\bin\Debug Unicode\miranda32.exe" "$(OUTDIR)\miranda32.bsc"
+
+!ENDIF
+
+!IF "$(RECURSE)" == "1"
+CLEAN :"zlib - Win32 Debug UnicodeCLEAN"
+!ELSE
+CLEAN :
+!ENDIF
+ -@erase "$(INTDIR)\about.obj"
+ -@erase "$(INTDIR)\about.sbr"
+ -@erase "$(INTDIR)\addcontact.obj"
+ -@erase "$(INTDIR)\addcontact.sbr"
+ -@erase "$(INTDIR)\auth.obj"
+ -@erase "$(INTDIR)\auth.sbr"
+ -@erase "$(INTDIR)\authdialogs.obj"
+ -@erase "$(INTDIR)\authdialogs.sbr"
+ -@erase "$(INTDIR)\autoaway.obj"
+ -@erase "$(INTDIR)\autoaway.sbr"
+ -@erase "$(INTDIR)\awaymsg.obj"
+ -@erase "$(INTDIR)\awaymsg.sbr"
+ -@erase "$(INTDIR)\bmpfilter.obj"
+ -@erase "$(INTDIR)\bmpfilter.sbr"
+ -@erase "$(INTDIR)\button.obj"
+ -@erase "$(INTDIR)\button.sbr"
+ -@erase "$(INTDIR)\clc.obj"
+ -@erase "$(INTDIR)\clc.sbr"
+ -@erase "$(INTDIR)\clcfiledrop.obj"
+ -@erase "$(INTDIR)\clcfiledrop.sbr"
+ -@erase "$(INTDIR)\clcidents.obj"
+ -@erase "$(INTDIR)\clcidents.sbr"
+ -@erase "$(INTDIR)\clcitems.obj"
+ -@erase "$(INTDIR)\clcitems.sbr"
+ -@erase "$(INTDIR)\clcmsgs.obj"
+ -@erase "$(INTDIR)\clcmsgs.sbr"
+ -@erase "$(INTDIR)\clcutils.obj"
+ -@erase "$(INTDIR)\clcutils.sbr"
+ -@erase "$(INTDIR)\clistcore.obj"
+ -@erase "$(INTDIR)\clistcore.sbr"
+ -@erase "$(INTDIR)\clistevents.obj"
+ -@erase "$(INTDIR)\clistevents.sbr"
+ -@erase "$(INTDIR)\clistmenus.obj"
+ -@erase "$(INTDIR)\clistmenus.sbr"
+ -@erase "$(INTDIR)\clistmod.obj"
+ -@erase "$(INTDIR)\clistmod.sbr"
+ -@erase "$(INTDIR)\clistsettings.obj"
+ -@erase "$(INTDIR)\clistsettings.sbr"
+ -@erase "$(INTDIR)\clisttray.obj"
+ -@erase "$(INTDIR)\clisttray.sbr"
+ -@erase "$(INTDIR)\clui.obj"
+ -@erase "$(INTDIR)\clui.sbr"
+ -@erase "$(INTDIR)\cluiservices.obj"
+ -@erase "$(INTDIR)\cluiservices.sbr"
+ -@erase "$(INTDIR)\colourpicker.obj"
+ -@erase "$(INTDIR)\colourpicker.sbr"
+ -@erase "$(INTDIR)\commonheaders.obj"
+ -@erase "$(INTDIR)\commonheaders.sbr"
+ -@erase "$(INTDIR)\contact.obj"
+ -@erase "$(INTDIR)\contact.sbr"
+ -@erase "$(INTDIR)\contactinfo.obj"
+ -@erase "$(INTDIR)\contactinfo.sbr"
+ -@erase "$(INTDIR)\contacts.obj"
+ -@erase "$(INTDIR)\contacts.sbr"
+ -@erase "$(INTDIR)\database.obj"
+ -@erase "$(INTDIR)\database.sbr"
+ -@erase "$(INTDIR)\dbini.obj"
+ -@erase "$(INTDIR)\dbini.sbr"
+ -@erase "$(INTDIR)\dblists.obj"
+ -@erase "$(INTDIR)\dblists.sbr"
+ -@erase "$(INTDIR)\dbutils.obj"
+ -@erase "$(INTDIR)\dbutils.sbr"
+ -@erase "$(INTDIR)\descbutton.obj"
+ -@erase "$(INTDIR)\descbutton.sbr"
+ -@erase "$(INTDIR)\Docking.obj"
+ -@erase "$(INTDIR)\Docking.sbr"
+ -@erase "$(INTDIR)\email.obj"
+ -@erase "$(INTDIR)\email.sbr"
+ -@erase "$(INTDIR)\extracticon.obj"
+ -@erase "$(INTDIR)\extracticon.sbr"
+ -@erase "$(INTDIR)\file.obj"
+ -@erase "$(INTDIR)\file.sbr"
+ -@erase "$(INTDIR)\fileexistsdlg.obj"
+ -@erase "$(INTDIR)\fileexistsdlg.sbr"
+ -@erase "$(INTDIR)\fileopts.obj"
+ -@erase "$(INTDIR)\fileopts.sbr"
+ -@erase "$(INTDIR)\filerecvdlg.obj"
+ -@erase "$(INTDIR)\filerecvdlg.sbr"
+ -@erase "$(INTDIR)\filesenddlg.obj"
+ -@erase "$(INTDIR)\filesenddlg.sbr"
+ -@erase "$(INTDIR)\filexferdlg.obj"
+ -@erase "$(INTDIR)\filexferdlg.sbr"
+ -@erase "$(INTDIR)\filter.obj"
+ -@erase "$(INTDIR)\filter.sbr"
+ -@erase "$(INTDIR)\findadd.obj"
+ -@erase "$(INTDIR)\findadd.sbr"
+ -@erase "$(INTDIR)\FontOptions.obj"
+ -@erase "$(INTDIR)\FontOptions.sbr"
+ -@erase "$(INTDIR)\FontService.obj"
+ -@erase "$(INTDIR)\FontService.sbr"
+ -@erase "$(INTDIR)\ftmanager.obj"
+ -@erase "$(INTDIR)\ftmanager.sbr"
+ -@erase "$(INTDIR)\genmenu.obj"
+ -@erase "$(INTDIR)\genmenu.sbr"
+ -@erase "$(INTDIR)\genmenuopt.obj"
+ -@erase "$(INTDIR)\genmenuopt.sbr"
+ -@erase "$(INTDIR)\groups.obj"
+ -@erase "$(INTDIR)\groups.sbr"
+ -@erase "$(INTDIR)\headerbar.obj"
+ -@erase "$(INTDIR)\headerbar.sbr"
+ -@erase "$(INTDIR)\help.obj"
+ -@erase "$(INTDIR)\help.sbr"
+ -@erase "$(INTDIR)\history.obj"
+ -@erase "$(INTDIR)\history.sbr"
+ -@erase "$(INTDIR)\hotkeys.obj"
+ -@erase "$(INTDIR)\hotkeys.sbr"
+ -@erase "$(INTDIR)\hyperlink.obj"
+ -@erase "$(INTDIR)\hyperlink.sbr"
+ -@erase "$(INTDIR)\iconheader.obj"
+ -@erase "$(INTDIR)\iconheader.sbr"
+ -@erase "$(INTDIR)\idle.obj"
+ -@erase "$(INTDIR)\idle.sbr"
+ -@erase "$(INTDIR)\ignore.obj"
+ -@erase "$(INTDIR)\ignore.sbr"
+ -@erase "$(INTDIR)\imgconv.obj"
+ -@erase "$(INTDIR)\imgconv.sbr"
+ -@erase "$(INTDIR)\keyboard.obj"
+ -@erase "$(INTDIR)\keyboard.sbr"
+ -@erase "$(INTDIR)\langpack.obj"
+ -@erase "$(INTDIR)\langpack.sbr"
+ -@erase "$(INTDIR)\lpservices.obj"
+ -@erase "$(INTDIR)\lpservices.sbr"
+ -@erase "$(INTDIR)\md5.obj"
+ -@erase "$(INTDIR)\md5.sbr"
+ -@erase "$(INTDIR)\memory.obj"
+ -@erase "$(INTDIR)\memory.sbr"
+ -@erase "$(INTDIR)\miranda.obj"
+ -@erase "$(INTDIR)\miranda.sbr"
+ -@erase "$(INTDIR)\miranda32.pch"
+ -@erase "$(INTDIR)\modules.obj"
+ -@erase "$(INTDIR)\modules.sbr"
+ -@erase "$(INTDIR)\movetogroup.obj"
+ -@erase "$(INTDIR)\movetogroup.sbr"
+ -@erase "$(INTDIR)\netlib.obj"
+ -@erase "$(INTDIR)\netlib.sbr"
+ -@erase "$(INTDIR)\netlibautoproxy.obj"
+ -@erase "$(INTDIR)\netlibautoproxy.sbr"
+ -@erase "$(INTDIR)\netlibbind.obj"
+ -@erase "$(INTDIR)\netlibbind.sbr"
+ -@erase "$(INTDIR)\netlibhttp.obj"
+ -@erase "$(INTDIR)\netlibhttp.sbr"
+ -@erase "$(INTDIR)\netlibhttpproxy.obj"
+ -@erase "$(INTDIR)\netlibhttpproxy.sbr"
+ -@erase "$(INTDIR)\netliblog.obj"
+ -@erase "$(INTDIR)\netliblog.sbr"
+ -@erase "$(INTDIR)\netlibopenconn.obj"
+ -@erase "$(INTDIR)\netlibopenconn.sbr"
+ -@erase "$(INTDIR)\netlibopts.obj"
+ -@erase "$(INTDIR)\netlibopts.sbr"
+ -@erase "$(INTDIR)\netlibpktrecver.obj"
+ -@erase "$(INTDIR)\netlibpktrecver.sbr"
+ -@erase "$(INTDIR)\netlibsecurity.obj"
+ -@erase "$(INTDIR)\netlibsecurity.sbr"
+ -@erase "$(INTDIR)\netlibsock.obj"
+ -@erase "$(INTDIR)\netlibsock.sbr"
+ -@erase "$(INTDIR)\netlibssl.obj"
+ -@erase "$(INTDIR)\netlibssl.sbr"
+ -@erase "$(INTDIR)\netlibupnp.obj"
+ -@erase "$(INTDIR)\netlibupnp.sbr"
+ -@erase "$(INTDIR)\newplugins.obj"
+ -@erase "$(INTDIR)\newplugins.sbr"
+ -@erase "$(INTDIR)\openurl.obj"
+ -@erase "$(INTDIR)\openurl.sbr"
+ -@erase "$(INTDIR)\options.obj"
+ -@erase "$(INTDIR)\options.sbr"
+ -@erase "$(INTDIR)\path.obj"
+ -@erase "$(INTDIR)\path.sbr"
+ -@erase "$(INTDIR)\profilemanager.obj"
+ -@erase "$(INTDIR)\profilemanager.sbr"
+ -@erase "$(INTDIR)\protoaccs.obj"
+ -@erase "$(INTDIR)\protoaccs.sbr"
+ -@erase "$(INTDIR)\protochains.obj"
+ -@erase "$(INTDIR)\protochains.sbr"
+ -@erase "$(INTDIR)\protocolorder.obj"
+ -@erase "$(INTDIR)\protocolorder.sbr"
+ -@erase "$(INTDIR)\protocols.obj"
+ -@erase "$(INTDIR)\protocols.sbr"
+ -@erase "$(INTDIR)\protoint.obj"
+ -@erase "$(INTDIR)\protoint.sbr"
+ -@erase "$(INTDIR)\protoopts.obj"
+ -@erase "$(INTDIR)\protoopts.sbr"
+ -@erase "$(INTDIR)\resizer.obj"
+ -@erase "$(INTDIR)\resizer.sbr"
+ -@erase "$(INTDIR)\searchresults.obj"
+ -@erase "$(INTDIR)\searchresults.sbr"
+ -@erase "$(INTDIR)\sendmsg.obj"
+ -@erase "$(INTDIR)\sendmsg.sbr"
+ -@erase "$(INTDIR)\services.obj"
+ -@erase "$(INTDIR)\services.sbr"
+ -@erase "$(INTDIR)\sha1.obj"
+ -@erase "$(INTDIR)\sha1.sbr"
+ -@erase "$(INTDIR)\skin2icons.obj"
+ -@erase "$(INTDIR)\skin2icons.sbr"
+ -@erase "$(INTDIR)\skinicons.obj"
+ -@erase "$(INTDIR)\skinicons.sbr"
+ -@erase "$(INTDIR)\sounds.obj"
+ -@erase "$(INTDIR)\sounds.sbr"
+ -@erase "$(INTDIR)\stdinfo.obj"
+ -@erase "$(INTDIR)\stdinfo.sbr"
+ -@erase "$(INTDIR)\timeutils.obj"
+ -@erase "$(INTDIR)\timeutils.sbr"
+ -@erase "$(INTDIR)\timezones.obj"
+ -@erase "$(INTDIR)\timezones.sbr"
+ -@erase "$(INTDIR)\updatenotify.obj"
+ -@erase "$(INTDIR)\updatenotify.sbr"
+ -@erase "$(INTDIR)\url.obj"
+ -@erase "$(INTDIR)\url.sbr"
+ -@erase "$(INTDIR)\urldialogs.obj"
+ -@erase "$(INTDIR)\urldialogs.sbr"
+ -@erase "$(INTDIR)\userinfo.obj"
+ -@erase "$(INTDIR)\userinfo.sbr"
+ -@erase "$(INTDIR)\useronline.obj"
+ -@erase "$(INTDIR)\useronline.sbr"
+ -@erase "$(INTDIR)\utf.obj"
+ -@erase "$(INTDIR)\utf.sbr"
+ -@erase "$(INTDIR)\utils.obj"
+ -@erase "$(INTDIR)\utils.sbr"
+ -@erase "$(INTDIR)\vc6.res"
+ -@erase "$(INTDIR)\vc60.idb"
+ -@erase "$(INTDIR)\vc60.pdb"
+ -@erase "$(INTDIR)\visibility.obj"
+ -@erase "$(INTDIR)\visibility.sbr"
+ -@erase "$(INTDIR)\windowlist.obj"
+ -@erase "$(INTDIR)\windowlist.sbr"
+ -@erase "$(INTDIR)\xmlApi.obj"
+ -@erase "$(INTDIR)\xmlApi.sbr"
+ -@erase "$(INTDIR)\xmlParser.obj"
+ -@erase "$(INTDIR)\xmlParser.sbr"
+ -@erase "$(OUTDIR)\miranda32.bsc"
+ -@erase "$(OUTDIR)\miranda32.pdb"
+ -@erase "..\bin\Debug Unicode\miranda32.exe"
+ -@erase "..\bin\Debug Unicode\miranda32.ilk"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP=cl.exe
+CPP_PROJ=/nologo /MDd /W3 /Gm /ZI /Od /I "../include" /I "../include/msapi" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_NOSDK" /D "UNICODE" /D "_STATIC" /Fr"$(INTDIR)\\" /Fp"$(INTDIR)\miranda32.pch" /Yu"commonheaders.h" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+.c{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(INTDIR)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+MTL=midl.exe
+MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
+RSC=rc.exe
+RSC_PROJ=/l 0x409 /fo"$(INTDIR)\vc6.res" /i "../include" /d "_DEBUG"
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\miranda32.bsc"
+BSC32_SBRS= \
+ "$(INTDIR)\commonheaders.sbr" \
+ "$(INTDIR)\memory.sbr" \
+ "$(INTDIR)\miranda.sbr" \
+ "$(INTDIR)\modules.sbr" \
+ "$(INTDIR)\addcontact.sbr" \
+ "$(INTDIR)\autoaway.sbr" \
+ "$(INTDIR)\button.sbr" \
+ "$(INTDIR)\contacts.sbr" \
+ "$(INTDIR)\database.sbr" \
+ "$(INTDIR)\dbini.sbr" \
+ "$(INTDIR)\dblists.sbr" \
+ "$(INTDIR)\dbutils.sbr" \
+ "$(INTDIR)\profilemanager.sbr" \
+ "$(INTDIR)\findadd.sbr" \
+ "$(INTDIR)\searchresults.sbr" \
+ "$(INTDIR)\about.sbr" \
+ "$(INTDIR)\help.sbr" \
+ "$(INTDIR)\history.sbr" \
+ "$(INTDIR)\idle.sbr" \
+ "$(INTDIR)\ignore.sbr" \
+ "$(INTDIR)\langpack.sbr" \
+ "$(INTDIR)\lpservices.sbr" \
+ "$(INTDIR)\netlib.sbr" \
+ "$(INTDIR)\netlibautoproxy.sbr" \
+ "$(INTDIR)\netlibbind.sbr" \
+ "$(INTDIR)\netlibhttp.sbr" \
+ "$(INTDIR)\netlibhttpproxy.sbr" \
+ "$(INTDIR)\netliblog.sbr" \
+ "$(INTDIR)\netlibopenconn.sbr" \
+ "$(INTDIR)\netlibopts.sbr" \
+ "$(INTDIR)\netlibpktrecver.sbr" \
+ "$(INTDIR)\netlibsecurity.sbr" \
+ "$(INTDIR)\netlibsock.sbr" \
+ "$(INTDIR)\netlibssl.sbr" \
+ "$(INTDIR)\netlibupnp.sbr" \
+ "$(INTDIR)\descbutton.sbr" \
+ "$(INTDIR)\filter.sbr" \
+ "$(INTDIR)\headerbar.sbr" \
+ "$(INTDIR)\iconheader.sbr" \
+ "$(INTDIR)\options.sbr" \
+ "$(INTDIR)\newplugins.sbr" \
+ "$(INTDIR)\protoaccs.sbr" \
+ "$(INTDIR)\protochains.sbr" \
+ "$(INTDIR)\protocols.sbr" \
+ "$(INTDIR)\protoint.sbr" \
+ "$(INTDIR)\protoopts.sbr" \
+ "$(INTDIR)\hotkeys.sbr" \
+ "$(INTDIR)\skinicons.sbr" \
+ "$(INTDIR)\sounds.sbr" \
+ "$(INTDIR)\auth.sbr" \
+ "$(INTDIR)\authdialogs.sbr" \
+ "$(INTDIR)\awaymsg.sbr" \
+ "$(INTDIR)\sendmsg.sbr" \
+ "$(INTDIR)\email.sbr" \
+ "$(INTDIR)\file.sbr" \
+ "$(INTDIR)\fileexistsdlg.sbr" \
+ "$(INTDIR)\fileopts.sbr" \
+ "$(INTDIR)\filerecvdlg.sbr" \
+ "$(INTDIR)\filesenddlg.sbr" \
+ "$(INTDIR)\filexferdlg.sbr" \
+ "$(INTDIR)\ftmanager.sbr" \
+ "$(INTDIR)\url.sbr" \
+ "$(INTDIR)\urldialogs.sbr" \
+ "$(INTDIR)\contactinfo.sbr" \
+ "$(INTDIR)\stdinfo.sbr" \
+ "$(INTDIR)\userinfo.sbr" \
+ "$(INTDIR)\useronline.sbr" \
+ "$(INTDIR)\bmpfilter.sbr" \
+ "$(INTDIR)\colourpicker.sbr" \
+ "$(INTDIR)\hyperlink.sbr" \
+ "$(INTDIR)\imgconv.sbr" \
+ "$(INTDIR)\md5.sbr" \
+ "$(INTDIR)\openurl.sbr" \
+ "$(INTDIR)\path.sbr" \
+ "$(INTDIR)\resizer.sbr" \
+ "$(INTDIR)\sha1.sbr" \
+ "$(INTDIR)\timeutils.sbr" \
+ "$(INTDIR)\timezones.sbr" \
+ "$(INTDIR)\utf.sbr" \
+ "$(INTDIR)\utils.sbr" \
+ "$(INTDIR)\windowlist.sbr" \
+ "$(INTDIR)\visibility.sbr" \
+ "$(INTDIR)\clc.sbr" \
+ "$(INTDIR)\clcfiledrop.sbr" \
+ "$(INTDIR)\clcidents.sbr" \
+ "$(INTDIR)\clcitems.sbr" \
+ "$(INTDIR)\clcmsgs.sbr" \
+ "$(INTDIR)\clcutils.sbr" \
+ "$(INTDIR)\clistcore.sbr" \
+ "$(INTDIR)\clistevents.sbr" \
+ "$(INTDIR)\clistmenus.sbr" \
+ "$(INTDIR)\clistmod.sbr" \
+ "$(INTDIR)\clistsettings.sbr" \
+ "$(INTDIR)\clisttray.sbr" \
+ "$(INTDIR)\clui.sbr" \
+ "$(INTDIR)\cluiservices.sbr" \
+ "$(INTDIR)\contact.sbr" \
+ "$(INTDIR)\Docking.sbr" \
+ "$(INTDIR)\genmenu.sbr" \
+ "$(INTDIR)\genmenuopt.sbr" \
+ "$(INTDIR)\groups.sbr" \
+ "$(INTDIR)\keyboard.sbr" \
+ "$(INTDIR)\movetogroup.sbr" \
+ "$(INTDIR)\protocolorder.sbr" \
+ "$(INTDIR)\FontOptions.sbr" \
+ "$(INTDIR)\FontService.sbr" \
+ "$(INTDIR)\services.sbr" \
+ "$(INTDIR)\extracticon.sbr" \
+ "$(INTDIR)\skin2icons.sbr" \
+ "$(INTDIR)\updatenotify.sbr" \
+ "$(INTDIR)\xmlApi.sbr" \
+ "$(INTDIR)\xmlParser.sbr"
+
+"$(OUTDIR)\miranda32.bsc" : "$(OUTDIR)" $(BSC32_SBRS)
+ $(BSC32) @<<
+ $(BSC32_FLAGS) $(BSC32_SBRS)
+<<
+
+LINK32=link.exe
+LINK32_FLAGS=ws2_32.lib kernel32.lib user32.lib gdi32.lib shell32.lib comdlg32.lib advapi32.lib ole32.lib oleaut32.lib uuid.lib comctl32.lib winmm.lib version.lib crypt32.lib /nologo /subsystem:windows /incremental:yes /pdb:"$(OUTDIR)\miranda32.pdb" /debug /machine:I386 /out:"../bin/Debug Unicode/miranda32.exe"
+LINK32_OBJS= \
+ "$(INTDIR)\commonheaders.obj" \
+ "$(INTDIR)\memory.obj" \
+ "$(INTDIR)\miranda.obj" \
+ "$(INTDIR)\modules.obj" \
+ "$(INTDIR)\addcontact.obj" \
+ "$(INTDIR)\autoaway.obj" \
+ "$(INTDIR)\button.obj" \
+ "$(INTDIR)\contacts.obj" \
+ "$(INTDIR)\database.obj" \
+ "$(INTDIR)\dbini.obj" \
+ "$(INTDIR)\dblists.obj" \
+ "$(INTDIR)\dbutils.obj" \
+ "$(INTDIR)\profilemanager.obj" \
+ "$(INTDIR)\findadd.obj" \
+ "$(INTDIR)\searchresults.obj" \
+ "$(INTDIR)\about.obj" \
+ "$(INTDIR)\help.obj" \
+ "$(INTDIR)\history.obj" \
+ "$(INTDIR)\idle.obj" \
+ "$(INTDIR)\ignore.obj" \
+ "$(INTDIR)\langpack.obj" \
+ "$(INTDIR)\lpservices.obj" \
+ "$(INTDIR)\netlib.obj" \
+ "$(INTDIR)\netlibautoproxy.obj" \
+ "$(INTDIR)\netlibbind.obj" \
+ "$(INTDIR)\netlibhttp.obj" \
+ "$(INTDIR)\netlibhttpproxy.obj" \
+ "$(INTDIR)\netliblog.obj" \
+ "$(INTDIR)\netlibopenconn.obj" \
+ "$(INTDIR)\netlibopts.obj" \
+ "$(INTDIR)\netlibpktrecver.obj" \
+ "$(INTDIR)\netlibsecurity.obj" \
+ "$(INTDIR)\netlibsock.obj" \
+ "$(INTDIR)\netlibssl.obj" \
+ "$(INTDIR)\netlibupnp.obj" \
+ "$(INTDIR)\descbutton.obj" \
+ "$(INTDIR)\filter.obj" \
+ "$(INTDIR)\headerbar.obj" \
+ "$(INTDIR)\iconheader.obj" \
+ "$(INTDIR)\options.obj" \
+ "$(INTDIR)\newplugins.obj" \
+ "$(INTDIR)\protoaccs.obj" \
+ "$(INTDIR)\protochains.obj" \
+ "$(INTDIR)\protocols.obj" \
+ "$(INTDIR)\protoint.obj" \
+ "$(INTDIR)\protoopts.obj" \
+ "$(INTDIR)\hotkeys.obj" \
+ "$(INTDIR)\skinicons.obj" \
+ "$(INTDIR)\sounds.obj" \
+ "$(INTDIR)\auth.obj" \
+ "$(INTDIR)\authdialogs.obj" \
+ "$(INTDIR)\awaymsg.obj" \
+ "$(INTDIR)\sendmsg.obj" \
+ "$(INTDIR)\email.obj" \
+ "$(INTDIR)\file.obj" \
+ "$(INTDIR)\fileexistsdlg.obj" \
+ "$(INTDIR)\fileopts.obj" \
+ "$(INTDIR)\filerecvdlg.obj" \
+ "$(INTDIR)\filesenddlg.obj" \
+ "$(INTDIR)\filexferdlg.obj" \
+ "$(INTDIR)\ftmanager.obj" \
+ "$(INTDIR)\url.obj" \
+ "$(INTDIR)\urldialogs.obj" \
+ "$(INTDIR)\contactinfo.obj" \
+ "$(INTDIR)\stdinfo.obj" \
+ "$(INTDIR)\userinfo.obj" \
+ "$(INTDIR)\useronline.obj" \
+ "$(INTDIR)\bmpfilter.obj" \
+ "$(INTDIR)\colourpicker.obj" \
+ "$(INTDIR)\hyperlink.obj" \
+ "$(INTDIR)\imgconv.obj" \
+ "$(INTDIR)\md5.obj" \
+ "$(INTDIR)\openurl.obj" \
+ "$(INTDIR)\path.obj" \
+ "$(INTDIR)\resizer.obj" \
+ "$(INTDIR)\sha1.obj" \
+ "$(INTDIR)\timeutils.obj" \
+ "$(INTDIR)\timezones.obj" \
+ "$(INTDIR)\utf.obj" \
+ "$(INTDIR)\utils.obj" \
+ "$(INTDIR)\windowlist.obj" \
+ "$(INTDIR)\visibility.obj" \
+ "$(INTDIR)\clc.obj" \
+ "$(INTDIR)\clcfiledrop.obj" \
+ "$(INTDIR)\clcidents.obj" \
+ "$(INTDIR)\clcitems.obj" \
+ "$(INTDIR)\clcmsgs.obj" \
+ "$(INTDIR)\clcutils.obj" \
+ "$(INTDIR)\clistcore.obj" \
+ "$(INTDIR)\clistevents.obj" \
+ "$(INTDIR)\clistmenus.obj" \
+ "$(INTDIR)\clistmod.obj" \
+ "$(INTDIR)\clistsettings.obj" \
+ "$(INTDIR)\clisttray.obj" \
+ "$(INTDIR)\clui.obj" \
+ "$(INTDIR)\cluiservices.obj" \
+ "$(INTDIR)\contact.obj" \
+ "$(INTDIR)\Docking.obj" \
+ "$(INTDIR)\genmenu.obj" \
+ "$(INTDIR)\genmenuopt.obj" \
+ "$(INTDIR)\groups.obj" \
+ "$(INTDIR)\keyboard.obj" \
+ "$(INTDIR)\movetogroup.obj" \
+ "$(INTDIR)\protocolorder.obj" \
+ "$(INTDIR)\FontOptions.obj" \
+ "$(INTDIR)\FontService.obj" \
+ "$(INTDIR)\services.obj" \
+ "$(INTDIR)\extracticon.obj" \
+ "$(INTDIR)\skin2icons.obj" \
+ "$(INTDIR)\updatenotify.obj" \
+ "$(INTDIR)\xmlApi.obj" \
+ "$(INTDIR)\xmlParser.obj" \
+ "$(INTDIR)\vc6.res" \
+ "..\plugins\zlib\Debug_Unicode\zlib.lib"
+
+"..\bin\Debug Unicode\miranda32.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ENDIF
+
+
+!IF "$(NO_EXTERNAL_DEPS)" != "1"
+!IF EXISTS("miranda32.dep")
+!INCLUDE "miranda32.dep"
+!ELSE
+!MESSAGE Warning: cannot find "miranda32.dep"
+!ENDIF
+!ENDIF
+
+
+!IF "$(CFG)" == "miranda32 - Win32 Release" || "$(CFG)" == "miranda32 - Win32 Debug" || "$(CFG)" == "miranda32 - Win32 Release Unicode" || "$(CFG)" == "miranda32 - Win32 Debug Unicode"
+SOURCE=.\core\commonheaders.cpp
+
+!IF "$(CFG)" == "miranda32 - Win32 Release"
+
+CPP_SWITCHES=/nologo /MD /W3 /Zi /O1 /I "../include" /I "../include/msapi" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_NOSDK" /D "_STATIC" /Fr"$(INTDIR)\\" /Fp"$(INTDIR)\miranda32.pch" /Yc"commonheaders.h" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+"$(INTDIR)\commonheaders.obj" "$(INTDIR)\commonheaders.sbr" "$(INTDIR)\miranda32.pch" : $(SOURCE) "$(INTDIR)"
+ $(CPP) @<<
+ $(CPP_SWITCHES) $(SOURCE)
+<<
+
+
+!ELSEIF "$(CFG)" == "miranda32 - Win32 Debug"
+
+CPP_SWITCHES=/nologo /MDd /W3 /Gm /ZI /Od /I "../include" /I "../include/msapi" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_NOSDK" /D "_STATIC" /Fr"$(INTDIR)\\" /Fp"$(INTDIR)\miranda32.pch" /Yc"commonheaders.h" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+"$(INTDIR)\commonheaders.obj" "$(INTDIR)\commonheaders.sbr" "$(INTDIR)\miranda32.pch" : $(SOURCE) "$(INTDIR)"
+ $(CPP) @<<
+ $(CPP_SWITCHES) $(SOURCE)
+<<
+
+
+!ELSEIF "$(CFG)" == "miranda32 - Win32 Release Unicode"
+
+CPP_SWITCHES=/nologo /MD /W3 /Zi /O1 /I "../include/msapi" /I "../include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_NOSDK" /D "UNICODE" /D "_STATIC" /Fr"$(INTDIR)\\" /Fp"$(INTDIR)\miranda32.pch" /Yc"commonheaders.h" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+"$(INTDIR)\commonheaders.obj" "$(INTDIR)\commonheaders.sbr" "$(INTDIR)\miranda32.pch" : $(SOURCE) "$(INTDIR)"
+ $(CPP) @<<
+ $(CPP_SWITCHES) $(SOURCE)
+<<
+
+
+!ELSEIF "$(CFG)" == "miranda32 - Win32 Debug Unicode"
+
+CPP_SWITCHES=/nologo /MDd /W3 /Gm /ZI /Od /I "../include" /I "../include/msapi" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_NOSDK" /D "UNICODE" /D "_STATIC" /Fr"$(INTDIR)\\" /Fp"$(INTDIR)\miranda32.pch" /Yc"commonheaders.h" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+"$(INTDIR)\commonheaders.obj" "$(INTDIR)\commonheaders.sbr" "$(INTDIR)\miranda32.pch" : $(SOURCE) "$(INTDIR)"
+ $(CPP) @<<
+ $(CPP_SWITCHES) $(SOURCE)
+<<
+
+
+!ENDIF
+
+SOURCE=.\core\memory.cpp
+
+"$(INTDIR)\memory.obj" "$(INTDIR)\memory.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\core\miranda.cpp
+
+"$(INTDIR)\miranda.obj" "$(INTDIR)\miranda.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\core\modules.cpp
+
+"$(INTDIR)\modules.obj" "$(INTDIR)\modules.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\addcontact\addcontact.cpp
+
+"$(INTDIR)\addcontact.obj" "$(INTDIR)\addcontact.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\autoaway\autoaway.cpp
+
+"$(INTDIR)\autoaway.obj" "$(INTDIR)\autoaway.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\button\button.cpp
+
+"$(INTDIR)\button.obj" "$(INTDIR)\button.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\contacts\contacts.cpp
+
+"$(INTDIR)\contacts.obj" "$(INTDIR)\contacts.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\database\database.cpp
+
+"$(INTDIR)\database.obj" "$(INTDIR)\database.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\database\dbini.cpp
+
+"$(INTDIR)\dbini.obj" "$(INTDIR)\dbini.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\database\dblists.cpp
+
+"$(INTDIR)\dblists.obj" "$(INTDIR)\dblists.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\database\dbutils.cpp
+
+"$(INTDIR)\dbutils.obj" "$(INTDIR)\dbutils.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\database\profilemanager.cpp
+
+"$(INTDIR)\profilemanager.obj" "$(INTDIR)\profilemanager.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\findadd\findadd.cpp
+
+"$(INTDIR)\findadd.obj" "$(INTDIR)\findadd.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\findadd\searchresults.cpp
+
+"$(INTDIR)\searchresults.obj" "$(INTDIR)\searchresults.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\help\about.cpp
+
+"$(INTDIR)\about.obj" "$(INTDIR)\about.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\help\help.cpp
+
+"$(INTDIR)\help.obj" "$(INTDIR)\help.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\history\history.cpp
+
+"$(INTDIR)\history.obj" "$(INTDIR)\history.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\idle\idle.cpp
+
+"$(INTDIR)\idle.obj" "$(INTDIR)\idle.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\ignore\ignore.cpp
+
+"$(INTDIR)\ignore.obj" "$(INTDIR)\ignore.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\langpack\langpack.cpp
+
+"$(INTDIR)\langpack.obj" "$(INTDIR)\langpack.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\langpack\lpservices.cpp
+
+"$(INTDIR)\lpservices.obj" "$(INTDIR)\lpservices.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\netlib\netlib.cpp
+
+"$(INTDIR)\netlib.obj" "$(INTDIR)\netlib.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\netlib\netlibautoproxy.cpp
+
+"$(INTDIR)\netlibautoproxy.obj" "$(INTDIR)\netlibautoproxy.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\netlib\netlibbind.cpp
+
+"$(INTDIR)\netlibbind.obj" "$(INTDIR)\netlibbind.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\netlib\netlibhttp.cpp
+
+"$(INTDIR)\netlibhttp.obj" "$(INTDIR)\netlibhttp.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\netlib\netlibhttpproxy.cpp
+
+"$(INTDIR)\netlibhttpproxy.obj" "$(INTDIR)\netlibhttpproxy.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\netlib\netliblog.cpp
+
+"$(INTDIR)\netliblog.obj" "$(INTDIR)\netliblog.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\netlib\netlibopenconn.cpp
+
+"$(INTDIR)\netlibopenconn.obj" "$(INTDIR)\netlibopenconn.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\netlib\netlibopts.cpp
+
+"$(INTDIR)\netlibopts.obj" "$(INTDIR)\netlibopts.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\netlib\netlibpktrecver.cpp
+
+"$(INTDIR)\netlibpktrecver.obj" "$(INTDIR)\netlibpktrecver.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\netlib\netlibsecurity.cpp
+
+"$(INTDIR)\netlibsecurity.obj" "$(INTDIR)\netlibsecurity.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\netlib\netlibsock.cpp
+
+"$(INTDIR)\netlibsock.obj" "$(INTDIR)\netlibsock.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\netlib\netlibssl.cpp
+
+"$(INTDIR)\netlibssl.obj" "$(INTDIR)\netlibssl.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\netlib\netlibupnp.cpp
+
+"$(INTDIR)\netlibupnp.obj" "$(INTDIR)\netlibupnp.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\options\descbutton.cpp
+
+"$(INTDIR)\descbutton.obj" "$(INTDIR)\descbutton.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\options\filter.cpp
+
+"$(INTDIR)\filter.obj" "$(INTDIR)\filter.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\options\headerbar.cpp
+
+"$(INTDIR)\headerbar.obj" "$(INTDIR)\headerbar.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\options\iconheader.cpp
+
+"$(INTDIR)\iconheader.obj" "$(INTDIR)\iconheader.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\options\options.cpp
+
+"$(INTDIR)\options.obj" "$(INTDIR)\options.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\plugins\newplugins.cpp
+
+"$(INTDIR)\newplugins.obj" "$(INTDIR)\newplugins.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\protocols\protoaccs.cpp
+
+"$(INTDIR)\protoaccs.obj" "$(INTDIR)\protoaccs.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\protocols\protochains.cpp
+
+"$(INTDIR)\protochains.obj" "$(INTDIR)\protochains.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\protocols\protocols.cpp
+
+"$(INTDIR)\protocols.obj" "$(INTDIR)\protocols.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\protocols\protoint.cpp
+
+"$(INTDIR)\protoint.obj" "$(INTDIR)\protoint.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\protocols\protoopts.cpp
+
+"$(INTDIR)\protoopts.obj" "$(INTDIR)\protoopts.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\skin\hotkeys.cpp
+
+"$(INTDIR)\hotkeys.obj" "$(INTDIR)\hotkeys.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\skin\skinicons.cpp
+
+"$(INTDIR)\skinicons.obj" "$(INTDIR)\skinicons.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\skin\sounds.cpp
+
+"$(INTDIR)\sounds.obj" "$(INTDIR)\sounds.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\srauth\auth.cpp
+
+"$(INTDIR)\auth.obj" "$(INTDIR)\auth.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\srauth\authdialogs.cpp
+
+"$(INTDIR)\authdialogs.obj" "$(INTDIR)\authdialogs.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\srawaymsg\awaymsg.cpp
+
+"$(INTDIR)\awaymsg.obj" "$(INTDIR)\awaymsg.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\srawaymsg\sendmsg.cpp
+
+"$(INTDIR)\sendmsg.obj" "$(INTDIR)\sendmsg.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\sremail\email.cpp
+
+"$(INTDIR)\email.obj" "$(INTDIR)\email.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\srfile\file.cpp
+
+"$(INTDIR)\file.obj" "$(INTDIR)\file.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\srfile\fileexistsdlg.cpp
+
+"$(INTDIR)\fileexistsdlg.obj" "$(INTDIR)\fileexistsdlg.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\srfile\fileopts.cpp
+
+"$(INTDIR)\fileopts.obj" "$(INTDIR)\fileopts.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\srfile\filerecvdlg.cpp
+
+"$(INTDIR)\filerecvdlg.obj" "$(INTDIR)\filerecvdlg.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\srfile\filesenddlg.cpp
+
+"$(INTDIR)\filesenddlg.obj" "$(INTDIR)\filesenddlg.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\srfile\filexferdlg.cpp
+
+"$(INTDIR)\filexferdlg.obj" "$(INTDIR)\filexferdlg.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\srfile\ftmanager.cpp
+
+"$(INTDIR)\ftmanager.obj" "$(INTDIR)\ftmanager.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\srurl\url.cpp
+
+"$(INTDIR)\url.obj" "$(INTDIR)\url.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\srurl\urldialogs.cpp
+
+"$(INTDIR)\urldialogs.obj" "$(INTDIR)\urldialogs.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\userinfo\contactinfo.cpp
+
+"$(INTDIR)\contactinfo.obj" "$(INTDIR)\contactinfo.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\userinfo\stdinfo.cpp
+
+"$(INTDIR)\stdinfo.obj" "$(INTDIR)\stdinfo.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\userinfo\userinfo.cpp
+
+"$(INTDIR)\userinfo.obj" "$(INTDIR)\userinfo.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\useronline\useronline.cpp
+
+"$(INTDIR)\useronline.obj" "$(INTDIR)\useronline.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\utils\bmpfilter.cpp
+
+"$(INTDIR)\bmpfilter.obj" "$(INTDIR)\bmpfilter.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\utils\colourpicker.cpp
+
+"$(INTDIR)\colourpicker.obj" "$(INTDIR)\colourpicker.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\utils\hyperlink.cpp
+
+"$(INTDIR)\hyperlink.obj" "$(INTDIR)\hyperlink.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\utils\imgconv.cpp
+
+"$(INTDIR)\imgconv.obj" "$(INTDIR)\imgconv.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\utils\md5.cpp
+
+"$(INTDIR)\md5.obj" "$(INTDIR)\md5.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\utils\openurl.cpp
+
+"$(INTDIR)\openurl.obj" "$(INTDIR)\openurl.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\utils\path.cpp
+
+"$(INTDIR)\path.obj" "$(INTDIR)\path.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\utils\resizer.cpp
+
+"$(INTDIR)\resizer.obj" "$(INTDIR)\resizer.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\utils\sha1.cpp
+
+"$(INTDIR)\sha1.obj" "$(INTDIR)\sha1.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\utils\timeutils.cpp
+
+"$(INTDIR)\timeutils.obj" "$(INTDIR)\timeutils.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\utils\timezones.cpp
+
+"$(INTDIR)\timezones.obj" "$(INTDIR)\timezones.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\utils\utf.cpp
+
+"$(INTDIR)\utf.obj" "$(INTDIR)\utf.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\utils\utils.cpp
+
+"$(INTDIR)\utils.obj" "$(INTDIR)\utils.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\utils\windowlist.cpp
+
+"$(INTDIR)\windowlist.obj" "$(INTDIR)\windowlist.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\visibility\visibility.cpp
+
+"$(INTDIR)\visibility.obj" "$(INTDIR)\visibility.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\clist\clc.cpp
+
+"$(INTDIR)\clc.obj" "$(INTDIR)\clc.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\clist\clcfiledrop.cpp
+
+"$(INTDIR)\clcfiledrop.obj" "$(INTDIR)\clcfiledrop.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\clist\clcidents.cpp
+
+"$(INTDIR)\clcidents.obj" "$(INTDIR)\clcidents.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\clist\clcitems.cpp
+
+"$(INTDIR)\clcitems.obj" "$(INTDIR)\clcitems.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\clist\clcmsgs.cpp
+
+"$(INTDIR)\clcmsgs.obj" "$(INTDIR)\clcmsgs.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\clist\clcutils.cpp
+
+"$(INTDIR)\clcutils.obj" "$(INTDIR)\clcutils.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\clist\clistcore.cpp
+
+"$(INTDIR)\clistcore.obj" "$(INTDIR)\clistcore.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\clist\clistevents.cpp
+
+"$(INTDIR)\clistevents.obj" "$(INTDIR)\clistevents.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\clist\clistmenus.cpp
+
+"$(INTDIR)\clistmenus.obj" "$(INTDIR)\clistmenus.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\clist\clistmod.cpp
+
+"$(INTDIR)\clistmod.obj" "$(INTDIR)\clistmod.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\clist\clistsettings.cpp
+
+"$(INTDIR)\clistsettings.obj" "$(INTDIR)\clistsettings.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\clist\clisttray.cpp
+
+"$(INTDIR)\clisttray.obj" "$(INTDIR)\clisttray.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\clist\clui.cpp
+
+"$(INTDIR)\clui.obj" "$(INTDIR)\clui.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\clist\cluiservices.cpp
+
+"$(INTDIR)\cluiservices.obj" "$(INTDIR)\cluiservices.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\clist\contact.cpp
+
+"$(INTDIR)\contact.obj" "$(INTDIR)\contact.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\clist\Docking.cpp
+
+"$(INTDIR)\Docking.obj" "$(INTDIR)\Docking.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\clist\genmenu.cpp
+
+"$(INTDIR)\genmenu.obj" "$(INTDIR)\genmenu.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\clist\genmenuopt.cpp
+
+"$(INTDIR)\genmenuopt.obj" "$(INTDIR)\genmenuopt.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\clist\groups.cpp
+
+"$(INTDIR)\groups.obj" "$(INTDIR)\groups.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\clist\keyboard.cpp
+
+"$(INTDIR)\keyboard.obj" "$(INTDIR)\keyboard.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\clist\movetogroup.cpp
+
+"$(INTDIR)\movetogroup.obj" "$(INTDIR)\movetogroup.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\clist\protocolorder.cpp
+
+"$(INTDIR)\protocolorder.obj" "$(INTDIR)\protocolorder.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\fonts\FontOptions.cpp
+
+"$(INTDIR)\FontOptions.obj" "$(INTDIR)\FontOptions.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\fonts\FontService.cpp
+
+"$(INTDIR)\FontService.obj" "$(INTDIR)\FontService.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\fonts\services.cpp
+
+"$(INTDIR)\services.obj" "$(INTDIR)\services.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\icolib\extracticon.cpp
+
+!IF "$(CFG)" == "miranda32 - Win32 Release"
+
+CPP_SWITCHES=/nologo /MD /W3 /Zi /O1 /I "../include" /I "../include/msapi" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_NOSDK" /D "_STATIC" /Fr"$(INTDIR)\\" /Fp"$(INTDIR)\miranda32.pch" /Yu"commonheaders.h" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+"$(INTDIR)\extracticon.obj" "$(INTDIR)\extracticon.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) @<<
+ $(CPP_SWITCHES) $(SOURCE)
+<<
+
+
+!ELSEIF "$(CFG)" == "miranda32 - Win32 Debug"
+
+CPP_SWITCHES=/nologo /MDd /W3 /Gm /ZI /Od /I "../include" /I "../include/msapi" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_NOSDK" /D "_STATIC" /Fr"$(INTDIR)\\" /Fp"$(INTDIR)\miranda32.pch" /Yu"commonheaders.h" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+"$(INTDIR)\extracticon.obj" "$(INTDIR)\extracticon.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) @<<
+ $(CPP_SWITCHES) $(SOURCE)
+<<
+
+
+!ELSEIF "$(CFG)" == "miranda32 - Win32 Release Unicode"
+
+CPP_SWITCHES=/nologo /MD /W3 /Zi /O1 /I "../include/msapi" /I "../include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_NOSDK" /D "UNICODE" /D "_STATIC" /Fr"$(INTDIR)\\" /Fp"$(INTDIR)\miranda32.pch" /Yu"commonheaders.h" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+"$(INTDIR)\extracticon.obj" "$(INTDIR)\extracticon.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) @<<
+ $(CPP_SWITCHES) $(SOURCE)
+<<
+
+
+!ELSEIF "$(CFG)" == "miranda32 - Win32 Debug Unicode"
+
+CPP_SWITCHES=/nologo /MDd /W3 /Gm /ZI /Od /I "../include" /I "../include/msapi" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_NOSDK" /D "UNICODE" /D "_STATIC" /Fr"$(INTDIR)\\" /Fp"$(INTDIR)\miranda32.pch" /Yu"commonheaders.h" /Fo"$(INTDIR)\\" /Fd"$(INTDIR)\\" /FD /c
+
+"$(INTDIR)\extracticon.obj" "$(INTDIR)\extracticon.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) @<<
+ $(CPP_SWITCHES) $(SOURCE)
+<<
+
+
+!ENDIF
+
+SOURCE=.\modules\icolib\skin2icons.cpp
+
+"$(INTDIR)\skin2icons.obj" "$(INTDIR)\skin2icons.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\updatenotify\updatenotify.cpp
+
+"$(INTDIR)\updatenotify.obj" "$(INTDIR)\updatenotify.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\xml\xmlApi.cpp
+
+"$(INTDIR)\xmlApi.obj" "$(INTDIR)\xmlApi.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\modules\xml\xmlParser.cpp
+
+"$(INTDIR)\xmlParser.obj" "$(INTDIR)\xmlParser.sbr" : $(SOURCE) "$(INTDIR)" "$(INTDIR)\miranda32.pch"
+ $(CPP) $(CPP_PROJ) $(SOURCE)
+
+
+SOURCE=.\vc6.rc
+
+"$(INTDIR)\vc6.res" : $(SOURCE) "$(INTDIR)"
+ $(RSC) $(RSC_PROJ) $(SOURCE)
+
+
+!IF "$(CFG)" == "miranda32 - Win32 Release"
+
+"zlib - Win32 Release" :
+ cd "..\plugins\zlib"
+ $(MAKE) /$(MAKEFLAGS) /F .\zlib.mak CFG="zlib - Win32 Release"
+ cd "..\..\src"
+
+"zlib - Win32 ReleaseCLEAN" :
+ cd "..\plugins\zlib"
+ $(MAKE) /$(MAKEFLAGS) /F .\zlib.mak CFG="zlib - Win32 Release" RECURSE=1 CLEAN
+ cd "..\..\src"
+
+!ELSEIF "$(CFG)" == "miranda32 - Win32 Debug"
+
+"zlib - Win32 Debug" :
+ cd "..\plugins\zlib"
+ $(MAKE) /$(MAKEFLAGS) /F .\zlib.mak CFG="zlib - Win32 Debug"
+ cd "..\..\src"
+
+"zlib - Win32 DebugCLEAN" :
+ cd "..\plugins\zlib"
+ $(MAKE) /$(MAKEFLAGS) /F .\zlib.mak CFG="zlib - Win32 Debug" RECURSE=1 CLEAN
+ cd "..\..\src"
+
+!ELSEIF "$(CFG)" == "miranda32 - Win32 Release Unicode"
+
+"zlib - Win32 Release Unicode" :
+ cd "..\plugins\zlib"
+ $(MAKE) /$(MAKEFLAGS) /F .\zlib.mak CFG="zlib - Win32 Release Unicode"
+ cd "..\..\src"
+
+"zlib - Win32 Release UnicodeCLEAN" :
+ cd "..\plugins\zlib"
+ $(MAKE) /$(MAKEFLAGS) /F .\zlib.mak CFG="zlib - Win32 Release Unicode" RECURSE=1 CLEAN
+ cd "..\..\src"
+
+!ELSEIF "$(CFG)" == "miranda32 - Win32 Debug Unicode"
+
+"zlib - Win32 Debug Unicode" :
+ cd "..\plugins\zlib"
+ $(MAKE) /$(MAKEFLAGS) /F .\zlib.mak CFG="zlib - Win32 Debug Unicode"
+ cd "..\..\src"
+
+"zlib - Win32 Debug UnicodeCLEAN" :
+ cd "..\plugins\zlib"
+ $(MAKE) /$(MAKEFLAGS) /F .\zlib.mak CFG="zlib - Win32 Debug Unicode" RECURSE=1 CLEAN
+ cd "..\..\src"
+
+!ENDIF
+
+
+!ENDIF
+
diff --git a/src/miranda32.vcproj b/src/miranda32.vcproj
new file mode 100644
index 0000000000..5e2fce532c
--- /dev/null
+++ b/src/miranda32.vcproj
@@ -0,0 +1,3275 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="miranda32"
+ RootNamespace="miranda32"
+ SccProjectName=""
+ SccLocalPath="">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(SolutionDir)$(ConfigurationName)/Obj/$(ProjectName)"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ WholeProgramOptimization="TRUE">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="3"
+ GlobalOptimizations="TRUE"
+ InlineFunctionExpansion="1"
+ FavorSizeOrSpeed="2"
+ AdditionalIncludeDirectories="../include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;_NOSDK;_STATIC"
+ StringPooling="TRUE"
+ ExceptionHandling="FALSE"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="TRUE"
+ UsePrecompiledHeader="3"
+ PrecompiledHeaderThrough="commonheaders.h"
+ AssemblerOutput="3"
+ BrowseInformation="1"
+ BrowseInformationFile="$(IntDir)/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ IgnoreImportLibrary="TRUE"
+ AdditionalDependencies="vc7to6.lib oldnames.lib ws2_32.lib shlwapi.lib comctl32.lib winmm.lib version.lib"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ AdditionalLibraryDirectories="../lib"
+ IgnoreAllDefaultLibraries="TRUE"
+ GenerateDebugInformation="TRUE"
+ GenerateMapFile="TRUE"
+ MapFileName="$(OutDir)/$(ProjectName).map"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ OptimizeForWindows98="1"
+ ImportLibrary="$(IntDir)/$(TargetName).lib"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="TRUE"
+ SuppressStartupBanner="TRUE"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Release/miranda32.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(SolutionDir)$(ConfigurationName)/Obj/$(ProjectName)"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_WINDOWS;_NOSDK;_STATIC"
+ ExceptionHandling="FALSE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="3"
+ PrecompiledHeaderThrough="commonheaders.h"
+ BrowseInformation="1"
+ BrowseInformationFile="$(IntDir)/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="4"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib comctl32.lib winmm.lib version.lib"
+ LinkIncremental="2"
+ SuppressStartupBanner="TRUE"
+ GenerateDebugInformation="TRUE"
+ SubSystem="2"
+ ImportLibrary="$(IntDir)/$(TargetName).lib"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="TRUE"
+ SuppressStartupBanner="TRUE"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Debug/miranda32.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release Unicode|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(SolutionDir)$(ConfigurationName)/Obj/$(ProjectName)"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="1"
+ WholeProgramOptimization="FALSE">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="3"
+ GlobalOptimizations="TRUE"
+ FavorSizeOrSpeed="2"
+ OmitFramePointers="FALSE"
+ OptimizeForProcessor="0"
+ AdditionalIncludeDirectories="../include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;_NOSDK;_STATIC"
+ StringPooling="TRUE"
+ ExceptionHandling="FALSE"
+ RuntimeLibrary="2"
+ BufferSecurityCheck="TRUE"
+ UsePrecompiledHeader="3"
+ PrecompiledHeaderThrough="commonheaders.h"
+ AssemblerOutput="3"
+ BrowseInformation="1"
+ BrowseInformationFile="$(IntDir)/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ IgnoreImportLibrary="TRUE"
+ AdditionalDependencies="vc7to6.lib oldnames.lib ws2_32.lib shlwapi.lib comctl32.lib winmm.lib version.lib"
+ OutputFile="$(OutDir)/$(ProjectName).exe"
+ AdditionalLibraryDirectories="../lib"
+ IgnoreAllDefaultLibraries="TRUE"
+ GenerateDebugInformation="TRUE"
+ GenerateMapFile="TRUE"
+ MapFileName="$(OutDir)/$(ProjectName).map"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ OptimizeForWindows98="1"
+ ImportLibrary="$(IntDir)/$(TargetName).lib"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="TRUE"
+ SuppressStartupBanner="TRUE"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Release/miranda32.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Debug Unicode|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(SolutionDir)$(ConfigurationName)/Obj/$(ProjectName)"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="1">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_WINDOWS;_NOSDK;_STATIC"
+ ExceptionHandling="FALSE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ BufferSecurityCheck="TRUE"
+ UsePrecompiledHeader="3"
+ PrecompiledHeaderThrough="commonheaders.h"
+ BrowseInformation="1"
+ BrowseInformationFile="$(IntDir)/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="4"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ IgnoreImportLibrary="TRUE"
+ AdditionalDependencies="ws2_32.lib comctl32.lib winmm.lib version.lib"
+ OutputFile="$(OutDir)/$(ProjectName).exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="TRUE"
+ GenerateDebugInformation="TRUE"
+ SubSystem="2"
+ ImportLibrary="$(IntDir)/$(TargetName).lib"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="TRUE"
+ SuppressStartupBanner="TRUE"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Debug/miranda32.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="SDK"
+ Filter="">
+ <File
+ RelativePath="..\include\m_addcontact.h">
+ </File>
+ <File
+ RelativePath="..\include\m_awaymsg.h">
+ </File>
+ <File
+ RelativePath="..\include\m_button.h">
+ </File>
+ <File
+ RelativePath="..\include\m_clc.h">
+ </File>
+ <File
+ RelativePath="..\include\m_clist.h">
+ </File>
+ <File
+ RelativePath="..\include\m_clistint.h">
+ </File>
+ <File
+ RelativePath="..\include\m_clui.h">
+ </File>
+ <File
+ RelativePath="..\include\m_contacts.h">
+ </File>
+ <File
+ RelativePath="..\include\m_database.h">
+ </File>
+ <File
+ RelativePath="..\include\m_email.h">
+ </File>
+ <File
+ RelativePath="..\include\m_file.h">
+ </File>
+ <File
+ RelativePath="..\include\m_findadd.h">
+ </File>
+ <File
+ RelativePath="..\include\m_fuse.h">
+ </File>
+ <File
+ RelativePath="..\include\m_genmenu.h">
+ </File>
+ <File
+ RelativePath="..\include\m_help.h">
+ </File>
+ <File
+ RelativePath="..\include\m_history.h">
+ </File>
+ <File
+ RelativePath="..\include\m_icolib.h">
+ </File>
+ <File
+ RelativePath="..\include\m_icq.h">
+ </File>
+ <File
+ RelativePath="..\include\m_idle.h">
+ </File>
+ <File
+ RelativePath="..\include\m_ignore.h">
+ </File>
+ <File
+ RelativePath="..\include\m_langpack.h">
+ </File>
+ <File
+ RelativePath="..\include\m_message.h">
+ </File>
+ <File
+ RelativePath="..\include\m_netlib.h">
+ </File>
+ <File
+ RelativePath="..\include\m_options.h">
+ </File>
+ <File
+ RelativePath="..\include\m_plugins.h">
+ </File>
+ <File
+ RelativePath="..\include\m_popup.h">
+ </File>
+ <File
+ RelativePath="..\include\m_protocols.h">
+ </File>
+ <File
+ RelativePath="..\include\m_protomod.h">
+ </File>
+ <File
+ RelativePath="..\include\m_protosvc.h">
+ </File>
+ <File
+ RelativePath="..\include\m_sessions.h">
+ </File>
+ <File
+ RelativePath="..\include\m_skin.h">
+ </File>
+ <File
+ RelativePath="..\include\m_system.h">
+ </File>
+ <File
+ RelativePath="..\include\m_system_cpp.h">
+ </File>
+ <File
+ RelativePath="..\include\m_url.h">
+ </File>
+ <File
+ RelativePath="..\include\m_userinfo.h">
+ </File>
+ <File
+ RelativePath="..\include\m_utils.h">
+ </File>
+ <File
+ RelativePath="..\include\newpluginapi.h">
+ </File>
+ <File
+ RelativePath="..\include\statusmodes.h">
+ </File>
+ <File
+ RelativePath="..\include\win2k.h">
+ </File>
+ </Filter>
+ <Filter
+ Name="Core"
+ Filter="">
+ <File
+ RelativePath="core\commonheaders.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ UsePrecompiledHeader="1"
+ PrecompiledHeaderThrough="commonheaders.h"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ UsePrecompiledHeader="1"
+ PrecompiledHeaderThrough="commonheaders.h"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ UsePrecompiledHeader="1"
+ PrecompiledHeaderThrough="commonheaders.h"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ UsePrecompiledHeader="1"
+ PrecompiledHeaderThrough="commonheaders.h"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="core\commonheaders.h">
+ </File>
+ <File
+ RelativePath="core\forkthread.h">
+ </File>
+ <File
+ RelativePath=".\core\memory.cpp">
+ </File>
+ <File
+ RelativePath="core\miranda.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ PrecompiledHeaderThrough="commonheaders.h"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ PrecompiledHeaderThrough="commonheaders.h"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ PrecompiledHeaderThrough="commonheaders.h"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ PrecompiledHeaderThrough="commonheaders.h"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\core\miranda.h">
+ </File>
+ <File
+ RelativePath="core\modules.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ PrecompiledHeaderThrough="commonheaders.h"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ PrecompiledHeaderThrough="commonheaders.h"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ PrecompiledHeaderThrough="commonheaders.h"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ PrecompiledHeaderThrough="commonheaders.h"
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="core\modules.h">
+ </File>
+ </Filter>
+ <Filter
+ Name="Modules"
+ Filter="">
+ <Filter
+ Name="addcontact"
+ Filter="">
+ <File
+ RelativePath="modules\addcontact\addcontact.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="autoaway"
+ Filter="">
+ <File
+ RelativePath="modules\autoaway\autoaway.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="button"
+ Filter="">
+ <File
+ RelativePath="modules\button\button.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="clist"
+ Filter="">
+ <File
+ RelativePath=".\modules\clist\clc.cpp">
+ </File>
+ <File
+ RelativePath=".\modules\clist\clc.h">
+ </File>
+ <File
+ RelativePath=".\modules\clist\clcfiledrop.cpp">
+ </File>
+ <File
+ RelativePath=".\modules\clist\clcidents.cpp">
+ </File>
+ <File
+ RelativePath=".\modules\clist\clcitems.cpp">
+ </File>
+ <File
+ RelativePath=".\modules\clist\clcmsgs.cpp">
+ </File>
+ <File
+ RelativePath=".\modules\clist\clcutils.cpp">
+ </File>
+ <File
+ RelativePath=".\modules\clist\clistcore.cpp">
+ </File>
+ <File
+ RelativePath=".\modules\clist\clistevents.cpp">
+ </File>
+ <File
+ RelativePath=".\modules\clist\clistmenus.cpp">
+ </File>
+ <File
+ RelativePath=".\modules\clist\clistmod.cpp">
+ </File>
+ <File
+ RelativePath=".\modules\clist\clistsettings.cpp">
+ </File>
+ <File
+ RelativePath=".\modules\clist\clisttray.cpp">
+ </File>
+ <File
+ RelativePath=".\modules\clist\clui.cpp">
+ </File>
+ <File
+ RelativePath=".\modules\clist\cluiservices.cpp">
+ </File>
+ <File
+ RelativePath=".\modules\clist\contact.cpp">
+ </File>
+ <File
+ RelativePath=".\modules\clist\Docking.cpp">
+ </File>
+ <File
+ RelativePath=".\modules\clist\genmenu.cpp">
+ </File>
+ <File
+ RelativePath=".\modules\clist\genmenu.h">
+ </File>
+ <File
+ RelativePath=".\modules\clist\genmenuopt.cpp">
+ </File>
+ <File
+ RelativePath=".\modules\clist\groups.cpp">
+ </File>
+ <File
+ RelativePath=".\modules\clist\keyboard.cpp">
+ </File>
+ <File
+ RelativePath=".\modules\clist\movetogroup.cpp">
+ </File>
+ <File
+ RelativePath=".\modules\clist\protocolorder.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="contacts"
+ Filter="">
+ <File
+ RelativePath="modules\contacts\contacts.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="database"
+ Filter="">
+ <File
+ RelativePath="modules\database\database.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\modules\database\dbini.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../../core/commonheaders.h"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../../core/commonheaders.h"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../../core/commonheaders.h"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ PrecompiledHeaderThrough="../../core/commonheaders.h"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="modules\database\dblists.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="modules\database\dblists.h">
+ </File>
+ <File
+ RelativePath=".\modules\database\dbtime.cpp">
+ </File>
+ <File
+ RelativePath=".\modules\database\dbutils.cpp">
+ </File>
+ <File
+ RelativePath=".\modules\database\profilemanager.cpp">
+ </File>
+ <File
+ RelativePath=".\modules\database\profilemanager.h">
+ </File>
+ </Filter>
+ <Filter
+ Name="findadd"
+ Filter="">
+ <File
+ RelativePath="modules\findadd\findadd.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="modules\findadd\findadd.h">
+ </File>
+ <File
+ RelativePath="modules\findadd\searchresults.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="fonts"
+ Filter="">
+ <File
+ RelativePath=".\modules\fonts\FontOptions.cpp">
+ </File>
+ <File
+ RelativePath=".\modules\fonts\FontService.cpp">
+ </File>
+ <File
+ RelativePath=".\modules\fonts\FontService.h">
+ </File>
+ <File
+ RelativePath=".\modules\fonts\services.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="help"
+ Filter="">
+ <File
+ RelativePath="modules\help\about.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="modules\help\help.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="history"
+ Filter="">
+ <File
+ RelativePath="modules\history\history.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="icolib"
+ Filter="">
+ <File
+ RelativePath=".\modules\icolib\extracticon.cpp">
+ </File>
+ <File
+ RelativePath=".\modules\icolib\IcoLib.h">
+ </File>
+ <File
+ RelativePath=".\modules\icolib\skin2icons.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="idle"
+ Filter="">
+ <File
+ RelativePath="modules\idle\idle.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="ignore"
+ Filter="">
+ <File
+ RelativePath="modules\ignore\ignore.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="langpack"
+ Filter="">
+ <File
+ RelativePath="modules\langpack\langpack.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="modules\langpack\lpservices.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="netlib"
+ Filter="">
+ <File
+ RelativePath="modules\netlib\netlib.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="modules\netlib\netlib.h">
+ </File>
+ <File
+ RelativePath="modules\netlib\netlibbind.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="modules\netlib\netlibhttp.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="modules\netlib\netlibhttpproxy.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="modules\netlib\netliblog.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="modules\netlib\netlibopenconn.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="modules\netlib\netlibopts.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="modules\netlib\netlibpktrecver.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\modules\netlib\netlibsecurity.cpp">
+ </File>
+ <File
+ RelativePath="modules\netlib\netlibsock.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\modules\netlib\netlibssl.cpp">
+ </File>
+ <File
+ RelativePath=".\modules\netlib\netlibupnp.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="options"
+ Filter="">
+ <File
+ RelativePath=".\modules\options\descbutton.cpp">
+ </File>
+ <File
+ RelativePath=".\modules\options\filter.cpp">
+ </File>
+ <File
+ RelativePath=".\modules\options\filter.h">
+ </File>
+ <File
+ RelativePath=".\modules\options\headerbar.cpp">
+ </File>
+ <File
+ RelativePath=".\modules\options\iconheader.cpp">
+ </File>
+ <File
+ RelativePath="modules\options\options.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="plugins"
+ Filter="">
+ <File
+ RelativePath="modules\plugins\newplugins.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="protocols"
+ Filter="">
+ <File
+ RelativePath=".\modules\protocols\protoaccs.cpp">
+ </File>
+ <File
+ RelativePath="modules\protocols\protochains.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="modules\protocols\protocols.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\modules\protocols\protoint.cpp">
+ </File>
+ <File
+ RelativePath=".\modules\protocols\protoopts.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="skin"
+ Filter="">
+ <File
+ RelativePath=".\modules\skin\hotkeys.cpp">
+ </File>
+ <File
+ RelativePath="modules\skin\skinicons.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="modules\skin\sounds.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="srauth"
+ Filter="">
+ <File
+ RelativePath="modules\srauth\auth.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="modules\srauth\authdialogs.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="srawaymsg"
+ Filter="">
+ <File
+ RelativePath="modules\srawaymsg\awaymsg.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="modules\srawaymsg\sendmsg.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="sremail"
+ Filter="">
+ <File
+ RelativePath="modules\sremail\email.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="srfile"
+ Filter="">
+ <File
+ RelativePath="modules\srfile\file.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="modules\srfile\file.h">
+ </File>
+ <File
+ RelativePath="modules\srfile\fileexistsdlg.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="modules\srfile\fileopts.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="modules\srfile\filerecvdlg.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="modules\srfile\filesenddlg.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="modules\srfile\filexferdlg.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\modules\srfile\ftmanager.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="srurl"
+ Filter="">
+ <File
+ RelativePath="modules\srurl\url.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="modules\srurl\url.h">
+ </File>
+ <File
+ RelativePath="modules\srurl\urldialogs.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="updater"
+ Filter="">
+ <File
+ RelativePath=".\modules\updatenotify\updatenotify.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="userinfo"
+ Filter="">
+ <File
+ RelativePath="modules\userinfo\contactinfo.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="modules\userinfo\stdinfo.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="modules\userinfo\userinfo.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="useronline"
+ Filter="">
+ <File
+ RelativePath="modules\useronline\useronline.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="utils"
+ Filter="">
+ <File
+ RelativePath="modules\utils\bmpfilter.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="modules\utils\colourpicker.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="modules\utils\hyperlink.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\modules\utils\md5.cpp">
+ </File>
+ <File
+ RelativePath="modules\utils\openurl.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="modules\utils\path.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="modules\utils\resizer.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\modules\utils\sha1.cpp">
+ </File>
+ <File
+ RelativePath=".\modules\utils\utf.cpp">
+ </File>
+ <File
+ RelativePath="modules\utils\utils.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="modules\utils\windowlist.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="visibility"
+ Filter="">
+ <File
+ RelativePath="modules\visibility\visibility.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="1"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BrowseInformation="1"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="xml"
+ Filter="">
+ <File
+ RelativePath=".\modules\xml\xmlApi.cpp">
+ </File>
+ <File
+ RelativePath=".\modules\xml\xmlParser.cpp">
+ </File>
+ <File
+ RelativePath=".\modules\xml\xmlParser.h">
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="Resources"
+ Filter="">
+ <File
+ RelativePath=".\res\_blank.ico">
+ </File>
+ <File
+ RelativePath=".\res\arrow_sort_column_down.bmp">
+ </File>
+ <File
+ RelativePath=".\res\arrow_sort_column_up.bmp">
+ </File>
+ <File
+ RelativePath=".\res\check_off.ico">
+ </File>
+ <File
+ RelativePath=".\res\check_on.ico">
+ </File>
+ <File
+ RelativePath=".\res\contact_add.ico">
+ </File>
+ <File
+ RelativePath=".\res\contact_delete.ico">
+ </File>
+ <File
+ RelativePath=".\res\contact_rename.ico">
+ </File>
+ <File
+ RelativePath=".\res\contact_view_details.ico">
+ </File>
+ <File
+ RelativePath="..\docs\contributors.txt">
+ </File>
+ <File
+ RelativePath=".\res\cursor_drag_copy.cur">
+ </File>
+ <File
+ RelativePath=".\res\cursor_drop_user.cur">
+ </File>
+ <File
+ RelativePath=".\res\cursor_hyperlink.cur">
+ </File>
+ <File
+ RelativePath=".\res\group_closed.ico">
+ </File>
+ <File
+ RelativePath=".\res\group_opened.ico">
+ </File>
+ <File
+ RelativePath=".\res\icon_accmgr.ico">
+ </File>
+ <File
+ RelativePath=".\res\icon_all.ico">
+ </File>
+ <File
+ RelativePath=".\res\icon_ansi.ico">
+ </File>
+ <File
+ RelativePath=".\res\icon_auth_request.ico">
+ </File>
+ <File
+ RelativePath=".\res\icon_connecting.ico">
+ </File>
+ <File
+ RelativePath=".\res\icon_down_arrow.ico">
+ </File>
+ <File
+ RelativePath=".\res\icon_file.ico">
+ </File>
+ <File
+ RelativePath=".\res\icon_find_user.ico">
+ </File>
+ <File
+ RelativePath=".\res\icon_help.ico">
+ </File>
+ <File
+ RelativePath=".\res\icon_history.ico">
+ </File>
+ <File
+ RelativePath=".\res\icon_loaded.ico">
+ </File>
+ <File
+ RelativePath=".\res\icon_mail.ico">
+ </File>
+ <File
+ RelativePath=".\res\icon_message.ico">
+ </File>
+ <File
+ RelativePath=".\res\icon_notloaded.ico">
+ </File>
+ <File
+ RelativePath=".\res\icon_options.ico">
+ </File>
+ <File
+ RelativePath=".\res\icon_search_all.ico">
+ </File>
+ <File
+ RelativePath=".\res\icon_small_dot.ico">
+ </File>
+ <File
+ RelativePath=".\res\icon_sms.ico">
+ </File>
+ <File
+ RelativePath=".\res\icon_typing.ico">
+ </File>
+ <File
+ RelativePath=".\res\icon_undo.ico">
+ </File>
+ <File
+ RelativePath=".\res\icon_unicode.ico">
+ </File>
+ <File
+ RelativePath=".\res\icon_url.ico">
+ </File>
+ <File
+ RelativePath=".\res\icon_window.ico">
+ </File>
+ <File
+ RelativePath=".\res\icon_windows.ico">
+ </File>
+ <File
+ RelativePath=".\res\load.ico">
+ </File>
+ <File
+ RelativePath=".\manifest.rc">
+ </File>
+ <File
+ RelativePath=".\res\miranda_home.ico">
+ </File>
+ <File
+ RelativePath=".\res\miranda_logo.ico">
+ </File>
+ <File
+ RelativePath=".\res\miranda_manager.ico">
+ </File>
+ <File
+ RelativePath="resource.h">
+ </File>
+ <File
+ RelativePath="resource.rc">
+ </File>
+ <File
+ RelativePath=".\res\status_away.ico">
+ </File>
+ <File
+ RelativePath=".\res\status_DND.ico">
+ </File>
+ <File
+ RelativePath=".\res\status_free4chat.ico">
+ </File>
+ <File
+ RelativePath=".\res\status_invisible.ico">
+ </File>
+ <File
+ RelativePath=".\res\status_NA.ico">
+ </File>
+ <File
+ RelativePath=".\res\status_occupied.ico">
+ </File>
+ <File
+ RelativePath=".\res\status_offline.ico">
+ </File>
+ <File
+ RelativePath=".\res\status_on_the_phone.ico">
+ </File>
+ <File
+ RelativePath=".\res\status_online.ico">
+ </File>
+ <File
+ RelativePath=".\res\status_out2lunch.ico">
+ </File>
+ <File
+ RelativePath=".\res\status_user_online.ico">
+ </File>
+ <File
+ RelativePath=".\res\typing.ico">
+ </File>
+ <File
+ RelativePath=".\version.rc">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/src/miranda32_10.vcxproj b/src/miranda32_10.vcxproj
new file mode 100644
index 0000000000..1839a01aed
--- /dev/null
+++ b/src/miranda32_10.vcxproj
@@ -0,0 +1,759 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug Unicode|Win32">
+ <Configuration>Debug Unicode</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug Unicode|x64">
+ <Configuration>Debug Unicode</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release Unicode|Win32">
+ <Configuration>Release Unicode</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release Unicode|x64">
+ <Configuration>Release Unicode</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectName>miranda32</ProjectName>
+ <ProjectGuid>{F9916510-9055-4C9F-997A-3755DEC1511B}</ProjectGuid>
+ <RootNamespace>miranda32</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug Unicode|Win32'" Label="Configuration">
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release Unicode|Win32'" Label="Configuration">
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug Unicode|x64'" Label="Configuration">
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release Unicode|x64'" Label="Configuration">
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug Unicode|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release Unicode|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug Unicode|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release Unicode|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.30128.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Configuration)/Obj/$(ProjectName)\</IntDir>
+ <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</IgnoreImportLibrary>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)64\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(SolutionDir)$(Configuration)64/Obj/$(ProjectName)\</IntDir>
+ <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</IgnoreImportLibrary>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Configuration)/Obj/$(ProjectName)\</IntDir>
+ <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</IgnoreImportLibrary>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Configuration)64\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(SolutionDir)$(Configuration)64/Obj/$(ProjectName)\</IntDir>
+ <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</IgnoreImportLibrary>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release Unicode|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release Unicode|Win32'">$(SolutionDir)$(Configuration)/Obj/$(ProjectName)\</IntDir>
+ <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Release Unicode|Win32'">true</IgnoreImportLibrary>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release Unicode|x64'">$(SolutionDir)$(Configuration)64\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release Unicode|x64'">$(SolutionDir)$(Configuration)64/Obj/$(ProjectName)\</IntDir>
+ <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Release Unicode|x64'">true</IgnoreImportLibrary>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug Unicode|Win32'">$(SolutionDir)$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug Unicode|Win32'">$(SolutionDir)$(Configuration)/Obj/$(ProjectName)\</IntDir>
+ <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Debug Unicode|Win32'">true</IgnoreImportLibrary>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug Unicode|x64'">$(SolutionDir)$(Configuration)64/Obj/$(ProjectName)\</IntDir>
+ <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Debug Unicode|x64'">true</IgnoreImportLibrary>
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug Unicode|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug Unicode|Win32'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug Unicode|Win32'" />
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug Unicode|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug Unicode|x64'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug Unicode|x64'" />
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release Unicode|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release Unicode|Win32'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release Unicode|Win32'" />
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release Unicode|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release Unicode|x64'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release Unicode|x64'" />
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug Unicode|x64'">$(SolutionDir)$(Configuration)64\</OutDir>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug Unicode|x64'">miranda64</TargetName>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">miranda64</TargetName>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Release Unicode|x64'">miranda64</TargetName>
+ <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">miranda64</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Midl>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>Win32</TargetEnvironment>
+ <TypeLibraryName>.\Release/miranda32.tlb</TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <AdditionalIncludeDirectories>../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>NDEBUG;WIN32;_WINDOWS;_NOSDK;_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <ExceptionHandling>false</ExceptionHandling>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <FloatingPointModel>Fast</FloatingPointModel>
+ <RuntimeTypeInfo>false</RuntimeTypeInfo>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PrecompiledHeaderFile>commonheaders.h</PrecompiledHeaderFile>
+ <WarningLevel>Level3</WarningLevel>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <BufferSecurityCheck>false</BufferSecurityCheck>
+ <FloatingPointExceptions>false</FloatingPointExceptions>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0409</Culture>
+ <AdditionalIncludeDirectories>./../include/msapi/</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>wsock32.lib;comctl32.lib;winmm.lib;version.lib;crypt32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <AdditionalManifestDependencies>type=%27win32%27 name=%27Microsoft.Windows.Common-Controls%27 version=%276.0.0.0%27 processorArchitecture=%27*%27 publicKeyToken=%276595b64144ccf1df%27 language=%27*%27;type=%27win32%27 name=%27Microsoft.Windows.Gdiplus%27 version=%271.0.0.0%27 processorArchitecture=%27X86%27 publicKeyToken=%276595b64144ccf1df%27 language=%27*%27;%(AdditionalManifestDependencies)</AdditionalManifestDependencies>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Windows</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Midl>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>X64</TargetEnvironment>
+ <TypeLibraryName>.\Release/miranda32.tlb</TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <AdditionalIncludeDirectories>../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>NDEBUG;WIN32;_WINDOWS;_NOSDK;_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <ExceptionHandling>false</ExceptionHandling>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <RuntimeTypeInfo>false</RuntimeTypeInfo>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PrecompiledHeaderFile>commonheaders.h</PrecompiledHeaderFile>
+ <WarningLevel>Level3</WarningLevel>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <BufferSecurityCheck>false</BufferSecurityCheck>
+ <FloatingPointModel>Fast</FloatingPointModel>
+ <FloatingPointExceptions>false</FloatingPointExceptions>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0409</Culture>
+ <AdditionalIncludeDirectories>./../include/msapi/</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>wsock32.lib;comctl32.lib;winmm.lib;version.lib;crypt32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <AdditionalManifestDependencies>type=%27win32%27 name=%27Microsoft.Windows.Common-Controls%27 version=%276.0.0.0%27 processorArchitecture=%27*%27 publicKeyToken=%276595b64144ccf1df%27 language=%27*%27;type=%27win32%27 name=%27Microsoft.Windows.Gdiplus%27 version=%271.0.0.0%27 processorArchitecture=%27amd64%27 publicKeyToken=%276595b64144ccf1df%27 language=%27*%27;%(AdditionalManifestDependencies)</AdditionalManifestDependencies>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Windows</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX64</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Midl>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>Win32</TargetEnvironment>
+ <TypeLibraryName>.\Debug/miranda32.tlb</TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_DEBUG;WIN32;_WINDOWS;_NOSDK;_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PrecompiledHeaderFile>commonheaders.h</PrecompiledHeaderFile>
+ <WarningLevel>Level3</WarningLevel>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0409</Culture>
+ <AdditionalIncludeDirectories>./../include/msapi/</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>wsock32.lib;comctl32.lib;winmm.lib;version.lib;crypt32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <AdditionalManifestDependencies>type=%27win32%27 name=%27Microsoft.Windows.Common-Controls%27 version=%276.0.0.0%27 processorArchitecture=%27*%27 publicKeyToken=%276595b64144ccf1df%27 language=%27*%27;type=%27win32%27 name=%27Microsoft.Windows.Gdiplus%27 version=%271.0.0.0%27 processorArchitecture=%27X86%27 publicKeyToken=%276595b64144ccf1df%27 language=%27*%27;%(AdditionalManifestDependencies)</AdditionalManifestDependencies>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Windows</SubSystem>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Midl>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>X64</TargetEnvironment>
+ <TypeLibraryName>.\Debug/miranda32.tlb</TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_DEBUG;WIN32;_WINDOWS;_NOSDK;_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PrecompiledHeaderFile>commonheaders.h</PrecompiledHeaderFile>
+ <WarningLevel>Level3</WarningLevel>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0409</Culture>
+ <AdditionalIncludeDirectories>./../include/msapi/</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>wsock32.lib;comctl32.lib;winmm.lib;version.lib;crypt32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <AdditionalManifestDependencies>type=%27win32%27 name=%27Microsoft.Windows.Common-Controls%27 version=%276.0.0.0%27 processorArchitecture=%27*%27 publicKeyToken=%276595b64144ccf1df%27 language=%27*%27;type=%27win32%27 name=%27Microsoft.Windows.Gdiplus%27 version=%271.0.0.0%27 processorArchitecture=%27amd64%27 publicKeyToken=%276595b64144ccf1df%27 language=%27*%27;%(AdditionalManifestDependencies)</AdditionalManifestDependencies>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Windows</SubSystem>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX64</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release Unicode|Win32'">
+ <Midl>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>Win32</TargetEnvironment>
+ <TypeLibraryName>.\Release/miranda32.tlb</TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <AdditionalIncludeDirectories>../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>NDEBUG;WIN32;_WINDOWS;_NOSDK;_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <ExceptionHandling>false</ExceptionHandling>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <RuntimeTypeInfo>false</RuntimeTypeInfo>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PrecompiledHeaderFile>commonheaders.h</PrecompiledHeaderFile>
+ <WarningLevel>Level3</WarningLevel>
+ <DisableSpecificWarnings>4996;4706;4127;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <BufferSecurityCheck>false</BufferSecurityCheck>
+ <FloatingPointModel>Fast</FloatingPointModel>
+ <FloatingPointExceptions>false</FloatingPointExceptions>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0409</Culture>
+ <AdditionalIncludeDirectories>./../include/msapi/</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>wsock32.lib;comctl32.lib;winmm.lib;version.lib;crypt32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalManifestDependencies>type=%27win32%27 name=%27Microsoft.Windows.Common-Controls%27 version=%276.0.0.0%27 processorArchitecture=%27*%27 publicKeyToken=%276595b64144ccf1df%27 language=%27*%27;type=%27win32%27 name=%27Microsoft.Windows.Gdiplus%27 version=%271.0.0.0%27 processorArchitecture=%27X86%27 publicKeyToken=%276595b64144ccf1df%27 language=%27*%27;%(AdditionalManifestDependencies)</AdditionalManifestDependencies>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Windows</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release Unicode|x64'">
+ <Midl>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>X64</TargetEnvironment>
+ <TypeLibraryName>.\Release/miranda32.tlb</TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
+ <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <AdditionalIncludeDirectories>../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>NDEBUG;WIN32;_WINDOWS;_NOSDK;_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <ExceptionHandling>false</ExceptionHandling>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <RuntimeTypeInfo>false</RuntimeTypeInfo>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PrecompiledHeaderFile>commonheaders.h</PrecompiledHeaderFile>
+ <WarningLevel>Level3</WarningLevel>
+ <DisableSpecificWarnings>4996;4706;4127;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <BufferSecurityCheck>false</BufferSecurityCheck>
+ <FloatingPointModel>Fast</FloatingPointModel>
+ <FloatingPointExceptions>false</FloatingPointExceptions>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0409</Culture>
+ <AdditionalIncludeDirectories>./../include/msapi/</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>wsock32.lib;comctl32.lib;winmm.lib;version.lib;crypt32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalManifestDependencies>type=%27win32%27 name=%27Microsoft.Windows.Common-Controls%27 version=%276.0.0.0%27 processorArchitecture=%27*%27 publicKeyToken=%276595b64144ccf1df%27 language=%27*%27;type=%27win32%27 name=%27Microsoft.Windows.Gdiplus%27 version=%271.0.0.0%27 processorArchitecture=%27amd64%27 publicKeyToken=%276595b64144ccf1df%27 language=%27*%27;%(AdditionalManifestDependencies)</AdditionalManifestDependencies>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Windows</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX64</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug Unicode|Win32'">
+ <Midl>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>Win32</TargetEnvironment>
+ <TypeLibraryName>.\Debug/miranda32.tlb</TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_DEBUG;WIN32;_WINDOWS;_NOSDK;_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>false</StringPooling>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <FloatingPointModel>Precise</FloatingPointModel>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PrecompiledHeaderFile>commonheaders.h</PrecompiledHeaderFile>
+ <WarningLevel>Level3</WarningLevel>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0409</Culture>
+ <AdditionalIncludeDirectories>./../include/msapi/</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>wsock32.lib;comctl32.lib;winmm.lib;version.lib;crypt32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <AdditionalManifestDependencies>type=%27win32%27 name=%27Microsoft.Windows.Common-Controls%27 version=%276.0.0.0%27 processorArchitecture=%27*%27 publicKeyToken=%276595b64144ccf1df%27 language=%27*%27;type=%27win32%27 name=%27Microsoft.Windows.Gdiplus%27 version=%271.0.0.0%27 processorArchitecture=%27X86%27 publicKeyToken=%276595b64144ccf1df%27 language=%27*%27;%(AdditionalManifestDependencies)</AdditionalManifestDependencies>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(TargetDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <SubSystem>Windows</SubSystem>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug Unicode|x64'">
+ <Midl>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>X64</TargetEnvironment>
+ <TypeLibraryName>.\Debug/miranda32.tlb</TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>../include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>_DEBUG;WIN32;_WINDOWS;_NOSDK;_STATIC;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>false</StringPooling>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <FloatingPointModel>Precise</FloatingPointModel>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PrecompiledHeaderFile>commonheaders.h</PrecompiledHeaderFile>
+ <WarningLevel>Level3</WarningLevel>
+ <DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ </ClCompile>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0409</Culture>
+ <AdditionalIncludeDirectories>./../include/msapi/</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>ws2_32.lib;comctl32.lib;winmm.lib;version.lib;crypt32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <AdditionalManifestDependencies>type=%27win32%27 name=%27Microsoft.Windows.Common-Controls%27 version=%276.0.0.0%27 processorArchitecture=%27*%27 publicKeyToken=%276595b64144ccf1df%27 language=%27*%27;type=%27win32%27 name=%27Microsoft.Windows.Gdiplus%27 version=%271.0.0.0%27 processorArchitecture=%27amd64%27 publicKeyToken=%276595b64144ccf1df%27 language=%27*%27;%(AdditionalManifestDependencies)</AdditionalManifestDependencies>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(TargetDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <SubSystem>Windows</SubSystem>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ <TargetMachine>MachineX64</TargetMachine>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClInclude Include="..\include\m_addcontact.h" />
+ <ClInclude Include="..\include\m_awaymsg.h" />
+ <ClInclude Include="..\include\m_button.h" />
+ <ClInclude Include="..\include\m_clc.h" />
+ <ClInclude Include="..\include\m_clist.h" />
+ <ClInclude Include="..\include\m_clistint.h" />
+ <ClInclude Include="..\include\m_clui.h" />
+ <ClInclude Include="..\include\m_contacts.h" />
+ <ClInclude Include="..\include\m_database.h" />
+ <ClInclude Include="..\include\m_email.h" />
+ <ClInclude Include="..\include\m_file.h" />
+ <ClInclude Include="..\include\m_findadd.h" />
+ <ClInclude Include="..\include\m_fuse.h" />
+ <ClInclude Include="..\include\m_history.h" />
+ <ClInclude Include="..\include\m_hotkeys.h" />
+ <ClInclude Include="..\include\m_icq.h" />
+ <ClInclude Include="..\include\m_idle.h" />
+ <ClInclude Include="..\include\m_ignore.h" />
+ <ClInclude Include="..\include\m_langpack.h" />
+ <ClInclude Include="..\include\m_message.h" />
+ <ClInclude Include="..\include\m_netlib.h" />
+ <ClInclude Include="..\include\m_options.h" />
+ <ClInclude Include="..\include\m_plugins.h" />
+ <ClInclude Include="..\include\m_popup.h" />
+ <ClInclude Include="..\include\m_protocols.h" />
+ <ClInclude Include="..\include\m_protomod.h" />
+ <ClInclude Include="..\include\m_protosvc.h" />
+ <ClInclude Include="..\include\m_skin.h" />
+ <ClInclude Include="..\include\m_system.h" />
+ <ClInclude Include="..\include\m_system_cpp.h" />
+ <ClInclude Include="..\include\m_timezones.h" />
+ <ClInclude Include="..\include\m_url.h" />
+ <ClInclude Include="..\include\m_userinfo.h" />
+ <ClInclude Include="..\include\m_utils.h" />
+ <ClInclude Include="..\include\newpluginapi.h" />
+ <ClInclude Include="..\include\statusmodes.h" />
+ <ClInclude Include="..\include\win2k.h" />
+ <ClInclude Include="core\commonheaders.h" />
+ <ClInclude Include="core\forkthread.h" />
+ <ClInclude Include="core\miranda.h" />
+ <ClInclude Include="core\modules.h" />
+ <ClInclude Include="modules\database\dblists.h" />
+ <ClInclude Include="modules\database\profilemanager.h" />
+ <ClInclude Include="modules\findadd\findadd.h" />
+ <ClInclude Include="modules\netlib\netlib.h" />
+ <ClInclude Include="modules\options\filter.h" />
+ <ClInclude Include="..\include\m_protoint.h" />
+ <ClInclude Include="modules\srfile\file.h" />
+ <ClInclude Include="modules\srurl\url.h" />
+ <ClInclude Include="modules\clist\clc.h" />
+ <ClInclude Include="modules\clist\genmenu.h" />
+ <ClInclude Include="modules\fonts\FontService.h" />
+ <ClInclude Include="modules\icolib\IcoLib.h" />
+ <ClInclude Include="..\include\m_xml.h" />
+ <ClInclude Include="modules\xml\xmlParser.h" />
+ <ClInclude Include="resource.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="core\commonheaders.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug Unicode|Win32'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release Unicode|Win32'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug Unicode|x64'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release Unicode|x64'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="core\memory.cpp" />
+ <ClCompile Include="core\miranda.cpp" />
+ <ClCompile Include="core\modules.cpp" />
+ <ClCompile Include="modules\addcontact\addcontact.cpp" />
+ <ClCompile Include="modules\autoaway\autoaway.cpp" />
+ <ClCompile Include="modules\button\button.cpp" />
+ <ClCompile Include="modules\contacts\contacts.cpp" />
+ <ClCompile Include="modules\database\database.cpp" />
+ <ClCompile Include="modules\database\dbini.cpp" />
+ <ClCompile Include="modules\database\dblists.cpp" />
+ <ClCompile Include="modules\database\dbutils.cpp" />
+ <ClCompile Include="modules\database\profilemanager.cpp" />
+ <ClCompile Include="modules\findadd\findadd.cpp" />
+ <ClCompile Include="modules\findadd\searchresults.cpp" />
+ <ClCompile Include="modules\help\about.cpp" />
+ <ClCompile Include="modules\help\help.cpp" />
+ <ClCompile Include="modules\history\history.cpp" />
+ <ClCompile Include="modules\idle\idle.cpp" />
+ <ClCompile Include="modules\ignore\ignore.cpp" />
+ <ClCompile Include="modules\langpack\langpack.cpp" />
+ <ClCompile Include="modules\langpack\lpservices.cpp" />
+ <ClCompile Include="modules\netlib\netlib.cpp" />
+ <ClCompile Include="modules\netlib\netlibautoproxy.cpp" />
+ <ClCompile Include="modules\netlib\netlibbind.cpp" />
+ <ClCompile Include="modules\netlib\netlibhttp.cpp" />
+ <ClCompile Include="modules\netlib\netlibhttpproxy.cpp" />
+ <ClCompile Include="modules\netlib\netliblog.cpp" />
+ <ClCompile Include="modules\netlib\netlibopenconn.cpp" />
+ <ClCompile Include="modules\netlib\netlibopts.cpp" />
+ <ClCompile Include="modules\netlib\netlibpktrecver.cpp" />
+ <ClCompile Include="modules\netlib\netlibsecurity.cpp" />
+ <ClCompile Include="modules\netlib\netlibsock.cpp" />
+ <ClCompile Include="modules\netlib\netlibssl.cpp" />
+ <ClCompile Include="modules\netlib\netlibupnp.cpp" />
+ <ClCompile Include="modules\options\descbutton.cpp" />
+ <ClCompile Include="modules\options\filter.cpp" />
+ <ClCompile Include="modules\options\headerbar.cpp" />
+ <ClCompile Include="modules\options\iconheader.cpp" />
+ <ClCompile Include="modules\options\options.cpp" />
+ <ClCompile Include="modules\plugins\newplugins.cpp" />
+ <ClCompile Include="modules\protocols\protoaccs.cpp" />
+ <ClCompile Include="modules\protocols\protochains.cpp" />
+ <ClCompile Include="modules\protocols\protocols.cpp" />
+ <ClCompile Include="modules\protocols\protoint.cpp" />
+ <ClCompile Include="modules\protocols\protoopts.cpp" />
+ <ClCompile Include="modules\skin\hotkeys.cpp" />
+ <ClCompile Include="modules\skin\skinicons.cpp" />
+ <ClCompile Include="modules\skin\sounds.cpp" />
+ <ClCompile Include="modules\srauth\auth.cpp" />
+ <ClCompile Include="modules\srauth\authdialogs.cpp" />
+ <ClCompile Include="modules\srawaymsg\awaymsg.cpp" />
+ <ClCompile Include="modules\srawaymsg\sendmsg.cpp" />
+ <ClCompile Include="modules\sremail\email.cpp" />
+ <ClCompile Include="modules\srfile\file.cpp" />
+ <ClCompile Include="modules\srfile\fileexistsdlg.cpp" />
+ <ClCompile Include="modules\srfile\fileopts.cpp" />
+ <ClCompile Include="modules\srfile\filerecvdlg.cpp" />
+ <ClCompile Include="modules\srfile\filesenddlg.cpp" />
+ <ClCompile Include="modules\srfile\filexferdlg.cpp" />
+ <ClCompile Include="modules\srfile\ftmanager.cpp" />
+ <ClCompile Include="modules\srurl\url.cpp" />
+ <ClCompile Include="modules\srurl\urldialogs.cpp" />
+ <ClCompile Include="modules\updatenotify\updatenotify.cpp" />
+ <ClCompile Include="modules\userinfo\contactinfo.cpp" />
+ <ClCompile Include="modules\userinfo\stdinfo.cpp" />
+ <ClCompile Include="modules\userinfo\userinfo.cpp" />
+ <ClCompile Include="modules\useronline\useronline.cpp" />
+ <ClCompile Include="modules\utils\bmpfilter.cpp" />
+ <ClCompile Include="modules\utils\colourpicker.cpp" />
+ <ClCompile Include="modules\utils\hyperlink.cpp" />
+ <ClCompile Include="modules\utils\imgconv.cpp" />
+ <ClCompile Include="modules\utils\md5.cpp" />
+ <ClCompile Include="modules\utils\openurl.cpp" />
+ <ClCompile Include="modules\utils\path.cpp" />
+ <ClCompile Include="modules\utils\resizer.cpp" />
+ <ClCompile Include="modules\utils\sha1.cpp" />
+ <ClCompile Include="modules\utils\timeutils.cpp" />
+ <ClCompile Include="modules\utils\timezones.cpp" />
+ <ClCompile Include="modules\utils\utf.cpp" />
+ <ClCompile Include="modules\utils\utils.cpp" />
+ <ClCompile Include="modules\utils\windowlist.cpp" />
+ <ClCompile Include="modules\visibility\visibility.cpp" />
+ <ClCompile Include="modules\clist\clc.cpp" />
+ <ClCompile Include="modules\clist\clcfiledrop.cpp" />
+ <ClCompile Include="modules\clist\clcidents.cpp" />
+ <ClCompile Include="modules\clist\clcitems.cpp" />
+ <ClCompile Include="modules\clist\clcmsgs.cpp" />
+ <ClCompile Include="modules\clist\clcutils.cpp" />
+ <ClCompile Include="modules\clist\clistcore.cpp" />
+ <ClCompile Include="modules\clist\clistevents.cpp" />
+ <ClCompile Include="modules\clist\clistmenus.cpp" />
+ <ClCompile Include="modules\clist\clistmod.cpp" />
+ <ClCompile Include="modules\clist\clistsettings.cpp" />
+ <ClCompile Include="modules\clist\clisttray.cpp" />
+ <ClCompile Include="modules\clist\clui.cpp" />
+ <ClCompile Include="modules\clist\cluiservices.cpp" />
+ <ClCompile Include="modules\clist\contact.cpp" />
+ <ClCompile Include="modules\clist\Docking.cpp" />
+ <ClCompile Include="modules\clist\genmenu.cpp" />
+ <ClCompile Include="modules\clist\genmenuopt.cpp" />
+ <ClCompile Include="modules\clist\groups.cpp" />
+ <ClCompile Include="modules\clist\keyboard.cpp" />
+ <ClCompile Include="modules\clist\movetogroup.cpp" />
+ <ClCompile Include="modules\clist\protocolorder.cpp" />
+ <ClCompile Include="modules\fonts\FontOptions.cpp" />
+ <ClCompile Include="modules\fonts\FontService.cpp" />
+ <ClCompile Include="modules\fonts\services.cpp" />
+ <ClCompile Include="modules\icolib\extracticon.cpp" />
+ <ClCompile Include="modules\icolib\skin2icons.cpp" />
+ <ClCompile Include="modules\xml\xmlApi.cpp" />
+ <ClCompile Include="modules\xml\xmlParser.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="..\protocols\JabberG\docs\translation_jabber.txt" />
+ <None Include="res\Off.ico" />
+ <None Include="res\On.ico" />
+ <None Include="res\_blank.ico" />
+ <None Include="res\arrow_sort_column_down.bmp" />
+ <None Include="res\arrow_sort_column_up.bmp" />
+ <None Include="res\chat_join.ico" />
+ <None Include="res\chat_leave.ico" />
+ <None Include="res\check_off.ico" />
+ <None Include="res\check_on.ico" />
+ <None Include="res\contact_add.ico" />
+ <None Include="res\contact_delete.ico" />
+ <None Include="res\contact_groups.ico" />
+ <None Include="res\contact_rename.ico" />
+ <None Include="res\contact_view_details.ico" />
+ <None Include="..\docs\contributors.txt" />
+ <None Include="..\docs\credits.txt" />
+ <None Include="res\cursor_drag_copy.cur" />
+ <None Include="res\cursor_drop_user.cur" />
+ <None Include="res\cursor_hyperlink.cur" />
+ <None Include="res\group_closed.ico" />
+ <None Include="res\group_opened.ico" />
+ <None Include="res\icon_accmgr.ico" />
+ <None Include="res\icon_all.ico" />
+ <None Include="res\icon_ansi.ico" />
+ <None Include="res\icon_auth_request.ico" />
+ <None Include="res\icon_connecting.ico" />
+ <None Include="res\icon_down_arrow.ico" />
+ <None Include="res\Icon_exit.ico" />
+ <None Include="res\icon_file.ico" />
+ <None Include="res\icon_find_user.ico" />
+ <None Include="res\icon_help.ico" />
+ <None Include="res\icon_history.ico" />
+ <None Include="res\icon_loaded.ico" />
+ <None Include="res\icon_mail.ico" />
+ <None Include="res\icon_message.ico" />
+ <None Include="res\icon_notloaded.ico" />
+ <None Include="res\icon_options.ico" />
+ <None Include="res\icon_search_all.ico" />
+ <None Include="res\Icon_show_hide.ico" />
+ <None Include="res\icon_small_dot.ico" />
+ <None Include="res\icon_sms.ico" />
+ <None Include="res\icon_typing.ico" />
+ <None Include="res\icon_undo.ico" />
+ <None Include="res\icon_unicode.ico" />
+ <None Include="res\icon_url.ico" />
+ <None Include="res\icon_window.ico" />
+ <None Include="res\icon_windows.ico" />
+ <None Include="res\miranda_home.ico" />
+ <None Include="res\miranda_logo.ico" />
+ <None Include="res\miranda_manager.ico" />
+ <None Include="res\status_away.ico" />
+ <None Include="res\status_DND.ico" />
+ <None Include="res\status_free4chat.ico" />
+ <None Include="res\status_invisible.ico" />
+ <None Include="res\status_locked.ico" />
+ <None Include="res\status_NA.ico" />
+ <None Include="res\status_occupied.ico" />
+ <None Include="res\status_offline.ico" />
+ <None Include="res\status_on_the_phone.ico" />
+ <None Include="res\status_online.ico" />
+ <None Include="res\status_out2lunch.ico" />
+ <None Include="res\status_user_online.ico" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="resource.rc" />
+ <ResourceCompile Include="version.rc" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\plugins\zlib\zlib_10.vcxproj">
+ <Project>{e2a369cd-eda3-414f-8ad0-e732cd7ee68c}</Project>
+ <ReferenceOutputAssembly>false</ReferenceOutputAssembly>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/src/miranda32_10.vcxproj.filters b/src/miranda32_10.vcxproj.filters
new file mode 100644
index 0000000000..ad4a60a1c6
--- /dev/null
+++ b/src/miranda32_10.vcxproj.filters
@@ -0,0 +1,814 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="SDK">
+ <UniqueIdentifier>{9263229c-5f0c-40b1-90c1-9f09be9d7dcc}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Core">
+ <UniqueIdentifier>{9a75b1ab-85d2-4231-b3a8-633eb85d8506}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Modules">
+ <UniqueIdentifier>{ad89ee42-29f6-4b6b-9316-11f7cad2f75b}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Modules\addcontact">
+ <UniqueIdentifier>{edb05be9-a16a-4f37-8035-711e5286311f}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Modules\autoaway">
+ <UniqueIdentifier>{3e3f52bd-7183-4064-8803-93a7d3c57925}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Modules\button">
+ <UniqueIdentifier>{880105c7-0ef2-41ee-9541-fe2c9e5a7679}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Modules\contacts">
+ <UniqueIdentifier>{3e919355-7099-4252-be9f-46e5b4f6bbc7}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Modules\database">
+ <UniqueIdentifier>{a4463881-5b8c-497a-b5f4-5832dbc5fbfa}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Modules\findadd">
+ <UniqueIdentifier>{ada379e5-5553-4316-b4f0-62f2f60e8540}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Modules\help">
+ <UniqueIdentifier>{51edc105-758f-4472-bf65-59e307fd25e1}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Modules\history">
+ <UniqueIdentifier>{0dba3b26-757e-488d-bcb2-8b63ab5fe948}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Modules\idle">
+ <UniqueIdentifier>{8409f336-1269-46d8-878c-a93588927a66}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Modules\ignore">
+ <UniqueIdentifier>{4f9373ec-57ce-4c35-9217-9ffc5aefa841}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Modules\langpack">
+ <UniqueIdentifier>{384c1011-28ee-43b0-8bd7-33e316792bc3}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Modules\netlib">
+ <UniqueIdentifier>{3bd450f7-3173-4cb6-8eea-23acebcb8671}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Modules\options">
+ <UniqueIdentifier>{ec6cab41-4990-429f-b01f-db0f3a8d1ba6}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Modules\plugins">
+ <UniqueIdentifier>{6f3414dd-ebb2-43d1-b17a-56117abfac62}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Modules\protocols">
+ <UniqueIdentifier>{9bea12c5-dd45-4fd2-906c-a0f1cc89fe29}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Modules\skin">
+ <UniqueIdentifier>{474a2558-48fd-45d5-b8e8-3a07d780f02a}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Modules\srauth">
+ <UniqueIdentifier>{ec3937ae-458b-400e-a9de-8f1923e993ed}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Modules\srawaymsg">
+ <UniqueIdentifier>{ede3d43b-a5cf-462a-90df-4ddd7a091234}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Modules\sremail">
+ <UniqueIdentifier>{0a314e80-e4e2-4ba9-a4b7-683df1e66538}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Modules\srfile">
+ <UniqueIdentifier>{3fbbdcec-4a5c-4c83-8e94-724103f35d47}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Modules\srurl">
+ <UniqueIdentifier>{e470787f-f935-4619-a98e-dfdb01ffa83e}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Modules\updater">
+ <UniqueIdentifier>{9074e889-f17c-4c90-a3cf-1cfb2e513491}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Modules\userinfo">
+ <UniqueIdentifier>{34172b4f-5cec-4166-8610-1537127749d9}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Modules\useronline">
+ <UniqueIdentifier>{daa4af16-7ada-4bd5-92bb-59f5ab815e9c}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Modules\utils">
+ <UniqueIdentifier>{4549cb1a-17d4-49a2-82e9-3acd7e17f5bc}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Modules\visibility">
+ <UniqueIdentifier>{a0e1084a-b62f-4bc2-a973-8fcc2df5deae}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Modules\clist">
+ <UniqueIdentifier>{c0446d71-a213-4c3a-ac52-98af890c5dcf}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Modules\fonts">
+ <UniqueIdentifier>{4c1e9a4f-27f1-4c36-9efe-ca1b4f586f06}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Modules\icolib">
+ <UniqueIdentifier>{021bd45a-8d83-4aca-83df-ac43192b922a}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Modules\xmlparser">
+ <UniqueIdentifier>{c3bf6128-d3fd-44f6-a207-df2977019960}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resources">
+ <UniqueIdentifier>{dcc9b0d7-b335-458b-ac09-6cc6cf55e397}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\include\m_addcontact.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\m_awaymsg.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\m_button.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\m_clc.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\m_clist.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\m_clistint.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\m_clui.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\m_contacts.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\m_database.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\m_email.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\m_file.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\m_findadd.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\m_fuse.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\m_history.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\m_hotkeys.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\m_icq.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\m_idle.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\m_ignore.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\m_langpack.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\m_message.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\m_netlib.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\m_options.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\m_plugins.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\m_popup.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\m_protocols.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\m_protomod.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\m_protosvc.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\m_skin.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\m_system.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\m_system_cpp.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\m_url.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\m_userinfo.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\m_utils.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\newpluginapi.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\statusmodes.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\win2k.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ <ClInclude Include="core\commonheaders.h">
+ <Filter>Core</Filter>
+ </ClInclude>
+ <ClInclude Include="core\forkthread.h">
+ <Filter>Core</Filter>
+ </ClInclude>
+ <ClInclude Include="core\miranda.h">
+ <Filter>Core</Filter>
+ </ClInclude>
+ <ClInclude Include="core\modules.h">
+ <Filter>Core</Filter>
+ </ClInclude>
+ <ClInclude Include="modules\database\dblists.h">
+ <Filter>Modules\database</Filter>
+ </ClInclude>
+ <ClInclude Include="modules\database\profilemanager.h">
+ <Filter>Modules\database</Filter>
+ </ClInclude>
+ <ClInclude Include="modules\findadd\findadd.h">
+ <Filter>Modules\findadd</Filter>
+ </ClInclude>
+ <ClInclude Include="modules\netlib\netlib.h">
+ <Filter>Modules\netlib</Filter>
+ </ClInclude>
+ <ClInclude Include="modules\options\filter.h">
+ <Filter>Modules\options</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\m_protoint.h">
+ <Filter>Modules\protocols</Filter>
+ </ClInclude>
+ <ClInclude Include="modules\srfile\file.h">
+ <Filter>Modules\srfile</Filter>
+ </ClInclude>
+ <ClInclude Include="modules\srurl\url.h">
+ <Filter>Modules\srurl</Filter>
+ </ClInclude>
+ <ClInclude Include="modules\clist\clc.h">
+ <Filter>Modules\clist</Filter>
+ </ClInclude>
+ <ClInclude Include="modules\clist\genmenu.h">
+ <Filter>Modules\clist</Filter>
+ </ClInclude>
+ <ClInclude Include="modules\fonts\FontService.h">
+ <Filter>Modules\fonts</Filter>
+ </ClInclude>
+ <ClInclude Include="modules\icolib\IcoLib.h">
+ <Filter>Modules\icolib</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\m_xml.h">
+ <Filter>Modules\xmlparser</Filter>
+ </ClInclude>
+ <ClInclude Include="modules\xml\xmlParser.h">
+ <Filter>Modules\xmlparser</Filter>
+ </ClInclude>
+ <ClInclude Include="resource.h">
+ <Filter>Resources</Filter>
+ </ClInclude>
+ <ClInclude Include="..\include\m_timezones.h">
+ <Filter>SDK</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="core\commonheaders.cpp">
+ <Filter>Core</Filter>
+ </ClCompile>
+ <ClCompile Include="core\memory.cpp">
+ <Filter>Core</Filter>
+ </ClCompile>
+ <ClCompile Include="core\miranda.cpp">
+ <Filter>Core</Filter>
+ </ClCompile>
+ <ClCompile Include="core\modules.cpp">
+ <Filter>Core</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\addcontact\addcontact.cpp">
+ <Filter>Modules\addcontact</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\autoaway\autoaway.cpp">
+ <Filter>Modules\autoaway</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\button\button.cpp">
+ <Filter>Modules\button</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\contacts\contacts.cpp">
+ <Filter>Modules\contacts</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\database\database.cpp">
+ <Filter>Modules\database</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\database\dbini.cpp">
+ <Filter>Modules\database</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\database\dblists.cpp">
+ <Filter>Modules\database</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\database\dbutils.cpp">
+ <Filter>Modules\database</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\database\profilemanager.cpp">
+ <Filter>Modules\database</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\findadd\findadd.cpp">
+ <Filter>Modules\findadd</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\findadd\searchresults.cpp">
+ <Filter>Modules\findadd</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\help\about.cpp">
+ <Filter>Modules\help</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\help\help.cpp">
+ <Filter>Modules\help</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\history\history.cpp">
+ <Filter>Modules\history</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\idle\idle.cpp">
+ <Filter>Modules\idle</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\ignore\ignore.cpp">
+ <Filter>Modules\ignore</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\langpack\langpack.cpp">
+ <Filter>Modules\langpack</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\langpack\lpservices.cpp">
+ <Filter>Modules\langpack</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\netlib\netlib.cpp">
+ <Filter>Modules\netlib</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\netlib\netlibautoproxy.cpp">
+ <Filter>Modules\netlib</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\netlib\netlibbind.cpp">
+ <Filter>Modules\netlib</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\netlib\netlibhttp.cpp">
+ <Filter>Modules\netlib</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\netlib\netlibhttpproxy.cpp">
+ <Filter>Modules\netlib</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\netlib\netliblog.cpp">
+ <Filter>Modules\netlib</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\netlib\netlibopenconn.cpp">
+ <Filter>Modules\netlib</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\netlib\netlibopts.cpp">
+ <Filter>Modules\netlib</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\netlib\netlibpktrecver.cpp">
+ <Filter>Modules\netlib</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\netlib\netlibsecurity.cpp">
+ <Filter>Modules\netlib</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\netlib\netlibsock.cpp">
+ <Filter>Modules\netlib</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\netlib\netlibssl.cpp">
+ <Filter>Modules\netlib</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\netlib\netlibupnp.cpp">
+ <Filter>Modules\netlib</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\options\descbutton.cpp">
+ <Filter>Modules\options</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\options\filter.cpp">
+ <Filter>Modules\options</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\options\headerbar.cpp">
+ <Filter>Modules\options</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\options\iconheader.cpp">
+ <Filter>Modules\options</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\options\options.cpp">
+ <Filter>Modules\options</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\plugins\newplugins.cpp">
+ <Filter>Modules\plugins</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\protocols\protoaccs.cpp">
+ <Filter>Modules\protocols</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\protocols\protochains.cpp">
+ <Filter>Modules\protocols</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\protocols\protocols.cpp">
+ <Filter>Modules\protocols</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\protocols\protoint.cpp">
+ <Filter>Modules\protocols</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\protocols\protoopts.cpp">
+ <Filter>Modules\protocols</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\skin\hotkeys.cpp">
+ <Filter>Modules\skin</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\skin\skinicons.cpp">
+ <Filter>Modules\skin</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\skin\sounds.cpp">
+ <Filter>Modules\skin</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\srauth\auth.cpp">
+ <Filter>Modules\srauth</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\srauth\authdialogs.cpp">
+ <Filter>Modules\srauth</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\srawaymsg\awaymsg.cpp">
+ <Filter>Modules\srawaymsg</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\srawaymsg\sendmsg.cpp">
+ <Filter>Modules\srawaymsg</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\sremail\email.cpp">
+ <Filter>Modules\sremail</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\srfile\file.cpp">
+ <Filter>Modules\srfile</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\srfile\fileexistsdlg.cpp">
+ <Filter>Modules\srfile</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\srfile\fileopts.cpp">
+ <Filter>Modules\srfile</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\srfile\filerecvdlg.cpp">
+ <Filter>Modules\srfile</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\srfile\filesenddlg.cpp">
+ <Filter>Modules\srfile</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\srfile\filexferdlg.cpp">
+ <Filter>Modules\srfile</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\srfile\ftmanager.cpp">
+ <Filter>Modules\srfile</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\srurl\url.cpp">
+ <Filter>Modules\srurl</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\srurl\urldialogs.cpp">
+ <Filter>Modules\srurl</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\updatenotify\updatenotify.cpp">
+ <Filter>Modules\updater</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\userinfo\contactinfo.cpp">
+ <Filter>Modules\userinfo</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\userinfo\stdinfo.cpp">
+ <Filter>Modules\userinfo</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\userinfo\userinfo.cpp">
+ <Filter>Modules\userinfo</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\useronline\useronline.cpp">
+ <Filter>Modules\useronline</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\utils\bmpfilter.cpp">
+ <Filter>Modules\utils</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\utils\colourpicker.cpp">
+ <Filter>Modules\utils</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\utils\hyperlink.cpp">
+ <Filter>Modules\utils</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\utils\md5.cpp">
+ <Filter>Modules\utils</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\utils\openurl.cpp">
+ <Filter>Modules\utils</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\utils\path.cpp">
+ <Filter>Modules\utils</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\utils\resizer.cpp">
+ <Filter>Modules\utils</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\utils\sha1.cpp">
+ <Filter>Modules\utils</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\utils\utf.cpp">
+ <Filter>Modules\utils</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\utils\utils.cpp">
+ <Filter>Modules\utils</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\utils\windowlist.cpp">
+ <Filter>Modules\utils</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\visibility\visibility.cpp">
+ <Filter>Modules\visibility</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\clist\clc.cpp">
+ <Filter>Modules\clist</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\clist\clcfiledrop.cpp">
+ <Filter>Modules\clist</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\clist\clcidents.cpp">
+ <Filter>Modules\clist</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\clist\clcitems.cpp">
+ <Filter>Modules\clist</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\clist\clcmsgs.cpp">
+ <Filter>Modules\clist</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\clist\clcutils.cpp">
+ <Filter>Modules\clist</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\clist\clistcore.cpp">
+ <Filter>Modules\clist</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\clist\clistevents.cpp">
+ <Filter>Modules\clist</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\clist\clistmenus.cpp">
+ <Filter>Modules\clist</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\clist\clistmod.cpp">
+ <Filter>Modules\clist</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\clist\clistsettings.cpp">
+ <Filter>Modules\clist</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\clist\clisttray.cpp">
+ <Filter>Modules\clist</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\clist\clui.cpp">
+ <Filter>Modules\clist</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\clist\cluiservices.cpp">
+ <Filter>Modules\clist</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\clist\contact.cpp">
+ <Filter>Modules\clist</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\clist\Docking.cpp">
+ <Filter>Modules\clist</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\clist\genmenu.cpp">
+ <Filter>Modules\clist</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\clist\genmenuopt.cpp">
+ <Filter>Modules\clist</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\clist\groups.cpp">
+ <Filter>Modules\clist</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\clist\keyboard.cpp">
+ <Filter>Modules\clist</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\clist\movetogroup.cpp">
+ <Filter>Modules\clist</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\clist\protocolorder.cpp">
+ <Filter>Modules\clist</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\fonts\FontOptions.cpp">
+ <Filter>Modules\fonts</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\fonts\FontService.cpp">
+ <Filter>Modules\fonts</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\fonts\services.cpp">
+ <Filter>Modules\fonts</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\icolib\extracticon.cpp">
+ <Filter>Modules\icolib</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\icolib\skin2icons.cpp">
+ <Filter>Modules\icolib</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\xml\xmlApi.cpp">
+ <Filter>Modules\xmlparser</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\xml\xmlParser.cpp">
+ <Filter>Modules\xmlparser</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\utils\imgconv.cpp">
+ <Filter>Modules\utils</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\utils\timezones.cpp">
+ <Filter>Modules\utils</Filter>
+ </ClCompile>
+ <ClCompile Include="modules\utils\timeutils.cpp">
+ <Filter>Modules\utils</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="res\_blank.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\arrow_sort_column_down.bmp">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\arrow_sort_column_up.bmp">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\chat_join.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\chat_leave.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\check_off.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\check_on.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\contact_add.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\contact_delete.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\contact_groups.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\contact_rename.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\contact_view_details.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="..\docs\contributors.txt">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="..\docs\credits.txt">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\cursor_drag_copy.cur">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\cursor_drop_user.cur">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\cursor_hyperlink.cur">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\group_closed.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\group_opened.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\icon_accmgr.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\icon_all.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\icon_ansi.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\icon_auth_request.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\icon_connecting.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\icon_down_arrow.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\Icon_exit.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\icon_file.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\icon_find_user.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\icon_help.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\icon_history.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\icon_loaded.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\icon_mail.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\icon_message.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\icon_notloaded.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\icon_options.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\icon_search_all.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\Icon_show_hide.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\icon_small_dot.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\icon_sms.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\icon_typing.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\icon_undo.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\icon_unicode.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\icon_url.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\icon_window.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\icon_windows.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\miranda_home.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\miranda_logo.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\miranda_manager.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\status_away.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\status_DND.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\status_free4chat.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\status_invisible.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\status_locked.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\status_NA.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\status_occupied.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\status_offline.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\status_on_the_phone.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\status_online.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\status_out2lunch.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\status_user_online.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="..\protocols\JabberG\docs\translation_jabber.txt">
+ <Filter>SDK</Filter>
+ </None>
+ <None Include="res\Off.ico">
+ <Filter>Resources</Filter>
+ </None>
+ <None Include="res\On.ico">
+ <Filter>Resources</Filter>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="resource.rc">
+ <Filter>Resources</Filter>
+ </ResourceCompile>
+ <ResourceCompile Include="version.rc">
+ <Filter>Resources</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/src/miranda32_8.vcproj b/src/miranda32_8.vcproj
new file mode 100644
index 0000000000..021b3b5c93
--- /dev/null
+++ b/src/miranda32_8.vcproj
@@ -0,0 +1,1531 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8,00"
+ Name="miranda32"
+ ProjectGUID="{F9916510-9055-4C9F-997A-3755DEC1511B}"
+ RootNamespace="miranda32"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(SolutionDir)$(ConfigurationName)/Obj/$(ProjectName)"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Release/miranda32.tlb"
+ HeaderFileName=""
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="3"
+ InlineFunctionExpansion="2"
+ FavorSizeOrSpeed="2"
+ OmitFramePointers="true"
+ WholeProgramOptimization="true"
+ AdditionalIncludeDirectories="../include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;_NOSDK;_STATIC"
+ StringPooling="true"
+ ExceptionHandling="0"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough="commonheaders.h"
+ AssemblerListingLocation=""
+ BrowseInformation="0"
+ BrowseInformationFile=""
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="3"
+ CompileAs="0"
+ DisableSpecificWarnings="4996"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ IgnoreImportLibrary="true"
+ AdditionalDependencies="ws2_32.lib comctl32.lib winmm.lib version.lib"
+ SuppressStartupBanner="true"
+ AdditionalManifestDependencies="type=&apos;win32&apos; name=&apos;Microsoft.Windows.Common-Controls&apos; version=&apos;6.0.0.0&apos; processorArchitecture=&apos;*&apos; publicKeyToken=&apos;6595b64144ccf1df&apos; language=&apos;*&apos;;type=&apos;win32&apos; name=&apos;Microsoft.Windows.Gdiplus&apos; version=&apos;1.0.0.0&apos; processorArchitecture=&apos;X86&apos; publicKeyToken=&apos;6595b64144ccf1df&apos; language=&apos;*&apos;"
+ GenerateDebugInformation="true"
+ GenerateMapFile="false"
+ MapFileName=""
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ LinkTimeCodeGeneration="1"
+ ImportLibrary="$(IntDir)/$(TargetName).lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(SolutionDir)$(ConfigurationName)/Obj/$(ProjectName)"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Debug/miranda32.tlb"
+ HeaderFileName=""
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_WINDOWS;_NOSDK;_STATIC"
+ ExceptionHandling="0"
+ RuntimeLibrary="3"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough="commonheaders.h"
+ AssemblerListingLocation=""
+ BrowseInformation="0"
+ BrowseInformationFile=""
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="4"
+ CompileAs="0"
+ DisableSpecificWarnings="4996"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib comctl32.lib winmm.lib version.lib"
+ LinkIncremental="2"
+ SuppressStartupBanner="true"
+ AdditionalManifestDependencies="type=&apos;win32&apos; name=&apos;Microsoft.Windows.Common-Controls&apos; version=&apos;6.0.0.0&apos; processorArchitecture=&apos;*&apos; publicKeyToken=&apos;6595b64144ccf1df&apos; language=&apos;*&apos;;type=&apos;win32&apos; name=&apos;Microsoft.Windows.Gdiplus&apos; version=&apos;1.0.0.0&apos; processorArchitecture=&apos;X86&apos; publicKeyToken=&apos;6595b64144ccf1df&apos; language=&apos;*&apos;"
+ GenerateDebugInformation="true"
+ GenerateMapFile="false"
+ MapFileName=""
+ SubSystem="2"
+ ImportLibrary="$(IntDir)/$(TargetName).lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release Unicode|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(SolutionDir)$(ConfigurationName)/Obj/$(ProjectName)"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Release/miranda32.tlb"
+ HeaderFileName=""
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="3"
+ InlineFunctionExpansion="1"
+ FavorSizeOrSpeed="2"
+ WholeProgramOptimization="true"
+ AdditionalIncludeDirectories="../include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;_NOSDK;_STATIC"
+ StringPooling="true"
+ ExceptionHandling="0"
+ RuntimeLibrary="2"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough="commonheaders.h"
+ AssemblerListingLocation=""
+ BrowseInformation="0"
+ BrowseInformationFile=""
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="3"
+ CompileAs="0"
+ DisableSpecificWarnings="4996"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ IgnoreImportLibrary="true"
+ AdditionalDependencies="ws2_32.lib comctl32.lib winmm.lib version.lib"
+ SuppressStartupBanner="true"
+ AdditionalManifestDependencies="type=&apos;win32&apos; name=&apos;Microsoft.Windows.Common-Controls&apos; version=&apos;6.0.0.0&apos; processorArchitecture=&apos;*&apos; publicKeyToken=&apos;6595b64144ccf1df&apos; language=&apos;*&apos;;type=&apos;win32&apos; name=&apos;Microsoft.Windows.Gdiplus&apos; version=&apos;1.0.0.0&apos; processorArchitecture=&apos;X86&apos; publicKeyToken=&apos;6595b64144ccf1df&apos; language=&apos;*&apos;"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(TargetDir)$(TargetName).pdb"
+ GenerateMapFile="false"
+ MapFileName=""
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ LinkTimeCodeGeneration="1"
+ ImportLibrary="$(IntDir)/$(TargetName).lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug Unicode|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(SolutionDir)$(ConfigurationName)/Obj/$(ProjectName)"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Debug/miranda32.tlb"
+ HeaderFileName=""
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_WINDOWS;_NOSDK;_STATIC"
+ StringPooling="false"
+ ExceptionHandling="0"
+ RuntimeLibrary="3"
+ EnableFunctionLevelLinking="true"
+ FloatingPointModel="0"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough="commonheaders.h"
+ AssemblerListingLocation=""
+ BrowseInformation="0"
+ BrowseInformationFile=""
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="4"
+ CompileAs="0"
+ DisableSpecificWarnings="4996"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib comctl32.lib winmm.lib version.lib"
+ LinkIncremental="1"
+ SuppressStartupBanner="true"
+ AdditionalManifestDependencies="type=&apos;win32&apos; name=&apos;Microsoft.Windows.Common-Controls&apos; version=&apos;6.0.0.0&apos; processorArchitecture=&apos;*&apos; publicKeyToken=&apos;6595b64144ccf1df&apos; language=&apos;*&apos;;type=&apos;win32&apos; name=&apos;Microsoft.Windows.Gdiplus&apos; version=&apos;1.0.0.0&apos; processorArchitecture=&apos;X86&apos; publicKeyToken=&apos;6595b64144ccf1df&apos; language=&apos;*&apos;"
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(TargetDir)$(TargetName).pdb"
+ GenerateMapFile="false"
+ MapFileName=""
+ SubSystem="2"
+ ImportLibrary="$(IntDir)/$(TargetName).lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="SDK"
+ >
+ <File
+ RelativePath="..\include\m_addcontact.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_awaymsg.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_button.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_clc.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_clist.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_clistint.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_clui.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_contacts.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_database.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_email.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_file.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_findadd.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_fuse.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_history.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_hotkeys.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_icq.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_idle.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_ignore.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_langpack.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_message.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_netlib.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_options.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_plugins.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_popup.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_protocols.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_protomod.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_protosvc.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_skin.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_system.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_system_cpp.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_timezones.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_url.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_userinfo.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_utils.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\newpluginapi.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\statusmodes.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\win2k.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Core"
+ >
+ <File
+ RelativePath="core\commonheaders.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="core\commonheaders.h"
+ >
+ </File>
+ <File
+ RelativePath="core\forkthread.h"
+ >
+ </File>
+ <File
+ RelativePath=".\core\memory.cpp"
+ >
+ </File>
+ <File
+ RelativePath="core\miranda.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\core\miranda.h"
+ >
+ </File>
+ <File
+ RelativePath="core\modules.cpp"
+ >
+ </File>
+ <File
+ RelativePath="core\modules.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Modules"
+ >
+ <Filter
+ Name="addcontact"
+ >
+ <File
+ RelativePath="modules\addcontact\addcontact.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="autoaway"
+ >
+ <File
+ RelativePath="modules\autoaway\autoaway.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="button"
+ >
+ <File
+ RelativePath="modules\button\button.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="contacts"
+ >
+ <File
+ RelativePath="modules\contacts\contacts.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="database"
+ >
+ <File
+ RelativePath="modules\database\database.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\database\dbini.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\database\dblists.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\database\dblists.h"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\database\dbutils.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\database\profilemanager.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\database\profilemanager.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="findadd"
+ >
+ <File
+ RelativePath="modules\findadd\findadd.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\findadd\findadd.h"
+ >
+ </File>
+ <File
+ RelativePath="modules\findadd\searchresults.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="help"
+ >
+ <File
+ RelativePath="modules\help\about.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\help\help.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="history"
+ >
+ <File
+ RelativePath="modules\history\history.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="idle"
+ >
+ <File
+ RelativePath="modules\idle\idle.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="ignore"
+ >
+ <File
+ RelativePath="modules\ignore\ignore.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="langpack"
+ >
+ <File
+ RelativePath="modules\langpack\langpack.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\langpack\lpservices.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="netlib"
+ >
+ <File
+ RelativePath="modules\netlib\netlib.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\netlib\netlib.h"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\netlib\netlibautoproxy.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\netlib\netlibbind.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\netlib\netlibhttp.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\netlib\netlibhttpproxy.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\netlib\netliblog.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\netlib\netlibopenconn.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\netlib\netlibopts.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\netlib\netlibpktrecver.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\netlib\netlibsecurity.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\netlib\netlibsock.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\netlib\netlibssl.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\netlib\netlibupnp.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="options"
+ >
+ <File
+ RelativePath="modules\options\descbutton.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\options\filter.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\options\filter.h"
+ >
+ </File>
+ <File
+ RelativePath="modules\options\headerbar.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\options\iconheader.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\options\options.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="plugins"
+ >
+ <File
+ RelativePath="modules\plugins\newplugins.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="protocols"
+ >
+ <File
+ RelativePath="..\include\m_protoint.h"
+ >
+ </File>
+ <File
+ RelativePath="modules\protocols\protoaccs.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\protocols\protochains.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\protocols\protocols.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\protocols\protoint.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\protocols\protoopts.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="skin"
+ >
+ <File
+ RelativePath="modules\skin\hotkeys.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\skin\skinicons.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\skin\sounds.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="srauth"
+ >
+ <File
+ RelativePath="modules\srauth\auth.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\srauth\authdialogs.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="srawaymsg"
+ >
+ <File
+ RelativePath="modules\srawaymsg\awaymsg.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\srawaymsg\sendmsg.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="sremail"
+ >
+ <File
+ RelativePath="modules\sremail\email.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="srfile"
+ >
+ <File
+ RelativePath="modules\srfile\file.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\srfile\file.h"
+ >
+ </File>
+ <File
+ RelativePath="modules\srfile\fileexistsdlg.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\srfile\fileopts.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\srfile\filerecvdlg.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\srfile\filesenddlg.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\srfile\filexferdlg.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\srfile\ftmanager.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="srurl"
+ >
+ <File
+ RelativePath="modules\srurl\url.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\srurl\url.h"
+ >
+ </File>
+ <File
+ RelativePath="modules\srurl\urldialogs.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="updater"
+ >
+ <File
+ RelativePath=".\modules\updatenotify\updatenotify.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="userinfo"
+ >
+ <File
+ RelativePath="modules\userinfo\contactinfo.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\userinfo\stdinfo.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\userinfo\userinfo.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="useronline"
+ >
+ <File
+ RelativePath="modules\useronline\useronline.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="utils"
+ >
+ <File
+ RelativePath="modules\utils\bmpfilter.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\utils\colourpicker.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\utils\hyperlink.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\utils\imgconv.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\utils\md5.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\utils\openurl.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\utils\path.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\utils\resizer.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\utils\sha1.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\utils\timeutils.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\utils\timezones.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\utils\utf.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\utils\utils.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\utils\windowlist.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="visibility"
+ >
+ <File
+ RelativePath="modules\visibility\visibility.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="clist"
+ >
+ <File
+ RelativePath=".\modules\clist\clc.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\clc.h"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\clcfiledrop.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\clcidents.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\clcitems.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\clcmsgs.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\clcutils.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\clistcore.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\clistevents.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\clistmenus.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\clistmod.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\clistsettings.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\clisttray.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\clui.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\cluiservices.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\contact.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\Docking.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\genmenu.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\genmenu.h"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\genmenuopt.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\groups.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\keyboard.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\movetogroup.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\protocolorder.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="fonts"
+ >
+ <File
+ RelativePath=".\modules\fonts\FontOptions.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\fonts\FontService.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\fonts\FontService.h"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\fonts\services.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="icolib"
+ >
+ <File
+ RelativePath=".\modules\icolib\extracticon.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\icolib\IcoLib.h"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\icolib\skin2icons.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="xmlparser"
+ >
+ <File
+ RelativePath="..\include\m_xml.h"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\xml\xmlApi.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\xml\xmlParser.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\xml\xmlParser.h"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="Resources"
+ >
+ <File
+ RelativePath=".\res\_blank.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\arrow_sort_column_down.bmp"
+ >
+ </File>
+ <File
+ RelativePath=".\res\arrow_sort_column_up.bmp"
+ >
+ </File>
+ <File
+ RelativePath=".\res\chat_join.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\chat_leave.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\check_off.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\check_on.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\contact_add.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\contact_delete.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\contact_groups.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\contact_rename.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\contact_view_details.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\docs\contributors.txt"
+ >
+ </File>
+ <File
+ RelativePath="..\docs\credits.txt"
+ >
+ </File>
+ <File
+ RelativePath=".\res\cursor_drag_copy.cur"
+ >
+ </File>
+ <File
+ RelativePath=".\res\cursor_drop_user.cur"
+ >
+ </File>
+ <File
+ RelativePath=".\res\cursor_hyperlink.cur"
+ >
+ </File>
+ <File
+ RelativePath=".\res\group_closed.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\group_opened.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_accmgr.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_all.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_ansi.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_auth_request.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_connecting.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_down_arrow.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\Icon_exit.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_file.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_find_user.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_help.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_history.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_loaded.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_mail.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_message.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_notloaded.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_options.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_search_all.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\Icon_show_hide.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_small_dot.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_sms.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_typing.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_undo.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_unicode.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_url.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_window.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_windows.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\miranda_home.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\miranda_logo.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\miranda_manager.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\Off.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\On.ico"
+ >
+ </File>
+ <File
+ RelativePath="resource.h"
+ >
+ </File>
+ <File
+ RelativePath="resource.rc"
+ >
+ </File>
+ <File
+ RelativePath=".\res\status_away.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\status_DND.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\status_free4chat.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\status_invisible.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\status_locked.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\status_NA.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\status_occupied.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\status_offline.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\status_on_the_phone.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\status_online.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\status_out2lunch.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\status_user_online.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\version.rc"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/src/miranda32_9.vcproj b/src/miranda32_9.vcproj
new file mode 100644
index 0000000000..82565d8725
--- /dev/null
+++ b/src/miranda32_9.vcproj
@@ -0,0 +1,1963 @@
+<?xml version="1.0" encoding="windows-1251"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="miranda32"
+ ProjectGUID="{F9916510-9055-4C9F-997A-3755DEC1511B}"
+ RootNamespace="miranda32"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(SolutionDir)$(ConfigurationName)/Obj/$(ProjectName)"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Release/miranda32.tlb"
+ HeaderFileName=""
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="3"
+ InlineFunctionExpansion="1"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
+ WholeProgramOptimization="true"
+ AdditionalIncludeDirectories="../include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;_NOSDK;_STATIC"
+ StringPooling="true"
+ ExceptionHandling="0"
+ RuntimeLibrary="2"
+ BufferSecurityCheck="false"
+ EnableFunctionLevelLinking="true"
+ FloatingPointModel="2"
+ RuntimeTypeInfo="false"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough="commonheaders.h"
+ AssemblerListingLocation=""
+ BrowseInformationFile=""
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="3"
+ CompileAs="0"
+ DisableSpecificWarnings="4996"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ IgnoreImportLibrary="true"
+ AdditionalDependencies="ws2_32.lib comctl32.lib winmm.lib version.lib crypt32.lib"
+ SuppressStartupBanner="true"
+ AdditionalManifestDependencies="type=&apos;win32&apos; name=&apos;Microsoft.Windows.Common-Controls&apos; version=&apos;6.0.0.0&apos; processorArchitecture=&apos;*&apos; publicKeyToken=&apos;6595b64144ccf1df&apos; language=&apos;*&apos;;type=&apos;win32&apos; name=&apos;Microsoft.Windows.Gdiplus&apos; version=&apos;1.0.0.0&apos; processorArchitecture=&apos;X86&apos; publicKeyToken=&apos;6595b64144ccf1df&apos; language=&apos;*&apos;"
+ ModuleDefinitionFile=""
+ GenerateDebugInformation="true"
+ MapFileName=""
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ OptimizeForWindows98="0"
+ LinkTimeCodeGeneration="1"
+ RandomizedBaseAddress="1"
+ ImportLibrary="$(IntDir)/$(TargetName).lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)64"
+ IntermediateDirectory="$(SolutionDir)$(ConfigurationName)64/Obj/$(ProjectName)"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="3"
+ TypeLibraryName=".\Release/miranda32.tlb"
+ HeaderFileName=""
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="3"
+ InlineFunctionExpansion="1"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
+ WholeProgramOptimization="true"
+ AdditionalIncludeDirectories="../include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;_NOSDK;_STATIC"
+ StringPooling="true"
+ ExceptionHandling="0"
+ RuntimeLibrary="2"
+ BufferSecurityCheck="false"
+ EnableFunctionLevelLinking="true"
+ FloatingPointModel="2"
+ RuntimeTypeInfo="false"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough="commonheaders.h"
+ AssemblerListingLocation=""
+ BrowseInformationFile=""
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="3"
+ CompileAs="0"
+ DisableSpecificWarnings="4996"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ IgnoreImportLibrary="true"
+ AdditionalDependencies="ws2_32.lib comctl32.lib winmm.lib version.lib crypt32.lib"
+ OutputFile="$(OutDir)\miranda64.exe"
+ AdditionalManifestDependencies="type=&apos;win32&apos; name=&apos;Microsoft.Windows.Common-Controls&apos; version=&apos;6.0.0.0&apos; processorArchitecture=&apos;*&apos; publicKeyToken=&apos;6595b64144ccf1df&apos; language=&apos;*&apos;;type=&apos;win32&apos; name=&apos;Microsoft.Windows.Gdiplus&apos; version=&apos;1.0.0.0&apos; processorArchitecture=&apos;amd64&apos; publicKeyToken=&apos;6595b64144ccf1df&apos; language=&apos;*&apos;"
+ ModuleDefinitionFile=""
+ GenerateDebugInformation="true"
+ MapFileName=""
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ LinkTimeCodeGeneration="1"
+ RandomizedBaseAddress="1"
+ ImportLibrary="$(IntDir)/$(TargetName).lib"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(SolutionDir)$(ConfigurationName)/Obj/$(ProjectName)"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Debug/miranda32.tlb"
+ HeaderFileName=""
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_WINDOWS;_NOSDK;_STATIC"
+ ExceptionHandling="0"
+ RuntimeLibrary="3"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough="commonheaders.h"
+ AssemblerListingLocation=""
+ BrowseInformationFile=""
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="4"
+ CompileAs="0"
+ DisableSpecificWarnings="4996"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ IgnoreImportLibrary="true"
+ AdditionalDependencies="ws2_32.lib comctl32.lib winmm.lib version.lib crypt32.lib"
+ SuppressStartupBanner="true"
+ AdditionalManifestDependencies="type=&apos;win32&apos; name=&apos;Microsoft.Windows.Common-Controls&apos; version=&apos;6.0.0.0&apos; processorArchitecture=&apos;*&apos; publicKeyToken=&apos;6595b64144ccf1df&apos; language=&apos;*&apos;;type=&apos;win32&apos; name=&apos;Microsoft.Windows.Gdiplus&apos; version=&apos;1.0.0.0&apos; processorArchitecture=&apos;X86&apos; publicKeyToken=&apos;6595b64144ccf1df&apos; language=&apos;*&apos;"
+ ModuleDefinitionFile=""
+ GenerateDebugInformation="true"
+ MapFileName=""
+ SubSystem="2"
+ RandomizedBaseAddress="1"
+ ImportLibrary="$(IntDir)/$(TargetName).lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)64"
+ IntermediateDirectory="$(SolutionDir)$(ConfigurationName)64/Obj/$(ProjectName)"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="3"
+ TypeLibraryName=".\Debug/miranda32.tlb"
+ HeaderFileName=""
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_WINDOWS;_NOSDK;_STATIC"
+ ExceptionHandling="0"
+ RuntimeLibrary="3"
+ EnableFunctionLevelLinking="true"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough="commonheaders.h"
+ AssemblerListingLocation=""
+ BrowseInformationFile=""
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="3"
+ CompileAs="0"
+ DisableSpecificWarnings="4996"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ IgnoreImportLibrary="true"
+ AdditionalDependencies="ws2_32.lib comctl32.lib winmm.lib version.lib crypt32.lib"
+ OutputFile="$(OutDir)\miranda64.exe"
+ AdditionalManifestDependencies="type=&apos;win32&apos; name=&apos;Microsoft.Windows.Common-Controls&apos; version=&apos;6.0.0.0&apos; processorArchitecture=&apos;*&apos; publicKeyToken=&apos;6595b64144ccf1df&apos; language=&apos;*&apos;;type=&apos;win32&apos; name=&apos;Microsoft.Windows.Gdiplus&apos; version=&apos;1.0.0.0&apos; processorArchitecture=&apos;amd64&apos; publicKeyToken=&apos;6595b64144ccf1df&apos; language=&apos;*&apos;"
+ ModuleDefinitionFile=""
+ GenerateDebugInformation="true"
+ MapFileName=""
+ SubSystem="2"
+ RandomizedBaseAddress="1"
+ ImportLibrary="$(IntDir)/$(TargetName).lib"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release Unicode|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(SolutionDir)$(ConfigurationName)/Obj/$(ProjectName)"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Release/miranda32.tlb"
+ HeaderFileName=""
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="3"
+ InlineFunctionExpansion="1"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
+ WholeProgramOptimization="true"
+ AdditionalIncludeDirectories="../include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;_NOSDK;_STATIC"
+ StringPooling="true"
+ ExceptionHandling="0"
+ RuntimeLibrary="2"
+ BufferSecurityCheck="false"
+ EnableFunctionLevelLinking="true"
+ FloatingPointModel="2"
+ RuntimeTypeInfo="false"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough="commonheaders.h"
+ AssemblerOutput="4"
+ BrowseInformationFile=""
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="3"
+ CompileAs="0"
+ DisableSpecificWarnings="4996;4706;4127"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ IgnoreImportLibrary="true"
+ AdditionalDependencies="ws2_32.lib comctl32.lib winmm.lib version.lib crypt32.lib"
+ AdditionalManifestDependencies="type=&apos;win32&apos; name=&apos;Microsoft.Windows.Common-Controls&apos; version=&apos;6.0.0.0&apos; processorArchitecture=&apos;*&apos; publicKeyToken=&apos;6595b64144ccf1df&apos; language=&apos;*&apos;;type=&apos;win32&apos; name=&apos;Microsoft.Windows.Gdiplus&apos; version=&apos;1.0.0.0&apos; processorArchitecture=&apos;X86&apos; publicKeyToken=&apos;6595b64144ccf1df&apos; language=&apos;*&apos;"
+ ModuleDefinitionFile=""
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ LinkTimeCodeGeneration="1"
+ RandomizedBaseAddress="1"
+ ImportLibrary="$(IntDir)/$(TargetName).lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release Unicode|x64"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)64"
+ IntermediateDirectory="$(SolutionDir)$(ConfigurationName)64/Obj/$(ProjectName)"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="NDEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="3"
+ TypeLibraryName=".\Release/miranda32.tlb"
+ HeaderFileName=""
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="3"
+ InlineFunctionExpansion="1"
+ EnableIntrinsicFunctions="true"
+ FavorSizeOrSpeed="2"
+ WholeProgramOptimization="true"
+ AdditionalIncludeDirectories="../include"
+ PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;_NOSDK;_STATIC"
+ StringPooling="true"
+ ExceptionHandling="0"
+ RuntimeLibrary="2"
+ BufferSecurityCheck="false"
+ EnableFunctionLevelLinking="true"
+ FloatingPointModel="2"
+ RuntimeTypeInfo="false"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough="commonheaders.h"
+ BrowseInformationFile=""
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="3"
+ CompileAs="0"
+ DisableSpecificWarnings="4996;4706;4127"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ IgnoreImportLibrary="true"
+ AdditionalDependencies="ws2_32.lib comctl32.lib winmm.lib version.lib crypt32.lib"
+ OutputFile="$(OutDir)\miranda64.exe"
+ AdditionalManifestDependencies="type=&apos;win32&apos; name=&apos;Microsoft.Windows.Common-Controls&apos; version=&apos;6.0.0.0&apos; processorArchitecture=&apos;*&apos; publicKeyToken=&apos;6595b64144ccf1df&apos; language=&apos;*&apos;;type=&apos;win32&apos; name=&apos;Microsoft.Windows.Gdiplus&apos; version=&apos;1.0.0.0&apos; processorArchitecture=&apos;amd64&apos; publicKeyToken=&apos;6595b64144ccf1df&apos; language=&apos;*&apos;"
+ ModuleDefinitionFile=""
+ GenerateDebugInformation="true"
+ SubSystem="2"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ LinkTimeCodeGeneration="1"
+ RandomizedBaseAddress="1"
+ ImportLibrary="$(IntDir)/$(TargetName).lib"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug Unicode|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(SolutionDir)$(ConfigurationName)/Obj/$(ProjectName)"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="1"
+ TypeLibraryName=".\Debug/miranda32.tlb"
+ HeaderFileName=""
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_WINDOWS;_NOSDK;_STATIC"
+ StringPooling="false"
+ ExceptionHandling="0"
+ RuntimeLibrary="3"
+ EnableFunctionLevelLinking="true"
+ FloatingPointModel="0"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough="commonheaders.h"
+ AssemblerListingLocation=""
+ BrowseInformationFile=""
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="4"
+ CompileAs="0"
+ DisableSpecificWarnings="4996"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ IgnoreImportLibrary="true"
+ AdditionalDependencies="ws2_32.lib comctl32.lib winmm.lib version.lib crypt32.lib"
+ SuppressStartupBanner="true"
+ AdditionalManifestDependencies="type=&apos;win32&apos; name=&apos;Microsoft.Windows.Common-Controls&apos; version=&apos;6.0.0.0&apos; processorArchitecture=&apos;*&apos; publicKeyToken=&apos;6595b64144ccf1df&apos; language=&apos;*&apos;;type=&apos;win32&apos; name=&apos;Microsoft.Windows.Gdiplus&apos; version=&apos;1.0.0.0&apos; processorArchitecture=&apos;X86&apos; publicKeyToken=&apos;6595b64144ccf1df&apos; language=&apos;*&apos;"
+ ModuleDefinitionFile=""
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(TargetDir)$(TargetName).pdb"
+ MapFileName=""
+ SubSystem="2"
+ RandomizedBaseAddress="1"
+ ImportLibrary="$(IntDir)/$(TargetName).lib"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug Unicode|x64"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)64"
+ IntermediateDirectory="$(SolutionDir)$(ConfigurationName)64/Obj/$(ProjectName)"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="false"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ PreprocessorDefinitions="_DEBUG"
+ MkTypLibCompatible="true"
+ SuppressStartupBanner="true"
+ TargetEnvironment="3"
+ TypeLibraryName=".\Debug/miranda32.tlb"
+ HeaderFileName=""
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../include"
+ PreprocessorDefinitions="_DEBUG;WIN32;_WINDOWS;_NOSDK;_STATIC"
+ StringPooling="false"
+ ExceptionHandling="0"
+ RuntimeLibrary="3"
+ EnableFunctionLevelLinking="true"
+ FloatingPointModel="0"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough="commonheaders.h"
+ AssemblerListingLocation=""
+ BrowseInformationFile=""
+ WarningLevel="3"
+ SuppressStartupBanner="true"
+ DebugInformationFormat="3"
+ CompileAs="0"
+ DisableSpecificWarnings="4996"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ IgnoreImportLibrary="true"
+ AdditionalDependencies="ws2_32.lib comctl32.lib winmm.lib version.lib crypt32.lib"
+ OutputFile="$(OutDir)\miranda64.exe"
+ AdditionalManifestDependencies="type=&apos;win32&apos; name=&apos;Microsoft.Windows.Common-Controls&apos; version=&apos;6.0.0.0&apos; processorArchitecture=&apos;*&apos; publicKeyToken=&apos;6595b64144ccf1df&apos; language=&apos;*&apos;;type=&apos;win32&apos; name=&apos;Microsoft.Windows.Gdiplus&apos; version=&apos;1.0.0.0&apos; processorArchitecture=&apos;amd64&apos; publicKeyToken=&apos;6595b64144ccf1df&apos; language=&apos;*&apos;"
+ ModuleDefinitionFile=""
+ GenerateDebugInformation="true"
+ ProgramDatabaseFile="$(TargetDir)$(TargetName).pdb"
+ MapFileName=""
+ SubSystem="2"
+ RandomizedBaseAddress="1"
+ ImportLibrary="$(IntDir)/$(TargetName).lib"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="SDK"
+ >
+ <File
+ RelativePath="..\include\m_addcontact.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_awaymsg.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_button.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_clc.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_clist.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_clistint.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_clui.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_contacts.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_database.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_email.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_file.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_findadd.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_fuse.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_history.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_hotkeys.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_icq.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_idle.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_ignore.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_langpack.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_message.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_netlib.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_options.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_plugins.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_popup.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_protocols.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_protomod.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_protosvc.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_skin.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_system.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_system_cpp.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_timezones.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_url.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_userinfo.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\m_utils.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\newpluginapi.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\statusmodes.h"
+ >
+ </File>
+ <File
+ RelativePath="..\include\win2k.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Core"
+ >
+ <File
+ RelativePath="core\commonheaders.cpp"
+ >
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release Unicode|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug Unicode|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="core\commonheaders.h"
+ >
+ </File>
+ <File
+ RelativePath="core\forkthread.h"
+ >
+ </File>
+ <File
+ RelativePath=".\core\memory.cpp"
+ >
+ </File>
+ <File
+ RelativePath="core\miranda.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\core\miranda.h"
+ >
+ </File>
+ <File
+ RelativePath="core\modules.cpp"
+ >
+ </File>
+ <File
+ RelativePath="core\modules.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Modules"
+ >
+ <Filter
+ Name="addcontact"
+ >
+ <File
+ RelativePath="modules\addcontact\addcontact.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="button"
+ >
+ <File
+ RelativePath="modules\button\button.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="contacts"
+ >
+ <File
+ RelativePath="modules\contacts\contacts.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="database"
+ >
+ <File
+ RelativePath="modules\database\database.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\database\dbini.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\database\dblists.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\database\dblists.h"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\database\dbutils.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\database\profilemanager.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\database\profilemanager.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="findadd"
+ >
+ <File
+ RelativePath="modules\findadd\findadd.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\findadd\findadd.h"
+ >
+ </File>
+ <File
+ RelativePath="modules\findadd\searchresults.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="help"
+ >
+ <File
+ RelativePath="modules\help\about.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\help\help.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="history"
+ >
+ <File
+ RelativePath="modules\history\history.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="idle"
+ >
+ <File
+ RelativePath="modules\idle\idle.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="ignore"
+ >
+ <File
+ RelativePath="modules\ignore\ignore.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="langpack"
+ >
+ <File
+ RelativePath="modules\langpack\langpack.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\langpack\lpservices.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="netlib"
+ >
+ <File
+ RelativePath="modules\netlib\netlib.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\netlib\netlib.h"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\netlib\netlibautoproxy.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\netlib\netlibbind.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\netlib\netlibhttp.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\netlib\netlibhttpproxy.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\netlib\netliblog.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\netlib\netlibopenconn.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\netlib\netlibopts.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\netlib\netlibpktrecver.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\netlib\netlibsecurity.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\netlib\netlibsock.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\netlib\netlibssl.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\netlib\netlibupnp.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="options"
+ >
+ <File
+ RelativePath=".\modules\options\descbutton.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\options\filter.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\options\filter.h"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\options\headerbar.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\options\iconheader.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\options\options.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="plugins"
+ >
+ <File
+ RelativePath="modules\plugins\newplugins.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="protocols"
+ >
+ <File
+ RelativePath="..\include\m_protoint.h"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\protocols\protoaccs.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\protocols\protochains.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\protocols\protocols.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\protocols\protoint.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\protocols\protoopts.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="skin"
+ >
+ <File
+ RelativePath=".\modules\skin\hotkeys.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\skin\skinicons.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\skin\sounds.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="srauth"
+ >
+ <File
+ RelativePath="modules\srauth\auth.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\srauth\authdialogs.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="srawaymsg"
+ >
+ <File
+ RelativePath="modules\srawaymsg\awaymsg.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\srawaymsg\sendmsg.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="sremail"
+ >
+ <File
+ RelativePath="modules\sremail\email.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="srfile"
+ >
+ <File
+ RelativePath="modules\srfile\file.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\srfile\file.h"
+ >
+ </File>
+ <File
+ RelativePath="modules\srfile\fileexistsdlg.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\srfile\fileopts.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\srfile\filerecvdlg.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\srfile\filesenddlg.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\srfile\filexferdlg.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\srfile\ftmanager.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="srurl"
+ >
+ <File
+ RelativePath="modules\srurl\url.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\srurl\url.h"
+ >
+ </File>
+ <File
+ RelativePath="modules\srurl\urldialogs.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="updater"
+ >
+ <File
+ RelativePath=".\modules\updatenotify\updatenotify.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="userinfo"
+ >
+ <File
+ RelativePath="modules\userinfo\contactinfo.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\userinfo\stdinfo.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\userinfo\userinfo.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="useronline"
+ >
+ <File
+ RelativePath="modules\useronline\useronline.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="utils"
+ >
+ <File
+ RelativePath="modules\utils\bmpfilter.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\utils\colourpicker.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\utils\hyperlink.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\utils\imgconv.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\utils\md5.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\utils\openurl.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\utils\path.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\utils\resizer.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\utils\sha1.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\utils\timeutils.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\utils\timezones.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\utils\utf.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\utils\utils.cpp"
+ >
+ </File>
+ <File
+ RelativePath="modules\utils\windowlist.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="visibility"
+ >
+ <File
+ RelativePath="modules\visibility\visibility.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="clist"
+ >
+ <File
+ RelativePath=".\modules\clist\clc.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\clc.h"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\clcfiledrop.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\clcidents.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\clcitems.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\clcmsgs.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\clcutils.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\clistcore.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\clistevents.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\clistmenus.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\clistmod.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\clistsettings.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\clisttray.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\clui.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\cluiservices.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\contact.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\Docking.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\genmenu.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\genmenu.h"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\genmenuopt.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\groups.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\keyboard.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\movetogroup.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\clist\protocolorder.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="fonts"
+ >
+ <File
+ RelativePath=".\modules\fonts\FontOptions.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\fonts\FontService.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\fonts\FontService.h"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\fonts\services.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="icolib"
+ >
+ <File
+ RelativePath=".\modules\icolib\extracticon.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\icolib\IcoLib.h"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\icolib\skin2icons.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="xmlparser"
+ >
+ <File
+ RelativePath="..\include\m_xml.h"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\xml\xmlApi.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\xml\xmlParser.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\modules\xml\xmlParser.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="autoaway"
+ >
+ <File
+ RelativePath="modules\autoaway\autoaway.cpp"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="Resources"
+ >
+ <File
+ RelativePath=".\res\_blank.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\arrow_sort_column_down.bmp"
+ >
+ </File>
+ <File
+ RelativePath=".\res\arrow_sort_column_up.bmp"
+ >
+ </File>
+ <File
+ RelativePath=".\res\chat_join.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\chat_leave.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\check_off.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\check_on.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\contact_add.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\contact_delete.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\contact_groups.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\contact_rename.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\contact_view_details.ico"
+ >
+ </File>
+ <File
+ RelativePath="..\docs\contributors.txt"
+ >
+ </File>
+ <File
+ RelativePath="..\docs\credits.txt"
+ >
+ </File>
+ <File
+ RelativePath=".\res\cursor_drag_copy.cur"
+ >
+ </File>
+ <File
+ RelativePath=".\res\cursor_drop_user.cur"
+ >
+ </File>
+ <File
+ RelativePath=".\res\cursor_hyperlink.cur"
+ >
+ </File>
+ <File
+ RelativePath=".\res\group_closed.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\group_opened.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_accmgr.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_all.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_ansi.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_auth_request.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_connecting.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_down_arrow.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\Icon_exit.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_file.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_find_user.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_help.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_history.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_loaded.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_mail.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_message.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_notloaded.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_options.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_search_all.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\Icon_show_hide.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_small_dot.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_sms.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_typing.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_undo.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_unicode.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_url.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_window.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\icon_windows.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\miranda_home.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\miranda_logo.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\miranda_manager.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\Off.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\On.ico"
+ >
+ </File>
+ <File
+ RelativePath="resource.h"
+ >
+ </File>
+ <File
+ RelativePath="resource.rc"
+ >
+ </File>
+ <File
+ RelativePath=".\res\status_away.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\status_DND.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\status_free4chat.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\status_invisible.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\status_locked.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\status_NA.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\status_occupied.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\status_offline.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\status_on_the_phone.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\status_online.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\status_out2lunch.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\res\status_user_online.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\version.rc"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/src/modules/addcontact/addcontact.cpp b/src/modules/addcontact/addcontact.cpp
new file mode 100644
index 0000000000..0be08b93ba
--- /dev/null
+++ b/src/modules/addcontact/addcontact.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"
+
+INT_PTR CALLBACK AddContactDlgProc(HWND hdlg,UINT msg,WPARAM wparam,LPARAM lparam)
+{
+ ADDCONTACTSTRUCT *acs;
+
+ switch(msg) {
+ case WM_INITDIALOG:
+ {
+ char szUin[10];
+ acs=(ADDCONTACTSTRUCT *)lparam;
+ SetWindowLongPtr(hdlg,GWLP_USERDATA,(LONG_PTR)acs);
+
+ TranslateDialogDefault(hdlg);
+ Window_SetIcon_IcoLib(hdlg, SKINICON_OTHER_ADDCONTACT);
+ if ( acs->handleType == HANDLE_EVENT ) {
+ DWORD dwUin;
+ DBEVENTINFO dbei = { 0 };
+ dbei.cbSize=sizeof(dbei);
+ dbei.cbBlob=sizeof(DWORD);
+ dbei.pBlob=(PBYTE)&dwUin;
+ CallService(MS_DB_EVENT_GET,(WPARAM)acs->handle,(LPARAM)&dbei);
+ _ltoa(dwUin,szUin,10);
+ acs->szProto = dbei.szModule;
+ }
+ {
+ TCHAR *szName = NULL, *tmpStr = NULL;
+ if ( acs->handleType == HANDLE_CONTACT )
+ szName = cli.pfnGetContactDisplayName( acs->handle, GCDNF_TCHAR );
+ else {
+ int isSet = 0;
+
+ if (acs->handleType == HANDLE_EVENT) {
+ DBEVENTINFO dbei;
+ HANDLE hcontact;
+
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.cbBlob=CallService(MS_DB_EVENT_GETBLOBSIZE,(WPARAM)acs->handle,0);
+ dbei.pBlob=(PBYTE)mir_alloc(dbei.cbBlob);
+ CallService(MS_DB_EVENT_GET,(WPARAM)acs->handle,(LPARAM)&dbei);
+ hcontact=*((PHANDLE)(dbei.pBlob+sizeof(DWORD)));
+ mir_free(dbei.pBlob);
+ if (hcontact!=INVALID_HANDLE_VALUE) {
+ szName = cli.pfnGetContactDisplayName( hcontact, 0 );
+ isSet = 1;
+ }
+ }
+ if (!isSet) {
+ szName = (acs->handleType == HANDLE_EVENT) ? (tmpStr = mir_a2t(szUin)) :
+ (acs->psr->id ? acs->psr->id : acs->psr->nick);
+ } }
+
+ if ( szName && szName[0] ) {
+ TCHAR szTitle[128];
+ mir_sntprintf( szTitle, SIZEOF(szTitle), TranslateT("Add %s"), szName );
+ SetWindowText( hdlg, szTitle );
+ }
+ else SetWindowText( hdlg, TranslateT("Add Contact"));
+ mir_free(tmpStr);
+ } }
+
+ if ( acs->handleType == HANDLE_CONTACT && acs->handle )
+ if ( acs->szProto == NULL || (acs->szProto != NULL && *acs->szProto == 0 ))
+ acs->szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)acs->handle,0);
+
+ {
+ int groupId;
+ for ( groupId = 0; groupId < 999; groupId++ ) {
+ DBVARIANT dbv;
+ char idstr[4];
+ int id;
+ _itoa(groupId,idstr,10);
+ if(DBGetContactSettingTString(NULL,"CListGroups",idstr,&dbv)) break;
+ id = SendDlgItemMessage(hdlg,IDC_GROUP,CB_ADDSTRING,0,(LPARAM)(dbv.ptszVal+1));
+ SendDlgItemMessage(hdlg,IDC_GROUP,CB_SETITEMDATA ,id,groupId+1);
+ DBFreeVariant(&dbv);
+ } }
+
+ SendDlgItemMessage(hdlg,IDC_GROUP,CB_INSERTSTRING,0,(LPARAM)TranslateT("None"));
+ SendDlgItemMessage(hdlg,IDC_GROUP,CB_SETCURSEL,0,0);
+ /* acs->szProto may be NULL don't expect it */
+ {
+ // By default check both checkboxes
+ CheckDlgButton(hdlg,IDC_ADDED,BST_CHECKED);
+ CheckDlgButton(hdlg,IDC_AUTH,BST_CHECKED);
+
+ DWORD flags = (acs->szProto) ? CallProtoService(acs->szProto,PS_GETCAPS,PFLAGNUM_4,0) : 0;
+ if (flags&PF4_FORCEADDED) { // force you were added requests for this protocol
+ EnableWindow(GetDlgItem(hdlg,IDC_ADDED),FALSE);
+ }
+ if (flags&PF4_FORCEAUTH) { // force auth requests for this protocol
+ EnableWindow(GetDlgItem(hdlg,IDC_AUTH),FALSE);
+ }
+ if (flags&PF4_NOCUSTOMAUTH) {
+ EnableWindow(GetDlgItem(hdlg,IDC_AUTHREQ),FALSE);
+ EnableWindow(GetDlgItem(hdlg,IDC_AUTHGB),FALSE);
+ }
+ else {
+ EnableWindow(GetDlgItem(hdlg,IDC_AUTHREQ),IsDlgButtonChecked(hdlg,IDC_AUTH));
+ EnableWindow(GetDlgItem(hdlg,IDC_AUTHGB),IsDlgButtonChecked(hdlg,IDC_AUTH));
+ SetDlgItemText(hdlg,IDC_AUTHREQ,TranslateT("Please authorize my request and add me to your contact list."));
+ }
+ }
+ break;
+
+ case WM_COMMAND:
+ acs = (ADDCONTACTSTRUCT *)GetWindowLongPtr(hdlg, GWLP_USERDATA);
+
+ switch (LOWORD(wparam))
+ {
+ case IDC_AUTH:
+ {
+ DWORD flags = CallProtoService(acs->szProto,PS_GETCAPS,PFLAGNUM_4,0);
+ if (flags & PF4_NOCUSTOMAUTH) {
+ EnableWindow(GetDlgItem(hdlg,IDC_AUTHREQ),FALSE);
+ EnableWindow(GetDlgItem(hdlg,IDC_AUTHGB),FALSE);
+ }
+ else {
+ EnableWindow(GetDlgItem(hdlg,IDC_AUTHREQ),IsDlgButtonChecked(hdlg,IDC_AUTH));
+ EnableWindow(GetDlgItem(hdlg,IDC_AUTHGB),IsDlgButtonChecked(hdlg,IDC_AUTH));
+ }
+ }
+ break;
+ case IDOK:
+ {
+ HANDLE hContact = INVALID_HANDLE_VALUE;
+ switch (acs->handleType)
+ {
+ case HANDLE_EVENT:
+ {
+ DBEVENTINFO dbei = { 0 };
+ dbei.cbSize = sizeof(dbei);
+ CallService(MS_DB_EVENT_GET, (WPARAM)acs->handle, (LPARAM)&dbei);
+ hContact = (HANDLE)CallProtoService(dbei.szModule, PS_ADDTOLISTBYEVENT, 0, (LPARAM)acs->handle);
+ }
+ break;
+
+ case HANDLE_SEARCHRESULT:
+ hContact = (HANDLE)CallProtoService(acs->szProto, PS_ADDTOLIST, 0, (LPARAM)acs->psr);
+ break;
+
+ case HANDLE_CONTACT:
+ hContact = acs->handle;
+ break;
+ }
+
+ if (hContact == NULL)
+ break;
+
+ TCHAR szHandle[256];
+ if (GetDlgItemText(hdlg, IDC_MYHANDLE, szHandle, SIZEOF(szHandle)))
+ DBWriteContactSettingTString(hContact, "CList", "MyHandle", szHandle);
+
+ int item = SendDlgItemMessage(hdlg, IDC_GROUP, CB_GETCURSEL, 0, 0);
+ if (item > 0)
+ {
+ item = SendDlgItemMessage(hdlg, IDC_GROUP, CB_GETITEMDATA, item, 0);
+ CallService(MS_CLIST_CONTACTCHANGEGROUP, (WPARAM)hContact, item);
+ }
+
+ DBDeleteContactSetting(hContact, "CList", "NotOnList");
+
+ if (IsDlgButtonChecked(hdlg, IDC_ADDED))
+ CallContactService(hContact, PSS_ADDED, 0, 0);
+
+ if (IsDlgButtonChecked(hdlg, IDC_AUTH))
+ {
+ DWORD flags = CallProtoService(acs->szProto, PS_GETCAPS, PFLAGNUM_4, 0);
+ if (flags & PF4_NOCUSTOMAUTH)
+ CallContactService(hContact, PSS_AUTHREQUESTT, 0, 0);
+ else
+ {
+ TCHAR szReason[512];
+ GetDlgItemText(hdlg, IDC_AUTHREQ, szReason, SIZEOF(szReason));
+ CallContactService(hContact, PSS_AUTHREQUESTT, 0, (LPARAM)szReason);
+ }
+ }
+ }
+ // fall through
+ case IDCANCEL:
+ if ( GetParent( hdlg ) == NULL)
+ DestroyWindow( hdlg );
+ else
+ EndDialog( hdlg, 0 );
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ /* if there is no parent for the dialog, its a modeless dialog and can't be killed using EndDialog() */
+ if ( GetParent( hdlg ) == NULL )
+ DestroyWindow(hdlg);
+ else
+ EndDialog( hdlg, 0 );
+ break;
+
+ case WM_DESTROY:
+ Window_FreeIcon_IcoLib(hdlg);
+ acs = ( ADDCONTACTSTRUCT* )GetWindowLongPtr(hdlg,GWLP_USERDATA);
+ if (acs) {
+ if (acs->psr) {
+ mir_free(acs->psr->nick);
+ mir_free(acs->psr->firstName);
+ mir_free(acs->psr->lastName);
+ mir_free(acs->psr->email);
+ mir_free(acs->psr);
+ }
+ mir_free(acs);
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+INT_PTR AddContactDialog(WPARAM wParam,LPARAM lParam)
+{
+ if (lParam) {
+ ADDCONTACTSTRUCT* acs = ( ADDCONTACTSTRUCT* )mir_alloc(sizeof(ADDCONTACTSTRUCT));
+ memmove( acs, ( ADDCONTACTSTRUCT* )lParam, sizeof( ADDCONTACTSTRUCT ));
+ if ( acs->psr ) {
+ PROTOSEARCHRESULT *psr;
+ /* bad! structures that are bigger than psr will cause crashes if they define pointers within unreachable structural space */
+ psr = (PROTOSEARCHRESULT *)mir_alloc(acs->psr->cbSize);
+ memmove(psr,acs->psr,acs->psr->cbSize);
+ psr->nick = psr->flags & PSR_UNICODE ? mir_u2t((wchar_t*)psr->nick) : mir_a2t((char*)psr->nick);
+ psr->firstName = psr->flags & PSR_UNICODE ? mir_u2t((wchar_t*)psr->firstName) : mir_a2t((char*)psr->firstName);
+ psr->lastName = psr->flags & PSR_UNICODE ? mir_u2t((wchar_t*)psr->lastName) : mir_a2t((char*)psr->lastName);
+ psr->email = psr->flags & PSR_UNICODE ? mir_u2t((wchar_t*)psr->email) : mir_a2t((char*)psr->email);
+ psr->flags = psr->flags & ~PSR_UNICODE | PSR_TCHAR;
+ acs->psr = psr;
+ /* copied the passed acs structure, the psr structure with, the pointers within that */
+ }
+
+ if ( wParam )
+ DialogBoxParam(hMirandaInst,MAKEINTRESOURCE(IDD_ADDCONTACT),(HWND)wParam,AddContactDlgProc,(LPARAM)acs);
+ else
+ CreateDialogParam(hMirandaInst,MAKEINTRESOURCE(IDD_ADDCONTACT),(HWND)wParam,AddContactDlgProc,(LPARAM)acs);
+ return 0;
+ }
+ return 1;
+}
+
+int LoadAddContactModule(void)
+{
+ CreateServiceFunction(MS_ADDCONTACT_SHOW,AddContactDialog);
+ return 0;
+}
diff --git a/src/modules/autoaway/autoaway.cpp b/src/modules/autoaway/autoaway.cpp
new file mode 100644
index 0000000000..9805535173
--- /dev/null
+++ b/src/modules/autoaway/autoaway.cpp
@@ -0,0 +1,74 @@
+/*
+
+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 AA_MODULE "AutoAway"
+
+void Proto_SetStatus(const char* szProto, unsigned status);
+
+static int AutoAwayEvent(WPARAM, LPARAM lParam)
+{
+ int i;
+
+ MIRANDA_IDLE_INFO mii;
+ mii.cbSize = sizeof( mii );
+ CallService( MS_IDLE_GETIDLEINFO, 0, (LPARAM)&mii );
+ if ( mii.aaStatus == 0 )
+ return 0;
+
+ for ( i=0; i < accounts.getCount(); i++ ) {
+ PROTOACCOUNT* pa = accounts[i];
+
+ if (!Proto_IsAccountEnabled( pa ) || Proto_IsAccountLocked( pa )) continue;
+
+ int statusbits = CallProtoService( pa->szModuleName, PS_GETCAPS, PFLAGNUM_2, 0 );
+ int currentstatus = CallProtoService( pa->szModuleName, PS_GETSTATUS, 0, 0 );
+ int status = mii.aaStatus;
+ if ( !(statusbits & Proto_Status2Flag(status)) ) {
+ // the protocol doesnt support the given status
+ if ( statusbits & Proto_Status2Flag( ID_STATUS_AWAY ))
+ status = ID_STATUS_AWAY;
+ // the proto doesnt support user mode or even away, bail.
+ else
+ continue;
+ }
+ if ( currentstatus >= ID_STATUS_ONLINE && currentstatus != ID_STATUS_INVISIBLE ) {
+ if ( (lParam&IDF_ISIDLE) && ( currentstatus == ID_STATUS_ONLINE || currentstatus == ID_STATUS_FREECHAT )) {
+ DBWriteContactSettingByte( NULL, AA_MODULE, pa->szModuleName, 1 );
+ Proto_SetStatus( pa->szModuleName, status );
+ }
+ else if ( !(lParam & IDF_ISIDLE) && DBGetContactSettingByte( NULL, AA_MODULE, pa->szModuleName, 0 )) {
+ // returning from idle and this proto was set away, set it back
+ DBWriteContactSettingByte( NULL, AA_MODULE, pa->szModuleName, 0 );
+ if ( !mii.aaLock )
+ Proto_SetStatus( pa->szModuleName, ID_STATUS_ONLINE);
+ } } }
+
+ return 0;
+}
+
+int LoadAutoAwayModule(void)
+{
+ HookEvent(ME_IDLE_CHANGED, AutoAwayEvent);
+ return 0;
+}
diff --git a/src/modules/button/button.cpp b/src/modules/button/button.cpp
new file mode 100644
index 0000000000..b6265dfa7a
--- /dev/null
+++ b/src/modules/button/button.cpp
@@ -0,0 +1,614 @@
+/*
+
+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 <initguid.h>
+#include <oleacc.h>
+
+// TODO:
+// - Support for bitmap buttons (simple call to DrawIconEx())
+
+static LRESULT CALLBACK MButtonWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+typedef struct {
+ HWND hwnd;
+ int stateId; // button state
+ int focus; // has focus (1 or 0)
+ HFONT hFont; // font
+ HICON arrow; // uses down arrow
+ int defbutton; // default button
+ HICON hIcon;
+ HBITMAP hBitmap;
+ int pushBtn;
+ int pbState;
+ HTHEME hThemeButton;
+ HTHEME hThemeToolbar;
+ char cHot;
+ int flatBtn;
+ HWND hwndToolTips;
+ IAccPropServices* pAccPropServices;
+} MButtonCtrl;
+
+
+static CRITICAL_SECTION csTips;
+static SortedList lToolTips;
+static BOOL bModuleInitialized = FALSE;
+
+typedef struct
+{
+ DWORD ThreadId;
+ HWND hwnd;
+} TTooltips;
+
+int LoadButtonModule(void)
+{
+ WNDCLASSEX wc = {0};
+
+ if ( bModuleInitialized ) return 0;
+ bModuleInitialized = TRUE;
+
+ wc.cbSize = sizeof(wc);
+ wc.lpszClassName = MIRANDABUTTONCLASS;
+ wc.lpfnWndProc = MButtonWndProc;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.cbWndExtra = sizeof(MButtonCtrl*);
+ wc.hbrBackground = 0;
+ wc.style = CS_GLOBALCLASS;
+ RegisterClassEx(&wc);
+
+ InitializeCriticalSection(&csTips);
+ lToolTips.increment = 1;
+ lToolTips.sortFunc = NumericKeySort;
+ return 0;
+}
+
+void UnloadButtonModule()
+{
+ if ( !bModuleInitialized ) return;
+ EnterCriticalSection(&csTips);
+ List_Destroy(&lToolTips);
+ LeaveCriticalSection(&csTips);
+ DeleteCriticalSection(&csTips);
+}
+
+// Used for our own cheap TrackMouseEvent
+#define BUTTON_POLLID 100
+#define BUTTON_POLLDELAY 50
+
+static void DestroyTheme(MButtonCtrl *ctl) {
+ if (closeThemeData) {
+ if (ctl->hThemeButton) {
+ closeThemeData(ctl->hThemeButton);
+ ctl->hThemeButton = NULL;
+ }
+ if (ctl->hThemeToolbar) {
+ closeThemeData(ctl->hThemeToolbar);
+ ctl->hThemeToolbar = NULL;
+ }
+ }
+}
+
+static void LoadTheme(MButtonCtrl *ctl)
+{
+ if (openThemeData) {
+ DestroyTheme(ctl);
+ ctl->hThemeButton = openThemeData(ctl->hwnd, L"BUTTON");
+ ctl->hThemeToolbar = openThemeData(ctl->hwnd, L"TOOLBAR");
+ }
+}
+
+static void SetHwndPropInt(MButtonCtrl* bct, DWORD idObject, DWORD idChild, MSAAPROPID idProp, int val)
+{
+ if (bct->pAccPropServices == NULL) return;
+ VARIANT var;
+ var.vt = VT_I4;
+ var.lVal = val;
+ bct->pAccPropServices->SetHwndProp(bct->hwnd, idObject, idChild, idProp, var);
+}
+static int TBStateConvert2Flat(int state)
+{
+ switch(state) {
+ case PBS_NORMAL: return TS_NORMAL;
+ case PBS_HOT: return TS_HOT;
+ case PBS_PRESSED: return TS_PRESSED;
+ case PBS_DISABLED: return TS_DISABLED;
+ case PBS_DEFAULTED: return TS_NORMAL;
+ }
+ return TS_NORMAL;
+}
+
+#ifndef DFCS_HOT
+#define DFCS_HOT 0x1000
+#endif
+
+static void PaintWorker(MButtonCtrl *ctl, HDC hdcPaint)
+{
+ if (hdcPaint) {
+ HDC hdcMem;
+ HBITMAP hbmMem;
+ HDC hOld;
+ RECT rcClient;
+
+ GetClientRect(ctl->hwnd, &rcClient);
+ hdcMem = CreateCompatibleDC(hdcPaint);
+ hbmMem = CreateCompatibleBitmap(hdcPaint, rcClient.right-rcClient.left, rcClient.bottom-rcClient.top);
+ hOld = ( HDC )SelectObject(hdcMem, hbmMem);
+
+ // If its a push button, check to see if it should stay pressed
+ if (ctl->pushBtn && ctl->pbState) ctl->stateId = PBS_PRESSED;
+
+ // Draw the flat button
+ if (ctl->flatBtn) {
+ if (ctl->hThemeToolbar) {
+ int state = IsWindowEnabled(ctl->hwnd)?(ctl->stateId==PBS_NORMAL&&ctl->defbutton?PBS_DEFAULTED:ctl->stateId):PBS_DISABLED;
+ if (isThemeBackgroundPartiallyTransparent(ctl->hThemeToolbar, TP_BUTTON, TBStateConvert2Flat(state))) {
+ drawThemeParentBackground(ctl->hwnd, hdcMem, &rcClient);
+ }
+ drawThemeBackground(ctl->hThemeToolbar, hdcMem, TP_BUTTON, TBStateConvert2Flat(state), &rcClient, &rcClient);
+ }
+ else {
+ HBRUSH hbr;
+
+ if (ctl->stateId==PBS_PRESSED||ctl->stateId==PBS_HOT)
+ hbr = GetSysColorBrush(COLOR_3DLIGHT);
+ else {
+ HWND hwndParent = GetParent(ctl->hwnd);
+ HDC dc = GetDC(hwndParent);
+ HBRUSH oldBrush = (HBRUSH)GetCurrentObject( dc, OBJ_BRUSH );
+ hbr = (HBRUSH)SendMessage(hwndParent, WM_CTLCOLORDLG, (WPARAM)dc, (LPARAM)hwndParent);
+ SelectObject(dc,oldBrush);
+ ReleaseDC(hwndParent,dc);
+ }
+ if (hbr) {
+ FillRect(hdcMem, &rcClient, hbr);
+ DeleteObject(hbr);
+ }
+ if (ctl->stateId==PBS_HOT||ctl->focus) {
+ if (ctl->pbState)
+ DrawEdge(hdcMem,&rcClient, EDGE_ETCHED,BF_RECT|BF_SOFT);
+ else DrawEdge(hdcMem,&rcClient, BDR_RAISEDOUTER,BF_RECT|BF_SOFT|BF_FLAT);
+ }
+ else if (ctl->stateId==PBS_PRESSED)
+ DrawEdge(hdcMem, &rcClient, BDR_SUNKENOUTER,BF_RECT|BF_SOFT);
+ }
+ }
+ else {
+ // Draw background/border
+ if (ctl->hThemeButton) {
+ int state = IsWindowEnabled(ctl->hwnd)?(ctl->stateId==PBS_NORMAL&&ctl->defbutton?PBS_DEFAULTED:ctl->stateId):PBS_DISABLED;
+ if (isThemeBackgroundPartiallyTransparent(ctl->hThemeButton, BP_PUSHBUTTON, state)) {
+ drawThemeParentBackground(ctl->hwnd, hdcMem, &rcClient);
+ }
+ drawThemeBackground(ctl->hThemeButton, hdcMem, BP_PUSHBUTTON, state, &rcClient, &rcClient);
+ }
+ else {
+ UINT uState = DFCS_BUTTONPUSH|((ctl->stateId==PBS_HOT)?DFCS_HOT:0)|((ctl->stateId == PBS_PRESSED)?DFCS_PUSHED:0);
+ if (ctl->defbutton&&ctl->stateId==PBS_NORMAL) uState |= DLGC_DEFPUSHBUTTON;
+ DrawFrameControl(hdcMem, &rcClient, DFC_BUTTON, uState);
+ }
+
+ // Draw focus rectangle if button has focus
+ if (ctl->focus) {
+ RECT focusRect = rcClient;
+ InflateRect(&focusRect, -3, -3);
+ DrawFocusRect(hdcMem, &focusRect);
+ }
+ }
+
+ // If we have an icon or a bitmap, ignore text and only draw the image on the button
+ if (ctl->hIcon) {
+ int ix = (rcClient.right-rcClient.left)/2 - (GetSystemMetrics(SM_CXSMICON)/2);
+ int iy = (rcClient.bottom-rcClient.top)/2 - (GetSystemMetrics(SM_CYSMICON)/2);
+ if (ctl->stateId == PBS_PRESSED) {
+ ix++;
+ iy++;
+ }
+ {
+ HIMAGELIST hImageList;
+ HICON hIconNew;
+
+ hImageList = ImageList_Create(GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON), IsWinVerXPPlus()? ILC_COLOR32 | ILC_MASK : ILC_COLOR16 | ILC_MASK, 1, 0);
+ ImageList_AddIcon(hImageList, ctl->hIcon);
+ hIconNew = ImageList_GetIcon(hImageList, 0, ILD_NORMAL);
+ DrawState(hdcMem,NULL,NULL,(LPARAM)hIconNew,0,ix,iy,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),IsWindowEnabled(ctl->hwnd)?DST_ICON|DSS_NORMAL:DST_ICON|DSS_DISABLED);
+ ImageList_RemoveAll(hImageList);
+ ImageList_Destroy(hImageList);
+ DestroyIcon(hIconNew);
+ }
+ }
+ else if (ctl->hBitmap) {
+ BITMAP bminfo;
+ int ix,iy;
+
+ GetObject(ctl->hBitmap, sizeof(bminfo), &bminfo);
+ ix = (rcClient.right-rcClient.left)/2 - (bminfo.bmWidth/2);
+ iy = (rcClient.bottom-rcClient.top)/2 - (bminfo.bmHeight/2);
+ if (ctl->stateId == PBS_PRESSED) {
+ ix++;
+ iy++;
+ }
+ DrawState(hdcMem,NULL,NULL,(LPARAM)ctl->hBitmap,0,ix,iy,bminfo.bmWidth,bminfo.bmHeight,IsWindowEnabled(ctl->hwnd)?DST_BITMAP:DST_BITMAP|DSS_DISABLED);
+ }
+ else if (GetWindowTextLength(ctl->hwnd)) {
+ // Draw the text and optinally the arrow
+ TCHAR szText[MAX_PATH];
+ SIZE sz;
+ RECT rcText;
+ HFONT hOldFont;
+
+ CopyRect(&rcText, &rcClient);
+ GetWindowText(ctl->hwnd, szText, SIZEOF(szText));
+ SetBkMode(hdcMem, TRANSPARENT);
+ hOldFont = (HFONT)SelectObject(hdcMem, ctl->hFont);
+ // XP w/themes doesn't used the glossy disabled text. Is it always using COLOR_GRAYTEXT? Seems so.
+ SetTextColor(hdcMem, IsWindowEnabled(ctl->hwnd)||!ctl->hThemeButton?GetSysColor(COLOR_BTNTEXT):GetSysColor(COLOR_GRAYTEXT));
+ GetTextExtentPoint32(hdcMem, szText, lstrlen(szText), &sz);
+ if (ctl->cHot) {
+ SIZE szHot;
+
+ GetTextExtentPoint32 (hdcMem, _T("&"), 1, &szHot);
+ sz.cx -= szHot.cx;
+ }
+ if (ctl->arrow) {
+ DrawState(hdcMem,NULL,NULL,(LPARAM)ctl->arrow,0,rcClient.right-rcClient.left-5-GetSystemMetrics(SM_CXSMICON)+(!ctl->hThemeButton&&ctl->stateId==PBS_PRESSED?1:0),(rcClient.bottom-rcClient.top)/2-GetSystemMetrics(SM_CYSMICON)/2+(!ctl->hThemeButton&&ctl->stateId==PBS_PRESSED?1:0),GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),IsWindowEnabled(ctl->hwnd)?DST_ICON:DST_ICON|DSS_DISABLED);
+ }
+ SelectObject(hdcMem, ctl->hFont);
+ DrawState(hdcMem,NULL,NULL,(LPARAM)szText,0,(rcText.right-rcText.left-sz.cx)/2+(!ctl->hThemeButton&&ctl->stateId==PBS_PRESSED?1:0),ctl->hThemeButton?(rcText.bottom-rcText.top-sz.cy)/2:(rcText.bottom-rcText.top-sz.cy)/2-(ctl->stateId==PBS_PRESSED?0:1),sz.cx,sz.cy,IsWindowEnabled(ctl->hwnd)||ctl->hThemeButton?DST_PREFIXTEXT|DSS_NORMAL:DST_PREFIXTEXT|DSS_DISABLED);
+ SelectObject(hdcMem, hOldFont);
+ }
+ BitBlt(hdcPaint, 0, 0, rcClient.right-rcClient.left, rcClient.bottom-rcClient.top, hdcMem, 0, 0, SRCCOPY);
+ SelectObject(hdcMem, hOld);
+ DeleteObject(hbmMem);
+ DeleteDC(hdcMem);
+
+ }
+}
+
+static LRESULT CALLBACK MButtonWndProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ MButtonCtrl* bct = (MButtonCtrl *)GetWindowLongPtr(hwndDlg, 0);
+ switch(msg) {
+ case WM_NCCREATE:
+ SetWindowLongPtr(hwndDlg, GWL_STYLE, GetWindowLongPtr(hwndDlg, GWL_STYLE) | BS_OWNERDRAW);
+ bct = ( MButtonCtrl* )mir_calloc(sizeof(MButtonCtrl));
+ if (bct==NULL) return FALSE;
+ bct->hwnd = hwndDlg;
+ bct->stateId = PBS_NORMAL;
+ bct->hFont = ( HFONT )GetStockObject(DEFAULT_GUI_FONT);
+ LoadTheme(bct);
+ if (SUCCEEDED(CoCreateInstance(CLSID_AccPropServices, NULL, CLSCTX_SERVER,
+ IID_IAccPropServices, (void**)&bct->pAccPropServices)))
+ {
+ // Annotating the Role of this object to be PushButton
+ SetHwndPropInt(bct, OBJID_CLIENT, CHILDID_SELF, PROPID_ACC_ROLE, ROLE_SYSTEM_PUSHBUTTON);
+ }
+ else
+ bct->pAccPropServices = NULL;
+ SetWindowLongPtr(hwndDlg, 0, (LONG_PTR)bct);
+ if (((CREATESTRUCT *)lParam)->lpszName) SetWindowText(hwndDlg, ((CREATESTRUCT *)lParam)->lpszName);
+ return TRUE;
+
+ case WM_DESTROY:
+ if (bct) {
+ if (bct->pAccPropServices) {
+ bct->pAccPropServices->Release();
+ bct->pAccPropServices = NULL;
+ }
+ if (bct->hwndToolTips) {
+ TOOLINFO ti = {0};
+ ti.cbSize = sizeof(ti);
+ ti.uFlags = TTF_IDISHWND;
+ ti.hwnd = bct->hwnd;
+ ti.uId = (UINT_PTR)bct->hwnd;
+ if (SendMessage(bct->hwndToolTips, TTM_GETTOOLINFO, 0, (LPARAM)&ti)) {
+ SendMessage(bct->hwndToolTips, TTM_DELTOOL, 0, (LPARAM)&ti);
+ }
+ if ( SendMessage(bct->hwndToolTips, TTM_GETTOOLCOUNT, 0, (LPARAM)&ti) == 0 ) {
+ int idx;
+ TTooltips tt;
+ tt.ThreadId = GetCurrentThreadId();
+
+ EnterCriticalSection(&csTips);
+ if ( List_GetIndex( &lToolTips, &tt, &idx ) ) {
+ mir_free( lToolTips.items[idx] );
+ List_Remove( &lToolTips, idx );
+ DestroyWindow( bct->hwndToolTips );
+ }
+ LeaveCriticalSection(&csTips);
+
+ bct->hwndToolTips = NULL;
+ }
+ }
+ if (bct->arrow) IconLib_ReleaseIcon(bct->arrow, 0);
+ DestroyTheme(bct);
+ }
+ break; // DONT! fall thru
+
+ case WM_NCDESTROY:
+ mir_free(bct);
+ break;
+
+ case WM_SETTEXT:
+ bct->cHot = 0;
+ if ( lParam != 0 ) {
+ TCHAR *tmp = ( TCHAR* )lParam;
+ while (*tmp) {
+ if (*tmp=='&' && *(tmp+1)) {
+ bct->cHot = _tolower(*(tmp+1));
+ break;
+ }
+ tmp++;
+ }
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ break;
+
+ case WM_KEYUP:
+ if (bct->stateId!=PBS_DISABLED && wParam == VK_SPACE) {
+ if (bct->pushBtn) {
+ if (bct->pbState) {
+ bct->pbState = 0;
+ bct->stateId = PBS_NORMAL;
+ }
+ else {
+ bct->pbState = 1;
+ bct->stateId = PBS_PRESSED;
+ }
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ SendMessage(GetParent(hwndDlg), WM_COMMAND, MAKELONG(GetDlgCtrlID(hwndDlg), BN_CLICKED), (LPARAM)hwndDlg);
+ return 0;
+ }
+ break;
+
+ case WM_SYSKEYUP:
+ if (bct->stateId!=PBS_DISABLED && bct->cHot && bct->cHot == tolower((int)wParam)) {
+ if (bct->pushBtn) {
+ if (bct->pbState) {
+ bct->pbState = 0;
+ bct->stateId = PBS_NORMAL;
+ }
+ else {
+ bct->pbState = 1;
+ bct->stateId = PBS_PRESSED;
+ }
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ SendMessage(GetParent(hwndDlg), WM_COMMAND, MAKELONG(GetDlgCtrlID(hwndDlg), BN_CLICKED), (LPARAM)hwndDlg);
+ return 0;
+ }
+ break;
+
+ case WM_THEMECHANGED:
+ // themed changed, reload theme object
+ LoadTheme(bct);
+ InvalidateRect(bct->hwnd, NULL, TRUE); // repaint it
+ break;
+
+ case WM_SETFONT: // remember the font so we can use it later
+ bct->hFont = (HFONT)wParam; // maybe we should redraw?
+ break;
+
+ case WM_NCPAINT:
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ HDC hdcPaint;
+
+ hdcPaint = BeginPaint(hwndDlg, &ps);
+ if (hdcPaint) {
+ PaintWorker(bct, hdcPaint);
+ EndPaint(hwndDlg, &ps);
+ }
+ break;
+ }
+ case BM_SETIMAGE:
+ {
+ HGDIOBJ hnd = NULL;
+ if (bct->hIcon) hnd = bct->hIcon;
+ else if (bct->hBitmap) hnd = bct->hBitmap;
+
+ if (wParam == IMAGE_ICON) {
+ bct->hIcon = (HICON)lParam;
+ bct->hBitmap = NULL;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ else if (wParam == IMAGE_BITMAP) {
+ bct->hBitmap = (HBITMAP)lParam;
+ bct->hIcon = NULL;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ return (LRESULT)hnd;
+ }
+ case BM_GETIMAGE:
+ if (bct->hIcon) return (LRESULT)bct->hIcon;
+ else if (bct->hBitmap) return (LRESULT)bct->hBitmap;
+ else return 0;
+ case BM_SETCHECK:
+ if (!bct->pushBtn) break;
+ if (wParam == BST_CHECKED) {
+ bct->pbState = 1;
+ bct->stateId = PBS_PRESSED;
+ }
+ else if (wParam == BST_UNCHECKED) {
+ bct->pbState = 0;
+ bct->stateId = PBS_NORMAL;
+ }
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+ case BM_GETCHECK:
+ if (bct->pushBtn) {
+ return bct->pbState?BST_CHECKED:BST_UNCHECKED;
+ }
+ return 0;
+ case BUTTONSETARROW: // turn arrow on/off
+ if (wParam) {
+ if (!bct->arrow) {
+ bct->arrow = LoadSkinIcon(SKINICON_OTHER_DOWNARROW);
+ SetHwndPropInt(bct, OBJID_CLIENT, CHILDID_SELF, PROPID_ACC_ROLE, ROLE_SYSTEM_BUTTONDROPDOWN);
+ }
+ }
+ else {
+ if (bct->arrow) {
+ IconLib_ReleaseIcon(bct->arrow, 0);
+ bct->arrow = NULL;
+ SetHwndPropInt(bct, OBJID_CLIENT, CHILDID_SELF, PROPID_ACC_ROLE, ROLE_SYSTEM_PUSHBUTTON);
+ }
+ }
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+ case BUTTONSETDEFAULT:
+ bct->defbutton = wParam?1:0;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+ case BUTTONSETASPUSHBTN:
+ bct->pushBtn = 1;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+ case BUTTONSETASFLATBTN:
+ bct->flatBtn = 1;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+ case BUTTONADDTOOLTIP:
+ if ( wParam ) {
+ TOOLINFO ti = {0};
+ if ( !bct->hwndToolTips ) {
+ int idx;
+ TTooltips tt;
+ tt.ThreadId = GetCurrentThreadId();
+
+ EnterCriticalSection(&csTips);
+ if ( List_GetIndex( &lToolTips, &tt, &idx )) {
+ bct->hwndToolTips = ((TTooltips*)lToolTips.items[idx])->hwnd;
+ } else {
+ TTooltips *ptt = ( TTooltips* )mir_alloc( sizeof(TTooltips) );
+ ptt->ThreadId = tt.ThreadId;
+ ptt->hwnd = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, _T(""), TTS_ALWAYSTIP, 0, 0, 0, 0, NULL, NULL, hMirandaInst, NULL);
+ List_Insert( &lToolTips, ptt, idx );
+ bct->hwndToolTips = ptt->hwnd;
+ }
+ LeaveCriticalSection(&csTips);
+ }
+ ti.cbSize = sizeof(ti);
+ ti.uFlags = TTF_IDISHWND;
+ ti.hwnd = bct->hwnd;
+ ti.uId = (UINT_PTR)bct->hwnd;
+ if (SendMessage(bct->hwndToolTips, TTM_GETTOOLINFO, 0, (LPARAM)&ti))
+ SendMessage(bct->hwndToolTips, TTM_DELTOOL, 0, (LPARAM)&ti);
+ ti.uFlags = TTF_IDISHWND|TTF_SUBCLASS;
+ ti.uId = (UINT_PTR)bct->hwnd;
+ #if defined( _UNICODE )
+ if ( lParam & BATF_UNICODE )
+ ti.lpszText = mir_wstrdup( TranslateW(( WCHAR* )wParam ));
+ else
+ ti.lpszText = LangPackPcharToTchar(( char* )wParam );
+ #else
+ ti.lpszText = Translate(( char* )wParam );
+ #endif
+ if (bct->pAccPropServices) {
+ wchar_t *tmpstr = mir_t2u(ti.lpszText);
+ bct->pAccPropServices->SetHwndPropStr(bct->hwnd, OBJID_CLIENT,
+ CHILDID_SELF, PROPID_ACC_DESCRIPTION, tmpstr);
+ mir_free(tmpstr);
+ }
+ SendMessage( bct->hwndToolTips, TTM_ADDTOOL, 0, (LPARAM)&ti);
+ #if defined( _UNICODE )
+ mir_free( ti.lpszText );
+ #endif
+ }
+ break;
+ case WM_SETFOCUS: // set keybord focus and redraw
+ bct->focus = 1;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+
+ case WM_KILLFOCUS: // kill focus and redraw
+ bct->focus = 0;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+
+ case WM_WINDOWPOSCHANGED:
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+
+ case WM_ENABLE: // windows tells us to enable/disable
+ bct->stateId = wParam?PBS_NORMAL:PBS_DISABLED;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ break;
+
+ case WM_MOUSELEAVE: // faked by the WM_TIMER
+ if (bct->stateId!=PBS_DISABLED) { // don't change states if disabled
+ bct->stateId = PBS_NORMAL;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ break;
+
+ case WM_LBUTTONDOWN:
+ if (bct->stateId!=PBS_DISABLED) { // don't change states if disabled
+ bct->stateId = PBS_PRESSED;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ break;
+
+ case WM_LBUTTONUP:
+ {
+ int showClick = 0;
+ if (bct->pushBtn) {
+ if (bct->pbState) bct->pbState = 0;
+ else bct->pbState = 1;
+ }
+ if (bct->stateId!=PBS_DISABLED) { // don't change states if disabled
+ if (bct->stateId==PBS_PRESSED)
+ showClick = 1;
+ if (msg==WM_LBUTTONUP) bct->stateId = PBS_HOT;
+ else bct->stateId = PBS_NORMAL;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ if (showClick) // Tell your daddy you got clicked.
+ SendMessage(GetParent(hwndDlg), WM_COMMAND, MAKELONG(GetDlgCtrlID(hwndDlg), BN_CLICKED), (LPARAM)hwndDlg);
+ break;
+ }
+ case WM_MOUSEMOVE:
+ if (bct->stateId == PBS_NORMAL) {
+ bct->stateId = PBS_HOT;
+ InvalidateRect(bct->hwnd, NULL, TRUE);
+ }
+ // Call timer, used to start cheesy TrackMouseEvent faker
+ SetTimer(hwndDlg,BUTTON_POLLID,BUTTON_POLLDELAY,NULL);
+ break;
+ case WM_TIMER: // use a timer to check if they have did a mouseout
+ if (wParam == BUTTON_POLLID) {
+ RECT rc;
+ POINT pt;
+ GetWindowRect(hwndDlg,&rc);
+ GetCursorPos(&pt);
+ if(!PtInRect(&rc,pt)) { // mouse must be gone, trigger mouse leave
+ PostMessage(hwndDlg,WM_MOUSELEAVE,0,0L);
+ KillTimer(hwndDlg,BUTTON_POLLID);
+ } }
+ break;
+
+ case WM_ERASEBKGND:
+ return 1;
+ }
+ return DefWindowProc(hwndDlg, msg, wParam, lParam);
+}
diff --git a/src/modules/clist/Docking.cpp b/src/modules/clist/Docking.cpp
new file mode 100644
index 0000000000..8dd61cdc37
--- /dev/null
+++ b/src/modules/clist/Docking.cpp
@@ -0,0 +1,392 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2010 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 "clc.h"
+
+#define WM_DOCKCALLBACK (WM_USER+121)
+#define EDGESENSITIVITY 3
+
+#define DOCKED_NONE 0
+#define DOCKED_LEFT 1
+#define DOCKED_RIGHT 2
+
+static char docked;
+static POINT dockPos;
+
+static void Docking_GetMonitorRectFromPoint(LPPOINT pt, LPRECT rc)
+{
+ if (MyMonitorFromPoint)
+ {
+ MONITORINFO monitorInfo;
+ HMONITOR hMonitor = MyMonitorFromPoint(*pt, MONITOR_DEFAULTTONEAREST); // always returns a valid value
+ monitorInfo.cbSize = sizeof(monitorInfo);
+
+ if (MyGetMonitorInfo(hMonitor, &monitorInfo))
+ {
+ *rc = monitorInfo.rcMonitor;
+ return;
+ }
+ }
+
+ // "generic" win95/NT support, also serves as failsafe
+ rc->left = 0;
+ rc->top = 0;
+ rc->bottom = GetSystemMetrics(SM_CYSCREEN);
+ rc->right = GetSystemMetrics(SM_CXSCREEN);
+}
+
+static void Docking_RectToDock(LPRECT rc)
+{
+ rc->right += dockPos.x - rc->left;
+ rc->left = dockPos.x;
+ rc->bottom += dockPos.y - rc->top;
+ rc->top = dockPos.y;
+}
+
+static void Docking_PosCommand(HWND hwnd, LPRECT rc, bool query)
+{
+ APPBARDATA abd = {0};
+
+ abd.cbSize = sizeof(abd);
+ abd.hWnd = hwnd;
+ abd.uEdge = docked == DOCKED_LEFT ? ABE_LEFT : ABE_RIGHT;
+ abd.rc = *rc;
+ SHAppBarMessage(query ? ABM_QUERYPOS : ABM_SETPOS, &abd);
+ *rc = abd.rc;
+}
+
+static UINT_PTR Docking_Command(HWND hwnd, int cmd)
+{
+ APPBARDATA abd = {0};
+
+ abd.cbSize = sizeof(abd);
+ abd.hWnd = hwnd;
+ abd.uCallbackMessage = WM_DOCKCALLBACK;
+ return SHAppBarMessage(cmd, &abd);
+}
+
+static void Docking_AdjustPosition(HWND hwnd, LPRECT rcDisplay, LPRECT rc, bool query, bool move)
+{
+ int cx = rc->right - rc->left;
+
+ rc->top = rcDisplay->top;
+ rc->bottom = rcDisplay->bottom;
+ if (docked == DOCKED_LEFT)
+ {
+ rc->right = rcDisplay->left + (rc->right - rc->left);
+ rc->left = rcDisplay->left;
+ }
+ else
+ {
+ rc->left = rcDisplay->right - (rc->right - rc->left);
+ rc->right = rcDisplay->right;
+ }
+ Docking_PosCommand(hwnd, rc, true);
+
+ if (docked == DOCKED_LEFT)
+ rc->right = rc->left + cx;
+ else
+ rc->left = rc->right - cx;
+
+ if (!query)
+ {
+ Docking_PosCommand(hwnd, rc, false);
+ dockPos = *(LPPOINT)rc;
+ }
+
+ if (move)
+ {
+ MoveWindow(hwnd, rc->left, rc->top, rc->right - rc->left,
+ rc->bottom - rc->top, TRUE);
+ }
+}
+
+static void Docking_SetSize(HWND hwnd, LPRECT rc, bool query, bool move)
+{
+ RECT rcMonitor;
+ Docking_GetMonitorRectFromPoint(
+ docked == DOCKED_LEFT && !query ? (LPPOINT)&rc->right : (LPPOINT)rc, &rcMonitor);
+ Docking_AdjustPosition(hwnd, &rcMonitor, rc, query, move);
+}
+
+static bool Docking_IsWindowVisible(HWND hwnd)
+{
+ LONG style = GetWindowLong(hwnd, GWL_STYLE);
+ return style & WS_VISIBLE && !(style & WS_MINIMIZE);
+}
+
+INT_PTR Docking_IsDocked(WPARAM, LPARAM)
+{
+ return docked;
+}
+
+int fnDocking_ProcessWindowMessage(WPARAM wParam, LPARAM lParam)
+{
+ static int draggingTitle;
+ MSG *msg = (MSG *) wParam;
+
+ if (msg->message == WM_DESTROY)
+ {
+ if (docked)
+ {
+ DBWriteContactSettingByte(NULL, "CList", "Docked", (BYTE) docked);
+ DBWriteContactSettingDword(NULL, "CList", "DockX", (DWORD) dockPos.x);
+ DBWriteContactSettingDword(NULL, "CList", "DockY", (DWORD) dockPos.y);
+ }
+ else
+ {
+ DBDeleteContactSetting(NULL, "CList", "Docked");
+ DBDeleteContactSetting(NULL, "CList", "DockX");
+ DBDeleteContactSetting(NULL, "CList", "DockY");
+ }
+ }
+
+ if (!docked && msg->message != WM_CREATE && msg->message != WM_MOVING)
+ return 0;
+
+ switch (msg->message)
+ {
+ case WM_CREATE:
+ draggingTitle = 0;
+ docked = DBGetContactSettingByte(NULL, "CLUI", "DockToSides", 1) ?
+ (char) DBGetContactSettingByte(NULL, "CList", "Docked", 0) : 0;
+ dockPos.x = (int) DBGetContactSettingDword(NULL, "CList", "DockX", 0);
+ dockPos.y = (int) DBGetContactSettingDword(NULL, "CList", "DockY", 0);
+ break;
+
+ case WM_ACTIVATE:
+ Docking_Command(msg->hwnd, ABM_ACTIVATE);
+ break;
+
+ case WM_WINDOWPOSCHANGING:
+ {
+ LPWINDOWPOS wp = (LPWINDOWPOS)msg->lParam;
+
+ bool vis = Docking_IsWindowVisible(msg->hwnd);
+ if (wp->flags & SWP_SHOWWINDOW)
+ vis = !IsIconic(msg->hwnd);
+ if (wp->flags & SWP_HIDEWINDOW)
+ vis = false;
+
+ if (vis)
+ {
+ if (!(wp->flags & (SWP_NOMOVE | SWP_NOSIZE)))
+ {
+ bool addbar = Docking_Command(msg->hwnd, ABM_NEW) != 0;
+
+ RECT rc = {0};
+ GetWindowRect(msg->hwnd, &rc);
+
+ int cx = rc.right - rc.left;
+ if (!(wp->flags & SWP_NOMOVE)) { rc.left = wp->x; rc.top = wp->y; }
+
+ if (addbar)
+ Docking_RectToDock(&rc);
+
+ if (!(wp->flags & SWP_NOSIZE))
+ {
+ rc.right = rc.left + wp->cx;
+ rc.bottom = rc.top + wp->cy;
+ addbar |= (cx != wp->cx);
+ }
+
+ Docking_SetSize(msg->hwnd, &rc, !addbar, false);
+
+ if (!(wp->flags & SWP_NOMOVE)) { wp->x = rc.left; wp->y = rc.top; }
+ if (!(wp->flags & SWP_NOSIZE)) wp->cy = rc.bottom - rc.top;
+
+ *((LRESULT *) lParam) = TRUE;
+ return TRUE;
+ }
+ else
+ {
+ if ((wp->flags & SWP_SHOWWINDOW) && Docking_Command(msg->hwnd, ABM_NEW))
+ {
+ RECT rc = {0};
+ GetWindowRect(msg->hwnd, &rc);
+ Docking_RectToDock(&rc);
+
+ Docking_SetSize(msg->hwnd, &rc, false, false);
+
+ wp->x = rc.left;
+ wp->y = rc.top;
+ wp->cy = rc.bottom - rc.top;
+ wp->cx = rc.right - rc.left;
+ wp->flags &= ~(SWP_NOSIZE | SWP_NOMOVE);
+ }
+ }
+ }
+ break;
+ }
+
+ case WM_WINDOWPOSCHANGED:
+ {
+ LPWINDOWPOS wp = (LPWINDOWPOS)msg->lParam;
+ bool vis = Docking_IsWindowVisible(msg->hwnd);
+ if (wp->flags & SWP_SHOWWINDOW)
+ vis = !IsIconic(msg->hwnd);
+ if (wp->flags & SWP_HIDEWINDOW)
+ vis = false;
+
+ if (!vis)
+ Docking_Command(msg->hwnd, ABM_REMOVE);
+ else
+ Docking_Command(msg->hwnd, ABM_WINDOWPOSCHANGED);
+ break;
+ }
+
+ case WM_DISPLAYCHANGE:
+ if (Docking_IsWindowVisible(msg->hwnd))
+ {
+ RECT rc = {0};
+ GetWindowRect(msg->hwnd, &rc);
+ Docking_RectToDock(&rc);
+ Docking_SetSize(msg->hwnd, &rc, false, true);
+ }
+ break;
+
+ case WM_MOVING:
+ if (!docked)
+ {
+ RECT rcMonitor;
+ POINT ptCursor;
+
+ // stop early
+ if (GetAsyncKeyState(VK_CONTROL) & 0x8000)
+ return 0;
+
+ // GetMessagePos() is no good, position is always unsigned
+// GetCursorPos(&ptCursor);
+ DWORD pos = GetMessagePos();
+ ptCursor.x = GET_X_LPARAM(pos);
+ ptCursor.y = GET_Y_LPARAM(pos);
+ Docking_GetMonitorRectFromPoint(&ptCursor, &rcMonitor);
+
+ if (((ptCursor.x < rcMonitor.left + EDGESENSITIVITY) ||
+ (ptCursor.x >= rcMonitor.right - EDGESENSITIVITY)) &&
+ DBGetContactSettingByte(NULL, "CLUI", "DockToSides", 1))
+ {
+ docked = (ptCursor.x < rcMonitor.left + EDGESENSITIVITY) ? DOCKED_LEFT : DOCKED_RIGHT;
+ PostMessage(msg->hwnd, WM_LBUTTONUP, 0, MAKELPARAM(ptCursor.x, ptCursor.y));
+
+ Docking_Command(msg->hwnd, ABM_NEW);
+ Docking_AdjustPosition(msg->hwnd, &rcMonitor, (LPRECT)msg->lParam, false, true);
+
+ *((LRESULT *) lParam) = TRUE;
+ return TRUE;
+ }
+ }
+ break;
+
+ case WM_NCHITTEST:
+ switch (DefWindowProc(msg->hwnd, WM_NCHITTEST, msg->wParam, msg->lParam))
+ {
+ case HTSIZE: case HTTOP: case HTTOPLEFT: case HTTOPRIGHT:
+ case HTBOTTOM: case HTBOTTOMRIGHT: case HTBOTTOMLEFT:
+ *((LRESULT *) lParam) = HTCLIENT;
+ return TRUE;
+
+ case HTLEFT:
+ if (docked == DOCKED_LEFT)
+ {
+ *((LRESULT *) lParam) = HTCLIENT;
+ return TRUE;
+ }
+ break;
+
+ case HTRIGHT:
+ if (docked == DOCKED_RIGHT)
+ {
+ *((LRESULT *) lParam) = HTCLIENT;
+ return TRUE;
+ }
+ break;
+ }
+ break;
+
+ case WM_SYSCOMMAND:
+ if ((msg->wParam & 0xFFF0) != SC_MOVE)
+ return 0;
+
+ SetActiveWindow(msg->hwnd);
+ SetCapture(msg->hwnd);
+ draggingTitle = 1;
+ *((LRESULT *) lParam) = 0;
+ return 1;
+
+ case WM_MOUSEMOVE:
+ if (draggingTitle)
+ {
+ RECT rc;
+ POINT pt;
+ GetClientRect(msg->hwnd, &rc);
+ if ((docked == DOCKED_LEFT && (short) LOWORD(msg->lParam) > rc.right) ||
+ (docked == DOCKED_RIGHT && (short) LOWORD(msg->lParam) < 0))
+ {
+ ReleaseCapture();
+ draggingTitle = 0;
+ docked = 0;
+ GetCursorPos(&pt);
+ PostMessage(msg->hwnd, WM_NCLBUTTONDOWN, HTCAPTION, MAKELPARAM(pt.x, pt.y));
+ SetWindowPos(msg->hwnd, 0, pt.x - rc.right / 2,
+ pt.y - GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYSMCAPTION) / 2,
+ DBGetContactSettingDword(NULL, "CList", "Width", 0),
+ DBGetContactSettingDword(NULL, "CList", "Height", 0),
+ SWP_NOZORDER);
+ Docking_Command(msg->hwnd, ABM_REMOVE);
+ }
+ return 1;
+ }
+ break;
+
+ case WM_LBUTTONUP:
+ if (draggingTitle)
+ {
+ ReleaseCapture();
+ draggingTitle = 0;
+ }
+ break;
+
+ case WM_DOCKCALLBACK:
+ switch (msg->wParam)
+ {
+ case ABN_WINDOWARRANGE:
+ ShowWindow(msg->hwnd, msg->lParam ? SW_HIDE : SW_SHOW);
+ break;
+
+ case ABN_POSCHANGED:
+ {
+ RECT rc = {0};
+ GetWindowRect(msg->hwnd, &rc);
+ Docking_SetSize(msg->hwnd, &rc, false, true);
+ }
+ break;
+ }
+ return 1;
+
+ case WM_DESTROY:
+ Docking_Command(msg->hwnd, ABM_REMOVE);
+ break;
+ }
+ return 0;
+}
diff --git a/src/modules/clist/clc.cpp b/src/modules/clist/clc.cpp
new file mode 100644
index 0000000000..1994706992
--- /dev/null
+++ b/src/modules/clist/clc.cpp
@@ -0,0 +1,1350 @@
+/*
+
+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 "clc.h"
+
+int InitGenMenu( void );
+int UnitGenMenu( void );
+
+void InitCustomMenus( void );
+void UninitCustomMenus( void );
+
+void MTG_OnmodulesLoad( void );
+
+static BOOL bModuleInitialized = FALSE;
+static HANDLE hClcWindowList;
+static HANDLE hShowInfoTipEvent;
+HANDLE hHideInfoTipEvent;
+static HANDLE hAckHook;
+static HANDLE hClcSettingsChanged;
+
+int g_IconWidth, g_IconHeight;
+
+void FreeDisplayNameCache(void);
+
+void fnClcBroadcast( int msg, WPARAM wParam, LPARAM lParam )
+{
+ WindowList_Broadcast(hClcWindowList, msg, wParam, lParam);
+}
+
+void fnClcOptionsChanged(void)
+{
+ cli.pfnClcBroadcast( INTM_RELOADOPTIONS, 0, 0);
+}
+
+HMENU fnBuildGroupPopupMenu( struct ClcGroup* group )
+{
+ HMENU hMenu = LoadMenu(cli.hInst, MAKEINTRESOURCE(IDR_CONTEXT));
+ HMENU hGroupMenu = GetSubMenu(hMenu, 2);
+ RemoveMenu(hMenu, 2, MF_BYPOSITION);
+ DestroyMenu(hMenu);
+ CallService(MS_LANGPACK_TRANSLATEMENU, (WPARAM) hGroupMenu, 0);
+
+ CheckMenuItem(hGroupMenu, POPUP_GROUPHIDEOFFLINE, group->hideOffline ? MF_CHECKED : MF_UNCHECKED);
+ return hGroupMenu;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// standard CLC services
+
+static int ClcSettingChanged(WPARAM wParam, LPARAM lParam)
+{
+ char *szProto;
+ DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING *) lParam;
+ if ( (HANDLE)wParam != NULL && !strcmp(cws->szModule, "CList")) {
+ if (!strcmp(cws->szSetting, "MyHandle")) {
+ cli.pfnInvalidateDisplayNameCacheEntry((HANDLE) wParam);
+ cli.pfnClcBroadcast( INTM_NAMECHANGED, wParam, lParam);
+ }
+ else if (!strcmp(cws->szSetting, "Group"))
+ cli.pfnClcBroadcast( INTM_GROUPCHANGED, wParam, lParam);
+ else if (!strcmp(cws->szSetting, "Hidden"))
+ cli.pfnClcBroadcast( INTM_HIDDENCHANGED, wParam, lParam);
+ else if (!strcmp(cws->szSetting, "NotOnList"))
+ cli.pfnClcBroadcast( INTM_NOTONLISTCHANGED, wParam, lParam);
+ else if (!strcmp(cws->szSetting, "Status"))
+ cli.pfnClcBroadcast( INTM_INVALIDATE, 0, 0);
+ else if (!strcmp(cws->szSetting, "NameOrder"))
+ cli.pfnClcBroadcast( INTM_NAMEORDERCHANGED, 0, 0);
+ }
+ else if (!strcmp(cws->szModule, "CListGroups")) {
+ cli.pfnClcBroadcast( INTM_GROUPSCHANGED, wParam, lParam);
+ }
+ else {
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ if (szProto != NULL && (HANDLE) wParam != NULL) {
+ char *id = NULL;
+ if (!strcmp(cws->szModule, "Protocol") && !strcmp(cws->szSetting, "p")) {
+ cli.pfnClcBroadcast( INTM_PROTOCHANGED, wParam, lParam);
+ }
+ // something is being written to a protocol module
+ if (!strcmp(szProto, cws->szModule)) {
+ // was a unique setting key written?
+ id = (char *) CallProtoService(szProto, PS_GETCAPS, PFLAG_UNIQUEIDSETTING, 0);
+ if ((INT_PTR) id != CALLSERVICE_NOTFOUND && id != NULL && !strcmp(id, cws->szSetting)) {
+ cli.pfnClcBroadcast( INTM_PROTOCHANGED, wParam, lParam);
+ }
+ }
+ }
+ if (szProto == NULL || strcmp(szProto, cws->szModule))
+ return 0;
+ if (!strcmp(cws->szSetting, "Nick") || !strcmp(cws->szSetting, "FirstName") || !strcmp(cws->szSetting, "e-mail")
+ || !strcmp(cws->szSetting, "LastName") || !strcmp(cws->szSetting, "UIN"))
+ cli.pfnClcBroadcast( INTM_NAMECHANGED, wParam, lParam);
+ else if (!strcmp(cws->szSetting, "ApparentMode"))
+ cli.pfnClcBroadcast( INTM_APPARENTMODECHANGED, wParam, lParam);
+ else if (!strcmp(cws->szSetting, "IdleTS"))
+ cli.pfnClcBroadcast( INTM_IDLECHANGED, wParam, lParam);
+ }
+ return 0;
+}
+
+static int ClcAccountsChanged(WPARAM, LPARAM)
+{
+ int i, cnt;
+ for (i = 0, cnt = 0; i < accounts.getCount(); ++i)
+ if (Proto_IsAccountEnabled(accounts[i])) ++cnt;
+
+ cli.hClcProtoCount = cnt;
+ cli.clcProto = (ClcProtoStatus *) mir_realloc(cli.clcProto, sizeof(ClcProtoStatus) * cli.hClcProtoCount);
+
+ for (i = 0, cnt = 0; i < accounts.getCount(); ++i) {
+ if (Proto_IsAccountEnabled(accounts[i])) {
+ cli.clcProto[cnt].szProto = accounts[i]->szModuleName;
+ cli.clcProto[cnt].dwStatus = CallProtoService(accounts[i]->szModuleName, PS_GETSTATUS, 0, 0);
+ ++cnt;
+ }
+ }
+ return 0;
+}
+
+static int ClcModulesLoaded(WPARAM, LPARAM)
+{
+ ClcAccountsChanged(0, 0);
+ MTG_OnmodulesLoad();
+ return 0;
+}
+
+static int ClcProtoAck(WPARAM, LPARAM lParam)
+{
+ ACKDATA *ack = (ACKDATA *) lParam;
+ int i;
+
+ if (ack->type == ACKTYPE_STATUS) {
+ WindowList_BroadcastAsync(hClcWindowList,INTM_INVALIDATE,0,0);
+ if (ack->result == ACKRESULT_SUCCESS) {
+ for (i = 0; i < cli.hClcProtoCount; i++) {
+ if (!lstrcmpA(cli.clcProto[i].szProto, ack->szModule)) {
+ cli.clcProto[i].dwStatus = (WORD) ack->lParam;
+ break;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static int ClcContactAdded(WPARAM wParam, LPARAM lParam)
+{
+ WindowList_BroadcastAsync(hClcWindowList,INTM_CONTACTADDED,wParam,lParam);
+ return 0;
+}
+
+static int ClcContactDeleted(WPARAM wParam, LPARAM lParam)
+{
+ WindowList_BroadcastAsync(hClcWindowList,INTM_CONTACTDELETED,wParam,lParam);
+ return 0;
+}
+
+static int ClcContactIconChanged(WPARAM wParam, LPARAM lParam)
+{
+ WindowList_BroadcastAsync(hClcWindowList,INTM_ICONCHANGED,wParam,lParam);
+ return 0;
+}
+
+static int ClcIconsChanged(WPARAM, LPARAM)
+{
+ WindowList_BroadcastAsync(hClcWindowList,INTM_INVALIDATE,0,0);
+ return 0;
+}
+
+static INT_PTR SetInfoTipHoverTime(WPARAM wParam, LPARAM)
+{
+ DBWriteContactSettingWord(NULL, "CLC", "InfoTipHoverTime", (WORD) wParam);
+ cli.pfnClcBroadcast( INTM_SETINFOTIPHOVERTIME, wParam, 0);
+ return 0;
+}
+
+static INT_PTR GetInfoTipHoverTime(WPARAM, LPARAM)
+{
+ return DBGetContactSettingWord(NULL, "CLC", "InfoTipHoverTime", 750);
+}
+
+static void SortClcByTimer( HWND hwnd )
+{
+ KillTimer( hwnd, TIMERID_DELAYEDRESORTCLC );
+ SetTimer( hwnd, TIMERID_DELAYEDRESORTCLC, 200, NULL );
+}
+
+int LoadCLCModule(void)
+{
+ bModuleInitialized = TRUE;
+
+ g_IconWidth = GetSystemMetrics(SM_CXSMICON);
+ g_IconHeight = GetSystemMetrics(SM_CYSMICON);
+
+ hClcWindowList = (HANDLE) CallService(MS_UTILS_ALLOCWINDOWLIST, 0, 0);
+ hShowInfoTipEvent = CreateHookableEvent(ME_CLC_SHOWINFOTIP);
+ hHideInfoTipEvent = CreateHookableEvent(ME_CLC_HIDEINFOTIP);
+ CreateServiceFunction(MS_CLC_SETINFOTIPHOVERTIME, SetInfoTipHoverTime);
+ CreateServiceFunction(MS_CLC_GETINFOTIPHOVERTIME, GetInfoTipHoverTime);
+
+ InitFileDropping();
+
+ HookEvent(ME_SYSTEM_MODULESLOADED, ClcModulesLoaded);
+ HookEvent(ME_PROTO_ACCLISTCHANGED, ClcAccountsChanged);
+ hClcSettingsChanged = HookEvent(ME_DB_CONTACT_SETTINGCHANGED, ClcSettingChanged);
+ HookEvent(ME_DB_CONTACT_ADDED, ClcContactAdded);
+ HookEvent(ME_DB_CONTACT_DELETED, ClcContactDeleted);
+ HookEvent(ME_CLIST_CONTACTICONCHANGED, ClcContactIconChanged);
+ HookEvent(ME_SKIN_ICONSCHANGED, ClcIconsChanged);
+ hAckHook = (HANDLE) HookEvent(ME_PROTO_ACK, ClcProtoAck);
+
+ InitCustomMenus();
+ return 0;
+}
+
+void UnloadClcModule()
+{
+ if ( !bModuleInitialized ) return;
+
+ UnhookEvent(hAckHook);
+ UnhookEvent(hClcSettingsChanged);
+
+ mir_free(cli.clcProto);
+
+ FreeDisplayNameCache();
+
+ UninitCustomMenus();
+ UnitGenMenu();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// default contact list control window procedure
+
+LRESULT CALLBACK fnContactListControlWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct ClcData *dat;
+
+ dat = (struct ClcData *) GetWindowLongPtr(hwnd, 0);
+ if (msg >= CLM_FIRST && msg < CLM_LAST)
+ return cli.pfnProcessExternalMessages(hwnd, dat, msg, wParam, lParam);
+
+ switch (msg) {
+ case WM_CREATE:
+ WindowList_Add(hClcWindowList, hwnd, NULL);
+ cli.pfnRegisterFileDropping(hwnd);
+ if ( dat == NULL ) {
+ dat = (struct ClcData *) mir_calloc(sizeof(struct ClcData));
+ SetWindowLongPtr(hwnd, 0, (LONG_PTR) dat);
+ }
+ {
+ int i;
+ for (i = 0; i <= FONTID_MAX; i++)
+ dat->fontInfo[i].changed = 1;
+ }
+ dat->selection = -1;
+ dat->iconXSpace = 20;
+ dat->checkboxSize = 13;
+ dat->dragAutoScrollHeight = 30;
+ dat->iDragItem = -1;
+ dat->iInsertionMark = -1;
+ dat->insertionMarkHitHeight = 5;
+ dat->iHotTrack = -1;
+ dat->infoTipTimeout = DBGetContactSettingWord(NULL, "CLC", "InfoTipHoverTime", 750);
+ dat->extraColumnSpacing = 20;
+ dat->list.cl.increment = 30;
+ dat->needsResort = 1;
+ cli.pfnLoadClcOptions(hwnd, dat);
+ if (!IsWindowVisible(hwnd))
+ SetTimer(hwnd,TIMERID_REBUILDAFTER,10,NULL);
+ else
+ {
+ cli.pfnRebuildEntireList(hwnd,dat);
+ NMCLISTCONTROL nm;
+ nm.hdr.code = CLN_LISTREBUILT;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nm);
+ }
+ break;
+ case INTM_SCROLLBARCHANGED:
+ if (GetWindowLongPtr(hwnd, GWL_STYLE) & CLS_CONTACTLIST) {
+ if (dat->noVScrollbar)
+ ShowScrollBar(hwnd, SB_VERT, FALSE);
+ else
+ cli.pfnRecalcScrollBar(hwnd, dat);
+ }
+ break;
+
+ case INTM_RELOADOPTIONS:
+ cli.pfnLoadClcOptions(hwnd, dat);
+ cli.pfnSaveStateAndRebuildList(hwnd, dat);
+ break;
+ case WM_THEMECHANGED:
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+ case WM_SIZE:
+ cli.pfnEndRename(hwnd, dat, 1);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ KillTimer(hwnd, TIMERID_RENAME);
+ cli.pfnRecalcScrollBar(hwnd, dat);
+ { // creating imagelist containing blue line for highlight
+ HBITMAP hBmp, hBmpMask, hoBmp, hoMaskBmp;
+ HDC hdc,hdcMem;
+ RECT rc;
+ int depth;
+ HBRUSH hBrush;
+
+ GetClientRect(hwnd, &rc);
+ if (rc.right == 0)
+ break;
+ rc.bottom = dat->rowHeight;
+ hdc = GetDC(hwnd);
+ depth = GetDeviceCaps(hdc, BITSPIXEL);
+ if (depth < 16)
+ depth = 16;
+ hBmp = CreateBitmap(rc.right, rc.bottom, 1, depth, NULL);
+ hBmpMask = CreateBitmap(rc.right, rc.bottom, 1, 1, NULL);
+ hdcMem = CreateCompatibleDC(hdc);
+ hoBmp = (HBITMAP) SelectObject(hdcMem, hBmp);
+ hBrush = CreateSolidBrush(dat->useWindowsColours ? GetSysColor(COLOR_HIGHLIGHT) : dat->selBkColour);
+ FillRect(hdcMem, &rc, hBrush);
+ DeleteObject(hBrush);
+
+ hoMaskBmp = ( HBITMAP )SelectObject(hdcMem, hBmpMask);
+ FillRect(hdcMem, &rc, ( HBRUSH )GetStockObject(BLACK_BRUSH));
+ SelectObject(hdcMem, hoMaskBmp);
+ SelectObject(hdcMem, hoBmp);
+ DeleteDC(hdcMem);
+ ReleaseDC(hwnd, hdc);
+ if (dat->himlHighlight)
+ ImageList_Destroy(dat->himlHighlight);
+ dat->himlHighlight = ImageList_Create(rc.right, rc.bottom, (IsWinVerXPPlus()? ILC_COLOR32 : ILC_COLOR16) | ILC_MASK, 1, 1);
+ ImageList_Add(dat->himlHighlight, hBmp, hBmpMask);
+ DeleteObject(hBmpMask);
+ DeleteObject(hBmp);
+ }
+ break;
+
+ case WM_SYSCOLORCHANGE:
+ SendMessage(hwnd, WM_SIZE, 0, 0);
+ break;
+
+ case WM_GETDLGCODE:
+ if (lParam) {
+ MSG *msg = (MSG *) lParam;
+ if (msg->message == WM_KEYDOWN) {
+ if (msg->wParam == VK_TAB)
+ return 0;
+ if (msg->wParam == VK_ESCAPE && dat->hwndRenameEdit == NULL && dat->szQuickSearch[0] == 0)
+ return 0;
+ }
+ if (msg->message == WM_CHAR) {
+ if (msg->wParam == '\t')
+ return 0;
+ if (msg->wParam == 27 && dat->hwndRenameEdit == NULL && dat->szQuickSearch[0] == 0)
+ return 0;
+ }
+ }
+ return DLGC_WANTMESSAGE;
+
+ case WM_KILLFOCUS:
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ KillTimer(hwnd, TIMERID_RENAME);
+ case WM_SETFOCUS:
+ case WM_ENABLE:
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+
+ case WM_GETFONT:
+ return (LRESULT) dat->fontInfo[FONTID_CONTACTS].hFont;
+
+ case INTM_GROUPSCHANGED:
+ {
+ DBCONTACTWRITESETTING *dbcws = (DBCONTACTWRITESETTING *) lParam;
+ if (dbcws->value.type == DBVT_ASCIIZ || dbcws->value.type == DBVT_UTF8) {
+ int groupId = atoi(dbcws->szSetting) + 1;
+ struct ClcContact *contact;
+ struct ClcGroup *group;
+ TCHAR szFullName[512];
+ int i, nameLen, eq;
+ //check name of group and ignore message if just being expanded/collapsed
+ if (cli.pfnFindItem(hwnd, dat, (HANDLE) (groupId | HCONTACT_ISGROUP), &contact, &group, NULL)) {
+ lstrcpy(szFullName, contact->szText);
+ while (group->parent) {
+ for (i = 0; i < group->parent->cl.count; i++)
+ if (group->parent->cl.items[i]->group == group)
+ break;
+ if (i == group->parent->cl.count) {
+ szFullName[0] = '\0';
+ break;
+ }
+ group = group->parent;
+ nameLen = lstrlen(group->cl.items[i]->szText);
+ if (lstrlen(szFullName) + 1 + nameLen > SIZEOF(szFullName)) {
+ szFullName[0] = '\0';
+ break;
+ }
+ memmove(szFullName + 1 + nameLen, szFullName, sizeof( TCHAR )*( lstrlen(szFullName) + 1));
+ memcpy(szFullName, group->cl.items[i]->szText, sizeof( TCHAR )*nameLen);
+ szFullName[nameLen] = '\\';
+ }
+
+ if ( dbcws->value.type == DBVT_ASCIIZ ) {
+ #if defined( UNICODE )
+ WCHAR* wszGrpName = mir_a2u(dbcws->value.pszVal+1);
+ eq = !lstrcmp( szFullName, wszGrpName );
+ mir_free( wszGrpName );
+ #else
+ eq = !lstrcmp( szFullName, dbcws->value.pszVal+1 );
+ #endif
+ }
+ else {
+ char* szGrpName = NEWSTR_ALLOCA(dbcws->value.pszVal+1);
+ #if defined( UNICODE )
+ WCHAR* wszGrpName;
+ Utf8Decode(szGrpName, &wszGrpName );
+ eq = !lstrcmp( szFullName, wszGrpName );
+ mir_free( wszGrpName );
+ #else
+ Utf8Decode(szGrpName, NULL);
+ eq = !lstrcmp( szFullName, szGrpName );
+ #endif
+ }
+ if ( eq && (contact->group->hideOffline != 0) == ((dbcws->value.pszVal[0] & GROUPF_HIDEOFFLINE) != 0))
+ break; //only expanded has changed: no action reqd
+ }
+ }
+ cli.pfnSaveStateAndRebuildList(hwnd, dat);
+ break;
+ }
+ case INTM_NAMEORDERCHANGED:
+ PostMessage(hwnd, CLM_AUTOREBUILD, 0, 0);
+ break;
+
+ case INTM_CONTACTADDED:
+ cli.pfnAddContactToTree(hwnd, dat, (HANDLE) wParam, 1, 1);
+ cli.pfnNotifyNewContact(hwnd, (HANDLE) wParam);
+ SortClcByTimer(hwnd);
+ break;
+
+ case INTM_CONTACTDELETED:
+ cli.pfnDeleteItemFromTree(hwnd, (HANDLE) wParam);
+ SortClcByTimer(hwnd);
+ break;
+
+ case INTM_HIDDENCHANGED:
+ {
+ DBCONTACTWRITESETTING *dbcws = (DBCONTACTWRITESETTING *) lParam;
+ if (GetWindowLongPtr(hwnd, GWL_STYLE) & CLS_SHOWHIDDEN)
+ break;
+ if (dbcws->value.type == DBVT_DELETED || dbcws->value.bVal == 0) {
+ if (cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, NULL, NULL, NULL))
+ break;
+ cli.pfnAddContactToTree(hwnd, dat, (HANDLE) wParam, 1, 1);
+ cli.pfnNotifyNewContact(hwnd, (HANDLE) wParam);
+ }
+ else cli.pfnDeleteItemFromTree(hwnd, (HANDLE) wParam);
+
+ dat->needsResort = 1;
+ SortClcByTimer(hwnd);
+ break;
+ }
+ case INTM_GROUPCHANGED:
+ {
+ struct ClcContact *contact;
+ BYTE iExtraImage[MAXEXTRACOLUMNS];
+ BYTE flags = 0;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ memset(iExtraImage, 0xFF, SIZEOF(iExtraImage));
+ else {
+ CopyMemory(iExtraImage, contact->iExtraImage, SIZEOF(iExtraImage));
+ flags = contact->flags;
+ }
+ cli.pfnDeleteItemFromTree(hwnd, (HANDLE) wParam);
+ if (GetWindowLongPtr(hwnd, GWL_STYLE) & CLS_SHOWHIDDEN || !DBGetContactSettingByte((HANDLE) wParam, "CList", "Hidden", 0)) {
+ NMCLISTCONTROL nm;
+ cli.pfnAddContactToTree(hwnd, dat, (HANDLE) wParam, 1, 1);
+ if (cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL)) {
+ CopyMemory(contact->iExtraImage, iExtraImage, SIZEOF(iExtraImage));
+ if(flags & CONTACTF_CHECKED)
+ contact->flags |= CONTACTF_CHECKED;
+ }
+ nm.hdr.code = CLN_CONTACTMOVED;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.flags = 0;
+ nm.hItem = (HANDLE) wParam;
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nm);
+ dat->needsResort = 1;
+ }
+ SetTimer(hwnd,TIMERID_REBUILDAFTER,1,NULL);
+ break;
+ }
+ case INTM_ICONCHANGED:
+ {
+ struct ClcContact *contact = NULL;
+ struct ClcGroup *group = NULL;
+ int recalcScrollBar = 0, shouldShow;
+ WORD status;
+ char *szProto;
+ HANDLE hSelItem = NULL;
+ struct ClcContact *selcontact = NULL;
+
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ if (szProto == NULL)
+ status = ID_STATUS_OFFLINE;
+ else
+ status = DBGetContactSettingWord((HANDLE) wParam, szProto, "Status", ID_STATUS_OFFLINE);
+
+ DWORD style = GetWindowLongPtr(hwnd, GWL_STYLE);
+ shouldShow = (style & CLS_SHOWHIDDEN || !DBGetContactSettingByte((HANDLE) wParam, "CList", "Hidden", 0))
+ && (!cli.pfnIsHiddenMode(dat, status)
+ || CallService(MS_CLIST_GETCONTACTICON, wParam, 0) != lParam); // this means an offline msg is flashing, so the contact should be shown
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, &group, NULL)) {
+ if (shouldShow && CallService(MS_DB_CONTACT_IS, wParam, 0)) {
+ if (dat->selection >= 0 && cli.pfnGetRowByIndex(dat, dat->selection, &selcontact, NULL) != -1)
+ hSelItem = cli.pfnContactToHItem(selcontact);
+ cli.pfnAddContactToTree(hwnd, dat, (HANDLE) wParam, (style & CLS_CONTACTLIST) == 0, 0);
+ recalcScrollBar = 1;
+ cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL);
+ if (contact) {
+ contact->iImage = (WORD) lParam;
+ cli.pfnNotifyNewContact(hwnd, (HANDLE) wParam);
+ dat->needsResort = 1;
+ } }
+ }
+ else { // item in list already
+ if (contact->iImage == (WORD) lParam)
+ break;
+ if (!shouldShow && !(style & CLS_NOHIDEOFFLINE) && (style & CLS_HIDEOFFLINE || group->hideOffline)) {
+ if (dat->selection >= 0 && cli.pfnGetRowByIndex(dat, dat->selection, &selcontact, NULL) != -1)
+ hSelItem = cli.pfnContactToHItem(selcontact);
+ cli.pfnRemoveItemFromGroup(hwnd, group, contact, (style & CLS_CONTACTLIST) == 0);
+ recalcScrollBar = 1;
+ }
+ else {
+ contact->iImage = (WORD) lParam;
+ if (!cli.pfnIsHiddenMode(dat, status))
+ contact->flags |= CONTACTF_ONLINE;
+ else
+ contact->flags &= ~CONTACTF_ONLINE;
+ }
+ dat->needsResort = 1;
+ }
+ if (hSelItem) {
+ struct ClcGroup *selgroup;
+ if (cli.pfnFindItem(hwnd, dat, hSelItem, &selcontact, &selgroup, NULL))
+ dat->selection = cli.pfnGetRowsPriorTo(&dat->list, selgroup, List_IndexOf(( SortedList* )&selgroup->cl, selcontact));
+ else
+ dat->selection = -1;
+ }
+ SortClcByTimer(hwnd);
+ break;
+ }
+ case INTM_NAMECHANGED:
+ {
+ struct ClcContact *contact;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ break;
+
+ lstrcpyn(contact->szText, cli.pfnGetContactDisplayName((HANDLE)wParam,0), SIZEOF(contact->szText));
+ dat->needsResort = 1;
+ SortClcByTimer(hwnd);
+ break;
+ }
+ case INTM_PROTOCHANGED:
+ {
+ struct ClcContact *contact = NULL;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ break;
+ contact->proto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ cli.pfnInvalidateDisplayNameCacheEntry((HANDLE)wParam);
+ lstrcpyn(contact->szText, cli.pfnGetContactDisplayName((HANDLE)wParam,0), SIZEOF(contact->szText));
+ SortClcByTimer(hwnd);
+ break;
+ }
+ case INTM_NOTONLISTCHANGED:
+ {
+ DBCONTACTWRITESETTING *dbcws = (DBCONTACTWRITESETTING *) lParam;
+ struct ClcContact *contact;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ break;
+ if (contact->type != CLCIT_CONTACT)
+ break;
+ if (dbcws->value.type == DBVT_DELETED || dbcws->value.bVal == 0)
+ contact->flags &= ~CONTACTF_NOTONLIST;
+ else
+ contact->flags |= CONTACTF_NOTONLIST;
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+ }
+ case INTM_INVALIDATE:
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+
+ case INTM_APPARENTMODECHANGED:
+ {
+ WORD apparentMode;
+ char *szProto;
+ struct ClcContact *contact;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ break;
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ if (szProto == NULL)
+ break;
+ apparentMode = DBGetContactSettingWord((HANDLE) wParam, szProto, "ApparentMode", 0);
+ contact->flags &= ~(CONTACTF_INVISTO | CONTACTF_VISTO);
+ if (apparentMode == ID_STATUS_OFFLINE)
+ contact->flags |= CONTACTF_INVISTO;
+ else if (apparentMode == ID_STATUS_ONLINE)
+ contact->flags |= CONTACTF_VISTO;
+ else if (apparentMode)
+ contact->flags |= CONTACTF_VISTO | CONTACTF_INVISTO;
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+ }
+ case INTM_SETINFOTIPHOVERTIME:
+ dat->infoTipTimeout = wParam;
+ break;
+
+ case INTM_IDLECHANGED:
+ {
+ char *szProto;
+ struct ClcContact *contact;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ break;
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ if (szProto == NULL)
+ break;
+ contact->flags &= ~CONTACTF_IDLE;
+ if (DBGetContactSettingDword((HANDLE) wParam, szProto, "IdleTS", 0)) {
+ contact->flags |= CONTACTF_IDLE;
+ }
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+ }
+ case WM_PRINTCLIENT:
+ cli.pfnPaintClc(hwnd, dat, (HDC) wParam, NULL);
+ break;
+
+ case WM_NCPAINT:
+ if (wParam == 1)
+ break;
+ {
+ POINT ptTopLeft = { 0, 0 };
+ HRGN hClientRgn;
+ ClientToScreen(hwnd, &ptTopLeft);
+ hClientRgn = CreateRectRgn(0, 0, 1, 1);
+ CombineRgn(hClientRgn, (HRGN) wParam, NULL, RGN_COPY);
+ OffsetRgn(hClientRgn, -ptTopLeft.x, -ptTopLeft.y);
+ InvalidateRgn(hwnd, hClientRgn, FALSE);
+ DeleteObject(hClientRgn);
+ UpdateWindow(hwnd);
+ }
+ break;
+
+ case WM_PAINT:
+ {
+ HDC hdc;
+ PAINTSTRUCT ps;
+ hdc = BeginPaint(hwnd, &ps);
+ /* we get so many cli.pfnInvalidateRect()'s that there is no point painting,
+ Windows in theory shouldn't queue up WM_PAINTs in this case but it does so
+ we'll just ignore them */
+ if (IsWindowVisible(hwnd))
+ cli.pfnPaintClc(hwnd, dat, hdc, &ps.rcPaint);
+ EndPaint(hwnd, &ps);
+ break;
+ }
+ case WM_VSCROLL:
+ {
+ int desty;
+ RECT clRect;
+ int noSmooth = 0;
+
+ cli.pfnEndRename(hwnd, dat, 1);
+ cli.pfnHideInfoTip(hwnd, dat);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ KillTimer(hwnd, TIMERID_RENAME);
+ desty = dat->yScroll;
+ GetClientRect(hwnd, &clRect);
+ switch (LOWORD(wParam)) {
+ case SB_LINEUP: desty -= dat->rowHeight; break;
+ case SB_LINEDOWN: desty += dat->rowHeight; break;
+ case SB_PAGEUP: desty -= clRect.bottom - dat->rowHeight; break;
+ case SB_PAGEDOWN: desty += clRect.bottom - dat->rowHeight; break;
+ case SB_BOTTOM: desty = 0x7FFFFFFF; break;
+ case SB_TOP: desty = 0; break;
+ case SB_THUMBTRACK: desty = HIWORD(wParam); noSmooth = 1; break; //noone has more than 4000 contacts, right?
+ default: return 0;
+ }
+ cli.pfnScrollTo(hwnd, dat, desty, noSmooth);
+ break;
+ }
+ case WM_MOUSEWHEEL:
+ {
+ UINT scrollLines;
+ cli.pfnEndRename(hwnd, dat, 1);
+ cli.pfnHideInfoTip(hwnd, dat);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ KillTimer(hwnd, TIMERID_RENAME);
+ if (!SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &scrollLines, FALSE))
+ scrollLines = 3;
+ cli.pfnScrollTo(hwnd, dat, dat->yScroll - (short) HIWORD(wParam) * dat->rowHeight * (signed) scrollLines / WHEEL_DELTA, 0);
+ return 0;
+ }
+ case WM_KEYDOWN:
+ {
+ int selMoved = 0;
+ int changeGroupExpand = 0;
+ int pageSize;
+ cli.pfnHideInfoTip(hwnd, dat);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ KillTimer(hwnd, TIMERID_RENAME);
+ if (CallService(MS_CLIST_MENUPROCESSHOTKEY, wParam, MPCF_CONTACTMENU))
+ break;
+ {
+ RECT clRect;
+ GetClientRect(hwnd, &clRect);
+ pageSize = clRect.bottom / dat->rowHeight;
+ }
+ switch (wParam) {
+ case VK_DOWN: dat->selection++; selMoved = 1; break;
+ case VK_UP: dat->selection--; selMoved = 1; break;
+ case VK_PRIOR: dat->selection -= pageSize; selMoved = 1; break;
+ case VK_NEXT: dat->selection += pageSize; selMoved = 1; break;
+ case VK_HOME: dat->selection = 0; selMoved = 1; break;
+ case VK_END: dat->selection = cli.pfnGetGroupContentsCount(&dat->list, 1) - 1; selMoved = 1; break;
+ case VK_LEFT: changeGroupExpand = 1; break;
+ case VK_RIGHT: changeGroupExpand = 2; break;
+ case VK_RETURN: cli.pfnDoSelectionDefaultAction(hwnd, dat); return 0;
+ case VK_F2: cli.pfnBeginRenameSelection(hwnd, dat); return 0;
+ case VK_DELETE: cli.pfnDeleteFromContactList(hwnd, dat); return 0;
+ default:
+ {
+ NMKEY nmkey;
+ nmkey.hdr.hwndFrom = hwnd;
+ nmkey.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nmkey.hdr.code = NM_KEYDOWN;
+ nmkey.nVKey = wParam;
+ nmkey.uFlags = HIWORD(lParam);
+ if (SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nmkey))
+ return 0;
+ }
+ }
+ if (changeGroupExpand) {
+ int hit;
+ struct ClcContact *contact;
+ struct ClcGroup *group;
+ dat->szQuickSearch[0] = 0;
+ hit = cli.pfnGetRowByIndex(dat, dat->selection, &contact, &group);
+ if (hit != -1) {
+ if (changeGroupExpand == 1 && contact->type == CLCIT_CONTACT) {
+ if (group == &dat->list)
+ return 0;
+ dat->selection = cli.pfnGetRowsPriorTo(&dat->list, group, -1);
+ selMoved = 1;
+ }
+ else {
+ if (contact->type == CLCIT_GROUP)
+ cli.pfnSetGroupExpand(hwnd, dat, contact->group, changeGroupExpand == 2);
+ return 0;
+ }
+ }
+ else
+ return 0;
+ }
+ if (selMoved) {
+ dat->szQuickSearch[0] = 0;
+ if (dat->selection >= cli.pfnGetGroupContentsCount(&dat->list, 1))
+ dat->selection = cli.pfnGetGroupContentsCount(&dat->list, 1) - 1;
+ if (dat->selection < 0)
+ dat->selection = 0;
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ cli.pfnEnsureVisible(hwnd, dat, dat->selection, 0);
+ UpdateWindow(hwnd);
+ return 0;
+ }
+ break;
+ }
+ case WM_CHAR:
+ cli.pfnHideInfoTip(hwnd, dat);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ KillTimer(hwnd, TIMERID_RENAME);
+ if (wParam == 27) //escape
+ dat->szQuickSearch[0] = 0;
+ else if (wParam == '\b' && dat->szQuickSearch[0])
+ dat->szQuickSearch[lstrlen(dat->szQuickSearch) - 1] = '\0';
+ else if (wParam < ' ')
+ break;
+ else if (wParam == ' ' && dat->szQuickSearch[0] == '\0' && GetWindowLongPtr(hwnd, GWL_STYLE) & CLS_CHECKBOXES) {
+ struct ClcContact *contact;
+ NMCLISTCONTROL nm;
+ if (cli.pfnGetRowByIndex(dat, dat->selection, &contact, NULL) == -1)
+ break;
+ if (contact->type != CLCIT_CONTACT)
+ break;
+ contact->flags ^= CONTACTF_CHECKED;
+ if (contact->type == CLCIT_GROUP)
+ cli.pfnSetGroupChildCheckboxes(contact->group, contact->flags & CONTACTF_CHECKED);
+ cli.pfnRecalculateGroupCheckboxes(hwnd, dat);
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ nm.hdr.code = CLN_CHECKCHANGED;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.flags = 0;
+ nm.hItem = cli.pfnContactToItemHandle(contact, &nm.flags);
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nm);
+ }
+ else {
+ TCHAR szNew[2];
+ szNew[0] = (TCHAR) wParam;
+ szNew[1] = '\0';
+ if (lstrlen(dat->szQuickSearch) >= SIZEOF(dat->szQuickSearch) - 1) {
+ MessageBeep(MB_OK);
+ break;
+ }
+ _tcscat(dat->szQuickSearch, szNew);
+ }
+ if (dat->szQuickSearch[0]) {
+ int index;
+ index = cli.pfnFindRowByText(hwnd, dat, dat->szQuickSearch, 1);
+ if (index != -1)
+ dat->selection = index;
+ else {
+ MessageBeep(MB_OK);
+ dat->szQuickSearch[ lstrlen(dat->szQuickSearch) - 1] = '\0';
+ }
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ cli.pfnEnsureVisible(hwnd, dat, dat->selection, 0);
+ }
+ else
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+
+ case WM_SYSKEYDOWN:
+ cli.pfnEndRename(hwnd, dat, 1);
+ cli.pfnHideInfoTip(hwnd, dat);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ KillTimer(hwnd, TIMERID_RENAME);
+ dat->iHotTrack = -1;
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ ReleaseCapture();
+ if (wParam == VK_F10 && GetKeyState(VK_SHIFT) & 0x8000)
+ break;
+ SendMessage(GetParent(hwnd), msg, wParam, lParam);
+ return 0;
+
+ case WM_TIMER:
+ switch( wParam ) {
+ case TIMERID_RENAME:
+ cli.pfnBeginRenameSelection(hwnd, dat);
+ break;
+ case TIMERID_DRAGAUTOSCROLL:
+ cli.pfnScrollTo(hwnd, dat, dat->yScroll + dat->dragAutoScrolling * dat->rowHeight * 2, 0);
+ break;
+ case TIMERID_INFOTIP:
+ { CLCINFOTIP it;
+ struct ClcContact *contact;
+ int hit;
+ RECT clRect;
+ POINT ptClientOffset = { 0 };
+
+ KillTimer(hwnd, wParam);
+ GetCursorPos(&it.ptCursor);
+ ScreenToClient(hwnd, &it.ptCursor);
+ if (it.ptCursor.x != dat->ptInfoTip.x || it.ptCursor.y != dat->ptInfoTip.y)
+ break;
+ GetClientRect(hwnd, &clRect);
+ it.rcItem.left = 0;
+ it.rcItem.right = clRect.right;
+ hit = cli.pfnHitTest(hwnd, dat, it.ptCursor.x, it.ptCursor.y, &contact, NULL, NULL);
+ if (hit == -1)
+ break;
+ if (contact->type != CLCIT_GROUP && contact->type != CLCIT_CONTACT)
+ break;
+ ClientToScreen(hwnd, &it.ptCursor);
+ ClientToScreen(hwnd, &ptClientOffset);
+ it.isTreeFocused = GetFocus() == hwnd;
+ it.rcItem.top = cli.pfnGetRowTopY(dat, hit) - dat->yScroll;
+ it.rcItem.bottom = it.rcItem.top + cli.pfnGetRowHeight(dat, hit);
+ OffsetRect(&it.rcItem, ptClientOffset.x, ptClientOffset.y);
+ it.isGroup = contact->type == CLCIT_GROUP;
+ it.hItem = contact->type == CLCIT_GROUP ? (HANDLE) contact->groupId : contact->hContact;
+ it.cbSize = sizeof(it);
+ dat->hInfoTipItem = cli.pfnContactToHItem(contact);
+ NotifyEventHooks(hShowInfoTipEvent, 0, (LPARAM) & it);
+ break;
+ }
+ case TIMERID_REBUILDAFTER:
+ KillTimer(hwnd,TIMERID_REBUILDAFTER);
+ cli.pfnInvalidateRect(hwnd,NULL,FALSE);
+ cli.pfnSaveStateAndRebuildList(hwnd,dat);
+ break;
+
+ case TIMERID_DELAYEDRESORTCLC:
+ KillTimer(hwnd,TIMERID_DELAYEDRESORTCLC);
+ cli.pfnInvalidateRect(hwnd,NULL,FALSE);
+ cli.pfnSortCLC(hwnd,dat,1);
+ cli.pfnRecalcScrollBar(hwnd,dat);
+ break;
+ }
+ break;
+
+ case WM_MBUTTONDOWN:
+ case WM_LBUTTONDOWN:
+ {
+ struct ClcContact *contact;
+ struct ClcGroup *group;
+ int hit;
+ DWORD hitFlags;
+
+ if (GetFocus() != hwnd)
+ SetFocus(hwnd);
+ cli.pfnHideInfoTip(hwnd, dat);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ KillTimer(hwnd, TIMERID_RENAME);
+ cli.pfnEndRename(hwnd, dat, 1);
+ dat->ptDragStart.x = (short) LOWORD(lParam);
+ dat->ptDragStart.y = (short) HIWORD(lParam);
+ dat->szQuickSearch[0] = 0;
+ hit = cli.pfnHitTest(hwnd, dat, (short) LOWORD(lParam), (short) HIWORD(lParam), &contact, &group, &hitFlags);
+ if (hit != -1) {
+ if (hit == dat->selection && hitFlags & CLCHT_ONITEMLABEL && dat->exStyle & CLS_EX_EDITLABELS) {
+ SetCapture(hwnd);
+ dat->iDragItem = dat->selection;
+ dat->dragStage = DRAGSTAGE_NOTMOVED | DRAGSTAGEF_MAYBERENAME;
+ dat->dragAutoScrolling = 0;
+ break;
+ } }
+
+ if (hit != -1 && contact->type == CLCIT_GROUP)
+ if (hitFlags & CLCHT_ONITEMICON) {
+ struct ClcGroup *selgroup;
+ struct ClcContact *selcontact;
+ dat->selection = cli.pfnGetRowByIndex(dat, dat->selection, &selcontact, &selgroup);
+ cli.pfnSetGroupExpand(hwnd, dat, contact->group, -1);
+ if (dat->selection != -1) {
+ dat->selection =
+ cli.pfnGetRowsPriorTo(&dat->list, selgroup, List_IndexOf((SortedList*)&selgroup->cl,selcontact));
+ if (dat->selection == -1)
+ dat->selection = cli.pfnGetRowsPriorTo(&dat->list, contact->group, -1);
+ }
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ UpdateWindow(hwnd);
+ break;
+ }
+ if (hit != -1 && hitFlags & CLCHT_ONITEMCHECK) {
+ NMCLISTCONTROL nm;
+ contact->flags ^= CONTACTF_CHECKED;
+ if (contact->type == CLCIT_GROUP)
+ cli.pfnSetGroupChildCheckboxes(contact->group, contact->flags & CONTACTF_CHECKED);
+ cli.pfnRecalculateGroupCheckboxes(hwnd, dat);
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ nm.hdr.code = CLN_CHECKCHANGED;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.flags = 0;
+ nm.hItem = cli.pfnContactToItemHandle(contact, &nm.flags);
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nm);
+ }
+ if (!(hitFlags & (CLCHT_ONITEMICON | CLCHT_ONITEMLABEL | CLCHT_ONITEMCHECK))) {
+ NMCLISTCONTROL nm;
+ nm.hdr.code = NM_CLICK;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.flags = 0;
+ if (hit == -1)
+ nm.hItem = NULL;
+ else
+ nm.hItem = cli.pfnContactToItemHandle(contact, &nm.flags);
+ nm.iColumn = hitFlags & CLCHT_ONITEMEXTRA ? HIBYTE(HIWORD(hitFlags)) : -1;
+ nm.pt = dat->ptDragStart;
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nm);
+ }
+ if (hitFlags & (CLCHT_ONITEMCHECK | CLCHT_ONITEMEXTRA))
+ break;
+ dat->selection = hit;
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ if (dat->selection != -1)
+ cli.pfnEnsureVisible(hwnd, dat, hit, 0);
+ UpdateWindow(hwnd);
+ if (dat->selection != -1 && (contact->type == CLCIT_CONTACT || contact->type == CLCIT_GROUP)
+ && !(hitFlags & (CLCHT_ONITEMEXTRA | CLCHT_ONITEMCHECK))) {
+ SetCapture(hwnd);
+ dat->iDragItem = dat->selection;
+ dat->dragStage = DRAGSTAGE_NOTMOVED;
+ dat->dragAutoScrolling = 0;
+ }
+ break;
+ }
+ case WM_MOUSEMOVE:
+ if (dat->iDragItem == -1) {
+ int iOldHotTrack = dat->iHotTrack;
+ if (dat->hwndRenameEdit != NULL)
+ break;
+ if (GetKeyState(VK_MENU) & 0x8000 || GetKeyState(VK_F10) & 0x8000)
+ break;
+ dat->iHotTrack = cli.pfnHitTest(hwnd, dat, (short) LOWORD(lParam), (short) HIWORD(lParam), NULL, NULL, NULL);
+ if (iOldHotTrack != dat->iHotTrack) {
+ if (iOldHotTrack == -1)
+ SetCapture(hwnd);
+ else if (dat->iHotTrack == -1)
+ ReleaseCapture();
+ if (dat->exStyle & CLS_EX_TRACKSELECT) {
+ cli.pfnInvalidateItem(hwnd, dat, iOldHotTrack);
+ cli.pfnInvalidateItem(hwnd, dat, dat->iHotTrack);
+ }
+ cli.pfnHideInfoTip(hwnd, dat);
+ }
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ if (wParam == 0 && dat->hInfoTipItem == NULL) {
+ dat->ptInfoTip.x = (short) LOWORD(lParam);
+ dat->ptInfoTip.y = (short) HIWORD(lParam);
+ SetTimer(hwnd, TIMERID_INFOTIP, dat->infoTipTimeout, NULL);
+ }
+ break;
+ }
+ if ((dat->dragStage & DRAGSTAGEM_STAGE) == DRAGSTAGE_NOTMOVED && !(dat->exStyle & CLS_EX_DISABLEDRAGDROP)) {
+ if (abs((short) LOWORD(lParam) - dat->ptDragStart.x) >= GetSystemMetrics(SM_CXDRAG)
+ || abs((short) HIWORD(lParam) - dat->ptDragStart.y) >= GetSystemMetrics(SM_CYDRAG))
+ dat->dragStage = (dat->dragStage & ~DRAGSTAGEM_STAGE) | DRAGSTAGE_ACTIVE;
+ }
+ if ((dat->dragStage & DRAGSTAGEM_STAGE) == DRAGSTAGE_ACTIVE) {
+ HCURSOR hNewCursor;
+ RECT clRect;
+ POINT pt;
+ int target;
+
+ GetClientRect(hwnd, &clRect);
+ pt.x = (short) LOWORD(lParam);
+ pt.y = (short) HIWORD(lParam);
+ hNewCursor = LoadCursor(NULL, IDC_NO);
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ if (dat->dragAutoScrolling) {
+ KillTimer(hwnd, TIMERID_DRAGAUTOSCROLL);
+ dat->dragAutoScrolling = 0;
+ }
+ target = cli.pfnGetDropTargetInformation(hwnd, dat, pt);
+ if (dat->dragStage & DRAGSTAGEF_OUTSIDE && target != DROPTARGET_OUTSIDE) {
+ NMCLISTCONTROL nm;
+ struct ClcContact *contact;
+ cli.pfnGetRowByIndex(dat, dat->iDragItem, &contact, NULL);
+ nm.hdr.code = CLN_DRAGSTOP;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.flags = 0;
+ nm.hItem = cli.pfnContactToItemHandle(contact, &nm.flags);
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nm);
+ dat->dragStage &= ~DRAGSTAGEF_OUTSIDE;
+ }
+ switch (target) {
+ case DROPTARGET_ONSELF:
+ case DROPTARGET_ONCONTACT:
+ break;
+ case DROPTARGET_ONGROUP:
+ hNewCursor = LoadCursor(cli.hInst, MAKEINTRESOURCE(IDC_DROPUSER));
+ break;
+ case DROPTARGET_INSERTION:
+ hNewCursor = LoadCursor(cli.hInst, MAKEINTRESOURCE(IDC_DROPUSER));
+ break;
+ case DROPTARGET_OUTSIDE:
+ {
+ NMCLISTCONTROL nm;
+ struct ClcContact *contact;
+
+ if (pt.x >= 0 && pt.x < clRect.right
+ && ((pt.y < 0 && pt.y > -dat->dragAutoScrollHeight)
+ || (pt.y >= clRect.bottom && pt.y < clRect.bottom + dat->dragAutoScrollHeight))) {
+ if (!dat->dragAutoScrolling) {
+ if (pt.y < 0)
+ dat->dragAutoScrolling = -1;
+ else
+ dat->dragAutoScrolling = 1;
+ SetTimer(hwnd, TIMERID_DRAGAUTOSCROLL, dat->scrollTime, NULL);
+ }
+ SendMessage(hwnd, WM_TIMER, TIMERID_DRAGAUTOSCROLL, 0);
+ }
+
+ dat->dragStage |= DRAGSTAGEF_OUTSIDE;
+ cli.pfnGetRowByIndex(dat, dat->iDragItem, &contact, NULL);
+ nm.hdr.code = CLN_DRAGGING;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.flags = 0;
+ nm.hItem = cli.pfnContactToItemHandle(contact, &nm.flags);
+ nm.pt = pt;
+ if (SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nm))
+ return 0;
+ break;
+ }
+ default:
+ {
+ struct ClcGroup *group;
+ cli.pfnGetRowByIndex(dat, dat->iDragItem, NULL, &group);
+ if (group->parent)
+ hNewCursor = LoadCursor(cli.hInst, MAKEINTRESOURCE(IDC_DROPUSER));
+ break;
+ }
+ }
+ SetCursor(hNewCursor);
+ }
+ break;
+
+ case WM_LBUTTONUP:
+ if (dat->iDragItem == -1)
+ break;
+ SetCursor((HCURSOR) GetClassLongPtr(hwnd, GCLP_HCURSOR));
+ if (dat->exStyle & CLS_EX_TRACKSELECT) {
+ dat->iHotTrack = cli.pfnHitTest(hwnd, dat, (short) LOWORD(lParam), (short) HIWORD(lParam), NULL, NULL, NULL);
+ if (dat->iHotTrack == -1)
+ ReleaseCapture();
+ }
+ else ReleaseCapture();
+ KillTimer(hwnd, TIMERID_DRAGAUTOSCROLL);
+ if (dat->dragStage == (DRAGSTAGE_NOTMOVED | DRAGSTAGEF_MAYBERENAME))
+ SetTimer(hwnd, TIMERID_RENAME, GetDoubleClickTime(), NULL);
+ else if ((dat->dragStage & DRAGSTAGEM_STAGE) == DRAGSTAGE_ACTIVE) {
+ POINT pt;
+ int target;
+
+ pt.x = (short) LOWORD(lParam);
+ pt.y = (short) HIWORD(lParam);
+ target = cli.pfnGetDropTargetInformation(hwnd, dat, pt);
+ switch (target) {
+ case DROPTARGET_ONSELF:
+ break;
+ case DROPTARGET_ONCONTACT:
+ break;
+ case DROPTARGET_ONGROUP:
+ {
+ struct ClcContact *contactn, *contacto;
+ cli.pfnGetRowByIndex(dat, dat->selection, &contactn, NULL);
+ cli.pfnGetRowByIndex(dat, dat->iDragItem, &contacto, NULL);
+ if (contacto->type == CLCIT_CONTACT) //dropee is a contact
+ CallService(MS_CLIST_CONTACTCHANGEGROUP, (WPARAM)contacto->hContact, contactn->groupId);
+ else if (contacto->type == CLCIT_GROUP) { //dropee is a group
+ TCHAR szNewName[120];
+ TCHAR* szGroup = cli.pfnGetGroupName(contactn->groupId, NULL);
+ mir_sntprintf(szNewName, SIZEOF(szNewName), _T("%s\\%s"), szGroup, contacto->szText);
+ cli.pfnRenameGroup( contacto->groupId, szNewName );
+ }
+ break;
+ }
+ case DROPTARGET_INSERTION:
+ {
+ struct ClcContact *contact, *destcontact;
+ struct ClcGroup *destgroup;
+ cli.pfnGetRowByIndex(dat, dat->iDragItem, &contact, NULL);
+ if (cli.pfnGetRowByIndex(dat, dat->iInsertionMark, &destcontact, &destgroup) == -1 || destgroup != contact->group->parent)
+ CallService(MS_CLIST_GROUPMOVEBEFORE, contact->groupId, 0);
+ else {
+ if (destcontact->type == CLCIT_GROUP)
+ destgroup = destcontact->group;
+ else
+ destgroup = destgroup;
+ CallService(MS_CLIST_GROUPMOVEBEFORE, contact->groupId, destgroup->groupId);
+ }
+ break;
+ }
+ case DROPTARGET_OUTSIDE:
+ {
+ NMCLISTCONTROL nm;
+ struct ClcContact *contact;
+ cli.pfnGetRowByIndex(dat, dat->iDragItem, &contact, NULL);
+ nm.hdr.code = CLN_DROPPED;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.flags = 0;
+ nm.hItem = cli.pfnContactToItemHandle(contact, &nm.flags);
+ nm.pt = pt;
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nm);
+ break;
+ }
+ default:
+ {
+ struct ClcGroup *group;
+ struct ClcContact *contact;
+ cli.pfnGetRowByIndex(dat, dat->iDragItem, &contact, &group);
+ if (group->parent) { //move to root
+ if (contact->type == CLCIT_CONTACT) //dropee is a contact
+ CallService(MS_CLIST_CONTACTCHANGEGROUP, (WPARAM)contact->hContact, 0);
+ else if (contact->type == CLCIT_GROUP) { //dropee is a group
+ TCHAR szNewName[120];
+ lstrcpyn(szNewName, contact->szText, SIZEOF(szNewName));
+ cli.pfnRenameGroup( contact->groupId, szNewName );
+ } } } } }
+
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ dat->iDragItem = -1;
+ dat->iInsertionMark = -1;
+ break;
+
+ case WM_LBUTTONDBLCLK:
+ {
+ struct ClcContact *contact;
+ DWORD hitFlags;
+ ReleaseCapture();
+ dat->iHotTrack = -1;
+ cli.pfnHideInfoTip(hwnd, dat);
+ KillTimer(hwnd, TIMERID_RENAME);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ dat->szQuickSearch[0] = 0;
+ dat->selection = cli.pfnHitTest(hwnd, dat, (short) LOWORD(lParam), (short) HIWORD(lParam), &contact, NULL, &hitFlags);
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ if (dat->selection != -1)
+ cli.pfnEnsureVisible(hwnd, dat, dat->selection, 0);
+ if (!(hitFlags & (CLCHT_ONITEMICON | CLCHT_ONITEMLABEL)))
+ break;
+ UpdateWindow(hwnd);
+ cli.pfnDoSelectionDefaultAction(hwnd, dat);
+ break;
+ }
+ case WM_CONTEXTMENU:
+ {
+ struct ClcContact *contact;
+ HMENU hMenu = NULL;
+ POINT pt;
+ DWORD hitFlags;
+
+ cli.pfnEndRename(hwnd, dat, 1);
+ cli.pfnHideInfoTip(hwnd, dat);
+ KillTimer(hwnd, TIMERID_RENAME);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ if (GetFocus() != hwnd)
+ SetFocus(hwnd);
+ dat->iHotTrack = -1;
+ dat->szQuickSearch[0] = 0;
+ pt.x = (short) LOWORD(lParam);
+ pt.y = (short) HIWORD(lParam);
+ if (pt.x == -1 && pt.y == -1) {
+ dat->selection = cli.pfnGetRowByIndex(dat, dat->selection, &contact, NULL);
+ if (dat->selection != -1)
+ cli.pfnEnsureVisible(hwnd, dat, dat->selection, 0);
+ pt.x = dat->iconXSpace + 15;
+ pt.y = cli.pfnGetRowTopY(dat, dat->selection) - dat->yScroll + (int)(cli.pfnGetRowHeight(dat, dat->selection) * .7);
+ hitFlags = dat->selection == -1 ? CLCHT_NOWHERE : CLCHT_ONITEMLABEL;
+ }
+ else {
+ ScreenToClient(hwnd, &pt);
+ dat->selection = cli.pfnHitTest(hwnd, dat, pt.x, pt.y, &contact, NULL, &hitFlags);
+ }
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ if (dat->selection != -1)
+ cli.pfnEnsureVisible(hwnd, dat, dat->selection, 0);
+ UpdateWindow(hwnd);
+
+ if (dat->selection != -1 && hitFlags & (CLCHT_ONITEMICON | CLCHT_ONITEMCHECK | CLCHT_ONITEMLABEL)) {
+ if (contact->type == CLCIT_GROUP) {
+ hMenu = cli.pfnBuildGroupPopupMenu(contact->group);
+ ClientToScreen(hwnd, &pt);
+ TrackPopupMenu(hMenu, TPM_TOPALIGN | TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, 0, hwnd, NULL);
+ DestroyMenu(hMenu);
+ return 0;
+ }
+ else if (contact->type == CLCIT_CONTACT)
+ hMenu = (HMENU) CallService(MS_CLIST_MENUBUILDCONTACT, (WPARAM) contact->hContact, 0);
+ }
+ else {
+ //call parent for new group/hide offline menu
+ SendMessage(GetParent(hwnd), WM_CONTEXTMENU, wParam, lParam);
+ }
+ if (hMenu != NULL) {
+ ClientToScreen(hwnd, &pt);
+ TrackPopupMenu(hMenu, TPM_TOPALIGN | TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, 0, hwnd, NULL);
+ DestroyMenu(hMenu);
+ }
+ return 0;
+ }
+ case WM_MEASUREITEM:
+ return CallService(MS_CLIST_MENUMEASUREITEM, wParam, lParam);
+
+ case WM_DRAWITEM:
+ return CallService(MS_CLIST_MENUDRAWITEM, wParam, lParam);
+
+ case WM_COMMAND:
+ {
+ struct ClcContact *contact;
+ int hit = cli.pfnGetRowByIndex(dat, dat->selection, &contact, NULL);
+ if (hit == -1)
+ break;
+ if (contact->type == CLCIT_CONTACT)
+ if (CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(wParam), MPCF_CONTACTMENU), (LPARAM) contact->hContact))
+ break;
+ switch (LOWORD(wParam)) {
+ case POPUP_NEWSUBGROUP:
+ if (contact->type != CLCIT_GROUP)
+ break;
+ SetWindowLongPtr(hwnd, GWL_STYLE, GetWindowLongPtr(hwnd, GWL_STYLE) & ~CLS_HIDEEMPTYGROUPS);
+ CallService(MS_CLIST_GROUPCREATE, contact->groupId, 0);
+ break;
+ case POPUP_RENAMEGROUP:
+ cli.pfnBeginRenameSelection(hwnd, dat);
+ break;
+ case POPUP_DELETEGROUP:
+ if (contact->type != CLCIT_GROUP)
+ break;
+ CallService(MS_CLIST_GROUPDELETE, contact->groupId, 0);
+ break;
+ case POPUP_GROUPHIDEOFFLINE:
+ if (contact->type != CLCIT_GROUP)
+ break;
+ CallService(MS_CLIST_GROUPSETFLAGS, contact->groupId,
+ MAKELPARAM(contact->group->hideOffline ? 0 : GROUPF_HIDEOFFLINE, GROUPF_HIDEOFFLINE));
+ break;
+ }
+ break;
+ }
+ case WM_DESTROY:
+ cli.pfnHideInfoTip(hwnd, dat);
+ {
+ int i;
+ for (i = 0; i <= FONTID_MAX; i++)
+ if (!dat->fontInfo[i].changed)
+ DeleteObject(dat->fontInfo[i].hFont);
+ }
+ if (dat->himlHighlight)
+ ImageList_Destroy(dat->himlHighlight);
+ if (dat->hwndRenameEdit)
+ DestroyWindow(dat->hwndRenameEdit);
+ if (!dat->bkChanged && dat->hBmpBackground)
+ DeleteObject(dat->hBmpBackground);
+ cli.pfnFreeGroup(&dat->list);
+ mir_free(dat);
+ cli.pfnUnregisterFileDropping(hwnd);
+ WindowList_Remove(hClcWindowList, hwnd);
+ }
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+}
diff --git a/src/modules/clist/clc.h b/src/modules/clist/clc.h
new file mode 100644
index 0000000000..0bbf197b44
--- /dev/null
+++ b/src/modules/clist/clc.h
@@ -0,0 +1,248 @@
+/*
+
+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.
+*/
+
+struct ClcContact {
+ BYTE type;
+ BYTE flags;
+ union {
+ struct {
+ WORD iImage;
+ HANDLE hContact;
+ };
+ struct {
+ WORD groupId;
+ struct ClcGroup *group;
+ };
+ };
+ BYTE iExtraImage[MAXEXTRACOLUMNS];
+ TCHAR szText[120-MAXEXTRACOLUMNS];
+ char * proto; // MS_PROTO_GETBASEPROTO
+};
+
+struct ClcData {
+ struct ClcGroup list;
+ int rowHeight;
+ int yScroll;
+ int selection;
+ struct ClcFontInfo fontInfo[FONTID_MAX + 1];
+ int scrollTime;
+ HIMAGELIST himlHighlight;
+ int groupIndent;
+ TCHAR szQuickSearch[128];
+ int iconXSpace;
+ HWND hwndRenameEdit;
+ COLORREF bkColour, selBkColour, selTextColour, hotTextColour, quickSearchColour;
+ int iDragItem, iInsertionMark;
+ int dragStage;
+ POINT ptDragStart;
+ int dragAutoScrolling;
+ int dragAutoScrollHeight;
+ int leftMargin;
+ int insertionMarkHitHeight;
+ HBITMAP hBmpBackground;
+ int backgroundBmpUse, bkChanged;
+ int iHotTrack;
+ int gammaCorrection;
+ DWORD greyoutFlags; //see m_clc.h
+ DWORD offlineModes;
+ DWORD exStyle;
+ POINT ptInfoTip;
+ int infoTipTimeout;
+ HANDLE hInfoTipItem;
+ HIMAGELIST himlExtraColumns;
+ int extraColumnsCount;
+ int extraColumnSpacing;
+ int checkboxSize;
+ int showSelAlways;
+ int showIdle;
+ int noVScrollbar;
+ int useWindowsColours;
+ int needsResort;
+};
+
+/* clc.c */
+extern int g_IconWidth, g_IconHeight;
+
+void fnClcOptionsChanged( void );
+void fnClcBroadcast( int msg, WPARAM wParam, LPARAM lParam );
+HMENU fnBuildGroupPopupMenu( struct ClcGroup* group );
+
+LRESULT CALLBACK fnContactListControlWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+/* clcidents.c */
+int fnGetRowsPriorTo( struct ClcGroup *group, struct ClcGroup *subgroup, int contactIndex );
+int fnFindItem( HWND hwnd, struct ClcData *dat, HANDLE hItem, struct ClcContact **contact, struct ClcGroup **subgroup, int *isVisible );
+int fnGetRowByIndex( struct ClcData *dat, int testindex, struct ClcContact **contact, struct ClcGroup **subgroup );
+HANDLE fnContactToHItem( struct ClcContact* contact );
+HANDLE fnContactToItemHandle( struct ClcContact * contact, DWORD * nmFlags );
+
+/* clcitems.c */
+struct ClcGroup* fnAddGroup( HWND hwnd, struct ClcData *dat, const TCHAR *szName, DWORD flags, int groupId, int calcTotalMembers );
+struct ClcGroup* fnRemoveItemFromGroup(HWND hwnd, struct ClcGroup *group, struct ClcContact *contact, int updateTotalCount);
+
+void fnFreeContact( struct ClcContact *p );
+void fnFreeGroup( struct ClcGroup *group );
+int fnAddInfoItemToGroup(struct ClcGroup *group, int flags, const TCHAR *pszText);
+int fnAddItemToGroup( struct ClcGroup *group,int iAboveItem );
+void fnAddContactToTree( HWND hwnd, struct ClcData *dat, HANDLE hContact, int updateTotalCount, int checkHideOffline);
+int fnAddContactToGroup( struct ClcData *dat, struct ClcGroup *group, HANDLE hContact);
+void fnDeleteItemFromTree( HWND hwnd, HANDLE hItem );
+void fnRebuildEntireList( HWND hwnd, struct ClcData *dat );
+int fnGetGroupContentsCount( struct ClcGroup *group, int visibleOnly );
+void fnSortCLC( HWND hwnd, struct ClcData *dat, int useInsertionSort );
+void fnSaveStateAndRebuildList(HWND hwnd, struct ClcData *dat);
+
+/* clcmsgs.c */
+LRESULT fnProcessExternalMessages(HWND hwnd, struct ClcData *dat, UINT msg, WPARAM wParam, LPARAM lParam );
+
+/* clcutils.c */
+char* fnGetGroupCountsText(struct ClcData *dat, struct ClcContact *contact );
+int fnHitTest( HWND hwnd, struct ClcData *dat, int testx, int testy, struct ClcContact **contact, struct ClcGroup **group, DWORD * flags );
+void fnScrollTo( HWND hwnd, struct ClcData *dat, int desty, int noSmooth );
+void fnEnsureVisible(HWND hwnd, struct ClcData *dat, int iItem, int partialOk );
+void fnRecalcScrollBar( HWND hwnd, struct ClcData *dat );
+void fnSetGroupExpand( HWND hwnd, struct ClcData *dat, struct ClcGroup *group, int newState );
+void fnDoSelectionDefaultAction( HWND hwnd, struct ClcData *dat );
+int fnFindRowByText(HWND hwnd, struct ClcData *dat, const TCHAR *text, int prefixOk );
+void fnEndRename(HWND hwnd, struct ClcData *dat, int save );
+void fnDeleteFromContactList( HWND hwnd, struct ClcData *dat );
+void fnBeginRenameSelection( HWND hwnd, struct ClcData *dat );
+void fnCalcEipPosition( struct ClcData *dat, struct ClcContact *contact, struct ClcGroup *group, POINT *result);
+int fnGetDropTargetInformation( HWND hwnd, struct ClcData *dat, POINT pt );
+int fnClcStatusToPf2( int status );
+int fnIsHiddenMode( struct ClcData *dat, int status );
+void fnHideInfoTip( HWND hwnd, struct ClcData *dat );
+void fnNotifyNewContact( HWND hwnd, HANDLE hContact );
+DWORD fnGetDefaultExStyle( void );
+void fnGetSetting( int i, LOGFONT* lf, COLORREF* colour );
+void fnGetDefaultFontSetting(int i, LOGFONT* lf, COLORREF* colour);
+void fnGetFontSetting( int i, LOGFONT* lf, COLORREF* colour );
+void fnLoadClcOptions( HWND hwnd, struct ClcData *dat );
+void fnRecalculateGroupCheckboxes( HWND hwnd, struct ClcData *dat );
+void fnSetGroupChildCheckboxes( struct ClcGroup *group, int checked );
+void fnInvalidateItem( HWND hwnd, struct ClcData *dat, int iItem );
+
+int fnGetRowBottomY(struct ClcData *dat, int item);
+int fnGetRowHeight(struct ClcData *dat, int item);
+int fnGetRowTopY(struct ClcData *dat, int item);
+int fnGetRowTotalHeight(struct ClcData *dat);
+int fnRowHitTest(struct ClcData *dat, int y);
+
+/* clcopts.c */
+int ClcOptInit(WPARAM wParam,LPARAM lParam);
+DWORD GetDefaultExStyle(void);
+void GetFontSetting(int i,LOGFONTA *lf,COLORREF *colour);
+
+/* clistmenus.c */
+HGENMENU fnGetProtocolMenu( const char* );
+int fnGetProtocolVisibility( const char* accName );
+
+int fnGetAccountIndexByPos(int Pos);
+int fnGetProtoIndexByPos(PROTOCOLDESCRIPTOR ** proto, int protoCnt, int Pos);
+void RebuildMenuOrder( void );
+
+INT_PTR MenuProcessCommand(WPARAM wParam, LPARAM lParam);
+
+/* clistsettings.c */
+TCHAR* fnGetContactDisplayName( HANDLE hContact, int mode );
+void fnGetDefaultFontSetting( int i, LOGFONT* lf, COLORREF * colour);
+void fnInvalidateDisplayNameCacheEntry( HANDLE hContact );
+
+ClcCacheEntryBase* fnGetCacheEntry( HANDLE hContact );
+ClcCacheEntryBase* fnCreateCacheItem ( HANDLE hContact );
+void fnCheckCacheItem( ClcCacheEntryBase* p );
+void fnFreeCacheItem( ClcCacheEntryBase* p );
+
+/* clcfiledrop.c */
+void InitFileDropping(void);
+
+void fnRegisterFileDropping ( HWND hwnd );
+void fnUnregisterFileDropping ( HWND hwnd );
+
+/* clistevents.c */
+struct CListEvent* fnAddEvent( CLISTEVENT *cle );
+CLISTEVENT* fnGetEvent( HANDLE hContact, int idx );
+
+struct CListEvent* fnCreateEvent( void );
+void fnFreeEvent( struct CListEvent* p );
+
+int fnEventsProcessContactDoubleClick( HANDLE hContact );
+int fnEventsProcessTrayDoubleClick( int );
+int fnGetImlIconIndex(HICON hIcon);
+int fnRemoveEvent( HANDLE hContact, HANDLE dbEvent );
+
+/* clistmod.c */
+int fnIconFromStatusMode(const char *szProto, int status, HANDLE hContact);
+int fnShowHide( WPARAM wParam, LPARAM lParam );
+HICON fnGetIconFromStatusMode( HANDLE hContact, const char *szProto, int status );
+TCHAR* fnGetStatusModeDescription( int wParam, int lParam);
+int fnGetWindowVisibleState(HWND hWnd, int iStepX, int iStepY);
+
+/* clisttray.c */
+void fnInitTray( void );
+void fnUninitTray( void );
+void fnLockTray( void );
+void fnUnlockTray( void );
+int fnCListTrayNotify(MIRANDASYSTRAYNOTIFY *msn);
+int fnTrayIconAdd(HWND hwnd, const char *szProto, const char *szIconProto, int status);
+int fnTrayIconDestroy( HWND hwnd );
+void fnTrayIconIconsChanged ( void );
+int fnTrayIconInit( HWND hwnd );
+TCHAR* fnTrayIconMakeTooltip( const TCHAR *szPrefix, const char *szProto );
+int fnTrayIconPauseAutoHide ( WPARAM wParam, LPARAM lParam );
+INT_PTR fnTrayIconProcessMessage ( WPARAM wParam, LPARAM lParam );
+void fnTrayIconRemove(HWND hwnd, const char *szProto);
+int fnTrayIconSetBaseInfo(HICON hIcon, const char *szPreferredProto);
+void fnTrayIconSetToBase ( char *szPreferredProto );
+void fnTrayIconTaskbarCreated( HWND hwnd );
+int fnTrayIconUpdate( HICON hNewIcon, const TCHAR *szNewTip, const char *szPreferredProto, int isBase );
+void fnTrayIconUpdateBase ( const char *szChangedProto );
+void fnTrayIconUpdateWithImageList ( int iImage, const TCHAR *szNewTip, char *szPreferredProto );
+
+VOID CALLBACK fnTrayCycleTimerProc(HWND hwnd, UINT message, UINT_PTR idEvent, DWORD dwTime);
+
+/* clui.c */
+LRESULT CALLBACK fnContactListWndProc ( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
+void fnLoadCluiGlobalOpts( void );
+void fnCluiProtocolStatusChanged(int,const char*);
+void fnDrawMenuItem(DRAWITEMSTRUCT *dis, HICON hIcon, HICON eventIcon);
+
+/* contact.c */
+void fnChangeContactIcon ( HANDLE hContact, int iIcon, int add );
+void fnLoadContactTree ( void );
+int fnCompareContacts ( const struct ClcContact *contact1, const struct ClcContact *contact2);
+void fnSortContacts ( void );
+int fnSetHideOffline ( WPARAM wParam, LPARAM lParam );
+
+/* docking.c */
+int fnDocking_ProcessWindowMessage ( WPARAM wParam, LPARAM lParam );
+
+/* group.c */
+TCHAR* fnGetGroupName ( int idx, DWORD* pdwFlags );
+int fnRenameGroup ( int groupID, TCHAR* newName );
+
+/* keyboard.c */
+int fnHotKeysRegister ( HWND hwnd );
+void fnHotKeysUnregister ( HWND hwnd );
+int fnHotKeysProcess ( HWND hwnd, WPARAM wParam, LPARAM lParam );
+int fnHotkeysProcessMessage ( WPARAM wParam, LPARAM lParam );
diff --git a/src/modules/clist/clcfiledrop.cpp b/src/modules/clist/clcfiledrop.cpp
new file mode 100644
index 0000000000..aae299d7b8
--- /dev/null
+++ b/src/modules/clist/clcfiledrop.cpp
@@ -0,0 +1,278 @@
+/*
+
+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 "clc.h"
+#include <shlobj.h>
+
+struct CDropTarget : IDropTarget
+{
+ LONG refCount;
+ IDropTargetHelper *pDropTargetHelper;
+
+ ULONG STDMETHODCALLTYPE AddRef(void);
+ ULONG STDMETHODCALLTYPE Release(void);
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void ** ppvObject);
+
+ HRESULT STDMETHODCALLTYPE DragEnter(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
+ HRESULT STDMETHODCALLTYPE DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
+ HRESULT STDMETHODCALLTYPE DragLeave(void);
+ HRESULT STDMETHODCALLTYPE Drop(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
+}
+static dropTarget;
+
+static HWND hwndCurrentDrag = NULL;
+static int originalSelection;
+
+HRESULT CDropTarget::QueryInterface(REFIID riid, LPVOID * ppvObj)
+{
+ if (riid == IID_IDropTarget) {
+ *ppvObj = this;
+ AddRef();
+ return S_OK;
+ }
+ *ppvObj = NULL;
+ return E_NOINTERFACE;
+}
+
+ULONG CDropTarget::AddRef(void)
+{
+ return InterlockedIncrement(&refCount);
+}
+
+ULONG CDropTarget::Release(void)
+{
+ if (refCount == 1) {
+ if (pDropTargetHelper)
+ pDropTargetHelper->Release();
+ }
+ return InterlockedDecrement(&refCount);
+}
+
+static HANDLE HContactFromPoint(HWND hwnd, struct ClcData *dat, int x, int y, int *hitLine)
+{
+ int hit;
+ struct ClcContact *contact;
+ DWORD hitFlags;
+ char *szProto;
+ DWORD protoCaps;
+
+ hit = cli.pfnHitTest(hwnd, dat, x, y, &contact, NULL, &hitFlags);
+ if (hit == -1 || !(hitFlags & (CLCHT_ONITEMLABEL | CLCHT_ONITEMICON)) || contact->type != CLCIT_CONTACT)
+ return NULL;
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) contact->hContact, 0);
+ if (szProto == NULL)
+ return NULL;
+ protoCaps = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0);
+ if (!(protoCaps & PF1_FILESEND))
+ return NULL;
+ if (ID_STATUS_OFFLINE == DBGetContactSettingWord(contact->hContact, szProto, "Status", ID_STATUS_OFFLINE))
+ return NULL;
+ if (hitLine)
+ *hitLine = hit;
+ return contact->hContact;
+}
+
+HRESULT CDropTarget::DragOver(DWORD /*grfKeyState*/, POINTL pt, DWORD * pdwEffect)
+{
+ POINT shortPt;
+ struct ClcData *dat;
+ RECT clRect;
+ int hit;
+ HANDLE hContact;
+
+ if (pDropTargetHelper && hwndCurrentDrag)
+ pDropTargetHelper->DragOver((POINT*)&pt, *pdwEffect);
+
+ *pdwEffect = 0;
+ if (hwndCurrentDrag == NULL) {
+ *pdwEffect = DROPEFFECT_NONE;
+ return S_OK;
+ }
+ CallService(MS_CLIST_PAUSEAUTOHIDE, 0, 0);
+ dat = (struct ClcData *) GetWindowLongPtr(hwndCurrentDrag, 0);
+ shortPt.x = pt.x;
+ shortPt.y = pt.y;
+ ScreenToClient(hwndCurrentDrag, &shortPt);
+ GetClientRect(hwndCurrentDrag, &clRect);
+
+ if (shortPt.y < dat->dragAutoScrollHeight || shortPt.y >= clRect.bottom - dat->dragAutoScrollHeight) {
+ *pdwEffect |= DROPEFFECT_SCROLL;
+ cli.pfnScrollTo(hwndCurrentDrag, dat, dat->yScroll + (shortPt.y < dat->dragAutoScrollHeight ? -1 : 1) * dat->rowHeight * 2, 0);
+ }
+ hContact = HContactFromPoint(hwndCurrentDrag, dat, shortPt.x, shortPt.y, &hit);
+ if (hContact == NULL) {
+ hit = -1;
+ *pdwEffect |= DROPEFFECT_NONE;
+ }
+ else
+ *pdwEffect |= DROPEFFECT_COPY;
+
+ if (dat->selection != hit) {
+ dat->selection = hit;
+ cli.pfnInvalidateRect(hwndCurrentDrag, NULL, FALSE);
+ if (pDropTargetHelper) pDropTargetHelper->Show(FALSE);
+ UpdateWindow(hwndCurrentDrag);
+ if (pDropTargetHelper) pDropTargetHelper->Show(TRUE);
+ }
+
+ return S_OK;
+}
+
+HRESULT CDropTarget::DragEnter(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
+{
+ HWND hwnd;
+ TCHAR szWindowClass[64];
+ POINT shortPt;
+
+ shortPt.x = pt.x;
+ shortPt.y = pt.y;
+ hwnd = WindowFromPoint(shortPt);
+ GetClassName(hwnd, szWindowClass, SIZEOF(szWindowClass));
+ if (!lstrcmp(szWindowClass, CLISTCONTROL_CLASS)) {
+ struct ClcData *dat;
+ hwndCurrentDrag = hwnd;
+ dat = (struct ClcData *) GetWindowLongPtr(hwndCurrentDrag, 0);
+ originalSelection = dat->selection;
+ dat->showSelAlways = 1;
+ }
+ if (pDropTargetHelper && hwndCurrentDrag)
+ pDropTargetHelper->DragEnter(hwndCurrentDrag, pDataObj, (POINT*)&pt, *pdwEffect);
+ return DragOver(grfKeyState, pt, pdwEffect);
+}
+
+HRESULT CDropTarget::DragLeave(void)
+{
+ if (hwndCurrentDrag) {
+ struct ClcData *dat;
+ if (pDropTargetHelper)
+ pDropTargetHelper->DragLeave();
+ dat = (struct ClcData *) GetWindowLongPtr(hwndCurrentDrag, 0);
+ dat->showSelAlways = 0;
+ dat->selection = originalSelection;
+ cli.pfnInvalidateRect(hwndCurrentDrag, NULL, FALSE);
+ }
+ hwndCurrentDrag = NULL;
+ return S_OK;
+}
+
+static void AddToFileList(TCHAR ***pppFiles, int *totalCount, const TCHAR *szFilename)
+{
+ *pppFiles = (TCHAR **) mir_realloc(*pppFiles, (++*totalCount + 1) * sizeof(TCHAR *));
+ (*pppFiles)[*totalCount] = NULL;
+ (*pppFiles)[*totalCount - 1] = mir_tstrdup(szFilename);
+ if (GetFileAttributes(szFilename) & FILE_ATTRIBUTE_DIRECTORY) {
+ WIN32_FIND_DATA fd;
+ HANDLE hFind;
+ TCHAR szPath[MAX_PATH];
+ lstrcpy(szPath, szFilename);
+ lstrcat(szPath, _T("\\*"));
+ if (hFind = FindFirstFile(szPath, &fd)) {
+ do {
+ if (!lstrcmp(fd.cFileName, _T(".")) || !lstrcmp(fd.cFileName, _T("..")))
+ continue;
+ lstrcpy(szPath, szFilename);
+ lstrcat(szPath, _T("\\"));
+ lstrcat(szPath, fd.cFileName);
+ AddToFileList(pppFiles, totalCount, szPath);
+ } while (FindNextFile(hFind, &fd));
+ FindClose(hFind);
+ }
+ }
+}
+
+HRESULT CDropTarget::Drop(IDataObject * pDataObj, DWORD /*fKeyState*/, POINTL pt, DWORD * pdwEffect)
+{
+ FORMATETC fe = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
+ STGMEDIUM stg;
+ HDROP hDrop;
+ POINT shortPt;
+ struct ClcData *dat;
+ HANDLE hContact;
+
+ if (pDropTargetHelper && hwndCurrentDrag)
+ pDropTargetHelper->Drop(pDataObj, (POINT*)&pt, *pdwEffect);
+
+ *pdwEffect = DROPEFFECT_NONE;
+ if (hwndCurrentDrag == NULL || S_OK != pDataObj->GetData(&fe, &stg))
+ return S_OK;
+ hDrop = (HDROP) stg.hGlobal;
+ dat = (struct ClcData *) GetWindowLongPtr(hwndCurrentDrag, 0);
+
+ shortPt.x = pt.x;
+ shortPt.y = pt.y;
+ ScreenToClient(hwndCurrentDrag, &shortPt);
+ hContact = HContactFromPoint(hwndCurrentDrag, dat, shortPt.x, shortPt.y, NULL);
+ if (hContact != NULL) {
+ TCHAR **ppFiles = NULL;
+ TCHAR szFilename[MAX_PATH];
+ int fileCount, totalCount = 0, i;
+
+ fileCount = DragQueryFile(hDrop, -1, NULL, 0);
+ ppFiles = NULL;
+ for (i = 0; i < fileCount; i++) {
+ DragQueryFile(hDrop, i, szFilename, SIZEOF(szFilename));
+ AddToFileList(&ppFiles, &totalCount, szFilename);
+ }
+
+ if (!CallService(MS_FILE_SENDSPECIFICFILEST, (WPARAM) hContact, (LPARAM) ppFiles))
+ *pdwEffect = DROPEFFECT_COPY;
+
+ for (i = 0; ppFiles[i]; i++)
+ mir_free(ppFiles[i]);
+ mir_free(ppFiles);
+ }
+
+ if (stg.pUnkForRelease)
+ stg.pUnkForRelease->Release();
+ else
+ GlobalFree(stg.hGlobal);
+
+ DragLeave();
+ return S_OK;
+}
+
+static VOID CALLBACK CreateDropTargetHelperTimerProc(HWND hwnd, UINT, UINT_PTR idEvent, DWORD)
+{
+ KillTimer(hwnd, idEvent);
+ //This is a ludicrously slow function (~200ms) so we delay load it a bit.
+ if (S_OK != CoCreateInstance(CLSID_DragDropHelper, NULL, CLSCTX_INPROC_SERVER,
+ IID_IDropTargetHelper, (LPVOID*)&dropTarget.pDropTargetHelper))
+ dropTarget.pDropTargetHelper = NULL;
+}
+
+void InitFileDropping(void)
+{
+ // Disabled as this function loads tons of dlls for no apparenet reason
+ // we will se what the reaction will be
+// SetTimer(NULL, 1, 1000, CreateDropTargetHelperTimerProc);
+}
+
+void fnRegisterFileDropping(HWND hwnd)
+{
+ RegisterDragDrop(hwnd, (IDropTarget *) & dropTarget);
+}
+
+void fnUnregisterFileDropping(HWND hwnd)
+{
+ RevokeDragDrop(hwnd);
+}
diff --git a/src/modules/clist/clcidents.cpp b/src/modules/clist/clcidents.cpp
new file mode 100644
index 0000000000..7cb18760fe
--- /dev/null
+++ b/src/modules/clist/clcidents.cpp
@@ -0,0 +1,201 @@
+/*
+
+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 "clc.h"
+
+/* the CLC uses 3 different ways to identify elements in its list, this file
+contains routines to convert between them.
+
+1) struct ClcContact/struct ClcGroup pair. Only ever used within the duration
+ of a single operation, but used at some point in nearly everything
+2) index integer. The 0-based number of the item from the top. Only visible
+ items are counted (ie not closed groups). Used for saving selection and drag
+ highlight
+3) hItem handle. Either the hContact or (hGroup|HCONTACT_ISGROUP). Used
+ exclusively externally
+
+1->2: GetRowsPriorTo()
+1->3: ContactToHItem()
+3->1: FindItem()
+2->1: GetRowByIndex()
+*/
+
+int fnGetRowsPriorTo(struct ClcGroup *group, struct ClcGroup *subgroup, int contactIndex)
+{
+ int count = 0;
+
+ group->scanIndex = 0;
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ group = group->parent;
+ if (group == NULL)
+ break;
+ group->scanIndex++;
+ continue;
+ }
+ if (group == subgroup && contactIndex == group->scanIndex)
+ return count;
+ count++;
+ if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
+ if (group->cl.items[group->scanIndex]->group == subgroup && contactIndex == -1)
+ return count - 1;
+ if (group->cl.items[group->scanIndex]->group->expanded) {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+ continue;
+ }
+ }
+ group->scanIndex++;
+ }
+ return -1;
+}
+
+int fnFindItem(HWND hwnd, struct ClcData *dat, HANDLE hItem, struct ClcContact **contact, struct ClcGroup **subgroup, int *isVisible)
+{
+ int index = 0;
+ int nowVisible = 1;
+ struct ClcGroup *group = &dat->list;
+
+ group->scanIndex = 0;
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ struct ClcGroup *tgroup;
+ group = group->parent;
+ if (group == NULL)
+ break;
+ nowVisible = 1;
+ for (tgroup = group; tgroup; tgroup = tgroup->parent)
+ if (!group->expanded) {
+ nowVisible = 0;
+ break;
+ }
+ group->scanIndex++;
+ continue;
+ }
+ if (nowVisible)
+ index++;
+ if ((IsHContactGroup(hItem) && group->cl.items[group->scanIndex]->type == CLCIT_GROUP
+ && ((unsigned) hItem & ~HCONTACT_ISGROUP) == group->cl.items[group->scanIndex]->groupId) || (IsHContactContact(hItem)
+ && group->cl.items[group->scanIndex]->type == CLCIT_CONTACT
+ && group->cl.items[group->scanIndex]->hContact == hItem) || (IsHContactInfo(hItem)
+ && group->cl.items[group->scanIndex]->type == CLCIT_INFO
+ && group->cl.items[group->scanIndex]->hContact == (HANDLE) ((UINT_PTR)hItem & ~HCONTACT_ISINFO)))
+ {
+ if (isVisible) {
+ if (!nowVisible)
+ *isVisible = 0;
+ else {
+ int posY = cli.pfnGetRowTopY(dat, index+1);
+ if (posY < dat->yScroll)
+ *isVisible = 0;
+ else {
+ RECT clRect;
+ GetClientRect(hwnd, &clRect);
+ if (posY >= dat->yScroll + clRect.bottom)
+ *isVisible = 0;
+ else
+ *isVisible = 1;
+ }
+ }
+ }
+ if (contact)
+ *contact = group->cl.items[group->scanIndex];
+ if (subgroup)
+ *subgroup = group;
+ return 1;
+ }
+ if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+ nowVisible &= group->expanded;
+ continue;
+ }
+ group->scanIndex++;
+ }
+ return 0;
+}
+
+int fnGetRowByIndex(struct ClcData *dat, int testindex, struct ClcContact **contact, struct ClcGroup **subgroup)
+{
+ int index = 0;
+ struct ClcGroup *group = &dat->list;
+
+ if (testindex<0)
+ return (-1);
+
+ group->scanIndex = 0;
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ group = group->parent;
+ if (group == NULL)
+ break;
+ group->scanIndex++;
+ continue;
+ }
+ if (testindex == index) {
+ if (contact)
+ *contact = group->cl.items[group->scanIndex];
+ if (subgroup)
+ *subgroup = group;
+ return index;
+ }
+ index++;
+ if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP && group->cl.items[group->scanIndex]->group->expanded) {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+ continue;
+ }
+ group->scanIndex++;
+ }
+ return -1;
+}
+
+HANDLE fnContactToHItem(struct ClcContact * contact)
+{
+ switch (contact->type) {
+ case CLCIT_CONTACT:
+ return contact->hContact;
+ case CLCIT_GROUP:
+ return (HANDLE) (contact->groupId | HCONTACT_ISGROUP);
+ case CLCIT_INFO:
+ return (HANDLE) ((UINT_PTR) contact->hContact | HCONTACT_ISINFO);
+ }
+ return NULL;
+}
+
+HANDLE fnContactToItemHandle(struct ClcContact * contact, DWORD * nmFlags)
+{
+ switch (contact->type) {
+ case CLCIT_CONTACT:
+ return contact->hContact;
+ case CLCIT_GROUP:
+ if (nmFlags)
+ *nmFlags |= CLNF_ISGROUP;
+ return (HANDLE) contact->groupId;
+ case CLCIT_INFO:
+ if (nmFlags)
+ *nmFlags |= CLNF_ISINFO;
+ return (HANDLE) ((UINT_PTR) contact->hContact | HCONTACT_ISINFO);
+ }
+ return NULL;
+}
diff --git a/src/modules/clist/clcitems.cpp b/src/modules/clist/clcitems.cpp
new file mode 100644
index 0000000000..cc338d5ec9
--- /dev/null
+++ b/src/modules/clist/clcitems.cpp
@@ -0,0 +1,707 @@
+/*
+
+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 "clc.h"
+
+//routines for managing adding/removal of items in the list, including sorting
+
+int fnAddItemToGroup(struct ClcGroup *group, int iAboveItem)
+{
+ struct ClcContact* newItem = cli.pfnCreateClcContact();
+ newItem->type = CLCIT_DIVIDER;
+ newItem->flags = 0;
+ newItem->szText[0] = '\0';
+ memset( newItem->iExtraImage, 0xFF, SIZEOF(newItem->iExtraImage));
+
+ List_Insert(( SortedList* )&group->cl, newItem, iAboveItem );
+ return iAboveItem;
+}
+
+struct ClcGroup* fnAddGroup(HWND hwnd, struct ClcData *dat, const TCHAR *szName, DWORD flags, int groupId, int calcTotalMembers)
+{
+ TCHAR *pBackslash, *pNextField, szThisField[ SIZEOF(dat->list.cl.items[0]->szText) ];
+ struct ClcGroup *group = &dat->list;
+ int i, compareResult;
+
+ dat->needsResort = 1;
+ if (!(GetWindowLongPtr(hwnd, GWL_STYLE) & CLS_USEGROUPS))
+ return &dat->list;
+
+ pNextField = ( TCHAR* )szName;
+ do {
+ pBackslash = _tcschr(pNextField, '\\');
+ if (pBackslash == NULL) {
+ lstrcpyn(szThisField, pNextField, SIZEOF(szThisField));
+ pNextField = NULL;
+ }
+ else {
+ lstrcpyn(szThisField, pNextField, min( SIZEOF(szThisField), pBackslash - pNextField + 1 ));
+ pNextField = pBackslash + 1;
+ }
+ compareResult = 1;
+ for (i = 0; i < group->cl.count; i++) {
+ if (group->cl.items[i]->type == CLCIT_CONTACT)
+ break;
+ if (group->cl.items[i]->type != CLCIT_GROUP)
+ continue;
+ compareResult = lstrcmp(szThisField, group->cl.items[i]->szText);
+ if (compareResult == 0) {
+ if (pNextField == NULL && flags != (DWORD) - 1) {
+ group->cl.items[i]->groupId = (WORD) groupId;
+ group = group->cl.items[i]->group;
+ group->expanded = (flags & GROUPF_EXPANDED) != 0;
+ group->hideOffline = (flags & GROUPF_HIDEOFFLINE) != 0;
+ group->groupId = groupId;
+ }
+ else
+ group = group->cl.items[i]->group;
+ break;
+ }
+ if (pNextField == NULL && group->cl.items[i]->groupId == 0)
+ break;
+ if (!(dat->exStyle & CLS_EX_SORTGROUPSALPHA) && groupId && group->cl.items[i]->groupId > groupId)
+ break;
+ }
+ if (compareResult) {
+ if (groupId == 0)
+ return NULL;
+ i = cli.pfnAddItemToGroup(group, i);
+ group->cl.items[i]->type = CLCIT_GROUP;
+ lstrcpyn(group->cl.items[i]->szText, szThisField, SIZEOF( group->cl.items[i]->szText ));
+ group->cl.items[i]->groupId = (WORD) (pNextField ? 0 : groupId);
+ group->cl.items[i]->group = (struct ClcGroup *) mir_alloc(sizeof(struct ClcGroup));
+ group->cl.items[i]->group->parent = group;
+ group = group->cl.items[i]->group;
+ memset( &group->cl, 0, sizeof( group->cl ));
+ group->cl.increment = 10;
+ if (flags == (DWORD) - 1 || pNextField != NULL) {
+ group->expanded = 0;
+ group->hideOffline = 0;
+ }
+ else {
+ group->expanded = (flags & GROUPF_EXPANDED) != 0;
+ group->hideOffline = (flags & GROUPF_HIDEOFFLINE) != 0;
+ }
+ group->groupId = pNextField ? 0 : groupId;
+ group->totalMembers = 0;
+ if (flags != (DWORD) - 1 && pNextField == NULL && calcTotalMembers) {
+ DWORD style = GetWindowLongPtr(hwnd, GWL_STYLE);
+ HANDLE hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while (hContact) {
+ ClcCacheEntryBase* cache = cli.pfnGetCacheEntry( hContact );
+ if ( !lstrcmp( cache->group, szName) && (style & CLS_SHOWHIDDEN || !cache->isHidden ))
+ group->totalMembers++;
+
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0);
+ }
+ }
+ }
+ } while (pNextField);
+ return group;
+}
+
+void fnFreeContact(struct ClcContact* p)
+{
+ if (p->type == CLCIT_GROUP) {
+ cli.pfnFreeGroup(p->group);
+ mir_free(p->group);
+} }
+
+void fnFreeGroup(struct ClcGroup *group)
+{
+ int i;
+ for (i = 0; i < group->cl.count; i++) {
+ cli.pfnFreeContact(group->cl.items[i]);
+ mir_free(group->cl.items[i]);
+ }
+ if (group->cl.items)
+ mir_free(group->cl.items);
+ group->cl.limit = group->cl.count = 0;
+ group->cl.items = NULL;
+}
+
+static int iInfoItemUniqueHandle = 0;
+int fnAddInfoItemToGroup(struct ClcGroup *group, int flags, const TCHAR *pszText)
+{
+ int i = 0;
+
+ if (flags & CLCIIF_BELOWCONTACTS)
+ i = group->cl.count;
+ else if (flags & CLCIIF_BELOWGROUPS) {
+ for (; i < group->cl.count; i++)
+ if (group->cl.items[i]->type == CLCIT_CONTACT)
+ break;
+ }
+ else
+ for (; i < group->cl.count; i++)
+ if (group->cl.items[i]->type != CLCIT_INFO)
+ break;
+ i = cli.pfnAddItemToGroup(group, i);
+ iInfoItemUniqueHandle = (iInfoItemUniqueHandle + 1) & 0xFFFF;
+ if (iInfoItemUniqueHandle == 0)
+ ++iInfoItemUniqueHandle;
+ group->cl.items[i]->type = CLCIT_INFO;
+ group->cl.items[i]->flags = (BYTE) flags;
+ group->cl.items[i]->hContact = (HANDLE)++ iInfoItemUniqueHandle;
+ lstrcpyn(group->cl.items[i]->szText, pszText, SIZEOF( group->cl.items[i]->szText ));
+ return i;
+}
+
+int fnAddContactToGroup(struct ClcData *dat, struct ClcGroup *group, HANDLE hContact)
+{
+ char *szProto;
+ WORD apparentMode;
+ DWORD idleMode;
+
+ int i, index = -1;
+
+ dat->needsResort = 1;
+ for (i = group->cl.count - 1; i >= 0; i--) {
+ if (group->cl.items[i]->hContact == hContact )
+ return i;
+
+ if ( index == -1 )
+ if (group->cl.items[i]->type != CLCIT_INFO || !(group->cl.items[i]->flags & CLCIIF_BELOWCONTACTS))
+ index = i;
+ }
+
+ i = cli.pfnAddItemToGroup(group, index + 1);
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+ group->cl.items[i]->type = CLCIT_CONTACT;
+ group->cl.items[i]->iImage = CallService(MS_CLIST_GETCONTACTICON, (WPARAM) hContact, 0);
+ group->cl.items[i]->hContact = hContact;
+ group->cl.items[i]->proto = szProto;
+ if (szProto != NULL && !cli.pfnIsHiddenMode(dat, DBGetContactSettingWord(hContact, szProto, "Status", ID_STATUS_OFFLINE)))
+ group->cl.items[i]->flags |= CONTACTF_ONLINE;
+ apparentMode = szProto != NULL ? DBGetContactSettingWord(hContact, szProto, "ApparentMode", 0) : 0;
+ if (apparentMode == ID_STATUS_OFFLINE)
+ group->cl.items[i]->flags |= CONTACTF_INVISTO;
+ else if (apparentMode == ID_STATUS_ONLINE)
+ group->cl.items[i]->flags |= CONTACTF_VISTO;
+ else if (apparentMode)
+ group->cl.items[i]->flags |= CONTACTF_VISTO | CONTACTF_INVISTO;
+ if (DBGetContactSettingByte(hContact, "CList", "NotOnList", 0))
+ group->cl.items[i]->flags |= CONTACTF_NOTONLIST;
+ idleMode = szProto != NULL ? DBGetContactSettingDword(hContact, szProto, "IdleTS", 0) : 0;
+ if (idleMode)
+ group->cl.items[i]->flags |= CONTACTF_IDLE;
+ lstrcpyn(group->cl.items[i]->szText, cli.pfnGetContactDisplayName(hContact,0), SIZEOF(group->cl.items[i]->szText));
+
+ { ClcCacheEntryBase* p = cli.pfnGetCacheEntry(hContact);
+ if ( p != NULL ) {
+ if ( p->group ) mir_free( p->group );
+ p->group = NULL;
+ } }
+
+ return i;
+}
+
+void fnAddContactToTree(HWND hwnd, struct ClcData *dat, HANDLE hContact, int updateTotalCount, int checkHideOffline)
+{
+ struct ClcGroup *group;
+ DBVARIANT dbv;
+ DWORD style = GetWindowLongPtr(hwnd, GWL_STYLE);
+ WORD status = ID_STATUS_OFFLINE;
+ char *szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+
+ dat->needsResort = 1;
+ if (style & CLS_NOHIDEOFFLINE)
+ checkHideOffline = 0;
+ if (checkHideOffline)
+ if (szProto != NULL)
+ status = DBGetContactSettingWord(hContact, szProto, "Status", ID_STATUS_OFFLINE);
+
+ if ( DBGetContactSettingTString(hContact, "CList", "Group", &dbv))
+ group = &dat->list;
+ else {
+ group = cli.pfnAddGroup(hwnd, dat, dbv.ptszVal, (DWORD) - 1, 0, 0);
+ if (group == NULL) {
+ int i, len;
+ DWORD groupFlags;
+ TCHAR *szGroupName;
+ if (!(style & CLS_HIDEEMPTYGROUPS)) {
+ mir_free(dbv.ptszVal);
+ return;
+ }
+ if (checkHideOffline && cli.pfnIsHiddenMode(dat, status)) {
+ for (i = 1;; i++) {
+ szGroupName = cli.pfnGetGroupName(i, &groupFlags);
+ if (szGroupName == NULL) {
+ mir_free(dbv.ptszVal);
+ return;
+ } //never happens
+ if (!lstrcmp(szGroupName, dbv.ptszVal))
+ break;
+ }
+ if (groupFlags & GROUPF_HIDEOFFLINE) {
+ mir_free(dbv.ptszVal);
+ return;
+ }
+ }
+ for (i = 1;; i++) {
+ szGroupName = cli.pfnGetGroupName(i, &groupFlags);
+ if (szGroupName == NULL) {
+ mir_free(dbv.ptszVal);
+ return;
+ } //never happens
+ if (!lstrcmp(szGroupName, dbv.ptszVal))
+ break;
+ len = lstrlen(szGroupName);
+ if (!_tcsncmp(szGroupName, dbv.ptszVal, len) && dbv.ptszVal[len] == '\\')
+ cli.pfnAddGroup(hwnd, dat, szGroupName, groupFlags, i, 1);
+ }
+ group = cli.pfnAddGroup(hwnd, dat, dbv.ptszVal, groupFlags, i, 1);
+ }
+ mir_free(dbv.ptszVal);
+ }
+ if (checkHideOffline) {
+ if (cli.pfnIsHiddenMode(dat, status) && (style & CLS_HIDEOFFLINE || group->hideOffline)) {
+ if (updateTotalCount)
+ group->totalMembers++;
+ return;
+ }
+ }
+ cli.pfnAddContactToGroup(dat, group, hContact);
+ if (updateTotalCount)
+ group->totalMembers++;
+}
+
+struct ClcGroup* fnRemoveItemFromGroup(HWND hwnd, struct ClcGroup *group, struct ClcContact *contact, int updateTotalCount)
+{
+ int iContact;
+ if (( iContact = List_IndexOf(( SortedList* )&group->cl, contact )) == -1 )
+ return group;
+
+ if (updateTotalCount && contact->type == CLCIT_CONTACT)
+ group->totalMembers--;
+
+ { ClcCacheEntryBase* p = cli.pfnGetCacheEntry(contact->hContact);
+ if ( p != NULL ) {
+ if ( p->group ) mir_free( p->group );
+ p->group = NULL;
+ } }
+
+ cli.pfnFreeContact( group->cl.items[iContact] );
+ mir_free( group->cl.items[iContact] );
+ List_Remove(( SortedList* )&group->cl, iContact );
+
+ if ((GetWindowLongPtr(hwnd, GWL_STYLE) & CLS_HIDEEMPTYGROUPS) && group->cl.count == 0) {
+ int i;
+ if (group->parent == NULL)
+ return group;
+ for (i = 0; i < group->parent->cl.count; i++)
+ if (group->parent->cl.items[i]->type == CLCIT_GROUP && group->parent->cl.items[i]->groupId == group->groupId)
+ break;
+ if (i == group->parent->cl.count)
+ return group; //never happens
+ return cli.pfnRemoveItemFromGroup(hwnd, group->parent, group->parent->cl.items[i], 0);
+ }
+ return group;
+}
+
+void fnDeleteItemFromTree(HWND hwnd, HANDLE hItem)
+{
+ struct ClcContact *contact;
+ struct ClcGroup *group;
+ struct ClcData *dat = (struct ClcData *) GetWindowLongPtr(hwnd, 0);
+
+ dat->needsResort = 1;
+ if (!cli.pfnFindItem(hwnd, dat, hItem, &contact, &group, NULL)) {
+ DBVARIANT dbv;
+ int i, nameOffset;
+ if (!IsHContactContact(hItem))
+ return;
+ if (DBGetContactSettingTString(hItem, "CList", "Group", &dbv))
+ return;
+
+ //decrease member counts of all parent groups too
+ group = &dat->list;
+ nameOffset = 0;
+ for (i = 0;; i++) {
+ if (group->scanIndex == group->cl.count)
+ break;
+ if (group->cl.items[i]->type == CLCIT_GROUP) {
+ int len = lstrlen(group->cl.items[i]->szText);
+ if (!_tcsncmp(group->cl.items[i]->szText, dbv.ptszVal + nameOffset, len) &&
+ (dbv.ptszVal[nameOffset + len] == '\\' || dbv.ptszVal[nameOffset + len] == '\0')) {
+ group->totalMembers--;
+ if (dbv.ptszVal[nameOffset + len] == '\0')
+ break;
+ }
+ }
+ }
+ mir_free(dbv.ptszVal);
+ }
+ else
+ cli.pfnRemoveItemFromGroup(hwnd, group, contact, 1);
+}
+
+void fnRebuildEntireList(HWND hwnd, struct ClcData *dat)
+{
+ char *szProto;
+ DWORD style = GetWindowLongPtr(hwnd, GWL_STYLE);
+ HANDLE hContact;
+ struct ClcGroup *group;
+ DBVARIANT dbv;
+
+ dat->list.expanded = 1;
+ dat->list.hideOffline = DBGetContactSettingByte(NULL, "CLC", "HideOfflineRoot", 0) && style&CLS_USEGROUPS;
+ dat->list.cl.count = dat->list.cl.limit = 0;
+ dat->selection = -1;
+ {
+ int i;
+ TCHAR *szGroupName;
+ DWORD groupFlags;
+
+ for (i = 1;; i++) {
+ szGroupName = cli.pfnGetGroupName(i, &groupFlags);
+ if (szGroupName == NULL)
+ break;
+ cli.pfnAddGroup(hwnd, dat, szGroupName, groupFlags, i, 0);
+ }
+ }
+
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while (hContact) {
+ if (style & CLS_SHOWHIDDEN || !DBGetContactSettingByte(hContact, "CList", "Hidden", 0)) {
+ if (DBGetContactSettingTString(hContact, "CList", "Group", &dbv))
+ group = &dat->list;
+ else {
+ group = cli.pfnAddGroup(hwnd, dat, dbv.ptszVal, (DWORD) - 1, 0, 0);
+ if (group == NULL && style & CLS_SHOWHIDDEN) group = &dat->list;
+ mir_free(dbv.ptszVal);
+ }
+
+ if (group != NULL) {
+ group->totalMembers++;
+ if (!(style & CLS_NOHIDEOFFLINE) && (style & CLS_HIDEOFFLINE || group->hideOffline)) {
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+ if (szProto == NULL) {
+ if (!cli.pfnIsHiddenMode(dat, ID_STATUS_OFFLINE))
+ cli.pfnAddContactToGroup(dat, group, hContact);
+ }
+ else if (!cli.pfnIsHiddenMode(dat, DBGetContactSettingWord(hContact, szProto, "Status", ID_STATUS_OFFLINE)))
+ cli.pfnAddContactToGroup(dat, group, hContact);
+ }
+ else cli.pfnAddContactToGroup(dat, group, hContact);
+ }
+ }
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0);
+ }
+
+ if (style & CLS_HIDEEMPTYGROUPS) {
+ group = &dat->list;
+ group->scanIndex = 0;
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ group = group->parent;
+ if (group == NULL)
+ break;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
+ if (group->cl.items[group->scanIndex]->group->cl.count == 0) {
+ group = cli.pfnRemoveItemFromGroup(hwnd, group, group->cl.items[group->scanIndex], 0);
+ }
+ else {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+ }
+ continue;
+ }
+ group->scanIndex++;
+ }
+ }
+
+ cli.pfnSortCLC(hwnd, dat, 0);
+}
+
+int fnGetGroupContentsCount(struct ClcGroup *group, int visibleOnly)
+{
+ int count = group->cl.count;
+ struct ClcGroup *topgroup = group;
+
+ group->scanIndex = 0;
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ if (group == topgroup)
+ break;
+ group = group->parent;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP && (!visibleOnly || group->cl.items[group->scanIndex]->group->expanded)) {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+ count += group->cl.count;
+ continue;
+ }
+ group->scanIndex++;
+ }
+ return count;
+}
+
+static int __cdecl GroupSortProc(const void* p1, const void* p2)
+{
+ ClcContact **contact1 = ( ClcContact** )p1, **contact2 = ( ClcContact** )p2;
+
+ return lstrcmpi(contact1[0]->szText, contact2[0]->szText);
+}
+
+static int __cdecl ContactSortProc(const void* p1, const void* p2)
+{
+ ClcContact **contact1 = ( ClcContact** )p1, **contact2 = ( ClcContact** )p2;
+
+ int result = cli.pfnCompareContacts( contact1[0], contact2[0] );
+ if (result)
+ return result;
+ //nothing to distinguish them, so make sure they stay in the same order
+ return (int)((INT_PTR) contact2[0]->hContact - (INT_PTR) contact1[0]->hContact);
+}
+
+static void InsertionSort(struct ClcContact **pContactArray, int nArray, int (*CompareProc) (const void *, const void *))
+{
+ int i, j;
+ struct ClcContact* testElement;
+
+ for (i = 1; i < nArray; i++) {
+ if (CompareProc(&pContactArray[i - 1], &pContactArray[i]) > 0) {
+ testElement = pContactArray[i];
+ for (j = i - 2; j >= 0; j--)
+ if (CompareProc(&pContactArray[j], &testElement) <= 0)
+ break;
+ j++;
+ memmove(&pContactArray[j + 1], &pContactArray[j], sizeof(void*) * (i - j));
+ pContactArray[j] = testElement;
+} } }
+
+static void SortGroup(struct ClcData *dat, struct ClcGroup *group, int useInsertionSort)
+{
+ int i, sortCount;
+
+ for (i = group->cl.count - 1; i >= 0; i--) {
+ if (group->cl.items[i]->type == CLCIT_DIVIDER) {
+ mir_free( group->cl.items[i] );
+ List_Remove(( SortedList* )&group->cl, i );
+ } }
+
+ for (i = 0; i < group->cl.count; i++)
+ if (group->cl.items[i]->type != CLCIT_INFO)
+ break;
+ if (i > group->cl.count - 2)
+ return;
+ if (group->cl.items[i]->type == CLCIT_GROUP) {
+ if (dat->exStyle & CLS_EX_SORTGROUPSALPHA) {
+ for (sortCount = 0; i + sortCount < group->cl.count; sortCount++)
+ if (group->cl.items[i + sortCount]->type != CLCIT_GROUP)
+ break;
+ qsort(group->cl.items + i, sortCount, sizeof(void*), GroupSortProc);
+ i = i + sortCount;
+ }
+ for (; i < group->cl.count; i++)
+ if (group->cl.items[i]->type == CLCIT_CONTACT)
+ break;
+ if (group->cl.count - i < 2)
+ return;
+ }
+ for (sortCount = 0; i + sortCount < group->cl.count; sortCount++)
+ if (group->cl.items[i + sortCount]->type != CLCIT_CONTACT)
+ break;
+ if (useInsertionSort)
+ InsertionSort(group->cl.items + i, sortCount, ContactSortProc);
+ else
+ qsort(group->cl.items + i, sortCount, sizeof(void*), ContactSortProc);
+ if (dat->exStyle & CLS_EX_DIVIDERONOFF) {
+ int prevContactOnline = 0;
+ for (i = 0; i < group->cl.count; i++) {
+ if (group->cl.items[i]->type != CLCIT_CONTACT)
+ continue;
+ if (group->cl.items[i]->flags & CONTACTF_ONLINE)
+ prevContactOnline = 1;
+ else {
+ if (prevContactOnline) {
+ i = cli.pfnAddItemToGroup(group, i);
+ group->cl.items[i]->type = CLCIT_DIVIDER;
+ lstrcpy(group->cl.items[i]->szText, TranslateT("Offline"));
+ }
+ break;
+} } } }
+
+void fnSortCLC(HWND hwnd, struct ClcData *dat, int useInsertionSort)
+{
+ struct ClcContact *selcontact;
+ struct ClcGroup *group = &dat->list, *selgroup;
+ HANDLE hSelItem;
+
+ if ( dat->needsResort ) {
+ if (cli.pfnGetRowByIndex(dat, dat->selection, &selcontact, NULL) == -1)
+ hSelItem = NULL;
+ else
+ hSelItem = cli.pfnContactToHItem(selcontact);
+ group->scanIndex = 0;
+ SortGroup(dat, group, useInsertionSort);
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ group = group->parent;
+ if (group == NULL)
+ break;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+ SortGroup(dat, group, useInsertionSort);
+ continue;
+ }
+ group->scanIndex++;
+ }
+ if (hSelItem)
+ if (cli.pfnFindItem(hwnd, dat, hSelItem, &selcontact, &selgroup, NULL))
+ dat->selection = cli.pfnGetRowsPriorTo(&dat->list, selgroup, List_IndexOf((SortedList*)&selgroup->cl,selcontact));
+
+ cli.pfnRecalcScrollBar(hwnd, dat);
+ }
+ dat->needsResort = 0;
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+}
+
+struct SavedContactState_t
+{
+ HANDLE hContact;
+ BYTE iExtraImage[MAXEXTRACOLUMNS];
+ int checked;
+};
+
+struct SavedGroupState_t
+{
+ int groupId, expanded;
+};
+
+struct SavedInfoState_t
+{
+ int parentId;
+ ClcContact contact;
+};
+
+void fnSaveStateAndRebuildList(HWND hwnd, struct ClcData *dat)
+{
+ NMCLISTCONTROL nm;
+ int i, j;
+ ClcGroup *group;
+ ClcContact *contact;
+
+ cli.pfnHideInfoTip(hwnd, dat);
+ KillTimer(hwnd, TIMERID_INFOTIP);
+ KillTimer(hwnd, TIMERID_RENAME);
+ cli.pfnEndRename(hwnd, dat, 1);
+
+ OBJLIST<SavedContactState_t> saveContact( 10, HandleKeySortT );
+ OBJLIST<SavedGroupState_t> saveGroup( 100, NumericKeySortT );
+ OBJLIST<SavedInfoState_t> saveInfo( 10, NumericKeySortT );
+
+ dat->needsResort = 1;
+ group = &dat->list;
+ group->scanIndex = 0;
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ group = group->parent;
+ if (group == NULL)
+ break;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+
+ SavedGroupState_t* p = new SavedGroupState_t;
+ p->groupId = group->groupId;
+ p->expanded = group->expanded;
+ saveGroup.insert( p );
+ continue;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_CONTACT) {
+ SavedContactState_t* p = new SavedContactState_t;
+ p->hContact = group->cl.items[group->scanIndex]->hContact;
+ CopyMemory( p->iExtraImage, group->cl.items[group->scanIndex]->iExtraImage,
+ sizeof(group->cl.items[group->scanIndex]->iExtraImage));
+ p->checked = group->cl.items[group->scanIndex]->flags & CONTACTF_CHECKED;
+ saveContact.insert( p );
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_INFO) {
+ SavedInfoState_t* p = new SavedInfoState_t;
+ p->parentId = (group->parent == NULL) ? -1 : group->groupId;
+ p->contact = *group->cl.items[group->scanIndex];
+ saveInfo.insert( p );
+ }
+ group->scanIndex++;
+ }
+
+ cli.pfnFreeGroup(&dat->list);
+ cli.pfnRebuildEntireList(hwnd, dat);
+
+ group = &dat->list;
+ group->scanIndex = 0;
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ group = group->parent;
+ if (group == NULL)
+ break;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+
+ SavedGroupState_t tmp, *p;
+ tmp.groupId = group->groupId;
+ if (( p = saveGroup.find( &tmp )) != NULL )
+ group->expanded = p->expanded;
+ continue;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_CONTACT) {
+ SavedContactState_t tmp, *p;
+ tmp.hContact = group->cl.items[group->scanIndex]->hContact;
+ if (( p = saveContact.find( &tmp )) != NULL ) {
+ CopyMemory(group->cl.items[group->scanIndex]->iExtraImage, p->iExtraImage,
+ SIZEOF(group->cl.items[group->scanIndex]->iExtraImage));
+ if (p->checked)
+ group->cl.items[group->scanIndex]->flags |= CONTACTF_CHECKED;
+ } }
+
+ group->scanIndex++;
+ }
+
+ for (i = 0; i < saveInfo.getCount(); i++) {
+ if (saveInfo[i].parentId == -1)
+ group = &dat->list;
+ else {
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) (saveInfo[i].parentId | HCONTACT_ISGROUP), &contact, NULL, NULL))
+ continue;
+ group = contact->group;
+ }
+ j = cli.pfnAddInfoItemToGroup(group, saveInfo[i].contact.flags, _T(""));
+ *group->cl.items[j] = saveInfo[i].contact;
+ }
+
+ cli.pfnRecalculateGroupCheckboxes(hwnd, dat);
+
+ cli.pfnRecalcScrollBar(hwnd, dat);
+ nm.hdr.code = CLN_LISTREBUILT;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nm);
+}
diff --git a/src/modules/clist/clcmsgs.cpp b/src/modules/clist/clcmsgs.cpp
new file mode 100644
index 0000000000..a46777939d
--- /dev/null
+++ b/src/modules/clist/clcmsgs.cpp
@@ -0,0 +1,472 @@
+/*
+
+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 "clc.h"
+
+//processing of all the CLM_ messages incoming
+
+LRESULT fnProcessExternalMessages(HWND hwnd, struct ClcData *dat, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case CLM_ADDCONTACT:
+ cli.pfnAddContactToTree(hwnd, dat, (HANDLE) wParam, 1, 0);
+ cli.pfnRecalcScrollBar(hwnd, dat);
+ cli.pfnSortCLC(hwnd, dat, 1);
+ break;
+
+ case CLM_ADDGROUP:
+ {
+ DWORD groupFlags;
+ TCHAR *szName = cli.pfnGetGroupName(wParam, &groupFlags);
+ if (szName == NULL)
+ break;
+ cli.pfnAddGroup(hwnd, dat, szName, groupFlags, wParam, 0);
+ cli.pfnRecalcScrollBar(hwnd, dat);
+ break;
+ }
+
+ case CLM_ADDINFOITEMA:
+ case CLM_ADDINFOITEMW:
+ {
+ int i;
+ ClcContact *groupContact;
+ ClcGroup *group;
+ CLCINFOITEM *cii = (CLCINFOITEM *) lParam;
+ if (cii==NULL || cii->cbSize != sizeof(CLCINFOITEM))
+ return (LRESULT) (HANDLE) NULL;
+ if (cii->hParentGroup == NULL)
+ group = &dat->list;
+ else {
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) ((UINT_PTR) cii->hParentGroup | HCONTACT_ISGROUP), &groupContact, NULL, NULL))
+ return (LRESULT) (HANDLE) NULL;
+ group = groupContact->group;
+ }
+ #if defined( _UNICODE )
+ if ( msg == CLM_ADDINFOITEMA )
+ { WCHAR* wszText = mir_a2u(( char* )cii->pszText );
+ i = cli.pfnAddInfoItemToGroup(group, cii->flags, wszText);
+ mir_free( wszText );
+ }
+ else i = cli.pfnAddInfoItemToGroup(group, cii->flags, cii->pszText);
+ #else
+ i = cli.pfnAddInfoItemToGroup(group, cii->flags, cii->pszText);
+ #endif
+ cli.pfnRecalcScrollBar(hwnd, dat);
+ return (LRESULT) group->cl.items[i]->hContact | HCONTACT_ISINFO;
+ }
+
+ case CLM_AUTOREBUILD:
+ KillTimer(hwnd,TIMERID_REBUILDAFTER);
+ cli.pfnSaveStateAndRebuildList(hwnd, dat);
+ break;
+
+ case CLM_DELETEITEM:
+ cli.pfnDeleteItemFromTree(hwnd, (HANDLE) wParam);
+ cli.pfnSortCLC(hwnd, dat, 1);
+ cli.pfnRecalcScrollBar(hwnd, dat);
+ break;
+
+ case CLM_EDITLABEL:
+ SendMessage(hwnd, CLM_SELECTITEM, wParam, 0);
+ cli.pfnBeginRenameSelection(hwnd, dat);
+ break;
+
+ case CLM_ENDEDITLABELNOW:
+ cli.pfnEndRename(hwnd, dat, wParam);
+ break;
+
+ case CLM_ENSUREVISIBLE:
+ {
+ ClcContact *contact;
+ ClcGroup *group, *tgroup;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, &group, NULL))
+ break;
+ for (tgroup = group; tgroup; tgroup = tgroup->parent)
+ cli.pfnSetGroupExpand(hwnd, dat, tgroup, 1);
+ cli.pfnEnsureVisible(hwnd, dat, cli.pfnGetRowsPriorTo(&dat->list, group, List_IndexOf((SortedList*)&group->cl,contact)), 0);
+ break;
+ }
+
+ case CLM_EXPAND:
+ {
+ ClcContact *contact;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ break;
+ if (contact->type != CLCIT_GROUP)
+ break;
+ cli.pfnSetGroupExpand(hwnd, dat, contact->group, lParam);
+ break;
+ }
+
+ case CLM_FINDCONTACT:
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, NULL, NULL, NULL))
+ return (LRESULT) (HANDLE) NULL;
+ return wParam;
+
+ case CLM_FINDGROUP:
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) (wParam | HCONTACT_ISGROUP), NULL, NULL, NULL))
+ return (LRESULT) (HANDLE) NULL;
+ return wParam | HCONTACT_ISGROUP;
+
+ case CLM_GETBKCOLOR:
+ return dat->bkColour;
+
+ case CLM_GETCHECKMARK:
+ {
+ ClcContact *contact;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ return 0;
+ return (contact->flags & CONTACTF_CHECKED) != 0;
+ }
+
+ case CLM_GETCOUNT:
+ return cli.pfnGetGroupContentsCount(&dat->list, 0);
+
+ case CLM_GETEDITCONTROL:
+ return (LRESULT) dat->hwndRenameEdit;
+
+ case CLM_GETEXPAND:
+ {
+ ClcContact *contact;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ return CLE_INVALID;
+ if (contact->type != CLCIT_GROUP)
+ return CLE_INVALID;
+ return contact->group->expanded;
+ }
+
+ case CLM_GETEXTRACOLUMNS:
+ return dat->extraColumnsCount;
+
+ case CLM_GETEXTRAIMAGE:
+ {
+ ClcContact *contact;
+ if (LOWORD(lParam) >= dat->extraColumnsCount)
+ return 0xFF;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ return 0xFF;
+ return contact->iExtraImage[LOWORD(lParam)];
+ }
+
+ case CLM_GETEXTRAIMAGELIST:
+ return (LRESULT) dat->himlExtraColumns;
+
+ case CLM_GETFONT:
+ if (wParam < 0 || wParam > FONTID_MAX)
+ return 0;
+ return (LRESULT) dat->fontInfo[wParam].hFont;
+
+ case CLM_GETHIDEOFFLINEROOT:
+ return DBGetContactSettingByte(NULL, "CLC", "HideOfflineRoot", 0);
+
+ case CLM_GETINDENT:
+ return dat->groupIndent;
+
+ case CLM_GETISEARCHSTRING:
+ lstrcpy(( TCHAR* ) lParam, dat->szQuickSearch);
+ return lstrlen(dat->szQuickSearch);
+
+ case CLM_GETITEMTEXT:
+ {
+ ClcContact *contact;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ return 0;
+ lstrcpy(( TCHAR* ) lParam, contact->szText);
+ return lstrlen(contact->szText);
+ }
+
+ case CLM_GETITEMTYPE:
+ {
+ ClcContact *contact;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ return CLCIT_INVALID;
+ return contact->type;
+ }
+
+ case CLM_GETLEFTMARGIN:
+ return dat->leftMargin;
+
+ case CLM_GETNEXTITEM:
+ {
+ if (wParam == CLGN_ROOT) {
+ if (dat->list.cl.count)
+ return (LRESULT) cli.pfnContactToHItem(dat->list.cl.items[0]);
+ return NULL;
+ }
+
+ ClcContact *contact;
+ ClcGroup *group;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) lParam, &contact, &group, NULL))
+ return NULL;
+
+ int i = List_IndexOf((SortedList*)&group->cl,contact);
+ switch (wParam) {
+ case CLGN_CHILD:
+ if (contact->type != CLCIT_GROUP)
+ return (LRESULT) (HANDLE) NULL;
+ group = contact->group;
+ if (group->cl.count == 0)
+ return NULL;
+ return (LRESULT) cli.pfnContactToHItem(group->cl.items[0]);
+
+ case CLGN_PARENT:
+ return group->groupId | HCONTACT_ISGROUP;
+
+ case CLGN_NEXT:
+ do {
+ if (++i >= group->cl.count)
+ return NULL;
+ }
+ while (group->cl.items[i]->type == CLCIT_DIVIDER);
+ return (LRESULT) cli.pfnContactToHItem(group->cl.items[i]);
+
+ case CLGN_PREVIOUS:
+ do {
+ if (--i < 0)
+ return NULL;
+ }
+ while (group->cl.items[i]->type == CLCIT_DIVIDER);
+ return (LRESULT) cli.pfnContactToHItem(group->cl.items[i]);
+
+ case CLGN_NEXTCONTACT:
+ for (i++; i < group->cl.count; i++)
+ if (group->cl.items[i]->type == CLCIT_CONTACT)
+ break;
+ if (i >= group->cl.count)
+ return NULL;
+ return (LRESULT) cli.pfnContactToHItem(group->cl.items[i]);
+
+ case CLGN_PREVIOUSCONTACT:
+ if (i >= group->cl.count)
+ return NULL;
+ for (i--; i >= 0; i--)
+ if (group->cl.items[i]->type == CLCIT_CONTACT)
+ break;
+ if (i < 0)
+ return NULL;
+ return (LRESULT) cli.pfnContactToHItem(group->cl.items[i]);
+
+ case CLGN_NEXTGROUP:
+ for (i++; i < group->cl.count; i++)
+ if (group->cl.items[i]->type == CLCIT_GROUP)
+ break;
+ if (i >= group->cl.count)
+ return NULL;
+ return (LRESULT) cli.pfnContactToHItem(group->cl.items[i]);
+
+ case CLGN_PREVIOUSGROUP:
+ if (i >= group->cl.count)
+ return NULL;
+ for (i--; i >= 0; i--)
+ if (group->cl.items[i]->type == CLCIT_GROUP)
+ break;
+ if (i < 0)
+ return NULL;
+ return (LRESULT) cli.pfnContactToHItem(group->cl.items[i]);
+ }
+ return NULL;
+ }
+
+ case CLM_GETSCROLLTIME:
+ return dat->scrollTime;
+
+ case CLM_GETSELECTION:
+ {
+ ClcContact *contact;
+ if (cli.pfnGetRowByIndex(dat, dat->selection, &contact, NULL) == -1)
+ return NULL;
+ return (LRESULT) cli.pfnContactToHItem(contact);
+ }
+
+ case CLM_GETTEXTCOLOR:
+ if (wParam < 0 || wParam > FONTID_MAX)
+ return 0;
+ return (LRESULT) dat->fontInfo[wParam].colour;
+
+ case CLM_HITTEST:
+ {
+ ClcContact *contact;
+ DWORD hitFlags;
+ int hit;
+ hit = cli.pfnHitTest(hwnd, dat, (short) LOWORD(lParam), (short) HIWORD(lParam), &contact, NULL, &hitFlags);
+ if (wParam)
+ *(PDWORD) wParam = hitFlags;
+ if (hit == -1)
+ return NULL;
+ return (LRESULT) cli.pfnContactToHItem(contact);
+ }
+
+ case CLM_SELECTITEM:
+ {
+ ClcContact *contact;
+ ClcGroup *group, *tgroup;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, &group, NULL))
+ break;
+ for (tgroup = group; tgroup; tgroup = tgroup->parent)
+ cli.pfnSetGroupExpand(hwnd, dat, tgroup, 1);
+ dat->selection = cli.pfnGetRowsPriorTo(&dat->list, group, List_IndexOf((SortedList*)&group->cl,contact));
+ cli.pfnEnsureVisible(hwnd, dat, dat->selection, 0);
+ break;
+ }
+
+ case CLM_SETBKBITMAP:
+ if (!dat->bkChanged && dat->hBmpBackground) {
+ DeleteObject(dat->hBmpBackground);
+ dat->hBmpBackground = NULL;
+ }
+ dat->hBmpBackground = (HBITMAP) lParam;
+ dat->backgroundBmpUse = wParam;
+ dat->bkChanged = 1;
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+
+ case CLM_SETBKCOLOR:
+ if (!dat->bkChanged && dat->hBmpBackground) {
+ DeleteObject(dat->hBmpBackground);
+ dat->hBmpBackground = NULL;
+ }
+ dat->bkColour = wParam;
+ dat->bkChanged = 1;
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+
+ case CLM_SETCHECKMARK:
+ {
+ ClcContact *contact;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ return 0;
+ if (lParam)
+ contact->flags |= CONTACTF_CHECKED;
+ else
+ contact->flags &= ~CONTACTF_CHECKED;
+ cli.pfnRecalculateGroupCheckboxes(hwnd, dat);
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+ }
+
+ case CLM_SETEXTRACOLUMNS:
+ if (wParam > MAXEXTRACOLUMNS)
+ return 0;
+ dat->extraColumnsCount = wParam;
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+
+ case CLM_SETEXTRAIMAGE:
+ {
+ ClcContact *contact;
+ if (LOWORD(lParam) >= dat->extraColumnsCount)
+ return 0;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ return 0;
+ contact->iExtraImage[LOWORD(lParam)] = (BYTE) HIWORD(lParam);
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+ }
+
+ case CLM_SETEXTRAIMAGELIST:
+ dat->himlExtraColumns = (HIMAGELIST) lParam;
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+
+ case CLM_SETFONT:
+ if (HIWORD(lParam) < 0 || HIWORD(lParam) > FONTID_MAX)
+ return 0;
+ dat->fontInfo[HIWORD(lParam)].hFont = (HFONT) wParam;
+ dat->fontInfo[HIWORD(lParam)].changed = 1;
+ {
+ SIZE fontSize;
+ HDC hdc = GetDC(hwnd);
+ SelectObject(hdc, (HFONT) wParam);
+ GetTextExtentPoint32A(hdc, "x", 1, &fontSize);
+ dat->fontInfo[HIWORD(lParam)].fontHeight = fontSize.cy;
+ if (dat->rowHeight < fontSize.cy + 2)
+ dat->rowHeight = fontSize.cy + 2;
+ ReleaseDC(hwnd, hdc);
+ }
+ if (LOWORD(lParam))
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+
+ case CLM_SETGREYOUTFLAGS:
+ dat->greyoutFlags = wParam;
+ break;
+
+ case CLM_SETHIDEEMPTYGROUPS:
+ if (wParam)
+ SetWindowLongPtr(hwnd, GWL_STYLE, GetWindowLongPtr(hwnd, GWL_STYLE) | CLS_HIDEEMPTYGROUPS);
+ else
+ SetWindowLongPtr(hwnd, GWL_STYLE, GetWindowLongPtr(hwnd, GWL_STYLE) & ~CLS_HIDEEMPTYGROUPS);
+ SendMessage(hwnd, CLM_AUTOREBUILD, 0, 0);
+ break;
+
+ case CLM_SETHIDEOFFLINEROOT:
+ DBWriteContactSettingByte(NULL, "CLC", "HideOfflineRoot", (BYTE) wParam);
+ SendMessage(hwnd, CLM_AUTOREBUILD, 0, 0);
+ break;
+
+ case CLM_SETINDENT:
+ dat->groupIndent = wParam;
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+
+ case CLM_SETITEMTEXT:
+ {
+ ClcContact *contact;
+ if (!cli.pfnFindItem(hwnd, dat, (HANDLE) wParam, &contact, NULL, NULL))
+ break;
+ lstrcpyn(contact->szText, ( TCHAR* )lParam, SIZEOF( contact->szText ));
+ cli.pfnSortCLC(hwnd, dat, 1);
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+ }
+
+ case CLM_SETLEFTMARGIN:
+ dat->leftMargin = wParam;
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ break;
+
+ case CLM_SETOFFLINEMODES:
+ dat->offlineModes = wParam;
+ SendMessage(hwnd, CLM_AUTOREBUILD, 0, 0);
+ break;
+
+ case CLM_SETSCROLLTIME:
+ dat->scrollTime = wParam;
+ break;
+
+ case CLM_SETTEXTCOLOR:
+ if (wParam < 0 || wParam > FONTID_MAX)
+ break;
+ dat->fontInfo[wParam].colour = lParam;
+ break;
+
+ case CLM_SETUSEGROUPS:
+ if (wParam)
+ SetWindowLongPtr(hwnd, GWL_STYLE, GetWindowLongPtr(hwnd, GWL_STYLE) | CLS_USEGROUPS);
+ else
+ SetWindowLongPtr(hwnd, GWL_STYLE, GetWindowLongPtr(hwnd, GWL_STYLE) & ~CLS_USEGROUPS);
+ SendMessage(hwnd, CLM_AUTOREBUILD, 0, 0);
+ break;
+ }
+ return 0;
+}
diff --git a/src/modules/clist/clcutils.cpp b/src/modules/clist/clcutils.cpp
new file mode 100644
index 0000000000..3205066e2f
--- /dev/null
+++ b/src/modules/clist/clcutils.cpp
@@ -0,0 +1,879 @@
+/*
+
+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 "clc.h"
+
+//loads of stuff that didn't really fit anywhere else
+
+extern HANDLE hHideInfoTipEvent;
+
+char* fnGetGroupCountsText(struct ClcData *dat, struct ClcContact *contact)
+{
+ static char szName[32];
+ int onlineCount, totalCount;
+ struct ClcGroup *group, *topgroup;
+
+ if (contact->type != CLCIT_GROUP || !(dat->exStyle & CLS_EX_SHOWGROUPCOUNTS))
+ return "";
+
+ group = topgroup = contact->group;
+ onlineCount = 0;
+ totalCount = group->totalMembers;
+ group->scanIndex = 0;
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ if (group == topgroup)
+ break;
+ group = group->parent;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+ totalCount += group->totalMembers;
+ continue;
+ }
+ else if (group->cl.items[group->scanIndex]->type == CLCIT_CONTACT)
+ if (group->cl.items[group->scanIndex]->flags & CONTACTF_ONLINE)
+ onlineCount++;
+ group->scanIndex++;
+ }
+ if (onlineCount == 0 && dat->exStyle & CLS_EX_HIDECOUNTSWHENEMPTY)
+ return "";
+ mir_snprintf(szName, SIZEOF(szName), "(%u/%u)", onlineCount, totalCount);
+ return szName;
+}
+
+int fnHitTest(HWND hwnd, struct ClcData *dat, int testx, int testy, struct ClcContact **contact, struct ClcGroup **group, DWORD * flags)
+{
+ ClcContact *hitcontact = NULL;
+ ClcGroup *hitgroup = NULL;
+ int hit, indent, width, i;
+ int checkboxWidth;
+ SIZE textSize;
+ HDC hdc;
+ RECT clRect;
+ HFONT hFont;
+ DWORD style = GetWindowLongPtr(hwnd, GWL_STYLE);
+ POINT pt;
+
+ if ( flags )
+ *flags = 0;
+
+ pt.x = testx;
+ pt.y = testy;
+ ClientToScreen(hwnd, &pt);
+
+ HWND hwndParent = hwnd, hwndTemp;
+ do
+ {
+ hwndTemp = hwndParent;
+ hwndParent = (HWND)GetWindowLongPtr(hwndTemp, GWLP_HWNDPARENT);
+
+ POINT pt1 = pt;
+ ScreenToClient(hwndParent, &pt1);
+ HWND h = ChildWindowFromPointEx(hwndParent ? hwndParent : GetDesktopWindow(),
+ pt1, CWP_SKIPINVISIBLE | CWP_SKIPTRANSPARENT);
+ if (h != hwndTemp)
+ {
+ if (!hwndParent || !(GetWindowLong(hwndTemp, GWL_STYLE) & BS_GROUPBOX))
+ return -1;
+ }
+ }
+ while (hwndParent);
+
+ GetClientRect(hwnd, &clRect);
+ if ( testx < 0 || testy < 0 || testy >= clRect.bottom || testx >= clRect.right ) {
+ if ( flags ) {
+ if (testx < 0)
+ *flags |= CLCHT_TOLEFT;
+ else if (testx >= clRect.right)
+ *flags |= CLCHT_TORIGHT;
+ if (testy < 0)
+ *flags |= CLCHT_ABOVE;
+ else if (testy >= clRect.bottom)
+ *flags |= CLCHT_BELOW;
+ }
+ return -1;
+ }
+ if (testx < dat->leftMargin) {
+ if (flags)
+ *flags |= CLCHT_INLEFTMARGIN | CLCHT_NOWHERE;
+ return -1;
+ }
+ hit = cli.pfnRowHitTest(dat, dat->yScroll + testy);
+ if ( hit != -1 )
+ hit = cli.pfnGetRowByIndex(dat, hit, &hitcontact, &hitgroup);
+ if (hit == -1) {
+ if (flags)
+ *flags |= CLCHT_NOWHERE | CLCHT_BELOWITEMS;
+ return -1;
+ }
+ if (contact)
+ *contact = hitcontact;
+ if (group)
+ *group = hitgroup;
+ for (indent = 0; hitgroup->parent; indent++, hitgroup = hitgroup->parent);
+ if (testx < dat->leftMargin + indent * dat->groupIndent) {
+ if (flags)
+ *flags |= CLCHT_ONITEMINDENT;
+ return hit;
+ }
+ checkboxWidth = 0;
+ if (style & CLS_CHECKBOXES && hitcontact->type == CLCIT_CONTACT)
+ checkboxWidth = dat->checkboxSize + 2;
+ if (style & CLS_GROUPCHECKBOXES && hitcontact->type == CLCIT_GROUP)
+ checkboxWidth = dat->checkboxSize + 2;
+ if (hitcontact->type == CLCIT_INFO && hitcontact->flags & CLCIIF_CHECKBOX)
+ checkboxWidth = dat->checkboxSize + 2;
+ if (testx < dat->leftMargin + indent * dat->groupIndent + checkboxWidth) {
+ if (flags)
+ *flags |= CLCHT_ONITEMCHECK;
+ return hit;
+ }
+ if (testx < dat->leftMargin + indent * dat->groupIndent + checkboxWidth + dat->iconXSpace) {
+ if (flags)
+ *flags |= CLCHT_ONITEMICON;
+ return hit;
+ }
+
+ for (i = 0; i < dat->extraColumnsCount; i++) {
+ if (hitcontact->iExtraImage[i] == 0xFF)
+ continue;
+ if (testx >= clRect.right - dat->extraColumnSpacing * (dat->extraColumnsCount - i) &&
+ testx < clRect.right - dat->extraColumnSpacing * (dat->extraColumnsCount - i) + g_IconWidth ) {
+ if (flags)
+ *flags |= CLCHT_ONITEMEXTRA | (i << 24);
+ return hit;
+ }
+ }
+ hdc = GetDC(hwnd);
+ if (hitcontact->type == CLCIT_GROUP)
+ hFont = ( HFONT )SelectObject(hdc, dat->fontInfo[FONTID_GROUPS].hFont);
+ else
+ hFont = ( HFONT )SelectObject(hdc, dat->fontInfo[FONTID_CONTACTS].hFont);
+ GetTextExtentPoint32(hdc, hitcontact->szText, lstrlen(hitcontact->szText), &textSize);
+ width = textSize.cx;
+ if (hitcontact->type == CLCIT_GROUP) {
+ char *szCounts;
+ szCounts = cli.pfnGetGroupCountsText(dat, hitcontact);
+ if (szCounts[0]) {
+ GetTextExtentPoint32A(hdc, " ", 1, &textSize);
+ width += textSize.cx;
+ SelectObject(hdc, dat->fontInfo[FONTID_GROUPCOUNTS].hFont);
+ GetTextExtentPoint32A(hdc, szCounts, lstrlenA(szCounts), &textSize);
+ width += textSize.cx;
+ }
+ }
+ SelectObject(hdc, hFont);
+ ReleaseDC(hwnd, hdc);
+ if (testx < dat->leftMargin + indent * dat->groupIndent + checkboxWidth + dat->iconXSpace + width + 4) {
+ if (flags)
+ *flags |= CLCHT_ONITEMLABEL;
+ return hit;
+ }
+ if (flags)
+ *flags |= CLCHT_NOWHERE;
+ return -1;
+}
+
+void fnScrollTo(HWND hwnd, struct ClcData *dat, int desty, int noSmooth)
+{
+ DWORD startTick, nowTick;
+ int oldy = dat->yScroll;
+ RECT clRect, rcInvalidate;
+ int maxy, previousy;
+
+ if (dat->iHotTrack != -1 && dat->yScroll != desty) {
+ cli.pfnInvalidateItem(hwnd, dat, dat->iHotTrack);
+ dat->iHotTrack = -1;
+ ReleaseCapture();
+ }
+ GetClientRect(hwnd, &clRect);
+ rcInvalidate = clRect;
+ maxy = cli.pfnGetRowTotalHeight(dat) - clRect.bottom;
+ if (desty > maxy)
+ desty = maxy;
+ if (desty < 0)
+ desty = 0;
+ if (abs(desty - dat->yScroll) < 4)
+ noSmooth = 1;
+ if (!noSmooth && dat->exStyle & CLS_EX_NOSMOOTHSCROLLING)
+ noSmooth = 1;
+ previousy = dat->yScroll;
+ if (!noSmooth) {
+ startTick = GetTickCount();
+ for (;;) {
+ nowTick = GetTickCount();
+ if (nowTick >= startTick + dat->scrollTime)
+ break;
+ dat->yScroll = oldy + (desty - oldy) * (int) (nowTick - startTick) / dat->scrollTime;
+ if (dat->backgroundBmpUse & CLBF_SCROLL || dat->hBmpBackground == NULL)
+ ScrollWindowEx(hwnd, 0, previousy - dat->yScroll, NULL, NULL, NULL, NULL, SW_INVALIDATE);
+ else
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ previousy = dat->yScroll;
+ SetScrollPos(hwnd, SB_VERT, dat->yScroll, TRUE);
+ UpdateWindow(hwnd);
+ }
+ }
+ dat->yScroll = desty;
+ if (dat->backgroundBmpUse & CLBF_SCROLL || dat->hBmpBackground == NULL)
+ ScrollWindowEx(hwnd, 0, previousy - dat->yScroll, NULL, NULL, NULL, NULL, SW_INVALIDATE);
+ else
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ SetScrollPos(hwnd, SB_VERT, dat->yScroll, TRUE);
+}
+
+void fnEnsureVisible(HWND hwnd, struct ClcData *dat, int iItem, int partialOk)
+{
+ int itemy = cli.pfnGetRowTopY(dat, iItem), itemh = cli.pfnGetRowHeight(dat, iItem), newY = 0;
+ int moved = 0;
+ RECT clRect;
+
+ GetClientRect(hwnd, &clRect);
+ if (partialOk) {
+ if (itemy + itemh - 1 < dat->yScroll) {
+ newY = itemy;
+ moved = 1;
+ }
+ else if (itemy >= dat->yScroll + clRect.bottom) {
+ newY = itemy - clRect.bottom + itemh;
+ moved = 1;
+ }
+ }
+ else {
+ if (itemy < dat->yScroll) {
+ newY = itemy;
+ moved = 1;
+ }
+ else if (itemy >= dat->yScroll + clRect.bottom - itemh) {
+ newY = itemy - clRect.bottom + itemh;
+ moved = 1;
+ }
+ }
+ if (moved)
+ cli.pfnScrollTo(hwnd, dat, newY, 0);
+}
+
+void fnRecalcScrollBar(HWND hwnd, struct ClcData *dat)
+{
+ SCROLLINFO si = { 0 };
+ RECT clRect;
+ NMCLISTCONTROL nm;
+
+ GetClientRect(hwnd, &clRect);
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_ALL;
+ si.nMin = 0;
+ si.nMax = cli.pfnGetRowTotalHeight(dat)-1;
+ si.nPage = clRect.bottom;
+ si.nPos = dat->yScroll;
+
+ if (GetWindowLongPtr(hwnd, GWL_STYLE) & CLS_CONTACTLIST) {
+ if (dat->noVScrollbar == 0)
+ SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
+ }
+ else SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
+
+ cli.pfnScrollTo(hwnd, dat, dat->yScroll, 1);
+ nm.hdr.code = CLN_LISTSIZECHANGE;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.pt.y = si.nMax;
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nm);
+}
+
+void fnSetGroupExpand(HWND hwnd, struct ClcData *dat, struct ClcGroup *group, int newState)
+{
+ int contentCount;
+ int groupy;
+ int newY, posY;
+ RECT clRect;
+ NMCLISTCONTROL nm;
+
+ if (newState == -1)
+ group->expanded ^= 1;
+ else {
+ if (group->expanded == (newState != 0))
+ return;
+ group->expanded = newState != 0;
+ }
+ cli.pfnInvalidateRect(hwnd, NULL, FALSE);
+ contentCount = cli.pfnGetGroupContentsCount(group, 1);
+ groupy = cli.pfnGetRowsPriorTo(&dat->list, group, -1);
+ if (dat->selection > groupy && dat->selection < groupy + contentCount)
+ dat->selection = groupy;
+ GetClientRect(hwnd, &clRect);
+ newY = dat->yScroll;
+ posY = cli.pfnGetRowBottomY(dat, groupy + contentCount);
+ if (posY >= newY + clRect.bottom)
+ newY = posY - clRect.bottom;
+ posY = cli.pfnGetRowTopY(dat, groupy);
+ if (newY > posY)
+ newY = posY;
+ cli.pfnRecalcScrollBar(hwnd, dat);
+ if (group->expanded)
+ cli.pfnScrollTo(hwnd, dat, newY, 0);
+ nm.hdr.code = CLN_EXPANDED;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.hItem = (HANDLE) group->groupId;
+ nm.action = group->expanded;
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nm);
+}
+
+void fnDoSelectionDefaultAction(HWND hwnd, struct ClcData *dat)
+{
+ struct ClcContact *contact;
+
+ if (dat->selection == -1)
+ return;
+ dat->szQuickSearch[0] = 0;
+ if (cli.pfnGetRowByIndex(dat, dat->selection, &contact, NULL) == -1)
+ return;
+ if (contact->type == CLCIT_GROUP)
+ cli.pfnSetGroupExpand(hwnd, dat, contact->group, -1);
+ if (contact->type == CLCIT_CONTACT)
+ CallService(MS_CLIST_CONTACTDOUBLECLICKED, (WPARAM) contact->hContact, 0);
+}
+
+int fnFindRowByText(HWND hwnd, struct ClcData *dat, const TCHAR *text, int prefixOk)
+{
+ struct ClcGroup *group = &dat->list;
+ int testlen = lstrlen(text);
+
+ group->scanIndex = 0;
+ for (;;) {
+ if (group->scanIndex == group->cl.count) {
+ group = group->parent;
+ if (group == NULL)
+ break;
+ group->scanIndex++;
+ continue;
+ }
+ if (group->cl.items[group->scanIndex]->type != CLCIT_DIVIDER) {
+ if ((prefixOk && !_tcsnicmp(text, group->cl.items[group->scanIndex]->szText, testlen)) ||
+ (!prefixOk && !lstrcmpi(text, group->cl.items[group->scanIndex]->szText))) {
+ struct ClcGroup *contactGroup = group;
+ int contactScanIndex = group->scanIndex;
+ for (; group; group = group->parent)
+ cli.pfnSetGroupExpand(hwnd, dat, group, 1);
+ return cli.pfnGetRowsPriorTo(&dat->list, contactGroup, contactScanIndex);
+ }
+ if (group->cl.items[group->scanIndex]->type == CLCIT_GROUP) {
+ if (!(dat->exStyle & CLS_EX_QUICKSEARCHVISONLY) || group->cl.items[group->scanIndex]->group->expanded) {
+ group = group->cl.items[group->scanIndex]->group;
+ group->scanIndex = 0;
+ continue;
+ }
+ }
+ }
+ group->scanIndex++;
+ }
+ return -1;
+}
+
+void fnEndRename(HWND, struct ClcData *dat, int save)
+{
+ HWND hwndEdit = dat->hwndRenameEdit;
+ if (hwndEdit == NULL)
+ return;
+
+ dat->hwndRenameEdit = NULL;
+ if (save) {
+ TCHAR text[120]; text[0] = 0;
+ GetWindowText(hwndEdit, text, SIZEOF(text));
+
+ ClcContact *contact;
+ if (cli.pfnGetRowByIndex(dat, dat->selection, &contact, NULL) != -1) {
+ if (lstrcmp(contact->szText, text) && !_tcsstr(text, _T("\\"))) {
+ if (contact->type == CLCIT_GROUP) {
+ if (contact->group->parent && contact->group->parent->parent) {
+ TCHAR szFullName[256];
+ mir_sntprintf(szFullName, SIZEOF(szFullName), _T("%s\\%s"),
+ cli.pfnGetGroupName(contact->group->parent->groupId, NULL), text);
+ cli.pfnRenameGroup(contact->groupId, szFullName);
+ }
+ else
+ cli.pfnRenameGroup(contact->groupId, text);
+ }
+ else if (contact->type == CLCIT_CONTACT) {
+ cli.pfnInvalidateDisplayNameCacheEntry(contact->hContact);
+ TCHAR* otherName = cli.pfnGetContactDisplayName(contact->hContact, GCDNF_NOMYHANDLE);
+ if (!text[0] || !lstrcmp(otherName, text))
+ DBDeleteContactSetting(contact->hContact, "CList", "MyHandle");
+ else
+ DBWriteContactSettingTString(contact->hContact, "CList", "MyHandle", text);
+ mir_free(otherName);
+ }
+ }
+ }
+ }
+ DestroyWindow(hwndEdit);
+}
+
+void fnDeleteFromContactList(HWND hwnd, struct ClcData *dat)
+{
+ struct ClcContact *contact;
+ if (dat->selection == -1)
+ return;
+ dat->szQuickSearch[0] = 0;
+ if (cli.pfnGetRowByIndex(dat, dat->selection, &contact, NULL) == -1)
+ return;
+ switch (contact->type) {
+ case CLCIT_GROUP:
+ CallService(MS_CLIST_GROUPDELETE, (WPARAM)contact->groupId, 0);
+ break;
+ case CLCIT_CONTACT:
+ CallService("CList/DeleteContactCommand", (WPARAM)contact->hContact, (LPARAM)hwnd );
+ break;
+} }
+
+static WNDPROC OldRenameEditWndProc;
+static LRESULT CALLBACK RenameEditSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_KEYDOWN:
+ switch (wParam) {
+ case VK_RETURN:
+ cli.pfnEndRename(GetParent(hwnd), (struct ClcData *) GetWindowLongPtr(GetParent(hwnd), 0), 1);
+ return 0;
+ case VK_ESCAPE:
+ cli.pfnEndRename(GetParent(hwnd), (struct ClcData *) GetWindowLongPtr(GetParent(hwnd), 0), 0);
+ return 0;
+ }
+ break;
+ case WM_GETDLGCODE:
+ if (lParam) {
+ MSG *msg = (MSG *) lParam;
+ if (msg->message == WM_KEYDOWN && msg->wParam == VK_TAB)
+ return 0;
+ if (msg->message == WM_CHAR && msg->wParam == '\t')
+ return 0;
+ }
+ return DLGC_WANTMESSAGE;
+ case WM_KILLFOCUS:
+ cli.pfnEndRename(GetParent(hwnd), (struct ClcData *) GetWindowLongPtr(GetParent(hwnd), 0), 1);
+ return 0;
+ }
+ return CallWindowProc(OldRenameEditWndProc, hwnd, msg, wParam, lParam);
+}
+
+void fnBeginRenameSelection(HWND hwnd, struct ClcData *dat)
+{
+ struct ClcContact *contact;
+ struct ClcGroup *group;
+ RECT clRect;
+ POINT pt;
+ int h;
+
+ KillTimer(hwnd, TIMERID_RENAME);
+ ReleaseCapture();
+ dat->iHotTrack = -1;
+ dat->selection = cli.pfnGetRowByIndex(dat, dat->selection, &contact, &group);
+ if (dat->selection == -1)
+ return;
+ if (contact->type != CLCIT_CONTACT && contact->type != CLCIT_GROUP)
+ return;
+ GetClientRect(hwnd, &clRect);
+ cli.pfnCalcEipPosition( dat, contact, group, &pt );
+ h = cli.pfnGetRowHeight(dat, dat->selection);
+ dat->hwndRenameEdit = CreateWindow( _T("EDIT"), contact->szText, WS_CHILD | WS_BORDER | ES_AUTOHSCROLL, pt.x, pt.y, clRect.right - pt.x, h, hwnd, NULL, cli.hInst, NULL);
+ OldRenameEditWndProc = (WNDPROC) SetWindowLongPtr(dat->hwndRenameEdit, GWLP_WNDPROC, (LONG_PTR) RenameEditSubclassProc);
+ SendMessage(dat->hwndRenameEdit, WM_SETFONT, (WPARAM) (contact->type == CLCIT_GROUP ? dat->fontInfo[FONTID_GROUPS].hFont : dat->fontInfo[FONTID_CONTACTS].hFont), 0);
+ SendMessage(dat->hwndRenameEdit, EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN | EC_USEFONTINFO, 0);
+ SendMessage(dat->hwndRenameEdit, EM_SETSEL, 0, (LPARAM) (-1));
+ ShowWindow(dat->hwndRenameEdit, SW_SHOW);
+ SetFocus(dat->hwndRenameEdit);
+}
+
+void fnCalcEipPosition( struct ClcData *dat, struct ClcContact *, struct ClcGroup *group, POINT *result)
+{
+ int indent;
+ for (indent = 0; group->parent; indent++, group = group->parent);
+ result->x = indent * dat->groupIndent + dat->iconXSpace - 2;
+ result->y = cli.pfnGetRowTopY(dat, dat->selection) - dat->yScroll;
+}
+
+int fnGetDropTargetInformation(HWND hwnd, struct ClcData *dat, POINT pt)
+{
+ RECT clRect;
+ int hit;
+ struct ClcContact *contact, *movecontact;
+ struct ClcGroup *group, *movegroup;
+ DWORD hitFlags;
+
+ GetClientRect(hwnd, &clRect);
+ dat->selection = dat->iDragItem;
+ dat->iInsertionMark = -1;
+ if (!PtInRect(&clRect, pt))
+ return DROPTARGET_OUTSIDE;
+
+ hit = cli.pfnHitTest(hwnd, dat, pt.x, pt.y, &contact, &group, &hitFlags);
+ cli.pfnGetRowByIndex(dat, dat->iDragItem, &movecontact, &movegroup);
+ if (hit == dat->iDragItem)
+ return DROPTARGET_ONSELF;
+ if (hit == -1 || hitFlags & CLCHT_ONITEMEXTRA)
+ return DROPTARGET_ONNOTHING;
+
+ if (movecontact->type == CLCIT_GROUP) {
+ struct ClcContact *bottomcontact = NULL, *topcontact = NULL;
+ struct ClcGroup *topgroup = NULL;
+ int topItem = -1, bottomItem = -1;
+ int ok = 0;
+ if (pt.y + dat->yScroll < cli.pfnGetRowTopY(dat, hit) + dat->insertionMarkHitHeight) {
+ //could be insertion mark (above)
+ topItem = hit - 1;
+ bottomItem = hit;
+ bottomcontact = contact;
+ topItem = cli.pfnGetRowByIndex(dat, topItem, &topcontact, &topgroup);
+ ok = 1;
+ }
+ if (pt.y + dat->yScroll >= cli.pfnGetRowBottomY(dat, hit+1) - dat->insertionMarkHitHeight) {
+ //could be insertion mark (below)
+ topItem = hit;
+ bottomItem = hit + 1;
+ topcontact = contact;
+ topgroup = group;
+ bottomItem = cli.pfnGetRowByIndex(dat, bottomItem, &bottomcontact, NULL);
+ ok = 1;
+ }
+ if (ok) {
+ ok = 0;
+ if (bottomItem == -1 || bottomcontact->type != CLCIT_GROUP) { //need to special-case moving to end
+ if (topItem != dat->iDragItem) {
+ for (; topgroup; topgroup = topgroup->parent) {
+ if (topgroup == movecontact->group)
+ break;
+ if (topgroup == movecontact->group->parent) {
+ ok = 1;
+ break;
+ }
+ }
+ if (ok)
+ bottomItem = topItem + 1;
+ }
+ }
+ else if (bottomItem != dat->iDragItem && bottomcontact->type == CLCIT_GROUP && bottomcontact->group->parent == movecontact->group->parent) {
+ if (bottomcontact != movecontact + 1)
+ ok = 1;
+ }
+ if (ok) {
+ dat->iInsertionMark = bottomItem;
+ dat->selection = -1;
+ return DROPTARGET_INSERTION;
+ }
+ }
+ }
+ if (contact->type == CLCIT_GROUP) {
+ if (dat->iInsertionMark == -1) {
+ if (movecontact->type == CLCIT_GROUP) { //check not moving onto its own subgroup
+ for (; group; group = group->parent)
+ if (group == movecontact->group)
+ return DROPTARGET_ONSELF;
+ }
+ dat->selection = hit;
+ return DROPTARGET_ONGROUP;
+ }
+ }
+ return DROPTARGET_ONCONTACT;
+}
+
+int fnClcStatusToPf2(int status)
+{
+ switch(status) {
+ case ID_STATUS_ONLINE: return PF2_ONLINE;
+ case ID_STATUS_AWAY: return PF2_SHORTAWAY;
+ case ID_STATUS_DND: return PF2_HEAVYDND;
+ case ID_STATUS_NA: return PF2_LONGAWAY;
+ case ID_STATUS_OCCUPIED: return PF2_LIGHTDND;
+ case ID_STATUS_FREECHAT: return PF2_FREECHAT;
+ case ID_STATUS_INVISIBLE: return PF2_INVISIBLE;
+ case ID_STATUS_ONTHEPHONE: return PF2_ONTHEPHONE;
+ case ID_STATUS_OUTTOLUNCH: return PF2_OUTTOLUNCH;
+ case ID_STATUS_OFFLINE: return MODEF_OFFLINE;
+ }
+ return 0;
+}
+
+int fnIsHiddenMode(struct ClcData *dat, int status)
+{
+ return dat->offlineModes & cli.pfnClcStatusToPf2(status);
+}
+
+void fnHideInfoTip(HWND, struct ClcData *dat)
+{
+ CLCINFOTIP it = { 0 };
+
+ if (dat->hInfoTipItem == NULL)
+ return;
+ it.isGroup = IsHContactGroup(dat->hInfoTipItem);
+ it.hItem = (HANDLE) ((UINT_PTR) dat->hInfoTipItem & ~HCONTACT_ISGROUP);
+ it.cbSize = sizeof(it);
+ dat->hInfoTipItem = NULL;
+ NotifyEventHooks(hHideInfoTipEvent, 0, (LPARAM) & it);
+}
+
+void fnNotifyNewContact(HWND hwnd, HANDLE hContact)
+{
+ NMCLISTCONTROL nm;
+ nm.hdr.code = CLN_NEWCONTACT;
+ nm.hdr.hwndFrom = hwnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hwnd);
+ nm.flags = 0;
+ nm.hItem = hContact;
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & nm);
+}
+
+DWORD fnGetDefaultExStyle(void)
+{
+ BOOL param;
+ DWORD ret = CLCDEFAULT_EXSTYLE;
+ if (SystemParametersInfo(SPI_GETLISTBOXSMOOTHSCROLLING, 0, &param, FALSE) && !param)
+ ret |= CLS_EX_NOSMOOTHSCROLLING;
+ if (SystemParametersInfo(SPI_GETHOTTRACKING, 0, &param, FALSE) && !param)
+ ret &= ~CLS_EX_TRACKSELECT;
+ return ret;
+}
+
+#define DBFONTF_BOLD 1
+#define DBFONTF_ITALIC 2
+#define DBFONTF_UNDERLINE 4
+
+void fnGetDefaultFontSetting(int i, LOGFONT* lf, COLORREF* colour)
+{
+ SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), lf, FALSE);
+ *colour = GetSysColor(COLOR_WINDOWTEXT);
+ lf->lfHeight = 8;
+ switch (i) {
+ case FONTID_GROUPS:
+ lf->lfWeight = FW_BOLD;
+ break;
+ case FONTID_GROUPCOUNTS:
+ *colour = GetSysColor(COLOR_3DSHADOW);
+ break;
+ case FONTID_OFFINVIS:
+ case FONTID_INVIS:
+ lf->lfItalic = !lf->lfItalic;
+ break;
+ case FONTID_DIVIDERS:
+ break;
+ case FONTID_NOTONLIST:
+ *colour = GetSysColor(COLOR_3DSHADOW);
+ break;
+} }
+
+void fnGetFontSetting(int i, LOGFONT* lf, COLORREF* colour)
+{
+ DBVARIANT dbv;
+ char idstr[20];
+ BYTE style;
+
+ cli.pfnGetDefaultFontSetting(i, lf, colour);
+ mir_snprintf(idstr, SIZEOF(idstr), "Font%dName", i);
+ if ( !DBGetContactSettingTString(NULL, "CLC", idstr, &dbv )) {
+ lstrcpy(lf->lfFaceName, dbv.ptszVal);
+ mir_free(dbv.pszVal);
+ }
+ mir_snprintf(idstr, SIZEOF(idstr), "Font%dCol", i);
+ *colour = DBGetContactSettingDword(NULL, "CLC", idstr, *colour);
+ mir_snprintf(idstr, SIZEOF(idstr), "Font%dSize", i);
+ lf->lfHeight = (char) DBGetContactSettingByte(NULL, "CLC", idstr, lf->lfHeight);
+ mir_snprintf(idstr, SIZEOF(idstr), "Font%dSty", i);
+ style = (BYTE) DBGetContactSettingByte(NULL, "CLC", idstr, (lf->lfWeight == FW_NORMAL ? 0 : DBFONTF_BOLD) | (lf->lfItalic ? DBFONTF_ITALIC : 0) | (lf->lfUnderline ? DBFONTF_UNDERLINE : 0));
+ lf->lfWidth = lf->lfEscapement = lf->lfOrientation = 0;
+ lf->lfWeight = style & DBFONTF_BOLD ? FW_BOLD : FW_NORMAL;
+ lf->lfItalic = (style & DBFONTF_ITALIC) != 0;
+ lf->lfUnderline = (style & DBFONTF_UNDERLINE) != 0;
+ lf->lfStrikeOut = 0;
+ mir_snprintf(idstr, SIZEOF(idstr), "Font%dSet", i);
+ lf->lfCharSet = DBGetContactSettingByte(NULL, "CLC", idstr, lf->lfCharSet);
+ lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
+ lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ lf->lfQuality = DEFAULT_QUALITY;
+ lf->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+}
+
+void fnLoadClcOptions(HWND hwnd, struct ClcData *dat)
+{
+ dat->rowHeight = DBGetContactSettingByte(NULL, "CLC", "RowHeight", CLCDEFAULT_ROWHEIGHT);
+ {
+ int i;
+ LOGFONT lf;
+ SIZE fontSize;
+
+ HDC hdc = GetDC(hwnd);
+ for (i = 0; i <= FONTID_MAX; i++)
+ {
+ if (!dat->fontInfo[i].changed)
+ DeleteObject(dat->fontInfo[i].hFont);
+
+ cli.pfnGetFontSetting(i, &lf, &dat->fontInfo[i].colour);
+ lf.lfHeight = -MulDiv(lf.lfHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72);
+
+ dat->fontInfo[i].hFont = CreateFontIndirect(&lf);
+ dat->fontInfo[i].changed = 0;
+
+ HFONT holdfont = (HFONT)SelectObject(hdc,dat->fontInfo[i].hFont);
+ GetTextExtentPoint32(hdc, _T("x"), 1, &fontSize);
+ SelectObject(hdc, holdfont);
+
+ dat->fontInfo[i].fontHeight = fontSize.cy;
+ }
+ ReleaseDC(hwnd, hdc);
+ }
+ dat->leftMargin = DBGetContactSettingByte(NULL, "CLC", "LeftMargin", CLCDEFAULT_LEFTMARGIN);
+ dat->exStyle = DBGetContactSettingDword(NULL, "CLC", "ExStyle", cli.pfnGetDefaultExStyle());
+ dat->scrollTime = DBGetContactSettingWord(NULL, "CLC", "ScrollTime", CLCDEFAULT_SCROLLTIME);
+ dat->groupIndent = DBGetContactSettingByte(NULL, "CLC", "GroupIndent", CLCDEFAULT_GROUPINDENT);
+ dat->gammaCorrection = DBGetContactSettingByte(NULL, "CLC", "GammaCorrect", CLCDEFAULT_GAMMACORRECT);
+ dat->showIdle = DBGetContactSettingByte(NULL, "CLC", "ShowIdle", CLCDEFAULT_SHOWIDLE);
+ dat->noVScrollbar = DBGetContactSettingByte(NULL, "CLC", "NoVScrollBar", 0);
+ SendMessage(hwnd, INTM_SCROLLBARCHANGED, 0, 0);
+ if (!dat->bkChanged) {
+ DBVARIANT dbv;
+ dat->bkColour = DBGetContactSettingDword(NULL, "CLC", "BkColour", CLCDEFAULT_BKCOLOUR);
+ if (dat->hBmpBackground) {
+ DeleteObject(dat->hBmpBackground);
+ dat->hBmpBackground = NULL;
+ }
+ if (DBGetContactSettingByte(NULL, "CLC", "UseBitmap", CLCDEFAULT_USEBITMAP)) {
+ if (!DBGetContactSettingString(NULL, "CLC", "BkBitmap", &dbv)) {
+ dat->hBmpBackground = (HBITMAP) CallService(MS_UTILS_LOADBITMAP, 0, (LPARAM) dbv.pszVal);
+ mir_free(dbv.pszVal);
+ }
+ }
+ dat->backgroundBmpUse = DBGetContactSettingWord(NULL, "CLC", "BkBmpUse", CLCDEFAULT_BKBMPUSE);
+ }
+ dat->greyoutFlags = DBGetContactSettingDword(NULL, "CLC", "GreyoutFlags", CLCDEFAULT_GREYOUTFLAGS);
+ dat->offlineModes = DBGetContactSettingDword(NULL, "CLC", "OfflineModes", CLCDEFAULT_OFFLINEMODES);
+ dat->selBkColour = DBGetContactSettingDword(NULL, "CLC", "SelBkColour", CLCDEFAULT_SELBKCOLOUR);
+ dat->selTextColour = DBGetContactSettingDword(NULL, "CLC", "SelTextColour", CLCDEFAULT_SELTEXTCOLOUR);
+ dat->hotTextColour = DBGetContactSettingDword(NULL, "CLC", "HotTextColour", CLCDEFAULT_HOTTEXTCOLOUR);
+ dat->quickSearchColour = DBGetContactSettingDword(NULL, "CLC", "QuickSearchColour", CLCDEFAULT_QUICKSEARCHCOLOUR);
+ dat->useWindowsColours = DBGetContactSettingByte(NULL, "CLC", "UseWinColours", CLCDEFAULT_USEWINDOWSCOLOURS);
+ {
+ NMHDR hdr;
+ hdr.code = CLN_OPTIONSCHANGED;
+ hdr.hwndFrom = hwnd;
+ hdr.idFrom = GetDlgCtrlID(hwnd);
+ SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM) & hdr);
+ }
+ SendMessage(hwnd, WM_SIZE, 0, 0);
+}
+
+#define GSIF_HASMEMBERS 0x80000000
+#define GSIF_ALLCHECKED 0x40000000
+#define GSIF_INDEXMASK 0x3FFFFFFF
+void fnRecalculateGroupCheckboxes(HWND, struct ClcData *dat)
+{
+ struct ClcGroup *group;
+ int check;
+
+ group = &dat->list;
+ group->scanIndex = GSIF_ALLCHECKED;
+ for (;;) {
+ if ((group->scanIndex & GSIF_INDEXMASK) == group->cl.count) {
+ check = (group->scanIndex & (GSIF_HASMEMBERS | GSIF_ALLCHECKED)) == (GSIF_HASMEMBERS | GSIF_ALLCHECKED);
+ if (group->parent == NULL)
+ break;
+ group->parent->scanIndex |= group->scanIndex & GSIF_HASMEMBERS;
+ group = group->parent;
+ if (check)
+ group->cl.items[(group->scanIndex & GSIF_INDEXMASK)]->flags |= CONTACTF_CHECKED;
+ else {
+ group->cl.items[(group->scanIndex & GSIF_INDEXMASK)]->flags &= ~CONTACTF_CHECKED;
+ group->scanIndex &= ~GSIF_ALLCHECKED;
+ }
+ }
+ else if (group->cl.items[(group->scanIndex & GSIF_INDEXMASK)]->type == CLCIT_GROUP) {
+ group = group->cl.items[(group->scanIndex & GSIF_INDEXMASK)]->group;
+ group->scanIndex = GSIF_ALLCHECKED;
+ continue;
+ }
+ else if (group->cl.items[(group->scanIndex & GSIF_INDEXMASK)]->type == CLCIT_CONTACT) {
+ group->scanIndex |= GSIF_HASMEMBERS;
+ if (!(group->cl.items[(group->scanIndex & GSIF_INDEXMASK)]->flags & CONTACTF_CHECKED))
+ group->scanIndex &= ~GSIF_ALLCHECKED;
+ }
+ group->scanIndex++;
+ }
+}
+
+void fnSetGroupChildCheckboxes(struct ClcGroup *group, int checked)
+{
+ int i;
+
+ for (i = 0; i < group->cl.count; i++) {
+ if (group->cl.items[i]->type == CLCIT_GROUP) {
+ cli.pfnSetGroupChildCheckboxes(group->cl.items[i]->group, checked);
+ if (checked)
+ group->cl.items[i]->flags |= CONTACTF_CHECKED;
+ else
+ group->cl.items[i]->flags &= ~CONTACTF_CHECKED;
+ }
+ else if (group->cl.items[i]->type == CLCIT_CONTACT) {
+ if (checked)
+ group->cl.items[i]->flags |= CONTACTF_CHECKED;
+ else
+ group->cl.items[i]->flags &= ~CONTACTF_CHECKED;
+ }
+ }
+}
+
+void fnInvalidateItem(HWND hwnd, struct ClcData *dat, int iItem)
+{
+ RECT rc;
+ if ( iItem == -1 )
+ return;
+
+ GetClientRect(hwnd, &rc);
+ rc.top = cli.pfnGetRowTopY(dat, iItem) - dat->yScroll;
+ rc.bottom = rc.top + cli.pfnGetRowHeight(dat, iItem);
+ cli.pfnInvalidateRect(hwnd, &rc, FALSE);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// row coord functions
+
+int fnGetRowTopY(struct ClcData *dat, int item)
+{ return item * dat->rowHeight;
+}
+
+int fnGetRowBottomY(struct ClcData *dat, int item)
+{ return (item+1) * dat->rowHeight;
+}
+
+int fnGetRowTotalHeight(struct ClcData *dat)
+{ return dat->rowHeight * cli.pfnGetGroupContentsCount(&dat->list, 1);
+}
+
+int fnGetRowHeight(struct ClcData *dat, int)
+{ return dat->rowHeight;
+}
+
+int fnRowHitTest(struct ClcData *dat, int y)
+{ if (!dat->rowHeight)
+ return y;
+ return y / dat->rowHeight;
+}
diff --git a/src/modules/clist/clistcore.cpp b/src/modules/clist/clistcore.cpp
new file mode 100644
index 0000000000..2fe4a288e9
--- /dev/null
+++ b/src/modules/clist/clistcore.cpp
@@ -0,0 +1,224 @@
+/*
+
+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 "clc.h"
+#include "genmenu.h"
+
+CLIST_INTERFACE cli = { 0 };
+
+static TCHAR szTip[MAX_TIP_SIZE+1];
+
+int LoadContactListModule2( void );
+int LoadCLCModule( void );
+void BuildProtoMenus( void );
+
+static int interfaceInited = 0;
+
+static void fnPaintClc( HWND, ClcData*, HDC, RECT* )
+{
+}
+
+static struct ClcContact* fnCreateClcContact( void )
+{
+ return ( struct ClcContact* )mir_calloc( sizeof( struct ClcContact ));
+}
+
+static BOOL fnInvalidateRect( HWND hwnd, CONST RECT* lpRect,BOOL bErase )
+{
+ return InvalidateRect( hwnd, lpRect, bErase );
+}
+
+static void fnOnCreateClc( void )
+{
+}
+
+static void fnReloadProtoMenus( void )
+{
+ RebuildMenuOrder();
+ if (DBGetContactSettingByte(NULL, "CList", "MoveProtoMenus", FALSE))
+ BuildProtoMenus();
+ cli.pfnCluiProtocolStatusChanged(0,0);
+}
+
+static INT_PTR srvRetrieveInterface( WPARAM, LPARAM lParam )
+{
+ int rc;
+
+ if ( interfaceInited == 0 ) {
+ cli.version = 6;
+ cli.bDisplayLocked = TRUE;
+
+ cli.pfnClcOptionsChanged = fnClcOptionsChanged;
+ cli.pfnClcBroadcast = fnClcBroadcast;
+ cli.pfnContactListControlWndProc = fnContactListControlWndProc;
+ cli.pfnBuildGroupPopupMenu = fnBuildGroupPopupMenu;
+
+ cli.pfnRegisterFileDropping = fnRegisterFileDropping;
+ cli.pfnUnregisterFileDropping = fnUnregisterFileDropping;
+
+ cli.pfnGetRowsPriorTo = fnGetRowsPriorTo;
+ cli.pfnFindItem = fnFindItem;
+ cli.pfnGetRowByIndex = fnGetRowByIndex;
+ cli.pfnContactToHItem = fnContactToHItem;
+ cli.pfnContactToItemHandle = fnContactToItemHandle;
+
+ cli.pfnAddGroup = fnAddGroup;
+ cli.pfnAddItemToGroup = fnAddItemToGroup;
+ cli.pfnCreateClcContact = fnCreateClcContact;
+ cli.pfnRemoveItemFromGroup = fnRemoveItemFromGroup;
+ cli.pfnFreeContact = fnFreeContact;
+ cli.pfnFreeGroup = fnFreeGroup;
+ cli.pfnAddInfoItemToGroup = fnAddInfoItemToGroup;
+ cli.pfnAddContactToGroup = fnAddContactToGroup;
+ cli.pfnAddContactToTree = fnAddContactToTree;
+ cli.pfnDeleteItemFromTree = fnDeleteItemFromTree;
+ cli.pfnRebuildEntireList = fnRebuildEntireList;
+ cli.pfnGetGroupContentsCount = fnGetGroupContentsCount;
+ cli.pfnSortCLC = fnSortCLC;
+ cli.pfnSaveStateAndRebuildList = fnSaveStateAndRebuildList;
+
+ cli.pfnProcessExternalMessages = fnProcessExternalMessages;
+
+ cli.pfnPaintClc = fnPaintClc;
+
+ cli.pfnGetGroupCountsText = fnGetGroupCountsText;
+ cli.pfnHitTest = fnHitTest;
+ cli.pfnScrollTo = fnScrollTo;
+ cli.pfnEnsureVisible = fnEnsureVisible;
+ cli.pfnRecalcScrollBar = fnRecalcScrollBar;
+ cli.pfnSetGroupExpand = fnSetGroupExpand;
+ cli.pfnDoSelectionDefaultAction = fnDoSelectionDefaultAction;
+ cli.pfnFindRowByText = fnFindRowByText;
+ cli.pfnEndRename = fnEndRename;
+ cli.pfnDeleteFromContactList = fnDeleteFromContactList;
+ cli.pfnBeginRenameSelection = fnBeginRenameSelection;
+ cli.pfnCalcEipPosition = fnCalcEipPosition;
+ cli.pfnGetDropTargetInformation = fnGetDropTargetInformation;
+ cli.pfnClcStatusToPf2 = fnClcStatusToPf2;
+ cli.pfnIsHiddenMode = fnIsHiddenMode;
+ cli.pfnHideInfoTip = fnHideInfoTip;
+ cli.pfnNotifyNewContact = fnNotifyNewContact;
+ cli.pfnGetDefaultExStyle = fnGetDefaultExStyle;
+ cli.pfnGetDefaultFontSetting = fnGetDefaultFontSetting;
+ cli.pfnGetFontSetting = fnGetFontSetting;
+ cli.pfnLoadClcOptions = fnLoadClcOptions;
+ cli.pfnRecalculateGroupCheckboxes = fnRecalculateGroupCheckboxes;
+ cli.pfnSetGroupChildCheckboxes = fnSetGroupChildCheckboxes;
+ cli.pfnInvalidateItem = fnInvalidateItem;
+ cli.pfnGetRowBottomY = fnGetRowBottomY;
+ cli.pfnGetRowHeight = fnGetRowHeight;
+ cli.pfnGetRowTopY = fnGetRowTopY;
+ cli.pfnGetRowTotalHeight = fnGetRowTotalHeight;
+ cli.pfnRowHitTest = fnRowHitTest;
+
+ cli.pfnAddEvent = fnAddEvent;
+ cli.pfnCreateEvent = fnCreateEvent;
+ cli.pfnEventsProcessContactDoubleClick = fnEventsProcessContactDoubleClick;
+ cli.pfnEventsProcessTrayDoubleClick = fnEventsProcessTrayDoubleClick;
+ cli.pfnFreeEvent = fnFreeEvent;
+ cli.pfnGetEvent = fnGetEvent;
+ cli.pfnGetImlIconIndex = fnGetImlIconIndex;
+ cli.pfnRemoveEvent = fnRemoveEvent;
+
+ cli.pfnGetContactDisplayName = fnGetContactDisplayName;
+ cli.pfnInvalidateDisplayNameCacheEntry = fnInvalidateDisplayNameCacheEntry;
+ cli.pfnCreateCacheItem = fnCreateCacheItem;
+ cli.pfnCheckCacheItem = fnCheckCacheItem;
+ cli.pfnFreeCacheItem = fnFreeCacheItem;
+ cli.pfnGetCacheEntry = fnGetCacheEntry;
+
+ cli.szTip = szTip;
+ cli.pfnInitTray = fnInitTray;
+ cli.pfnUninitTray = fnUninitTray;
+ cli.pfnLockTray = fnLockTray;
+ cli.pfnUnlockTray = fnUnlockTray;
+
+ cli.pfnTrayCycleTimerProc = fnTrayCycleTimerProc;
+ cli.pfnTrayIconAdd = fnTrayIconAdd;
+ cli.pfnTrayIconDestroy = fnTrayIconDestroy;
+ cli.pfnTrayIconIconsChanged = fnTrayIconIconsChanged;
+ cli.pfnTrayIconInit = fnTrayIconInit;
+ cli.pfnTrayIconMakeTooltip = fnTrayIconMakeTooltip;
+ cli.pfnTrayIconPauseAutoHide = fnTrayIconPauseAutoHide;
+ cli.pfnTrayIconProcessMessage = fnTrayIconProcessMessage;
+ cli.pfnTrayIconRemove = fnTrayIconRemove;
+ cli.pfnTrayIconSetBaseInfo = fnTrayIconSetBaseInfo;
+ cli.pfnTrayIconSetToBase = fnTrayIconSetToBase;
+ cli.pfnTrayIconTaskbarCreated = fnTrayIconTaskbarCreated;
+ cli.pfnTrayIconUpdate = fnTrayIconUpdate;
+ cli.pfnTrayIconUpdateBase = fnTrayIconUpdateBase;
+ cli.pfnTrayIconUpdateWithImageList = fnTrayIconUpdateWithImageList;
+ cli.pfnCListTrayNotify = fnCListTrayNotify;
+
+ cli.pfnContactListWndProc = fnContactListWndProc;
+ cli.pfnLoadCluiGlobalOpts = fnLoadCluiGlobalOpts;
+ cli.pfnCluiProtocolStatusChanged = fnCluiProtocolStatusChanged;
+ cli.pfnDrawMenuItem = fnDrawMenuItem;
+ cli.pfnInvalidateRect = fnInvalidateRect;
+ cli.pfnOnCreateClc = fnOnCreateClc;
+
+ cli.pfnChangeContactIcon = fnChangeContactIcon;
+ cli.pfnLoadContactTree = fnLoadContactTree;
+ cli.pfnCompareContacts = fnCompareContacts;
+ cli.pfnSortContacts = fnSortContacts;
+ cli.pfnSetHideOffline = fnSetHideOffline;
+
+ cli.pfnDocking_ProcessWindowMessage = fnDocking_ProcessWindowMessage;
+
+ cli.pfnGetIconFromStatusMode = fnGetIconFromStatusMode;
+ cli.pfnGetWindowVisibleState = fnGetWindowVisibleState;
+ cli.pfnIconFromStatusMode = fnIconFromStatusMode;
+ cli.pfnShowHide = fnShowHide;
+ cli.pfnGetStatusModeDescription = fnGetStatusModeDescription;
+
+ cli.pfnGetGroupName = fnGetGroupName;
+ cli.pfnRenameGroup = fnRenameGroup;
+
+ cli.pfnHotKeysRegister = fnHotKeysRegister;
+ cli.pfnHotKeysUnregister = fnHotKeysUnregister;
+ cli.pfnHotKeysProcess = fnHotKeysProcess;
+ cli.pfnHotkeysProcessMessage = fnHotkeysProcessMessage;
+
+ cli.pfnGetProtocolVisibility = fnGetProtocolVisibility;
+ cli.pfnGetProtoIndexByPos = fnGetProtoIndexByPos;
+ cli.pfnReloadProtoMenus = fnReloadProtoMenus;
+ cli.pfnGetAccountIndexByPos = fnGetAccountIndexByPos;
+ cli.pfnGetProtocolMenu = fnGetProtocolMenu;
+
+ cli.hInst = ( HMODULE )lParam;
+
+ rc = LoadContactListModule2();
+ if (rc == 0)
+ rc = LoadCLCModule();
+ interfaceInited = 1;
+ }
+
+ return ( LPARAM )&cli;
+}
+
+int LoadContactListModule()
+{
+ CreateServiceFunction( MS_CLIST_RETRIEVE_INTERFACE, srvRetrieveInterface );
+ return 0;
+}
diff --git a/src/modules/clist/clistevents.cpp b/src/modules/clist/clistevents.cpp
new file mode 100644
index 0000000000..20f5995c4e
--- /dev/null
+++ b/src/modules/clist/clistevents.cpp
@@ -0,0 +1,441 @@
+/*
+
+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 "clc.h"
+
+struct CListEvent
+{
+ int imlIconIndex;
+ int flashesDone;
+ CLISTEVENT cle;
+};
+
+struct CListImlIcon
+{
+ int index;
+ HICON hIcon;
+};
+static struct CListImlIcon *imlIcon;
+static int imlIconCount;
+
+extern HIMAGELIST hCListImages;
+
+static UINT_PTR flashTimerId;
+static int iconsOn;
+static int disableTrayFlash;
+static int disableIconFlash;
+
+int fnGetImlIconIndex(HICON hIcon)
+{
+ int i;
+
+ for (i = 0; i < imlIconCount; i++) {
+ if (imlIcon[i].hIcon == hIcon)
+ return imlIcon[i].index;
+ }
+ imlIcon = (struct CListImlIcon *) mir_realloc(imlIcon, sizeof(struct CListImlIcon) * (imlIconCount + 1));
+ imlIconCount++;
+ imlIcon[i].hIcon = hIcon;
+ imlIcon[i].index = ImageList_AddIcon(hCListImages, hIcon);
+ return imlIcon[i].index;
+}
+
+static char * GetEventProtocol(int idx)
+{
+ if (cli.events.count && idx>=0 && idx<cli.events.count)
+ {
+ char *szProto;
+ if (cli.events.items[idx]->cle.hContact == NULL)
+ {
+ if (cli.events.items[idx]->cle.flags&CLEF_PROTOCOLGLOBAL)
+ szProto = cli.events.items[idx]->cle.lpszProtocol;
+ else
+ szProto = NULL;
+ }
+ else
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) cli.events.items[idx]->cle.hContact, 0);
+ return szProto;
+ }
+ return NULL;
+}
+
+static void ShowOneEventInTray(int idx)
+{
+ cli.pfnTrayIconUpdateWithImageList((iconsOn || disableTrayFlash) ? cli.events.items[idx]->imlIconIndex : 0, cli.events.items[idx]->cle.ptszTooltip, GetEventProtocol(idx));
+}
+
+static void ShowEventsInTray()
+{
+ int i;
+ char ** pTrayProtos;
+ char nTrayProtoCnt;
+ int nTrayCnt=cli.trayIconCount;
+ if (!cli.events.count || !nTrayCnt) return;
+ if (cli.events.count ==1 || nTrayCnt == 1)
+ {
+ ShowOneEventInTray(0); //for only one icon in tray show topmost event
+ return;
+ }
+
+ // in case if we have several icons in tray and several events with different protocols
+ // lets use several icon to show events from protocols in different icons
+ cli.pfnLockTray();
+ pTrayProtos = (char**)_alloca(sizeof(char*)*cli.trayIconCount);
+ nTrayProtoCnt=0;
+ for (i=0; i<cli.trayIconCount; i++)
+ {
+ if (cli.trayIcon[i].id == 0 || !cli.trayIcon[i].szProto) continue;
+ pTrayProtos[nTrayProtoCnt++]=cli.trayIcon[i].szProto;
+ }
+ for (i=0; i<cli.events.count; i++)
+ {
+ char * iEventProto=GetEventProtocol(i);
+ {
+ int j;
+ for (j=0; j<nTrayProtoCnt; j++)
+ if ( iEventProto && pTrayProtos[j] && !lstrcmpA(pTrayProtos[j],iEventProto))
+ break;
+ if ( j>=nTrayProtoCnt ) j=0; //event was not found so assume first icon
+ if ( pTrayProtos[j] ) //if not already set
+ ShowOneEventInTray(i); //show it
+ pTrayProtos[j]=NULL; //and clear slot
+ }
+ }
+ cli.pfnUnlockTray();
+}
+
+static VOID CALLBACK IconFlashTimer(HWND, UINT, UINT_PTR idEvent, DWORD)
+{
+ int i, j;
+ ShowEventsInTray();
+ for (i = 0; i < cli.events.count; i++) {
+ for (j = 0; j < i; j++)
+ if (cli.events.items[j]->cle.hContact == cli.events.items[i]->cle.hContact)
+ break;
+ if (j >= i)
+ cli.pfnChangeContactIcon(cli.events.items[i]->cle.hContact, iconsOn || disableIconFlash ? cli.events.items[i]->imlIconIndex : 0, 0);
+ //decrease eflashes in any case - no need to collect all events
+ if (cli.events.items[i]->cle.flags & CLEF_ONLYAFEW) {
+ if (0 >= --cli.events.items[i]->flashesDone)
+ cli.pfnRemoveEvent( cli.events.items[i]->cle.hContact, cli.events.items[i]->cle.hDbEvent);
+ } }
+
+ if (cli.events.count == 0) {
+ KillTimer(NULL, idEvent);
+ cli.pfnTrayIconSetToBase( NULL );
+ }
+
+ iconsOn = !iconsOn;
+}
+
+struct CListEvent* fnAddEvent( CLISTEVENT *cle )
+{
+ int i;
+ struct CListEvent* p;
+
+ if (cle==NULL || cle->cbSize != sizeof(CLISTEVENT))
+ return NULL;
+
+ if (cle->flags & CLEF_URGENT) {
+ for (i = 0; i < cli.events.count; i++)
+ if (!(cli.events.items[i]->cle.flags & CLEF_URGENT))
+ break;
+ }
+ else i = cli.events.count;
+
+ if (( p = ( struct CListEvent* )cli.pfnCreateEvent()) == NULL )
+ return NULL;
+
+ List_Insert(( SortedList* )&cli.events, p, i );
+ p->cle = *cle;
+ p->imlIconIndex = fnGetImlIconIndex(cli.events.items[i]->cle.hIcon);
+ p->flashesDone = 12;
+ p->cle.pszService = mir_strdup(cli.events.items[i]->cle.pszService);
+ #if defined( _UNICODE )
+ if (p->cle.flags & CLEF_UNICODE)
+ p->cle.ptszTooltip = mir_tstrdup((TCHAR*)p->cle.ptszTooltip);
+ else
+ p->cle.ptszTooltip = mir_a2u((char*)p->cle.pszTooltip); //if no flag defined it handled as unicode
+ #else
+ p->cle.ptszTooltip = mir_tstrdup(p->cle.ptszTooltip);
+ #endif
+ if (cli.events.count == 1) {
+ char *szProto;
+ if (cle->hContact == NULL)
+ {
+ if (cle->flags&CLEF_PROTOCOLGLOBAL)
+ szProto = cle->lpszProtocol;
+ else
+ szProto=NULL;
+ }
+ else
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)cle->hContact, 0);
+ iconsOn = 1;
+ flashTimerId = SetTimer(NULL, 0, DBGetContactSettingWord(NULL, "CList", "IconFlashTime", 550), IconFlashTimer);
+ cli.pfnTrayIconUpdateWithImageList( p->imlIconIndex, p->cle.ptszTooltip, szProto);
+ }
+ cli.pfnChangeContactIcon(cle->hContact, p->imlIconIndex, 1);
+ cli.pfnSortContacts();
+ return p;
+}
+
+// Removes an event from the contact list's queue
+// Returns 0 if the event was successfully removed, or nonzero if the event was not found
+int fnRemoveEvent( HANDLE hContact, HANDLE dbEvent )
+{
+ int i;
+ char *szProto;
+ int nSameProto=0;
+
+ // Find the event that should be removed
+ for (i = 0; i < cli.events.count; i++)
+ if ((cli.events.items[i]->cle.hContact == hContact) && (cli.events.items[i]->cle.hDbEvent == dbEvent))
+ break;
+
+ // Event was not found
+ if (i == cli.events.count)
+ return 1;
+
+ // Update contact's icon
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ cli.pfnChangeContactIcon(cli.events.items[i]->cle.hContact,
+ CallService(MS_CLIST_GETCONTACTICON, (WPARAM)cli.events.items[i]->cle.hContact, 1),
+ 0);
+
+ // Free any memory allocated to the event
+ cli.pfnFreeEvent( cli.events.items[i] );
+ List_Remove(( SortedList* )&cli.events, i );
+ {
+ //count same protocoled events
+ char * szEventProto;
+ for (i = 0; i < cli.events.count; i++)
+ {
+ if (cli.events.items[i]->cle.hContact)
+ szEventProto=(char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)(cli.events.items[i]->cle.hContact), 0);
+ else if (cli.events.items[i]->cle.flags&CLEF_PROTOCOLGLOBAL)
+ szEventProto=(char *) cli.events.items[i]->cle.lpszProtocol;
+ else
+ szEventProto = NULL;
+ if (szEventProto && szProto && !lstrcmpA(szEventProto,szProto))
+ nSameProto++;
+
+ }
+
+ }
+ if (cli.events.count == 0 || nSameProto == 0) {
+ if (cli.events.count == 0)
+ KillTimer(NULL, flashTimerId);
+ cli.pfnTrayIconSetToBase( hContact == NULL ? NULL : szProto);
+ }
+ else {
+ if (cli.events.items[0]->cle.hContact == NULL)
+ szProto = NULL;
+ else
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) cli.events.items[0]->cle.hContact, 0);
+ cli.pfnTrayIconUpdateWithImageList(iconsOn ? cli.events.items[0]->imlIconIndex : 0, cli.events.items[0]->cle.ptszTooltip, szProto);
+ }
+
+ return 0;
+}
+
+CLISTEVENT* fnGetEvent( HANDLE hContact, int idx )
+{
+ if ( hContact == INVALID_HANDLE_VALUE) {
+ if (idx >= cli.events.count)
+ return NULL;
+ return &cli.events.items[idx]->cle;
+ }
+
+ for (int i = 0; i < cli.events.count; i++)
+ if (cli.events.items[i]->cle.hContact == hContact)
+ if (idx-- == 0)
+ return &cli.events.items[i]->cle;
+ return NULL;
+}
+
+int fnEventsProcessContactDoubleClick(HANDLE hContact)
+{
+ for (int i = 0; i < cli.events.count; i++) {
+ if (cli.events.items[i]->cle.hContact == hContact) {
+ HANDLE hDbEvent = cli.events.items[i]->cle.hDbEvent;
+ CallService(cli.events.items[i]->cle.pszService, (WPARAM) (HWND) NULL, (LPARAM) & cli.events.items[i]->cle);
+ cli.pfnRemoveEvent(hContact, hDbEvent);
+ return 0;
+ } }
+
+ return 1;
+}
+
+int fnEventsProcessTrayDoubleClick(int index)
+{
+ BOOL click_in_first_icon=FALSE;
+ if (cli.events.count) {
+ HANDLE hContact, hDbEvent;
+ int eventIndex=0;
+ cli.pfnLockTray();
+ if (cli.trayIconCount>1 && index>0) {
+ int i;
+ char * szProto=NULL;
+ for (i=0; i<cli.trayIconCount; i++)
+ if (cli.trayIcon[i].id==index) {
+ szProto=cli.trayIcon[i].szProto;
+ if (i==0) click_in_first_icon=TRUE;
+ break;
+ }
+ if (szProto) {
+ for(i=0; i<cli.events.count; i++) {
+ char * eventProto=NULL;
+ if (cli.events.items[i]->cle.hContact)
+ eventProto=(char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)cli.events.items[i]->cle.hContact, 0);
+ if (!eventProto)
+ eventProto=cli.events.items[i]->cle.lpszProtocol;
+
+ if (!eventProto || !_strcmpi(eventProto, szProto)) {
+ eventIndex=i;
+ break;
+ } }
+
+ if (i==cli.events.count) { //EventNotFound
+ //lets process backward try to find first event without desired proto in tray
+ int j;
+ if (click_in_first_icon)
+ for(i=0; i<cli.events.count; i++) {
+ char * eventProto=NULL;
+ if (cli.events.items[i]->cle.hContact)
+ eventProto=(char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)cli.events.items[i]->cle.hContact, 0);
+ if (!eventProto)
+ eventProto=cli.events.items[i]->cle.lpszProtocol;
+ if (eventProto) {
+ for (j=0; j<cli.trayIconCount; j++)
+ if (cli.trayIcon[j].szProto && !_strcmpi(eventProto, cli.trayIcon[j].szProto))
+ break;
+
+ if (j==cli.trayIconCount) {
+ eventIndex=i;
+ break;
+ } } }
+ if (i==cli.events.count) { //not found
+ cli.pfnUnlockTray();
+ return 1; //continue processing to show contact list
+ } } } }
+
+ cli.pfnUnlockTray();
+ hContact = cli.events.items[eventIndex]->cle.hContact;
+ hDbEvent = cli.events.items[eventIndex]->cle.hDbEvent;
+ //if (!ServiceExists(cli.events.items[eventIndex]->cle.pszService))
+ // ; may be better to show send msg?
+ CallService(cli.events.items[eventIndex]->cle.pszService, (WPARAM) NULL, (LPARAM) & cli.events.items[eventIndex]->cle);
+ cli.pfnRemoveEvent(hContact, hDbEvent);
+ return 0;
+ }
+ return 1;
+}
+
+static int RemoveEventsForContact(WPARAM wParam, LPARAM)
+{
+ int j, hit;
+
+ /*
+ the for(;;) loop is used here since the cli.events.count can not be relied upon to take us
+ thru the cli.events.items[] array without suffering from shortsightedness about how many unseen
+ events remain, e.g. three events, we remove the first, we're left with 2, the event
+ loop exits at 2 and we never see the real new 2.
+ */
+
+ for (; cli.events.count > 0;) {
+ for (hit = 0, j = 0; j < cli.events.count; j++) {
+ if (cli.events.items[j]->cle.hContact == (HANDLE) wParam) {
+ cli.pfnRemoveEvent((HANDLE)wParam, cli.events.items[j]->cle.hDbEvent);
+ hit = 1;
+ }
+ }
+ if (j == cli.events.count && hit == 0)
+ return 0; /* got to the end of the array and didnt remove anything */
+ }
+
+ return 0;
+}
+
+static int CListEventSettingsChanged(WPARAM wParam, LPARAM lParam)
+{
+ HANDLE hContact = (HANDLE) wParam;
+ DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING *) lParam;
+ if (hContact == NULL && cws && cws->szModule && cws->szSetting && strcmp(cws->szModule, "CList") == 0) {
+ if (strcmp(cws->szSetting, "DisableTrayFlash") == 0)
+ disableTrayFlash = (int) cws->value.bVal;
+ else if (strcmp(cws->szSetting, "NoIconBlink") == 0)
+ disableIconFlash = (int) cws->value.bVal;
+ }
+ return 0;
+}
+
+/***************************************************************************************/
+
+INT_PTR AddEventSyncStub(WPARAM wParam, LPARAM lParam) { return CallServiceSync(MS_CLIST_ADDEVENT"_SYNC",wParam, lParam); }
+INT_PTR AddEventStub(WPARAM, LPARAM lParam) { return cli.pfnAddEvent((CLISTEVENT*)lParam ) == NULL; }
+INT_PTR RemoveEventStub(WPARAM wParam, LPARAM lParam) { return cli.pfnRemoveEvent((HANDLE)wParam,(HANDLE)lParam ); }
+INT_PTR GetEventStub(WPARAM wParam, LPARAM lParam) { return (INT_PTR)cli.pfnGetEvent((HANDLE)wParam,(int)lParam); }
+
+int InitCListEvents(void)
+{
+ memset( &cli.events, 0, sizeof(cli.events));
+ cli.events.increment = 10;
+
+ disableTrayFlash = DBGetContactSettingByte(NULL, "CList", "DisableTrayFlash", 0);
+ disableIconFlash = DBGetContactSettingByte(NULL, "CList", "NoIconBlink", 0);
+ CreateServiceFunction(MS_CLIST_ADDEVENT, AddEventSyncStub); //need to be called through sync to keep flash timer workable
+ CreateServiceFunction(MS_CLIST_ADDEVENT"_SYNC", AddEventStub);
+ CreateServiceFunction(MS_CLIST_REMOVEEVENT, RemoveEventStub);
+ CreateServiceFunction(MS_CLIST_GETEVENT, GetEventStub);
+ HookEvent(ME_DB_CONTACT_DELETED, RemoveEventsForContact);
+ HookEvent(ME_DB_CONTACT_SETTINGCHANGED, CListEventSettingsChanged);
+ return 0;
+}
+
+struct CListEvent* fnCreateEvent( void )
+{
+ return (struct CListEvent*)mir_calloc( sizeof(struct CListEvent));
+}
+
+void fnFreeEvent( struct CListEvent* p )
+{
+ if ( p->cle.pszService )
+ mir_free( p->cle.pszService );
+ if ( p->cle.pszTooltip )
+ mir_free( p->cle.pszTooltip );
+ mir_free( p );
+}
+
+void UninitCListEvents(void)
+{
+ int i;
+
+ if (cli.events.count) KillTimer(NULL, flashTimerId);
+
+ for (i = 0; i < cli.events.count; i++)
+ cli.pfnFreeEvent(( struct CListEvent* )cli.events.items[i] );
+ List_Destroy(( SortedList* )&cli.events );
+
+ if ( imlIcon != NULL )
+ mir_free( imlIcon );
+}
diff --git a/src/modules/clist/clistmenus.cpp b/src/modules/clist/clistmenus.cpp
new file mode 100644
index 0000000000..6c2a4f7a3f
--- /dev/null
+++ b/src/modules/clist/clistmenus.cpp
@@ -0,0 +1,1443 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2010 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"
+#pragma hdrstop
+
+#include "m_hotkeys.h"
+
+#include "clc.h"
+#include "genmenu.h"
+
+#define MS_CLIST_HKSTATUS "Clist/HK/SetStatus"
+
+#define FIRSTCUSTOMMENUITEMID 30000
+#define MENU_CUSTOMITEMMAIN 0x80000000
+//#define MENU_CUSTOMITEMCONTEXT 0x40000000
+//#define MENU_CUSTOMITEMFRAME 0x20000000
+
+typedef struct {
+ WORD id;
+ int iconId;
+ CLISTMENUITEM mi;
+}
+ CListIntMenuItem,*lpCListIntMenuItem;
+
+//new menu sys
+HANDLE hMainMenuObject = 0;
+HANDLE hContactMenuObject = 0;
+HANDLE hStatusMenuObject = 0;
+int UnloadMoveToGroup(void);
+
+int statustopos(int status);
+void Proto_SetStatus(const char* szProto, unsigned status);
+
+bool prochotkey;
+
+HANDLE hPreBuildMainMenuEvent, hStatusModeChangeEvent, hPreBuildContactMenuEvent;
+
+static HANDLE hAckHook;
+
+static HMENU hMainMenu,hStatusMenu = 0;
+static const int statusModeList[ MAX_STATUS_COUNT ] =
+{
+ ID_STATUS_OFFLINE, ID_STATUS_ONLINE, ID_STATUS_AWAY, ID_STATUS_NA, ID_STATUS_OCCUPIED,
+ ID_STATUS_DND, ID_STATUS_FREECHAT, ID_STATUS_INVISIBLE, ID_STATUS_ONTHEPHONE, ID_STATUS_OUTTOLUNCH
+};
+
+static const int skinIconStatusList[ MAX_STATUS_COUNT ] =
+{
+ SKINICON_STATUS_OFFLINE, SKINICON_STATUS_ONLINE, SKINICON_STATUS_AWAY, SKINICON_STATUS_NA, SKINICON_STATUS_OCCUPIED,
+ SKINICON_STATUS_DND, SKINICON_STATUS_FREE4CHAT, SKINICON_STATUS_INVISIBLE, SKINICON_STATUS_ONTHEPHONE, SKINICON_STATUS_OUTTOLUNCH
+};
+
+static const int statusModePf2List[ MAX_STATUS_COUNT ] =
+{
+ 0xFFFFFFFF, PF2_ONLINE, PF2_SHORTAWAY, PF2_LONGAWAY, PF2_LIGHTDND,
+ PF2_HEAVYDND, PF2_FREECHAT, PF2_INVISIBLE, PF2_ONTHEPHONE, PF2_OUTTOLUNCH
+};
+
+static INT_PTR statusHotkeys[ MAX_STATUS_COUNT ];
+
+PMO_IntMenuItem* hStatusMainMenuHandles;
+int hStatusMainMenuHandlesCnt;
+
+typedef struct
+{
+ int protoindex;
+ int protostatus[ MAX_STATUS_COUNT ];
+ PMO_IntMenuItem menuhandle[ MAX_STATUS_COUNT ];
+}
+ tStatusMenuHandles,*lpStatusMenuHandles;
+
+lpStatusMenuHandles hStatusMenuHandles;
+int hStatusMenuHandlesCnt;
+
+//mainmenu exec param(ownerdata)
+typedef struct
+{
+ char *szServiceName;
+ TCHAR *szMenuName;
+ int Param1;
+}
+ MainMenuExecParam,*lpMainMenuExecParam;
+
+//contactmenu exec param(ownerdata)
+//also used in checkservice
+typedef struct
+{
+ char *szServiceName;
+ char *pszContactOwner;//for check proc
+ int param;
+}
+ ContactMenuExecParam,*lpContactMenuExecParam;
+
+typedef struct
+{
+ char *szProto;
+ int isOnList;
+ int isOnline;
+}
+ BuildContactParam;
+
+typedef struct
+{
+ char *proto; //This is unique protoname
+ int protoindex;
+ int status;
+
+ BOOL custom;
+ char *svc;
+ HANDLE hMenuItem;
+}
+ StatusMenuExecParam,*lpStatusMenuExecParam;
+
+typedef struct _MenuItemHandles
+{
+ HMENU OwnerMenu;
+ int position;
+}
+ MenuItemData;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// service functions
+
+void FreeMenuProtos( void )
+{
+ int i;
+
+ if ( cli.menuProtos ) {
+ for ( i=0; i < cli.menuProtoCount; i++ )
+ if ( cli.menuProtos[i].szProto )
+ mir_free(cli.menuProtos[i].szProto);
+
+ mir_free( cli.menuProtos );
+ cli.menuProtos = NULL;
+ }
+ cli.menuProtoCount = 0;
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+int GetAverageMode(int* pNetProtoCount = NULL)
+{
+ int netProtoCount = 0;
+ int averageMode = 0;
+
+ for ( int i=0; i < accounts.getCount(); i++ ) {
+ PROTOACCOUNT* pa = accounts[i];
+ if ( cli.pfnGetProtocolVisibility( pa->szModuleName ) == 0 )
+ continue;
+
+ netProtoCount++;
+
+ if ( averageMode == 0 )
+ averageMode = CallProtoService( pa->szModuleName, PS_GETSTATUS, 0, 0 );
+ else if ( averageMode > 0 && averageMode != CallProtoService( pa->szModuleName, PS_GETSTATUS, 0, 0 )) {
+ averageMode = -1;
+ if (pNetProtoCount == NULL) break;
+ }
+ }
+
+ if (pNetProtoCount) *pNetProtoCount = netProtoCount;
+ return averageMode;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// MAIN MENU
+
+/*
+wparam=handle to the menu item returned by MS_CLIST_ADDCONTACTMENUITEM
+return 0 on success.
+*/
+
+static INT_PTR RemoveMainMenuItem(WPARAM wParam, LPARAM)
+{
+ CallService(MO_REMOVEMENUITEM,wParam,0);
+ return 0;
+}
+
+static INT_PTR BuildMainMenu(WPARAM, LPARAM)
+{
+ ListParam param = { 0 };
+ param.MenuObjectHandle = hMainMenuObject;
+
+ NotifyEventHooks(hPreBuildMainMenuEvent,(WPARAM)0,(LPARAM)0);
+
+ CallService(MO_BUILDMENU,(WPARAM)hMainMenu,(LPARAM)&param);
+ DrawMenuBar((HWND)CallService("CLUI/GetHwnd",(WPARAM)0,(LPARAM)0));
+ return (INT_PTR)hMainMenu;
+}
+
+static INT_PTR AddMainMenuItem(WPARAM, LPARAM lParam)
+{
+ CLISTMENUITEM* mi = ( CLISTMENUITEM* )lParam;
+ if ( mi->cbSize != sizeof( CLISTMENUITEM ))
+ return NULL;
+
+ TMO_MenuItem tmi = { 0 };
+ tmi.cbSize = sizeof(tmi);
+ tmi.flags = mi->flags;
+ tmi.hIcon = mi->hIcon;
+ tmi.hotKey = mi->hotKey;
+ tmi.ptszName = mi->ptszName;
+ tmi.position = mi->position;
+
+ //pszPopupName for new system mean root level
+ //pszPopupName for old system mean that exists popup
+ tmi.root = ( HGENMENU )mi->pszPopupName;
+ {
+ lpMainMenuExecParam mmep;
+ mmep = ( lpMainMenuExecParam )mir_alloc( sizeof( MainMenuExecParam ));
+ if ( mmep == NULL )
+ return 0;
+
+ //we need just one parametr.
+ mmep->szServiceName = mir_strdup(mi->pszService);
+ mmep->Param1 = mi->popupPosition;
+ mmep->szMenuName = tmi.ptszName;
+ tmi.ownerdata=mmep;
+ }
+
+ PMO_IntMenuItem pimi = MO_AddNewMenuItem( hMainMenuObject, &tmi );
+
+ char* name;
+ bool needFree = false;
+
+ if (mi->pszService)
+ name = mi->pszService;
+ else if (mi->flags & CMIF_UNICODE) {
+ name = mir_t2a( mi->ptszName );
+ needFree = true;
+ }
+ else
+ name = mi->pszName;
+
+ MO_SetOptionsMenuItem( pimi, OPT_MENUITEMSETUNIQNAME, ( INT_PTR )name );
+ if (needFree) mir_free(name);
+
+ return ( INT_PTR )pimi;
+}
+
+int MainMenuCheckService(WPARAM, LPARAM)
+{
+ return 0;
+}
+
+//called with:
+//wparam - ownerdata
+//lparam - lparam from winproc
+INT_PTR MainMenuExecService(WPARAM wParam, LPARAM lParam)
+{
+ lpMainMenuExecParam mmep = ( lpMainMenuExecParam )wParam;
+ if ( mmep != NULL ) {
+ // bug in help.c,it used wparam as parent window handle without reason.
+ if ( !lstrcmpA(mmep->szServiceName,"Help/AboutCommand"))
+ mmep->Param1 = 0;
+
+ CallService(mmep->szServiceName,mmep->Param1,lParam);
+ }
+ return 1;
+}
+
+INT_PTR FreeOwnerDataMainMenu(WPARAM, LPARAM lParam)
+{
+ lpMainMenuExecParam mmep = ( lpMainMenuExecParam )lParam;
+ if ( mmep != NULL ) {
+ FreeAndNil(( void** )&mmep->szServiceName);
+ FreeAndNil(( void** )&mmep);
+ }
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// CONTACT MENU
+
+static INT_PTR RemoveContactMenuItem(WPARAM wParam, LPARAM)
+{
+ CallService(MO_REMOVEMENUITEM,wParam,0);
+ return 0;
+}
+
+static INT_PTR AddContactMenuItem(WPARAM, LPARAM lParam)
+{
+ CLISTMENUITEM *mi=(CLISTMENUITEM*)lParam;
+ if ( mi->cbSize != sizeof( CLISTMENUITEM ))
+ return 0;
+
+ TMO_MenuItem tmi = { 0 };
+ tmi.cbSize = sizeof(tmi);
+ tmi.flags = mi->flags;
+ tmi.hIcon = mi->hIcon;
+ tmi.hotKey = mi->hotKey;
+ tmi.position = mi->position;
+ tmi.ptszName = mi->ptszName;
+ tmi.root = ( HGENMENU )mi->pszPopupName;
+
+ if ( !( mi->flags & CMIF_ROOTHANDLE )) {
+ //old system
+ tmi.flags |= CMIF_ROOTHANDLE;
+ tmi.root = NULL;
+ }
+
+ //owner data
+ lpContactMenuExecParam cmep = ( lpContactMenuExecParam )mir_calloc(sizeof(ContactMenuExecParam));
+ cmep->szServiceName = mir_strdup( mi->pszService );
+ if ( mi->pszContactOwner != NULL )
+ cmep->pszContactOwner = mir_strdup( mi->pszContactOwner );
+ cmep->param = mi->popupPosition;
+ tmi.ownerdata = cmep;
+
+ //may be need to change how UniqueName is formed?
+ PMO_IntMenuItem menuHandle = MO_AddNewMenuItem( hContactMenuObject, &tmi );
+ char buf[ 256 ];
+ if (mi->pszService)
+ mir_snprintf( buf, SIZEOF(buf), "%s/%s", (mi->pszContactOwner) ? mi->pszContactOwner : "", (mi->pszService) ? mi->pszService : "" );
+ else if (mi->ptszName)
+ {
+ if (tmi.flags&CMIF_UNICODE)
+ {
+ char * temp = mir_t2a(mi->ptszName);
+ mir_snprintf( buf, SIZEOF(buf), "%s/NoService/%s", (mi->pszContactOwner) ? mi->pszContactOwner : "", temp );
+ mir_free(temp);
+ }
+ else
+ mir_snprintf( buf, SIZEOF(buf), "%s/NoService/%s", (mi->pszContactOwner) ? mi->pszContactOwner : "", mi->ptszName );
+ }
+ else buf[0]='\0';
+ if (buf[0]) MO_SetOptionsMenuItem( menuHandle, OPT_MENUITEMSETUNIQNAME, ( INT_PTR )buf );
+ return ( INT_PTR )menuHandle;
+}
+
+static INT_PTR BuildContactMenu(WPARAM wParam, LPARAM)
+{
+ HANDLE hContact = ( HANDLE )wParam;
+ NotifyEventHooks(hPreBuildContactMenuEvent,(WPARAM)hContact,0);
+
+ char *szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hContact,0);
+
+ BuildContactParam bcp;
+ bcp.szProto = szProto;
+ bcp.isOnList = ( DBGetContactSettingByte(hContact,"CList","NotOnList",0) == 0 );
+ bcp.isOnline = ( szProto != NULL && ID_STATUS_OFFLINE != DBGetContactSettingWord(hContact,szProto,"Status",ID_STATUS_OFFLINE));
+
+ ListParam param = { 0 };
+ param.MenuObjectHandle = hContactMenuObject;
+ param.wParam = (WPARAM)&bcp;
+
+ HMENU hMenu = CreatePopupMenu();
+ CallService(MO_BUILDMENU,(WPARAM)hMenu,(LPARAM)&param);
+
+ return (INT_PTR)hMenu;
+}
+
+//called with:
+//wparam - ownerdata
+//lparam - lparam from winproc
+INT_PTR ContactMenuExecService(WPARAM wParam,LPARAM lParam)
+{
+ if (wParam!=0) {
+ lpContactMenuExecParam cmep=(lpContactMenuExecParam)wParam;
+ //call with wParam=(WPARAM)(HANDLE)hContact,lparam=popupposition
+ CallService(cmep->szServiceName,lParam,cmep->param);
+ }
+ return 0;
+}
+
+//true - ok,false ignore
+INT_PTR ContactMenuCheckService(WPARAM wParam,LPARAM)
+{
+ PCheckProcParam pcpp = ( PCheckProcParam )wParam;
+ BuildContactParam *bcp=NULL;
+ lpContactMenuExecParam cmep=NULL;
+ TMO_MenuItem mi;
+
+ if ( pcpp == NULL )
+ return FALSE;
+
+ bcp = ( BuildContactParam* )pcpp->wParam;
+ if ( bcp == NULL )
+ return FALSE;
+
+ cmep = ( lpContactMenuExecParam )pcpp->MenuItemOwnerData;
+ if ( cmep == NULL ) //this is root...build it
+ return TRUE;
+
+ if ( cmep->pszContactOwner != NULL ) {
+ if ( bcp->szProto == NULL ) return FALSE;
+ if ( strcmp( cmep->pszContactOwner, bcp->szProto )) return FALSE;
+ }
+ if ( MO_GetMenuItem(( WPARAM )pcpp->MenuItemHandle, ( LPARAM )&mi ) == 0 ) {
+ if ( mi.flags & CMIF_HIDDEN ) return FALSE;
+ if ( mi.flags & CMIF_NOTONLIST && bcp->isOnList ) return FALSE;
+ if ( mi.flags & CMIF_NOTOFFLIST && !bcp->isOnList ) return FALSE;
+ if ( mi.flags & CMIF_NOTONLINE && bcp->isOnline ) return FALSE;
+ if ( mi.flags & CMIF_NOTOFFLINE && !bcp->isOnline ) return FALSE;
+ }
+ return TRUE;
+}
+
+INT_PTR FreeOwnerDataContactMenu (WPARAM, LPARAM lParam)
+{
+ lpContactMenuExecParam cmep = ( lpContactMenuExecParam )lParam;
+ if ( cmep != NULL ) {
+ FreeAndNil(( void** )&cmep->szServiceName);
+ FreeAndNil(( void** )&cmep->pszContactOwner);
+ FreeAndNil(( void** )&cmep);
+ }
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// STATUS MENU
+
+BOOL FindMenuHandleByGlobalID(HMENU hMenu, PMO_IntMenuItem id, MenuItemData* itdat)
+{
+ int i;
+ PMO_IntMenuItem pimi;
+ MENUITEMINFO mii={0};
+ BOOL inSub=FALSE;
+ if (!itdat)
+ return FALSE;
+
+ mii.cbSize = MENUITEMINFO_V4_SIZE;
+ mii.fMask = MIIM_SUBMENU | MIIM_DATA;
+ for ( i = GetMenuItemCount( hMenu )-1; i >= 0; i-- ) {
+ GetMenuItemInfo(hMenu,i,TRUE,&mii);
+ if ( mii.fType == MFT_SEPARATOR )
+ continue;
+ if ( mii.hSubMenu )
+ inSub = FindMenuHandleByGlobalID(mii.hSubMenu, id, itdat);
+ if ( inSub )
+ return inSub;
+
+ pimi = MO_GetIntMenuItem(( HGENMENU )mii.dwItemData );
+ if ( pimi != NULL ) {
+ if ( pimi == id ) {
+ itdat->OwnerMenu = hMenu;
+ itdat->position = i;
+ return TRUE;
+ } } }
+
+ return FALSE;
+}
+
+INT_PTR StatusMenuCheckService(WPARAM wParam, LPARAM)
+{
+ PCheckProcParam pcpp = ( PCheckProcParam )wParam;
+ if ( !pcpp )
+ return TRUE;
+
+ PMO_IntMenuItem timi = MO_GetIntMenuItem( pcpp->MenuItemHandle );
+ if ( !timi )
+ return TRUE;
+
+ StatusMenuExecParam *smep = ( StatusMenuExecParam* )pcpp->MenuItemOwnerData;
+ if (smep && !smep->status && smep->custom )
+ {
+ if (wildcmp(smep->svc, "*XStatus*"))
+ {
+ int XStatus = CallProtoService(smep->proto, "/GetXStatus", 0, 0);
+ char buf[255];
+ mir_snprintf( buf, sizeof(buf), "*XStatus%d", XStatus );
+
+ bool check = wildcmp(smep->svc, buf);
+ bool reset = wildcmp(smep->svc, "*XStatus0");
+
+ if (check)
+ timi->mi.flags |= CMIF_CHECKED;
+ else
+ timi->mi.flags &= ~CMIF_CHECKED;
+
+ if ( reset || check )
+ {
+ PMO_IntMenuItem timiParent = MO_GetIntMenuItem( timi->mi.root );
+ if (timiParent)
+ {
+ CLISTMENUITEM mi2 = {0};
+ mi2.cbSize = sizeof(mi2);
+ mi2.flags = CMIM_NAME | CMIF_TCHAR;
+ mi2.ptszName = timi->mi.hIcon ? timi->mi.ptszName : TranslateT("Custom status");
+
+ timiParent = MO_GetIntMenuItem( timi->mi.root );
+
+ MenuItemData it = {0};
+
+ if (FindMenuHandleByGlobalID(hStatusMenu, timiParent, &it))
+ {
+ MENUITEMINFO mi ={0};
+ TCHAR d[100];
+ GetMenuString(it.OwnerMenu, it.position, d, SIZEOF(d), MF_BYPOSITION);
+
+ if (!IsWinVer98Plus())
+ {
+ mi.cbSize = MENUITEMINFO_V4_SIZE;
+ mi.fMask = MIIM_TYPE | MIIM_STATE;
+ mi.fType = MFT_STRING;
+ }
+ else
+ {
+ mi.cbSize = sizeof( mi );
+ mi.fMask = MIIM_STRING | MIIM_STATE;
+ if ( timi->iconId != -1 )
+ {
+ mi.fMask |= MIIM_BITMAP;
+ if (IsWinVerVistaPlus() && isThemeActive()) {
+ if (timi->hBmp == NULL)
+ timi->hBmp = ConvertIconToBitmap(NULL, timi->parent->m_hMenuIcons, timi->iconId);
+ mi.hbmpItem = timi->hBmp;
+ }
+ else
+ mi.hbmpItem = HBMMENU_CALLBACK;
+ }
+ }
+
+ mi.fState |= (check && !reset ? MFS_CHECKED : MFS_UNCHECKED );
+ mi.dwTypeData = mi2.ptszName;
+ SetMenuItemInfo(it.OwnerMenu, it.position, TRUE, &mi);
+ }
+
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)timi->mi.root, (LPARAM)&mi2);
+ timiParent->iconId = timi->iconId;
+ if (timiParent->hBmp) DeleteObject(timiParent->hBmp);
+ timiParent->hBmp = NULL;
+ } } }
+ }
+ else if ( smep && smep->status && !smep->custom ) {
+ int curProtoStatus = ( smep->proto ) ? CallProtoService(smep->proto,PS_GETSTATUS,0,0) : GetAverageMode();
+ if ( smep->status == curProtoStatus )
+ timi->mi.flags |= CMIF_CHECKED;
+ else
+ timi->mi.flags &= ~CMIF_CHECKED;
+ }
+ else if (( !smep || smep->proto ) && timi->mi.pszName ) {
+ int curProtoStatus=0;
+ BOOL IconNeedDestroy=FALSE;
+ char* prot;
+ if (smep)
+ prot = smep->proto;
+ else
+ {
+ #ifdef UNICODE
+ char *prn=mir_u2a(timi->mi.ptszName);
+ prot = NEWSTR_ALLOCA( prn );
+ if (prn) mir_free(prn);
+ #else
+ prot = timi->mi.ptszName;
+ #endif
+ }
+ if ( Proto_GetAccount( prot ) == NULL )
+ return TRUE;
+
+ if (( curProtoStatus = CallProtoService(prot,PS_GETSTATUS,0,0)) == CALLSERVICE_NOTFOUND )
+ curProtoStatus = 0;
+
+ if ( curProtoStatus >= ID_STATUS_OFFLINE && curProtoStatus < ID_STATUS_IDLE )
+ timi->mi.hIcon = LoadSkinProtoIcon(prot,curProtoStatus);
+ else {
+ timi->mi.hIcon=(HICON)CallProtoService(prot,PS_LOADICON,PLI_PROTOCOL|PLIF_SMALL,0);
+ if ( timi->mi.hIcon == (HICON)CALLSERVICE_NOTFOUND )
+ timi->mi.hIcon = NULL;
+ else
+ IconNeedDestroy = TRUE;
+ }
+
+ if (timi->mi.hIcon) {
+ timi->mi.flags |= CMIM_ICON;
+ MO_ModifyMenuItem( timi, &timi->mi );
+ if ( IconNeedDestroy ) {
+ DestroyIcon( timi->mi.hIcon );
+ timi->mi.hIcon = NULL;
+ }
+ else IconLib_ReleaseIcon(timi->mi.hIcon,0);
+ } }
+
+ return TRUE;
+}
+
+INT_PTR StatusMenuExecService(WPARAM wParam, LPARAM)
+{
+ lpStatusMenuExecParam smep = ( lpStatusMenuExecParam )wParam;
+ if ( smep != NULL ) {
+ if ( smep->custom ) {
+ if (smep->svc && *smep->svc)
+ CallService(smep->svc, 0, (LPARAM)smep->hMenuItem);
+ }
+ else {
+ if ( smep->status == 0 && smep->protoindex !=0 && smep->proto != NULL ) {
+ PMO_IntMenuItem pimi;
+ char *prot = smep->proto;
+ char szHumanName[64]={0};
+ PROTOACCOUNT * acc = Proto_GetAccount( smep->proto );
+ int i=(DBGetContactSettingByte(NULL,prot,"LockMainStatus",0)?0:1);
+ DBWriteContactSettingByte(NULL,prot,"LockMainStatus",(BYTE)i);
+
+ CallProtoService( smep->proto, PS_GETNAME, (WPARAM)SIZEOF(szHumanName), (LPARAM)szHumanName );
+ pimi = MO_GetIntMenuItem(( HGENMENU )smep->protoindex );
+ PMO_IntMenuItem root = (PMO_IntMenuItem)pimi->mi.root;
+ mir_free( pimi->mi.pszName );
+ mir_free( root->mi.pszName );
+ if ( i ) {
+ TCHAR buf[256];
+ pimi->mi.flags|=CMIF_CHECKED;
+ if ( cli.bDisplayLocked ) {
+ mir_sntprintf(buf,SIZEOF(buf),TranslateT("%s (locked)"),acc->tszAccountName);
+ pimi->mi.ptszName = mir_tstrdup( buf );
+ root->mi.ptszName = mir_tstrdup( buf );
+ }
+ else {
+ pimi->mi.ptszName = mir_tstrdup( acc->tszAccountName );
+ root->mi.ptszName = mir_tstrdup( acc->tszAccountName );
+ }
+ }
+ else {
+ pimi->mi.ptszName = mir_tstrdup( acc->tszAccountName );
+ root->mi.ptszName = mir_tstrdup( acc->tszAccountName );
+ pimi->mi.flags &= ~CMIF_CHECKED;
+ }
+ if ( cli.hwndStatus )
+ InvalidateRect( cli.hwndStatus, NULL, TRUE );
+ }
+ else if ( smep->proto != NULL ) {
+ Proto_SetStatus(smep->proto, smep->status);
+ NotifyEventHooks(hStatusModeChangeEvent, smep->status, (LPARAM)smep->proto);
+ }
+ else {
+ int MenusProtoCount = 0;
+
+ for( int i=0; i < accounts.getCount(); i++ )
+ if ( cli.pfnGetProtocolVisibility( accounts[i]->szModuleName ))
+ MenusProtoCount++;
+
+ cli.currentDesiredStatusMode = smep->status;
+
+ for ( int j=0; j < accounts.getCount(); j++ ) {
+ PROTOACCOUNT* pa = accounts[j];
+ if ( !Proto_IsAccountEnabled( pa ))
+ continue;
+ if ( MenusProtoCount > 1 && Proto_IsAccountLocked( pa ))
+ continue;
+
+ Proto_SetStatus(pa->szModuleName, cli.currentDesiredStatusMode);
+ }
+ NotifyEventHooks( hStatusModeChangeEvent, cli.currentDesiredStatusMode, 0 );
+ DBWriteContactSettingWord( NULL, "CList", "Status", ( WORD )cli.currentDesiredStatusMode );
+ return 1;
+ } } }
+
+ return 0;
+}
+
+INT_PTR FreeOwnerDataStatusMenu(WPARAM, LPARAM lParam)
+{
+ lpStatusMenuExecParam smep = (lpStatusMenuExecParam)lParam;
+ if ( smep != NULL ) {
+ FreeAndNil(( void** )&smep->proto);
+ FreeAndNil(( void** )&smep->svc);
+ FreeAndNil(( void** )&smep);
+ }
+
+ return (0);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Other menu functions
+
+//wparam MenuItemHandle
+static INT_PTR ModifyCustomMenuItem(WPARAM wParam,LPARAM lParam)
+{
+ CLISTMENUITEM *mi=(CLISTMENUITEM*)lParam;
+ TMO_MenuItem tmi;
+
+ if ( lParam == 0 )
+ return -1;
+ if ( mi->cbSize != sizeof( CLISTMENUITEM ))
+ return 1;
+
+ tmi.cbSize = sizeof(tmi);
+ tmi.flags = mi->flags;
+ tmi.hIcon = mi->hIcon;
+ tmi.hotKey = mi->hotKey;
+ tmi.ptszName = mi->ptszName;
+ return MO_ModifyMenuItem(( PMO_IntMenuItem )wParam, &tmi );
+}
+
+INT_PTR MenuProcessCommand(WPARAM wParam,LPARAM lParam)
+{
+ WORD cmd = LOWORD(wParam);
+
+ if ( HIWORD(wParam) & MPCF_MAINMENU ) {
+ int hst = LOWORD( wParam );
+ if ( hst >= ID_STATUS_OFFLINE && hst <= ID_STATUS_OUTTOLUNCH ) {
+ int pos = statustopos( hst );
+ if ( pos != -1 && hStatusMainMenuHandles != NULL )
+ return MO_ProcessCommand( hStatusMainMenuHandles[ pos ], lParam );
+ } }
+
+ if ( !( cmd >= CLISTMENUIDMIN && cmd <= CLISTMENUIDMAX ))
+ return 0; // DO NOT process ids outside from clist menu id range v0.7.0.27+
+
+ //process old menu sys
+ if ( HIWORD(wParam) & MPCF_CONTACTMENU )
+ return MO_ProcessCommandBySubMenuIdent( (int)hContactMenuObject, LOWORD(wParam), lParam );
+
+ //unknown old menu
+ return MO_ProcessCommandByMenuIdent( LOWORD(wParam), lParam );
+}
+
+BOOL FindMenuHanleByGlobalID(HMENU hMenu, PMO_IntMenuItem id, MenuItemData* itdat)
+{
+ int i;
+ PMO_IntMenuItem pimi;
+ MENUITEMINFO mii = {0};
+ BOOL inSub=FALSE;
+
+ if ( !itdat )
+ return FALSE;
+
+ mii.cbSize = MENUITEMINFO_V4_SIZE;
+ mii.fMask = MIIM_SUBMENU | MIIM_DATA;
+ for ( i = GetMenuItemCount( hMenu )-1; i >= 0; i-- ) {
+ GetMenuItemInfo( hMenu, i, TRUE, &mii );
+ if ( mii.fType == MFT_SEPARATOR )
+ continue;
+
+ if ( mii.hSubMenu )
+ inSub = FindMenuHanleByGlobalID( mii.hSubMenu, id, itdat );
+ if (inSub)
+ return inSub;
+
+ pimi = MO_GetIntMenuItem(( HGENMENU )mii.dwItemData);
+ if ( pimi != NULL ) {
+ if ( pimi == id ) {
+ itdat->OwnerMenu = hMenu;
+ itdat->position = i;
+ return TRUE;
+ } } }
+
+ return FALSE;
+}
+
+static INT_PTR MenuProcessHotkey(WPARAM vKey, LPARAM)
+{
+ prochotkey = true;
+
+ bool res =
+ MO_ProcessHotKeys( hStatusMenuObject, vKey ) ||
+ MO_ProcessHotKeys( hMainMenuObject, vKey );
+
+ prochotkey = false;
+
+ return res;
+}
+
+static int MenuIconsChanged(WPARAM, LPARAM)
+{
+ //just rebuild menu
+ RebuildMenuOrder();
+ cli.pfnCluiProtocolStatusChanged(0,0);
+ return 0;
+}
+
+static INT_PTR MeasureMenuItem(WPARAM, LPARAM lParam)
+{
+ return MO_MeasureMenuItem(( LPMEASUREITEMSTRUCT )lParam );
+}
+
+static INT_PTR DrawMenuItem(WPARAM, LPARAM lParam)
+{
+ return MO_DrawMenuItem(( LPDRAWITEMSTRUCT )lParam );
+}
+
+int RecursiveDeleteMenu(HMENU hMenu)
+{
+ int cnt = GetMenuItemCount(hMenu);
+ for ( int i=0; i < cnt; i++ ) {
+ HMENU submenu = GetSubMenu(hMenu, 0);
+ if (submenu) DestroyMenu(submenu);
+ DeleteMenu(hMenu, 0, MF_BYPOSITION);
+ }
+ return 0;
+}
+
+static INT_PTR MenuGetMain(WPARAM, LPARAM)
+{
+ RecursiveDeleteMenu(hMainMenu);
+ BuildMainMenu(0,0);
+ return (INT_PTR)hMainMenu;
+}
+
+static INT_PTR BuildStatusMenu(WPARAM, LPARAM)
+{
+ ListParam param = { 0 };
+ param.MenuObjectHandle = hStatusMenuObject;
+
+ RecursiveDeleteMenu(hStatusMenu);
+ CallService(MO_BUILDMENU,(WPARAM)hStatusMenu,(LPARAM)&param);
+ return (INT_PTR)hStatusMenu;
+}
+
+static INT_PTR SetStatusMode(WPARAM wParam, LPARAM)
+{
+ prochotkey = true;
+ MenuProcessCommand(MAKEWPARAM(LOWORD(wParam), MPCF_MAINMENU), 0);
+ prochotkey = false;
+ return 0;
+}
+
+int fnGetProtocolVisibility(const char* accName)
+{
+ if ( accName ) {
+ PROTOACCOUNT* pa = Proto_GetAccount( accName );
+ return pa && pa->bIsVisible && Proto_IsAccountEnabled( pa ) &&
+ pa->ppro && (pa->ppro->GetCaps( PFLAGNUM_2, 0 ) & ~pa->ppro->GetCaps( PFLAGNUM_5, 0 ));
+ }
+
+ return FALSE;
+}
+
+int fnGetProtoIndexByPos(PROTOCOLDESCRIPTOR ** proto, int protoCnt, int Pos)
+{
+ int p;
+ char buf[10];
+ DBVARIANT dbv;
+
+ _itoa( Pos, buf, 10 );
+ if ( !DBGetContactSetting( NULL, "Protocols", buf, &dbv )) {
+ for ( p=0; p < protoCnt; p++ ) {
+ if ( lstrcmpA( proto[p]->szName, dbv.pszVal ) == 0 ) {
+ DBFreeVariant( &dbv );
+ return p;
+ } }
+
+ DBFreeVariant( &dbv );
+ }
+
+ return -1;
+}
+
+int fnGetAccountIndexByPos(int Pos)
+{
+ int i;
+ for ( i=0; i < accounts.getCount(); i++ )
+ if ( accounts[i]->iOrder == Pos )
+ return i;
+
+ return -1;
+}
+
+void RebuildMenuOrder( void )
+{
+ int i,j,s;
+ DWORD flags;
+
+ BYTE bHideStatusMenu = DBGetContactSettingByte( NULL, "CLUI", "DontHideStatusMenu", 0 ); // cool perversion, though
+
+ //clear statusmenu
+ RecursiveDeleteMenu(hStatusMenu);
+
+ //status menu
+ if ( hStatusMenuObject != 0 ) {
+ CallService(MO_REMOVEMENUOBJECT,(WPARAM)hStatusMenuObject,0);
+ mir_free( hStatusMainMenuHandles );
+ mir_free( hStatusMenuHandles );
+ }
+
+ TMenuParam tmp = { 0 };
+ tmp.cbSize = sizeof(tmp);
+ tmp.ExecService = "StatusMenuExecService";
+ tmp.CheckService = "StatusMenuCheckService";
+ tmp.name = "StatusMenu";
+
+ hStatusMenuObject=(HANDLE)CallService(MO_CREATENEWMENUOBJECT,(WPARAM)0,(LPARAM)&tmp);
+ MO_SetOptionsMenuObject( hStatusMenuObject, OPT_MENUOBJECT_SET_FREE_SERVICE, (INT_PTR)"CLISTMENUS/FreeOwnerDataStatusMenu" );
+
+ hStatusMainMenuHandles = ( PMO_IntMenuItem* )mir_calloc( SIZEOF(statusModeList) * sizeof( PMO_IntMenuItem* ));
+ hStatusMainMenuHandlesCnt = SIZEOF(statusModeList);
+
+ hStatusMenuHandles = ( tStatusMenuHandles* )mir_calloc(sizeof(tStatusMenuHandles)*accounts.getCount());
+ hStatusMenuHandlesCnt = accounts.getCount();
+
+ FreeMenuProtos();
+
+ for ( s=0; s < accounts.getCount(); s++ ) {
+ i = cli.pfnGetAccountIndexByPos( s );
+ if ( i == -1 )
+ continue;
+
+ PROTOACCOUNT* pa = accounts[i];
+ int pos = 0;
+ if ( !bHideStatusMenu && !cli.pfnGetProtocolVisibility( pa->szModuleName ))
+ continue;
+
+ flags = pa->ppro->GetCaps( PFLAGNUM_2, 0 ) & ~pa->ppro->GetCaps( PFLAGNUM_5, 0 );
+ int j;
+ HICON ic;
+ TCHAR tbuf[256];
+
+ //adding root
+ TMO_MenuItem tmi = { 0 };
+ tmi.cbSize = sizeof(tmi);
+ tmi.flags = CMIF_TCHAR | CMIF_ROOTHANDLE | CMIF_KEEPUNTRANSLATED;
+ tmi.position = pos++;
+ tmi.hIcon = ic = (HICON)CallProtoService( pa->szModuleName, PS_LOADICON, PLI_PROTOCOL | PLIF_SMALL, 0 );
+
+ if ( Proto_IsAccountLocked( pa ) && cli.bDisplayLocked ) {
+ mir_sntprintf( tbuf, SIZEOF(tbuf), TranslateT("%s (locked)"), pa->tszAccountName );
+ tmi.ptszName = tbuf;
+ }
+ else tmi.ptszName = pa->tszAccountName;
+
+ {
+ //owner data
+ lpStatusMenuExecParam smep = ( lpStatusMenuExecParam )mir_calloc( sizeof( StatusMenuExecParam ));
+ smep->proto = mir_strdup(pa->szModuleName);
+ tmi.ownerdata = smep;
+ }
+ PMO_IntMenuItem rootmenu = MO_AddNewMenuItem( hStatusMenuObject, &tmi );
+
+ memset(&tmi,0,sizeof(tmi));
+ tmi.cbSize = sizeof(tmi);
+ tmi.flags = CMIF_TCHAR | CMIF_ROOTHANDLE | CMIF_KEEPUNTRANSLATED;
+ tmi.root = rootmenu;
+ tmi.position = pos++;
+ tmi.hIcon = ic;
+ {
+ //owner data
+ lpStatusMenuExecParam smep = ( lpStatusMenuExecParam )mir_alloc( sizeof( StatusMenuExecParam ));
+ memset( smep, 0, sizeof( *smep ));
+ smep->proto = mir_strdup(pa->szModuleName);
+ tmi.ownerdata = smep;
+ }
+
+ if ( Proto_IsAccountLocked( pa ))
+ tmi.flags |= CMIF_CHECKED;
+
+ if (( tmi.flags & CMIF_CHECKED ) && cli.bDisplayLocked ) {
+ mir_sntprintf( tbuf, SIZEOF(tbuf), TranslateT("%s (locked)"), pa->tszAccountName );
+ tmi.ptszName = tbuf;
+ }
+ else tmi.ptszName = pa->tszAccountName;
+
+ PMO_IntMenuItem menuHandle = MO_AddNewMenuItem( hStatusMenuObject, &tmi );
+ ((lpStatusMenuExecParam)tmi.ownerdata)->protoindex = ( int )menuHandle;
+ MO_ModifyMenuItem( menuHandle, &tmi );
+
+ cli.menuProtos=(MenuProto*)mir_realloc(cli.menuProtos, sizeof(MenuProto)*(cli.menuProtoCount+1));
+ memset(&(cli.menuProtos[cli.menuProtoCount]),0,sizeof(MenuProto));
+ cli.menuProtos[cli.menuProtoCount].pMenu = rootmenu;
+ cli.menuProtos[cli.menuProtoCount].szProto = mir_strdup(pa->szModuleName);
+
+ cli.menuProtoCount++;
+ {
+ char buf[256];
+ mir_snprintf( buf, SIZEOF(buf), "RootProtocolIcon_%s", pa->szModuleName );
+ MO_SetOptionsMenuItem( menuHandle, OPT_MENUITEMSETUNIQNAME, ( INT_PTR )buf );
+ }
+ DestroyIcon(ic);
+ pos += 500000;
+
+ for ( j=0; j < SIZEOF(statusModeList); j++ ) {
+ if ( !( flags & statusModePf2List[j] ))
+ continue;
+
+ //adding
+ memset( &tmi, 0, sizeof( tmi ));
+ tmi.cbSize = sizeof(tmi);
+ tmi.flags = CMIF_ROOTHANDLE | CMIF_TCHAR;
+ if ( statusModeList[j] == ID_STATUS_OFFLINE )
+ tmi.flags |= CMIF_CHECKED;
+ tmi.root = rootmenu;
+ tmi.position = pos++;
+ tmi.ptszName = cli.pfnGetStatusModeDescription( statusModeList[j], GSMDF_UNTRANSLATED );
+ tmi.hIcon = LoadSkinProtoIcon( pa->szModuleName, statusModeList[j] );
+ {
+ //owner data
+ lpStatusMenuExecParam smep = ( lpStatusMenuExecParam )mir_calloc( sizeof( StatusMenuExecParam ));
+ smep->custom = FALSE;
+ smep->status = statusModeList[j];
+ smep->protoindex = i;
+ smep->proto = mir_strdup(pa->szModuleName);
+ tmi.ownerdata = smep;
+ }
+
+ hStatusMenuHandles[i].protoindex = i;
+ hStatusMenuHandles[i].protostatus[j] = statusModeList[j];
+ hStatusMenuHandles[i].menuhandle[j] = MO_AddNewMenuItem( hStatusMenuObject, &tmi );
+ {
+ char buf[ 256 ];
+ mir_snprintf(buf, SIZEOF(buf), "ProtocolIcon_%s_%s",pa->szModuleName,tmi.pszName);
+ MO_SetOptionsMenuItem( hStatusMenuHandles[i].menuhandle[j], OPT_MENUITEMSETUNIQNAME, ( INT_PTR )buf );
+ }
+ IconLib_ReleaseIcon(tmi.hIcon,0);
+ } }
+
+ NotifyEventHooks(cli.hPreBuildStatusMenuEvent, 0, 0);
+ int pos = 200000;
+
+ //add to root menu
+ for ( j=0; j < SIZEOF(statusModeList); j++ ) {
+ for ( i=0; i < accounts.getCount(); i++ ) {
+ PROTOACCOUNT* pa = accounts[i];
+ if ( !bHideStatusMenu && !cli.pfnGetProtocolVisibility( pa->szModuleName ))
+ continue;
+
+ flags = pa->ppro->GetCaps(PFLAGNUM_2, 0) & ~pa->ppro->GetCaps(PFLAGNUM_5, 0);
+ if ( !( flags & statusModePf2List[j] ))
+ continue;
+
+ TMO_MenuItem tmi = { 0 };
+ tmi.cbSize = sizeof( tmi );
+ tmi.flags = CMIF_ROOTHANDLE | CMIF_TCHAR;
+ if ( statusModeList[j] == ID_STATUS_OFFLINE )
+ tmi.flags |= CMIF_CHECKED;
+
+ tmi.hIcon = LoadSkinIcon( skinIconStatusList[j] );
+ tmi.position = pos++;
+ tmi.hotKey = MAKELPARAM(MOD_CONTROL,'0'+j);
+ {
+ //owner data
+ lpStatusMenuExecParam smep = ( lpStatusMenuExecParam )mir_alloc( sizeof( StatusMenuExecParam ));
+ smep->custom = FALSE;
+ smep->status = statusModeList[j];
+ smep->proto = NULL;
+ smep->svc = NULL;
+ tmi.ownerdata = smep;
+ }
+ {
+ TCHAR buf[ 256 ], hotkeyName[ 100 ];
+ WORD hotKey = GetHotkeyValue( statusHotkeys[j] );
+ HotkeyToName( hotkeyName, SIZEOF(hotkeyName), HIBYTE(hotKey), LOBYTE(hotKey));
+ mir_sntprintf( buf, SIZEOF( buf ), TranslateT("%s\t%s"),
+ cli.pfnGetStatusModeDescription( statusModeList[j], 0 ), hotkeyName );
+ tmi.ptszName = buf;
+ tmi.hotKey = MAKELONG(HIBYTE(hotKey), LOBYTE(hotKey));
+ hStatusMainMenuHandles[j] = MO_AddNewMenuItem( hStatusMenuObject, &tmi );
+ }
+ {
+ char buf[ 256 ];
+ mir_snprintf( buf, sizeof( buf ), "Root2ProtocolIcon_%s_%s", pa->szModuleName, tmi.pszName );
+ MO_SetOptionsMenuItem( hStatusMainMenuHandles[j], OPT_MENUITEMSETUNIQNAME, ( INT_PTR )buf );
+ }
+ IconLib_ReleaseIcon( tmi.hIcon, 0 );
+ break;
+ } }
+
+ BuildStatusMenu(0,0);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static int sttRebuildHotkeys( WPARAM, LPARAM )
+{
+ TMO_MenuItem tmi = { 0 };
+ tmi.cbSize = sizeof( tmi );
+ tmi.flags = CMIM_HOTKEY | CMIM_NAME | CMIF_TCHAR;
+
+ for ( int j=0; j < SIZEOF(statusModeList); j++ ) {
+ TCHAR buf[ 256 ], hotkeyName[ 100 ];
+ WORD hotKey = GetHotkeyValue( statusHotkeys[j] );
+ HotkeyToName( hotkeyName, SIZEOF(hotkeyName), HIBYTE(hotKey), LOBYTE(hotKey));
+ mir_sntprintf( buf, SIZEOF( buf ), TranslateT("%s\t%s"),
+ cli.pfnGetStatusModeDescription( statusModeList[j], 0 ), hotkeyName );
+ tmi.ptszName = buf;
+ tmi.hotKey = MAKELONG(HIBYTE(hotKey), LOBYTE(hotKey));
+ MO_ModifyMenuItem( hStatusMainMenuHandles[j], &tmi );
+ }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int statustopos(int status)
+{
+ int j;
+ for ( j = 0; j < SIZEOF(statusModeList); j++ )
+ if ( status == statusModeList[j] )
+ return j;
+
+ return -1;
+}
+
+static int MenuProtoAck(WPARAM, LPARAM lParam)
+{
+ int i;
+ ACKDATA* ack=(ACKDATA*)lParam;
+ int overallStatus;
+ TMO_MenuItem tmi;
+
+ if ( ack->type != ACKTYPE_STATUS ) return 0;
+ if ( ack->result != ACKRESULT_SUCCESS ) return 0;
+ if ( hStatusMainMenuHandles == NULL ) return 0;
+
+ if ( cli.pfnGetProtocolVisibility( ack->szModule ) == 0 ) return 0;
+
+ overallStatus = GetAverageMode();
+
+ memset(&tmi,0,sizeof(tmi));
+ tmi.cbSize=sizeof(tmi);
+ if (overallStatus >= ID_STATUS_OFFLINE) {
+ int pos = statustopos(cli.currentStatusMenuItem);
+ if (pos==-1) pos=0;
+ { // reset all current possible checked statuses
+ int pos2;
+ for (pos2=0; pos2<hStatusMainMenuHandlesCnt; pos2++)
+ {
+ if (pos2>=0 && pos2 < hStatusMainMenuHandlesCnt)
+ {
+ tmi.flags = CMIM_FLAGS | CMIF_ROOTHANDLE;
+ MO_ModifyMenuItem( hStatusMainMenuHandles[pos2], &tmi );
+ } } }
+
+ cli.currentStatusMenuItem=overallStatus;
+ pos = statustopos(cli.currentStatusMenuItem);
+ if (pos>=0 && pos < hStatusMainMenuHandlesCnt) {
+ tmi.flags = CMIM_FLAGS | CMIF_ROOTHANDLE | CMIF_CHECKED;
+ MO_ModifyMenuItem( hStatusMainMenuHandles[pos], &tmi );
+ }
+// cli.currentDesiredStatusMode = cli.currentStatusMenuItem;
+ }
+ else {
+ int pos = statustopos( cli.currentStatusMenuItem );
+ if ( pos == -1 ) pos=0;
+ if ( pos >= 0 && pos < hStatusMainMenuHandlesCnt ) {
+ tmi.flags = CMIM_FLAGS | CMIF_ROOTHANDLE;
+ MO_ModifyMenuItem( hStatusMainMenuHandles[pos], &tmi );
+ }
+ //SetMenuDefaultItem(hStatusMenu,-1,FALSE);
+ cli.currentStatusMenuItem=0;
+ }
+
+ for ( i=0; i < accounts.getCount(); i++ ) {
+ if ( !lstrcmpA( accounts[i]->szModuleName, ack->szModule )) {
+ //hProcess is previous mode, lParam is new mode
+ if ((( int )ack->hProcess >= ID_STATUS_OFFLINE || ( int )ack->hProcess == 0 ) && ( int )ack->hProcess < ID_STATUS_OFFLINE + SIZEOF(statusModeList)) {
+ int pos = statustopos(( int )ack->hProcess);
+ if ( pos == -1 )
+ pos = 0;
+ for ( pos = 0; pos < SIZEOF(statusModeList); pos++ ) {
+ tmi.flags = CMIM_FLAGS | CMIF_ROOTHANDLE;
+ MO_ModifyMenuItem( hStatusMenuHandles[i].menuhandle[pos], &tmi );
+ } }
+
+ if ( ack->lParam >= ID_STATUS_OFFLINE && ack->lParam < ID_STATUS_OFFLINE + SIZEOF(statusModeList)) {
+ int pos = statustopos(( int )ack->lParam );
+ if ( pos >= 0 && pos < SIZEOF(statusModeList)) {
+ tmi.flags = CMIM_FLAGS | CMIF_ROOTHANDLE | CMIF_CHECKED;
+ MO_ModifyMenuItem( hStatusMenuHandles[i].menuhandle[pos], &tmi );
+ } }
+ break;
+ } }
+
+ //BuildStatusMenu(0,0);
+ return 0;
+}
+
+static MenuProto* FindProtocolMenu( const char* proto )
+{
+ for (int i=0; i < cli.menuProtoCount; i++)
+ if ( cli.menuProtos[i].pMenu && !lstrcmpiA( cli.menuProtos[i].szProto, proto ))
+ return &cli.menuProtos[i];
+
+ if ( cli.menuProtoCount == 1 )
+ if ( !lstrcmpiA( cli.menuProtos[0].szProto, proto ))
+ return &cli.menuProtos[0];
+
+ return NULL;
+}
+
+HGENMENU fnGetProtocolMenu( const char* proto )
+{
+ MenuProto* mp = FindProtocolMenu( proto );
+ if ( mp )
+ return mp->pMenu;
+
+ return NULL;
+}
+
+static INT_PTR AddStatusMenuItem(WPARAM wParam,LPARAM lParam)
+{
+ CLISTMENUITEM *mi = ( CLISTMENUITEM* )lParam;
+ if ( mi->cbSize != sizeof( CLISTMENUITEM ))
+ return 0;
+
+ PMO_IntMenuItem pRoot = NULL;
+ lpStatusMenuExecParam smep = NULL;
+
+ TMO_MenuItem tmi = { 0 };
+ tmi.cbSize = sizeof(tmi);
+ tmi.hIcon = mi->hIcon;
+ tmi.hotKey = mi->hotKey;
+ tmi.position = mi->position;
+ tmi.pszName = mi->pszName;
+ tmi.flags = mi->flags;
+ tmi.root = mi->hParentMenu;
+
+ // for new style menus the pszPopupName contains the root menu handle
+ if ( mi->flags & CMIF_ROOTHANDLE )
+ pRoot = MO_GetIntMenuItem( mi->hParentMenu );
+
+ // for old style menus the pszPopupName really means the popup name
+ else {
+ MenuProto* mp = FindProtocolMenu( mi->pszContactOwner );
+ if ( mp && mi->pszPopupName ) {
+ if ( mp->pMenu ) {
+ #if defined _UNICODE
+ TCHAR* ptszName = ( mi->flags & CMIF_UNICODE ) ? mir_tstrdup(mi->ptszPopupName) : mir_a2t(mi->pszPopupName);
+ pRoot = MO_RecursiveWalkMenu( mp->pMenu->submenu.first, FindRoot, ptszName );
+ mir_free( ptszName );
+ #else
+ pRoot = MO_RecursiveWalkMenu( mp->pMenu->submenu.first, FindRoot, mi->pszPopupName );
+ #endif
+ }
+ if ( pRoot == NULL ) {
+ TMO_MenuItem tmi = { 0 };
+ tmi.cbSize = sizeof(tmi);
+ tmi.flags = (mi->flags & CMIF_UNICODE) | CMIF_ROOTHANDLE;
+ tmi.position = 1001;
+ tmi.root = mp->pMenu;
+ tmi.hIcon = NULL;
+ tmi.pszName = mi->pszPopupName;
+ pRoot = MO_AddNewMenuItem( hStatusMenuObject, &tmi );
+ }
+
+ tmi.flags |= CMIF_ROOTHANDLE;
+ tmi.root = pRoot;
+ } }
+
+ if (wParam) {
+ int * res=(int*)wParam;
+ *res = ( int )pRoot;
+ }
+
+ //owner data
+ if ( mi->pszService ) {
+ smep = ( lpStatusMenuExecParam )mir_calloc(sizeof(StatusMenuExecParam));
+ smep->custom = TRUE;
+ smep->svc=mir_strdup(mi->pszService);
+ {
+ char *buf=mir_strdup(mi->pszService);
+ int i=0;
+ while(buf[i]!='\0' && buf[i]!='/') i++;
+ buf[i]='\0';
+ smep->proto=mir_strdup(buf);
+ mir_free(buf);
+ }
+ tmi.ownerdata = smep;
+ }
+ PMO_IntMenuItem menuHandle = MO_AddNewMenuItem( hStatusMenuObject, &tmi );
+ if ( smep )
+ smep->hMenuItem = menuHandle;
+
+ char buf[MAX_PATH+64];
+ #if defined( _UNICODE )
+ {
+ char* p = ( pRoot ) ? mir_t2a( pRoot->mi.ptszName ) : NULL;
+ mir_snprintf( buf, SIZEOF(buf), "%s/%s", ( p ) ? p : "", mi->pszService ? mi->pszService : "" );
+ mir_free( p );
+ }
+ #else
+ mir_snprintf( buf, SIZEOF(buf), "%s/%s", pRoot ? pRoot->mi.ptszName : _T(""), mi->pszService ? mi->pszService : "" );
+ #endif
+ MO_SetOptionsMenuItem( menuHandle, OPT_MENUITEMSETUNIQNAME, ( INT_PTR )buf );
+
+ return ( INT_PTR )menuHandle;
+}
+
+static INT_PTR HotkeySetStatus(WPARAM wParam,LPARAM lParam)
+{
+ return SetStatusMode( lParam, 0 );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// PROTOCOL MENU
+
+static INT_PTR AddProtoMenuItem(WPARAM wParam,LPARAM lParam)
+{
+ if ( DBGetContactSettingByte( NULL, "CList", "MoveProtoMenus", FALSE ))
+ return AddStatusMenuItem( wParam, lParam );
+
+ return AddMainMenuItem( wParam, lParam );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+void InitCustomMenus(void)
+{
+ CreateServiceFunction("MainMenuExecService",MainMenuExecService);
+
+ CreateServiceFunction("ContactMenuExecService",ContactMenuExecService);
+ CreateServiceFunction("ContactMenuCheckService",ContactMenuCheckService);
+
+ CreateServiceFunction("StatusMenuExecService",StatusMenuExecService);
+ CreateServiceFunction("StatusMenuCheckService",StatusMenuCheckService);
+
+ //free services
+ CreateServiceFunction("CLISTMENUS/FreeOwnerDataMainMenu",FreeOwnerDataMainMenu);
+ CreateServiceFunction("CLISTMENUS/FreeOwnerDataContactMenu",FreeOwnerDataContactMenu);
+ CreateServiceFunction("CLISTMENUS/FreeOwnerDataStatusMenu",FreeOwnerDataStatusMenu);
+
+ CreateServiceFunction(MS_CLIST_SETSTATUSMODE, SetStatusMode);
+
+ CreateServiceFunction(MS_CLIST_ADDMAINMENUITEM,AddMainMenuItem);
+ CreateServiceFunction(MS_CLIST_ADDSTATUSMENUITEM,AddStatusMenuItem);
+ CreateServiceFunction(MS_CLIST_MENUGETMAIN,MenuGetMain);
+ CreateServiceFunction(MS_CLIST_REMOVEMAINMENUITEM,RemoveMainMenuItem);
+ CreateServiceFunction(MS_CLIST_MENUBUILDMAIN,BuildMainMenu);
+
+ CreateServiceFunction(MS_CLIST_ADDCONTACTMENUITEM,AddContactMenuItem);
+ CreateServiceFunction(MS_CLIST_MENUBUILDCONTACT,BuildContactMenu);
+ CreateServiceFunction(MS_CLIST_REMOVECONTACTMENUITEM,RemoveContactMenuItem);
+
+ CreateServiceFunction(MS_CLIST_MODIFYMENUITEM,ModifyCustomMenuItem);
+ CreateServiceFunction(MS_CLIST_MENUMEASUREITEM,MeasureMenuItem);
+ CreateServiceFunction(MS_CLIST_MENUDRAWITEM,DrawMenuItem);
+
+ CreateServiceFunction(MS_CLIST_MENUGETSTATUS,BuildStatusMenu);
+ CreateServiceFunction(MS_CLIST_MENUPROCESSCOMMAND,MenuProcessCommand);
+ CreateServiceFunction(MS_CLIST_MENUPROCESSHOTKEY,MenuProcessHotkey);
+
+ CreateServiceFunction(MS_CLIST_ADDPROTOMENUITEM,AddProtoMenuItem);
+
+ hPreBuildContactMenuEvent=CreateHookableEvent(ME_CLIST_PREBUILDCONTACTMENU);
+ hPreBuildMainMenuEvent=CreateHookableEvent(ME_CLIST_PREBUILDMAINMENU);
+ cli.hPreBuildStatusMenuEvent=CreateHookableEvent(ME_CLIST_PREBUILDSTATUSMENU);
+ hStatusModeChangeEvent = CreateHookableEvent( ME_CLIST_STATUSMODECHANGE );
+
+ hAckHook=(HANDLE)HookEvent(ME_PROTO_ACK,MenuProtoAck);
+
+ hMainMenu = CreatePopupMenu();
+ hStatusMenu = CreatePopupMenu();
+
+ hStatusMainMenuHandles=NULL;
+ hStatusMainMenuHandlesCnt=0;
+
+ hStatusMenuHandles=NULL;
+ hStatusMenuHandlesCnt=0;
+
+ //new menu sys
+ InitGenMenu();
+
+ //main menu
+ {
+ TMenuParam tmp = { 0 };
+ tmp.cbSize=sizeof(tmp);
+ tmp.CheckService=NULL;
+ tmp.ExecService="MainMenuExecService";
+ tmp.name="MainMenu";
+ hMainMenuObject=(HANDLE)CallService(MO_CREATENEWMENUOBJECT,(WPARAM)0,(LPARAM)&tmp);
+ }
+
+ MO_SetOptionsMenuObject( hMainMenuObject, OPT_USERDEFINEDITEMS, TRUE );
+ MO_SetOptionsMenuObject( hMainMenuObject, OPT_MENUOBJECT_SET_FREE_SERVICE, (INT_PTR)"CLISTMENUS/FreeOwnerDataMainMenu" );
+
+ //contact menu
+ {
+ TMenuParam tmp = { 0 };
+ tmp.cbSize=sizeof(tmp);
+ tmp.CheckService="ContactMenuCheckService";
+ tmp.ExecService="ContactMenuExecService";
+ tmp.name="ContactMenu";
+ hContactMenuObject=(HANDLE)CallService(MO_CREATENEWMENUOBJECT,(WPARAM)0,(LPARAM)&tmp);
+ }
+
+ MO_SetOptionsMenuObject( hContactMenuObject, OPT_USERDEFINEDITEMS, TRUE );
+ MO_SetOptionsMenuObject( hContactMenuObject, OPT_MENUOBJECT_SET_FREE_SERVICE, (INT_PTR)"CLISTMENUS/FreeOwnerDataContactMenu" );
+
+ // initialize hotkeys
+ CreateServiceFunction(MS_CLIST_HKSTATUS, HotkeySetStatus);
+
+ HOTKEYDESC hkd = { 0 };
+ hkd.cbSize = sizeof( hkd );
+ hkd.ptszSection = _T("Status");
+ hkd.dwFlags = HKD_TCHAR;
+ for ( int i = 0; i < SIZEOF(statusHotkeys); i++ ) {
+ char szName[30];
+ mir_snprintf( szName, SIZEOF(szName), "StatusHotKey_%d", i );
+ hkd.pszName = szName;
+ hkd.lParam = statusModeList[i];
+ hkd.ptszDescription = fnGetStatusModeDescription( hkd.lParam, 0 );
+ hkd.DefHotKey = HOTKEYCODE( HOTKEYF_CONTROL, '0'+i ) | HKF_MIRANDA_LOCAL;
+ hkd.pszService = MS_CLIST_HKSTATUS;
+ statusHotkeys[i] = CallService( MS_HOTKEY_REGISTER, 0, LPARAM( &hkd ));
+ }
+
+ HookEvent( ME_HOTKEYS_CHANGED, sttRebuildHotkeys );
+
+ // add exit command to menu
+ {
+ CLISTMENUITEM mi = { 0 };
+ mi.cbSize = sizeof( mi );
+ mi.position = 0x7fffffff;
+ mi.flags = CMIF_ICONFROMICOLIB;
+ mi.pszService = "CloseAction";
+ mi.pszName = LPGEN("E&xit");
+ mi.icolibItem = GetSkinIconHandle( SKINICON_OTHER_EXIT );
+ AddMainMenuItem( 0, ( LPARAM )&mi );
+ }
+
+ cli.currentStatusMenuItem=ID_STATUS_OFFLINE;
+ cli.currentDesiredStatusMode=ID_STATUS_OFFLINE;
+
+ if ( IsWinVer98Plus() )
+ HookEvent(ME_SKIN_ICONSCHANGED, MenuIconsChanged );
+}
+
+void UninitCustomMenus(void)
+{
+ mir_free(hStatusMainMenuHandles);
+ hStatusMainMenuHandles = NULL;
+
+ mir_free( hStatusMenuHandles );
+ hStatusMenuHandles = NULL;
+
+ if ( hMainMenuObject ) CallService( MO_REMOVEMENUOBJECT, (WPARAM)hMainMenuObject, 0 );
+ if ( hStatusMenuObject ) CallService( MO_REMOVEMENUOBJECT, (WPARAM)hMainMenuObject, 0 );
+
+ UnloadMoveToGroup();
+ FreeMenuProtos();
+
+ DestroyMenu(hMainMenu);
+ DestroyMenu(hStatusMenu);
+ UnhookEvent(hAckHook);
+}
diff --git a/src/modules/clist/clistmod.cpp b/src/modules/clist/clistmod.cpp
new file mode 100644
index 0000000000..7de958342b
--- /dev/null
+++ b/src/modules/clist/clistmod.cpp
@@ -0,0 +1,569 @@
+/*
+
+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 "clc.h"
+
+INT_PTR AddMainMenuItem(WPARAM wParam, LPARAM lParam);
+INT_PTR AddContactMenuItem(WPARAM wParam, LPARAM lParam);
+INT_PTR ContactChangeGroup(WPARAM wParam, LPARAM lParam);
+int InitCListEvents(void);
+void UninitCListEvents(void);
+int ContactSettingChanged(WPARAM wParam, LPARAM lParam);
+int ContactAdded(WPARAM wParam, LPARAM lParam);
+int ContactDeleted(WPARAM wParam, LPARAM lParam);
+INT_PTR GetContactDisplayName(WPARAM wParam, LPARAM lParam);
+INT_PTR InvalidateDisplayName(WPARAM wParam, LPARAM lParam);
+int InitGroupServices(void);
+INT_PTR Docking_IsDocked(WPARAM wParam, LPARAM lParam);
+void InitDisplayNameCache(void);
+void FreeDisplayNameCache(void);
+int LoadCLUIModule(void);
+int InitClistHotKeys(void);
+
+HANDLE hContactDoubleClicked, hContactIconChangedEvent;
+HIMAGELIST hCListImages;
+BOOL(WINAPI * MySetProcessWorkingSetSize) (HANDLE, SIZE_T, SIZE_T);
+
+extern BYTE nameOrder[];
+
+struct ProtoIconIndex
+{
+ char *szProto;
+ int iIconBase;
+};
+
+OBJLIST<ProtoIconIndex> protoIconIndex(5);
+
+static HANDLE hProtoAckHook;
+static HANDLE hContactSettingChanged;
+
+TCHAR* fnGetStatusModeDescription( int mode, int flags )
+{
+ static TCHAR szMode[64];
+ TCHAR* descr;
+ int noPrefixReqd = 0;
+ switch (mode) {
+ case ID_STATUS_OFFLINE:
+ descr = _T("Offline");
+ noPrefixReqd = 1;
+ break;
+ case ID_STATUS_CONNECTING:
+ descr = _T("Connecting");
+ noPrefixReqd = 1;
+ break;
+ case ID_STATUS_ONLINE:
+ descr = _T("Online");
+ noPrefixReqd = 1;
+ break;
+ case ID_STATUS_AWAY:
+ descr = _T("Away");
+ break;
+ case ID_STATUS_DND:
+ descr = _T("DND");
+ break;
+ case ID_STATUS_NA:
+ descr = _T("NA");
+ break;
+ case ID_STATUS_OCCUPIED:
+ descr = _T("Occupied");
+ break;
+ case ID_STATUS_FREECHAT:
+ descr = _T("Free for chat");
+ break;
+ case ID_STATUS_INVISIBLE:
+ descr = _T("Invisible");
+ break;
+ case ID_STATUS_OUTTOLUNCH:
+ descr = _T("Out to lunch");
+ break;
+ case ID_STATUS_ONTHEPHONE:
+ descr = _T("On the phone");
+ break;
+ case ID_STATUS_IDLE:
+ descr = _T("Idle");
+ break;
+ default:
+ if (mode > ID_STATUS_CONNECTING && mode < ID_STATUS_CONNECTING + MAX_CONNECT_RETRIES) {
+ const TCHAR* connFmt = _T("Connecting (attempt %d)");
+ mir_sntprintf(szMode, SIZEOF(szMode), (flags&GSMDF_UNTRANSLATED)?connFmt:TranslateTS(connFmt), mode - ID_STATUS_CONNECTING + 1);
+ return szMode;
+ }
+ return NULL;
+ }
+ if (noPrefixReqd || !(flags & GSMDF_PREFIXONLINE))
+ return ( flags & GSMDF_UNTRANSLATED ) ? descr : TranslateTS( descr );
+
+ lstrcpy( szMode, TranslateT( "Online" ));
+ lstrcat( szMode, _T(": "));
+ lstrcat( szMode, ( flags & GSMDF_UNTRANSLATED ) ? descr : TranslateTS( descr ));
+ return szMode;
+}
+
+static INT_PTR GetStatusModeDescription(WPARAM wParam, LPARAM lParam)
+{
+ TCHAR* buf1 = cli.pfnGetStatusModeDescription( wParam, lParam );
+
+ #ifdef UNICODE
+ if ( !( lParam & GSMDF_TCHAR ))
+ {
+ static char szMode[64];
+ char *buf2 = mir_u2a(buf1);
+ mir_snprintf(szMode, SIZEOF(szMode), "%s", buf2);
+ mir_free(buf2);
+ return (INT_PTR)szMode;
+ }
+ #endif
+
+ return (INT_PTR)buf1;
+}
+
+static int ProtocolAck(WPARAM, LPARAM lParam)
+{
+ ACKDATA *ack = (ACKDATA *) lParam;
+
+ if (ack->type != ACKTYPE_STATUS)
+ return 0;
+ CallService(MS_CLUI_PROTOCOLSTATUSCHANGED, ack->lParam, (LPARAM) ack->szModule);
+
+ if ((int) ack->hProcess < ID_STATUS_ONLINE && ack->lParam >= ID_STATUS_ONLINE) {
+ DWORD caps;
+ caps = (DWORD) CallProtoService(ack->szModule, PS_GETCAPS, PFLAGNUM_1, 0);
+ if (caps & PF1_SERVERCLIST) {
+ HANDLE hContact;
+ char *szProto;
+
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while (hContact) {
+ szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+ if (szProto != NULL && !strcmp(szProto, ack->szModule))
+ if (DBGetContactSettingByte(hContact, "CList", "Delete", 0))
+ CallService(MS_DB_CONTACT_DELETE, (WPARAM) hContact, 0);
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0);
+ } } }
+
+ cli.pfnTrayIconUpdateBase(ack->szModule);
+ return 0;
+}
+
+HICON fnGetIconFromStatusMode( HANDLE hContact, const char *szProto, int status )
+{
+ return ImageList_GetIcon( hCListImages, cli.pfnIconFromStatusMode( szProto, status, hContact ), ILD_NORMAL);
+}
+
+int fnIconFromStatusMode(const char *szProto, int status, HANDLE )
+{
+ int index, i;
+
+ for ( index = 0; index < SIZEOF(statusModeList); index++ )
+ if ( status == statusModeList[index] )
+ break;
+
+ if ( index == SIZEOF(statusModeList))
+ index = 0;
+ if (szProto == NULL)
+ return index + 1;
+ for ( i = 0; i < protoIconIndex.getCount(); i++ ) {
+ if (strcmp(szProto, protoIconIndex[i].szProto) == 0)
+ return protoIconIndex[i].iIconBase + index;
+ }
+ return 1;
+}
+
+static INT_PTR GetContactIcon(WPARAM wParam, LPARAM)
+{
+ char *szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ HANDLE hContact = (HANDLE)wParam;
+
+ return cli.pfnIconFromStatusMode(szProto,
+ szProto == NULL ? ID_STATUS_OFFLINE : DBGetContactSettingWord(hContact, szProto, "Status", ID_STATUS_OFFLINE), hContact);
+}
+
+static void AddProtoIconIndex( PROTOACCOUNT* pa )
+{
+ ProtoIconIndex *pii = new ProtoIconIndex;
+ pii->szProto = pa->szModuleName;
+ for (int i = 0; i < SIZEOF(statusModeList); i++) {
+ int iImg = ImageList_AddIcon_ProtoIconLibLoaded(hCListImages, pa->szModuleName, statusModeList[i] );
+ if (i == 0)
+ pii->iIconBase = iImg;
+ }
+ protoIconIndex.insert(pii);
+}
+
+static void RemoveProtoIconIndex( PROTOACCOUNT* pa )
+{
+ for (int i = 0; i < protoIconIndex.getCount(); i++)
+ if (strcmp(protoIconIndex[i].szProto, pa->szModuleName) == 0) {
+ protoIconIndex.remove(i);
+ break;
+ }
+}
+
+static int ContactListModulesLoaded(WPARAM, LPARAM)
+{
+ if ( !ServiceExists( MS_DB_CONTACT_GETSETTING_STR )) {
+ MessageBox( NULL, TranslateT( "This plugin requires db3x plugin version 0.5.1.0 or later" ), _T("CList"), MB_OK );
+ return 1;
+ }
+
+ RebuildMenuOrder();
+ for (int i = 0; i < accounts.getCount(); i++)
+ AddProtoIconIndex( accounts[i] );
+
+ cli.pfnLoadContactTree();
+
+ LoadCLUIModule();
+
+ InitClistHotKeys();
+
+ return 0;
+}
+
+static int ContactListAccountsChanged( WPARAM eventCode, LPARAM lParam )
+{
+ switch (eventCode)
+ {
+ case PRAC_ADDED:
+ AddProtoIconIndex(( PROTOACCOUNT* )lParam );
+ break;
+
+ case PRAC_REMOVED:
+ RemoveProtoIconIndex(( PROTOACCOUNT* )lParam );
+ break;
+ }
+ cli.pfnReloadProtoMenus();
+ cli.pfnTrayIconIconsChanged();
+ cli.pfnClcBroadcast( INTM_RELOADOPTIONS, 0, 0 );
+ cli.pfnClcBroadcast( INTM_INVALIDATE, 0, 0 );
+ return 0;
+}
+
+static INT_PTR ContactDoubleClicked(WPARAM wParam, LPARAM)
+{
+ // Try to process event myself
+ if ( cli.pfnEventsProcessContactDoubleClick(( HANDLE )wParam ) == 0 )
+ return 0;
+
+ // Allow third-party plugins to process a dblclick
+ if ( NotifyEventHooks( hContactDoubleClicked, wParam, 0 ))
+ return 0;
+
+ // Otherwise try to execute the default action
+ TryProcessDoubleClick(( HANDLE )wParam );
+ return 0;
+}
+
+static INT_PTR GetIconsImageList(WPARAM, LPARAM)
+{
+ return (INT_PTR)hCListImages;
+}
+
+static INT_PTR ContactFilesDropped(WPARAM wParam, LPARAM lParam)
+{
+ CallService(MS_FILE_SENDSPECIFICFILES, wParam, lParam);
+ return 0;
+}
+
+static int CListIconsChanged(WPARAM, LPARAM)
+{
+ int i, j;
+
+ for (i = 0; i < SIZEOF(statusModeList); i++)
+ ImageList_ReplaceIcon_IconLibLoaded(hCListImages, i + 1, LoadSkinIcon( skinIconStatusList[i] ));
+ ImageList_ReplaceIcon_IconLibLoaded(hCListImages, IMAGE_GROUPOPEN, LoadSkinIcon( SKINICON_OTHER_GROUPOPEN ));
+ ImageList_ReplaceIcon_IconLibLoaded(hCListImages, IMAGE_GROUPSHUT, LoadSkinIcon( SKINICON_OTHER_GROUPSHUT ));
+ for (i = 0; i < protoIconIndex.getCount(); i++)
+ for (j = 0; j < SIZEOF(statusModeList); j++)
+ ImageList_ReplaceIcon_IconLibLoaded(hCListImages, protoIconIndex[i].iIconBase + j, LoadSkinProtoIcon(protoIconIndex[i].szProto, statusModeList[j] ));
+ cli.pfnTrayIconIconsChanged();
+ cli.pfnInvalidateRect( cli.hwndContactList, NULL, TRUE);
+ return 0;
+}
+
+/*
+Begin of Hrk's code for bug
+*/
+#define GWVS_HIDDEN 1
+#define GWVS_VISIBLE 2
+#define GWVS_COVERED 3
+#define GWVS_PARTIALLY_COVERED 4
+
+int fnGetWindowVisibleState(HWND hWnd, int iStepX, int iStepY)
+{
+ RECT rc, rcWin, rcWorkArea;
+ POINT pt;
+ register int i, j, width, height, iCountedDots = 0, iNotCoveredDots = 0;
+ BOOL bPartiallyCovered = FALSE;
+ HWND hAux = 0;
+
+ if (hWnd == NULL) {
+ SetLastError(0x00000006); //Wrong handle
+ return -1;
+ }
+ //Some defaults now. The routine is designed for thin and tall windows.
+ if (iStepX <= 0)
+ iStepX = 4;
+ if (iStepY <= 0)
+ iStepY = 16;
+
+ if (IsIconic(hWnd) || !IsWindowVisible(hWnd))
+ return GWVS_HIDDEN;
+ else
+ {
+ if (CallService(MS_CLIST_DOCKINGISDOCKED, 0, 0))
+ return GWVS_VISIBLE;
+
+ GetWindowRect(hWnd, &rcWin);
+
+ SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWorkArea, FALSE);
+ if (MyMonitorFromWindow)
+ {
+ HMONITOR hMon = MyMonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
+ MONITORINFO mi;
+ mi.cbSize = sizeof(mi);
+ if (MyGetMonitorInfo(hMon, &mi))
+ rcWorkArea = mi.rcWork;
+ }
+
+ IntersectRect(&rc, &rcWin, &rcWorkArea);
+
+ width = rc.right - rc.left;
+ height = rc.bottom - rc.top;
+
+ for (i = rc.top; i < rc.bottom; i += (height / iStepY)) {
+ pt.y = i;
+ for (j = rc.left; j < rc.right; j += (width / iStepX)) {
+ pt.x = j;
+ hAux = WindowFromPoint(pt);
+ while (GetParent(hAux) != NULL)
+ hAux = GetParent(hAux);
+ if (hAux != hWnd && hAux != NULL) //There's another window!
+ bPartiallyCovered = TRUE;
+ else
+ iNotCoveredDots++; //Let's count the not covered dots.
+ iCountedDots++; //Let's keep track of how many dots we checked.
+ }
+ }
+ if (iNotCoveredDots == iCountedDots) //Every dot was not covered: the window is visible.
+ return GWVS_VISIBLE;
+ else if (iNotCoveredDots == 0) //They're all covered!
+ return GWVS_COVERED;
+ else //There are dots which are visible, but they are not as many as the ones we counted: it's partially covered.
+ return GWVS_PARTIALLY_COVERED;
+ }
+}
+
+int fnShowHide(WPARAM, LPARAM)
+{
+ BOOL bShow = FALSE;
+
+ int iVisibleState = cli.pfnGetWindowVisibleState(cli.hwndContactList, 0, 0);
+
+ //bShow is FALSE when we enter the switch.
+ switch (iVisibleState) {
+ case GWVS_PARTIALLY_COVERED:
+ //If we don't want to bring it to top, we can use a simple break. This goes against readability ;-) but the comment explains it.
+ if (!DBGetContactSettingByte(NULL, "CList", "BringToFront", SETTING_BRINGTOFRONT_DEFAULT))
+ break;
+ case GWVS_COVERED: //Fall through (and we're already falling)
+ case GWVS_HIDDEN:
+ bShow = TRUE;
+ break;
+ case GWVS_VISIBLE: //This is not needed, but goes for readability.
+ bShow = FALSE;
+ break;
+ case -1: //We can't get here, both cli.hwndContactList and iStepX and iStepY are right.
+ return 0;
+ }
+ if (bShow == TRUE) {
+ RECT rcWindow;
+
+ ShowWindow(cli.hwndContactList, SW_RESTORE);
+ if (!DBGetContactSettingByte(NULL, "CList", "OnTop", SETTING_ONTOP_DEFAULT))
+ SetWindowPos(cli.hwndContactList, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
+ else
+ SetWindowPos(cli.hwndContactList, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+
+ SetForegroundWindow(cli.hwndContactList);
+ DBWriteContactSettingByte(NULL, "CList", "State", SETTING_STATE_NORMAL);
+
+ //this forces the window onto the visible screen
+ GetWindowRect(cli.hwndContactList, &rcWindow);
+ if (Utils_AssertInsideScreen(&rcWindow) == 1)
+ {
+ MoveWindow(cli.hwndContactList, rcWindow.left, rcWindow.top,
+ rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, TRUE);
+ }
+ }
+ else { //It needs to be hidden
+ if (DBGetContactSettingByte(NULL, "CList", "ToolWindow", SETTING_TOOLWINDOW_DEFAULT) ||
+ DBGetContactSettingByte(NULL, "CList", "Min2Tray", SETTING_MIN2TRAY_DEFAULT))
+ {
+ ShowWindow(cli.hwndContactList, SW_HIDE);
+ DBWriteContactSettingByte(NULL, "CList", "State", SETTING_STATE_HIDDEN);
+ }
+ else
+ {
+ ShowWindow(cli.hwndContactList, SW_MINIMIZE);
+ DBWriteContactSettingByte(NULL, "CList", "State", SETTING_STATE_MINIMIZED);
+ }
+
+ if (MySetProcessWorkingSetSize != NULL && DBGetContactSettingByte(NULL, "CList", "DisableWorkingSet", 1))
+ MySetProcessWorkingSetSize(GetCurrentProcess(), -1, -1);
+ }
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// old evil code. hopefully it will be deleted soon, cause nobody uses it now
+
+#define SAFESTRING(a) a?a:""
+
+int GetStatusModeOrdering(int statusMode);
+extern int sortByStatus, sortByProto;
+
+static INT_PTR CompareContacts( WPARAM wParam, LPARAM lParam )
+{
+ HANDLE a = (HANDLE) wParam, b = (HANDLE) lParam;
+ TCHAR namea[128], *nameb;
+ int statusa, statusb;
+ char *szProto1, *szProto2;
+ int rc;
+
+ szProto1 = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) a, 0);
+ szProto2 = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) b, 0);
+ statusa = DBGetContactSettingWord((HANDLE) a, SAFESTRING(szProto1), "Status", ID_STATUS_OFFLINE);
+ statusb = DBGetContactSettingWord((HANDLE) b, SAFESTRING(szProto2), "Status", ID_STATUS_OFFLINE);
+
+ if (sortByProto) {
+ /* deal with statuses, online contacts have to go above offline */
+ if ((statusa == ID_STATUS_OFFLINE) != (statusb == ID_STATUS_OFFLINE)) {
+ return 2 * (statusa == ID_STATUS_OFFLINE) - 1;
+ }
+ /* both are online, now check protocols */
+ rc = strcmp(SAFESTRING(szProto1), SAFESTRING(szProto2)); /* strcmp() doesn't like NULL so feed in "" as needed */
+ if (rc != 0 && (szProto1 != NULL && szProto2 != NULL))
+ return rc;
+ /* protocols are the same, order by display name */
+ }
+
+ if (sortByStatus) {
+ int ordera, orderb;
+ ordera = GetStatusModeOrdering(statusa);
+ orderb = GetStatusModeOrdering(statusb);
+ if (ordera != orderb)
+ return ordera - orderb;
+ }
+ else {
+ //one is offline: offline goes below online
+ if ((statusa == ID_STATUS_OFFLINE) != (statusb == ID_STATUS_OFFLINE)) {
+ return 2 * (statusa == ID_STATUS_OFFLINE) - 1;
+ }
+ }
+
+ nameb = cli.pfnGetContactDisplayName( a, 0);
+ _tcsncpy(namea, nameb, SIZEOF(namea));
+ namea[ SIZEOF(namea)-1 ] = 0;
+ nameb = cli.pfnGetContactDisplayName( b, 0);
+
+ //otherwise just compare names
+ return _tcsicmp(namea, nameb);
+}
+
+/***************************************************************************************/
+
+static INT_PTR TrayIconProcessMessageStub( WPARAM wParam, LPARAM lParam ) { return cli.pfnTrayIconProcessMessage( wParam, lParam ); }
+static INT_PTR TrayIconPauseAutoHideStub( WPARAM wParam, LPARAM lParam ) { return cli.pfnTrayIconPauseAutoHide( wParam, lParam ); }
+static INT_PTR ShowHideStub( WPARAM wParam, LPARAM lParam ) { return cli.pfnShowHide( wParam, lParam ); }
+static INT_PTR SetHideOfflineStub( WPARAM wParam, LPARAM lParam ) { return cli.pfnSetHideOffline( wParam, lParam ); }
+static INT_PTR Docking_ProcessWindowMessageStub( WPARAM wParam, LPARAM lParam ) { return cli.pfnDocking_ProcessWindowMessage( wParam, lParam ); }
+static INT_PTR HotkeysProcessMessageStub( WPARAM wParam, LPARAM lParam ) { return cli.pfnHotkeysProcessMessage( wParam, lParam ); }
+
+int LoadContactListModule2(void)
+{
+ HookEvent(ME_SYSTEM_MODULESLOADED, ContactListModulesLoaded);
+ HookEvent(ME_PROTO_ACCLISTCHANGED, ContactListAccountsChanged);
+ hContactSettingChanged = HookEvent(ME_DB_CONTACT_SETTINGCHANGED, ContactSettingChanged);
+ HookEvent(ME_DB_CONTACT_ADDED, ContactAdded);
+ HookEvent(ME_DB_CONTACT_DELETED, ContactDeleted);
+ hProtoAckHook = (HANDLE) HookEvent(ME_PROTO_ACK, ProtocolAck);
+ hContactDoubleClicked = CreateHookableEvent(ME_CLIST_DOUBLECLICKED);
+ hContactIconChangedEvent = CreateHookableEvent(ME_CLIST_CONTACTICONCHANGED);
+ CreateServiceFunction(MS_CLIST_CONTACTDOUBLECLICKED, ContactDoubleClicked);
+ CreateServiceFunction(MS_CLIST_CONTACTFILESDROPPED, ContactFilesDropped);
+ CreateServiceFunction(MS_CLIST_GETSTATUSMODEDESCRIPTION, GetStatusModeDescription);
+ CreateServiceFunction(MS_CLIST_GETCONTACTDISPLAYNAME, GetContactDisplayName);
+ CreateServiceFunction(MS_CLIST_INVALIDATEDISPLAYNAME, InvalidateDisplayName);
+ CreateServiceFunction(MS_CLIST_TRAYICONPROCESSMESSAGE, TrayIconProcessMessageStub );
+ CreateServiceFunction(MS_CLIST_PAUSEAUTOHIDE, TrayIconPauseAutoHideStub);
+ CreateServiceFunction(MS_CLIST_CONTACTSCOMPARE, CompareContacts);
+ CreateServiceFunction(MS_CLIST_CONTACTCHANGEGROUP, ContactChangeGroup);
+ CreateServiceFunction(MS_CLIST_SHOWHIDE, ShowHideStub);
+ CreateServiceFunction(MS_CLIST_SETHIDEOFFLINE, SetHideOfflineStub);
+ CreateServiceFunction(MS_CLIST_DOCKINGPROCESSMESSAGE, Docking_ProcessWindowMessageStub);
+ CreateServiceFunction(MS_CLIST_DOCKINGISDOCKED, Docking_IsDocked);
+ CreateServiceFunction(MS_CLIST_HOTKEYSPROCESSMESSAGE, HotkeysProcessMessageStub);
+ CreateServiceFunction(MS_CLIST_GETCONTACTICON, GetContactIcon);
+ MySetProcessWorkingSetSize = (BOOL(WINAPI *) (HANDLE, SIZE_T, SIZE_T)) GetProcAddress(GetModuleHandleA("kernel32"), "SetProcessWorkingSetSize");
+ InitDisplayNameCache();
+ InitCListEvents();
+ InitGroupServices();
+ cli.pfnInitTray();
+
+ hCListImages = ImageList_Create(16, 16, ILC_MASK | (IsWinVerXPPlus()? ILC_COLOR32 : ILC_COLOR16), 13, 0);
+ HookEvent(ME_SKIN_ICONSCHANGED, CListIconsChanged);
+ CreateServiceFunction(MS_CLIST_GETICONSIMAGELIST, GetIconsImageList);
+
+ ImageList_AddIcon_NotShared(hCListImages, MAKEINTRESOURCE(IDI_BLANK));
+
+ {
+ int i;
+ //now all core skin icons are loaded via icon lib. so lets release them
+ for (i = 0; i < SIZEOF(statusModeList); i++)
+ ImageList_AddIcon_IconLibLoaded(hCListImages, skinIconStatusList[i] );
+ }
+
+ //see IMAGE_GROUP... in clist.h if you add more images above here
+ ImageList_AddIcon_IconLibLoaded(hCListImages, SKINICON_OTHER_GROUPOPEN );
+ ImageList_AddIcon_IconLibLoaded(hCListImages, SKINICON_OTHER_GROUPSHUT );
+ return 0;
+}
+
+void UnloadContactListModule()
+{
+ if ( hCListImages ) {
+ //remove transitory contacts
+ HANDLE hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while (hContact != NULL) {
+ HANDLE hNext = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0);
+ if (DBGetContactSettingByte(hContact, "CList", "NotOnList", 0))
+ CallService(MS_DB_CONTACT_DELETE, (WPARAM) hContact, 0);
+ hContact = hNext;
+ }
+ ImageList_Destroy(hCListImages);
+ UnhookEvent(hProtoAckHook);
+ UninitCListEvents();
+ protoIconIndex.destroy();
+ DestroyHookableEvent(hContactDoubleClicked);
+ UnhookEvent(hContactSettingChanged);
+} }
diff --git a/src/modules/clist/clistsettings.cpp b/src/modules/clist/clistsettings.cpp
new file mode 100644
index 0000000000..df92386ded
--- /dev/null
+++ b/src/modules/clist/clistsettings.cpp
@@ -0,0 +1,331 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2010 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 "clc.h"
+
+SortedList* clistCache = NULL;
+
+static int compareContacts( ClcCacheEntryBase* p1, ClcCacheEntryBase* p2 )
+{
+ return ( char* )p1->hContact - ( char* )p2->hContact;
+}
+
+void InitDisplayNameCache(void)
+{
+ clistCache = List_Create( 0, 50 );
+ clistCache->sortFunc = ( FSortFunc )compareContacts;
+}
+
+void FreeDisplayNameCache(void)
+{
+ if ( clistCache != NULL ) {
+ int i;
+ for ( i = 0; i < clistCache->realCount; i++) {
+ cli.pfnFreeCacheItem(( ClcCacheEntryBase* )clistCache->items[i] );
+ mir_free( clistCache->items[i] );
+ }
+
+ List_Destroy( clistCache );
+ mir_free(clistCache);
+ clistCache = NULL;
+} }
+
+// default handlers for the cache item creation and destruction
+
+ClcCacheEntryBase* fnCreateCacheItem( HANDLE hContact )
+{
+ ClcCacheEntryBase* p = ( ClcCacheEntryBase* )mir_calloc( sizeof( ClcCacheEntryBase ));
+ if ( p == NULL )
+ return NULL;
+
+ p->hContact = hContact;
+ return p;
+}
+
+void fnCheckCacheItem( ClcCacheEntryBase* p )
+{
+ DBVARIANT dbv;
+ if ( p->group == NULL ) {
+ if ( !DBGetContactSettingTString( p->hContact, "CList", "Group", &dbv )) {
+ p->group = mir_tstrdup( dbv.ptszVal );
+ mir_free( dbv.ptszVal );
+ }
+ else p->group = mir_tstrdup( _T("") );
+ }
+
+ if ( p->isHidden == -1 )
+ p->isHidden = DBGetContactSettingByte( p->hContact, "CList", "Hidden", 0 );
+}
+
+void fnFreeCacheItem( ClcCacheEntryBase* p )
+{
+ if ( p->name ) { mir_free( p->name ); p->name = NULL; }
+ #if defined( _UNICODE )
+ if ( p->szName ) { mir_free( p->szName); p->szName = NULL; }
+ #endif
+ if ( p->group ) { mir_free( p->group ); p->group = NULL; }
+ p->isHidden = -1;
+}
+
+ClcCacheEntryBase* fnGetCacheEntry(HANDLE hContact)
+{
+ ClcCacheEntryBase* p;
+ int idx;
+ if ( !List_GetIndex( clistCache, &hContact, &idx )) {
+ if (( p = cli.pfnCreateCacheItem( hContact )) != NULL ) {
+ List_Insert( clistCache, p, idx );
+ cli.pfnInvalidateDisplayNameCacheEntry( p );
+ }
+ }
+ else p = ( ClcCacheEntryBase* )clistCache->items[idx];
+
+ cli.pfnCheckCacheItem( p );
+ return p;
+}
+
+void fnInvalidateDisplayNameCacheEntry(HANDLE hContact)
+{
+ if (hContact == INVALID_HANDLE_VALUE) {
+ FreeDisplayNameCache();
+ InitDisplayNameCache();
+ SendMessage(cli.hwndContactTree, CLM_AUTOREBUILD, 0, 0);
+ }
+ else {
+ int idx;
+ if ( List_GetIndex( clistCache, &hContact, &idx ))
+ cli.pfnFreeCacheItem(( ClcCacheEntryBase* )clistCache->items[idx] );
+} }
+
+TCHAR* fnGetContactDisplayName( HANDLE hContact, int mode )
+{
+ CONTACTINFO ci;
+ TCHAR *buffer;
+ ClcCacheEntryBase* cacheEntry = NULL;
+
+ if ( mode & GCDNF_NOCACHE )
+ mode &= ~GCDNF_NOCACHE;
+ else if ( mode != GCDNF_NOMYHANDLE) {
+ cacheEntry = cli.pfnGetCacheEntry( hContact );
+ if ( cacheEntry->name )
+ return cacheEntry->name;
+ }
+ ZeroMemory(&ci, sizeof(ci));
+ ci.cbSize = sizeof(ci);
+ ci.hContact = hContact;
+ if (ci.hContact == NULL)
+ ci.szProto = "ICQ";
+ ci.dwFlag = ((mode == GCDNF_NOMYHANDLE) ? CNF_DISPLAYNC : CNF_DISPLAY) | CNF_TCHAR;
+ if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) {
+ if (ci.type == CNFT_ASCIIZ) {
+ if (cacheEntry == NULL)
+ return ci.pszVal;
+
+ cacheEntry->name = ci.pszVal;
+ #if defined( _UNICODE )
+ cacheEntry->szName = mir_u2a( ci.pszVal );
+ #endif
+ return ci.pszVal;
+ }
+
+ if (ci.type == CNFT_DWORD) {
+ if (cacheEntry == NULL) {
+ buffer = (TCHAR*) mir_alloc(15 * sizeof( TCHAR ));
+ _ltot(ci.dVal, buffer, 10 );
+ return buffer;
+ }
+ else {
+ buffer = (TCHAR*) mir_alloc(15 * sizeof( TCHAR ));
+ _ltot(ci.dVal, buffer, 10 );
+ cacheEntry->name = buffer;
+ #if defined( _UNICODE )
+ cacheEntry->szName = mir_u2a( buffer );
+ #endif
+ return buffer;
+ } } }
+
+ CallContactService(hContact, PSS_GETINFO, SGIF_MINIMAL, 0);
+ buffer = TranslateT("(Unknown Contact)");
+ return ( cacheEntry == NULL ) ? mir_tstrdup( buffer ) : buffer;
+}
+
+INT_PTR GetContactDisplayName(WPARAM wParam, LPARAM lParam)
+{
+ CONTACTINFO ci;
+ ClcCacheEntryBase* cacheEntry = NULL;
+ char *buffer;
+ HANDLE hContact = (HANDLE)wParam;
+
+ if ( lParam & GCDNF_UNICODE )
+ return ( INT_PTR )cli.pfnGetContactDisplayName(hContact, lParam & ~GCDNF_UNICODE );
+
+ if ((int) lParam != GCDNF_NOMYHANDLE) {
+ cacheEntry = cli.pfnGetCacheEntry(hContact);
+ #if defined( _UNICODE )
+ if ( cacheEntry->szName )
+ return (INT_PTR)cacheEntry->szName;
+ #else
+ if ( cacheEntry->name )
+ return (INT_PTR)cacheEntry->name;
+ #endif
+ }
+ ZeroMemory(&ci, sizeof(ci));
+ ci.cbSize = sizeof(ci);
+ ci.hContact = hContact;
+ if (ci.hContact == NULL)
+ ci.szProto = "ICQ";
+ ci.dwFlag = ((lParam == GCDNF_NOMYHANDLE) ? CNF_DISPLAYNC : CNF_DISPLAY) | CNF_TCHAR;
+ if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) {
+ if (ci.type == CNFT_ASCIIZ) {
+ if (cacheEntry == NULL) {
+ #if defined( _UNICODE )
+ buffer = mir_u2a( ci.pszVal );
+ mir_free(ci.pszVal);
+ #else
+ buffer = ci.pszVal;
+ #endif
+ return (INT_PTR) buffer;
+ }
+ else {
+ cacheEntry->name = ci.pszVal;
+ #if defined( _UNICODE )
+ cacheEntry->szName = mir_u2a( ci.pszVal );
+ return (INT_PTR)cacheEntry->szName;
+ #else
+ return (INT_PTR)cacheEntry->name;
+ #endif
+ }
+ }
+ if (ci.type == CNFT_DWORD) {
+ if (cacheEntry == NULL) {
+ buffer = ( char* )mir_alloc(15);
+ _ltoa(ci.dVal, buffer, 10 );
+ return (INT_PTR) buffer;
+ }
+ else {
+ buffer = ( char* )mir_alloc(15);
+ _ltoa(ci.dVal, buffer, 10 );
+ #if defined( _UNICODE )
+ cacheEntry->szName = buffer;
+ cacheEntry->name = mir_a2u( buffer );
+ #else
+ cacheEntry->name = buffer;
+ #endif
+ return (INT_PTR) buffer;
+ } } }
+
+ CallContactService(hContact, PSS_GETINFO, SGIF_MINIMAL, 0);
+ buffer = Translate("(Unknown Contact)");
+ return (INT_PTR) buffer;
+}
+
+INT_PTR InvalidateDisplayName(WPARAM wParam, LPARAM)
+{
+ cli.pfnInvalidateDisplayNameCacheEntry((HANDLE)wParam);
+ return 0;
+}
+
+int ContactAdded(WPARAM wParam, LPARAM)
+{
+ cli.pfnChangeContactIcon((HANDLE)wParam, cli.pfnIconFromStatusMode((char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0), ID_STATUS_OFFLINE, NULL), 1);
+ cli.pfnSortContacts();
+ return 0;
+}
+
+int ContactDeleted(WPARAM wParam, LPARAM)
+{
+ CallService(MS_CLUI_CONTACTDELETED, wParam, 0);
+ return 0;
+}
+
+int ContactSettingChanged(WPARAM wParam, LPARAM lParam)
+{
+ DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING *) lParam;
+ DBVARIANT dbv;
+ HANDLE hContact = (HANDLE)wParam;
+
+ // Early exit
+ if ( hContact == NULL)
+ return 0;
+
+ dbv.pszVal = NULL;
+ if (!DBGetContactSetting(hContact, "Protocol", "p", &dbv)) {
+ if (!strcmp(cws->szModule, dbv.pszVal)) {
+ cli.pfnInvalidateDisplayNameCacheEntry(hContact);
+ if (!strcmp(cws->szSetting, "UIN") || !strcmp(cws->szSetting, "Nick") || !strcmp(cws->szSetting, "FirstName")
+ || !strcmp(cws->szSetting, "LastName") || !strcmp(cws->szSetting, "e-mail")) {
+ CallService(MS_CLUI_CONTACTRENAMED, wParam, 0);
+ }
+ else if (!strcmp(cws->szSetting, "Status")) {
+ if (!DBGetContactSettingByte(hContact, "CList", "Hidden", 0)) {
+ if (DBGetContactSettingByte(NULL, "CList", "HideOffline", SETTING_HIDEOFFLINE_DEFAULT)) {
+ // User's state is changing, and we are hideOffline-ing
+ if (cws->value.wVal == ID_STATUS_OFFLINE) {
+ cli.pfnChangeContactIcon(hContact, cli.pfnIconFromStatusMode(cws->szModule, cws->value.wVal, hContact), 0);
+ CallService(MS_CLUI_CONTACTDELETED, wParam, 0);
+ mir_free(dbv.pszVal);
+ return 0;
+ }
+ cli.pfnChangeContactIcon(hContact, cli.pfnIconFromStatusMode(cws->szModule, cws->value.wVal, hContact), 1);
+ }
+ cli.pfnChangeContactIcon(hContact, cli.pfnIconFromStatusMode(cws->szModule, cws->value.wVal, hContact), 0);
+ }
+ }
+ else {
+ mir_free(dbv.pszVal);
+ return 0;
+ }
+ cli.pfnSortContacts();
+ } }
+
+ if (!strcmp(cws->szModule, "CList")) {
+ if (!strcmp(cws->szSetting, "Hidden")) {
+ if (cws->value.type == DBVT_DELETED || cws->value.bVal == 0) {
+ char *szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ cli.pfnChangeContactIcon(hContact, cli.pfnIconFromStatusMode(szProto, szProto == NULL ? ID_STATUS_OFFLINE : DBGetContactSettingWord(hContact, szProto, "Status", ID_STATUS_OFFLINE), hContact), 1);
+ }
+ else
+ CallService(MS_CLUI_CONTACTDELETED, wParam, 0);
+ }
+ if (!strcmp(cws->szSetting, "MyHandle"))
+ cli.pfnInvalidateDisplayNameCacheEntry(hContact);
+ }
+
+ if (!strcmp(cws->szModule, "Protocol")) {
+ if (!strcmp(cws->szSetting, "p")) {
+ char *szProto;
+ if (cws->value.type == DBVT_DELETED)
+ szProto = NULL;
+ else
+ szProto = cws->value.pszVal;
+ cli.pfnChangeContactIcon(hContact,
+ cli.pfnIconFromStatusMode(szProto,
+ szProto == NULL ? ID_STATUS_OFFLINE : DBGetContactSettingWord(hContact, szProto, "Status",
+ ID_STATUS_OFFLINE), hContact), 0);
+ } }
+
+ // Clean up
+ if (dbv.pszVal)
+ mir_free(dbv.pszVal);
+
+ return 0;
+}
diff --git a/src/modules/clist/clisttray.cpp b/src/modules/clist/clisttray.cpp
new file mode 100644
index 0000000000..2292020c48
--- /dev/null
+++ b/src/modules/clist/clisttray.cpp
@@ -0,0 +1,980 @@
+/*
+
+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 "clc.h"
+
+#define TOOLTIP_TOLERANCE 5
+
+extern HIMAGELIST hCListImages;
+extern BOOL(WINAPI * MySetProcessWorkingSetSize) (HANDLE, SIZE_T, SIZE_T);
+
+int GetAverageMode(int* pNetProtoCount = NULL);
+
+static UINT WM_TASKBARCREATED;
+static UINT WM_TASKBARBUTTONCREATED;
+static BOOL mToolTipTrayTips = FALSE;
+static UINT_PTR cycleTimerId = 0;
+static int cycleStep = 0;
+static UINT_PTR RefreshTimerId=0; /////by FYR
+static CRITICAL_SECTION trayLockCS;
+
+// don't move to win2k.h, need new and old versions to work on 9x/2000/XP
+#define NIF_STATE 0x00000008
+#define NIF_INFO 0x00000010
+
+#define lock cli.pfnLockTray()
+#define ulock cli.pfnUnlockTray()
+
+#define initcheck if(!fTrayInited) return
+
+static BOOL fTrayInited=FALSE;
+
+static TCHAR* sttGetXStatus( const char* szProto )
+{
+ TCHAR* result = NULL;
+
+ if ( CallProtoService( szProto, PS_GETSTATUS, 0, 0 ) > ID_STATUS_OFFLINE ) {
+ char str[MAXMODULELABELLENGTH];
+ mir_snprintf( str, sizeof(str), "%s/GetXStatus", szProto );
+ if ( ServiceExists( str )) {
+ char* dbTitle = "XStatusName";
+ char* dbTitle2 = NULL;
+ int xstatus = CallProtoService( szProto, "/GetXStatus", ( WPARAM )&dbTitle, ( LPARAM )&dbTitle2 );
+ if ( dbTitle && xstatus ) {
+ DBVARIANT dbv={0};
+ if ( !DBGetContactSettingTString(NULL, szProto, dbTitle, &dbv )) {
+ if ( dbv.ptszVal[0] != 0 )
+ result = mir_tstrdup(dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ } } } }
+
+ return result;
+}
+
+static HICON lastTaskBarIcon;
+static void SetTaskBarIcon(const HICON hIcon, const TCHAR *szNewTip)
+{
+ if (pTaskbarInterface)
+ {
+ wchar_t *szTip = mir_t2u(szNewTip);
+ pTaskbarInterface->SetOverlayIcon(cli.hwndContactList, hIcon, szTip);
+ mir_free(szTip);
+ lastTaskBarIcon = hIcon;
+ }
+}
+
+TCHAR* fnTrayIconMakeTooltip( const TCHAR *szPrefix, const char *szProto )
+{
+ TCHAR *szStatus, *szSeparator;
+ TCHAR *ProtoXStatus=NULL;
+ int t;
+ PROTOACCOUNT* pa;
+ initcheck NULL;
+ lock;
+ if ( !mToolTipTrayTips )
+ szSeparator = (IsWinVerMEPlus()) ? szSeparator = _T("\n") : _T(" | ");
+ else
+ szSeparator = _T("\n");
+
+ if (szProto == NULL) {
+ if (accounts.getCount() == 0) {
+ ulock;
+ return NULL;
+ }
+ if (accounts.getCount() == 1) {
+ ulock;
+ return cli.pfnTrayIconMakeTooltip(szPrefix, accounts[0]->szModuleName);
+ }
+
+ if (szPrefix && szPrefix[0]) {
+ lstrcpyn(cli.szTip, szPrefix, MAX_TIP_SIZE);
+ if (!DBGetContactSettingByte(NULL, "CList", "AlwaysStatus", SETTING_ALWAYSSTATUS_DEFAULT))
+ { ulock; return cli.szTip; }
+ }
+ else cli.szTip[0] = '\0';
+ cli.szTip[ MAX_TIP_SIZE-1 ] = '\0';
+
+ for ( t = 0; t < accounts.getCount(); t++ ) {
+ int i = cli.pfnGetAccountIndexByPos( t );
+ if ( i == -1 )
+ continue;
+
+ pa = accounts[i];
+ if ( !cli.pfnGetProtocolVisibility( pa->szModuleName ))
+ continue;
+
+ szStatus = cli.pfnGetStatusModeDescription( CallProtoService( pa->szModuleName, PS_GETSTATUS, 0, 0), 0);
+ if ( !szStatus )
+ continue;
+
+ ProtoXStatus = sttGetXStatus( pa->szModuleName );
+
+ if ( mToolTipTrayTips ) {
+ TCHAR tipline[256];
+ mir_sntprintf(tipline, SIZEOF(tipline), _T("<b>%-12.12s</b>\t%s"), pa->tszAccountName, szStatus);
+ if ( cli.szTip[0] )
+ _tcsncat(cli.szTip, szSeparator, MAX_TIP_SIZE - _tcslen(cli.szTip));
+ _tcsncat(cli.szTip, tipline, MAX_TIP_SIZE - _tcslen(cli.szTip));
+ if (ProtoXStatus) {
+ mir_sntprintf(tipline, SIZEOF(tipline), _T("%-24.24s\n"), ProtoXStatus);
+ if ( cli.szTip[0] )
+ _tcsncat(cli.szTip, szSeparator, MAX_TIP_SIZE - _tcslen(cli.szTip));
+ _tcsncat(cli.szTip, tipline, MAX_TIP_SIZE - _tcslen(cli.szTip));
+ }
+ }
+ else {
+ if (cli.szTip[0])
+ _tcsncat(cli.szTip, szSeparator, MAX_TIP_SIZE - _tcslen(cli.szTip));
+
+ _tcsncat(cli.szTip, pa->tszAccountName, MAX_TIP_SIZE - _tcslen(cli.szTip));
+ _tcsncat(cli.szTip, _T(" "), MAX_TIP_SIZE - _tcslen(cli.szTip));
+ _tcsncat(cli.szTip, szStatus, MAX_TIP_SIZE - _tcslen(cli.szTip));
+ }
+ mir_free( ProtoXStatus );
+ }
+ }
+ else {
+ if (( pa = Proto_GetAccount( szProto )) != NULL ) {
+ ProtoXStatus = sttGetXStatus( szProto );
+ szStatus = cli.pfnGetStatusModeDescription(CallProtoService(szProto, PS_GETSTATUS, 0, 0), 0);
+ if ( szPrefix && szPrefix[0] ) {
+ if ( DBGetContactSettingByte( NULL, "CList", "AlwaysStatus", SETTING_ALWAYSSTATUS_DEFAULT )) {
+ if ( mToolTipTrayTips ) {
+ if ( ProtoXStatus )
+ mir_sntprintf(cli.szTip, MAX_TIP_SIZE, _T("%s%s<b>%-12.12s</b>\t%s%s%-24.24s"), szPrefix, szSeparator, pa->tszAccountName, szStatus,szSeparator,ProtoXStatus);
+ else
+ mir_sntprintf(cli.szTip, MAX_TIP_SIZE, _T("%s%s<b>%-12.12s</b>\t%s"), szPrefix, szSeparator, pa->tszAccountName, szStatus);
+ }
+ else mir_sntprintf(cli.szTip, MAX_TIP_SIZE, _T("%s%s%s %s"), szPrefix, szSeparator, pa->tszAccountName, szStatus);
+ }
+ else lstrcpyn(cli.szTip, szPrefix, MAX_TIP_SIZE);
+ }
+ else {
+ if ( mToolTipTrayTips ) {
+ if ( ProtoXStatus )
+ mir_sntprintf( cli.szTip, MAX_TIP_SIZE, _T("<b>%-12.12s</b>\t%s\n%-24.24s"), pa->tszAccountName, szStatus,ProtoXStatus);
+ else
+ mir_sntprintf( cli.szTip, MAX_TIP_SIZE, _T("<b>%-12.12s</b>\t%s"), pa->tszAccountName, szStatus);
+ }
+ else mir_sntprintf(cli.szTip, MAX_TIP_SIZE, _T("%s %s"), pa->tszAccountName, szStatus);
+ }
+ mir_free(ProtoXStatus);
+ } }
+
+ ulock;
+ return cli.szTip;
+}
+
+int fnTrayIconAdd(HWND hwnd, const char *szProto, const char *szIconProto, int status)
+{
+ NOTIFYICONDATA nid = { 0 };
+ int i;
+ initcheck 0;
+ lock;
+ for (i = 0; i < cli.trayIconCount; i++)
+ if (cli.trayIcon[i].id == 0)
+ break;
+
+ cli.trayIcon[i].id = TRAYICON_ID_BASE + i;
+ cli.trayIcon[i].szProto = (char *) szProto;
+ cli.trayIcon[i].hBaseIcon = cli.pfnGetIconFromStatusMode( NULL, szIconProto ? szIconProto : cli.trayIcon[i].szProto, status );
+
+ nid.cbSize = ( cli.shellVersion >= 5 ) ? sizeof(nid) : NOTIFYICONDATA_V1_SIZE;
+ nid.hWnd = hwnd;
+ nid.uID = cli.trayIcon[i].id;
+ nid.uFlags = mToolTipTrayTips ? NIF_ICON | NIF_MESSAGE : NIF_ICON | NIF_MESSAGE | NIF_TIP;
+ nid.uCallbackMessage = TIM_CALLBACK;
+ nid.hIcon = cli.trayIcon[i].hBaseIcon;
+
+ if (cli.shellVersion >= 5)
+ nid.uFlags |= NIF_INFO;
+
+ cli.pfnTrayIconMakeTooltip( NULL, cli.trayIcon[i].szProto );
+ if ( !mToolTipTrayTips )
+ lstrcpyn( nid.szTip, cli.szTip, SIZEOF( nid.szTip ));
+ cli.trayIcon[i].ptszToolTip = mir_tstrdup( cli.szTip );
+
+ Shell_NotifyIcon(NIM_ADD, &nid);
+ cli.trayIcon[i].isBase = 1;
+
+ if (cli.trayIconCount == 1)
+ SetTaskBarIcon(cli.trayIcon[0].hBaseIcon, cli.szTip);
+
+ ulock; return i;
+}
+
+void fnTrayIconRemove(HWND hwnd, const char *szProto)
+{
+ int i;
+ initcheck;
+ lock;
+ for ( i = 0; i < cli.trayIconCount; i++ ) {
+ struct trayIconInfo_t* pii = &cli.trayIcon[i];
+ if ( pii->id != 0 && !lstrcmpA( szProto, pii->szProto )) {
+ NOTIFYICONDATA nid = { 0 };
+ nid.cbSize = ( cli.shellVersion >= 5 ) ? sizeof(nid) : NOTIFYICONDATA_V1_SIZE;
+ nid.hWnd = hwnd;
+ nid.uID = pii->id;
+ Shell_NotifyIcon(NIM_DELETE, &nid);
+
+ DestroyIcon(pii->hBaseIcon);
+ mir_free(pii->ptszToolTip); pii->ptszToolTip = NULL;
+ pii->id = 0;
+ break;
+ } }
+
+ if (cli.trayIconCount == 1)
+ SetTaskBarIcon(NULL, NULL);
+
+ ulock;
+}
+
+int fnTrayIconInit(HWND hwnd)
+{
+ int netProtoCount = 0;
+ initcheck 0;
+ lock;
+
+ int averageMode = GetAverageMode(&netProtoCount);
+ mToolTipTrayTips = ServiceExists("mToolTip/ShowTip") != 0;
+
+ if ( cli.cycleTimerId ) {
+ KillTimer(NULL, cli.cycleTimerId);
+ cli.cycleTimerId = 0;
+ }
+
+ cli.trayIconCount = 1;
+
+ if (netProtoCount)
+ {
+ cli.trayIcon = (trayIconInfo_t *) mir_calloc(sizeof(trayIconInfo_t) * accounts.getCount());
+
+ int trayIconSetting = DBGetContactSettingByte(NULL, "CList", "TrayIcon", SETTING_TRAYICON_DEFAULT);
+
+ if (trayIconSetting == SETTING_TRAYICON_SINGLE)
+ {
+ DBVARIANT dbv = { DBVT_DELETED };
+ char *szProto;
+ if (!DBGetContactSettingString(NULL, "CList", "PrimaryStatus", &dbv)
+ && (averageMode < 0 || DBGetContactSettingByte(NULL, "CList", "AlwaysPrimary", 0) ))
+ szProto = dbv.pszVal;
+ else
+ szProto = NULL;
+
+ cli.pfnTrayIconAdd(hwnd, NULL, szProto, szProto ? CallProtoService(szProto, PS_GETSTATUS, 0, 0) : CallService(MS_CLIST_GETSTATUSMODE, 0, 0));
+ DBFreeVariant(&dbv);
+ }
+ else if (trayIconSetting == SETTING_TRAYICON_MULTI &&
+ (averageMode < 0 || DBGetContactSettingByte(NULL, "CList", "AlwaysMulti", SETTING_ALWAYSMULTI_DEFAULT )))
+ {
+ cli.trayIconCount = netProtoCount;
+ for (int i = 0; i < accounts.getCount(); ++i)
+ {
+ int j = cli.pfnGetAccountIndexByPos(i);
+ if (j >= 0)
+ {
+ PROTOACCOUNT* pa = accounts[j];
+ if (cli.pfnGetProtocolVisibility(pa->szModuleName))
+ cli.pfnTrayIconAdd(hwnd, pa->szModuleName, NULL, CallProtoService(pa->szModuleName, PS_GETSTATUS, 0, 0));
+ }
+ }
+ }
+ else
+ {
+ cli.pfnTrayIconAdd(hwnd, NULL, NULL, averageMode);
+
+ if (trayIconSetting == SETTING_TRAYICON_CYCLE && averageMode < 0)
+ cli.cycleTimerId = SetTimer(NULL, 0, DBGetContactSettingWord(NULL, "CList", "CycleTime", SETTING_CYCLETIME_DEFAULT) * 1000, cli.pfnTrayCycleTimerProc);
+ }
+ }
+ else
+ {
+ cli.trayIcon = (trayIconInfo_t *) mir_calloc(sizeof(trayIconInfo_t));
+ cli.pfnTrayIconAdd(hwnd, NULL, NULL, CallService(MS_CLIST_GETSTATUSMODE, 0, 0));
+ }
+
+ ulock;
+ return 0;
+}
+
+int fnTrayIconDestroy(HWND hwnd)
+{
+ NOTIFYICONDATA nid = { 0 };
+ int i;
+ initcheck 0;
+ lock;
+
+ if (cli.trayIconCount == 1)
+ SetTaskBarIcon(NULL, NULL);
+
+ nid.cbSize = ( cli.shellVersion >= 5 ) ? sizeof(nid) : NOTIFYICONDATA_V1_SIZE;
+ nid.hWnd = hwnd;
+ for ( i = 0; i < cli.trayIconCount; i++ ) {
+ if ( cli.trayIcon[i].id == 0 )
+ continue;
+ nid.uID = cli.trayIcon[i].id;
+ Shell_NotifyIcon( NIM_DELETE, &nid );
+ DestroyIcon( cli.trayIcon[i].hBaseIcon );
+ mir_free( cli.trayIcon[i].ptszToolTip );
+ }
+ mir_free(cli.trayIcon);
+ cli.trayIcon = NULL;
+ cli.trayIconCount = 0;
+
+ ulock;
+ return 0;
+}
+
+//called when Explorer crashes and the taskbar is remade
+void fnTrayIconTaskbarCreated(HWND hwnd)
+{
+ initcheck;
+ cli.pfnTrayIconDestroy(hwnd);
+ cli.pfnTrayIconInit(hwnd);
+}
+
+static VOID CALLBACK RefreshTimerProc(HWND, UINT, UINT_PTR, DWORD)
+{
+ int i;
+ if ( RefreshTimerId ) {
+ KillTimer(NULL,RefreshTimerId);
+ RefreshTimerId=0;
+ }
+ for (i=0; i < accounts.getCount(); i++) {
+ cli.pfnTrayIconUpdateBase( accounts[i]->szModuleName );
+ }
+}
+
+int fnTrayIconUpdate(HICON hNewIcon, const TCHAR *szNewTip, const char *szPreferredProto, int isBase)
+{
+ NOTIFYICONDATA nid = { 0 };
+ int i;
+
+ initcheck -1;
+ lock;
+ nid.cbSize = ( cli.shellVersion >= 5 ) ? sizeof(nid) : NOTIFYICONDATA_V1_SIZE;
+ nid.hWnd = cli.hwndContactList;
+ nid.uFlags = mToolTipTrayTips ? NIF_ICON : NIF_ICON | NIF_TIP;
+ nid.hIcon = hNewIcon;
+ if (!hNewIcon)
+ { ulock; return -1; }
+
+ for (i = 0; i < cli.trayIconCount; i++) {
+ if (cli.trayIcon[i].id == 0)
+ continue;
+ if (lstrcmpA(cli.trayIcon[i].szProto, szPreferredProto))
+ continue;
+
+ nid.uID = cli.trayIcon[i].id;
+ cli.pfnTrayIconMakeTooltip(szNewTip, cli.trayIcon[i].szProto);
+ mir_free( cli.trayIcon[i].ptszToolTip );
+ cli.trayIcon[i].ptszToolTip = mir_tstrdup( cli.szTip );
+ if (!mToolTipTrayTips)
+ lstrcpyn(nid.szTip, cli.szTip, SIZEOF(nid.szTip));
+ Shell_NotifyIcon(NIM_MODIFY, &nid);
+
+ if (cli.trayIconCount == 1)
+ SetTaskBarIcon(hNewIcon, cli.szTip);
+ else
+ SetTaskBarIcon(NULL, NULL);
+
+ cli.trayIcon[i].isBase = isBase;
+ { ulock; return i; }
+ }
+
+ //if there wasn't a suitable icon, change all the icons
+ {
+ for (i = 0; i < cli.trayIconCount; i++) {
+ if (cli.trayIcon[i].id == 0)
+ continue;
+ nid.uID = cli.trayIcon[i].id;
+
+ cli.pfnTrayIconMakeTooltip(szNewTip, cli.trayIcon[i].szProto);
+ mir_free( cli.trayIcon[i].ptszToolTip );
+ cli.trayIcon[i].ptszToolTip = mir_tstrdup( cli.szTip );
+ if(!mToolTipTrayTips)
+ lstrcpyn(nid.szTip, cli.szTip, SIZEOF(nid.szTip));
+ Shell_NotifyIcon(NIM_MODIFY, &nid);
+
+ if (cli.trayIconCount == 1)
+ SetTaskBarIcon(hNewIcon, cli.szTip);
+ else
+ SetTaskBarIcon(NULL, NULL);
+
+ cli.trayIcon[i].isBase = isBase;
+ if (DBGetContactSettingByte(NULL,"CList","TrayIcon",SETTING_TRAYICON_DEFAULT) == SETTING_TRAYICON_MULTI)
+ {
+ DWORD time1=DBGetContactSettingWord(NULL,"CList","CycleTime",SETTING_CYCLETIME_DEFAULT)*200;
+ DWORD time2=DBGetContactSettingWord(NULL,"CList","IconFlashTime",550)+1000;
+ DWORD time=max(max(2000,time1),time2);
+ if(RefreshTimerId) {KillTimer(NULL,RefreshTimerId); RefreshTimerId=0;}
+ RefreshTimerId=SetTimer(NULL,0,time,RefreshTimerProc); // if unknown base was changed - than show preffered proto icon for 2 sec and reset it to original one after timeout
+ }
+ { ulock; return i; }
+ }
+ }
+ { ulock; return -1; }
+}
+
+int fnTrayIconSetBaseInfo(HICON hIcon, const char *szPreferredProto)
+{
+ int i;
+ initcheck -1;
+ lock;
+ if (szPreferredProto)
+ {
+ for (i = 0; i < cli.trayIconCount; i++) {
+ if (cli.trayIcon[i].id == 0)
+ continue;
+ if (lstrcmpA(cli.trayIcon[i].szProto, szPreferredProto))
+ continue;
+
+ DestroyIcon(cli.trayIcon[i].hBaseIcon);
+ cli.trayIcon[i].hBaseIcon = hIcon;
+ ulock; return i;
+ }
+ if ((cli.pfnGetProtocolVisibility(szPreferredProto))
+ && (GetAverageMode()==-1)
+ && (DBGetContactSettingByte(NULL,"CList","TrayIcon",SETTING_TRAYICON_DEFAULT)==SETTING_TRAYICON_MULTI)
+ && !(DBGetContactSettingByte(NULL,"CList","AlwaysMulti",SETTING_ALWAYSMULTI_DEFAULT)))
+ goto LBL_Error;
+ }
+
+ //if there wasn't a specific icon, there will only be one suitable
+ for (i = 0; i < cli.trayIconCount; i++) {
+ if (cli.trayIcon[i].id == 0)
+ continue;
+
+ DestroyIcon(cli.trayIcon[i].hBaseIcon);
+ cli.trayIcon[i].hBaseIcon = hIcon;
+ ulock; return i;
+ }
+
+LBL_Error:
+ DestroyIcon(hIcon);
+ ulock; return -1;
+}
+
+void fnTrayIconUpdateWithImageList(int iImage, const TCHAR *szNewTip, char *szPreferredProto)
+{
+ HICON hIcon = ImageList_GetIcon(hCListImages, iImage, ILD_NORMAL);
+ cli.pfnTrayIconUpdate(hIcon, szNewTip, szPreferredProto, 0);
+ DestroyIcon(hIcon);
+}
+
+VOID CALLBACK fnTrayCycleTimerProc(HWND, UINT, UINT_PTR, DWORD)
+{
+ initcheck;
+ lock;
+
+ int i;
+ for (i = accounts.getCount() + 1; --i;) {
+ cycleStep = (cycleStep + 1) % accounts.getCount();
+ if ( cli.pfnGetProtocolVisibility( accounts[cycleStep]->szModuleName ))
+ break;
+ }
+
+ if (i)
+ {
+ DestroyIcon(cli.trayIcon[0].hBaseIcon);
+ cli.trayIcon[0].hBaseIcon = cli.pfnGetIconFromStatusMode(NULL, accounts[cycleStep]->szModuleName,
+ CallProtoService( accounts[cycleStep]->szModuleName, PS_GETSTATUS, 0, 0 ));
+ if (cli.trayIcon[0].isBase)
+ cli.pfnTrayIconUpdate(cli.trayIcon[0].hBaseIcon, NULL, NULL, 1);
+ }
+
+ ulock;
+}
+
+void fnTrayIconUpdateBase(const char *szChangedProto)
+{
+ if ( !cli.pfnGetProtocolVisibility( szChangedProto )) return;
+
+ int i, netProtoCount, changed = -1;
+ HWND hwnd = cli.hwndContactList;
+ initcheck;
+ lock;
+ int averageMode = GetAverageMode(&netProtoCount);
+
+ if (cli.cycleTimerId) {
+ KillTimer(NULL, cli.cycleTimerId);
+ cli.cycleTimerId = 0;
+ }
+
+ for (i = 0; i < accounts.getCount(); i++) {
+ if (!lstrcmpA(szChangedProto, accounts[i]->szModuleName ))
+ cycleStep = i - 1;
+ }
+
+ if (netProtoCount > 0)
+ {
+ int trayIconSetting = DBGetContactSettingByte(NULL, "CList", "TrayIcon", SETTING_TRAYICON_DEFAULT);
+
+ if (averageMode > 0) {
+ if (trayIconSetting == SETTING_TRAYICON_MULTI) {
+ if (DBGetContactSettingByte(NULL, "CList", "AlwaysMulti", SETTING_ALWAYSMULTI_DEFAULT))
+ //changed = cli.pfnTrayIconSetBaseInfo( cli.pfnGetIconFromStatusMode((char*)szChangedProto, NULL, averageMode), (char*)szChangedProto);
+ changed = cli.pfnTrayIconSetBaseInfo( cli.pfnGetIconFromStatusMode( NULL, szChangedProto, CallProtoService(szChangedProto, PS_GETSTATUS, 0, 0)), (char*)szChangedProto );
+ else if (cli.trayIcon && cli.trayIcon[0].szProto != NULL) {
+ cli.pfnTrayIconDestroy(hwnd);
+ cli.pfnTrayIconInit(hwnd);
+ }
+ else
+ changed = cli.pfnTrayIconSetBaseInfo( cli.pfnGetIconFromStatusMode(NULL, NULL, averageMode), NULL );
+ }
+ else
+ changed = cli.pfnTrayIconSetBaseInfo( cli.pfnGetIconFromStatusMode(NULL, NULL, averageMode), NULL);
+ }
+ else {
+ switch (trayIconSetting) {
+ case SETTING_TRAYICON_SINGLE:
+ {
+ DBVARIANT dbv = { DBVT_DELETED };
+ char *szProto;
+ if (DBGetContactSettingString(NULL, "CList", "PrimaryStatus", &dbv))
+ szProto = NULL;
+ else
+ szProto = dbv.pszVal;
+ changed = cli.pfnTrayIconSetBaseInfo( cli.pfnGetIconFromStatusMode( NULL, szProto, szProto ? CallProtoService(szProto, PS_GETSTATUS, 0,0) : CallService(MS_CLIST_GETSTATUSMODE, 0, 0)), szProto );
+ DBFreeVariant(&dbv);
+ break;
+ }
+ case SETTING_TRAYICON_CYCLE:
+ cli.cycleTimerId =
+ SetTimer(NULL, 0, DBGetContactSettingWord(NULL, "CList", "CycleTime", SETTING_CYCLETIME_DEFAULT) * 1000, cli.pfnTrayCycleTimerProc);
+ changed =
+ cli.pfnTrayIconSetBaseInfo(ImageList_GetIcon
+ (hCListImages, cli.pfnIconFromStatusMode(szChangedProto, CallProtoService(szChangedProto, PS_GETSTATUS, 0, 0), NULL),
+ ILD_NORMAL), NULL);
+ break;
+ case SETTING_TRAYICON_MULTI:
+ if (!cli.trayIcon) {
+ cli.pfnTrayIconRemove(NULL, NULL);
+ }
+ else if ((cli.trayIconCount > 1 || netProtoCount == 1) || DBGetContactSettingByte( NULL, "CList", "AlwaysMulti", SETTING_ALWAYSMULTI_DEFAULT ))
+ changed = cli.pfnTrayIconSetBaseInfo( cli.pfnGetIconFromStatusMode( NULL, szChangedProto, CallProtoService(szChangedProto, PS_GETSTATUS, 0, 0)), (char*)szChangedProto );
+ else {
+ cli.pfnTrayIconDestroy(hwnd);
+ cli.pfnTrayIconInit(hwnd);
+ }
+ break;
+ }
+ }
+ }
+ else
+ changed = cli.pfnTrayIconSetBaseInfo(ImageList_GetIcon(hCListImages, cli.pfnIconFromStatusMode(NULL, averageMode, NULL), ILD_NORMAL), NULL);
+
+ if (changed != -1 && cli.trayIcon[changed].isBase)
+ cli.pfnTrayIconUpdate(cli.trayIcon[changed].hBaseIcon, NULL, cli.trayIcon[changed].szProto, 1);
+ ulock;
+}
+
+void fnTrayIconSetToBase(char *szPreferredProto)
+{
+ int i;
+ initcheck;
+ lock;
+
+ for (i = 0; i < cli.trayIconCount; i++) {
+ if ( cli.trayIcon[i].id == 0 )
+ continue;
+ if ( lstrcmpA( cli.trayIcon[i].szProto, szPreferredProto ))
+ continue;
+ cli.pfnTrayIconUpdate( cli.trayIcon[i].hBaseIcon, NULL, szPreferredProto, 1);
+ ulock; return;
+ }
+
+ //if there wasn't a specific icon, there will only be one suitable
+ for ( i = 0; i < cli.trayIconCount; i++) {
+ if ( cli.trayIcon[i].id == 0 )
+ continue;
+ cli.pfnTrayIconUpdate( cli.trayIcon[i].hBaseIcon, NULL, szPreferredProto, 1);
+ ulock; return;
+ }
+ ulock; return;
+}
+
+void fnTrayIconIconsChanged(void)
+{
+ initcheck;
+ lock;
+ cli.pfnTrayIconDestroy(cli.hwndContactList);
+ cli.pfnTrayIconInit(cli.hwndContactList);
+ ulock;
+}
+
+static UINT_PTR autoHideTimerId;
+static VOID CALLBACK TrayIconAutoHideTimer(HWND hwnd, UINT, UINT_PTR idEvent, DWORD)
+{
+ HWND hwndClui;
+ initcheck;
+ lock;
+ KillTimer(hwnd, idEvent);
+ hwndClui = cli.hwndContactList;
+ if (GetActiveWindow() != hwndClui) {
+ ShowWindow(hwndClui, SW_HIDE);
+ if (MySetProcessWorkingSetSize != NULL)
+ MySetProcessWorkingSetSize(GetCurrentProcess(), -1, -1);
+ }
+ ulock; return;
+}
+
+int fnTrayIconPauseAutoHide(WPARAM, LPARAM)
+{
+ initcheck 0;
+ lock;
+ if (DBGetContactSettingByte(NULL, "CList", "AutoHide", SETTING_AUTOHIDE_DEFAULT)) {
+ if ( GetActiveWindow() != cli.hwndContactList ) {
+ KillTimer(NULL, autoHideTimerId);
+ autoHideTimerId = SetTimer(NULL, 0, 1000 * DBGetContactSettingWord(NULL, "CList", "HideTime", SETTING_HIDETIME_DEFAULT), TrayIconAutoHideTimer);
+ }
+ }
+ ulock; return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// processes tray icon's messages
+
+static BYTE s_LastHoverIconID = 0;
+static BOOL g_trayTooltipActive = FALSE;
+static POINT tray_hover_pos = {0};
+
+static void CALLBACK TrayHideToolTipTimerProc(HWND hwnd, UINT, UINT_PTR, DWORD)
+{
+ if ( g_trayTooltipActive ) {
+ POINT pt;
+ GetCursorPos(&pt);
+ if ( abs(pt.x - tray_hover_pos.x) > TOOLTIP_TOLERANCE || abs(pt.y - tray_hover_pos.y) > TOOLTIP_TOLERANCE ) {
+ CallService("mToolTip/HideTip", 0, 0);
+ g_trayTooltipActive = FALSE;
+ KillTimer( hwnd, TIMERID_TRAYHOVER_2 );
+ }
+ }
+ else KillTimer( hwnd, TIMERID_TRAYHOVER_2 );
+}
+
+static void CALLBACK TrayToolTipTimerProc(HWND hwnd, UINT, UINT_PTR id, DWORD)
+{
+ if ( !g_trayTooltipActive && !cli.bTrayMenuOnScreen ) {
+ CLCINFOTIP ti = {0};
+ POINT pt;
+ GetCursorPos( &pt );
+ if ( abs(pt.x - tray_hover_pos.x) <= TOOLTIP_TOLERANCE && abs(pt.y - tray_hover_pos.y) <= TOOLTIP_TOLERANCE ) {
+ TCHAR* szTipCur = cli.szTip;
+ {
+ int n = s_LastHoverIconID-100;
+ if ( n >= 0 && n < cli.trayIconCount )
+ szTipCur = cli.trayIcon[n].ptszToolTip;
+ }
+ ti.rcItem.left = pt.x - 10;
+ ti.rcItem.right = pt.x + 10;
+ ti.rcItem.top = pt.y - 10;
+ ti.rcItem.bottom = pt.y + 10;
+ ti.cbSize = sizeof( ti );
+ ti.isTreeFocused = GetFocus() == cli.hwndContactList ? 1 : 0;
+ #if defined( _UNICODE )
+ if (CallService( "mToolTip/ShowTipW", (WPARAM)szTipCur, (LPARAM)&ti ) == CALLSERVICE_NOTFOUND)
+ {
+ char* p = mir_u2a( szTipCur );
+ CallService( "mToolTip/ShowTip", (WPARAM)p, (LPARAM)&ti );
+ mir_free( p );
+ }
+ #else
+ CallService( "mToolTip/ShowTip", (WPARAM)szTipCur, (LPARAM)&ti );
+ #endif
+ GetCursorPos( &tray_hover_pos );
+ SetTimer( cli.hwndContactList, TIMERID_TRAYHOVER_2, 600, TrayHideToolTipTimerProc );
+ g_trayTooltipActive = TRUE;
+ } }
+
+ KillTimer(hwnd, id);
+}
+
+INT_PTR fnTrayIconProcessMessage(WPARAM wParam, LPARAM lParam)
+{
+ MSG *msg = (MSG *) wParam;
+ switch (msg->message) {
+ case WM_CREATE: {
+ WM_TASKBARCREATED = RegisterWindowMessage( _T("TaskbarCreated"));
+ WM_TASKBARBUTTONCREATED = RegisterWindowMessage( _T("TaskbarButtonCreated"));
+ PostMessage(msg->hwnd, TIM_CREATE, 0, 0);
+ break;
+ }
+ case TIM_CREATE:
+ cli.pfnTrayIconInit(msg->hwnd);
+ break;
+
+ case WM_ACTIVATE:
+ if (DBGetContactSettingByte(NULL, "CList", "AutoHide", SETTING_AUTOHIDE_DEFAULT)) {
+ if (LOWORD(msg->wParam) == WA_INACTIVE)
+ autoHideTimerId = SetTimer(NULL, 0, 1000 * DBGetContactSettingWord(NULL, "CList", "HideTime", SETTING_HIDETIME_DEFAULT), TrayIconAutoHideTimer);
+ else
+ KillTimer(NULL, autoHideTimerId);
+ }
+ break;
+
+ case WM_DESTROY:
+ cli.pfnTrayIconDestroy(msg->hwnd);
+ cli.pfnUninitTray();
+ break;
+
+ case TIM_CALLBACK:
+ if ( msg->lParam == WM_RBUTTONDOWN || msg->lParam == WM_LBUTTONDOWN || msg->lParam == WM_RBUTTONDOWN && g_trayTooltipActive ) {
+ CallService("mToolTip/HideTip", 0, 0);
+ g_trayTooltipActive = FALSE;
+ }
+
+ if ( msg->lParam == WM_MBUTTONUP )
+ cli.pfnShowHide(0, 0);
+ else if (msg->lParam == (DBGetContactSettingByte(NULL, "CList", "Tray1Click", SETTING_TRAY1CLICK_DEFAULT) ? WM_LBUTTONUP : WM_LBUTTONDBLCLK)) {
+ if ((GetAsyncKeyState(VK_CONTROL) & 0x8000))
+ {
+ POINT pt;
+ HMENU hMenu = (HMENU)CallService(MS_CLIST_MENUGETSTATUS, 0, 0);
+
+ for (int i = 0; i < cli.trayIconCount; ++i)
+ {
+ if ((unsigned)cli.trayIcon[i].id == msg->wParam)
+ {
+ if (!cli.trayIcon[i].szProto) break;
+
+ int ind = 0;
+ for (int j = 0; j < accounts.getCount(); ++j)
+ {
+ int k = cli.pfnGetAccountIndexByPos(j);
+ if (k >= 0)
+ {
+ if (!strcmp(cli.trayIcon[i].szProto, accounts[k]->szModuleName))
+ {
+ HMENU hm = GetSubMenu(hMenu, ind);
+ if (hm) hMenu = hm;
+ break;
+ }
+
+ if (cli.pfnGetProtocolVisibility(accounts[k]->szModuleName))
+ ++ind;
+ }
+ }
+ break;
+ }
+ }
+
+ SetForegroundWindow(msg->hwnd);
+ SetFocus(msg->hwnd);
+ GetCursorPos(&pt);
+ TrackPopupMenu(hMenu, TPM_TOPALIGN | TPM_LEFTALIGN | TPM_LEFTBUTTON, pt.x, pt.y, 0, msg->hwnd, NULL);
+ }
+ else if (cli.pfnEventsProcessTrayDoubleClick(msg->wParam))
+ cli.pfnShowHide(0, 0);
+ }
+ else if (msg->lParam == WM_RBUTTONUP) {
+ MENUITEMINFO mi;
+ POINT pt;
+ HMENU hMainMenu = LoadMenu(cli.hInst, MAKEINTRESOURCE(IDR_CONTEXT));
+ HMENU hMenu = GetSubMenu(hMainMenu, 0);
+ CallService(MS_LANGPACK_TRANSLATEMENU, (WPARAM) hMenu, 0);
+
+ ZeroMemory(&mi, sizeof(mi));
+ mi.cbSize = MENUITEMINFO_V4_SIZE;
+ mi.fMask = MIIM_SUBMENU | MIIM_TYPE;
+ mi.fType = MFT_STRING;
+ mi.hSubMenu = (HMENU) CallService(MS_CLIST_MENUGETMAIN, 0, 0);
+ mi.dwTypeData = TranslateT("&Main Menu");
+ InsertMenuItem(hMenu, 1, TRUE, &mi);
+ mi.hSubMenu = (HMENU) CallService(MS_CLIST_MENUGETSTATUS, 0, 0);
+ mi.dwTypeData = TranslateT("&Status");
+ InsertMenuItem(hMenu, 2, TRUE, &mi);
+ SetMenuDefaultItem(hMenu, ID_TRAY_HIDE, FALSE);
+
+ SetForegroundWindow(msg->hwnd);
+ SetFocus(msg->hwnd);
+ GetCursorPos(&pt);
+ TrackPopupMenu(hMenu, TPM_TOPALIGN | TPM_LEFTALIGN, pt.x, pt.y, 0, msg->hwnd, NULL);
+
+ RemoveMenu(hMenu, 1, MF_BYPOSITION);
+ RemoveMenu(hMenu, 1, MF_BYPOSITION);
+ DestroyMenu(hMainMenu);
+ }
+ else if ( msg->lParam == WM_MOUSEMOVE ) {
+ s_LastHoverIconID = msg->wParam;
+ if ( g_trayTooltipActive ) {
+ POINT pt;
+ GetCursorPos( &pt );
+ if ( abs(pt.x - tray_hover_pos.x) > TOOLTIP_TOLERANCE || abs(pt.y - tray_hover_pos.y) > TOOLTIP_TOLERANCE ) {
+ CallService("mToolTip/HideTip", 0, 0);
+ g_trayTooltipActive = FALSE;
+ ReleaseCapture();
+ }
+ }
+ else {
+ GetCursorPos(&tray_hover_pos);
+ SetTimer(cli.hwndContactList, TIMERID_TRAYHOVER, 600, TrayToolTipTimerProc);
+ }
+ break;
+ }
+
+ *((LRESULT *) lParam) = 0;
+ return TRUE;
+
+ default:
+ if (msg->message == WM_TASKBARCREATED) {
+ cli.pfnTrayIconTaskbarCreated(msg->hwnd);
+ *((LRESULT *) lParam) = 0;
+ return TRUE;
+ }
+ else if (msg->message == WM_TASKBARBUTTONCREATED) {
+ SetTaskBarIcon(lastTaskBarIcon, NULL);
+ *((LRESULT *) lParam) = 0;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// processes tray icon's notifications
+
+int fnCListTrayNotify( MIRANDASYSTRAYNOTIFY* msn )
+{
+ UINT iconId = 0;
+
+ if ( msn == NULL )
+ return 1;
+
+ if ( msn->cbSize != sizeof(MIRANDASYSTRAYNOTIFY) || msn->szInfo == NULL || msn->szInfoTitle == NULL )
+ return 1;
+
+ if ( cli.trayIcon == NULL )
+ return 2;
+
+ if ( msn->szProto ) {
+ int j;
+ for ( j = 0; j < cli.trayIconCount; j++ ) {
+ if ( cli.trayIcon[j].szProto != NULL ) {
+ if ( !strcmp( msn->szProto, cli.trayIcon[j].szProto )) {
+ iconId = cli.trayIcon[j].id;
+ break;
+ }
+ }
+ else if ( cli.trayIcon[j].isBase ) {
+ iconId = cli.trayIcon[j].id;
+ break;
+ } }
+ }
+ else iconId = cli.trayIcon[0].id;
+
+#if defined(_UNICODE)
+ if ( msn->dwInfoFlags & NIIF_INTERN_UNICODE ) {
+ NOTIFYICONDATAW nid = {0};
+ nid.cbSize = ( cli.shellVersion >= 5 ) ? sizeof(nid) : NOTIFYICONDATAW_V1_SIZE;
+ nid.hWnd = cli.hwndContactList;
+ nid.uID = iconId;
+ nid.uFlags = NIF_INFO;
+ lstrcpynW( nid.szInfo, msn->tszInfo, SIZEOF( nid.szInfo ));
+ lstrcpynW( nid.szInfoTitle, msn->tszInfoTitle, SIZEOF( nid.szInfoTitle ));
+ nid.szInfo[ SIZEOF(nid.szInfo)-1 ] = 0;
+ nid.szInfoTitle[ SIZEOF(nid.szInfoTitle)-1 ] = 0;
+ nid.uTimeout = msn->uTimeout;
+ nid.dwInfoFlags = (msn->dwInfoFlags & ~NIIF_INTERN_UNICODE);
+ return Shell_NotifyIconW( NIM_MODIFY, &nid ) == 0;
+ }
+ else
+#endif
+ {
+ NOTIFYICONDATAA nid = { 0 };
+ nid.cbSize = ( cli.shellVersion >= 5 ) ? sizeof(nid) : NOTIFYICONDATAA_V1_SIZE;
+ nid.hWnd = cli.hwndContactList;
+ nid.uID = iconId;
+ nid.uFlags = NIF_INFO;
+ lstrcpynA( nid.szInfo, msn->szInfo, sizeof( nid.szInfo ));
+ lstrcpynA( nid.szInfoTitle, msn->szInfoTitle, sizeof( nid.szInfoTitle ));
+ nid.uTimeout = msn->uTimeout;
+ nid.dwInfoFlags = msn->dwInfoFlags;
+ return Shell_NotifyIconA( NIM_MODIFY, &nid ) == 0;
+} }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+typedef struct _DllVersionInfo
+{
+ DWORD cbSize;
+ DWORD dwMajorVersion; // Major version
+ DWORD dwMinorVersion; // Minor version
+ DWORD dwBuildNumber; // Build number
+ DWORD dwPlatformID; // DLLVER_PLATFORM_*
+}
+ DLLVERSIONINFO;
+
+typedef HRESULT(CALLBACK * DLLGETVERSIONPROC) (DLLVERSIONINFO *);
+
+static DLLVERSIONINFO dviShell;
+
+static INT_PTR pfnCListTrayNotifyStub(WPARAM, LPARAM lParam )
+{ return cli.pfnCListTrayNotify(( MIRANDASYSTRAYNOTIFY* )lParam );
+}
+
+void fnInitTray( void )
+{
+ HMODULE hLib = GetModuleHandleA("shell32");
+ if ( hLib ) {
+ DLLGETVERSIONPROC proc;
+ dviShell.cbSize = sizeof(dviShell);
+ proc = ( DLLGETVERSIONPROC )GetProcAddress( hLib, "DllGetVersion" );
+ if (proc) {
+ proc( &dviShell );
+ cli.shellVersion = dviShell.dwMajorVersion;
+ }
+ FreeLibrary(hLib);
+ }
+ InitializeCriticalSection(&trayLockCS);
+ if ( cli.shellVersion >= 5 )
+ CreateServiceFunction(MS_CLIST_SYSTRAY_NOTIFY, pfnCListTrayNotifyStub );
+ fTrayInited=TRUE;
+}
+
+void fnUninitTray( void )
+{
+ fTrayInited=FALSE;
+ DeleteCriticalSection( &trayLockCS );
+}
+void fnLockTray( void )
+{
+// return; //stub to be removed
+ initcheck;
+ EnterCriticalSection( &trayLockCS );
+}
+
+void fnUnlockTray( void )
+{
+// return; //stub to be removed
+ initcheck;
+#ifdef _DEBUG
+ if (trayLockCS.RecursionCount==0) DebugBreak(); //try to unlock already
+#endif
+ LeaveCriticalSection( &trayLockCS );
+}
+
+#undef lock
+#undef ulock
+#undef initcheck
diff --git a/src/modules/clist/clui.cpp b/src/modules/clist/clui.cpp
new file mode 100644
index 0000000000..13ebf74a21
--- /dev/null
+++ b/src/modules/clist/clui.cpp
@@ -0,0 +1,1136 @@
+/*
+
+ Miranda IM: the free IM client for Microsoft* Windows*
+
+ Copyright 2000-2010 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 "../database/profilemanager.h"
+#include "clc.h"
+
+#define TM_AUTOALPHA 1
+#define MENU_MIRANDAMENU 0xFFFF1234
+
+extern BOOL(WINAPI * MySetProcessWorkingSetSize) (HANDLE, SIZE_T, SIZE_T);
+
+static HMODULE hUserDll;
+static HANDLE hContactDraggingEvent, hContactDroppedEvent, hContactDragStopEvent;
+static int transparentFocus = 1;
+UINT uMsgProcessProfile;
+
+#define M_RESTORESTATUS (WM_USER+7)
+
+void LoadCluiServices();
+
+typedef struct {
+ int showsbar;
+ int showgrip;
+ int transparent;
+ int alpha;
+}
+ CluiOpts;
+
+static CluiOpts cluiopt = {0};
+
+void fnLoadCluiGlobalOpts()
+{
+ cluiopt.showsbar = DBGetContactSettingByte(NULL, "CLUI", "ShowSBar", 1);
+ cluiopt.showgrip = DBGetContactSettingByte(NULL, "CLUI", "ShowGrip", 1);
+ cluiopt.transparent = DBGetContactSettingByte(NULL,"CList","Transparent",SETTING_TRANSPARENT_DEFAULT);
+ cluiopt.alpha = DBGetContactSettingByte(NULL, "CList", "Alpha", SETTING_ALPHA_DEFAULT);
+}
+
+static int CluiModulesLoaded(WPARAM, LPARAM)
+{
+ if (cli.hMenuMain) {
+ MENUITEMINFO mii = { 0 };
+ mii.cbSize = MENUITEMINFO_V4_SIZE;
+ mii.fMask = MIIM_SUBMENU;
+ mii.hSubMenu = (HMENU) CallService(MS_CLIST_MENUGETMAIN, 0, 0);
+ SetMenuItemInfo(cli.hMenuMain, 0, TRUE, &mii);
+ mii.hSubMenu = (HMENU) CallService(MS_CLIST_MENUGETSTATUS, 0, 0);
+ SetMenuItemInfo(cli.hMenuMain, 1, TRUE, &mii);
+ }
+ return 0;
+}
+
+// Disconnect all protocols.
+// Happens on shutdown and standby.
+static void DisconnectAll()
+{
+ int nProto;
+ for (nProto = 0; nProto < accounts.getCount(); nProto++)
+ CallProtoService( accounts[nProto]->szModuleName, PS_SETSTATUS, ID_STATUS_OFFLINE, 0);
+}
+
+static int CluiIconsChanged(WPARAM, LPARAM)
+{
+ DrawMenuBar(cli.hwndContactList);
+ return 0;
+}
+
+static HANDLE hRenameMenuItem;
+
+static int MenuItem_PreBuild(WPARAM, LPARAM)
+{
+ TCHAR cls[128];
+ HANDLE hItem;
+ HWND hwndClist = GetFocus();
+ CLISTMENUITEM mi;
+
+ ZeroMemory(&mi, sizeof(mi));
+ mi.cbSize = sizeof(mi);
+ mi.flags = CMIM_FLAGS;
+ GetClassName(hwndClist, cls, SIZEOF(cls));
+ hwndClist = (!lstrcmp(CLISTCONTROL_CLASS, cls)) ? hwndClist : cli.hwndContactList;
+ hItem = (HANDLE) SendMessage(hwndClist, CLM_GETSELECTION, 0, 0);
+ if (!hItem) {
+ mi.flags = CMIM_FLAGS | CMIF_HIDDEN;
+ }
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM) hRenameMenuItem, (LPARAM) & mi);
+ return 0;
+}
+
+static INT_PTR MenuItem_RenameContact(WPARAM, LPARAM)
+{
+ TCHAR cls[128];
+ HANDLE hItem;
+ HWND hwndClist = GetFocus();
+ GetClassName(hwndClist, cls, SIZEOF(cls));
+ // worst case scenario, the rename is sent to the main contact list
+ hwndClist = (!lstrcmp(CLISTCONTROL_CLASS, cls)) ? hwndClist : cli.hwndContactList;
+ hItem = (HANDLE) SendMessage(hwndClist, CLM_GETSELECTION, 0, 0);
+ if (hItem) {
+ SetFocus(hwndClist);
+ SendMessage(hwndClist, CLM_EDITLABEL, (WPARAM) hItem, 0);
+ }
+ return 0;
+}
+
+static INT_PTR CALLBACK AskForConfirmationDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hWnd);
+ {
+ LOGFONT lf;
+ HFONT hFont;
+
+ hFont = (HFONT) SendDlgItemMessage(hWnd, IDYES, WM_GETFONT, 0, 0);
+ GetObject(hFont, sizeof(lf), &lf);
+ lf.lfWeight = FW_BOLD;
+ SendDlgItemMessage(hWnd, IDC_TOPLINE, WM_SETFONT, (WPARAM) CreateFontIndirect(&lf), 0);
+ }
+ {
+ TCHAR szFormat[256];
+ TCHAR szFinal[256];
+
+ GetDlgItemText(hWnd, IDC_TOPLINE, szFormat, SIZEOF(szFormat));
+ mir_sntprintf(szFinal, SIZEOF(szFinal), szFormat, cli.pfnGetContactDisplayName((HANDLE)lParam, 0));
+ SetDlgItemText(hWnd, IDC_TOPLINE, szFinal);
+ }
+ SetFocus(GetDlgItem(hWnd, IDNO));
+ SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+ break;
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDYES:
+ if (IsDlgButtonChecked(hWnd, IDC_HIDE)) {
+ EndDialog(hWnd, IDC_HIDE);
+ break;
+ }
+ //fall through
+ case IDCANCEL:
+ case IDNO:
+ EndDialog(hWnd, LOWORD(wParam));
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ SendMessage(hWnd, WM_COMMAND, MAKEWPARAM(IDNO, BN_CLICKED), 0);
+ break;
+
+ case WM_DESTROY:
+ DeleteObject((HFONT) SendDlgItemMessage(hWnd, IDC_TOPLINE, WM_GETFONT, 0, 0));
+ break;
+ }
+
+ return FALSE;
+}
+
+static INT_PTR MenuItem_DeleteContact(WPARAM wParam, LPARAM lParam)
+{
+ //see notes about deleting contacts on PF1_SERVERCLIST servers in m_protosvc.h
+ UINT_PTR action;
+
+ if (DBGetContactSettingByte(NULL, "CList", "ConfirmDelete", SETTING_CONFIRMDELETE_DEFAULT) &&
+ !(GetKeyState(VK_SHIFT)&0x8000) )
+ // Ask user for confirmation, and if the contact should be archived (hidden, not deleted)
+ action = DialogBoxParam(hMirandaInst, MAKEINTRESOURCE(IDD_DELETECONTACT), (HWND) lParam, AskForConfirmationDlgProc, wParam);
+ else
+ action = IDYES;
+
+ switch (action) {
+
+ // Delete contact
+ case IDYES:
+ {
+ char *szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ if (szProto != NULL) {
+ // Check if protocol uses server side lists
+ DWORD caps;
+
+ caps = (DWORD) CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0);
+ if (caps & PF1_SERVERCLIST) {
+ int status;
+
+ status = CallProtoService(szProto, PS_GETSTATUS, 0, 0);
+ if (status == ID_STATUS_OFFLINE || (status >= ID_STATUS_CONNECTING && status < ID_STATUS_CONNECTING + MAX_CONNECT_RETRIES)) {
+ // Set a flag so we remember to delete the contact when the protocol goes online the next time
+ DBWriteContactSettingByte((HANDLE) wParam, "CList", "Delete", 1);
+ MessageBox( NULL,
+ TranslateT("This contact is on an instant messaging system which stores its contact list on a central server. The contact will be removed from the server and from your contact list when you next connect to that network."),
+ TranslateT("Delete Contact"), MB_OK);
+ return 0;
+ } } }
+
+ CallService(MS_DB_CONTACT_DELETE, wParam, 0);
+ }
+ break;
+
+ // Archive contact
+ case IDC_HIDE:
+ DBWriteContactSettingByte((HANDLE) wParam, "CList", "Hidden", 1);
+ break;
+ }
+
+ return 0;
+}
+
+static INT_PTR MenuItem_AddContactToList(WPARAM wParam, LPARAM)
+{
+ ADDCONTACTSTRUCT acs = { 0 };
+
+ acs.handle = (HANDLE) wParam;
+ acs.handleType = HANDLE_CONTACT;
+ acs.szProto = "";
+
+ CallService(MS_ADDCONTACT_SHOW, (WPARAM) NULL, (LPARAM) & acs);
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// this is the smallest available window procedure
+
+#ifndef CS_DROPSHADOW
+#define CS_DROPSHADOW 0x00020000
+#endif
+
+LRESULT CALLBACK ContactListWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ LRESULT result;
+ MSG m;
+ m.hwnd=hwnd;
+ m.message=msg;
+ m.wParam=wParam;
+ m.lParam=lParam;
+ if ( cli.pfnDocking_ProcessWindowMessage(( WPARAM )&m, ( LPARAM )&result ))
+ return result;
+ if ( cli.pfnTrayIconProcessMessage(( WPARAM )&m, ( LPARAM )&result ))
+ return result;
+ if ( cli.pfnHotkeysProcessMessage(( WPARAM )&m, ( LPARAM )&result ))
+ return result;
+
+ return cli.pfnContactListWndProc( hwnd, msg, wParam, lParam );
+}
+
+int LoadCLUIModule(void)
+{
+ DBVARIANT dbv;
+ TCHAR titleText[256];
+
+ uMsgProcessProfile = RegisterWindowMessage( _T("Miranda::ProcessProfile"));
+ cli.pfnLoadCluiGlobalOpts();
+
+ HookEvent(ME_SYSTEM_MODULESLOADED, CluiModulesLoaded);
+ HookEvent(ME_SKIN_ICONSCHANGED, CluiIconsChanged);
+
+ hContactDraggingEvent = CreateHookableEvent(ME_CLUI_CONTACTDRAGGING);
+ hContactDroppedEvent = CreateHookableEvent(ME_CLUI_CONTACTDROPPED);
+ hContactDragStopEvent = CreateHookableEvent(ME_CLUI_CONTACTDRAGSTOP);
+ LoadCluiServices();
+
+ WNDCLASSEX wndclass;
+ wndclass.cbSize = sizeof(wndclass);
+ wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_GLOBALCLASS;
+ wndclass.lpfnWndProc = cli.pfnContactListControlWndProc;
+ wndclass.cbClsExtra = 0;
+ wndclass.cbWndExtra = sizeof(void *);
+ wndclass.hInstance = cli.hInst;
+ wndclass.hIcon = NULL;
+ wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndclass.hbrBackground = NULL;
+ wndclass.lpszMenuName = NULL;
+ wndclass.lpszClassName = CLISTCONTROL_CLASS;
+ wndclass.hIconSm = NULL;
+ RegisterClassEx(&wndclass);
+
+ wndclass.style = CS_HREDRAW | CS_VREDRAW | ((IsWinVerXPPlus() &&
+ DBGetContactSettingByte(NULL, "CList", "WindowShadow", 0) == 1) ? CS_DROPSHADOW : 0);
+ wndclass.lpfnWndProc = ContactListWndProc;
+ wndclass.cbClsExtra = 0;
+ wndclass.cbWndExtra = 0;
+ wndclass.hInstance = cli.hInst;
+ wndclass.hIcon = LoadSkinIcon(SKINICON_OTHER_MIRANDA, true);
+ wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndclass.hbrBackground = (HBRUSH) (COLOR_3DFACE + 1);
+ wndclass.lpszMenuName = MAKEINTRESOURCE(IDR_CLISTMENU);
+ wndclass.lpszClassName = _T(MIRANDACLASS);
+ wndclass.hIconSm = LoadSkinIcon(SKINICON_OTHER_MIRANDA);
+ RegisterClassEx(&wndclass);
+
+ if (DBGetContactSettingTString(NULL, "CList", "TitleText", &dbv))
+ lstrcpyn(titleText, _T(MIRANDANAME), SIZEOF( titleText ));
+ else {
+ lstrcpyn(titleText, dbv.ptszVal, SIZEOF(titleText));
+ DBFreeVariant(&dbv);
+ }
+
+ RECT pos;
+ pos.left = (int) DBGetContactSettingDword(NULL, "CList", "x", 700);
+ pos.top = (int) DBGetContactSettingDword(NULL, "CList", "y", 221);
+ pos.right = pos.left + (int) DBGetContactSettingDword(NULL, "CList", "Width", 108);
+ pos.bottom = pos.top + (int) DBGetContactSettingDword(NULL, "CList", "Height", 310);
+
+ Utils_AssertInsideScreen(&pos);
+
+ cli.hwndContactList = CreateWindowEx(
+ (DBGetContactSettingByte(NULL, "CList", "ToolWindow", SETTING_TOOLWINDOW_DEFAULT) ? WS_EX_TOOLWINDOW : WS_EX_APPWINDOW),
+ _T(MIRANDACLASS),
+ titleText,
+ WS_POPUPWINDOW | WS_THICKFRAME | WS_CLIPCHILDREN |
+ (DBGetContactSettingByte(NULL, "CLUI", "ShowCaption", SETTING_SHOWCAPTION_DEFAULT) ? WS_CAPTION | WS_SYSMENU |
+ (DBGetContactSettingByte(NULL, "CList", "Min2Tray", SETTING_MIN2TRAY_DEFAULT) ? 0 : WS_MINIMIZEBOX) : 0),
+ pos.left, pos.top, pos.right - pos.left, pos.bottom - pos.top,
+ NULL, NULL, cli.hInst, NULL);
+
+ if (DBGetContactSettingByte(NULL, "CList", "OnDesktop", 0)) {
+ HWND hProgMan = FindWindow(_T("Progman"), NULL);
+ if (IsWindow(hProgMan))
+ SetParent(cli.hwndContactList, hProgMan);
+ }
+
+ cli.pfnOnCreateClc();
+
+ PostMessage(cli.hwndContactList, M_RESTORESTATUS, 0, 0);
+
+ {
+ int state = DBGetContactSettingByte(NULL, "CList", "State", SETTING_STATE_NORMAL);
+ cli.hMenuMain = GetMenu(cli.hwndContactList);
+ if (!DBGetContactSettingByte(NULL, "CLUI", "ShowMainMenu", SETTING_SHOWMAINMENU_DEFAULT))
+ SetMenu(cli.hwndContactList, NULL);
+ if (state == SETTING_STATE_NORMAL)
+ ShowWindow(cli.hwndContactList, SW_SHOW);
+ else if (state == SETTING_STATE_MINIMIZED)
+ ShowWindow(cli.hwndContactList, SW_SHOWMINIMIZED);
+ SetWindowPos(cli.hwndContactList,
+ DBGetContactSettingByte(NULL, "CList", "OnTop", SETTING_ONTOP_DEFAULT) ? HWND_TOPMOST : HWND_NOTOPMOST,
+ 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
+ }
+ {
+ CLISTMENUITEM mi = { 0 };
+ mi.cbSize = sizeof(mi);
+
+ CreateServiceFunction("CList/DeleteContactCommand", MenuItem_DeleteContact);
+ mi.position = 2000070000;
+ mi.flags = CMIF_ICONFROMICOLIB;
+ mi.icolibItem = GetSkinIconHandle( SKINICON_OTHER_DELETE );
+ mi.pszContactOwner = NULL; //on every contact
+ mi.pszName = LPGEN("De&lete");
+ mi.pszService = "CList/DeleteContactCommand";
+ CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM) & mi);
+
+ CreateServiceFunction("CList/RenameContactCommand", MenuItem_RenameContact);
+ mi.position = 2000050000;
+ mi.icolibItem = GetSkinIconHandle( SKINICON_OTHER_RENAME );
+ mi.pszContactOwner = NULL; //on every contact
+ mi.pszName = LPGEN("&Rename");
+ mi.pszService = "CList/RenameContactCommand";
+ hRenameMenuItem = (HANDLE) CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM) & mi);
+
+ CreateServiceFunction("CList/AddToListContactCommand", MenuItem_AddContactToList);
+ mi.position = -2050000000;
+ mi.flags |= CMIF_NOTONLIST;
+ mi.icolibItem = GetSkinIconHandle( SKINICON_OTHER_ADDCONTACT );
+ mi.pszName = LPGEN("&Add permanently to list");
+ mi.pszService = "CList/AddToListContactCommand";
+ CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM) & mi);
+
+ HookEvent(ME_CLIST_PREBUILDCONTACTMENU, MenuItem_PreBuild);
+ }
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// default contact list window procedure
+
+void fnDrawMenuItem(DRAWITEMSTRUCT *dis, HICON hIcon, HICON eventIcon)
+{
+ if (!IsWinVerXPPlus()) {
+ FillRect(dis->hDC, &dis->rcItem, GetSysColorBrush(COLOR_MENU));
+ if (dis->itemState & ODS_HOTLIGHT)
+ DrawEdge(dis->hDC, &dis->rcItem, BDR_RAISEDINNER, BF_RECT);
+ else if (dis->itemState & ODS_SELECTED)
+ DrawEdge(dis->hDC, &dis->rcItem, BDR_SUNKENOUTER, BF_RECT);
+ if (eventIcon != 0) {
+ DrawState(dis->hDC, NULL, NULL, (LPARAM) eventIcon, 0, 2, (dis->rcItem.bottom + dis->rcItem.top - g_IconHeight) / 2 + (dis->itemState & ODS_SELECTED ? 1 : 0), 0, 0, DST_ICON | (dis->itemState & ODS_INACTIVE ? DSS_DISABLED : DSS_NORMAL));
+ DrawState(dis->hDC, NULL, NULL, (LPARAM) hIcon, 0, 4 + g_IconWidth, (dis->rcItem.bottom + dis->rcItem.top - g_IconHeight) / 2 + (dis->itemState & ODS_SELECTED ? 1 : 0), 0, 0, DST_ICON | (dis->itemState & ODS_INACTIVE ? DSS_DISABLED : DSS_NORMAL));
+ }
+ else DrawState(dis->hDC, NULL, NULL, (LPARAM) hIcon, 0, (dis->rcItem.right + dis->rcItem.left - g_IconWidth) / 2 + (dis->itemState & ODS_SELECTED ? 1 : 0), (dis->rcItem.bottom + dis->rcItem.top - g_IconHeight) / 2 + (dis->itemState & ODS_SELECTED ? 1 : 0), 0, 0, DST_ICON | (dis->itemState & ODS_INACTIVE ? DSS_DISABLED : DSS_NORMAL));
+ }
+ else {
+ HBRUSH hBr;
+ BOOL bfm = FALSE;
+ SystemParametersInfo(SPI_GETFLATMENU, 0, &bfm, 0);
+ if (bfm) {
+ /* flat menus: fill with COLOR_MENUHILIGHT and outline with COLOR_HIGHLIGHT, otherwise use COLOR_MENUBAR */
+ if (dis->itemState & ODS_SELECTED || dis->itemState & ODS_HOTLIGHT) {
+ /* selected or hot lighted, no difference */
+ hBr = GetSysColorBrush(COLOR_MENUHILIGHT);
+ FillRect(dis->hDC, &dis->rcItem, hBr);
+ DeleteObject(hBr);
+ /* draw the frame */
+ hBr = GetSysColorBrush(COLOR_HIGHLIGHT);
+ FrameRect(dis->hDC, &dis->rcItem, hBr);
+ DeleteObject(hBr);
+ } else {
+ /* flush the DC with the menu bar colour (only supported on XP) and then draw the icon */
+ hBr = GetSysColorBrush(COLOR_MENUBAR);
+ FillRect(dis->hDC, &dis->rcItem, hBr);
+ DeleteObject(hBr);
+ } //if
+ /* draw the icon */
+ if (eventIcon != 0) {
+ DrawState(dis->hDC, NULL, NULL, (LPARAM) eventIcon, 0, 2, (dis->rcItem.bottom + dis->rcItem.top - g_IconHeight) / 2 + (dis->itemState & ODS_SELECTED ? 1 : 0), 0, 0, DST_ICON | (dis->itemState & ODS_INACTIVE ? DSS_DISABLED : DSS_NORMAL));
+ DrawState(dis->hDC, NULL, NULL, (LPARAM) hIcon, 0, 4 + g_IconWidth, (dis->rcItem.bottom + dis->rcItem.top - g_IconHeight) / 2 + (dis->itemState & ODS_SELECTED ? 1 : 0), 0, 0, DST_ICON | (dis->itemState & ODS_INACTIVE ? DSS_DISABLED : DSS_NORMAL));
+ }
+ else DrawState(dis->hDC, NULL, NULL, (LPARAM) hIcon, 0, (dis->rcItem.right + dis->rcItem.left - g_IconWidth) / 2 + (dis->itemState & ODS_SELECTED ? 1 : 0), (dis->rcItem.bottom + dis->rcItem.top - g_IconHeight) / 2 + (dis->itemState & ODS_SELECTED ? 1 : 0), 0, 0, DST_ICON | (dis->itemState & ODS_INACTIVE ? DSS_DISABLED : DSS_NORMAL));
+ }
+ else {
+ /* non-flat menus, flush the DC with a normal menu colour */
+ FillRect(dis->hDC, &dis->rcItem, GetSysColorBrush(COLOR_MENU));
+ if (dis->itemState & ODS_HOTLIGHT)
+ DrawEdge(dis->hDC, &dis->rcItem, BDR_RAISEDINNER, BF_RECT);
+ else if (dis->itemState & ODS_SELECTED)
+ DrawEdge(dis->hDC, &dis->rcItem, BDR_SUNKENOUTER, BF_RECT);
+
+ if (eventIcon != 0) {
+ DrawState(dis->hDC, NULL, NULL, (LPARAM) eventIcon, 0, 2, (dis->rcItem.bottom + dis->rcItem.top - g_IconHeight) / 2 + (dis->itemState & ODS_SELECTED ? 1 : 0), 0, 0, DST_ICON | (dis->itemState & ODS_INACTIVE ? DSS_DISABLED : DSS_NORMAL));
+ DrawState(dis->hDC, NULL, NULL, (LPARAM) hIcon, 0, 4 + g_IconWidth, (dis->rcItem.bottom + dis->rcItem.top - g_IconHeight) / 2 + (dis->itemState & ODS_SELECTED ? 1 : 0), 0, 0, DST_ICON | (dis->itemState & ODS_INACTIVE ? DSS_DISABLED : DSS_NORMAL));
+ }
+ else DrawState(dis->hDC, NULL, NULL, (LPARAM) hIcon, 0, (dis->rcItem.right + dis->rcItem.left - g_IconWidth) / 2 + (dis->itemState & ODS_SELECTED ? 1 : 0), (dis->rcItem.bottom + dis->rcItem.top - g_IconHeight) / 2 + (dis->itemState & ODS_SELECTED ? 1 : 0), 0, 0, DST_ICON | (dis->itemState & ODS_INACTIVE ? DSS_DISABLED : DSS_NORMAL));
+ } }
+
+ DestroyIcon(hIcon);
+ return;
+}
+
+#define M_CREATECLC (WM_USER+1)
+LRESULT CALLBACK fnContactListWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ if (msg == uMsgProcessProfile)
+ {
+ TCHAR profile[MAX_PATH];
+ int rc;
+ // wParam = (ATOM)hProfileAtom, lParam = 0
+ if (GlobalGetAtomName((ATOM) wParam, profile, SIZEOF(profile)))
+ {
+ TCHAR *pfd = Utils_ReplaceVarsT(_T("%miranda_userdata%\\%miranda_profilename%.dat"));
+ rc = lstrcmpi(profile, pfd) == 0;
+ mir_free(pfd);
+ ReplyMessage(rc);
+ if (rc) {
+ ShowWindow(hwnd, SW_RESTORE);
+ ShowWindow(hwnd, SW_SHOW);
+ SetForegroundWindow(hwnd);
+ SetFocus(hwnd);
+ }
+ }
+ return 0;
+ }
+
+ switch (msg) {
+ case WM_NCCREATE:
+ {
+ MENUITEMINFO mii = { 0 };
+/*
+ if (IsWinVerVistaPlus() && isThemeActive())
+ {
+ HICON hIcon = LoadSkinnedIcon(SKINICON_OTHER_MAINMENU);
+ HBITMAP hBmp = ConvertIconToBitmap(hIcon, NULL, 0);
+ IconLib_ReleaseIcon(hIcon, NULL);
+
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_BITMAP | MIIM_STRING | MIIM_DATA;
+ mii.hbmpItem = hBmp;
+ }
+ else
+*/
+ {
+ mii.cbSize = MENUITEMINFO_V4_SIZE;
+ mii.fMask = MIIM_TYPE | MIIM_DATA;
+ mii.dwItemData = MENU_MIRANDAMENU;
+ mii.fType = MFT_OWNERDRAW;
+ }
+ SetMenuItemInfo(GetMenu(hwnd), 0, TRUE, &mii);
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+ }
+ case WM_CREATE:
+ CallService(MS_LANGPACK_TRANSLATEMENU, (WPARAM) GetMenu(hwnd), 0);
+ DrawMenuBar(hwnd);
+
+ //create the status wnd
+ {
+ int flags = WS_CHILD | CCS_BOTTOM;
+ flags |= cluiopt.showsbar ? WS_VISIBLE : 0;
+ flags |= cluiopt.showgrip ? SBARS_SIZEGRIP : 0;
+ cli.hwndStatus = CreateWindow(STATUSCLASSNAME, NULL, flags, 0, 0, 0, 0, hwnd, NULL, cli.hInst, NULL);
+ }
+ cli.pfnCluiProtocolStatusChanged(0, 0);
+
+ //delay creation of CLC so that it can get the status icons right the first time (needs protocol modules loaded)
+ PostMessage(hwnd, M_CREATECLC, 0, 0);
+
+ if (cluiopt.transparent) {
+ SetWindowLongPtr(hwnd, GWL_EXSTYLE, GetWindowLongPtr(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
+ if (setLayeredWindowAttributes)
+ setLayeredWindowAttributes(hwnd, RGB(0, 0, 0), (BYTE) cluiopt.alpha, LWA_ALPHA);
+ }
+ transparentFocus = 1;
+ return FALSE;
+
+ case M_CREATECLC:
+ cli.hwndContactTree = CreateWindow( CLISTCONTROL_CLASS, _T(""),
+ WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN
+ | CLS_CONTACTLIST
+ | (DBGetContactSettingByte(NULL, "CList", "UseGroups", SETTING_USEGROUPS_DEFAULT) ? CLS_USEGROUPS : 0)
+ | (DBGetContactSettingByte(NULL, "CList", "HideOffline", SETTING_HIDEOFFLINE_DEFAULT) ? CLS_HIDEOFFLINE : 0)
+ | (DBGetContactSettingByte(NULL, "CList", "HideEmptyGroups", SETTING_HIDEEMPTYGROUPS_DEFAULT) ?
+ CLS_HIDEEMPTYGROUPS : 0), 0, 0, 0, 0, hwnd, NULL, cli.hInst, NULL);
+ SendMessage(hwnd, WM_SIZE, 0, 0);
+ break;
+
+ case M_RESTORESTATUS:
+ #ifndef _DEBUG
+ {
+ int nStatus = DBGetContactSettingWord(NULL, "CList", "Status", ID_STATUS_OFFLINE);
+ if (nStatus != ID_STATUS_OFFLINE) CallService(MS_CLIST_SETSTATUSMODE, nStatus, 0);
+ }
+ #endif
+ break;
+
+ // Power management
+ case WM_POWERBROADCAST:
+ switch ((DWORD) wParam) {
+ case PBT_APMSUSPEND:
+ // Computer is suspending, disconnect all protocols
+ DisconnectAll();
+ break;
+
+ case PBT_APMRESUMEAUTOMATIC:
+ case PBT_APMRESUMESUSPEND:
+ // Computer is resuming, restore all protocols
+ PostMessage(hwnd, M_RESTORESTATUS, 0, 0);
+ break;
+ }
+ break;
+
+ case WM_SYSCOLORCHANGE:
+ SendMessage(cli.hwndContactTree, msg, wParam, lParam);
+ SendMessage(cli.hwndStatus, msg, wParam, lParam);
+ // XXX: only works with 4.71 with 95, IE4.
+ SendMessage(cli.hwndStatus, SB_SETBKCOLOR, 0, GetSysColor(COLOR_3DFACE));
+ break;
+
+ case WM_SIZE:
+ if (IsZoomed(hwnd))
+ ShowWindow(hwnd, SW_SHOWNORMAL);
+ {
+ RECT rect, rcStatus;
+ GetClientRect(hwnd, &rect);
+ if (cluiopt.showsbar) {
+ SetWindowPos(cli.hwndStatus, NULL, 0, rect.bottom - 20, rect.right - rect.left, 20, SWP_NOZORDER);
+ GetWindowRect(cli.hwndStatus, &rcStatus);
+ cli.pfnCluiProtocolStatusChanged(0, 0);
+ }
+ else
+ rcStatus.top = rcStatus.bottom = 0;
+ SetWindowPos(cli.hwndContactTree, NULL, 0, 0, rect.right, rect.bottom - (rcStatus.bottom - rcStatus.top), SWP_NOZORDER);
+ }
+ if (wParam == SIZE_MINIMIZED)
+ {
+ if ((GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_TOOLWINDOW) ||
+ DBGetContactSettingByte(NULL, "CList", "Min2Tray", SETTING_MIN2TRAY_DEFAULT))
+ {
+ ShowWindow(hwnd, SW_HIDE);
+ DBWriteContactSettingByte(NULL, "CList", "State", SETTING_STATE_HIDDEN);
+ }
+ else
+ DBWriteContactSettingByte(NULL, "CList", "State", SETTING_STATE_MINIMIZED);
+
+ if (MySetProcessWorkingSetSize != NULL && DBGetContactSettingByte(NULL, "CList", "DisableWorkingSet", 1))
+ MySetProcessWorkingSetSize(GetCurrentProcess(), -1, -1);
+ }
+ // drop thru
+ case WM_MOVE:
+ if (!IsIconic(hwnd)) {
+ RECT rc;
+ GetWindowRect(hwnd, &rc);
+
+ if (!CallService(MS_CLIST_DOCKINGISDOCKED, 0, 0)) { //if docked, dont remember pos (except for width)
+ DBWriteContactSettingDword(NULL, "CList", "Height", (DWORD) (rc.bottom - rc.top));
+ DBWriteContactSettingDword(NULL, "CList", "x", (DWORD) rc.left);
+ DBWriteContactSettingDword(NULL, "CList", "y", (DWORD) rc.top);
+ }
+ DBWriteContactSettingDword(NULL, "CList", "Width", (DWORD) (rc.right - rc.left));
+ }
+ return FALSE;
+
+ case WM_SETFOCUS:
+ SetFocus(cli.hwndContactTree);
+ return 0;
+
+ case WM_ACTIVATE:
+ if (wParam == WA_INACTIVE) {
+ if ((HWND) wParam != hwnd)
+ if (cluiopt.transparent)
+ if (transparentFocus)
+ SetTimer(hwnd, TM_AUTOALPHA, 250, NULL);
+ }
+ else {
+ if (cluiopt.transparent) {
+ KillTimer(hwnd, TM_AUTOALPHA);
+ if (setLayeredWindowAttributes)
+ setLayeredWindowAttributes(hwnd, RGB(0, 0, 0), (BYTE) cluiopt.alpha, LWA_ALPHA);
+ transparentFocus = 1;
+ }
+ }
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+
+ case WM_SETCURSOR:
+ if(cluiopt.transparent) {
+ if (!transparentFocus && GetForegroundWindow()!=hwnd && setLayeredWindowAttributes) {
+ setLayeredWindowAttributes(hwnd, RGB(0,0,0), (BYTE)cluiopt.alpha, LWA_ALPHA);
+ transparentFocus=1;
+ SetTimer(hwnd, TM_AUTOALPHA,250,NULL);
+ }
+ }
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+
+ case WM_NCHITTEST:
+ {
+ LRESULT result;
+ result = DefWindowProc(hwnd, WM_NCHITTEST, wParam, lParam);
+ if (result == HTSIZE || result == HTTOP || result == HTTOPLEFT || result == HTTOPRIGHT ||
+ result == HTBOTTOM || result == HTBOTTOMRIGHT || result == HTBOTTOMLEFT)
+ if (DBGetContactSettingByte(NULL, "CLUI", "AutoSize", 0))
+ return HTCLIENT;
+ return result;
+ }
+
+ case WM_TIMER:
+ if ((int) wParam == TM_AUTOALPHA) {
+ int inwnd;
+
+ if (GetForegroundWindow() == hwnd) {
+ KillTimer(hwnd, TM_AUTOALPHA);
+ inwnd = 1;
+ }
+ else {
+ POINT pt;
+ HWND hwndPt;
+ pt.x = (short) LOWORD(GetMessagePos());
+ pt.y = (short) HIWORD(GetMessagePos());
+ hwndPt = WindowFromPoint(pt);
+ inwnd = (hwndPt == hwnd || GetParent(hwndPt) == hwnd);
+ }
+ if (inwnd != transparentFocus && setLayeredWindowAttributes) { //change
+ transparentFocus = inwnd;
+ if (transparentFocus)
+ setLayeredWindowAttributes(hwnd, RGB(0, 0, 0), (BYTE) cluiopt.alpha, LWA_ALPHA);
+ else
+ setLayeredWindowAttributes(hwnd, RGB(0, 0, 0), (BYTE) DBGetContactSettingByte(NULL, "CList", "AutoAlpha", SETTING_AUTOALPHA_DEFAULT), LWA_ALPHA);
+ }
+ if (!transparentFocus)
+ KillTimer(hwnd, TM_AUTOALPHA);
+ }
+ return TRUE;
+
+ case WM_SHOWWINDOW:
+ {
+ static int noRecurse = 0;
+ if (lParam)
+ break;
+ if (noRecurse)
+ break;
+ if (!DBGetContactSettingByte(NULL, "CLUI", "FadeInOut", 0) || !IsWinVer2000Plus())
+ break;
+ if (GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_LAYERED) {
+ DWORD thisTick, startTick;
+ int sourceAlpha, destAlpha;
+ if (wParam) {
+ sourceAlpha = 0;
+ destAlpha = (BYTE) cluiopt.alpha;
+ setLayeredWindowAttributes(hwnd, RGB(0, 0, 0), 0, LWA_ALPHA);
+ noRecurse = 1;
+ ShowWindow(hwnd, SW_SHOW);
+ noRecurse = 0;
+ }
+ else {
+ sourceAlpha = (BYTE) cluiopt.alpha;
+ destAlpha = 0;
+ }
+ for (startTick = GetTickCount();;) {
+ thisTick = GetTickCount();
+ if (thisTick >= startTick + 200)
+ break;
+ setLayeredWindowAttributes(hwnd, RGB(0, 0, 0),
+ (BYTE) (sourceAlpha + (destAlpha - sourceAlpha) * (int) (thisTick - startTick) / 200), LWA_ALPHA);
+ }
+ setLayeredWindowAttributes(hwnd, RGB(0, 0, 0), (BYTE) destAlpha, LWA_ALPHA);
+ }
+ else {
+ if (wParam)
+ SetForegroundWindow(hwnd);
+ animateWindow(hwnd, 200, AW_BLEND | (wParam ? 0 : AW_HIDE));
+ SetWindowPos(cli.hwndContactTree, 0, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED);
+ }
+ break;
+ }
+ case WM_MENURBUTTONUP: /* this API is so badly documented at MSDN!! */
+ {
+ UINT id = 0;
+
+ id = GetMenuItemID((HMENU) lParam, LOWORD(wParam)); /* LOWORD(wParam) contains the menu pos in its parent menu */
+ if (id != (-1))
+ SendMessage(hwnd, WM_COMMAND, MAKEWPARAM(id, 0), 0);
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+ }
+ case WM_SYSCOMMAND:
+ switch (wParam)
+ {
+ case SC_MAXIMIZE:
+ return 0;
+
+ case SC_MINIMIZE:
+ case SC_CLOSE:
+ if ((GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_TOOLWINDOW) ||
+ DBGetContactSettingByte(NULL, "CList", "Min2Tray", SETTING_MIN2TRAY_DEFAULT))
+ {
+ ShowWindow(hwnd, SW_HIDE);
+ DBWriteContactSettingByte(NULL, "CList", "State", SETTING_STATE_HIDDEN);
+
+ if (MySetProcessWorkingSetSize != NULL && DBGetContactSettingByte(NULL, "CList", "DisableWorkingSet", 1))
+ MySetProcessWorkingSetSize(GetCurrentProcess(), -1, -1);
+
+ return 0;
+ }
+ else if (wParam == SC_CLOSE)
+ wParam = SC_MINIMIZE;
+ }
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+
+ case WM_COMMAND:
+ if (CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(wParam), MPCF_MAINMENU), (LPARAM) (HANDLE) NULL))
+ break;
+ switch (LOWORD(wParam)) {
+ case ID_TRAY_EXIT:
+ case ID_ICQ_EXIT:
+ if (CallService(MS_SYSTEM_OKTOEXIT, 0, 0))
+ DestroyWindow(hwnd);
+ break;
+ case ID_TRAY_HIDE:
+ CallService(MS_CLIST_SHOWHIDE, 0, 0);
+ break;
+ case POPUP_NEWGROUP:
+ SendMessage(cli.hwndContactTree, CLM_SETHIDEEMPTYGROUPS, 0, 0);
+ CallService(MS_CLIST_GROUPCREATE, 0, 0);
+ break;
+ case POPUP_HIDEOFFLINE:
+ CallService(MS_CLIST_SETHIDEOFFLINE, (WPARAM) (-1), 0);
+ break;
+ case POPUP_HIDEOFFLINEROOT:
+ SendMessage(cli.hwndContactTree, CLM_SETHIDEOFFLINEROOT, !SendMessage(cli.hwndContactTree, CLM_GETHIDEOFFLINEROOT, 0, 0), 0);
+ break;
+ case POPUP_HIDEEMPTYGROUPS:
+ {
+ int newVal = !(GetWindowLongPtr(cli.hwndContactTree, GWL_STYLE) & CLS_HIDEEMPTYGROUPS);
+ DBWriteContactSettingByte(NULL, "CList", "HideEmptyGroups", (BYTE) newVal);
+ SendMessage(cli.hwndContactTree, CLM_SETHIDEEMPTYGROUPS, newVal, 0);
+ break;
+ }
+ case POPUP_DISABLEGROUPS:
+ {
+ int newVal = !(GetWindowLongPtr(cli.hwndContactTree, GWL_STYLE) & CLS_USEGROUPS);
+ DBWriteContactSettingByte(NULL, "CList", "UseGroups", (BYTE) newVal);
+ SendMessage(cli.hwndContactTree, CLM_SETUSEGROUPS, newVal, 0);
+ break;
+ }
+ case POPUP_HIDEMIRANDA:
+ {
+ CallService(MS_CLIST_SHOWHIDE, 0, 0);
+ break;
+ } }
+ return FALSE;
+ case WM_KEYDOWN:
+ CallService(MS_CLIST_MENUPROCESSHOTKEY, wParam, MPCF_MAINMENU | MPCF_CONTACTMENU);
+ break;
+
+ case WM_GETMINMAXINFO:
+ DefWindowProc(hwnd, msg, wParam, lParam);
+ ((LPMINMAXINFO) lParam)->ptMinTrackSize.x = 16 + GetSystemMetrics(SM_CXHTHUMB);
+ ((LPMINMAXINFO) lParam)->ptMinTrackSize.y = 16;
+ return 0;
+
+ case WM_SETTINGCHANGE:
+ if (wParam == SPI_SETWORKAREA && (GetWindowLong(hwnd, GWL_STYLE) & (WS_VISIBLE | WS_MINIMIZE)) == WS_VISIBLE &&
+ !CallService(MS_CLIST_DOCKINGISDOCKED, 0, 0))
+ {
+ RECT rc;
+ GetWindowRect(hwnd, &rc);
+ if (Utils_AssertInsideScreen(&rc) == 1)
+ MoveWindow(hwnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE);
+ }
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+
+ case WM_DISPLAYCHANGE:
+ DefWindowProc(hwnd, msg, wParam, lParam);
+ SendMessage(cli.hwndContactTree, WM_SIZE, 0, 0); //forces it to send a cln_listsizechanged
+ break;
+
+ //MSG FROM CHILD CONTROL
+ case WM_NOTIFY:
+ if (((LPNMHDR) lParam)->hwndFrom == cli.hwndContactTree) {
+ switch (((LPNMHDR) lParam)->code) {
+ case CLN_EXPANDED:
+ {
+ NMCLISTCONTROL *nmc = (NMCLISTCONTROL *) lParam;
+ CallService(MS_CLIST_GROUPSETEXPANDED, (WPARAM) nmc->hItem, nmc->action);
+ return FALSE;
+ }
+ case CLN_DRAGGING:
+ {
+ NMCLISTCONTROL *nmc = (NMCLISTCONTROL *) lParam;
+ ClientToScreen(hwnd, &nmc->pt);
+ if (!(nmc->flags & CLNF_ISGROUP))
+ if (NotifyEventHooks(hContactDraggingEvent, (WPARAM) nmc->hItem, MAKELPARAM(nmc->pt.x, nmc->pt.y))) {
+ SetCursor(LoadCursor(cli.hInst, MAKEINTRESOURCE(IDC_DROPUSER)));
+ return TRUE;
+ }
+ break;
+ }
+ case CLN_DRAGSTOP:
+ {
+ NMCLISTCONTROL *nmc = (NMCLISTCONTROL *) lParam;
+ if (!(nmc->flags & CLNF_ISGROUP))
+ NotifyEventHooks(hContactDragStopEvent, (WPARAM) nmc->hItem, 0);
+ break;
+ }
+ case CLN_DROPPED:
+ {
+ NMCLISTCONTROL *nmc = (NMCLISTCONTROL *) lParam;
+ ClientToScreen(hwnd, &nmc->pt);
+ if (!(nmc->flags & CLNF_ISGROUP))
+ if (NotifyEventHooks(hContactDroppedEvent, (WPARAM) nmc->hItem, MAKELPARAM(nmc->pt.x, nmc->pt.y))) {
+ SetCursor(LoadCursor(cli.hInst, MAKEINTRESOURCE(IDC_DROPUSER)));
+ return TRUE;
+ }
+ break;
+ }
+ case NM_KEYDOWN:
+ {
+ NMKEY *nmkey = (NMKEY *) lParam;
+ return CallService(MS_CLIST_MENUPROCESSHOTKEY, nmkey->nVKey, MPCF_MAINMENU | MPCF_CONTACTMENU);
+ }
+ case CLN_LISTSIZECHANGE:
+ {
+ NMCLISTCONTROL *nmc = (NMCLISTCONTROL *) lParam;
+ RECT rcWindow, rcTree, rcWorkArea;
+ int maxHeight, newHeight;
+
+ if (!DBGetContactSettingByte(NULL, "CLUI", "AutoSize", 0))
+ break;
+ if (CallService(MS_CLIST_DOCKINGISDOCKED, 0, 0))
+ break;
+ maxHeight = DBGetContactSettingByte(NULL, "CLUI", "MaxSizeHeight", 75);
+ GetWindowRect(hwnd, &rcWindow);
+ GetWindowRect(cli.hwndContactTree, &rcTree);
+
+ SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWorkArea, FALSE);
+ if (MyMonitorFromWindow)
+ {
+ HMONITOR hMon = MyMonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
+ MONITORINFO mi;
+ mi.cbSize = sizeof(mi);
+ if (MyGetMonitorInfo(hMon, &mi))
+ rcWorkArea = mi.rcWork;
+ }
+
+ newHeight = max(nmc->pt.y, 9) + 1 + (rcWindow.bottom - rcWindow.top) - (rcTree.bottom - rcTree.top);
+ if (newHeight > (rcWorkArea.bottom - rcWorkArea.top) * maxHeight / 100)
+ newHeight = (rcWorkArea.bottom - rcWorkArea.top) * maxHeight / 100;
+ if (DBGetContactSettingByte(NULL, "CLUI", "AutoSizeUpward", 0)) {
+ rcWindow.top = rcWindow.bottom - newHeight;
+ if (rcWindow.top < rcWorkArea.top)
+ rcWindow.top = rcWorkArea.top;
+ }
+ else {
+ rcWindow.bottom = rcWindow.top + newHeight;
+ if (rcWindow.bottom > rcWorkArea.bottom)
+ rcWindow.bottom = rcWorkArea.bottom;
+ }
+ SetWindowPos(hwnd, 0, rcWindow.left, rcWindow.top, rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top,
+ SWP_NOZORDER | SWP_NOACTIVATE);
+ break;
+ }
+ case NM_CLICK:
+ {
+ NMCLISTCONTROL *nm = (NMCLISTCONTROL *) lParam;
+ DWORD hitFlags;
+
+ if (SendMessage(cli.hwndContactTree, CLM_HITTEST, (WPARAM) & hitFlags, MAKELPARAM(nm->pt.x, nm->pt.y)))
+ break;
+ if ((hitFlags & (CLCHT_NOWHERE | CLCHT_INLEFTMARGIN | CLCHT_BELOWITEMS)) == 0)
+ break;
+ if (DBGetContactSettingByte(NULL, "CLUI", "ClientAreaDrag", SETTING_CLIENTDRAG_DEFAULT)) {
+ POINT pt;
+ pt = nm->pt;
+ ClientToScreen(cli.hwndContactTree, &pt);
+ return SendMessage(hwnd, WM_SYSCOMMAND, SC_MOVE | HTCAPTION, MAKELPARAM(pt.x, pt.y));
+ }
+ break;
+ } }
+ }
+ else if (((LPNMHDR) lParam)->hwndFrom == cli.hwndStatus) {
+ if (((LPNMHDR) lParam)->code == NM_CLICK)
+ {
+ unsigned int nParts, nPanel;
+ NMMOUSE *nm = (NMMOUSE *) lParam;
+ HMENU hMenu;
+ RECT rc;
+ POINT pt;
+
+ hMenu = (HMENU) CallService(MS_CLIST_MENUGETSTATUS, 0, 0);
+ nParts = SendMessage(cli.hwndStatus, SB_GETPARTS, 0, 0);
+ if (nm->dwItemSpec == 0xFFFFFFFE) {
+ nPanel = nParts - 1;
+ SendMessage(cli.hwndStatus, SB_GETRECT, nPanel, (LPARAM) & rc);
+ if (nm->pt.x < rc.left)
+ return FALSE;
+ }
+ else nPanel = nm->dwItemSpec;
+
+ if (nParts > 0)
+ {
+ unsigned int cpnl = 0;
+ int mcnt = GetMenuItemCount(hMenu);
+ for (int i=0; i<mcnt; ++i) {
+ HMENU hMenus = GetSubMenu(hMenu, i);
+ if (hMenus && cpnl++ == nPanel) {
+ hMenu = hMenus;
+ break;
+ }
+ }
+ }
+ SendMessage(cli.hwndStatus, SB_GETRECT, nPanel, (LPARAM) & rc);
+ pt.x = rc.left;
+ pt.y = rc.top;
+ ClientToScreen(cli.hwndStatus, &pt);
+ TrackPopupMenu(hMenu, TPM_BOTTOMALIGN | TPM_LEFTALIGN, pt.x, pt.y, 0, hwnd, NULL);
+ } }
+ return FALSE;
+
+ case WM_MENUSELECT:
+ if(lParam && (HMENU)lParam == cli.hMenuMain) {
+ int pos = LOWORD(wParam);
+ POINT pt;
+ GetCursorPos(&pt);
+ if ((pos == 0 || pos == 1) && (HIWORD(wParam) & MF_POPUP) &&
+ (!(HIWORD(wParam) & MF_MOUSESELECT) || MenuItemFromPoint(hwnd, cli.hMenuMain, pt) != -1)) {
+ MENUITEMINFO mii = { 0 };
+ mii.cbSize = MENUITEMINFO_V4_SIZE;
+ mii.fMask = MIIM_SUBMENU;
+ mii.hSubMenu = (HMENU)CallService((pos == 0) ? MS_CLIST_MENUGETMAIN : MS_CLIST_MENUGETSTATUS, 0, 0);
+ SetMenuItemInfo(cli.hMenuMain, pos, TRUE, &mii);
+ } }
+ break;
+
+ case WM_CONTEXTMENU:
+ {
+ RECT rc;
+ POINT pt;
+
+ pt.x = (short) LOWORD(lParam);
+ pt.y = (short) HIWORD(lParam);
+ // x/y might be -1 if it was generated by a kb click
+ GetWindowRect(cli.hwndContactTree, &rc);
+ if (pt.x == -1 && pt.y == -1) {
+ // all this is done in screen-coords!
+ GetCursorPos(&pt);
+ // the mouse isnt near the window, so put it in the middle of the window
+ if (!PtInRect(&rc, pt)) {
+ pt.x = rc.left + (rc.right - rc.left) / 2;
+ pt.y = rc.top + (rc.bottom - rc.top) / 2;
+ }
+ }
+ if (PtInRect(&rc, pt)) {
+ HMENU hMenu;
+ hMenu = GetSubMenu(LoadMenu(cli.hInst, MAKEINTRESOURCE(IDR_CONTEXT)), 1);
+ CallService(MS_LANGPACK_TRANSLATEMENU, (WPARAM) hMenu, 0);
+ CheckMenuItem(hMenu, POPUP_HIDEOFFLINE,
+ DBGetContactSettingByte(NULL, "CList", "HideOffline", SETTING_HIDEOFFLINE_DEFAULT) ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(hMenu, POPUP_HIDEOFFLINEROOT, SendMessage(cli.hwndContactTree, CLM_GETHIDEOFFLINEROOT, 0, 0) ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(hMenu, POPUP_HIDEEMPTYGROUPS,
+ GetWindowLongPtr(cli.hwndContactTree, GWL_STYLE) & CLS_HIDEEMPTYGROUPS ? MF_CHECKED : MF_UNCHECKED);
+ CheckMenuItem(hMenu, POPUP_DISABLEGROUPS, GetWindowLongPtr(cli.hwndContactTree, GWL_STYLE) & CLS_USEGROUPS ? MF_UNCHECKED : MF_CHECKED);
+ TrackPopupMenu(hMenu, TPM_TOPALIGN | TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, 0, hwnd, NULL);
+ DestroyMenu(hMenu);
+ return 0;
+ }
+ GetWindowRect(cli.hwndStatus, &rc);
+ if (PtInRect(&rc, pt)) {
+ HMENU hMenu;
+ if (DBGetContactSettingByte(NULL, "CLUI", "SBarRightClk", 0))
+ hMenu = (HMENU) CallService(MS_CLIST_MENUGETMAIN, 0, 0);
+ else
+ hMenu = (HMENU) CallService(MS_CLIST_MENUGETSTATUS, 0, 0);
+ TrackPopupMenu(hMenu, TPM_TOPALIGN | TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, 0, hwnd, NULL);
+ return 0;
+ } }
+ break;
+
+ case WM_MEASUREITEM:
+ if (((LPMEASUREITEMSTRUCT) lParam)->itemData == MENU_MIRANDAMENU) {
+ ((LPMEASUREITEMSTRUCT) lParam)->itemWidth = g_IconWidth * 4 / 3;
+ ((LPMEASUREITEMSTRUCT) lParam)->itemHeight = 0;
+ return TRUE;
+ }
+ return CallService(MS_CLIST_MENUMEASUREITEM, wParam, lParam);
+ case WM_DRAWITEM:
+ {
+ LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT) lParam;
+ if (dis->hwndItem == cli.hwndStatus) {
+ char *szProto = (char *) dis->itemData;
+ if (szProto == NULL) return 0;
+ int status, x;
+ SIZE textSize;
+ BYTE showOpts = DBGetContactSettingByte(NULL, "CLUI", "SBarShow", 1);
+ status = CallProtoService(szProto, PS_GETSTATUS, 0, 0);
+ SetBkMode(dis->hDC, TRANSPARENT);
+ x = dis->rcItem.left;
+ if (showOpts & 1) {
+ HICON hIcon = LoadSkinProtoIcon(szProto, status);
+ DrawIconEx(dis->hDC, x, (dis->rcItem.top + dis->rcItem.bottom - g_IconHeight) >> 1, hIcon,
+ g_IconWidth, g_IconHeight, 0, NULL, DI_NORMAL);
+ IconLib_ReleaseIcon(hIcon,0);
+ if ( Proto_IsAccountLocked( Proto_GetAccount( szProto ))) {
+ hIcon = LoadSkinnedIcon(SKINICON_OTHER_STATUS_LOCKED);
+ if (hIcon != NULL) {
+ DrawIconEx(dis->hDC, x, (dis->rcItem.top + dis->rcItem.bottom - g_IconHeight) >> 1, hIcon,
+ g_IconWidth, g_IconHeight, 0, NULL, DI_NORMAL);
+ IconLib_ReleaseIcon(hIcon,0);
+ }
+
+ }
+ x += g_IconWidth + 2;
+ }
+ else
+ x += 2;
+ if (showOpts & 2) {
+ PROTOACCOUNT* pa;
+ TCHAR tszName[64];
+ if (( pa = Proto_GetAccount( szProto )) != NULL )
+ mir_sntprintf( tszName, SIZEOF(tszName), _T("%s "), pa->tszAccountName );
+ else
+ tszName[0] = 0;
+
+ GetTextExtentPoint32(dis->hDC, tszName, lstrlen(tszName), &textSize);
+ TextOut(dis->hDC, x, (dis->rcItem.top + dis->rcItem.bottom - textSize.cy) >> 1, tszName, lstrlen(tszName));
+ x += textSize.cx;
+ }
+ if (showOpts & 4) {
+ TCHAR* szStatus = cli.pfnGetStatusModeDescription( status, 0 );
+ if ( !szStatus )
+ szStatus = _T("");
+ GetTextExtentPoint32( dis->hDC, szStatus, lstrlen(szStatus), &textSize );
+ TextOut( dis->hDC, x, (dis->rcItem.top + dis->rcItem.bottom - textSize.cy ) >> 1, szStatus, lstrlen( szStatus ));
+ }
+ }
+ else if (dis->CtlType == ODT_MENU) {
+ if (dis->itemData == MENU_MIRANDAMENU) {
+ HICON hIcon = LoadSkinnedIcon(SKINICON_OTHER_MAINMENU);
+ fnDrawMenuItem(dis, CopyIcon(hIcon), NULL);
+ IconLib_ReleaseIcon(hIcon, NULL);
+ return TRUE;
+ }
+ return CallService(MS_CLIST_MENUDRAWITEM, wParam, lParam);
+ } }
+ return 0;
+
+ case WM_CLOSE:
+ if (CallService(MS_SYSTEM_OKTOEXIT, 0, 0))
+ DestroyWindow(hwnd);
+ return FALSE;
+
+ case WM_DESTROY:
+ if (!IsIconic(hwnd)) {
+ RECT rc;
+ GetWindowRect(hwnd, &rc);
+
+ if (!CallService(MS_CLIST_DOCKINGISDOCKED, 0, 0)) { //if docked, dont remember pos (except for width)
+ DBWriteContactSettingDword(NULL, "CList", "Height", (DWORD) (rc.bottom - rc.top));
+ DBWriteContactSettingDword(NULL, "CList", "x", (DWORD) rc.left);
+ DBWriteContactSettingDword(NULL, "CList", "y", (DWORD) rc.top);
+ }
+ DBWriteContactSettingDword(NULL, "CList", "Width", (DWORD) (rc.right - rc.left));
+ }
+
+ RemoveMenu(cli.hMenuMain, 0, MF_BYPOSITION);
+ RemoveMenu(cli.hMenuMain, 0, MF_BYPOSITION);
+
+ if ( cli.hwndStatus ) {
+ DestroyWindow( cli.hwndStatus );
+ cli.hwndStatus = NULL;
+ }
+
+ // Disconnect all protocols
+ DisconnectAll();
+
+ ShowWindow(hwnd, SW_HIDE);
+ DestroyWindow(cli.hwndContactTree);
+ FreeLibrary(hUserDll);
+ PostQuitMessage(0);
+
+ default:
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+ }
+
+ return TRUE;
+}
diff --git a/src/modules/clist/cluiservices.cpp b/src/modules/clist/cluiservices.cpp
new file mode 100644
index 0000000000..c6b6efda71
--- /dev/null
+++ b/src/modules/clist/cluiservices.cpp
@@ -0,0 +1,221 @@
+/*
+
+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 "clc.h"
+
+static INT_PTR GetHwnd(WPARAM, LPARAM)
+{
+ return (INT_PTR)cli.hwndContactList;
+}
+
+static INT_PTR GetHwndTree(WPARAM, LPARAM)
+{
+ return (INT_PTR)cli.hwndContactTree;
+}
+
+static INT_PTR CluiProtocolStatusChanged(WPARAM wParam, LPARAM lParam)
+{
+ cli.pfnCluiProtocolStatusChanged( wParam, (const char*)lParam );
+ return 0;
+}
+
+INT_PTR SortList(WPARAM, LPARAM)
+{
+ //unnecessary: CLC does this automatically
+ return 0;
+}
+
+static INT_PTR GroupAdded(WPARAM wParam, LPARAM lParam)
+{
+ //CLC does this automatically unless it's a new group
+ if (lParam) {
+ HANDLE hItem;
+ TCHAR szFocusClass[64];
+ HWND hwndFocus = GetFocus();
+
+ GetClassName(hwndFocus, szFocusClass, SIZEOF(szFocusClass));
+ if (!lstrcmp(szFocusClass, CLISTCONTROL_CLASS)) {
+ hItem = (HANDLE) SendMessage(hwndFocus, CLM_FINDGROUP, wParam, 0);
+ if (hItem)
+ SendMessage(hwndFocus, CLM_EDITLABEL, (WPARAM) hItem, 0);
+ }
+ }
+ return 0;
+}
+
+static INT_PTR ContactSetIcon(WPARAM, LPARAM)
+{
+ //unnecessary: CLC does this automatically
+ return 0;
+}
+
+static INT_PTR ContactDeleted(WPARAM, LPARAM)
+{
+ //unnecessary: CLC does this automatically
+ return 0;
+}
+
+static INT_PTR ContactAdded(WPARAM, LPARAM)
+{
+ //unnecessary: CLC does this automatically
+ return 0;
+}
+
+static INT_PTR ListBeginRebuild(WPARAM, LPARAM)
+{
+ //unnecessary: CLC does this automatically
+ return 0;
+}
+
+static INT_PTR ListEndRebuild(WPARAM, LPARAM)
+{
+ int rebuild = 0;
+ //CLC does this automatically, but we need to force it if hideoffline or hideempty has changed
+ if ((DBGetContactSettingByte(NULL, "CList", "HideOffline", SETTING_HIDEOFFLINE_DEFAULT) == 0) != ((GetWindowLongPtr(cli.hwndContactTree, GWL_STYLE) & CLS_HIDEOFFLINE) == 0)) {
+ if (DBGetContactSettingByte(NULL, "CList", "HideOffline", SETTING_HIDEOFFLINE_DEFAULT))
+ SetWindowLongPtr(cli.hwndContactTree, GWL_STYLE, GetWindowLongPtr(cli.hwndContactTree, GWL_STYLE) | CLS_HIDEOFFLINE);
+ else
+ SetWindowLongPtr(cli.hwndContactTree, GWL_STYLE, GetWindowLongPtr(cli.hwndContactTree, GWL_STYLE) & ~CLS_HIDEOFFLINE);
+ rebuild = 1;
+ }
+ if ((DBGetContactSettingByte(NULL, "CList", "HideEmptyGroups", SETTING_HIDEEMPTYGROUPS_DEFAULT) == 0) != ((GetWindowLongPtr(cli.hwndContactTree, GWL_STYLE) & CLS_HIDEEMPTYGROUPS) == 0)) {
+ if (DBGetContactSettingByte(NULL, "CList", "HideEmptyGroups", SETTING_HIDEEMPTYGROUPS_DEFAULT))
+ SetWindowLongPtr(cli.hwndContactTree, GWL_STYLE, GetWindowLongPtr(cli.hwndContactTree, GWL_STYLE) | CLS_HIDEEMPTYGROUPS);
+ else
+ SetWindowLongPtr(cli.hwndContactTree, GWL_STYLE, GetWindowLongPtr(cli.hwndContactTree, GWL_STYLE) & ~CLS_HIDEEMPTYGROUPS);
+ rebuild = 1;
+ }
+ if ((DBGetContactSettingByte(NULL, "CList", "UseGroups", SETTING_USEGROUPS_DEFAULT) == 0) != ((GetWindowLongPtr(cli.hwndContactTree, GWL_STYLE) & CLS_USEGROUPS) == 0)) {
+ if (DBGetContactSettingByte(NULL, "CList", "UseGroups", SETTING_USEGROUPS_DEFAULT))
+ SetWindowLongPtr(cli.hwndContactTree, GWL_STYLE, GetWindowLongPtr(cli.hwndContactTree, GWL_STYLE) | CLS_USEGROUPS);
+ else
+ SetWindowLongPtr(cli.hwndContactTree, GWL_STYLE, GetWindowLongPtr(cli.hwndContactTree, GWL_STYLE) & ~CLS_USEGROUPS);
+ rebuild = 1;
+ }
+ if (rebuild)
+ SendMessage(cli.hwndContactTree, CLM_AUTOREBUILD, 0, 0);
+ return 0;
+}
+
+static INT_PTR ContactRenamed(WPARAM, LPARAM)
+{
+ //unnecessary: CLC does this automatically
+ return 0;
+}
+
+static INT_PTR GetCaps(WPARAM wParam, LPARAM)
+{
+ switch (wParam) {
+ case CLUICAPS_FLAGS1:
+ return CLUIF_HIDEEMPTYGROUPS | CLUIF_DISABLEGROUPS | CLUIF_HASONTOPOPTION | CLUIF_HASAUTOHIDEOPTION;
+ }
+ return 0;
+}
+
+void LoadCluiServices(void)
+{
+ CreateServiceFunction(MS_CLUI_GETHWND, GetHwnd);
+ CreateServiceFunction(MS_CLUI_GETHWNDTREE,GetHwndTree);
+ CreateServiceFunction(MS_CLUI_PROTOCOLSTATUSCHANGED, CluiProtocolStatusChanged);
+ CreateServiceFunction(MS_CLUI_GROUPADDED, GroupAdded);
+ CreateServiceFunction(MS_CLUI_CONTACTSETICON, ContactSetIcon);
+ CreateServiceFunction(MS_CLUI_CONTACTADDED, ContactAdded);
+ CreateServiceFunction(MS_CLUI_CONTACTDELETED, ContactDeleted);
+ CreateServiceFunction(MS_CLUI_CONTACTRENAMED, ContactRenamed);
+ CreateServiceFunction(MS_CLUI_LISTBEGINREBUILD, ListBeginRebuild);
+ CreateServiceFunction(MS_CLUI_LISTENDREBUILD, ListEndRebuild);
+ CreateServiceFunction(MS_CLUI_SORTLIST, SortList);
+ CreateServiceFunction(MS_CLUI_GETCAPS, GetCaps);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// default protocol status notification handler
+
+void fnCluiProtocolStatusChanged(int, const char* )
+{
+ int i, *partWidths;
+ int borders[3];
+ int flags = 0;
+
+ if ( cli.menuProtoCount == 0 ) {
+ SendMessage(cli.hwndStatus, SB_SETPARTS, 0, 0);
+ SendMessage( cli.hwndStatus, SB_SETTEXT, SBT_OWNERDRAW, 0 );
+ return;
+ }
+
+ SendMessage(cli.hwndStatus, SB_GETBORDERS, 0, ( LPARAM )&borders);
+
+ partWidths = ( int* )alloca( cli.menuProtoCount * sizeof( int ));
+ if ( DBGetContactSettingByte( NULL, "CLUI", "EqualSections", 0 )) {
+ RECT rc;
+ GetClientRect( cli.hwndStatus, &rc );
+ rc.right -= borders[0] * 2 + ( DBGetContactSettingByte( NULL, "CLUI", "ShowGrip", 1 ) ? GetSystemMetrics( SM_CXVSCROLL ) : 0 );
+ for ( i = 0; i < cli.menuProtoCount; i++ )
+ partWidths[ i ] = ( i+1 ) * rc.right / cli.menuProtoCount - (borders[2] >> 1);
+ }
+ else {
+ HDC hdc;
+ SIZE textSize;
+ BYTE showOpts = DBGetContactSettingByte(NULL, "CLUI", "SBarShow", 1);
+
+ hdc = GetDC(NULL);
+ SelectObject(hdc, (HFONT) SendMessage(cli.hwndStatus, WM_GETFONT, 0, 0));
+ for ( i = 0; i < cli.menuProtoCount; i++ ) { //count down since built in ones tend to go at the end
+ int x = 2;
+ if ( showOpts & 1 )
+ x += g_IconWidth;
+ if ( showOpts & 2 ) {
+ TCHAR tszName[64];
+ PROTOACCOUNT* pa = Proto_GetAccount( cli.menuProtos[i].szProto );
+ if ( pa )
+ mir_sntprintf( tszName, SIZEOF(tszName), _T("%s "), pa->tszAccountName );
+ else
+ tszName[0] = 0;
+
+ if ( showOpts & 4 && lstrlen(tszName) < SIZEOF(tszName)-1 )
+ lstrcat( tszName, _T(" "));
+ GetTextExtentPoint32(hdc, tszName, lstrlen(tszName), &textSize);
+ x += textSize.cx;
+ x += GetSystemMetrics(SM_CXBORDER) * 4; // The SB panel doesnt allocate enough room
+ }
+ if ( showOpts & 4 ) {
+ TCHAR* modeDescr = cli.pfnGetStatusModeDescription( CallProtoService( cli.menuProtos[i].szProto, PS_GETSTATUS, 0, 0), 0 );
+ GetTextExtentPoint32(hdc, modeDescr, lstrlen(modeDescr), &textSize);
+ x += textSize.cx;
+ x += GetSystemMetrics(SM_CXBORDER) * 4; // The SB panel doesnt allocate enough room
+ }
+ partWidths[ i ] = ( i ? partWidths[ i-1] : 0 ) + x + 2;
+ }
+ ReleaseDC(NULL, hdc);
+ }
+
+ partWidths[ cli.menuProtoCount-1 ] = -1;
+ SendMessage(cli.hwndStatus, SB_SETMINHEIGHT, g_IconHeight, 0);
+ SendMessage(cli.hwndStatus, SB_SETPARTS, cli.menuProtoCount, ( LPARAM )partWidths);
+ flags = SBT_OWNERDRAW;
+ if ( DBGetContactSettingByte( NULL, "CLUI", "SBarBevel", 1 ) == 0 )
+ flags |= SBT_NOBORDERS;
+ for ( i = 0; i < cli.menuProtoCount; i++ ) {
+ SendMessage( cli.hwndStatus, SB_SETTEXT, i | flags, ( LPARAM )cli.menuProtos[i].szProto );
+ }
+}
diff --git a/src/modules/clist/contact.cpp b/src/modules/clist/contact.cpp
new file mode 100644
index 0000000000..f996dd11ac
--- /dev/null
+++ b/src/modules/clist/contact.cpp
@@ -0,0 +1,193 @@
+/*
+
+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 "clc.h"
+
+extern HANDLE hContactIconChangedEvent;
+extern HANDLE hGroupChangeEvent;
+
+int sortByStatus;
+int sortByProto;
+
+static const struct {
+ int status,order;
+} statusModeOrder[]={
+ {ID_STATUS_OFFLINE,500},
+ {ID_STATUS_ONLINE,10},
+ {ID_STATUS_AWAY,200},
+ {ID_STATUS_DND,110},
+ {ID_STATUS_NA,450},
+ {ID_STATUS_OCCUPIED,100},
+ {ID_STATUS_FREECHAT,0},
+ {ID_STATUS_INVISIBLE,20},
+ {ID_STATUS_ONTHEPHONE,150},
+ {ID_STATUS_OUTTOLUNCH,425}};
+
+static int GetContactStatus(HANDLE hContact)
+{
+ char* szProto = ( char* )CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0);
+ if (szProto == NULL)
+ return ID_STATUS_OFFLINE;
+ return DBGetContactSettingWord(hContact, szProto, "Status", ID_STATUS_OFFLINE);
+}
+
+void fnChangeContactIcon(HANDLE hContact, int iIcon, int add)
+{
+ CallService(add ? MS_CLUI_CONTACTADDED : MS_CLUI_CONTACTSETICON, (WPARAM) hContact, iIcon);
+ NotifyEventHooks(hContactIconChangedEvent, (WPARAM) hContact, iIcon);
+}
+
+int GetStatusModeOrdering(int statusMode)
+{
+ int i;
+ for (i = 0; i < SIZEOF(statusModeOrder); i++)
+ if (statusModeOrder[i].status == statusMode)
+ return statusModeOrder[i].order;
+ return 1000;
+}
+
+void fnLoadContactTree(void)
+{
+ HANDLE hContact;
+ int i, status, hideOffline;
+
+ CallService(MS_CLUI_LISTBEGINREBUILD, 0, 0);
+ for (i = 1;; i++) {
+ if ( cli.pfnGetGroupName(i, NULL) == NULL)
+ break;
+ CallService(MS_CLUI_GROUPADDED, i, 0);
+ }
+
+ hideOffline = DBGetContactSettingByte(NULL, "CList", "HideOffline", SETTING_HIDEOFFLINE_DEFAULT);
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while (hContact != NULL) {
+ status = GetContactStatus(hContact);
+ if ((!hideOffline || status != ID_STATUS_OFFLINE) && !DBGetContactSettingByte(hContact, "CList", "Hidden", 0))
+ cli.pfnChangeContactIcon(hContact, cli.pfnIconFromStatusMode((char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0), status, hContact), 1);
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0);
+ }
+ sortByStatus = DBGetContactSettingByte(NULL, "CList", "SortByStatus", SETTING_SORTBYSTATUS_DEFAULT);
+ sortByProto = DBGetContactSettingByte(NULL, "CList", "SortByProto", SETTING_SORTBYPROTO_DEFAULT);
+ CallService(MS_CLUI_SORTLIST, 0, 0);
+ CallService(MS_CLUI_LISTENDREBUILD, 0, 0);
+}
+
+int fnCompareContacts(const struct ClcContact* c1, const struct ClcContact* c2)
+{
+ HANDLE a = c1->hContact, b = c2->hContact;
+ TCHAR namea[128], *nameb;
+ int statusa, statusb;
+ int rc;
+
+ statusa = DBGetContactSettingWord((HANDLE) a, c1->proto, "Status", ID_STATUS_OFFLINE);
+ statusb = DBGetContactSettingWord((HANDLE) b, c2->proto, "Status", ID_STATUS_OFFLINE);
+
+ if (sortByProto) {
+ /* deal with statuses, online contacts have to go above offline */
+ if ((statusa == ID_STATUS_OFFLINE) != (statusb == ID_STATUS_OFFLINE)) {
+ return 2 * (statusa == ID_STATUS_OFFLINE) - 1;
+ }
+ /* both are online, now check protocols */
+ rc = lstrcmpA( c1->proto, c2->proto);
+ if (rc != 0 && (c1->proto != NULL && c2->proto != NULL))
+ return rc;
+ /* protocols are the same, order by display name */
+ }
+
+ if (sortByStatus) {
+ int ordera, orderb;
+ ordera = GetStatusModeOrdering(statusa);
+ orderb = GetStatusModeOrdering(statusb);
+ if (ordera != orderb)
+ return ordera - orderb;
+ }
+ else {
+ //one is offline: offline goes below online
+ if ((statusa == ID_STATUS_OFFLINE) != (statusb == ID_STATUS_OFFLINE)) {
+ return 2 * (statusa == ID_STATUS_OFFLINE) - 1;
+ }
+ }
+
+ nameb = cli.pfnGetContactDisplayName( a, 0);
+ _tcsncpy(namea, nameb, SIZEOF(namea));
+ namea[ SIZEOF(namea)-1 ] = 0;
+ nameb = cli.pfnGetContactDisplayName( b, 0);
+
+ //otherwise just compare names
+ return _tcsicmp(namea, nameb);
+}
+
+static UINT_PTR resortTimerId = 0;
+static VOID CALLBACK SortContactsTimer(HWND, UINT, UINT_PTR, DWORD)
+{
+ KillTimer(NULL, resortTimerId);
+ resortTimerId = 0;
+ CallService(MS_CLUI_SORTLIST, 0, 0);
+}
+
+void fnSortContacts(void)
+{
+ //avoid doing lots of resorts in quick succession
+ sortByStatus = DBGetContactSettingByte(NULL, "CList", "SortByStatus", SETTING_SORTBYSTATUS_DEFAULT);
+ sortByProto = DBGetContactSettingByte(NULL, "CList", "SortByProto", SETTING_SORTBYPROTO_DEFAULT);
+ if (resortTimerId)
+ KillTimer(NULL, resortTimerId);
+ // setting this to a higher delay causes shutdown waits.
+ resortTimerId = SetTimer(NULL, 0, 500, SortContactsTimer);
+}
+
+INT_PTR ContactChangeGroup(WPARAM wParam, LPARAM lParam)
+{
+ CLISTGROUPCHANGE grpChg = { sizeof(CLISTGROUPCHANGE), NULL, NULL };
+
+ CallService(MS_CLUI_CONTACTDELETED, wParam, 0);
+ if ((HANDLE) lParam == NULL)
+ DBDeleteContactSetting((HANDLE) wParam, "CList", "Group");
+ else {
+ grpChg.pszNewName = cli.pfnGetGroupName(lParam, NULL);
+ DBWriteContactSettingTString((HANDLE) wParam, "CList", "Group", grpChg.pszNewName);
+ }
+ CallService(MS_CLUI_CONTACTADDED, wParam,
+ cli.pfnIconFromStatusMode((char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0), GetContactStatus((HANDLE) wParam), (HANDLE) wParam));
+
+ NotifyEventHooks(hGroupChangeEvent, wParam, (LPARAM)&grpChg);
+ return 0;
+}
+
+int fnSetHideOffline(WPARAM wParam, LPARAM)
+{
+ switch(( int )wParam ) {
+ case 0:
+ DBWriteContactSettingByte(NULL, "CList", "HideOffline", 0);
+ break;
+ case 1:
+ DBWriteContactSettingByte(NULL, "CList", "HideOffline", 1);
+ break;
+ case -1:
+ DBWriteContactSettingByte(NULL, "CList", "HideOffline",
+ (BYTE) ! DBGetContactSettingByte(NULL, "CList", "HideOffline", SETTING_HIDEOFFLINE_DEFAULT));
+ break;
+ }
+ cli.pfnLoadContactTree();
+ return 0;
+}
diff --git a/src/modules/clist/genmenu.cpp b/src/modules/clist/genmenu.cpp
new file mode 100644
index 0000000000..92ec6d3edc
--- /dev/null
+++ b/src/modules/clist/genmenu.cpp
@@ -0,0 +1,1294 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2010 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 "genmenu.h"
+
+static bool bIsGenMenuInited;
+bool bIconsDisabled;
+static CRITICAL_SECTION csMenuHook;
+
+static int NextObjectId = 0x100, NextObjectMenuItemId = CLISTMENUIDMIN;
+
+#if defined( _DEBUG )
+static void DumpMenuItem( TMO_IntMenuItem* pParent, int level = 0 )
+{
+ char temp[ 30 ];
+ memset( temp, '\t', level );
+ temp[ level ] = 0;
+
+ for ( PMO_IntMenuItem pimi = pParent; pimi != NULL; pimi = pimi->next ) {
+ Netlib_Logf( NULL, "%sMenu item %08p [%08p]: %S", temp, pimi, pimi->mi.root, pimi->mi.ptszName );
+
+ PMO_IntMenuItem submenu = pimi->submenu.first;
+ if ( submenu )
+ DumpMenuItem( submenu, level+1 );
+} }
+
+#endif
+
+static int CompareMenus( const TIntMenuObject* p1, const TIntMenuObject* p2 )
+{
+ return lstrcmpA( p1->Name, p2->Name );
+}
+
+LIST<TIntMenuObject> g_menus( 10, CompareMenus );
+
+void FreeAndNil( void **p )
+{
+ if ( p == NULL )
+ return;
+
+ if ( *p != NULL ) {
+ mir_free( *p );
+ *p = NULL;
+} }
+
+int GetMenuObjbyId( const int id )
+{
+ for ( int i=0; i < g_menus.getCount(); i++ )
+ if ( g_menus[i]->id == id )
+ return i;
+
+ return -1;
+}
+
+PMO_IntMenuItem MO_RecursiveWalkMenu( PMO_IntMenuItem parent, pfnWalkFunc func, void* param )
+{
+ if ( parent == NULL )
+ return FALSE;
+
+ PMO_IntMenuItem pnext;
+ for ( PMO_IntMenuItem pimi = parent; pimi != NULL; pimi = pnext ) {
+ PMO_IntMenuItem submenu = pimi->submenu.first;
+ pnext = pimi->next;
+ if ( func( pimi, param )) // it can destroy the menu item
+ return pimi;
+
+ if ( submenu ) {
+ PMO_IntMenuItem res = MO_RecursiveWalkMenu( submenu, func, param );
+ if ( res )
+ return res;
+ }
+ }
+
+ return FALSE;
+}
+
+//wparam=0
+//lparam=LPMEASUREITEMSTRUCT
+int MO_MeasureMenuItem( LPMEASUREITEMSTRUCT mis )
+{
+ // prevent win9x from ugly menus displaying when there is no icon
+ mis->itemWidth = 0;
+ mis->itemHeight = 0;
+
+ if ( !bIsGenMenuInited )
+ return -1;
+
+ if ( mis == NULL )
+ return FALSE;
+
+ PMO_IntMenuItem pimi = MO_GetIntMenuItem(( HGENMENU )mis->itemData );
+ if ( pimi == NULL )
+ return FALSE;
+
+ if ( pimi->iconId == -1 )
+ return FALSE;
+
+ mis->itemWidth = max(0,GetSystemMetrics(SM_CXSMICON)-GetSystemMetrics(SM_CXMENUCHECK)+4);
+ mis->itemHeight = GetSystemMetrics(SM_CYSMICON)+2;
+ return TRUE;
+}
+
+//wparam=0
+//lparam=LPDRAWITEMSTRUCT
+int MO_DrawMenuItem( LPDRAWITEMSTRUCT dis )
+{
+ if ( !bIsGenMenuInited )
+ return -1;
+
+ if ( dis == NULL )
+ return FALSE;
+
+ EnterCriticalSection( &csMenuHook );
+
+ PMO_IntMenuItem pimi = MO_GetIntMenuItem(( HGENMENU )dis->itemData );
+ if ( pimi == NULL || pimi->iconId == -1 ) {
+ LeaveCriticalSection( &csMenuHook );
+ return FALSE;
+ }
+
+ int y = (dis->rcItem.bottom - dis->rcItem.top - GetSystemMetrics(SM_CYSMICON))/2+1;
+ if ( dis->itemState & ODS_SELECTED ) {
+ if ( dis->itemState & ODS_CHECKED ) {
+ RECT rc;
+ rc.left = 2; rc.right = GetSystemMetrics(SM_CXSMICON)+2;
+ rc.top = y; rc.bottom = rc.top+GetSystemMetrics(SM_CYSMICON)+2;
+ FillRect(dis->hDC, &rc, GetSysColorBrush( COLOR_HIGHLIGHT ));
+ ImageList_DrawEx( pimi->parent->m_hMenuIcons, pimi->iconId, dis->hDC, 2, y, 0, 0, CLR_NONE, CLR_DEFAULT, ILD_SELECTED );
+ }
+ else ImageList_DrawEx( pimi->parent->m_hMenuIcons, pimi->iconId, dis->hDC, 2, y, 0, 0, CLR_NONE, CLR_DEFAULT, ILD_FOCUS );
+ }
+ else {
+ if ( dis->itemState & ODS_CHECKED) {
+ RECT rc;
+ rc.left = 0; rc.right = GetSystemMetrics(SM_CXSMICON)+4;
+ rc.top = y-2; rc.bottom = rc.top + GetSystemMetrics(SM_CYSMICON)+4;
+ DrawEdge(dis->hDC,&rc,BDR_SUNKENOUTER,BF_RECT);
+ InflateRect(&rc,-1,-1);
+ COLORREF menuCol = GetSysColor(COLOR_MENU);
+ COLORREF hiliteCol = GetSysColor(COLOR_3DHIGHLIGHT);
+ HBRUSH hBrush = CreateSolidBrush(RGB((GetRValue(menuCol)+GetRValue(hiliteCol))/2,(GetGValue(menuCol)+GetGValue(hiliteCol))/2,(GetBValue(menuCol)+GetBValue(hiliteCol))/2));
+ FillRect(dis->hDC,&rc,GetSysColorBrush(COLOR_MENU));
+ DeleteObject(hBrush);
+ ImageList_DrawEx(pimi->parent->m_hMenuIcons,pimi->iconId,dis->hDC,2,y,0,0,CLR_NONE,GetSysColor(COLOR_MENU),ILD_BLEND50);
+ }
+ else ImageList_DrawEx(pimi->parent->m_hMenuIcons,pimi->iconId,dis->hDC,2,y,0,0,CLR_NONE,CLR_NONE,ILD_NORMAL);
+ }
+ LeaveCriticalSection( &csMenuHook );
+ return TRUE;
+}
+
+int MO_RemoveAllObjects()
+{
+ int i;
+ for ( i=0; i < g_menus.getCount(); i++ )
+ delete g_menus[i];
+
+ g_menus.destroy();
+ return 0;
+}
+
+//wparam=MenuObjectHandle
+INT_PTR MO_RemoveMenuObject(WPARAM wParam, LPARAM)
+{
+ int objidx;
+
+ if ( !bIsGenMenuInited) return -1;
+ EnterCriticalSection( &csMenuHook );
+
+ objidx = GetMenuObjbyId(( int )wParam );
+ if ( objidx == -1 ) {
+ LeaveCriticalSection( &csMenuHook );
+ return -1;
+ }
+
+ delete g_menus[ objidx ];
+ g_menus.remove( objidx );
+ LeaveCriticalSection( &csMenuHook );
+ return 0;
+}
+
+//wparam=MenuObjectHandle
+//lparam=vKey
+INT_PTR MO_ProcessHotKeys( HANDLE menuHandle, INT_PTR vKey )
+{
+ if ( !bIsGenMenuInited)
+ return -1;
+
+ EnterCriticalSection( &csMenuHook );
+
+ int objidx = GetMenuObjbyId( (int)menuHandle );
+ if ( objidx == -1 ) {
+ LeaveCriticalSection( &csMenuHook );
+ return FALSE;
+ }
+
+ for ( PMO_IntMenuItem pimi = g_menus[objidx]->m_items.first; pimi != NULL; pimi = pimi->next ) {
+ if ( pimi->mi.hotKey == 0 ) continue;
+ if ( HIWORD(pimi->mi.hotKey) != vKey) continue;
+ if ( !(LOWORD(pimi->mi.hotKey) & MOD_ALT ) != !( GetKeyState( VK_MENU ) & 0x8000)) continue;
+ if ( !(LOWORD(pimi->mi.hotKey) & MOD_CONTROL ) != !( GetKeyState( VK_CONTROL ) & 0x8000)) continue;
+ if ( !(LOWORD(pimi->mi.hotKey) & MOD_SHIFT ) != !( GetKeyState( VK_SHIFT ) & 0x8000)) continue;
+
+ MO_ProcessCommand( pimi, 0 );
+ LeaveCriticalSection( &csMenuHook );
+ return TRUE;
+ }
+
+ LeaveCriticalSection( &csMenuHook );
+ return FALSE;
+}
+
+INT_PTR MO_GetProtoRootMenu(WPARAM wParam,LPARAM lParam)
+{
+ char* szProto = ( char* )wParam;
+ if ( szProto == NULL )
+ return 0;
+
+ if ( DBGetContactSettingByte( NULL, "CList", "MoveProtoMenus", FALSE ))
+ return ( INT_PTR )cli.pfnGetProtocolMenu( szProto );
+
+ int objidx = GetMenuObjbyId(( int )hMainMenuObject );
+ if ( objidx == -1 )
+ return NULL;
+
+ EnterCriticalSection( &csMenuHook );
+
+ TIntMenuObject* pmo = g_menus[objidx];
+ PMO_IntMenuItem p;
+ for ( p = pmo->m_items.first; p != NULL; p = p->next )
+ if ( !lstrcmpA( p->UniqName, szProto ))
+ break;
+
+ LeaveCriticalSection( &csMenuHook );
+ return ( INT_PTR )p;
+}
+
+//wparam=MenuItemHandle
+//lparam=PMO_MenuItem
+INT_PTR MO_GetMenuItem(WPARAM wParam,LPARAM lParam)
+{
+ PMO_MenuItem mi = (PMO_MenuItem)lParam;
+ if ( !bIsGenMenuInited || mi == NULL )
+ return -1;
+
+ PMO_IntMenuItem pimi = MO_GetIntMenuItem(( HGENMENU )wParam);
+ EnterCriticalSection( &csMenuHook );
+ if ( !pimi ) {
+ LeaveCriticalSection( &csMenuHook );
+ return -1;
+ }
+
+ *mi = pimi->mi;
+ LeaveCriticalSection( &csMenuHook );
+ return 0;
+}
+
+static int FindDefaultItem( PMO_IntMenuItem pimi, void* )
+{
+ if ( pimi->mi.flags & ( CMIF_GRAYED | CMIF_HIDDEN ))
+ return FALSE;
+
+ return ( pimi->mi.flags & CMIF_DEFAULT ) ? TRUE : FALSE;
+}
+
+INT_PTR MO_GetDefaultMenuItem(WPARAM wParam, LPARAM)
+{
+ if ( !bIsGenMenuInited )
+ return -1;
+
+ PMO_IntMenuItem pimi = MO_GetIntMenuItem(( HGENMENU )wParam);
+ EnterCriticalSection( &csMenuHook );
+ if ( pimi )
+ pimi = MO_RecursiveWalkMenu( pimi, FindDefaultItem, NULL );
+
+ LeaveCriticalSection( &csMenuHook );
+ return ( INT_PTR )pimi;
+}
+
+//wparam MenuItemHandle
+//lparam PMO_MenuItem
+int MO_ModifyMenuItem( PMO_IntMenuItem menuHandle, PMO_MenuItem pmi )
+{
+ int oldflags;
+
+ if ( !bIsGenMenuInited || pmi == NULL || pmi->cbSize != sizeof( TMO_MenuItem ))
+ return -1;
+
+ EnterCriticalSection( &csMenuHook );
+
+ PMO_IntMenuItem pimi = MO_GetIntMenuItem(( HGENMENU )menuHandle );
+ if ( !pimi ) {
+ LeaveCriticalSection( &csMenuHook );
+ return -1;
+ }
+
+ if ( pmi->flags & CMIM_NAME ) {
+ FreeAndNil(( void** )&pimi->mi.pszName );
+#if defined( _UNICODE )
+ if ( pmi->flags & CMIF_UNICODE )
+ pimi->mi.ptszName = mir_tstrdup(( pmi->flags & CMIF_KEEPUNTRANSLATED ) ? pmi->ptszName : TranslateTS( pmi->ptszName ));
+ else {
+ if ( pmi->flags & CMIF_KEEPUNTRANSLATED ) {
+ int len = lstrlenA( pmi->pszName );
+ pimi->mi.ptszName = ( TCHAR* )mir_alloc( sizeof( TCHAR )*( len+1 ));
+ MultiByteToWideChar( CP_ACP, 0, pmi->pszName, -1, pimi->mi.ptszName, len+1 );
+ pimi->mi.ptszName[ len ] = 0;
+ }
+ else pimi->mi.ptszName = LangPackPcharToTchar( pmi->pszName );
+ }
+#else
+ pimi->mi.ptszName = mir_strdup(( pmi->flags & CMIF_KEEPUNTRANSLATED ) ? pmi->ptszName : Translate( pmi->ptszName ));
+#endif
+ }
+ if ( pmi->flags & CMIM_FLAGS ) {
+ oldflags = pimi->mi.flags & ( CMIF_ROOTHANDLE | CMIF_ICONFROMICOLIB );
+ pimi->mi.flags = (pmi->flags & ~CMIM_ALL) | oldflags;
+ }
+ if ( (pmi->flags & CMIM_ICON) && !bIconsDisabled ) {
+ if ( pimi->mi.flags & CMIF_ICONFROMICOLIB ) {
+ HICON hIcon = IcoLib_GetIconByHandle( pmi->hIcolibItem, false );
+ if ( hIcon != NULL ) {
+ pimi->hIcolibItem = pmi->hIcolibItem;
+ pimi->iconId = ImageList_ReplaceIcon( pimi->parent->m_hMenuIcons, pimi->iconId, hIcon );
+ IconLib_ReleaseIcon( hIcon, 0 );
+ }
+ else pimi->iconId = -1, pimi->hIcolibItem = NULL;
+ }
+ else {
+ pimi->mi.hIcon = pmi->hIcon;
+ if ( pmi->hIcon != NULL )
+ pimi->iconId = ImageList_ReplaceIcon( pimi->parent->m_hMenuIcons, pimi->iconId, pmi->hIcon );
+ else
+ pimi->iconId = -1; //fixme, should remove old icon & shuffle all iconIds
+ }
+ if (pimi->hBmp) DeleteObject(pimi->hBmp); pimi->hBmp = NULL;
+ }
+
+ if ( pmi->flags & CMIM_HOTKEY )
+ pimi->mi.hotKey = pmi->hotKey;
+
+ LeaveCriticalSection( &csMenuHook );
+ return 0;
+}
+
+//wparam MenuItemHandle
+//return ownerdata useful to free ownerdata before delete menu item,
+//NULL on error.
+INT_PTR MO_MenuItemGetOwnerData(WPARAM wParam, LPARAM)
+{
+ if ( !bIsGenMenuInited )
+ return -1;
+
+ EnterCriticalSection( &csMenuHook );
+ PMO_IntMenuItem pimi = MO_GetIntMenuItem(( HGENMENU )wParam );
+ if ( !pimi ) {
+ LeaveCriticalSection( &csMenuHook );
+ return -1;
+ }
+
+ INT_PTR res = ( INT_PTR )pimi->mi.ownerdata;
+ LeaveCriticalSection( &csMenuHook );
+ return res;
+}
+
+PMO_IntMenuItem MO_GetIntMenuItem(HGENMENU wParam)
+{
+ PMO_IntMenuItem result = ( PMO_IntMenuItem )wParam;
+ if ( result == NULL || wParam == (HGENMENU)0xffff1234 || wParam == HGENMENU_ROOT)
+ return NULL;
+
+ __try
+ {
+ if ( result->signature != MENUITEM_SIGNATURE )
+ result = NULL;
+ }
+ __except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ result = NULL;
+ }
+
+ return result;
+}
+
+//LOWORD(wparam) menuident
+
+static int FindMenuByCommand( PMO_IntMenuItem pimi, void* pCommand )
+{
+ return ( pimi->iCommand == (int)pCommand );
+}
+
+int MO_ProcessCommandBySubMenuIdent(int menuID, int command, LPARAM lParam)
+{
+ if ( !bIsGenMenuInited )
+ return -1;
+
+ EnterCriticalSection( &csMenuHook );
+
+ int objidx = GetMenuObjbyId( menuID );
+ if ( objidx == -1 ) {
+ LeaveCriticalSection( &csMenuHook );
+ return -1;
+ }
+
+ PMO_IntMenuItem pimi = MO_RecursiveWalkMenu( g_menus[objidx]->m_items.first, FindMenuByCommand, ( void* )command );
+ if ( pimi ) {
+ LeaveCriticalSection( &csMenuHook );
+ return MO_ProcessCommand( pimi, lParam );
+ }
+
+ LeaveCriticalSection( &csMenuHook );
+ return -1;
+}
+
+INT_PTR MO_ProcessCommandByMenuIdent(WPARAM wParam,LPARAM lParam)
+{
+ if ( !bIsGenMenuInited )
+ return -1;
+
+ EnterCriticalSection( &csMenuHook );
+
+ for ( int i=0; i < g_menus.getCount(); i++ ) {
+ PMO_IntMenuItem pimi = MO_RecursiveWalkMenu( g_menus[i]->m_items.first, FindMenuByCommand, ( void* )wParam );
+ if ( pimi ) {
+ LeaveCriticalSection( &csMenuHook );
+ return MO_ProcessCommand( pimi, lParam );
+ } }
+
+ LeaveCriticalSection( &csMenuHook );
+ return FALSE;
+}
+
+int MO_ProcessCommand( PMO_IntMenuItem aHandle, LPARAM lParam )
+{
+ if ( !bIsGenMenuInited )
+ return -1;
+
+ EnterCriticalSection( &csMenuHook );
+ PMO_IntMenuItem pimi = MO_GetIntMenuItem( aHandle );
+ if ( !pimi ) {
+ LeaveCriticalSection( &csMenuHook );
+ return -1;
+ }
+
+ char *srvname = pimi->parent->ExecService;
+ void *ownerdata = pimi->mi.ownerdata;
+ LeaveCriticalSection( &csMenuHook );
+ CallService( srvname, ( WPARAM )ownerdata, lParam );
+ return 1;
+}
+
+int MO_SetOptionsMenuItem( PMO_IntMenuItem aHandle, int setting, INT_PTR value )
+{
+ if ( !bIsGenMenuInited )
+ return -1;
+
+ EnterCriticalSection( &csMenuHook );
+ PMO_IntMenuItem pimi = MO_GetIntMenuItem( aHandle );
+ if ( !pimi ) {
+ LeaveCriticalSection( &csMenuHook );
+ return -1;
+ }
+
+ int res = -1;
+ __try
+ {
+ res = 1;
+ if ( setting == OPT_MENUITEMSETUNIQNAME ) {
+ mir_free( pimi->UniqName );
+ pimi->UniqName = mir_strdup(( char* )value );
+ }
+ }
+ __except( EXCEPTION_EXECUTE_HANDLER ) {}
+
+ LeaveCriticalSection( &csMenuHook );
+ return res;
+}
+
+int MO_SetOptionsMenuObject( HANDLE handle, int setting, INT_PTR value )
+{
+ int pimoidx;
+ int res = 0;
+
+ if ( !bIsGenMenuInited )
+ return -1;
+
+ EnterCriticalSection( &csMenuHook );
+ __try
+ {
+ pimoidx = GetMenuObjbyId( (int)handle );
+ res = pimoidx != -1;
+ if ( res ) {
+ TIntMenuObject* pmo = g_menus[pimoidx];
+
+ switch ( setting ) {
+ case OPT_MENUOBJECT_SET_ONADD_SERVICE:
+ FreeAndNil(( void** )&pmo->onAddService );
+ pmo->onAddService = mir_strdup(( char* )value );
+ break;
+
+ case OPT_MENUOBJECT_SET_FREE_SERVICE:
+ FreeAndNil(( void** )&pmo->FreeService );
+ pmo->FreeService = mir_strdup(( char* )value );
+ break;
+
+ case OPT_MENUOBJECT_SET_CHECK_SERVICE:
+ FreeAndNil(( void** )&pmo->CheckService );
+ pmo->CheckService = mir_strdup(( char* )value);
+ break;
+
+ case OPT_USERDEFINEDITEMS:
+ pmo->m_bUseUserDefinedItems = ( BOOL )value;
+ break;
+ }
+ }
+ }
+ __except( EXCEPTION_EXECUTE_HANDLER ) {}
+
+ LeaveCriticalSection( &csMenuHook );
+ return res;
+}
+
+//wparam=0;
+//lparam=PMenuParam;
+//result=MenuObjectHandle
+INT_PTR MO_CreateNewMenuObject(WPARAM, LPARAM lParam)
+{
+ PMenuParam pmp = ( PMenuParam )lParam;
+ if ( !bIsGenMenuInited || pmp == NULL )
+ return -1;
+
+ EnterCriticalSection( &csMenuHook );
+ TIntMenuObject* p = new TIntMenuObject();
+ p->id = NextObjectId++;
+ p->Name = mir_strdup( pmp->name );
+ p->CheckService = mir_strdup( pmp->CheckService );
+ p->ExecService = mir_strdup( pmp->ExecService );
+ p->m_hMenuIcons = ImageList_Create( GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
+ (IsWinVerXPPlus() ? ILC_COLOR32 : ILC_COLOR16) | ILC_MASK, 15, 100 );
+ g_menus.insert(p);
+
+ LeaveCriticalSection( &csMenuHook );
+ return p->id;
+}
+
+//wparam=MenuItemHandle
+//lparam=0
+
+static int FreeMenuItem( TMO_IntMenuItem* pimi, void* )
+{
+ pimi->parent->freeItem( pimi );
+ return FALSE;
+}
+
+static int FindParent( TMO_IntMenuItem* pimi, void* p )
+{
+ return pimi->next == p;
+}
+
+INT_PTR MO_RemoveMenuItem(WPARAM wParam, LPARAM)
+{
+ EnterCriticalSection( &csMenuHook );
+ PMO_IntMenuItem pimi = MO_GetIntMenuItem(( HGENMENU )wParam );
+ if ( !pimi ) {
+ LeaveCriticalSection( &csMenuHook );
+ return -1;
+ }
+
+ if ( pimi->submenu.first ) {
+ MO_RecursiveWalkMenu( pimi->submenu.first, FreeMenuItem, NULL );
+ pimi->submenu.first = NULL;
+ }
+
+ PMO_IntMenuItem prev = MO_RecursiveWalkMenu( pimi->owner->first, FindParent, pimi );
+ if ( prev )
+ prev->next = pimi->next;
+ if ( pimi->owner->first == pimi )
+ pimi->owner->first = pimi->next;
+ if ( pimi->owner->last == pimi )
+ pimi->owner->last = prev;
+
+ pimi->signature = 0; // invalidate all future calls to that object
+ pimi->parent->freeItem( pimi );
+
+ LeaveCriticalSection( &csMenuHook );
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// we presume that this function is being called inside csMenuHook only
+
+static int PackMenuItems( PMO_IntMenuItem pimi, void* )
+{
+ pimi->iCommand = NextObjectMenuItemId++;
+ return FALSE;
+}
+
+static int GetNextObjectMenuItemId()
+{
+ // if menu commands are exausted, pack the menu array
+ if ( NextObjectMenuItemId >= CLISTMENUIDMAX ) {
+ NextObjectMenuItemId = CLISTMENUIDMIN;
+ for ( int i=0; i < g_menus.getCount(); i++ )
+ MO_RecursiveWalkMenu( g_menus[i]->m_items.first, PackMenuItems, NULL );
+ }
+
+ return NextObjectMenuItemId++;
+}
+
+//wparam=MenuObjectHandle
+//lparam=PMO_MenuItem
+//return MenuItemHandle
+PMO_IntMenuItem MO_AddNewMenuItem( HANDLE menuobjecthandle, PMO_MenuItem pmi )
+{
+ if ( !bIsGenMenuInited || pmi == NULL || pmi->cbSize != sizeof( TMO_MenuItem ))
+ return NULL;
+
+ //old mode
+ if ( !( pmi->flags & CMIF_ROOTHANDLE ))
+ return MO_AddOldNewMenuItem( menuobjecthandle, pmi );
+
+ EnterCriticalSection( &csMenuHook );
+ int objidx = GetMenuObjbyId( (int)menuobjecthandle );
+ if ( objidx == -1 ) {
+ LeaveCriticalSection( &csMenuHook );
+ return NULL;
+ }
+
+ TIntMenuObject* pmo = g_menus[objidx];
+
+ TMO_IntMenuItem* p = ( TMO_IntMenuItem* )mir_calloc( sizeof( TMO_IntMenuItem ));
+ p->parent = pmo;
+ p->signature = MENUITEM_SIGNATURE;
+ p->iCommand = GetNextObjectMenuItemId();
+ p->mi = *pmi;
+ p->iconId = -1;
+ p->OverrideShow = TRUE;
+ p->originalPosition = pmi->position;
+ #if defined( _UNICODE )
+ if ( pmi->flags & CMIF_UNICODE )
+ p->mi.ptszName = mir_tstrdup(( pmi->flags & CMIF_KEEPUNTRANSLATED ) ? pmi->ptszName : TranslateTS( pmi->ptszName ));
+ else {
+ if ( pmi->flags & CMIF_KEEPUNTRANSLATED )
+ p->mi.ptszName = mir_a2u(pmi->pszName);
+ else
+ p->mi.ptszName = LangPackPcharToTchar( pmi->pszName );
+ }
+ #else
+ p->mi.ptszName = mir_strdup(( pmi->flags & CMIF_KEEPUNTRANSLATED ) ? pmi->ptszName : Translate( pmi->ptszName ));
+ #endif
+
+ if ( pmi->hIcon != NULL && !bIconsDisabled ) {
+ if ( pmi->flags & CMIF_ICONFROMICOLIB ) {
+ HICON hIcon = IcoLib_GetIconByHandle( pmi->hIcolibItem, false );
+ p->iconId = ImageList_AddIcon( pmo->m_hMenuIcons, hIcon );
+ p->hIcolibItem = pmi->hIcolibItem;
+ IconLib_ReleaseIcon( hIcon, 0 );
+ }
+ else {
+ HANDLE hIcolibItem = IcoLib_IsManaged( pmi->hIcon );
+ if ( hIcolibItem ) {
+ p->iconId = ImageList_AddIcon( pmo->m_hMenuIcons, pmi->hIcon );
+ p->hIcolibItem = hIcolibItem;
+ }
+ else p->iconId = ImageList_AddIcon( pmo->m_hMenuIcons, pmi->hIcon );
+ } }
+
+ if ( p->mi.root == HGENMENU_ROOT )
+ p->mi.root = NULL;
+
+ PMO_IntMenuItem pRoot = ( p->mi.root != NULL ) ? MO_GetIntMenuItem( p->mi.root ) : NULL;
+ if ( pRoot )
+ p->owner = &pRoot->submenu;
+ else
+ p->owner = &pmo->m_items;
+
+ if ( !p->owner->first )
+ p->owner->first = p;
+ if ( p->owner->last )
+ p->owner->last->next = p;
+ p->owner->last = p;
+
+ LeaveCriticalSection( &csMenuHook );
+ return p;
+}
+
+//wparam=MenuObjectHandle
+//lparam=PMO_MenuItem
+
+int FindRoot( PMO_IntMenuItem pimi, void* param )
+{
+ if ( pimi->mi.pszName != NULL )
+ if ( pimi->submenu.first && !_tcscmp( pimi->mi.ptszName, ( TCHAR* )param ))
+ return TRUE;
+
+ return FALSE;
+}
+
+PMO_IntMenuItem MO_AddOldNewMenuItem( HANDLE menuobjecthandle, PMO_MenuItem pmi )
+{
+ if ( !bIsGenMenuInited || pmi == NULL )
+ return NULL;
+
+ int objidx = GetMenuObjbyId( (int)menuobjecthandle );
+ if ( objidx == -1 )
+ return NULL;
+
+ if ( pmi->cbSize != sizeof( TMO_MenuItem ))
+ return NULL;
+
+ if ( pmi->flags & CMIF_ROOTHANDLE )
+ return NULL;
+
+ //is item with popup or not
+ if ( pmi->root == 0 ) {
+ //yes,this without popup
+ pmi->root = NULL; //first level
+ }
+ else { // no,search for needed root and create it if need
+ TCHAR* tszRoot;
+#if defined( _UNICODE )
+ if ( pmi->flags & CMIF_UNICODE )
+ tszRoot = mir_tstrdup(TranslateTS(( TCHAR* )pmi->root ));
+ else
+ tszRoot = LangPackPcharToTchar(( char* )pmi->root );
+#else
+ tszRoot = mir_tstrdup(TranslateTS(( TCHAR* )pmi->root ));
+#endif
+
+ PMO_IntMenuItem oldroot = MO_RecursiveWalkMenu( g_menus[objidx]->m_items.first, FindRoot, tszRoot );
+ mir_free( tszRoot );
+
+ if ( oldroot == NULL ) {
+ //not found,creating root
+ TMO_MenuItem tmi = { 0 };
+ tmi = *pmi;
+ tmi.flags |= CMIF_ROOTHANDLE;
+ tmi.ownerdata = 0;
+ tmi.root = NULL;
+ //copy pszPopupName
+ tmi.ptszName = ( TCHAR* )pmi->root;
+ if (( oldroot = MO_AddNewMenuItem( menuobjecthandle, &tmi )) != NULL )
+ MO_SetOptionsMenuItem( oldroot, OPT_MENUITEMSETUNIQNAME, (INT_PTR)pmi->root );
+ }
+ pmi->root = oldroot;
+
+ //popup will be created in next commands
+ }
+ pmi->flags |= CMIF_ROOTHANDLE;
+ //add popup(root allready exists)
+ return MO_AddNewMenuItem( menuobjecthandle, pmi );
+}
+
+static int WhereToPlace( HMENU hMenu, PMO_MenuItem mi )
+{
+ MENUITEMINFO mii = { 0 };
+ mii.cbSize = MENUITEMINFO_V4_SIZE;
+ mii.fMask = MIIM_SUBMENU | MIIM_DATA;
+ for ( int i=GetMenuItemCount( hMenu )-1; i >= 0; i-- ) {
+ GetMenuItemInfo( hMenu, i, TRUE, &mii );
+ if ( mii.fType != MFT_SEPARATOR ) {
+ PMO_IntMenuItem pimi = MO_GetIntMenuItem(( HGENMENU )mii.dwItemData);
+ if ( pimi != NULL )
+ if ( pimi->mi.position <= mi->position )
+ return i+1;
+ } }
+
+ return 0;
+}
+
+static void InsertMenuItemWithSeparators(HMENU hMenu, int uItem, MENUITEMINFO *lpmii)
+{
+ int needSeparator = 0;
+ MENUITEMINFO mii;
+
+ PMO_IntMenuItem pimi = MO_GetIntMenuItem(( HGENMENU )lpmii->dwItemData );
+ if ( pimi == NULL )
+ return;
+
+ int thisItemPosition = pimi->mi.position;
+
+ ZeroMemory( &mii, sizeof( mii ));
+ mii.cbSize = MENUITEMINFO_V4_SIZE;
+ //check for separator before
+ if ( uItem ) {
+ mii.fMask = MIIM_SUBMENU | MIIM_DATA | MIIM_TYPE;
+ GetMenuItemInfo( hMenu, uItem-1, TRUE, &mii );
+ pimi = MO_GetIntMenuItem(( HGENMENU )mii.dwItemData );
+ if ( pimi != NULL ) {
+ if ( mii.fType == MFT_SEPARATOR )
+ needSeparator = 0;
+ else
+ needSeparator = ( pimi->mi.position / SEPARATORPOSITIONINTERVAL ) != thisItemPosition / SEPARATORPOSITIONINTERVAL;
+ }
+ if ( needSeparator) {
+ //but might be supposed to be after the next one instead
+ mii.fType = 0;
+ if ( uItem < GetMenuItemCount( hMenu )) {
+ mii.fMask = MIIM_SUBMENU | MIIM_DATA | MIIM_TYPE;
+ GetMenuItemInfo( hMenu, uItem, TRUE, &mii );
+ }
+ if ( mii.fType != MFT_SEPARATOR) {
+ mii.fMask = MIIM_TYPE;
+ mii.fType = MFT_SEPARATOR;
+ InsertMenuItem( hMenu, uItem, TRUE, &mii );
+ }
+ uItem++;
+ } }
+
+ //check for separator after
+ if ( uItem < GetMenuItemCount( hMenu )) {
+ mii.fMask = MIIM_SUBMENU | MIIM_DATA | MIIM_TYPE;
+ mii.cch = 0;
+ GetMenuItemInfo( hMenu, uItem, TRUE, &mii );
+ pimi = MO_GetIntMenuItem(( HGENMENU )mii.dwItemData );
+ if ( pimi != NULL ) {
+ if ( mii.fType == MFT_SEPARATOR )
+ needSeparator=0;
+ else
+ needSeparator = pimi->mi.position / SEPARATORPOSITIONINTERVAL != thisItemPosition / SEPARATORPOSITIONINTERVAL;
+ }
+ if ( needSeparator) {
+ mii.fMask = MIIM_TYPE;
+ mii.fType = MFT_SEPARATOR;
+ InsertMenuItem( hMenu, uItem, TRUE, &mii );
+ } }
+
+ if ( uItem == GetMenuItemCount( hMenu )-1 ) {
+ TCHAR str[32];
+ mii.fMask = MIIM_SUBMENU | MIIM_DATA | MIIM_TYPE;
+ mii.dwTypeData = str;
+ mii.cch = SIZEOF( str );
+ GetMenuItemInfo( hMenu, uItem, TRUE, &mii );
+ }
+
+ // create local copy *lpmii so we can change some flags
+ MENUITEMINFO mii_copy = *lpmii;
+ lpmii = &mii_copy;
+
+ if (( GetMenuItemCount( hMenu ) % 35 ) == 33 /* will be 34 after addition :) */ && pimi != NULL )
+ if ( pimi->mi.root != NULL ) {
+ if ( !( lpmii->fMask & MIIM_FTYPE ))
+ lpmii->fType = 0;
+ lpmii->fMask |= MIIM_FTYPE;
+ lpmii->fType |= MFT_MENUBARBREAK;
+ }
+
+ InsertMenuItem( hMenu, uItem, TRUE, lpmii );
+}
+
+//wparam started hMenu
+//lparam ListParam*
+//result hMenu
+INT_PTR MO_BuildMenu(WPARAM wParam,LPARAM lParam)
+{
+ if ( !bIsGenMenuInited )
+ return -1;
+
+ EnterCriticalSection( &csMenuHook );
+
+ ListParam *lp = ( ListParam* )lParam;
+ int pimoidx = GetMenuObjbyId( (int)lp->MenuObjectHandle );
+ if ( pimoidx == -1 ) {
+ LeaveCriticalSection( &csMenuHook );
+ return 0;
+ }
+
+ #if defined( _DEBUG )
+ // DumpMenuItem( g_menus[pimoidx]->m_items.first );
+ #endif
+
+ INT_PTR res = (INT_PTR)BuildRecursiveMenu(( HMENU )wParam, g_menus[pimoidx]->m_items.first, ( ListParam* )lParam );
+ LeaveCriticalSection( &csMenuHook );
+ return res;
+}
+
+#ifdef _DEBUG
+#define PUTPOSITIONSONMENU
+#endif
+
+void GetMenuItemName( PMO_IntMenuItem pMenuItem, char* pszDest, size_t cbDestSize )
+{
+ if ( pMenuItem->UniqName )
+ mir_snprintf( pszDest, cbDestSize, "{%s}", pMenuItem->UniqName );
+ else if (pMenuItem->mi.flags & CMIF_UNICODE) {
+ char* name = mir_t2a( pMenuItem->mi.ptszName );
+ mir_snprintf( pszDest, cbDestSize, "{%s}", name );
+ mir_free(name);
+ }
+ else
+ mir_snprintf( pszDest, cbDestSize, "{%s}", pMenuItem->mi.pszName );
+}
+
+HMENU BuildRecursiveMenu(HMENU hMenu, PMO_IntMenuItem pRootMenu, ListParam *param)
+{
+ if ( param == NULL || pRootMenu == NULL )
+ return NULL;
+
+ TIntMenuObject* pmo = pRootMenu->parent;
+
+ int rootlevel = ( param->rootlevel == -1 ) ? 0 : param->rootlevel;
+
+ ListParam localparam = *param;
+
+ while ( rootlevel == 0 && GetMenuItemCount( hMenu ) > 0 )
+ DeleteMenu( hMenu, 0, MF_BYPOSITION );
+
+ for ( PMO_IntMenuItem pmi = pRootMenu; pmi != NULL; pmi = pmi->next ) {
+ PMO_MenuItem mi = &pmi->mi;
+ if ( mi->cbSize != sizeof( TMO_MenuItem ))
+ continue;
+
+ if ( mi->flags & CMIF_HIDDEN )
+ continue;
+
+ if ( pmo->CheckService != NULL ) {
+ TCheckProcParam CheckParam;
+ CheckParam.lParam = param->lParam;
+ CheckParam.wParam = param->wParam;
+ CheckParam.MenuItemOwnerData = mi->ownerdata;
+ CheckParam.MenuItemHandle = pmi;
+ if ( CallService( pmo->CheckService, ( WPARAM )&CheckParam, 0 ) == FALSE )
+ continue;
+ }
+
+ /**************************************/
+ if ( rootlevel == 0 && mi->root == NULL && pmo->m_bUseUserDefinedItems ) {
+ char DBString[256];
+ DBVARIANT dbv = { 0 };
+ int pos;
+ char MenuNameItems[256];
+ mir_snprintf(MenuNameItems, SIZEOF(MenuNameItems), "%s_Items", pmo->Name);
+
+ char menuItemName[256];
+ GetMenuItemName( pmi, menuItemName, sizeof( menuItemName ));
+
+ // check if it visible
+ mir_snprintf( DBString, SIZEOF(DBString), "%s_visible", menuItemName );
+ if ( DBGetContactSettingByte( NULL, MenuNameItems, DBString, -1 ) == -1 )
+ DBWriteContactSettingByte( NULL, MenuNameItems, DBString, 1 );
+
+ pmi->OverrideShow = TRUE;
+ if ( !DBGetContactSettingByte( NULL, MenuNameItems, DBString, 1 )) {
+ pmi->OverrideShow = FALSE;
+ continue; // find out what value to return if not getting added
+ }
+
+ // mi.pszName
+ mir_snprintf( DBString, SIZEOF(DBString), "%s_name", menuItemName );
+ if ( !DBGetContactSettingTString( NULL, MenuNameItems, DBString, &dbv )) {
+ if ( _tcslen( dbv.ptszVal ) > 0 ) {
+ if ( pmi->CustomName ) mir_free( pmi->CustomName );
+ pmi->CustomName = mir_tstrdup( dbv.ptszVal );
+ }
+ DBFreeVariant( &dbv );
+ }
+
+ mir_snprintf( DBString, SIZEOF(DBString), "%s_pos", menuItemName );
+ if (( pos = DBGetContactSettingDword( NULL, MenuNameItems, DBString, -1 )) == -1 ) {
+ DBWriteContactSettingDword( NULL, MenuNameItems, DBString, mi->position );
+ if ( pmi->submenu.first )
+ mi->position = 0;
+ }
+ else mi->position = pos;
+ }
+
+ /**************************************/
+
+ if ( rootlevel != (int)pmi->mi.root )
+ continue;
+
+ MENUITEMINFO mii = { 0 };
+ mii.dwItemData = ( LPARAM )pmi;
+
+ int i = WhereToPlace( hMenu, mi );
+
+ if ( !IsWinVer98Plus()) {
+ mii.cbSize = MENUITEMINFO_V4_SIZE;
+ mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_ID;
+ mii.fType = MFT_STRING;
+ }
+ else {
+ mii.cbSize = sizeof( mii );
+ mii.fMask = MIIM_DATA | MIIM_ID | MIIM_STRING;
+ if ( pmi->iconId != -1 ) {
+ mii.fMask |= MIIM_BITMAP;
+ if (IsWinVerVistaPlus() && isThemeActive()) {
+ if (pmi->hBmp == NULL)
+ pmi->hBmp = ConvertIconToBitmap(NULL, pmi->parent->m_hMenuIcons, pmi->iconId);
+ mii.hbmpItem = pmi->hBmp;
+ }
+ else
+ mii.hbmpItem = HBMMENU_CALLBACK;
+ }
+ }
+
+ mii.fMask |= MIIM_STATE;
+ mii.fState = (( pmi->mi.flags & CMIF_GRAYED ) ? MFS_GRAYED : MFS_ENABLED );
+ mii.fState |= (( pmi->mi.flags & CMIF_CHECKED) ? MFS_CHECKED : MFS_UNCHECKED );
+ if ( pmi->mi.flags & CMIF_DEFAULT ) mii.fState |= MFS_DEFAULT;
+
+ mii.dwTypeData = ( pmi->CustomName ) ? pmi->CustomName : mi->ptszName;
+
+ // it's a submenu
+ if ( pmi->submenu.first ) {
+ mii.fMask |= MIIM_SUBMENU;
+ mii.hSubMenu = CreatePopupMenu();
+
+ #ifdef PUTPOSITIONSONMENU
+ if ( GetKeyState(VK_CONTROL) & 0x8000) {
+ TCHAR str[256];
+ mir_sntprintf( str, SIZEOF(str), _T( "%s (%d,id %x)" ), mi->pszName, mi->position, mii.dwItemData );
+ mii.dwTypeData = str;
+ }
+ #endif
+
+ InsertMenuItemWithSeparators( hMenu, i, &mii);
+ localparam.rootlevel = LPARAM( pmi );
+ BuildRecursiveMenu( mii.hSubMenu, pmi->submenu.first, &localparam );
+ }
+ else {
+ mii.wID = pmi->iCommand;
+
+ #ifdef PUTPOSITIONSONMENU
+ if ( GetKeyState(VK_CONTROL) & 0x8000) {
+ TCHAR str[256];
+ mir_sntprintf( str, SIZEOF(str), _T("%s (%d,id %x)"), mi->pszName, mi->position, mii.dwItemData );
+ mii.dwTypeData = str;
+ }
+ #endif
+
+ if ( pmo->onAddService != NULL )
+ if ( CallService( pmo->onAddService, ( WPARAM )&mii, ( LPARAM )pmi ) == FALSE )
+ continue;
+
+ InsertMenuItemWithSeparators( hMenu, i, &mii );
+ } }
+
+ return hMenu;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// iconlib in menu
+
+static int MO_ReloadIcon( PMO_IntMenuItem pmi, void* )
+{
+ if ( pmi->hIcolibItem ) {
+ HICON newIcon = IcoLib_GetIconByHandle( pmi->hIcolibItem, false );
+ if ( newIcon )
+ ImageList_ReplaceIcon( pmi->parent->m_hMenuIcons, pmi->iconId, newIcon );
+
+ IconLib_ReleaseIcon(newIcon,0);
+ }
+
+ return FALSE;
+}
+
+int OnIconLibChanges(WPARAM, LPARAM)
+{
+ EnterCriticalSection( &csMenuHook );
+ for ( int mo=0; mo < g_menus.getCount(); mo++ )
+ if ( (int)hStatusMenuObject != g_menus[mo]->id ) //skip status menu
+ MO_RecursiveWalkMenu( g_menus[mo]->m_items.first, MO_ReloadIcon, 0 );
+
+ LeaveCriticalSection( &csMenuHook );
+
+ cli.pfnReloadProtoMenus();
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+//
+
+static int MO_RegisterIcon( PMO_IntMenuItem pmi, void* )
+{
+ char *uname, *descr;
+ uname = pmi->UniqName;
+ if ( uname == NULL )
+ #ifdef UNICODE
+ uname = mir_u2a(pmi->CustomName);
+ descr = mir_u2a(pmi->mi.ptszName);
+ #else
+ uname = pmi->CustomName;
+ descr = pmi->mi.pszName;
+ #endif
+
+ if ( !uname && !descr )
+ return FALSE;
+
+ if ( !pmi->hIcolibItem ) {
+ HICON hIcon = ImageList_GetIcon( pmi->parent->m_hMenuIcons, pmi->iconId, 0 );
+ char* buf = NEWSTR_ALLOCA( descr );
+
+ char sectionName[256], iconame[256];
+ mir_snprintf( sectionName, sizeof(sectionName), "Menu Icons/%s", pmi->parent->Name );
+
+ // remove '&'
+ char* start = buf;
+ while ( start ) {
+ if (( start = strchr( start, '&' )) == NULL )
+ break;
+
+ memmove(start,start+1,strlen(start+1)+1);
+ if (*start!='\0') start++;
+ else break;
+ }
+
+ mir_snprintf(iconame, sizeof(iconame), "genmenu_%s_%s", pmi->parent->Name, uname && *uname ? uname : descr);
+
+ SKINICONDESC sid={0};
+ sid.cbSize = sizeof(sid);
+ sid.cx = 16;
+ sid.cy = 16;
+ sid.pszSection = sectionName;
+ sid.pszName = iconame;
+ sid.pszDefaultFile = NULL;
+ sid.pszDescription = buf;
+ sid.hDefaultIcon = hIcon;
+ pmi->hIcolibItem = ( HANDLE )CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid);
+
+ Safe_DestroyIcon( hIcon );
+ if ( hIcon = ( HICON )CallService( MS_SKIN2_GETICON, 0, (LPARAM)iconame )) {
+ ImageList_ReplaceIcon( pmi->parent->m_hMenuIcons, pmi->iconId, hIcon );
+ IconLib_ReleaseIcon( hIcon, 0 );
+ } }
+
+ #ifdef UNICODE
+ if ( !pmi->UniqName )
+ mir_free( uname );
+ mir_free( descr );
+ #endif
+
+ return FALSE;
+}
+
+int RegisterAllIconsInIconLib()
+{
+ //register all icons
+ for ( int mo=0; mo < g_menus.getCount(); mo++ ) {
+ if ( (int)hStatusMenuObject == g_menus[mo]->id ) //skip status menu
+ continue;
+
+ MO_RecursiveWalkMenu( g_menus[mo]->m_items.first, MO_RegisterIcon, 0 );
+ }
+
+ return 0;
+}
+
+int TryProcessDoubleClick( HANDLE hContact )
+{
+ int iMenuID = GetMenuObjbyId( (int)hContactMenuObject );
+ if ( iMenuID != -1 ) {
+ NotifyEventHooks(hPreBuildContactMenuEvent,(WPARAM)hContact,0);
+
+ PMO_IntMenuItem pimi = ( PMO_IntMenuItem )MO_GetDefaultMenuItem(( WPARAM )g_menus[ iMenuID ]->m_items.first, 0 );
+ if ( pimi != NULL ) {
+ MO_ProcessCommand( pimi, ( LPARAM )hContact );
+ return 0;
+ } }
+
+ return 1;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Static services
+
+int posttimerid;
+
+static VOID CALLBACK PostRegisterIcons( HWND, UINT, UINT_PTR, DWORD )
+{
+ KillTimer( 0, posttimerid );
+ RegisterAllIconsInIconLib();
+}
+
+static int OnModulesLoaded(WPARAM, LPARAM)
+{
+ posttimerid = SetTimer(( HWND )NULL, 0, 5, ( TIMERPROC )PostRegisterIcons );
+ HookEvent(ME_SKIN2_ICONSCHANGED,OnIconLibChanges);
+ return 0;
+}
+
+static INT_PTR SRVMO_SetOptionsMenuObject( WPARAM, LPARAM lParam)
+{
+ lpOptParam lpop = ( lpOptParam )lParam;
+ if ( lpop == NULL )
+ return 0;
+
+ return MO_SetOptionsMenuObject( lpop->Handle, lpop->Setting, lpop->Value );
+}
+
+static INT_PTR SRVMO_SetOptionsMenuItem( WPARAM, LPARAM lParam)
+{
+ lpOptParam lpop = ( lpOptParam )lParam;
+ if ( lpop == NULL )
+ return 0;
+
+ return MO_SetOptionsMenuItem(( PMO_IntMenuItem )lpop->Handle, lpop->Setting, lpop->Value );
+}
+
+int InitGenMenu()
+{
+ InitializeCriticalSection( &csMenuHook );
+ CreateServiceFunction( MO_BUILDMENU, MO_BuildMenu );
+
+ CreateServiceFunction( MO_PROCESSCOMMAND, ( MIRANDASERVICE )MO_ProcessCommand );
+ CreateServiceFunction( MO_CREATENEWMENUOBJECT, MO_CreateNewMenuObject );
+ CreateServiceFunction( MO_REMOVEMENUITEM, MO_RemoveMenuItem );
+ CreateServiceFunction( MO_ADDNEWMENUITEM, ( MIRANDASERVICE )MO_AddNewMenuItem );
+ CreateServiceFunction( MO_MENUITEMGETOWNERDATA, MO_MenuItemGetOwnerData );
+ CreateServiceFunction( MO_MODIFYMENUITEM, ( MIRANDASERVICE )MO_ModifyMenuItem );
+ CreateServiceFunction( MO_GETMENUITEM, MO_GetMenuItem );
+ CreateServiceFunction( MO_GETDEFAULTMENUITEM, MO_GetDefaultMenuItem );
+ CreateServiceFunction( MO_PROCESSCOMMANDBYMENUIDENT, MO_ProcessCommandByMenuIdent );
+ CreateServiceFunction( MO_PROCESSHOTKEYS, ( MIRANDASERVICE )MO_ProcessHotKeys );
+ CreateServiceFunction( MO_REMOVEMENUOBJECT, MO_RemoveMenuObject );
+ CreateServiceFunction( MO_GETPROTOROOTMENU, MO_GetProtoRootMenu );
+
+ CreateServiceFunction( MO_SETOPTIONSMENUOBJECT, SRVMO_SetOptionsMenuObject );
+ CreateServiceFunction( MO_SETOPTIONSMENUITEM, SRVMO_SetOptionsMenuItem );
+
+ bIconsDisabled = DBGetContactSettingByte(NULL, "CList", "DisableMenuIcons", 0) != 0;
+
+ EnterCriticalSection( &csMenuHook );
+ bIsGenMenuInited = true;
+ LeaveCriticalSection( &csMenuHook );
+
+ HookEvent( ME_SYSTEM_MODULESLOADED, OnModulesLoaded );
+ HookEvent( ME_OPT_INITIALISE, GenMenuOptInit );
+ return 0;
+}
+
+int UnitGenMenu()
+{
+ if ( bIsGenMenuInited ) {
+ EnterCriticalSection( &csMenuHook );
+ MO_RemoveAllObjects();
+ bIsGenMenuInited=false;
+
+ LeaveCriticalSection( &csMenuHook );
+ DeleteCriticalSection(&csMenuHook);
+ }
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+TIntMenuObject::TIntMenuObject()
+{
+}
+
+TIntMenuObject::~TIntMenuObject()
+{
+ MO_RecursiveWalkMenu( m_items.first, FreeMenuItem, NULL );
+
+ FreeAndNil(( void** )&FreeService );
+ FreeAndNil(( void** )&onAddService );
+ FreeAndNil(( void** )&CheckService );
+ FreeAndNil(( void** )&ExecService );
+ FreeAndNil(( void** )&Name );
+
+ ImageList_Destroy(m_hMenuIcons);
+}
+
+void TIntMenuObject::freeItem( TMO_IntMenuItem* p )
+{
+ if ( FreeService )
+ CallService( FreeService, ( WPARAM )p, ( LPARAM )p->mi.ownerdata );
+
+ FreeAndNil(( void** )&p->mi.pszName );
+ FreeAndNil(( void** )&p->UniqName );
+ FreeAndNil(( void** )&p->CustomName );
+ if ( p->hBmp ) DeleteObject( p->hBmp );
+ mir_free( p );
+}
diff --git a/src/modules/clist/genmenu.h b/src/modules/clist/genmenu.h
new file mode 100644
index 0000000000..63c665b940
--- /dev/null
+++ b/src/modules/clist/genmenu.h
@@ -0,0 +1,146 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2010 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.
+*/
+#ifndef GENMENU_H
+#define GENMENU_H
+//general menu object module
+#include "m_genmenu.h"
+
+/* genmenu structs */
+
+#define MENUITEM_SIGNATURE 0xDEADBEEF
+
+typedef struct
+{
+ struct _tagIntMenuItem *first, // first element of submenu, or NULL
+ *last; // last element of submenu, or NULL
+}
+ TMO_LinkedList;
+
+typedef struct _tagIntMenuItem
+{
+ DWORD signature;
+ int iCommand;
+ int iconId; // icon index in the section's image list
+ TMO_MenuItem mi; // user-defined data
+ BOOL OverrideShow;
+ char* UniqName; // unique name
+ TCHAR* CustomName;
+ HANDLE hIcolibItem; // handle of iconlib item
+ HBITMAP hBmp;
+ int originalPosition;
+
+ struct _tagIntMenuItem *next; // next item in list
+ struct TIntMenuObject *parent;
+ TMO_LinkedList *owner;
+ TMO_LinkedList submenu;
+}
+ TMO_IntMenuItem,*PMO_IntMenuItem;
+
+struct TIntMenuObject
+{
+ TIntMenuObject();
+ ~TIntMenuObject();
+
+ __inline void* operator new( size_t size )
+ { return mir_calloc( size );
+ }
+ __inline void operator delete( void* p )
+ { mir_free( p );
+ }
+
+ char* Name;
+ int id;
+
+ //ExecService
+ //LPARAM lParam;//owner data
+ //WPARAM wParam;//allways lparam from winproc
+ char *ExecService;
+
+ //CheckService called when building menu
+ //return false to skip item.
+ //LPARAM lParam;//0
+ //WPARAM wParam;//CheckParam
+ char *CheckService;//analog to check_proc
+
+ //LPARAM lParam;//ownerdata
+ //WPARAM wParam;//menuitemhandle
+ char *FreeService;//callback service used to free ownerdata for menuitems
+
+ //LPARAM lParam;//MENUITEMINFO filled with all needed data
+ //WPARAM wParam;//menuitemhandle
+ char *onAddService;//called just before add MENUITEMINFO to hMenu
+
+ TMO_LinkedList m_items;
+ HIMAGELIST m_hMenuIcons;
+ BOOL m_bUseUserDefinedItems;
+
+ void freeItem( TMO_IntMenuItem* );
+};
+
+extern LIST<TIntMenuObject> g_menus;
+
+#define SEPARATORPOSITIONINTERVAL 100000
+
+//internal usage
+HMENU BuildRecursiveMenu(HMENU hMenu, PMO_IntMenuItem, ListParam *param);
+void GetMenuItemName( PMO_IntMenuItem pMenuItem, char* pszDest, size_t cbDestSize );
+
+PMO_IntMenuItem MO_GetIntMenuItem( HGENMENU );
+
+PMO_IntMenuItem MO_AddNewMenuItem( HANDLE menuobjecthandle, PMO_MenuItem pmi );
+PMO_IntMenuItem MO_AddOldNewMenuItem( HANDLE menuobjecthandle, PMO_MenuItem pmi );
+
+int MO_DrawMenuItem( LPDRAWITEMSTRUCT dis );
+int MO_MeasureMenuItem( LPMEASUREITEMSTRUCT mis );
+int MO_ModifyMenuItem( PMO_IntMenuItem menuHandle, PMO_MenuItem pmiparam );
+int MO_ProcessCommand( PMO_IntMenuItem pimi, LPARAM lParam );
+INT_PTR MO_ProcessHotKeys( HANDLE menuHandle, INT_PTR vKey );
+int MO_SetOptionsMenuItem( PMO_IntMenuItem menuobjecthandle, int setting, INT_PTR value );
+int MO_SetOptionsMenuObject( HANDLE menuobjecthandle, int setting, INT_PTR value );
+
+INT_PTR MO_ProcessCommandByMenuIdent(WPARAM wParam,LPARAM lParam);
+int MO_ProcessCommandBySubMenuIdent(int menuID, int command, LPARAM lParam);
+
+// function returns TRUE if the walk should be immediately stopped
+typedef int ( *pfnWalkFunc )( PMO_IntMenuItem, void* );
+
+// returns the item, on which pfnWalkFunc returned TRUE
+PMO_IntMenuItem MO_RecursiveWalkMenu( PMO_IntMenuItem, pfnWalkFunc, void* );
+
+//general stuff
+int InitGenMenu();
+int UnitGenMenu();
+
+int FindRoot( PMO_IntMenuItem pimi, void* param );
+
+TMO_IntMenuItem * GetMenuItemByGlobalID(int globalMenuID);
+BOOL FindMenuHanleByGlobalID(HMENU hMenu, int globalID, struct _MenuItemHandles * dat); //GenMenu.c
+
+int GenMenuOptInit(WPARAM wParam, LPARAM lParam);
+int GetMenuObjbyId(const int id);
+int GetMenuItembyId(const int objpos,const int id);
+INT_PTR MO_GetMenuItem(WPARAM wParam,LPARAM lParam);
+void FreeAndNil(void **p);
+static int RemoveFromList(int pos,void **lpList,int *ListElemCount,int ElemSize);
+static int RemoveFromList(int pos,void **lpList,int *ListElemCount,int ElemSize);
+#endif
diff --git a/src/modules/clist/genmenuopt.cpp b/src/modules/clist/genmenuopt.cpp
new file mode 100644
index 0000000000..7fefbf8dcb
--- /dev/null
+++ b/src/modules/clist/genmenuopt.cpp
@@ -0,0 +1,870 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2010 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 "genmenu.h"
+
+#define STR_SEPARATOR _T("-----------------------------------")
+
+extern bool bIconsDisabled;
+extern int DefaultImageListColorDepth;
+long handleCustomDraw(HWND hWndTreeView, LPNMTVCUSTOMDRAW pNMTVCD);
+void RebuildProtoMenus( int );
+
+struct OrderData
+{
+ int dragging;
+ HTREEITEM hDragItem;
+ int iInitMenuValue;
+};
+
+typedef struct tagMenuItemOptData
+{
+ TCHAR* name;
+ TCHAR* defname;
+ char* uniqname;
+
+ int pos;
+ boolean show;
+ DWORD isSelected;
+ int id;
+
+ PMO_IntMenuItem pimi;
+}
+ MenuItemOptData,*lpMenuItemOptData;
+
+static BOOL GetCurrentMenuObjectID(HWND hwndDlg, int* result)
+{
+ TVITEM tvi;
+ HWND hTree = GetDlgItem(hwndDlg, IDC_MENUOBJECTS);
+ HTREEITEM hti = TreeView_GetSelection(hTree);
+ if ( hti == NULL )
+ return FALSE;
+
+ tvi.mask = TVIF_HANDLE | TVIF_PARAM;
+ tvi.hItem = hti;
+ TreeView_GetItem(hTree, &tvi);
+ *result = (int)tvi.lParam;
+ return TRUE;
+}
+
+static int SaveTree(HWND hwndDlg)
+{
+ TVITEM tvi;
+ int count;
+ TCHAR idstr[100];
+ char menuItemName[256], DBString[256], MenuNameItems[256];
+ int menupos;
+ int MenuObjectId, runtimepos;
+ TIntMenuObject* pimo;
+ MenuItemOptData* iod;
+ HWND hTree = GetDlgItem( hwndDlg, IDC_MENUITEMS );
+
+ if ( !GetCurrentMenuObjectID( hwndDlg, &MenuObjectId ))
+ return 0;
+
+ tvi.hItem = TreeView_GetRoot( hTree );
+ tvi.cchTextMax = 99;
+ tvi.mask = TVIF_TEXT | TVIF_PARAM | TVIF_HANDLE;
+ tvi.pszText = idstr;
+ count = 0;
+
+ menupos = GetMenuObjbyId( MenuObjectId );
+ if ( menupos == -1 )
+ return -1;
+
+ pimo = g_menus[menupos];
+
+ mir_snprintf( MenuNameItems, sizeof(MenuNameItems), "%s_Items", pimo->Name);
+ runtimepos = 100;
+
+ while ( tvi.hItem != NULL ) {
+ TreeView_GetItem( hTree, &tvi );
+ iod = ( MenuItemOptData* )tvi.lParam;
+ if ( iod->pimi ) {
+ GetMenuItemName( iod->pimi, menuItemName, sizeof( menuItemName ));
+
+ mir_snprintf( DBString, SIZEOF(DBString), "%s_visible", menuItemName );
+ DBWriteContactSettingByte( NULL, MenuNameItems, DBString, iod->show );
+
+ mir_snprintf( DBString, SIZEOF(DBString), "%s_pos", menuItemName );
+ DBWriteContactSettingDword( NULL, MenuNameItems, DBString, runtimepos );
+
+ mir_snprintf( DBString, SIZEOF(DBString), "%s_name", menuItemName );
+ if ( lstrcmp( iod->name, iod->defname ) != 0 )
+ DBWriteContactSettingTString( NULL, MenuNameItems, DBString, iod->name );
+ else
+ DBDeleteContactSetting( NULL, MenuNameItems, DBString );
+
+ runtimepos += 100;
+ }
+
+ if ( iod->name && !_tcscmp( iod->name, STR_SEPARATOR) && iod->show )
+ runtimepos += SEPARATORPOSITIONINTERVAL;
+
+ tvi.hItem = TreeView_GetNextSibling( hTree, tvi.hItem );
+ count++;
+ }
+ return 1;
+}
+
+static int BuildMenuObjectsTree(HWND hwndDlg)
+{
+ TVINSERTSTRUCT tvis;
+ HWND hTree = GetDlgItem(hwndDlg,IDC_MENUOBJECTS);
+ int i;
+
+ tvis.hParent = NULL;
+ tvis.hInsertAfter = TVI_LAST;
+ tvis.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ TreeView_DeleteAllItems( hTree );
+ if ( g_menus.getCount() == 0 )
+ return FALSE;
+
+ for ( i=0; i < g_menus.getCount(); i++ ) {
+ if ( g_menus[i]->id == (int)hStatusMenuObject || !g_menus[i]->m_bUseUserDefinedItems )
+ continue;
+
+ tvis.item.lParam = ( LPARAM )g_menus[i]->id;
+ tvis.item.pszText = LangPackPcharToTchar( g_menus[i]->Name );
+ tvis.item.iImage = tvis.item.iSelectedImage = TRUE;
+ TreeView_InsertItem( hTree, &tvis );
+ mir_free( tvis.item.pszText );
+ }
+ return 1;
+}
+
+static int sortfunc(const void *a,const void *b)
+{
+ lpMenuItemOptData *sd1,*sd2;
+ sd1=(lpMenuItemOptData *)a;
+ sd2=(lpMenuItemOptData *)b;
+ if ((*sd1)->pos > (*sd2)->pos)
+ return 1;
+
+ if ((*sd1)->pos < (*sd2)->pos)
+ return -1;
+
+ return 0;
+}
+
+static int InsertSeparator(HWND hwndDlg)
+{
+ MenuItemOptData *PD;
+ TVINSERTSTRUCT tvis = {0};
+ TVITEM tvi = {0};
+ HTREEITEM hti = {0};
+ HWND hMenuTree = GetDlgItem( hwndDlg, IDC_MENUITEMS );
+
+ hti = TreeView_GetSelection( hMenuTree );
+ if ( hti == NULL )
+ return 1;
+
+ tvi.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM | TVIF_TEXT;
+ tvi.hItem = hti;
+ if ( TreeView_GetItem( hMenuTree, &tvi) == FALSE )
+ return 1;
+
+ PD = ( MenuItemOptData* )mir_alloc( sizeof( MenuItemOptData ));
+ ZeroMemory( PD, sizeof( MenuItemOptData ));
+ PD->id = -1;
+ PD->name = mir_tstrdup( STR_SEPARATOR );
+ PD->show = TRUE;
+ PD->pos = ((MenuItemOptData *)tvi.lParam)->pos-1;
+
+ tvis.item.lParam = (LPARAM)(PD);
+ tvis.item.pszText = PD->name;
+ tvis.item.iImage = tvis.item.iSelectedImage = PD->show;
+ tvis.hParent = NULL;
+ tvis.hInsertAfter = hti;
+ tvis.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ TreeView_InsertItem( hMenuTree, &tvis );
+ return 1;
+}
+
+static void FreeTreeData( HWND hwndDlg )
+{
+ HTREEITEM hItem = TreeView_GetRoot(GetDlgItem(hwndDlg,IDC_MENUITEMS));
+ while ( hItem != NULL ) {
+ TVITEM tvi;
+ tvi.mask = TVIF_HANDLE | TVIF_PARAM;
+ tvi.hItem = hItem;
+ TreeView_GetItem( GetDlgItem( hwndDlg, IDC_MENUITEMS ), &tvi );
+ { MenuItemOptData* O = (MenuItemOptData *)tvi.lParam;
+ if ( O->name ) mir_free( O->name );
+ if ( O->defname ) mir_free( O->defname );
+ if ( O->uniqname ) mir_free( O->uniqname );
+ mir_free( O );
+ }
+
+ tvi.lParam = 0;
+ TreeView_SetItem(GetDlgItem(hwndDlg,IDC_MENUITEMS), &tvi);
+
+ hItem = TreeView_GetNextSibling(GetDlgItem(hwndDlg,IDC_MENUITEMS), hItem);
+} }
+
+static int BuildTree(HWND hwndDlg,int MenuObjectId, BOOL bReread)
+{
+ char menuItemName[256],MenuNameItems[256];
+ char buf[256];
+
+ FreeTreeData( hwndDlg );
+ TreeView_DeleteAllItems(GetDlgItem(hwndDlg,IDC_MENUITEMS));
+
+ int menupos = GetMenuObjbyId( MenuObjectId );
+ if ( menupos == -1 )
+ return FALSE;
+
+ TIntMenuObject* pimo = g_menus[menupos];
+ if ( pimo->m_items.first == NULL )
+ return FALSE;
+
+ mir_snprintf( MenuNameItems, sizeof(MenuNameItems), "%s_Items", pimo->Name );
+
+ int count = 0;
+ {
+ for ( PMO_IntMenuItem p = pimo->m_items.first; p != NULL; p = p->next )
+ if ( p->mi.root == ( HGENMENU )-1 || p->mi.root == NULL )
+ count++;
+ }
+
+ lpMenuItemOptData *PDar = ( lpMenuItemOptData* )mir_alloc( sizeof( lpMenuItemOptData )*count );
+
+ count = 0;
+ {
+ for ( PMO_IntMenuItem p = pimo->m_items.first; p != NULL; p = p->next ) {
+ if ( p->mi.root != ( HGENMENU )-1 && p->mi.root != NULL )
+ continue;
+
+ MenuItemOptData *PD = ( MenuItemOptData* )mir_calloc( sizeof( MenuItemOptData ));
+ GetMenuItemName( p, menuItemName, sizeof( menuItemName ));
+ {
+ DBVARIANT dbv;
+ mir_snprintf(buf, SIZEOF(buf), "%s_name", menuItemName);
+
+ if ( !DBGetContactSettingTString( NULL, MenuNameItems, buf, &dbv )) {
+ PD->name = mir_tstrdup( dbv.ptszVal );
+ DBFreeVariant( &dbv );
+ }
+ else PD->name = mir_tstrdup( p->mi.ptszName );
+ }
+
+ PD->pimi = p;
+ PD->defname = mir_tstrdup( p->mi.ptszName );
+
+ mir_snprintf( buf, SIZEOF(buf), "%s_visible", menuItemName );
+ PD->show = DBGetContactSettingByte( NULL, MenuNameItems, buf, 1 );
+
+ if ( bReread ) {
+ mir_snprintf( buf, SIZEOF(buf), "%s_pos", menuItemName );
+ PD->pos = DBGetContactSettingDword( NULL, MenuNameItems, buf, 1 );
+ }
+ else PD->pos = ( PD->pimi ) ? PD->pimi->originalPosition : 0;
+
+ PD->id = p->iCommand;
+
+ if ( p->UniqName )
+ PD->uniqname = mir_strdup( p->UniqName );
+
+ PDar[ count ] = PD;
+ count++;
+ } }
+
+ qsort( PDar, count, sizeof( lpMenuItemOptData ), sortfunc );
+
+ SendDlgItemMessage(hwndDlg, IDC_MENUITEMS, WM_SETREDRAW, FALSE, 0);
+ int lastpos = 0;
+ bool first = TRUE;
+
+ TVINSERTSTRUCT tvis;
+ tvis.hParent = NULL;
+ tvis.hInsertAfter = TVI_LAST;
+ tvis.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ for ( int i=0; i < count; i++ ) {
+ if ( PDar[i]->pos - lastpos >= SEPARATORPOSITIONINTERVAL ) {
+ MenuItemOptData *PD = ( MenuItemOptData* )mir_calloc( sizeof( MenuItemOptData ));
+ PD->id = -1;
+ PD->name = mir_tstrdup( STR_SEPARATOR );
+ PD->pos = PDar[i]->pos - 1;
+ PD->show = TRUE;
+
+ tvis.item.lParam = ( LPARAM )PD;
+ tvis.item.pszText = PD->name;
+ tvis.item.iImage = tvis.item.iSelectedImage = PD->show;
+ SendDlgItemMessage(hwndDlg, IDC_MENUITEMS, TVM_INSERTITEM, 0, (LPARAM)&tvis);
+ }
+
+ tvis.item.lParam = ( LPARAM )PDar[i];
+ tvis.item.pszText = PDar[i]->name;
+ tvis.item.iImage = tvis.item.iSelectedImage = PDar[i]->show;
+
+ HTREEITEM hti = (HTREEITEM)SendDlgItemMessage(hwndDlg, IDC_MENUITEMS, TVM_INSERTITEM, 0, (LPARAM)&tvis);
+ if ( first ) {
+ TreeView_SelectItem(GetDlgItem(hwndDlg,IDC_MENUITEMS),hti);
+ first=FALSE;
+ }
+
+ lastpos = PDar[i]->pos;
+ }
+
+ SendDlgItemMessage( hwndDlg, IDC_MENUITEMS, WM_SETREDRAW, TRUE, 0 );
+ mir_free( PDar );
+ ShowWindow( GetDlgItem( hwndDlg, IDC_NOTSUPPORTWARNING ),( pimo->m_bUseUserDefinedItems ) ? SW_HIDE : SW_SHOW );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_MENUITEMS ), pimo->m_bUseUserDefinedItems );
+ EnableWindow( GetDlgItem( hwndDlg, IDC_INSERTSEPARATOR ), pimo->m_bUseUserDefinedItems );
+ return 1;
+}
+
+static void RebuildCurrent( HWND hwndDlg )
+{
+ int MenuObjectID;
+ if ( GetCurrentMenuObjectID( hwndDlg, &MenuObjectID ))
+ BuildTree( hwndDlg, MenuObjectID, TRUE );
+}
+
+static void ResetMenuItems( HWND hwndDlg )
+{
+ int MenuObjectID;
+ if ( GetCurrentMenuObjectID( hwndDlg, &MenuObjectID ))
+ BuildTree( hwndDlg, MenuObjectID, FALSE );
+}
+
+static HTREEITEM MoveItemAbove(HWND hTreeWnd, HTREEITEM hItem, HTREEITEM hInsertAfter)
+{
+ TVITEM tvi = { 0 };
+ tvi.mask = TVIF_HANDLE | TVIF_PARAM;
+ tvi.hItem = hItem;
+ if ( !SendMessage(hTreeWnd, TVM_GETITEM, 0, ( LPARAM )&tvi ))
+ return NULL;
+ if ( hItem && hInsertAfter ) {
+ TVINSERTSTRUCT tvis;
+ TCHAR name[128];
+ if ( hItem == hInsertAfter )
+ return hItem;
+
+ tvis.item.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ tvis.item.stateMask = 0xFFFFFFFF;
+ tvis.item.pszText = name;
+ tvis.item.cchTextMax = sizeof( name );
+ tvis.item.hItem = hItem;
+ tvis.item.iImage = tvis.item.iSelectedImage = (( MenuItemOptData* )tvi.lParam)->show;
+ if(!SendMessage(hTreeWnd, TVM_GETITEM, 0, (LPARAM)&tvis.item))
+ return NULL;
+ if (!TreeView_DeleteItem(hTreeWnd,hItem))
+ return NULL;
+ tvis.hParent=NULL;
+ tvis.hInsertAfter=hInsertAfter;
+ return TreeView_InsertItem(hTreeWnd, &tvis);
+ }
+ return NULL;
+}
+
+WNDPROC MyOldWindowProc=NULL;
+
+LRESULT CALLBACK LBTNDOWNProc(HWND hwnd,UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ if (uMsg==WM_LBUTTONDOWN && !(GetKeyState(VK_CONTROL)&0x8000)) {
+
+ TVHITTESTINFO hti;
+ hti.pt.x=(short)LOWORD(lParam);
+ hti.pt.y=(short)HIWORD(lParam);
+ // ClientToScreen(hwndDlg,&hti.pt);
+ // ScreenToClient(GetDlgItem(hwndDlg,IDC_MENUITEMS),&hti.pt);
+ TreeView_HitTest(hwnd,&hti);
+ if (hti.flags&TVHT_ONITEMLABEL) {
+ /// LabelClicked Set/unset selection
+ TVITEM tvi;
+ HWND tvw=hwnd;
+ tvi.mask=TVIF_HANDLE|TVIF_PARAM;
+ tvi.hItem=hti.hItem;
+ TreeView_GetItem( tvw, &tvi );
+
+ if (!((MenuItemOptData *)tvi.lParam)->isSelected) { /* is not Selected*/
+ // reset all selection except current
+ HTREEITEM hit;
+ hit=TreeView_GetRoot(tvw);
+ if (hit)
+ do {
+ TVITEM tvi={0};
+ tvi.mask=TVIF_HANDLE|TVIF_PARAM;
+ tvi.hItem=hit;
+ TreeView_GetItem(tvw, &tvi);
+
+ if (hti.hItem!=hit)
+ ((MenuItemOptData *)tvi.lParam)->isSelected=0;
+ else
+ ((MenuItemOptData *)tvi.lParam)->isSelected=1;
+ TreeView_SetItem(tvw, &tvi);
+ }
+ while (hit=TreeView_GetNextSibling(tvw,hit));
+ } } }
+
+ return CallWindowProc(MyOldWindowProc,hwnd,uMsg,wParam,lParam);
+}
+
+static INT_PTR CALLBACK GenMenuOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct OrderData *dat = (struct OrderData*)GetWindowLongPtr(GetDlgItem(hwndDlg,IDC_MENUITEMS),GWLP_USERDATA);
+ LPNMHDR hdr;
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ dat=(struct OrderData*)mir_alloc(sizeof(struct OrderData));
+ SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_MENUITEMS),GWLP_USERDATA,(LONG_PTR)dat);
+ dat->dragging = 0;
+ dat->iInitMenuValue = DBGetContactSettingByte( NULL, "CList", "MoveProtoMenus", FALSE );
+ MyOldWindowProc = (WNDPROC)GetWindowLongPtr(GetDlgItem(hwndDlg,IDC_MENUITEMS),GWLP_WNDPROC);
+ SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_MENUITEMS),GWLP_WNDPROC,(LONG_PTR)&LBTNDOWNProc);
+ {
+ HIMAGELIST himlCheckBoxes;
+ himlCheckBoxes=ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
+ (IsWinVerXPPlus() ? ILC_COLOR32 : ILC_COLOR16) | ILC_MASK, 2, 2);
+
+ ImageList_AddIcon_IconLibLoaded(himlCheckBoxes, SKINICON_OTHER_NOTICK);
+ ImageList_AddIcon_IconLibLoaded(himlCheckBoxes, SKINICON_OTHER_TICK);
+
+ TreeView_SetImageList(GetDlgItem(hwndDlg,IDC_MENUOBJECTS),himlCheckBoxes,TVSIL_NORMAL);
+ TreeView_SetImageList(GetDlgItem(hwndDlg,IDC_MENUITEMS),himlCheckBoxes,TVSIL_NORMAL);
+ }
+ CheckDlgButton(hwndDlg, dat->iInitMenuValue ? IDC_RADIO2 : IDC_RADIO1, TRUE );
+ CheckDlgButton(hwndDlg, IDC_DISABLEMENUICONS, bIconsDisabled );
+ BuildMenuObjectsTree(hwndDlg);
+ return TRUE;
+
+ case WM_COMMAND:
+ if ( HIWORD(wParam) == BN_CLICKED || HIWORD( wParam ) == BN_DBLCLK ) {
+ switch ( LOWORD( wParam )) {
+ case IDC_INSERTSEPARATOR:
+ InsertSeparator(hwndDlg);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case IDC_RESETMENU:
+ ResetMenuItems( hwndDlg );
+ SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
+ break;
+
+ case IDC_DISABLEMENUICONS:
+ case IDC_RADIO1:
+ case IDC_RADIO2:
+ SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
+ break;
+
+ case IDC_GENMENU_DEFAULT:
+ {
+ TVITEM tvi;
+ HTREEITEM hti;
+ MenuItemOptData *iod;
+
+ hti=TreeView_GetSelection(GetDlgItem(hwndDlg,IDC_MENUITEMS));
+ if (hti==NULL)
+ break;
+
+ tvi.mask=TVIF_HANDLE|TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_PARAM;
+ tvi.hItem=hti;
+ TreeView_GetItem(GetDlgItem(hwndDlg,IDC_MENUITEMS),&tvi);
+ iod = ( MenuItemOptData * )tvi.lParam;
+
+ if ( iod->name && _tcsstr( iod->name, STR_SEPARATOR ))
+ break;
+
+ if (iod->name)
+ mir_free(iod->name);
+ iod->name = mir_tstrdup( iod->defname );
+
+ SaveTree(hwndDlg);
+ RebuildCurrent(hwndDlg);
+ SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
+ }
+ break;
+
+ case IDC_GENMENU_SET:
+ {
+ TVITEM tvi;
+ TCHAR buf[256];
+ MenuItemOptData *iod;
+
+ HTREEITEM hti = TreeView_GetSelection( GetDlgItem( hwndDlg,IDC_MENUITEMS ));
+ if ( hti == NULL )
+ break;
+
+ tvi.mask = TVIF_HANDLE|TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_PARAM;
+ tvi.hItem = hti;
+ SendDlgItemMessage(hwndDlg, IDC_MENUITEMS, TVM_GETITEM, 0, (LPARAM)&tvi);
+ iod = ( MenuItemOptData * )tvi.lParam;
+
+ if ( iod->name && _tcsstr(iod->name, STR_SEPARATOR ))
+ break;
+
+ ZeroMemory(buf,sizeof( buf ));
+ GetDlgItemText( hwndDlg, IDC_GENMENU_CUSTOMNAME, buf, SIZEOF( buf ));
+ if (iod->name)
+ mir_free(iod->name);
+
+ iod->name = mir_tstrdup(buf);
+
+ SaveTree(hwndDlg);
+ RebuildCurrent(hwndDlg);
+ SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
+ }
+ break;
+ } }
+ break;
+
+ case WM_NOTIFY:
+ hdr = (LPNMHDR)lParam;
+ switch( hdr->idFrom ) {
+ case 0:
+ if (hdr->code == PSN_APPLY ) {
+ bIconsDisabled = IsDlgButtonChecked(hwndDlg, IDC_DISABLEMENUICONS) != 0;
+ DBWriteContactSettingByte(NULL, "CList", "DisableMenuIcons", bIconsDisabled);
+ SaveTree(hwndDlg);
+ int iNewMenuValue = IsDlgButtonChecked(hwndDlg, IDC_RADIO1) ? 0 : 1;
+ if ( iNewMenuValue != dat->iInitMenuValue ) {
+ RebuildProtoMenus( iNewMenuValue );
+ dat->iInitMenuValue = iNewMenuValue;
+ }
+ RebuildCurrent(hwndDlg);
+ }
+ break;
+
+ case IDC_MENUOBJECTS:
+ if (hdr->code == TVN_SELCHANGEDA )
+ RebuildCurrent( hwndDlg );
+ break;
+
+ case IDC_MENUITEMS:
+ switch (hdr->code) {
+ case NM_CUSTOMDRAW:
+ {
+ int i= handleCustomDraw(GetDlgItem(hwndDlg,IDC_MENUITEMS),(LPNMTVCUSTOMDRAW) lParam);
+ SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, i);
+ return TRUE;
+ }
+
+ case TVN_BEGINDRAGA:
+ SetCapture(hwndDlg);
+ dat->dragging=1;
+ dat->hDragItem=((LPNMTREEVIEW)lParam)->itemNew.hItem;
+ TreeView_SelectItem(GetDlgItem(hwndDlg,IDC_MENUITEMS),dat->hDragItem);
+ break;
+
+ case NM_CLICK:
+ {
+ TVHITTESTINFO hti;
+ hti.pt.x=(short)LOWORD(GetMessagePos());
+ hti.pt.y=(short)HIWORD(GetMessagePos());
+ ScreenToClient(hdr->hwndFrom,&hti.pt);
+ if (TreeView_HitTest(hdr->hwndFrom,&hti)) {
+ if (hti.flags&TVHT_ONITEMICON) {
+ TVITEM tvi;
+ tvi.mask=TVIF_HANDLE|TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_PARAM;
+ tvi.hItem=hti.hItem;
+ TreeView_GetItem(hdr->hwndFrom,&tvi);
+
+ tvi.iImage=tvi.iSelectedImage=!tvi.iImage;
+ ((MenuItemOptData *)tvi.lParam)->show=tvi.iImage;
+ TreeView_SetItem(hdr->hwndFrom,&tvi);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+
+ //all changes take effect in runtime
+ //ShowWindow(GetDlgItem(hwndDlg,IDC_BUTTONORDERTREEWARNING),SW_SHOW);
+ }
+ /*--------MultiSelection----------*/
+ if (hti.flags&TVHT_ONITEMLABEL) {
+ /// LabelClicked Set/unset selection
+ TVITEM tvi;
+ HWND tvw=hdr->hwndFrom;
+ tvi.mask=TVIF_HANDLE|TVIF_PARAM;
+ tvi.hItem=hti.hItem;
+ TreeView_GetItem(tvw,&tvi);
+ if (GetKeyState(VK_CONTROL)&0x8000) {
+ if (((MenuItemOptData *)tvi.lParam)->isSelected)
+ ((MenuItemOptData *)tvi.lParam)->isSelected=0;
+ else
+ ((MenuItemOptData *)tvi.lParam)->isSelected=1; //current selection order++.
+ TreeView_SetItem(tvw,&tvi);
+ }
+ else if (GetKeyState(VK_SHIFT)&0x8000) {
+ ; // shifted click
+ }
+ else {
+ // reset all selection except current
+ HTREEITEM hit;
+ hit=TreeView_GetRoot(tvw);
+ if (hit)
+ do {
+ TVITEM tvi={0};
+ tvi.mask=TVIF_HANDLE|TVIF_PARAM;
+ tvi.hItem=hit;
+ TreeView_GetItem(tvw,&tvi);
+
+ if (hti.hItem!=hit)
+ ((MenuItemOptData *)tvi.lParam)->isSelected=0;
+ else
+ ((MenuItemOptData *)tvi.lParam)->isSelected=1;
+ TreeView_SetItem(tvw,&tvi);
+ }
+ while (hit=TreeView_GetNextSibling(tvw,hit));
+ } } }
+ break;
+ }
+ case TVN_SELCHANGING:
+ {
+ LPNMTREEVIEW pn;
+ pn = (LPNMTREEVIEW) lParam;
+ //((MenuItemOptData *)(pn->itemNew.lParam))->isSelected=1;
+ /*if (pn->action==NotKeyPressed)
+ {
+ remove all selection
+ }
+ */
+ }
+ case TVN_SELCHANGEDA:
+ {
+ TVITEM tvi;
+ HTREEITEM hti;
+ MenuItemOptData *iod;
+
+ SetDlgItemTextA(hwndDlg,IDC_GENMENU_CUSTOMNAME,"");
+ SetDlgItemTextA(hwndDlg,IDC_GENMENU_SERVICE,"");
+
+ EnableWindow(GetDlgItem(hwndDlg,IDC_GENMENU_CUSTOMNAME),FALSE);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_GENMENU_DEFAULT),FALSE);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_GENMENU_SET),FALSE);
+
+ hti=TreeView_GetSelection(GetDlgItem(hwndDlg,IDC_MENUITEMS));
+ if (hti==NULL)
+ break;
+
+ tvi.mask=TVIF_HANDLE|TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_PARAM;
+ tvi.hItem=hti;
+ TreeView_GetItem(GetDlgItem(hwndDlg,IDC_MENUITEMS),&tvi);
+
+ if ( tvi.lParam == 0 )
+ break;
+
+ iod = ( MenuItemOptData * )tvi.lParam;
+
+ if ( iod->name && _tcsstr(iod->name, STR_SEPARATOR))
+ break;
+
+ SetDlgItemText(hwndDlg,IDC_GENMENU_CUSTOMNAME,iod->name);
+
+ if (iod->pimi->submenu.first == NULL && iod->uniqname)
+ SetDlgItemTextA(hwndDlg, IDC_GENMENU_SERVICE, iod->uniqname);
+
+ EnableWindow(GetDlgItem(hwndDlg,IDC_GENMENU_DEFAULT), lstrcmp(iod->name, iod->defname) != 0);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_GENMENU_SET),TRUE);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_GENMENU_CUSTOMNAME),TRUE);
+ break;
+ }
+ break;
+ } }
+ break;
+
+ case WM_MOUSEMOVE:
+ if (!dat||!dat->dragging) break;
+ {
+ TVHITTESTINFO hti;
+
+ hti.pt.x=(short)LOWORD(lParam);
+ hti.pt.y=(short)HIWORD(lParam);
+ ClientToScreen(hwndDlg,&hti.pt);
+ ScreenToClient(GetDlgItem(hwndDlg,IDC_MENUITEMS),&hti.pt);
+ TreeView_HitTest(GetDlgItem(hwndDlg,IDC_MENUITEMS),&hti);
+ if (hti.flags&(TVHT_ONITEM|TVHT_ONITEMRIGHT)) {
+ HTREEITEM it = hti.hItem;
+ hti.pt.y -= TreeView_GetItemHeight(GetDlgItem(hwndDlg,IDC_MENUITEMS))/2;
+ TreeView_HitTest(GetDlgItem(hwndDlg,IDC_MENUITEMS),&hti);
+ if (!(hti.flags&TVHT_ABOVE))
+ TreeView_SetInsertMark(GetDlgItem(hwndDlg,IDC_MENUITEMS),hti.hItem,1);
+ else
+ TreeView_SetInsertMark(GetDlgItem(hwndDlg,IDC_MENUITEMS),it,0);
+ }
+ else {
+ if (hti.flags&TVHT_ABOVE) SendDlgItemMessage(hwndDlg,IDC_MENUITEMS,WM_VSCROLL,MAKEWPARAM(SB_LINEUP,0),0);
+ if (hti.flags&TVHT_BELOW) SendDlgItemMessage(hwndDlg,IDC_MENUITEMS,WM_VSCROLL,MAKEWPARAM(SB_LINEDOWN,0),0);
+ TreeView_SetInsertMark(GetDlgItem(hwndDlg,IDC_MENUITEMS),NULL,0);
+ } }
+ break;
+
+ case WM_LBUTTONUP:
+ if (!dat->dragging)
+ break;
+
+ TreeView_SetInsertMark(GetDlgItem(hwndDlg,IDC_MENUITEMS),NULL,0);
+ dat->dragging=0;
+ ReleaseCapture();
+ {
+ TVHITTESTINFO hti;
+ hti.pt.x=(short)LOWORD(lParam);
+ hti.pt.y=(short)HIWORD(lParam);
+ ClientToScreen(hwndDlg,&hti.pt);
+ ScreenToClient(GetDlgItem(hwndDlg,IDC_MENUITEMS),&hti.pt);
+ hti.pt.y-=TreeView_GetItemHeight(GetDlgItem(hwndDlg,IDC_MENUITEMS))/2;
+ TreeView_HitTest(GetDlgItem(hwndDlg,IDC_MENUITEMS),&hti);
+ if (hti.flags&TVHT_ABOVE) hti.hItem=TVI_FIRST;
+ if (dat->hDragItem==hti.hItem) break;
+ dat->hDragItem=NULL;
+ if (hti.flags&(TVHT_ONITEM|TVHT_ONITEMRIGHT)||(hti.hItem==TVI_FIRST)) {
+ HWND tvw;
+ HTREEITEM * pSIT;
+ HTREEITEM FirstItem=NULL;
+ UINT uITCnt,uSic ;
+ tvw=GetDlgItem(hwndDlg,IDC_MENUITEMS);
+ uITCnt=TreeView_GetCount(tvw);
+ uSic=0;
+ if (uITCnt) {
+ pSIT=(HTREEITEM *)mir_alloc(sizeof(HTREEITEM)*uITCnt);
+ if (pSIT) {
+ HTREEITEM hit;
+ hit=TreeView_GetRoot(tvw);
+ if (hit)
+ do {
+ TVITEM tvi={0};
+ tvi.mask=TVIF_HANDLE|TVIF_PARAM;
+ tvi.hItem=hit;
+ TreeView_GetItem(tvw,&tvi);
+ if (((MenuItemOptData *)tvi.lParam)->isSelected) {
+ pSIT[uSic]=tvi.hItem;
+
+ uSic++;
+ }
+ }while (hit=TreeView_GetNextSibling(tvw,hit));
+ // Proceed moving
+ {
+ UINT i;
+ HTREEITEM insertAfter;
+ insertAfter=hti.hItem;
+ for (i=0; i<uSic; i++) {
+ if (insertAfter) insertAfter=MoveItemAbove(tvw,pSIT[i],insertAfter);
+ else break;
+ if (!i) FirstItem=insertAfter;
+ } }
+ // free pointers...
+ mir_free(pSIT);
+ } }
+
+ if (FirstItem) TreeView_SelectItem(tvw,FirstItem);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ SaveTree(hwndDlg);
+ } }
+ break;
+
+ case WM_DESTROY:
+ if ( dat )
+ mir_free( dat );
+
+ ImageList_Destroy(TreeView_SetImageList(GetDlgItem(hwndDlg,IDC_MENUOBJECTS),NULL,TVSIL_NORMAL));
+ FreeTreeData( hwndDlg );
+ break;
+
+ }
+ return FALSE;
+}
+
+long handleCustomDraw(HWND hWndTreeView, LPNMTVCUSTOMDRAW pNMTVCD)
+{
+ if ( pNMTVCD == NULL )
+ return -1;
+
+ switch ( pNMTVCD->nmcd.dwDrawStage ) {
+ case CDDS_PREPAINT:
+ return CDRF_NOTIFYITEMDRAW;
+
+ case CDDS_ITEMPREPAINT:
+ {
+ HTREEITEM hItem = (HTREEITEM) pNMTVCD->nmcd.dwItemSpec;
+ TCHAR buf[255];
+ TVITEM tvi = {0};
+ int k=0;
+ tvi.mask = TVIF_HANDLE |TVIF_PARAM|TVIS_SELECTED|TVIF_TEXT|TVIF_IMAGE;
+ tvi.stateMask=TVIS_SELECTED;
+ tvi.hItem = hItem;
+ tvi.pszText=(LPTSTR)(&buf);
+ tvi.cchTextMax=254;
+ TreeView_GetItem(hWndTreeView, &tvi);
+ if (((MenuItemOptData *)tvi.lParam)->isSelected) {
+ pNMTVCD->clrTextBk = GetSysColor(COLOR_HIGHLIGHT);
+ pNMTVCD->clrText = GetSysColor(COLOR_HIGHLIGHTTEXT);
+ }
+ else {
+ pNMTVCD->clrTextBk = GetSysColor(COLOR_WINDOW);
+ pNMTVCD->clrText = GetSysColor(COLOR_WINDOWTEXT);
+ }
+
+ /* At this point, you can change the background colors for the item
+ and any subitems and return CDRF_NEWFONT. If the list-view control
+ is in report mode, you can simply return CDRF_NOTIFYSUBITEMREDRAW
+ to customize the item's subitems individually */
+ if ( tvi.iImage == -1 ) {
+ HBRUSH br;
+ SIZE sz;
+ RECT rc;
+ k=1;
+
+ GetTextExtentPoint32(pNMTVCD->nmcd.hdc,tvi.pszText,lstrlen(tvi.pszText),&sz);
+
+ if (sz.cx+3>pNMTVCD->nmcd.rc.right-pNMTVCD->nmcd.rc.left) rc=pNMTVCD->nmcd.rc;
+ else SetRect(&rc,pNMTVCD->nmcd.rc.left,pNMTVCD->nmcd.rc.top,pNMTVCD->nmcd.rc.left+sz.cx+3,pNMTVCD->nmcd.rc.bottom);
+
+ br=CreateSolidBrush(pNMTVCD->clrTextBk);
+ SetTextColor(pNMTVCD->nmcd.hdc,pNMTVCD->clrText);
+ SetBkColor(pNMTVCD->nmcd.hdc,pNMTVCD->clrTextBk);
+ FillRect(pNMTVCD->nmcd.hdc,&rc,br);
+ DeleteObject(br);
+ DrawText(pNMTVCD->nmcd.hdc,tvi.pszText,lstrlen(tvi.pszText),&pNMTVCD->nmcd.rc,DT_LEFT|DT_VCENTER|DT_NOPREFIX);
+ }
+
+ return CDRF_NEWFONT|(k?CDRF_SKIPDEFAULT:0);
+ }
+ }
+ return 0;
+}
+
+INT_PTR CALLBACK ProtocolOrderOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+int GenMenuOptInit(WPARAM wParam, LPARAM)
+{
+ OPTIONSDIALOGPAGE odp = { 0 };
+ odp.cbSize=sizeof(odp);
+ odp.hInstance = hMirandaInst;
+ odp.pszGroup = LPGEN("Customize");
+
+ odp.position = -1000000000;
+ odp.pszTemplate = MAKEINTRESOURCEA( IDD_OPT_GENMENU );
+ odp.pszTitle = LPGEN("Menus");
+ odp.pfnDlgProc = GenMenuOpts;
+ odp.flags = ODPF_BOLDGROUPS;
+ CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
+
+ odp.position = -10000000;
+ odp.groupPosition = 1000000;
+ odp.pszTemplate = MAKEINTRESOURCEA( IDD_OPT_PROTOCOLORDER );
+ odp.pszTitle = LPGEN("Accounts");
+ odp.pfnDlgProc = ProtocolOrderOpts;
+ odp.flags = ODPF_BOLDGROUPS|ODPF_EXPERTONLY;
+ CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
+ return 0;
+}
diff --git a/src/modules/clist/groups.cpp b/src/modules/clist/groups.cpp
new file mode 100644
index 0000000000..0693c25036
--- /dev/null
+++ b/src/modules/clist/groups.cpp
@@ -0,0 +1,577 @@
+/*
+
+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 "clc.h"
+
+HANDLE hGroupChangeEvent;
+
+static INT_PTR RenameGroup(WPARAM wParam, LPARAM lParam);
+static INT_PTR MoveGroupBefore(WPARAM wParam, LPARAM lParam);
+
+static int CountGroups(void)
+{
+ DBVARIANT dbv;
+ int i;
+ char str[33];
+
+ for (i = 0;; i++) {
+ _itoa(i, str, 10);
+ if (DBGetContactSetting(NULL, "CListGroups", str, &dbv))
+ break;
+ DBFreeVariant(&dbv);
+ }
+ return i;
+}
+
+static int GroupNameExists(const TCHAR *name, int skipGroup)
+{
+ char idstr[33];
+ DBVARIANT dbv;
+ int i;
+
+ for (i = 0;; i++) {
+ if (i == skipGroup)
+ continue;
+ _itoa(i, idstr, 10);
+ if (DBGetContactSettingTString(NULL, "CListGroups", idstr, &dbv))
+ break;
+ if (!_tcscmp(dbv.ptszVal + 1, name)) {
+ DBFreeVariant(&dbv);
+ return i+1;
+ }
+ DBFreeVariant(&dbv);
+ }
+ return 0;
+}
+
+static INT_PTR CreateGroup(WPARAM wParam, LPARAM lParam)
+{
+ int newId = CountGroups();
+ TCHAR newBaseName[127], newName[128];
+ char str[33];
+ int i;
+ DBVARIANT dbv;
+
+ const TCHAR* grpName = lParam ? (TCHAR*)lParam : TranslateT("New Group");
+ if (wParam) {
+ _itoa(wParam - 1, str, 10);
+ if (DBGetContactSettingTString(NULL, "CListGroups", str, &dbv))
+ return 0;
+
+ mir_sntprintf( newBaseName, SIZEOF(newBaseName), _T("%s\\%s"), dbv.ptszVal + 1, grpName );
+ mir_free(dbv.pszVal);
+ }
+ else lstrcpyn( newBaseName, grpName, SIZEOF( newBaseName ));
+
+ _itoa(newId, str, 10);
+ lstrcpyn( newName + 1, newBaseName, SIZEOF(newName) - 1);
+ if (lParam) {
+ i = GroupNameExists(newBaseName, -1);
+ if (i) newId = i - 1;
+ i = !i;
+ }
+ else {
+ i = 1;
+ while (GroupNameExists(newName + 1, -1))
+ mir_sntprintf( newName + 1, SIZEOF(newName) - 1, _T("%s (%d)"), newBaseName, ++i );
+ }
+ if (i) {
+ const CLISTGROUPCHANGE grpChg = { sizeof(CLISTGROUPCHANGE), NULL, newName };
+
+ newName[0] = 1 | GROUPF_EXPANDED; //1 is required so we never get '\0'
+ DBWriteContactSettingTString(NULL, "CListGroups", str, newName);
+ CallService(MS_CLUI_GROUPADDED, newId + 1, 1);
+
+ NotifyEventHooks(hGroupChangeEvent, 0, (LPARAM)&grpChg);
+ }
+
+ return newId + 1;
+}
+
+static INT_PTR GetGroupName2(WPARAM wParam, LPARAM lParam)
+{
+ char idstr[33];
+ DBVARIANT dbv;
+ static char name[128];
+
+ _itoa(wParam - 1, idstr, 10);
+ if (DBGetContactSettingString(NULL, "CListGroups", idstr, &dbv))
+ return (INT_PTR) (char *) NULL;
+ lstrcpynA(name, dbv.pszVal + 1, SIZEOF(name));
+ if ((DWORD *) lParam != NULL)
+ *(DWORD *) lParam = dbv.pszVal[0];
+ DBFreeVariant(&dbv);
+ return (INT_PTR) name;
+}
+
+TCHAR* fnGetGroupName( int idx, DWORD* pdwFlags )
+{
+ char idstr[33];
+ DBVARIANT dbv;
+ static TCHAR name[128];
+
+ _itoa( idx-1, idstr, 10);
+ if (DBGetContactSettingTString( NULL, "CListGroups", idstr, &dbv ))
+ return NULL;
+
+ lstrcpyn( name, dbv.ptszVal + 1, SIZEOF( name ));
+ if ( pdwFlags != NULL )
+ *pdwFlags = dbv.ptszVal[0];
+ DBFreeVariant( &dbv );
+ return name;
+}
+
+static INT_PTR GetGroupName(WPARAM wParam, LPARAM lParam)
+{
+ INT_PTR ret;
+ ret = GetGroupName2(wParam, lParam);
+ if ((int *) lParam)
+ *(int *) lParam = 0 != (*(int *) lParam & GROUPF_EXPANDED);
+ return ret;
+}
+
+static INT_PTR DeleteGroup(WPARAM wParam, LPARAM)
+{
+ int i;
+ char str[33];
+ DBVARIANT dbv;
+ HANDLE hContact;
+ TCHAR name[256], szNewParent[256], *pszLastBackslash;
+
+ //get the name
+ _itoa(wParam - 1, str, 10);
+ if (DBGetContactSettingTString(NULL, "CListGroups", str, &dbv))
+ return 1;
+ lstrcpyn(name, dbv.ptszVal + 1, SIZEOF(name));
+ DBFreeVariant(&dbv);
+ if (DBGetContactSettingByte(NULL, "CList", "ConfirmDelete", SETTING_CONFIRMDELETE_DEFAULT))
+ {
+ TCHAR szQuestion[256+100];
+ mir_sntprintf( szQuestion, SIZEOF(szQuestion), TranslateT("Are you sure you want to delete group '%s'? This operation can not be undone."), name );
+ if (MessageBox(cli.hwndContactList, szQuestion, TranslateT("Delete Group"), MB_YESNO|MB_ICONQUESTION)==IDNO)
+ return 1;
+ }
+ SetCursor(LoadCursor(NULL, IDC_WAIT));
+ //must remove setting from all child contacts too
+ //children are demoted to the next group up, not deleted.
+ lstrcpy(szNewParent, name);
+ pszLastBackslash = _tcsrchr(szNewParent, '\\');
+ if (pszLastBackslash)
+ pszLastBackslash[0] = '\0';
+ else
+ szNewParent[0] = '\0';
+
+ CLISTGROUPCHANGE grpChg = { sizeof(CLISTGROUPCHANGE), NULL, NULL };
+
+ for (hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ hContact ;
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0))
+ {
+ if (DBGetContactSettingTString(hContact, "CList", "Group", &dbv))
+ continue;
+
+ if (_tcscmp(dbv.ptszVal, name))
+ {
+ DBFreeVariant(&dbv);
+ continue;
+ }
+ DBFreeVariant(&dbv);
+
+ if (szNewParent[0])
+ {
+ DBWriteContactSettingTString(hContact, "CList", "Group", szNewParent);
+ grpChg.pszNewName = szNewParent;
+ }
+ else
+ {
+ DBDeleteContactSetting(hContact, "CList", "Group");
+ grpChg.pszNewName = NULL;
+ }
+ NotifyEventHooks(hGroupChangeEvent, (WPARAM)hContact, (LPARAM)&grpChg);
+ }
+ //shuffle list of groups up to fill gap
+ for (i = wParam - 1;; i++) {
+ _itoa(i + 1, str, 10);
+ if (DBGetContactSettingStringUtf(NULL, "CListGroups", str, &dbv))
+ break;
+ _itoa(i, str, 10);
+ DBWriteContactSettingStringUtf(NULL, "CListGroups", str, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ _itoa(i, str, 10);
+ DBDeleteContactSetting(NULL, "CListGroups", str);
+ //rename subgroups
+ {
+ TCHAR szNewName[256];
+ int len;
+
+ len = lstrlen(name);
+ for (i = 0;; i++) {
+ _itoa(i, str, 10);
+ if (DBGetContactSettingTString(NULL, "CListGroups", str, &dbv))
+ break;
+ if (!_tcsncmp(dbv.ptszVal + 1, name, len) && dbv.pszVal[len + 1] == '\\' && _tcschr(dbv.ptszVal + len + 2, '\\') == NULL) {
+ if (szNewParent[0])
+ mir_sntprintf(szNewName, SIZEOF(szNewName), _T("%s\\%s"), szNewParent, dbv.ptszVal + len + 2);
+ else
+ lstrcpyn(szNewName, dbv.ptszVal + len + 2, SIZEOF(szNewName));
+ cli.pfnRenameGroup(i + 1, szNewName);
+ }
+ DBFreeVariant(&dbv);
+ }
+ }
+ SetCursor(LoadCursor(NULL, IDC_ARROW));
+ cli.pfnLoadContactTree();
+
+ {
+ const CLISTGROUPCHANGE grpChg = { sizeof(CLISTGROUPCHANGE), name, NULL };
+ NotifyEventHooks(hGroupChangeEvent, 0, (LPARAM)&grpChg);
+ }
+ return 0;
+}
+
+static int RenameGroupWithMove(int groupId, const TCHAR *szName, int move)
+{
+ char idstr[33];
+ TCHAR str[256], oldName[256];
+ DBVARIANT dbv;
+ HANDLE hContact;
+
+ if (GroupNameExists(szName, groupId)) {
+ MessageBox(NULL, TranslateT("You already have a group with that name. Please enter a unique name for the group."), TranslateT("Rename Group"), MB_OK);
+ return 1;
+ }
+
+ //do the change
+ _itoa(groupId, idstr, 10);
+ if (DBGetContactSettingTString(NULL, "CListGroups", idstr, &dbv))
+ return 1;
+ str[0] = dbv.pszVal[0] & 0x7F;
+ lstrcpyn(oldName, dbv.ptszVal + 1, SIZEOF(oldName));
+ DBFreeVariant(&dbv);
+ lstrcpyn(str + 1, szName, SIZEOF(str) - 1);
+ DBWriteContactSettingTString(NULL, "CListGroups", idstr, str);
+
+ //must rename setting in all child contacts too
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ do {
+ ClcCacheEntryBase* cache = cli.pfnGetCacheEntry( hContact );
+ if ( !lstrcmp(cache->group, oldName)) {
+ DBWriteContactSettingTString(hContact, "CList", "Group", szName);
+ mir_free(cache->group);
+ cache->group = 0;
+ cli.pfnCheckCacheItem(cache);
+ }
+ }
+ while ((hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0)) != NULL);
+
+ //rename subgroups
+ {
+ TCHAR szNewName[256];
+ int len, i;
+
+ len = lstrlen(oldName);
+ for (i = 0;; i++) {
+ if (i == groupId)
+ continue;
+ _itoa(i, idstr, 10);
+ if (DBGetContactSettingTString(NULL, "CListGroups", idstr, &dbv))
+ break;
+ if ( !_tcsncmp(dbv.ptszVal + 1, oldName, len) && dbv.ptszVal[len + 1] == '\\' && _tcschr(dbv.ptszVal + len + 2, '\\') == NULL) {
+ mir_sntprintf( szNewName, SIZEOF(szNewName), _T("%s\\%s"), szName, dbv.ptszVal + len + 2 );
+ RenameGroupWithMove(i, szNewName, 0); //luckily, child groups will never need reordering
+ }
+ DBFreeVariant(&dbv);
+ }
+ }
+
+ //finally must make sure it's after any parent items
+ if (move) {
+ TCHAR *pszLastBackslash;
+ int i;
+
+ lstrcpyn(str, szName, SIZEOF(str));
+ pszLastBackslash = _tcsrchr(str, '\\');
+ if (pszLastBackslash != NULL) {
+ *pszLastBackslash = '\0';
+ for (i = 0;; i++) {
+ _itoa(i, idstr, 10);
+ if (DBGetContactSettingTString(NULL, "CListGroups", idstr, &dbv))
+ break;
+ if (!lstrcmp(dbv.ptszVal + 1, str)) {
+ if (i < groupId)
+ break; //is OK
+ MoveGroupBefore(groupId + 1, i + 2);
+ break;
+ }
+ DBFreeVariant(&dbv);
+ }
+ }
+ }
+ {
+ const CLISTGROUPCHANGE grpChg = { sizeof(CLISTGROUPCHANGE), oldName, (TCHAR*)szName };
+ NotifyEventHooks(hGroupChangeEvent, 0, (LPARAM)&grpChg);
+ }
+ return 0;
+}
+
+int fnRenameGroup( int groupID, TCHAR* newName )
+{
+ return -1 != RenameGroupWithMove( groupID-1, newName, 1);
+}
+
+static INT_PTR RenameGroup(WPARAM wParam, LPARAM lParam)
+{
+ #if defined( _UNICODE )
+ WCHAR* temp = mir_a2u(( char* )lParam );
+ int result = ( -1 != RenameGroupWithMove(wParam - 1, temp, 1));
+ mir_free( temp );
+ return result;
+ #else
+ return -1 != RenameGroupWithMove(wParam - 1, (TCHAR*) lParam, 1);
+ #endif
+}
+
+static INT_PTR SetGroupExpandedState(WPARAM wParam, LPARAM lParam)
+{
+ char idstr[33];
+ DBVARIANT dbv;
+
+ _itoa(wParam - 1, idstr, 10);
+ if (DBGetContactSettingStringUtf(NULL, "CListGroups", idstr, &dbv))
+ return 1;
+ if (lParam)
+ dbv.pszVal[0] |= GROUPF_EXPANDED;
+ else
+ dbv.pszVal[0] = dbv.pszVal[0] & ~GROUPF_EXPANDED;
+ DBWriteContactSettingStringUtf(NULL, "CListGroups", idstr, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ return 0;
+}
+
+static INT_PTR SetGroupFlags(WPARAM wParam, LPARAM lParam)
+{
+ char idstr[33];
+ DBVARIANT dbv;
+ int flags, oldval, newval;
+
+ _itoa(wParam - 1, idstr, 10);
+ if (DBGetContactSettingStringUtf(NULL, "CListGroups", idstr, &dbv))
+ return 1;
+ flags = LOWORD(lParam) & HIWORD(lParam);
+ oldval = dbv.pszVal[0];
+ newval = dbv.pszVal[0] = ((oldval & ~HIWORD(lParam)) | flags) & 0x7f;
+ DBWriteContactSettingStringUtf(NULL, "CListGroups", idstr, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ if ((oldval & GROUPF_HIDEOFFLINE) != (newval & GROUPF_HIDEOFFLINE))
+ cli.pfnLoadContactTree();
+ return 0;
+}
+
+static INT_PTR MoveGroupBefore(WPARAM wParam, LPARAM lParam)
+{
+ int i, shuffleFrom, shuffleTo, shuffleDir;
+ char str[33];
+ TCHAR *szMoveName;
+ DBVARIANT dbv;
+
+ if (wParam == 0 || (LPARAM) wParam == lParam)
+ return 0;
+ _itoa(wParam - 1, str, 10);
+ if (DBGetContactSettingTString(NULL, "CListGroups", str, &dbv))
+ return 0;
+ szMoveName = dbv.ptszVal;
+ //shuffle list of groups up to fill gap
+ if (lParam == 0) {
+ shuffleFrom = wParam - 1;
+ shuffleTo = -1;
+ shuffleDir = -1;
+ }
+ else {
+ if ((LPARAM) wParam < lParam) {
+ shuffleFrom = wParam - 1;
+ shuffleTo = lParam - 2;
+ shuffleDir = -1;
+ }
+ else {
+ shuffleFrom = wParam - 1;
+ shuffleTo = lParam - 1;
+ shuffleDir = 1;
+ }
+ }
+ if (shuffleDir == -1) {
+ for (i = shuffleFrom; i != shuffleTo; i++) {
+ _itoa(i + 1, str, 10);
+ if (DBGetContactSettingStringUtf(NULL, "CListGroups", str, &dbv)) {
+ shuffleTo = i;
+ break;
+ }
+ _itoa(i, str, 10);
+ DBWriteContactSettingStringUtf(NULL, "CListGroups", str, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ }
+ else {
+ for (i = shuffleFrom; i != shuffleTo; i--) {
+ _itoa(i - 1, str, 10);
+ if (DBGetContactSettingStringUtf(NULL, "CListGroups", str, &dbv)) {
+ mir_free(szMoveName);
+ return 1;
+ } //never happens
+ _itoa(i, str, 10);
+ DBWriteContactSettingStringUtf(NULL, "CListGroups", str, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ }
+ _itoa(shuffleTo, str, 10);
+ DBWriteContactSettingTString(NULL, "CListGroups", str, szMoveName);
+ mir_free(szMoveName);
+ return shuffleTo + 1;
+}
+
+static INT_PTR BuildGroupMenu(WPARAM, LPARAM)
+{
+ char idstr[33];
+ DBVARIANT dbv;
+ int groupId;
+ HMENU hRootMenu, hThisMenu;
+ int nextMenuId = 100;
+ TCHAR *pBackslash, *pNextField, szThisField[128], szThisMenuItem[128];
+ int menuId, compareResult, menuItemCount;
+ MENUITEMINFO mii = { 0 };
+
+ if (DBGetContactSettingStringUtf(NULL, "CListGroups", "0", &dbv))
+ return (INT_PTR) (HMENU) NULL;
+ DBFreeVariant(&dbv);
+ hRootMenu = CreateMenu();
+ for (groupId = 0;; groupId++) {
+ _itoa(groupId, idstr, 10);
+ if (DBGetContactSettingTString(NULL, "CListGroups", idstr, &dbv))
+ break;
+
+ pNextField = dbv.ptszVal + 1;
+ hThisMenu = hRootMenu;
+ mii.cbSize = MENUITEMINFO_V4_SIZE;
+ do {
+ pBackslash = _tcschr(pNextField, '\\');
+ if (pBackslash == NULL) {
+ lstrcpyn(szThisField, pNextField, SIZEOF(szThisField));
+ pNextField = NULL;
+ }
+ else {
+ lstrcpyn(szThisField, pNextField, min( SIZEOF(szThisField), pBackslash - pNextField + 1));
+ pNextField = pBackslash + 1;
+ }
+ compareResult = 1;
+ menuItemCount = GetMenuItemCount(hThisMenu);
+ for (menuId = 0; menuId < menuItemCount; menuId++) {
+ mii.fMask = MIIM_TYPE | MIIM_SUBMENU | MIIM_DATA;
+ mii.cch = SIZEOF(szThisMenuItem);
+ mii.dwTypeData = szThisMenuItem;
+ GetMenuItemInfo(hThisMenu, menuId, TRUE, &mii);
+ compareResult = lstrcmp(szThisField, szThisMenuItem);
+ if (compareResult == 0) {
+ if (pNextField == NULL) {
+ mii.fMask = MIIM_DATA;
+ mii.dwItemData = groupId + 1;
+ SetMenuItemInfo(hThisMenu, menuId, TRUE, &mii);
+ }
+ else {
+ if (mii.hSubMenu == NULL) {
+ mii.fMask = MIIM_SUBMENU;
+ mii.hSubMenu = CreateMenu();
+ SetMenuItemInfo(hThisMenu, menuId, TRUE, &mii);
+ mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_ID;
+ //dwItemData doesn't change
+ mii.fType = MFT_STRING;
+ mii.dwTypeData = TranslateT("This group");
+ mii.wID = nextMenuId++;
+ InsertMenuItem(mii.hSubMenu, 0, TRUE, &mii);
+ mii.fMask = MIIM_TYPE;
+ mii.fType = MFT_SEPARATOR;
+ InsertMenuItem(mii.hSubMenu, 1, TRUE, &mii);
+ }
+ hThisMenu = mii.hSubMenu;
+ }
+ break;
+ }
+ if ((int) mii.dwItemData - 1 > groupId)
+ break;
+ }
+ if (compareResult) {
+ mii.fMask = MIIM_TYPE | MIIM_ID;
+ mii.wID = nextMenuId++;
+ mii.dwTypeData = szThisField;
+ mii.fType = MFT_STRING;
+ if (pNextField) {
+ mii.fMask |= MIIM_SUBMENU;
+ mii.hSubMenu = CreateMenu();
+ }
+ else {
+ mii.fMask |= MIIM_DATA;
+ mii.dwItemData = groupId + 1;
+ }
+ InsertMenuItem(hThisMenu, menuId, TRUE, &mii);
+ if (pNextField) {
+ hThisMenu = mii.hSubMenu;
+ }
+ }
+ } while (pNextField);
+
+ DBFreeVariant(&dbv);
+ }
+ return (INT_PTR) hRootMenu;
+}
+
+int InitGroupServices(void)
+{
+ for (int i = 0; ; i++)
+ {
+ char str[32];
+ _itoa(i, str, 10);
+
+ DBVARIANT dbv;
+ if (DBGetContactSettingStringUtf(NULL, "CListGroups", str, &dbv))
+ break;
+ if (dbv.pszVal[0] & 0x80)
+ {
+ dbv.pszVal[0] &= 0x7f;
+ DBWriteContactSettingStringUtf(NULL, "CListGroups", str, dbv.pszVal);
+ }
+ DBFreeVariant(&dbv);
+ }
+
+ CreateServiceFunction(MS_CLIST_GROUPCREATE, CreateGroup);
+ CreateServiceFunction(MS_CLIST_GROUPDELETE, DeleteGroup);
+ CreateServiceFunction(MS_CLIST_GROUPRENAME, RenameGroup);
+ CreateServiceFunction(MS_CLIST_GROUPGETNAME, GetGroupName);
+ CreateServiceFunction(MS_CLIST_GROUPGETNAME2, GetGroupName2);
+ CreateServiceFunction(MS_CLIST_GROUPSETEXPANDED, SetGroupExpandedState);
+ CreateServiceFunction(MS_CLIST_GROUPSETFLAGS, SetGroupFlags);
+ CreateServiceFunction(MS_CLIST_GROUPMOVEBEFORE, MoveGroupBefore);
+ CreateServiceFunction(MS_CLIST_GROUPBUILDMENU, BuildGroupMenu);
+
+ hGroupChangeEvent = CreateHookableEvent( ME_CLIST_GROUPCHANGE );
+
+ return 0;
+}
diff --git a/src/modules/clist/keyboard.cpp b/src/modules/clist/keyboard.cpp
new file mode 100644
index 0000000000..2c9cdce69c
--- /dev/null
+++ b/src/modules/clist/keyboard.cpp
@@ -0,0 +1,173 @@
+/*
+
+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 "clc.h"
+#include <m_hotkeys.h>
+
+static INT_PTR hkHideShow(WPARAM, LPARAM)
+{
+ cli.pfnShowHide(0,0);
+ return 0;
+}
+/*
+INT_PTR hkSearch(WPARAM wParam,LPARAM lParam)
+{
+ DBVARIANT dbv={0};
+ if(!DBGetContactSettingString(NULL,"CList","SearchUrl",&dbv)) {
+ CallService(MS_UTILS_OPENURL,DBGetContactSettingByte(NULL,"CList","HKSearchNewWnd",0),(LPARAM)dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ return 0;
+}
+*/
+static INT_PTR hkRead(WPARAM, LPARAM)
+{
+ if(cli.pfnEventsProcessTrayDoubleClick(0)==0) return TRUE;
+ SetForegroundWindow(cli.hwndContactList);
+ SetFocus(cli.hwndContactList);
+ return 0;
+}
+
+static INT_PTR hkOpts(WPARAM, LPARAM)
+{
+ CallService("Options/OptionsCommand",0, 0);
+ return 0;
+}
+/*
+static INT_PTR hkCloseMiranda(WPARAM wParam,LPARAM lParam)
+{
+ CallService("CloseAction", 0, 0);
+ return 0;
+}
+
+INT_PTR hkRestoreStatus(WPARAM wParam,LPARAM lParam)
+{
+ int nStatus = DBGetContactSettingWord(NULL, "CList", "Status", ID_STATUS_OFFLINE);
+ CallService(MS_CLIST_SETSTATUSMODE, nStatus, 0);
+ return 0;
+}
+
+static INT_PTR hkAllOffline(WPARAM, LPARAM)
+{
+ CallService(MS_CLIST_SETSTATUSMODE, ID_STATUS_OFFLINE, 0);
+ return 0;
+}
+*/
+int InitClistHotKeys(void)
+{
+ HOTKEYDESC shk = {0};
+
+ CreateServiceFunction("CLIST/HK/SHOWHIDE",hkHideShow);
+ CreateServiceFunction("CLIST/HK/Opts",hkOpts);
+ CreateServiceFunction("CLIST/HK/Read",hkRead);
+// CreateServiceFunction("CLIST/HK/CloseMiranda",hkCloseMiranda);
+// CreateServiceFunction("CLIST/HK/RestoreStatus",hkRestoreStatus);
+// CreateServiceFunction("CLIST/HK/AllOffline",hkAllOffline);
+
+ shk.cbSize=sizeof(shk);
+ shk.pszDescription="Show Hide Contact List";
+ shk.pszName="ShowHide";
+ shk.pszSection="Main";
+ shk.pszService="CLIST/HK/SHOWHIDE";
+ shk.DefHotKey = HOTKEYCODE(HOTKEYF_CONTROL|HOTKEYF_SHIFT, 'A');
+ CallService(MS_HOTKEY_REGISTER,0,(LPARAM)&shk);
+
+ shk.pszDescription="Read Message";
+ shk.pszName="ReadMessage";
+ shk.pszSection="Main";
+ shk.pszService="CLIST/HK/Read";
+ shk.DefHotKey = HOTKEYCODE(HOTKEYF_CONTROL|HOTKEYF_SHIFT, 'I');
+ CallService(MS_HOTKEY_REGISTER,0,(LPARAM)&shk);
+/*
+ shk.pszDescription="Search in site";
+ shk.pszName="SearchInWeb";
+ shk.pszSection="Main";
+ shk.pszService="CLIST/HK/Search";
+ shk.DefHotKey=846;
+ CallService(MS_HOTKEY_REGISTER,0,(LPARAM)&shk);
+*/
+ shk.pszDescription = "Open Options Page";
+ shk.pszName = "ShowOptions";
+ shk.pszSection = "Main";
+ shk.pszService = "CLIST/HK/Opts";
+ shk.DefHotKey = HOTKEYCODE(HOTKEYF_CONTROL|HOTKEYF_SHIFT, 'O') | HKF_MIRANDA_LOCAL;
+ CallService(MS_HOTKEY_REGISTER,0,(LPARAM)&shk);
+
+ shk.pszDescription = "Open Logging Options";
+ shk.pszName = "ShowLogOptions";
+ shk.pszSection = "Main";
+ shk.pszService = "Netlib/Log/Win";
+ shk.DefHotKey = 0;
+ CallService(MS_HOTKEY_REGISTER,0,(LPARAM)&shk);
+
+ shk.pszDescription="Open Find User Dialog";
+ shk.pszName="FindUsers";
+ shk.pszSection="Main";
+ shk.pszService="FindAdd/FindAddCommand";
+ shk.DefHotKey = HOTKEYCODE(HOTKEYF_CONTROL|HOTKEYF_SHIFT, 'F') | HKF_MIRANDA_LOCAL;
+ CallService(MS_HOTKEY_REGISTER,0,(LPARAM)&shk);
+
+/*
+ shk.pszDescription="Close Miranda";
+ shk.pszName="CloseMiranda";
+ shk.pszSection="Main";
+ shk.pszService="CLIST/HK/CloseMiranda";
+ shk.DefHotKey=0;
+ CallService(MS_HOTKEY_REGISTER,0,(LPARAM)&shk);
+
+ shk.pszDescription="Restore last status";
+ shk.pszName="RestoreLastStatus";
+ shk.pszSection="Status";
+ shk.pszService="CLIST/HK/RestoreStatus";
+ shk.DefHotKey=0;
+ CallService(MS_HOTKEY_REGISTER,0,(LPARAM)&shk);
+
+ shk.pszDescription="Set All Offline";
+ shk.pszName="AllOffline";
+ shk.pszSection="Status";
+ shk.pszService="CLIST/HK/AllOffline";
+ shk.DefHotKey=0;
+ CallService(MS_HOTKEY_REGISTER,0,(LPARAM)&shk);
+*/
+ return 0;
+}
+
+
+int fnHotKeysRegister(HWND)
+{
+ return 0;
+}
+
+void fnHotKeysUnregister(HWND)
+{
+}
+
+int fnHotKeysProcess(HWND, WPARAM, LPARAM)
+{
+ return TRUE;
+}
+
+int fnHotkeysProcessMessage(WPARAM, LPARAM)
+{
+ return FALSE;
+}
diff --git a/src/modules/clist/movetogroup.cpp b/src/modules/clist/movetogroup.cpp
new file mode 100644
index 0000000000..9924bef2aa
--- /dev/null
+++ b/src/modules/clist/movetogroup.cpp
@@ -0,0 +1,160 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2010 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"
+
+HANDLE hOnCntMenuBuild;
+HGENMENU hMoveToGroupItem=0, hPriorityItem = 0, hFloatingItem = 0;
+
+LIST<HANDLE> lphGroupsItems(5);
+
+//service
+//wparam - hcontact
+//lparam .popupposition from CLISTMENUITEM
+
+#define MTG_MOVE "MoveToGroup/Move"
+
+struct GroupItemSort
+{
+ TCHAR* name;
+ int position;
+
+ GroupItemSort(TCHAR* pname, int pos)
+ : name(mir_tstrdup(pname)), position(pos) {}
+
+ ~GroupItemSort() { mir_free(name); }
+
+ static int compare(const GroupItemSort* d1, const GroupItemSort* d2)
+ { return _tcscoll(d1->name, d2->name); }
+};
+
+static TCHAR* PrepareGroupName( TCHAR* str )
+{
+ TCHAR* p = _tcschr( str, '&' ), *d;
+ if ( p == NULL )
+ return mir_tstrdup( str );
+
+ d = p = ( TCHAR* )mir_alloc( sizeof( TCHAR )*( 2*_tcslen( str )+1 ));
+ while ( *str ) {
+ if ( *str == '&' )
+ *d++ = '&';
+ *d++ = *str++;
+ }
+
+ *d++ = 0;
+ return p;
+}
+
+static void AddGroupItem(HGENMENU hRoot, TCHAR* name, int pos, WPARAM param, bool checked)
+{
+ CLISTMENUITEM mi = { 0 };
+ mi.cbSize = sizeof(mi);
+ mi.hParentMenu = hRoot;
+ mi.popupPosition = param; // param to pszService - only with CMIF_CHILDPOPUP !!!!!!
+ mi.position = pos;
+ mi.ptszName = PrepareGroupName( name );
+ mi.flags = CMIF_ROOTHANDLE | CMIF_TCHAR | CMIF_KEEPUNTRANSLATED;
+ if ( checked )
+ mi.flags |= CMIF_CHECKED;
+ mi.pszService = MTG_MOVE;
+ HANDLE result = ( HANDLE )CallService(MS_CLIST_ADDCONTACTMENUITEM, param, (LPARAM)&mi);
+ mir_free( mi.ptszName );
+
+ lphGroupsItems.insert((HANDLE*)result);
+}
+
+static int OnContactMenuBuild(WPARAM wParam,LPARAM)
+{
+ int i;
+ OBJLIST<GroupItemSort> groups(10, GroupItemSort::compare);
+
+ if (!hMoveToGroupItem)
+ {
+ CLISTMENUITEM mi = {0};
+
+ mi.cbSize = sizeof(mi);
+ mi.position = 100000;
+ mi.pszName = LPGEN("&Move to Group");
+ mi.flags = CMIF_ROOTHANDLE | CMIF_ICONFROMICOLIB;
+ mi.icolibItem = GetSkinIconHandle(SKINICON_OTHER_GROUP);
+
+ hMoveToGroupItem = (HGENMENU)CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM)&mi);
+ }
+
+ for (i = 0; i < lphGroupsItems.getCount(); i++)
+ CallService(MS_CLIST_REMOVECONTACTMENUITEM, (WPARAM)lphGroupsItems[i], 0);
+ lphGroupsItems.destroy();
+
+ TCHAR *szContactGroup = DBGetStringT((HANDLE)wParam, "CList", "Group");
+
+ int pos = 1000;
+
+ AddGroupItem(hMoveToGroupItem, TranslateT("<Root Group>"), pos, -1, !szContactGroup);
+
+ pos += 100000; // Separator
+
+ for (i = 0; ; ++i)
+ {
+ char intname[20];
+ _itoa(i, intname, 10);
+
+ DBVARIANT dbv;
+ if (DBGetContactSettingTString(NULL, "CListGroups", intname, &dbv))
+ break;
+
+ if (dbv.ptszVal[0])
+ groups.insert(new GroupItemSort(dbv.ptszVal + 1, i + 1));
+
+ mir_free(dbv.ptszVal);
+ }
+
+ for (i = 0; i < groups.getCount(); ++i)
+ {
+ bool checked = szContactGroup && !_tcscmp(szContactGroup, groups[i].name);
+ AddGroupItem(hMoveToGroupItem, groups[i].name, ++pos, groups[i].position, checked);
+ }
+
+ groups.destroy();
+ mir_free(szContactGroup);
+
+ return 0;
+}
+
+static INT_PTR MTG_DOMOVE(WPARAM wParam,LPARAM lParam)
+{
+ CallService(MS_CLIST_CONTACTCHANGEGROUP, wParam, lParam < 0 ? 0 : lParam);
+ return 0;
+}
+
+void MTG_OnmodulesLoad()
+{
+ hOnCntMenuBuild=HookEvent(ME_CLIST_PREBUILDCONTACTMENU,OnContactMenuBuild);
+ CreateServiceFunction(MTG_MOVE,MTG_DOMOVE);
+}
+
+int UnloadMoveToGroup(void)
+{
+ UnhookEvent(hOnCntMenuBuild);
+ lphGroupsItems.destroy();
+
+ return 0;
+}
diff --git a/src/modules/clist/protocolorder.cpp b/src/modules/clist/protocolorder.cpp
new file mode 100644
index 0000000000..ff77babfec
--- /dev/null
+++ b/src/modules/clist/protocolorder.cpp
@@ -0,0 +1,351 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2010 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.
+*/
+
+// options dialog for protocol order and visibility
+// written by daniel vijge
+// gpl license ect...
+
+#include "commonheaders.h"
+#include "clc.h"
+
+typedef struct tagProtocolData
+{
+ char *RealName;
+ int protopos;
+ int show, enabled;
+}
+ ProtocolData;
+
+struct ProtocolOrderData
+{
+ int dragging;
+ HTREEITEM hDragItem;
+};
+
+typedef struct {
+ char* protoName;
+ int visible;
+}
+ tempProtoItem;
+
+int isProtoSuitable( PROTO_INTERFACE* ppi )
+{
+ if ( ppi == NULL )
+ return TRUE;
+
+ return ppi->GetCaps( PFLAGNUM_2, 0 ) & ~ppi->GetCaps( PFLAGNUM_5, 0 );
+}
+
+bool CheckProtocolOrder(void)
+{
+ bool changed = false;
+ int i, id = 0;
+
+ for (;;)
+ {
+ // Find account with this id
+ for (i = 0; i < accounts.getCount(); i++)
+ if (accounts[i]->iOrder == id) break;
+
+ // Account with id not found
+ if (i == accounts.getCount())
+ {
+ // Check if this is skipped id, if it is decrement all other ids
+ bool found = false;
+ for (i = 0; i < accounts.getCount(); i++)
+ {
+ if (accounts[i]->iOrder < 1000000 && accounts[i]->iOrder > id)
+ {
+ --accounts[i]->iOrder;
+ found = true;
+ }
+ }
+ if (found) changed = true;
+ else break;
+ }
+ else
+ ++id;
+ }
+
+ if (id < accounts.getCount())
+ {
+ // Remove huge ids
+ for (i = 0; i < accounts.getCount(); i++)
+ {
+ if (accounts[i]->iOrder >= 1000000)
+ accounts[i]->iOrder = id++;
+ }
+ changed = true;
+ }
+
+ if (id < accounts.getCount())
+ {
+ // Remove duplicate ids
+ for (i = 0; i < accounts.getCount(); i++)
+ {
+ bool found = false;
+ for (int j = 0; j < accounts.getCount(); j++)
+ {
+ if (accounts[j]->iOrder == i)
+ {
+ if (found) accounts[j]->iOrder = id++;
+ else found = true;
+ }
+ }
+ }
+ changed = true;
+ }
+
+ return changed;
+}
+
+
+int FillTree(HWND hwnd)
+{
+ ProtocolData *PD;
+ int i;
+ PROTOACCOUNT* pa;
+
+ TVINSERTSTRUCT tvis;
+ tvis.hParent = NULL;
+ tvis.hInsertAfter = TVI_LAST;
+ tvis.item.mask = TVIF_PARAM|TVIF_TEXT|TVIF_IMAGE|TVIF_SELECTEDIMAGE;
+
+ TreeView_DeleteAllItems(hwnd);
+ if ( accounts.getCount() == 0 )
+ return FALSE;
+
+ for ( i = 0; i < accounts.getCount(); i++ ) {
+ int idx = cli.pfnGetAccountIndexByPos( i );
+ if ( idx == -1 )
+ continue;
+
+ pa = accounts[idx];
+
+ PD = ( ProtocolData* )mir_alloc( sizeof( ProtocolData ));
+ PD->RealName = pa->szModuleName;
+ PD->protopos = pa->iOrder;
+ PD->enabled = Proto_IsAccountEnabled( pa ) && isProtoSuitable( pa->ppro );
+ PD->show = PD->enabled ? pa->bIsVisible : 100;
+
+ tvis.item.lParam = ( LPARAM )PD;
+ tvis.item.pszText = pa->tszAccountName;
+ tvis.item.iImage = tvis.item.iSelectedImage = PD->show;
+ TreeView_InsertItem( hwnd, &tvis );
+ }
+
+ return 0;
+}
+
+INT_PTR CALLBACK ProtocolOrderOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ HWND hwndProtoOrder = GetDlgItem(hwndDlg, IDC_PROTOCOLORDER);
+ struct ProtocolOrderData *dat = (ProtocolOrderData*)GetWindowLongPtr(hwndProtoOrder, GWLP_USERDATA);
+
+ switch (msg)
+ {
+ case WM_DESTROY:
+ ImageList_Destroy(TreeView_GetImageList(hwndProtoOrder, TVSIL_NORMAL));
+ mir_free( dat );
+ break;
+
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ dat = (ProtocolOrderData*)mir_calloc(sizeof(ProtocolOrderData));
+ SetWindowLongPtr(hwndProtoOrder, GWLP_USERDATA, (LONG_PTR)dat);
+ dat->dragging=0;
+
+ SetWindowLong(hwndProtoOrder, GWL_STYLE, GetWindowLong(hwndProtoOrder, GWL_STYLE) | TVS_NOHSCROLL);
+ {
+ HIMAGELIST himlCheckBoxes = ImageList_Create( GetSystemMetrics( SM_CXSMICON ), GetSystemMetrics( SM_CYSMICON ), ILC_COLOR32|ILC_MASK, 2, 2 );
+ ImageList_AddIcon_IconLibLoaded(himlCheckBoxes, SKINICON_OTHER_NOTICK);
+ ImageList_AddIcon_IconLibLoaded(himlCheckBoxes, SKINICON_OTHER_TICK);
+ TreeView_SetImageList(hwndProtoOrder, himlCheckBoxes, TVSIL_NORMAL);
+ }
+
+ FillTree(hwndProtoOrder);
+ return TRUE;
+
+ case WM_COMMAND:
+ if (LOWORD(wParam) == IDC_RESETPROTOCOLDATA && HIWORD(wParam) == BN_CLICKED)
+ {
+ for ( int i = 0; i < accounts.getCount(); i++ )
+ accounts[i]->iOrder = i;
+
+ FillTree(hwndProtoOrder);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, (WPARAM)hwndDlg, 0);
+ }
+ break;
+
+ case WM_NOTIFY:
+ switch(((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ if (((LPNMHDR)lParam)->code == PSN_APPLY ) {
+ int count = 0;
+
+ TVITEM tvi;
+ tvi.hItem = TreeView_GetRoot(hwndProtoOrder);
+ tvi.cchTextMax = 32;
+ tvi.mask = TVIF_PARAM | TVIF_HANDLE;
+
+ while ( tvi.hItem != NULL ) {
+ TreeView_GetItem(hwndProtoOrder, &tvi);
+
+ if (tvi.lParam!=0) {
+ ProtocolData* ppd = ( ProtocolData* )tvi.lParam;
+ PROTOACCOUNT* pa = Proto_GetAccount( ppd->RealName );
+ if ( pa != NULL ) {
+ pa->iOrder = count++;
+ if ( ppd->enabled )
+ pa->bIsVisible = ppd->show;
+ }
+ }
+
+ tvi.hItem = TreeView_GetNextSibling(hwndProtoOrder, tvi.hItem );
+ }
+
+ WriteDbAccounts();
+ cli.pfnReloadProtoMenus();
+ cli.pfnTrayIconIconsChanged();
+ cli.pfnClcBroadcast( INTM_RELOADOPTIONS, 0, 0 );
+ cli.pfnClcBroadcast( INTM_INVALIDATE, 0, 0 );
+ }
+ break;
+
+ case IDC_PROTOCOLORDER:
+ switch (((LPNMHDR)lParam)->code) {
+ case TVN_DELETEITEMA:
+ {
+ NMTREEVIEWA * pnmtv = (NMTREEVIEWA *) lParam;
+ if (pnmtv && pnmtv->itemOld.lParam)
+ mir_free((ProtocolData*)pnmtv->itemOld.lParam);
+ }
+ break;
+
+ case TVN_BEGINDRAGA:
+ SetCapture(hwndDlg);
+ dat->dragging=1;
+ dat->hDragItem=((LPNMTREEVIEW)lParam)->itemNew.hItem;
+ TreeView_SelectItem(hwndProtoOrder, dat->hDragItem);
+ break;
+
+ case NM_CLICK:
+ {
+ TVHITTESTINFO hti;
+ hti.pt.x=(short)LOWORD(GetMessagePos());
+ hti.pt.y=(short)HIWORD(GetMessagePos());
+ ScreenToClient(((LPNMHDR)lParam)->hwndFrom,&hti.pt);
+ if ( TreeView_HitTest(((LPNMHDR)lParam)->hwndFrom, &hti )) {
+ if ( hti.flags & TVHT_ONITEMICON ) {
+ TVITEMA tvi;
+ tvi.mask = TVIF_HANDLE|TVIF_IMAGE|TVIF_SELECTEDIMAGE;
+ tvi.hItem = hti.hItem;
+ TreeView_GetItem(((LPNMHDR)lParam)->hwndFrom,&tvi);
+
+ ProtocolData *pData = ( ProtocolData* )tvi.lParam;
+ if ( pData->enabled ) {
+ tvi.iImage = tvi.iSelectedImage = !tvi.iImage;
+ pData->show = tvi.iImage;
+ TreeView_SetItem(((LPNMHDR)lParam)->hwndFrom,&tvi);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, (WPARAM)hwndDlg, 0);
+ } } } } }
+ break;
+ }
+ break;
+
+ case WM_MOUSEMOVE:
+ if ( dat->dragging ) {
+ TVHITTESTINFO hti;
+ hti.pt.x=(short)LOWORD(lParam);
+ hti.pt.y=(short)HIWORD(lParam);
+ ClientToScreen(hwndDlg, &hti.pt);
+ ScreenToClient(hwndProtoOrder, &hti.pt);
+ TreeView_HitTest(hwndProtoOrder, &hti);
+ if ( hti.flags & (TVHT_ONITEM|TVHT_ONITEMRIGHT ))
+ {
+ HTREEITEM it = hti.hItem;
+ hti.pt.y -= TreeView_GetItemHeight(hwndProtoOrder) / 2;
+ TreeView_HitTest(hwndProtoOrder, &hti);
+ if ( !( hti.flags & TVHT_ABOVE ))
+ TreeView_SetInsertMark(hwndProtoOrder, hti.hItem, 1);
+ else
+ TreeView_SetInsertMark(hwndProtoOrder, it, 0);
+ }
+ else {
+ if (hti.flags&TVHT_ABOVE) SendMessage(hwndProtoOrder, WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), 0);
+ if (hti.flags&TVHT_BELOW) SendMessage(hwndProtoOrder, WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), 0);
+ TreeView_SetInsertMark(hwndProtoOrder, NULL, 0);
+ } }
+ break;
+
+ case WM_LBUTTONUP:
+ if ( dat->dragging ) {
+ TVHITTESTINFO hti;
+ TVITEM tvi;
+
+ TreeView_SetInsertMark(hwndProtoOrder, NULL, 0);
+ dat->dragging = 0;
+ ReleaseCapture();
+
+ hti.pt.x = (short)LOWORD(lParam);
+ hti.pt.y = (short)HIWORD(lParam);
+ ClientToScreen(hwndDlg, &hti.pt);
+ ScreenToClient(hwndProtoOrder, &hti.pt);
+ hti.pt.y -= TreeView_GetItemHeight(hwndProtoOrder) / 2;
+ TreeView_HitTest(hwndProtoOrder, &hti);
+ if (dat->hDragItem == hti.hItem) break;
+ if (hti.flags & TVHT_ABOVE) hti.hItem = TVI_FIRST;
+ tvi.mask = TVIF_HANDLE|TVIF_PARAM;
+ tvi.hItem = dat->hDragItem;
+ TreeView_GetItem(hwndProtoOrder, &tvi);
+ if ( hti.flags & (TVHT_ONITEM | TVHT_ONITEMRIGHT) || (hti.hItem == TVI_FIRST))
+ {
+ TVINSERTSTRUCT tvis;
+ TCHAR name[128];
+ ProtocolData * lpOldData;
+ tvis.item.mask = TVIF_HANDLE|TVIF_PARAM|TVIF_TEXT|TVIF_IMAGE|TVIF_SELECTEDIMAGE;
+ tvis.item.stateMask = 0xFFFFFFFF;
+ tvis.item.pszText = name;
+ tvis.item.cchTextMax = SIZEOF(name);
+ tvis.item.hItem = dat->hDragItem;
+ tvis.item.iImage = tvis.item.iSelectedImage = ((ProtocolData *)tvi.lParam)->show;
+ TreeView_GetItem(hwndProtoOrder, &tvis.item);
+
+ //the pointed lParam will be freed inside TVN_DELETEITEM
+ //so lets substitute it with 0
+ lpOldData=(ProtocolData *)tvis.item.lParam;
+ tvis.item.lParam=0;
+ TreeView_SetItem(hwndProtoOrder, &tvis.item);
+ tvis.item.lParam=(LPARAM)lpOldData;
+
+ //now current item contain lParam=0 we can delete it. the memory will be kept.
+ TreeView_DeleteItem(hwndProtoOrder, dat->hDragItem);
+ tvis.hParent = NULL;
+ tvis.hInsertAfter = hti.hItem;
+ TreeView_SelectItem(hwndProtoOrder, TreeView_InsertItem(hwndProtoOrder, &tvis));
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, (WPARAM)hwndDlg, 0);
+ } }
+ break;
+ }
+ return FALSE;
+}
diff --git a/src/modules/contacts/contacts.cpp b/src/modules/contacts/contacts.cpp
new file mode 100644
index 0000000000..f8bc787286
--- /dev/null
+++ b/src/modules/contacts/contacts.cpp
@@ -0,0 +1,513 @@
+/*
+Miranda IM
+
+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 NAMEORDERCOUNT 8
+static TCHAR* nameOrderDescr[ NAMEORDERCOUNT ] =
+{
+ _T( "My custom name (not moveable)" ),
+ _T( "Nick" ),
+ _T( "FirstName" ),
+ _T( "E-mail" ),
+ _T( "LastName" ),
+ _T( "Username" ),
+ _T( "FirstName LastName" ),
+ _T( "'(Unknown Contact)' (not moveable)" )
+};
+
+BYTE nameOrder[NAMEORDERCOUNT];
+
+static int GetDatabaseString( CONTACTINFO *ci, const char* setting, DBVARIANT* dbv )
+{
+ if (strcmp(ci->szProto, "CList") && CallProtoService(ci->szProto, PS_GETCAPS, PFLAGNUM_4, 0) & PF4_INFOSETTINGSVC)
+ {
+ DBCONTACTGETSETTING cgs = { ci->szProto, setting, dbv };
+ dbv->type = (ci->dwFlag & CNF_UNICODE) ? DBVT_WCHAR : DBVT_ASCIIZ;
+
+ int res = CallProtoService(ci->szProto, PS_GETINFOSETTING, (WPARAM)ci->hContact, (LPARAM)&cgs);
+ if (res != CALLSERVICE_NOTFOUND) return res;
+ }
+
+ if ( ci->dwFlag & CNF_UNICODE )
+ return DBGetContactSettingWString(ci->hContact,ci->szProto,setting,dbv);
+
+ return DBGetContactSettingString(ci->hContact,ci->szProto,setting,dbv);
+}
+
+static int ProcessDatabaseValueDefault(CONTACTINFO *ci, const char* setting)
+{
+ DBVARIANT dbv;
+ if ( !GetDatabaseString( ci, setting, &dbv )) {
+ switch (dbv.type) {
+ case DBVT_ASCIIZ:
+ if (!dbv.pszVal[0]) break;
+ case DBVT_WCHAR:
+ if (!dbv.pwszVal[0]) break;
+ ci->type = CNFT_ASCIIZ;
+ ci->pszVal = dbv.ptszVal;
+ return 0;
+ }
+ DBFreeVariant( &dbv );
+ }
+
+ if ( DBGetContactSetting( ci->hContact, ci->szProto, setting, &dbv ))
+ return 1;
+
+ switch (dbv.type) {
+ case DBVT_BYTE:
+ ci->type = CNFT_BYTE;
+ ci->bVal = dbv.bVal;
+ return 0;
+ case DBVT_WORD:
+ ci->type = CNFT_WORD;
+ ci->wVal = dbv.wVal;
+ return 0;
+ case DBVT_DWORD:
+ ci->type = CNFT_DWORD;
+ ci->dVal = dbv.dVal;
+ return 0;
+ }
+
+ DBFreeVariant( &dbv );
+ return 1;
+}
+
+static INT_PTR GetContactInfo(WPARAM, LPARAM lParam) {
+ DBVARIANT dbv;
+ CONTACTINFO *ci = (CONTACTINFO*)lParam;
+
+ if (ci==NULL) return 1;
+ if (ci->szProto==NULL) ci->szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEACCOUNT,(WPARAM)ci->hContact,0);
+ if (ci->szProto==NULL) return 1;
+ ci->type = 0;
+ switch(ci->dwFlag & 0x7F) {
+ case CNF_FIRSTNAME: return ProcessDatabaseValueDefault( ci, "FirstName" );
+ case CNF_LASTNAME: return ProcessDatabaseValueDefault( ci, "LastName" );
+ case CNF_NICK: return ProcessDatabaseValueDefault( ci, "Nick" );
+ case CNF_EMAIL: return ProcessDatabaseValueDefault( ci, "e-mail" );
+ case CNF_CITY: return ProcessDatabaseValueDefault( ci, "City" );
+ case CNF_STATE: return ProcessDatabaseValueDefault( ci, "State" );
+ case CNF_PHONE: return ProcessDatabaseValueDefault( ci, "Phone" );
+ case CNF_HOMEPAGE: return ProcessDatabaseValueDefault( ci, "Homepage" );
+ case CNF_ABOUT: return ProcessDatabaseValueDefault( ci, "About" );
+ case CNF_AGE: return ProcessDatabaseValueDefault( ci, "Age" );
+ case CNF_GENDER: return ProcessDatabaseValueDefault( ci, "Gender" );
+ case CNF_FAX: return ProcessDatabaseValueDefault( ci, "Fax" );
+ case CNF_CELLULAR: return ProcessDatabaseValueDefault( ci, "Cellular" );
+ case CNF_BIRTHDAY: return ProcessDatabaseValueDefault( ci, "BirthDay" );
+ case CNF_BIRTHMONTH: return ProcessDatabaseValueDefault( ci, "BirthMonth" );
+ case CNF_BIRTHYEAR: return ProcessDatabaseValueDefault( ci, "BirthYear" );
+ case CNF_STREET: return ProcessDatabaseValueDefault( ci, "Street" );
+ case CNF_ZIP: return ProcessDatabaseValueDefault( ci, "ZIP" );
+ case CNF_LANGUAGE1: return ProcessDatabaseValueDefault( ci, "Language1" );
+ case CNF_LANGUAGE2: return ProcessDatabaseValueDefault( ci, "Language2" );
+ case CNF_LANGUAGE3: return ProcessDatabaseValueDefault( ci, "Language3" );
+ case CNF_CONAME: return ProcessDatabaseValueDefault( ci, "Company" );
+ case CNF_CODEPT: return ProcessDatabaseValueDefault( ci, "CompanyDepartment" );
+ case CNF_COPOSITION: return ProcessDatabaseValueDefault( ci, "CompanyPosition" );
+ case CNF_COSTREET: return ProcessDatabaseValueDefault( ci, "CompanyStreet" );
+ case CNF_COCITY: return ProcessDatabaseValueDefault( ci, "CompanyCity" );
+ case CNF_COSTATE: return ProcessDatabaseValueDefault( ci, "CompanyState" );
+ case CNF_COZIP: return ProcessDatabaseValueDefault( ci, "CompanyZIP" );
+ case CNF_COHOMEPAGE: return ProcessDatabaseValueDefault( ci, "CompanyHomepage" );
+
+ case CNF_CUSTOMNICK:
+ {
+ char* saveProto = ci->szProto; ci->szProto = "CList";
+ if ( ci->hContact != NULL && !ProcessDatabaseValueDefault( ci, "MyHandle" )) {
+ ci->szProto = saveProto;
+ return 0;
+ }
+ ci->szProto = saveProto;
+ break;
+ }
+ case CNF_COUNTRY:
+ case CNF_COCOUNTRY:
+ if ( !GetDatabaseString( ci, (ci->dwFlag & 0x7F) == CNF_COUNTRY ? "CountryName" : "CompanyCountryName", &dbv ))
+ return 0;
+
+ if ( !DBGetContactSetting( ci->hContact, ci->szProto, (ci->dwFlag & 0x7F)==CNF_COUNTRY ? "Country" : "CompanyCountry", &dbv )) {
+ if ( dbv.type == DBVT_WORD ) {
+ int i,countryCount;
+ struct CountryListEntry *countries;
+ CallService(MS_UTILS_GETCOUNTRYLIST,(WPARAM)&countryCount,(LPARAM)&countries);
+ for(i=0;i<countryCount;i++) {
+ if(countries[i].id!=dbv.wVal) continue;
+
+ if ( ci->dwFlag & CNF_UNICODE ) {
+ int cbLen = MultiByteToWideChar( CP_ACP, 0, ( LPCSTR )countries[i].szName, -1, NULL, 0 );
+ WCHAR* buf = ( WCHAR* )mir_alloc( sizeof( WCHAR )*(cbLen+1) );
+ if ( buf != NULL )
+ MultiByteToWideChar( CP_ACP, 0, ( LPCSTR )countries[i].szName, -1, buf, cbLen );
+ ci->pszVal = ( TCHAR* )buf;
+ }
+ else ci->pszVal = ( TCHAR* )mir_strdup(countries[i].szName);
+
+ ci->type = CNFT_ASCIIZ;
+ DBFreeVariant(&dbv);
+ return 0;
+ }
+ }
+ else return ProcessDatabaseValueDefault( ci, (ci->dwFlag & 0x7F)==CNF_COUNTRY ? "Country" : "CompanyCountry" );
+ DBFreeVariant(&dbv);
+ }
+ break;
+
+ case CNF_FIRSTLAST:
+ if( !GetDatabaseString( ci, "FirstName", &dbv )) {
+ DBVARIANT dbv2;
+ if(!GetDatabaseString(ci,"LastName",&dbv2)) {
+ ci->type = CNFT_ASCIIZ;
+ if ( ci->dwFlag & CNF_UNICODE ) {
+ size_t len = wcslen(dbv.pwszVal) + wcslen(dbv2.pwszVal) + 2;
+ WCHAR* buf = ( WCHAR* )mir_alloc( sizeof( WCHAR )*len );
+ if ( buf != NULL )
+ wcscat( wcscat( wcscpy( buf, dbv.pwszVal ), L" " ), dbv2.pwszVal );
+ ci->pszVal = ( TCHAR* )buf;
+ }
+ else {
+ size_t len = strlen(dbv.pszVal) + strlen(dbv2.pszVal) + 2;
+ char* buf = ( char* )mir_alloc( len );
+ if ( buf != NULL )
+ strcat( strcat( strcpy( buf, dbv.pszVal ), " " ), dbv2.pszVal );
+ ci->pszVal = ( TCHAR* )buf;
+ }
+ DBFreeVariant( &dbv );
+ DBFreeVariant( &dbv2 );
+ return 0;
+ }
+ DBFreeVariant( &dbv );
+ }
+ break;
+
+ case CNF_UNIQUEID:
+ {
+ char *uid = (char*)CallProtoService(ci->szProto,PS_GETCAPS,PFLAG_UNIQUEIDSETTING,0);
+ if ((INT_PTR)uid!=CALLSERVICE_NOTFOUND&&uid)
+ if (!ProcessDatabaseValueDefault(ci,uid))
+ return 0;
+
+ break;
+ }
+ case CNF_DISPLAYUID:
+ {
+ if (!ProcessDatabaseValueDefault(ci, "display_uid"))
+ return 0;
+ char *uid = (char*)CallProtoService(ci->szProto,PS_GETCAPS,PFLAG_UNIQUEIDSETTING,0);
+ if ((INT_PTR)uid!=CALLSERVICE_NOTFOUND&&uid)
+ if (!ProcessDatabaseValueDefault(ci,uid))
+ return 0;
+
+ break;
+ }
+ case CNF_DISPLAYNC:
+ case CNF_DISPLAY:
+ {
+ int i;
+ for( i=0; i < NAMEORDERCOUNT; i++ ) {
+ switch(nameOrder[i]) {
+ case 0: // custom name
+ {
+ // make sure we aren't in CNF_DISPLAYNC mode
+ // don't get custom name for NULL contact
+ char* saveProto = ci->szProto; ci->szProto = "CList";
+ if (ci->hContact!=NULL && (ci->dwFlag&0x7F)==CNF_DISPLAY && !ProcessDatabaseValueDefault(ci,"MyHandle")) {
+ ci->szProto = saveProto;
+ return 0;
+ }
+ ci->szProto = saveProto;
+ break;
+ }
+ case 1:
+ if ( !ProcessDatabaseValueDefault( ci, "Nick" )) // nick
+ return 0;
+ break;
+ case 2:
+ if ( !ProcessDatabaseValueDefault( ci, "FirstName" )) // First Name
+ return 0;
+ break;
+ case 3:
+ if ( !ProcessDatabaseValueDefault( ci, "e-mail" )) // E-mail
+ return 0;
+ break;
+ case 4:
+ if ( !ProcessDatabaseValueDefault( ci, "LastName" )) // Last Name
+ return 0;
+ break;
+ case 5: // Unique id
+ {
+ // protocol must define a PFLAG_UNIQUEIDSETTING
+ char *uid = (char*)CallProtoService(ci->szProto,PS_GETCAPS,PFLAG_UNIQUEIDSETTING,0);
+ if ((INT_PTR)uid!=CALLSERVICE_NOTFOUND&&uid) {
+ if (!GetDatabaseString(ci,uid,&dbv)) {
+ if ( dbv.type == DBVT_BYTE || dbv.type == DBVT_WORD || dbv.type == DBVT_DWORD ) {
+ long value = (dbv.type == DBVT_BYTE) ? dbv.bVal:(dbv.type==DBVT_WORD ? dbv.wVal : dbv.dVal);
+ if ( ci->dwFlag & CNF_UNICODE ) {
+ WCHAR buf[ 40 ];
+ _ltow( value, buf, 10 );
+ ci->pszVal = ( TCHAR* )mir_wstrdup( buf );
+ }
+ else {
+ char buf[ 40 ];
+ _ltoa( value, buf, 10 );
+ ci->pszVal = ( TCHAR* )mir_strdup(buf);
+ }
+ ci->type = CNFT_ASCIIZ;
+ return 0;
+ }
+ if (dbv.type == DBVT_ASCIIZ && !(ci->dwFlag & CNF_UNICODE)) {
+ ci->type = CNFT_ASCIIZ;
+ ci->pszVal = dbv.ptszVal;
+ return 0;
+ }
+ if (dbv.type == DBVT_WCHAR && (ci->dwFlag & CNF_UNICODE)) {
+ ci->type = CNFT_ASCIIZ;
+ ci->pszVal = dbv.ptszVal;
+ return 0;
+ } } }
+ break;
+ }
+ case 6: // first + last name
+ if(!GetDatabaseString(ci,"FirstName",&dbv)) {
+ DBVARIANT dbv2;
+ if(!GetDatabaseString(ci,"LastName",&dbv2)) {
+ ci->type = CNFT_ASCIIZ;
+
+ if ( ci->dwFlag & CNF_UNICODE ) {
+ size_t len = wcslen(dbv.pwszVal) + wcslen(dbv2.pwszVal) + 2;
+ WCHAR* buf = ( WCHAR* )mir_alloc( sizeof( WCHAR )*len );
+ if ( buf != NULL )
+ wcscat( wcscat( wcscpy( buf, dbv.pwszVal ), L" " ), dbv2.pwszVal );
+ ci->pszVal = ( TCHAR* )buf;
+ }
+ else {
+ size_t len = strlen(dbv.pszVal) + strlen(dbv2.pszVal) + 2;
+ char* buf = ( char* )mir_alloc( len );
+ if ( buf != NULL )
+ strcat( strcat( strcpy( buf, dbv.pszVal ), " " ), dbv2.pszVal );
+ ci->pszVal = ( TCHAR* )buf;
+ }
+
+ DBFreeVariant( &dbv );
+ DBFreeVariant( &dbv2 );
+ return 0;
+ }
+ DBFreeVariant( &dbv );
+ }
+ break;
+
+ case 7:
+ if ( ci->dwFlag & CNF_UNICODE )
+ ci->pszVal = ( TCHAR* )mir_wstrdup( TranslateW( L"'(Unknown Contact)'" ));
+ else
+ ci->pszVal = ( TCHAR* )mir_strdup( Translate("'(Unknown Contact)'"));
+ ci->type = CNFT_ASCIIZ;
+ return 0;
+ } } }
+ break;
+
+ case CNF_TIMEZONE: {
+ HANDLE hTz = tmi.createByContact(ci->hContact, TZF_KNOWNONLY);
+ if (hTz)
+ {
+ LPTIME_ZONE_INFORMATION tzi = tmi.getTzi(hTz);
+ int offset = tzi->Bias + tzi->StandardBias;
+
+ char str[80];
+ mir_snprintf(str, SIZEOF(str), offset ? "UTC%+d:%02d" : "UTC", offset / -60, abs(offset % 60));
+ ci->pszVal = ci->dwFlag & CNF_UNICODE ? (TCHAR*)mir_a2u(str) : (TCHAR*)mir_strdup(str);
+ ci->type = CNFT_ASCIIZ;
+ return 0;
+ }
+ break;
+ }
+ case CNF_MYNOTES: {
+ char* saveProto = ci->szProto; ci->szProto = "UserInfo";
+ if (!ProcessDatabaseValueDefault(ci,"MyNotes")) {
+ ci->szProto = saveProto;
+ return 0;
+ }
+ ci->szProto = saveProto;
+ break;
+ } }
+
+ return 1;
+}
+
+struct ContactOptionsData {
+ int dragging;
+ HTREEITEM hDragItem;
+};
+
+static INT_PTR CALLBACK ContactOpts(HWND hwndDlg, UINT msg, WPARAM, LPARAM lParam)
+{ struct ContactOptionsData *dat;
+
+ dat=(struct ContactOptionsData*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA);
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ { TranslateDialogDefault(hwndDlg);
+ dat=(struct ContactOptionsData*)mir_alloc(sizeof(struct ContactOptionsData));
+ SetWindowLongPtr(hwndDlg,GWLP_USERDATA,(LONG_PTR)dat);
+ dat->dragging=0;
+ SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_NAMEORDER),GWL_STYLE,GetWindowLongPtr(GetDlgItem(hwndDlg,IDC_NAMEORDER),GWL_STYLE)|TVS_NOHSCROLL);
+ { TVINSERTSTRUCT tvis;
+ int i;
+ tvis.hParent = NULL;
+ tvis.hInsertAfter = TVI_LAST;
+ tvis.item.mask = TVIF_TEXT|TVIF_PARAM;
+ for(i=0; i < SIZEOF(nameOrderDescr); i++ ) {
+ tvis.item.lParam = nameOrder[i];
+ tvis.item.pszText = TranslateTS( nameOrderDescr[ nameOrder[i]] );
+ TreeView_InsertItem( GetDlgItem(hwndDlg,IDC_NAMEORDER), &tvis );
+ } }
+ return TRUE;
+ }
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ if (((LPNMHDR)lParam)->code == PSN_APPLY)
+ { DBCONTACTWRITESETTING cws;
+ TVITEM tvi;
+ int i;
+ cws.szModule = "Contact";
+ cws.szSetting = "NameOrder";
+ cws.value.type = DBVT_BLOB;
+ cws.value.cpbVal = SIZEOF(nameOrderDescr);
+ cws.value.pbVal = nameOrder;
+ tvi.hItem = TreeView_GetRoot(GetDlgItem(hwndDlg,IDC_NAMEORDER));
+ i=0;
+ while( tvi.hItem != NULL ) {
+ tvi.mask = TVIF_PARAM | TVIF_HANDLE;
+ TreeView_GetItem( GetDlgItem(hwndDlg,IDC_NAMEORDER), &tvi );
+ nameOrder[i++] = (BYTE)tvi.lParam;
+ tvi.hItem = TreeView_GetNextSibling(GetDlgItem(hwndDlg,IDC_NAMEORDER),tvi.hItem);
+ }
+ CallService(MS_DB_CONTACT_WRITESETTING,(WPARAM)(HANDLE)NULL,(LPARAM)&cws);
+ CallService(MS_CLIST_INVALIDATEDISPLAYNAME,(WPARAM)INVALID_HANDLE_VALUE,0);
+ }
+ break;
+ case IDC_NAMEORDER:
+ if (((LPNMHDR)lParam)->code == TVN_BEGINDRAGA) {
+ LPNMTREEVIEWA notify = (LPNMTREEVIEWA)lParam;
+ if ( notify->itemNew.lParam==0 || notify->itemNew.lParam == SIZEOF(nameOrderDescr)-1 )
+ break;
+ SetCapture(hwndDlg);
+ dat->dragging=1;
+ dat->hDragItem=((LPNMTREEVIEW)lParam)->itemNew.hItem;
+ TreeView_SelectItem(GetDlgItem(hwndDlg,IDC_NAMEORDER),dat->hDragItem);
+ }
+ break;
+ }
+ break;
+ case WM_MOUSEMOVE:
+ if(!dat->dragging) break;
+ { TVHITTESTINFO hti;
+ hti.pt.x=(short)LOWORD(lParam);
+ hti.pt.y=(short)HIWORD(lParam);
+ ClientToScreen(hwndDlg,&hti.pt);
+ ScreenToClient(GetDlgItem(hwndDlg,IDC_NAMEORDER),&hti.pt);
+ TreeView_HitTest(GetDlgItem(hwndDlg,IDC_NAMEORDER),&hti);
+ if(hti.flags&(TVHT_ONITEM|TVHT_ONITEMRIGHT)) {
+ hti.pt.y-=TreeView_GetItemHeight(GetDlgItem(hwndDlg,IDC_NAMEORDER))/2;
+ TreeView_HitTest(GetDlgItem(hwndDlg,IDC_NAMEORDER),&hti);
+ TreeView_SetInsertMark(GetDlgItem(hwndDlg,IDC_NAMEORDER),hti.hItem,1);
+ }
+ else {
+ if(hti.flags&TVHT_ABOVE) SendDlgItemMessage(hwndDlg,IDC_NAMEORDER,WM_VSCROLL,MAKEWPARAM(SB_LINEUP,0),0);
+ if(hti.flags&TVHT_BELOW) SendDlgItemMessage(hwndDlg,IDC_NAMEORDER,WM_VSCROLL,MAKEWPARAM(SB_LINEDOWN,0),0);
+ TreeView_SetInsertMark(GetDlgItem(hwndDlg,IDC_NAMEORDER),NULL,0);
+ }
+ }
+ break;
+ case WM_LBUTTONUP:
+ if(!dat->dragging) break;
+ TreeView_SetInsertMark(GetDlgItem(hwndDlg,IDC_NAMEORDER),NULL,0);
+ dat->dragging=0;
+ ReleaseCapture();
+ { TVHITTESTINFO hti;
+ TVITEM tvi;
+ hti.pt.x=(short)LOWORD(lParam);
+ hti.pt.y=(short)HIWORD(lParam);
+ ClientToScreen(hwndDlg,&hti.pt);
+ ScreenToClient(GetDlgItem(hwndDlg,IDC_NAMEORDER),&hti.pt);
+ hti.pt.y-=TreeView_GetItemHeight(GetDlgItem(hwndDlg,IDC_NAMEORDER))/2;
+ TreeView_HitTest(GetDlgItem(hwndDlg,IDC_NAMEORDER),&hti);
+ if(dat->hDragItem==hti.hItem) break;
+ tvi.mask=TVIF_HANDLE|TVIF_PARAM;
+ tvi.hItem=hti.hItem;
+ TreeView_GetItem(GetDlgItem(hwndDlg,IDC_NAMEORDER),&tvi);
+ if(tvi.lParam == SIZEOF(nameOrderDescr)-1) break;
+ if(hti.flags&(TVHT_ONITEM|TVHT_ONITEMRIGHT)) {
+ TVINSERTSTRUCT tvis;
+ TCHAR name[128];
+ tvis.item.mask=TVIF_HANDLE|TVIF_PARAM|TVIF_TEXT|TVIF_PARAM;
+ tvis.item.stateMask=0xFFFFFFFF;
+ tvis.item.pszText=name;
+ tvis.item.cchTextMax=SIZEOF(name);
+ tvis.item.hItem=dat->hDragItem;
+ TreeView_GetItem(GetDlgItem(hwndDlg,IDC_NAMEORDER),&tvis.item);
+ TreeView_DeleteItem(GetDlgItem(hwndDlg,IDC_NAMEORDER),dat->hDragItem);
+ tvis.hParent=NULL;
+ tvis.hInsertAfter=hti.hItem;
+ TreeView_SelectItem(GetDlgItem(hwndDlg,IDC_NAMEORDER),TreeView_InsertItem(GetDlgItem(hwndDlg,IDC_NAMEORDER),&tvis));
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ }
+ break;
+ case WM_DESTROY:
+ mir_free(dat);
+ break;
+ }
+ return FALSE;
+}
+
+static int ContactOptInit(WPARAM wParam, LPARAM)
+{
+ OPTIONSDIALOGPAGE odp = { 0 };
+ odp.cbSize = sizeof(odp);
+ odp.position = -1000000000;
+ odp.hInstance = hMirandaInst;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_CONTACT);
+ odp.pszGroup = LPGEN("Customize");
+ odp.pszTitle = LPGEN("Contacts");
+ odp.pfnDlgProc = ContactOpts;
+ odp.flags = ODPF_BOLDGROUPS;
+ CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
+ return 0;
+}
+
+int LoadContactsModule(void) {
+ {
+ // Load the name order
+ BYTE i;
+ DBVARIANT dbv;
+
+ for(i=0; i<NAMEORDERCOUNT; i++)
+ nameOrder[i]=i;
+
+ if(!DBGetContactSetting(NULL,"Contact","NameOrder",&dbv))
+ {
+ CopyMemory(nameOrder,dbv.pbVal,dbv.cpbVal);
+ DBFreeVariant(&dbv);
+ }
+ }
+ CreateServiceFunction(MS_CONTACT_GETCONTACTINFO,GetContactInfo);
+ HookEvent(ME_OPT_INITIALISE,ContactOptInit);
+ return 0;
+}
diff --git a/src/modules/database/database.cpp b/src/modules/database/database.cpp
new file mode 100644
index 0000000000..9c9aab8146
--- /dev/null
+++ b/src/modules/database/database.cpp
@@ -0,0 +1,563 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2010 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 "profilemanager.h"
+#include "../srfile/file.h"
+
+// from the plugin loader, hate extern but the db frontend is pretty much tied
+extern PLUGINLINK pluginCoreLink;
+// contains the location of mirandaboot.ini
+extern TCHAR mirandabootini[MAX_PATH];
+bool dbCreated;
+TCHAR g_profileDir[MAX_PATH], g_profileName[MAX_PATH];
+
+bool fileExist(TCHAR* fname)
+{
+ if (fname[0] == 0) return false;
+
+ FILE* fp = _tfopen(fname, _T("r+"));
+ bool res = fp != NULL;
+ if (res) fclose(fp);
+ return res;
+}
+
+static void fillProfileName( const TCHAR* ptszFileName )
+{
+ const TCHAR* p = _tcsrchr( ptszFileName, '\\' );
+ if ( p == NULL )
+ p = ptszFileName;
+ else
+ p++;
+
+ _tcsncpy( g_profileName, p, SIZEOF(g_profileName));
+}
+
+bool IsInsideRootDir(TCHAR* profiledir, bool exact)
+{
+ int res;
+ TCHAR* pfd = Utils_ReplaceVarsT(_T("%miranda_path%"));
+ if (exact)
+ res = _tcsicmp(profiledir, pfd);
+ else
+ {
+ size_t len = _tcslen(pfd);
+ res = _tcsnicmp(profiledir, pfd, len);
+ }
+ mir_free(pfd);
+ return res == 0;
+}
+
+// returns 1 if the profile path was returned, without trailing slash
+int getProfilePath(TCHAR * buf, size_t cch)
+{
+ TCHAR profiledir[MAX_PATH];
+ GetPrivateProfileString(_T("Database"), _T("ProfileDir"), _T(""), profiledir, SIZEOF(profiledir), mirandabootini);
+
+ if (profiledir[0] == 0)
+ _tcscpy(profiledir, _T("%miranda_path%\\Profiles"));
+
+ TCHAR* exprofiledir = Utils_ReplaceVarsT(profiledir);
+ size_t len = pathToAbsoluteT(exprofiledir, buf, NULL);
+ mir_free(exprofiledir);
+
+ if (buf[len-1] == '/' || buf[len-1] == '\\')
+ buf[len-1] = 0;
+
+ return 0;
+}
+
+// returns 1 if *.dat spec is matched
+int isValidProfileName(const TCHAR *name)
+{
+ size_t len = _tcslen(name) - 4;
+ return len > 0 && _tcsicmp(&name[len], _T(".dat")) == 0;
+}
+
+// returns 1 if the profile manager should be shown
+static bool showProfileManager(void)
+{
+ TCHAR Mgr[32];
+ // is control pressed?
+ if (GetAsyncKeyState(VK_CONTROL)&0x8000)
+ return 1;
+
+ // wanna show it?
+ GetPrivateProfileString(_T("Database"), _T("ShowProfileMgr"), _T("never"), Mgr, SIZEOF(Mgr), mirandabootini);
+ return ( _tcsicmp(Mgr, _T("yes")) == 0 );
+}
+
+bool shouldAutoCreate(TCHAR *szProfile)
+{
+ if (szProfile[0] == 0)
+ return false;
+
+ TCHAR ac[32];
+ GetPrivateProfileString(_T("Database"), _T("AutoCreate"), _T(""), ac, SIZEOF(ac), mirandabootini);
+ return _tcsicmp(ac, _T("yes")) == 0;
+}
+
+static void getDefaultProfile(TCHAR * szProfile, size_t cch, TCHAR * profiledir)
+{
+ TCHAR defaultProfile[MAX_PATH];
+ GetPrivateProfileString(_T("Database"), _T("DefaultProfile"), _T(""), defaultProfile, SIZEOF(defaultProfile), mirandabootini);
+
+ if (defaultProfile[0] == 0)
+ return;
+
+ TCHAR* res = Utils_ReplaceVarsT(defaultProfile);
+ if (res) {
+ mir_sntprintf(szProfile, cch, _T("%s\\%s\\%s%s"), profiledir, res, res, isValidProfileName(res) ? _T("") : _T(".dat"));
+ mir_free(res);
+ }
+ else szProfile[0] = 0;
+}
+
+// returns 1 if something that looks like a profile is there
+static int getProfileCmdLineArgs(TCHAR * szProfile, size_t cch)
+{
+ TCHAR *szCmdLine = GetCommandLine();
+ TCHAR *szEndOfParam;
+ TCHAR szThisParam[1024];
+ int firstParam=1;
+
+ while(szCmdLine[0])
+ {
+ if(szCmdLine[0]=='"')
+ {
+ szEndOfParam = _tcschr(szCmdLine+1, '"');
+ if(szEndOfParam == NULL) break;
+ lstrcpyn(szThisParam, szCmdLine+1, min(SIZEOF(szThisParam), szEndOfParam - szCmdLine));
+ szCmdLine = szEndOfParam + 1;
+ }
+ else
+ {
+ szEndOfParam = szCmdLine + _tcscspn(szCmdLine, _T(" \t"));
+ lstrcpyn(szThisParam, szCmdLine, min(SIZEOF(szThisParam), szEndOfParam - szCmdLine+1));
+ szCmdLine = szEndOfParam;
+ }
+ while(*szCmdLine && *szCmdLine<=' ') szCmdLine++;
+ if (firstParam) { firstParam=0; continue; } //first param is executable name
+ if (szThisParam[0] == '/' || szThisParam[0] == '-') continue; //no switches supported
+
+ TCHAR* res = Utils_ReplaceVarsT(szThisParam);
+ if (res == NULL) return 0;
+ _tcsncpy(szProfile, res, cch); szProfile[cch-1] = 0;
+ mir_free(res);
+ return 1;
+ }
+ return 0;
+}
+
+void getProfileCmdLine(TCHAR * szProfile, size_t cch, TCHAR * profiledir)
+{
+ TCHAR buf[MAX_PATH];
+ if (getProfileCmdLineArgs(buf, SIZEOF(buf)))
+ {
+ TCHAR *p, profileName[MAX_PATH], newProfileDir[MAX_PATH];
+
+ p = _tcsrchr(buf, '\\'); if (p) ++p; else p = buf;
+
+ if (!isValidProfileName(buf) && *p)
+ _tcscat(buf, _T(".dat"));
+
+ _tcscpy(profileName, p);
+ p = _tcsrchr(profileName, '.'); if (p) *p = 0;
+
+ mir_sntprintf(newProfileDir, cch, _T("%s\\%s\\"), profiledir, profileName);
+ pathToAbsoluteT(buf, szProfile, newProfileDir);
+
+ if (_tcschr(buf, '\\'))
+ {
+ _tcscpy(profiledir, szProfile);
+ if (profileName[0])
+ {
+ p = _tcsrchr(profiledir, '\\'); *p = 0;
+ p = _tcsrchr(profiledir, '\\');
+ if (p && _tcsicmp(p + 1, profileName) == 0)
+ *p = 0;
+ }
+ else
+ szProfile[0] = 0;
+
+ }
+ }
+}
+
+// move profile from profile subdir
+static void moveProfileDirProfiles(TCHAR * profiledir, BOOL isRootDir = TRUE)
+{
+ TCHAR pfd[MAX_PATH];
+ if (isRootDir) {
+ TCHAR *path = Utils_ReplaceVarsT(_T("%miranda_path%\\*.dat"));
+ mir_sntprintf(pfd, SIZEOF(pfd), _T("%s"), path);
+ mir_free(path);
+ }
+ else
+ mir_sntprintf(pfd, SIZEOF(pfd), _T("%s\\*.dat"), profiledir);
+
+ WIN32_FIND_DATA ffd;
+ HANDLE hFind = FindFirstFile(pfd, &ffd);
+ if (hFind != INVALID_HANDLE_VALUE)
+ {
+ TCHAR *c =_tcsrchr(pfd, '\\'); if (c) *c = 0;
+ do
+ {
+ TCHAR path[MAX_PATH], path2[MAX_PATH];
+ TCHAR* profile = mir_tstrdup(ffd.cFileName);
+ TCHAR *c =_tcsrchr(profile, '.'); if (c) *c = 0;
+ mir_sntprintf(path, SIZEOF(path), _T("%s\\%s"), pfd, ffd.cFileName);
+ mir_sntprintf(path2, SIZEOF(path2), _T("%s\\%s"), profiledir, profile);
+ CreateDirectoryTreeT(path2);
+ mir_sntprintf(path2, SIZEOF(path2), _T("%s\\%s\\%s"), profiledir, profile, ffd.cFileName);
+ if (_taccess(path2, 0) == 0)
+ {
+ const TCHAR tszMoveMsg[] =
+ _T("Miranda is trying upgrade your profile structure.\n")
+ _T("It cannot move profile %s to the new location %s\n")
+ _T("Because profile with this name already exist. Please resolve the issue manually.");
+ TCHAR buf[512];
+
+ mir_sntprintf(buf, SIZEOF(buf), TranslateTS(tszMoveMsg), path, path2);
+ MessageBox(NULL, buf, _T("Miranda IM"), MB_ICONERROR | MB_OK);
+ }
+ else if (MoveFile(path, path2) == 0)
+ {
+ const TCHAR tszMoveMsg[] =
+ _T("Miranda is trying upgrade your profile structure.\n")
+ _T("It cannot move profile %s to the new location %s automatically\n")
+ _T("Most likely due to insufficient privileges. Please move profile manually.");
+ TCHAR buf[512];
+
+ mir_sntprintf(buf, SIZEOF(buf), TranslateTS(tszMoveMsg), path, path2);
+ MessageBox(NULL, buf, _T("Miranda IM"), MB_ICONERROR | MB_OK);
+ break;
+ }
+ mir_free(profile);
+ }
+ while(FindNextFile(hFind, &ffd));
+ }
+ FindClose(hFind);
+}
+
+// returns 1 if a single profile (full path) is found within the profile dir
+static int getProfile1(TCHAR * szProfile, size_t cch, TCHAR * profiledir, BOOL * noProfiles)
+{
+ unsigned int found = 0;
+
+ if (IsInsideRootDir(profiledir, false))
+ moveProfileDirProfiles(profiledir);
+ moveProfileDirProfiles(profiledir, FALSE);
+
+ bool nodprof = szProfile[0] == 0;
+ bool reqfd = !nodprof && (_taccess(szProfile, 0) == 0 || shouldAutoCreate(szProfile));
+ bool shpm = showProfileManager();
+
+ if (reqfd)
+ found++;
+
+ if (shpm || !reqfd) {
+ TCHAR searchspec[MAX_PATH];
+ mir_sntprintf(searchspec, SIZEOF(searchspec), _T("%s\\*.*"), profiledir);
+
+ WIN32_FIND_DATA ffd;
+ HANDLE hFind = FindFirstFile(searchspec, &ffd);
+ if (hFind != INVALID_HANDLE_VALUE) {
+ do {
+ // make sure the first hit is actually a *.dat file
+ if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && _tcscmp(ffd.cFileName, _T(".")) && _tcscmp(ffd.cFileName, _T(".."))) {
+ TCHAR newProfile[MAX_PATH];
+ mir_sntprintf(newProfile, MAX_PATH, _T("%s\\%s\\%s.dat"), profiledir, ffd.cFileName, ffd.cFileName);
+ if (_taccess(newProfile, 0) == 0)
+ if (++found == 1 && nodprof)
+ _tcscpy(szProfile, newProfile);
+ }
+ }
+ while (FindNextFile(hFind, &ffd));
+
+ FindClose(hFind);
+ }
+ reqfd = !shpm && found == 1 && nodprof;
+ }
+
+ if ( noProfiles )
+ *noProfiles = found == 0;
+
+ if ( nodprof && !reqfd )
+ szProfile[0] = 0;
+
+ return reqfd;
+}
+
+// returns 1 if a default profile should be selected instead of showing the manager.
+static int getProfileAutoRun(TCHAR * szProfile)
+{
+ TCHAR Mgr[32];
+ GetPrivateProfileString(_T("Database"), _T("ShowProfileMgr"), _T(""), Mgr, SIZEOF(Mgr), mirandabootini);
+ if (_tcsicmp(Mgr, _T("never")))
+ return 0;
+
+ return fileExist(szProfile) || shouldAutoCreate(szProfile);
+}
+
+// returns 1 if a profile was selected
+static int getProfile(TCHAR * szProfile, size_t cch)
+{
+ getProfilePath(g_profileDir, SIZEOF(g_profileDir));
+ if (IsInsideRootDir(g_profileDir, true))
+ {
+ if (WritePrivateProfileString(_T("Database"), _T("ProfileDir"), _T(""), mirandabootini))
+ getProfilePath(g_profileDir, SIZEOF(g_profileDir));
+ }
+
+ getDefaultProfile(szProfile, cch, g_profileDir);
+ getProfileCmdLine(szProfile, cch, g_profileDir);
+ if (IsInsideRootDir(g_profileDir, true))
+ {
+ MessageBox(NULL,
+ _T("Profile cannot be placed into Miranda root folder.\n")
+ _T("Please move Miranda profile to some other location."),
+ _T("Miranda IM"), MB_ICONERROR | MB_OK);
+ return 0;
+ }
+ if (getProfileAutoRun(szProfile))
+ return 1;
+
+ PROFILEMANAGERDATA pd = {0};
+ if (getProfile1(szProfile, cch, g_profileDir, &pd.noProfiles))
+ return 1;
+
+ pd.szProfile = szProfile;
+ pd.szProfileDir = g_profileDir;
+ return getProfileManager(&pd);
+}
+
+// carefully converts a file name from TCHAR* to char*
+char* makeFileName( const TCHAR* tszOriginalName )
+{
+ char* szResult = NULL;
+ char* szFileName = mir_t2a( tszOriginalName );
+ TCHAR* tszFileName = mir_a2t( szFileName );
+ if ( _tcscmp( tszOriginalName, tszFileName )) {
+ TCHAR tszProfile[MAX_PATH];
+ if ( GetShortPathName( tszOriginalName, tszProfile, MAX_PATH) != 0)
+ szResult = mir_t2a( tszProfile );
+ }
+
+ if ( !szResult )
+ szResult = szFileName;
+ else
+ mir_free(szFileName);
+ mir_free(tszFileName);
+
+ return szResult;
+}
+
+// called by the UI, return 1 on success, use link to create profile, set error if any
+int makeDatabase(TCHAR * profile, DATABASELINK * link, HWND hwndDlg)
+{
+ TCHAR buf[256];
+ int err=0;
+ // check if the file already exists
+ TCHAR * file = _tcsrchr(profile, '\\');
+ if (file) file++;
+ if (_taccess(profile, 0) == 0) {
+ // file already exists!
+ mir_sntprintf(buf, SIZEOF(buf), TranslateTS( _T("The profile '%s' already exists. Do you want to move it to the ")
+ _T("Recycle Bin? \n\nWARNING: The profile will be deleted if Recycle Bin is disabled.\n")
+ _T("WARNING: A profile may contain confidential information and should be properly deleted.")), file );
+ if ( MessageBox(hwndDlg, buf, TranslateT("The profile already exists"), MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2) != IDYES )
+ return 0;
+
+ // move the file
+ SHFILEOPSTRUCT sf = {0};
+ sf.wFunc = FO_DELETE;
+ sf.pFrom = buf;
+ sf.fFlags = FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT | FOF_ALLOWUNDO;
+ mir_sntprintf(buf, SIZEOF(buf), _T("%s\0"), profile);
+ if ( SHFileOperation(&sf) != 0 ) {
+ mir_sntprintf(buf, SIZEOF(buf),TranslateT("Couldn't move '%s' to the Recycle Bin, Please select another profile name."),file);
+ MessageBox(0,buf,TranslateT("Problem moving profile"),MB_ICONINFORMATION|MB_OK);
+ return 0;
+ }
+ // now the file should be gone!
+ }
+ // ask the database to create the profile
+ CreatePathToFileT(profile);
+ char *prf = makeFileName(profile);
+ if (link->makeDatabase(prf, &err)) {
+ mir_sntprintf(buf, SIZEOF(buf),TranslateT("Unable to create the profile '%s', the error was %x"),file, err);
+ MessageBox(hwndDlg,buf,TranslateT("Problem creating profile"),MB_ICONERROR|MB_OK);
+ mir_free(prf);
+ return 0;
+ }
+ dbCreated = true;
+ // the profile has been created! woot
+ mir_free(prf);
+ return 1;
+}
+
+// enumerate all plugins that had valid DatabasePluginInfo()
+static int FindDbPluginForProfile(const char*, DATABASELINK * dblink, LPARAM lParam)
+{
+ TCHAR* tszProfile = ( TCHAR* )lParam;
+
+ int res = DBPE_CONT;
+ if ( dblink && dblink->cbSize == sizeof(DATABASELINK)) {
+ char* szProfile = makeFileName(tszProfile);
+ // liked the profile?
+ int err = 0;
+ if (dblink->grokHeader(szProfile, &err) == 0) {
+ // added APIs?
+ if ( !dblink->Load(szProfile, &pluginCoreLink)) {
+ fillProfileName( tszProfile );
+ res = DBPE_DONE;
+ }
+ else res = DBPE_HALT;
+ }
+ else {
+ res = DBPE_HALT;
+ switch ( err ) {
+ case EGROKPRF_CANTREAD:
+ case EGROKPRF_UNKHEADER:
+ // just not supported.
+ res = DBPE_CONT;
+
+ case EGROKPRF_VERNEWER:
+ case EGROKPRF_DAMAGED:
+ break;
+ }
+ } //if
+ mir_free(szProfile);
+ }
+ return res;
+}
+
+// enumerate all plugins that had valid DatabasePluginInfo()
+static int FindDbPluginAutoCreate(const char*, DATABASELINK * dblink, LPARAM lParam)
+{
+ TCHAR* tszProfile = ( TCHAR* )lParam;
+
+ int res = DBPE_CONT;
+ if (dblink && dblink->cbSize == sizeof(DATABASELINK)) {
+ CreatePathToFileT( tszProfile );
+
+ int err;
+ char *szProfile = makeFileName( tszProfile );
+ if (dblink->makeDatabase(szProfile, &err) == 0) {
+ dbCreated = true;
+ if ( !dblink->Load(szProfile, &pluginCoreLink)) {
+ fillProfileName( tszProfile );
+ res = DBPE_DONE;
+ }
+ else res = DBPE_HALT;
+ }
+ mir_free(szProfile);
+ }
+ return res;
+}
+
+typedef struct {
+ TCHAR * profile;
+ UINT msg;
+ ATOM aPath;
+ int found;
+} ENUMMIRANDAWINDOW;
+
+static BOOL CALLBACK EnumMirandaWindows(HWND hwnd, LPARAM lParam)
+{
+ TCHAR classname[256];
+ ENUMMIRANDAWINDOW * x = (ENUMMIRANDAWINDOW *)lParam;
+ DWORD_PTR res=0;
+ if ( GetClassName(hwnd,classname,SIZEOF(classname)) && lstrcmp( _T("Miranda"),classname)==0 ) {
+ if ( SendMessageTimeout(hwnd, x->msg, (WPARAM)x->aPath, 0, SMTO_ABORTIFHUNG, 100, &res) && res ) {
+ x->found++;
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+static int FindMirandaForProfile(TCHAR * szProfile)
+{
+ ENUMMIRANDAWINDOW x={0};
+ x.profile=szProfile;
+ x.msg=RegisterWindowMessage( _T( "Miranda::ProcessProfile" ));
+ x.aPath=GlobalAddAtom(szProfile);
+ EnumWindows(EnumMirandaWindows, (LPARAM)&x);
+ GlobalDeleteAtom(x.aPath);
+ return x.found;
+}
+
+int LoadDatabaseModule(void)
+{
+ TCHAR szProfile[MAX_PATH];
+ pathToAbsoluteT(_T("."), szProfile, NULL);
+ _tchdir(szProfile);
+ szProfile[0] = 0;
+
+ // load the older basic services of the db
+ InitUtils();
+
+ // find out which profile to load
+ if ( !getProfile( szProfile, SIZEOF( szProfile )))
+ return 1;
+
+ PLUGIN_DB_ENUM dbe;
+ dbe.cbSize = sizeof(PLUGIN_DB_ENUM);
+ dbe.lParam = (LPARAM)szProfile;
+
+ if ( _taccess(szProfile, 0) && shouldAutoCreate( szProfile ))
+ dbe.pfnEnumCallback=( int(*) (const char*,void*,LPARAM) )FindDbPluginAutoCreate;
+ else
+ dbe.pfnEnumCallback=( int(*) (const char*,void*,LPARAM) )FindDbPluginForProfile;
+
+ // find a driver to support the given profile
+ int rc = CallService(MS_PLUGINS_ENUMDBPLUGINS, 0, (LPARAM)&dbe);
+ switch ( rc ) {
+ case -1: {
+ // no plugins at all
+ TCHAR buf[256];
+ TCHAR* p = _tcsrchr(szProfile,'\\');
+ mir_sntprintf(buf,SIZEOF(buf),TranslateT("Miranda is unable to open '%s' because you do not have any profile plugins installed.\nYou need to install dbx_3x.dll or equivalent."), p ? ++p : szProfile );
+ MessageBox(0,buf,TranslateT("No profile support installed!"),MB_OK | MB_ICONERROR);
+ break;
+ }
+ case 1:
+ // if there were drivers but they all failed cos the file is locked, try and find the miranda which locked it
+ if (fileExist(szProfile)) {
+ // file isn't locked, just no driver could open it.
+ TCHAR buf[256];
+ TCHAR* p = _tcsrchr(szProfile,'\\');
+ mir_sntprintf(buf,SIZEOF(buf),TranslateT("Miranda was unable to open '%s', it's in an unknown format.\nThis profile might also be damaged, please run DB-tool which should be installed."), p ? ++p : szProfile);
+ MessageBox(0,buf,TranslateT("Miranda can't understand that profile"),MB_OK | MB_ICONERROR);
+ }
+ else if (!FindMirandaForProfile(szProfile)) {
+ TCHAR buf[256];
+ TCHAR* p = _tcsrchr(szProfile,'\\');
+ mir_sntprintf(buf,SIZEOF(buf),TranslateT("Miranda was unable to open '%s'\nIt's inaccessible or used by other application or Miranda instance"), p ? ++p : szProfile);
+ MessageBox(0,buf,TranslateT("Miranda can't open that profile"),MB_OK | MB_ICONERROR);
+ }
+ break;
+ }
+ return (rc != 0);
+}
diff --git a/src/modules/database/dbini.cpp b/src/modules/database/dbini.cpp
new file mode 100644
index 0000000000..01e6645593
--- /dev/null
+++ b/src/modules/database/dbini.cpp
@@ -0,0 +1,490 @@
+/*
+
+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 "../srfile/file.h"
+
+static bool bModuleInitialized = false;
+static HANDLE hIniChangeNotification;
+
+extern TCHAR mirandabootini[MAX_PATH];
+extern bool dbCreated;
+
+static INT_PTR CALLBACK InstallIniDlgProc(HWND hwndDlg,UINT message,WPARAM wParam,LPARAM lParam)
+{
+ switch(message) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ SetDlgItemText(hwndDlg, IDC_ININAME, (TCHAR*)lParam);
+ {
+ TCHAR szSecurity[11];
+ const TCHAR *pszSecurityInfo;
+
+ GetPrivateProfileString(_T("AutoExec"), _T("Warn"), _T("notsafe"), szSecurity, SIZEOF(szSecurity), mirandabootini);
+ if(!lstrcmpi(szSecurity, _T("all")))
+ pszSecurityInfo = LPGENT("Security systems to prevent malicious changes are in place and you will be warned before every change that is made.");
+ else if (!lstrcmpi(szSecurity, _T("onlyunsafe")))
+ pszSecurityInfo = LPGENT("Security systems to prevent malicious changes are in place and you will be warned before changes that are known to be unsafe.");
+ else if (!lstrcmpi(szSecurity, _T("none")))
+ pszSecurityInfo = LPGENT("Security systems to prevent malicious changes have been disabled. You will receive no further warnings.");
+ else pszSecurityInfo = NULL;
+ if (pszSecurityInfo) SetDlgItemText(hwndDlg, IDC_SECURITYINFO, TranslateTS(pszSecurityInfo));
+ }
+ return TRUE;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDC_VIEWINI:
+ { TCHAR szPath[MAX_PATH];
+ GetDlgItemText(hwndDlg, IDC_ININAME, szPath, SIZEOF(szPath));
+ ShellExecute(hwndDlg, _T("open"), szPath, NULL, NULL, SW_SHOW);
+ break;
+ }
+ case IDOK:
+ case IDCANCEL:
+ case IDC_NOTOALL:
+ EndDialog(hwndDlg,LOWORD(wParam));
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static bool IsInSpaceSeparatedList(const char *szWord,const char *szList)
+{
+ const char *szItem,*szEnd;
+ int wordLen = lstrlenA(szWord);
+
+ for(szItem = szList;;) {
+ szEnd = strchr(szItem,' ');
+ if (szEnd == NULL)
+ return !lstrcmpA( szItem, szWord );
+ if ( szEnd - szItem == wordLen ) {
+ if ( !strncmp( szItem, szWord, wordLen ))
+ return true;
+ }
+ szItem = szEnd+1;
+} }
+
+struct warnSettingChangeInfo_t {
+ TCHAR *szIniPath;
+ char *szSection;
+ char *szSafeSections;
+ char *szUnsafeSections;
+ char *szName;
+ char *szValue;
+ int warnNoMore,cancel;
+};
+
+static INT_PTR CALLBACK WarnIniChangeDlgProc(HWND hwndDlg,UINT message,WPARAM wParam,LPARAM lParam)
+{
+ static struct warnSettingChangeInfo_t *warnInfo;
+
+ switch(message) {
+ case WM_INITDIALOG:
+ { char szSettingName[256];
+ const TCHAR *pszSecurityInfo;
+ warnInfo = (warnSettingChangeInfo_t*)lParam;
+ TranslateDialogDefault(hwndDlg);
+ SetDlgItemText(hwndDlg, IDC_ININAME, warnInfo->szIniPath);
+ lstrcpyA(szSettingName, warnInfo->szSection);
+ lstrcatA(szSettingName," / ");
+ lstrcatA(szSettingName,warnInfo->szName);
+ SetDlgItemTextA(hwndDlg,IDC_SETTINGNAME,szSettingName);
+ SetDlgItemTextA(hwndDlg,IDC_NEWVALUE,warnInfo->szValue);
+ if(IsInSpaceSeparatedList(warnInfo->szSection,warnInfo->szSafeSections))
+ pszSecurityInfo=LPGENT("This change is known to be safe.");
+ else if(IsInSpaceSeparatedList(warnInfo->szSection,warnInfo->szUnsafeSections))
+ pszSecurityInfo=LPGENT("This change is known to be potentially hazardous.");
+ else
+ pszSecurityInfo=LPGENT("This change is not known to be safe.");
+ SetDlgItemText(hwndDlg,IDC_SECURITYINFO,TranslateTS(pszSecurityInfo));
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDCANCEL:
+ warnInfo->cancel=1;
+ case IDYES:
+ case IDNO:
+ warnInfo->warnNoMore=IsDlgButtonChecked(hwndDlg,IDC_WARNNOMORE);
+ EndDialog(hwndDlg,LOWORD(wParam));
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static INT_PTR CALLBACK IniImportDoneDlgProc(HWND hwndDlg,UINT message,WPARAM wParam,LPARAM lParam)
+{
+ switch(message) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ SetDlgItemText(hwndDlg,IDC_ININAME,(TCHAR*)lParam);
+ SetDlgItemText(hwndDlg,IDC_NEWNAME,(TCHAR*)lParam);
+ return TRUE;
+ case WM_COMMAND:
+ { TCHAR szIniPath[MAX_PATH];
+ GetDlgItemText(hwndDlg,IDC_ININAME,szIniPath,SIZEOF(szIniPath));
+ switch(LOWORD(wParam)) {
+ case IDC_DELETE:
+ DeleteFile(szIniPath);
+ case IDC_LEAVE:
+ EndDialog(hwndDlg,LOWORD(wParam));
+ break;
+ case IDC_RECYCLE:
+ { SHFILEOPSTRUCT shfo={0};
+ shfo.wFunc=FO_DELETE;
+ shfo.pFrom=szIniPath;
+ szIniPath[lstrlen(szIniPath)+1]='\0';
+ shfo.fFlags = FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT | FOF_ALLOWUNDO;
+ SHFileOperation(&shfo);
+ }
+ EndDialog(hwndDlg,LOWORD(wParam));
+ break;
+ case IDC_MOVE:
+ { TCHAR szNewPath[MAX_PATH];
+ GetDlgItemText(hwndDlg,IDC_NEWNAME,szNewPath,SIZEOF(szNewPath));
+ MoveFile(szIniPath,szNewPath);
+ }
+ EndDialog(hwndDlg,LOWORD(wParam));
+ break;
+ }
+ break;
+ }
+ }
+ return FALSE;
+}
+
+// settings:
+struct SettingsList
+{
+ char *name;
+ SettingsList *next;
+} *setting_items = NULL;
+
+int SettingsEnumProc(const char *szSetting, LPARAM lParam)
+{
+ SettingsList *newItem = (SettingsList *)mir_alloc(sizeof(SettingsList));
+ newItem->name = mir_strdup(szSetting);
+ newItem->next = setting_items;
+ setting_items = newItem;
+ return 0;
+}
+
+void ConvertBackslashes(char *, UINT);
+static void ProcessIniFile(TCHAR* szIniPath, char *szSafeSections, char *szUnsafeSections, int secur, bool secFN)
+{
+ FILE *fp = _tfopen(szIniPath, _T("rt"));
+ if ( fp == NULL )
+ return;
+
+ bool warnThisSection = false;
+ char szSection[128]; szSection[0] = 0;
+
+ while(!feof(fp)) {
+ char szLine[2048];
+ if (fgets(szLine,sizeof(szLine),fp) == NULL)
+ break;
+
+ int lineLength = lstrlenA(szLine);
+ while (lineLength && (BYTE)(szLine[lineLength-1])<=' ')
+ szLine[--lineLength]='\0';
+
+ if (szLine[0]==';' || szLine[0]<=' ')
+ continue;
+
+ if (szLine[0]=='[') {
+ char *szEnd = strchr(szLine+1,']');
+ if (szEnd == NULL)
+ continue;
+
+ if (szLine[1] == '!')
+ szSection[0] = '\0';
+ else {
+ lstrcpynA(szSection,szLine+1,min(sizeof(szSection),(int)(szEnd-szLine)));
+ switch (secur) {
+ case 0:
+ warnThisSection = false;
+ break;
+
+ case 1:
+ warnThisSection = !IsInSpaceSeparatedList(szSection, szSafeSections);
+ break;
+
+ case 2:
+ warnThisSection = IsInSpaceSeparatedList(szSection, szUnsafeSections);
+ break;
+
+ default:
+ warnThisSection = true;
+ break;
+ }
+ if (secFN) warnThisSection=0;
+ }
+ if (szLine[1] == '?') {
+ DBCONTACTENUMSETTINGS dbces;
+ dbces.pfnEnumProc=SettingsEnumProc;
+ lstrcpynA(szSection,szLine+2,min(sizeof(szSection),(int)(szEnd-szLine-1)));
+ dbces.szModule=szSection;
+ dbces.ofsSettings=0;
+ CallService(MS_DB_CONTACT_ENUMSETTINGS,0,(LPARAM)&dbces);
+ while (setting_items) {
+ SettingsList *next = setting_items->next;
+
+ DBCONTACTGETSETTING dbcgs;
+ dbcgs.szModule = szSection;
+ dbcgs.szSetting = setting_items->name;
+ CallService(MS_DB_CONTACT_DELETESETTING, 0, (LPARAM)&dbcgs);
+
+ mir_free(setting_items->name);
+ mir_free(setting_items);
+ setting_items = next;
+ }
+ }
+ continue;
+ }
+
+ if(szSection[0]=='\0')
+ continue;
+
+ char *szValue=strchr(szLine,'=');
+ if ( szValue == NULL )
+ continue;
+
+ char szName[128];
+ lstrcpynA(szName,szLine,min(sizeof(szName),(int)(szValue-szLine+1)));
+ szValue++;
+ {
+ warnSettingChangeInfo_t warnInfo;
+ warnInfo.szIniPath=szIniPath;
+ warnInfo.szName=szName;
+ warnInfo.szSafeSections=szSafeSections;
+ warnInfo.szSection=szSection;
+ warnInfo.szUnsafeSections=szUnsafeSections;
+ warnInfo.szValue=szValue;
+ warnInfo.warnNoMore=0;
+ warnInfo.cancel=0;
+ if(warnThisSection && IDNO==DialogBoxParam(hMirandaInst,MAKEINTRESOURCE(IDD_WARNINICHANGE),NULL,WarnIniChangeDlgProc,(LPARAM)&warnInfo))
+ continue;
+ if(warnInfo.cancel)
+ break;
+ if(warnInfo.warnNoMore)
+ warnThisSection=0;
+ }
+
+ switch(szValue[0]) {
+ case 'b':
+ case 'B':
+ DBWriteContactSettingByte(NULL,szSection,szName,(BYTE)strtol(szValue+1,NULL,0));
+ break;
+ case 'w':
+ case 'W':
+ DBWriteContactSettingWord(NULL,szSection,szName,(WORD)strtol(szValue+1,NULL,0));
+ break;
+ case 'd':
+ case 'D':
+ DBWriteContactSettingDword(NULL,szSection,szName,(DWORD)strtoul(szValue+1,NULL,0));
+ break;
+ case 'l':
+ case 'L':
+ DBDeleteContactSetting(NULL,szSection,szName);
+ break;
+ case 'e':
+ case 'E':
+ ConvertBackslashes(szValue+1, LangPackGetDefaultCodePage());
+ case 's':
+ case 'S':
+ DBWriteContactSettingString(NULL,szSection,szName,szValue+1);
+ break;
+ case 'g':
+ case 'G':
+ { char *pstr;
+ for(pstr=szValue+1;*pstr;pstr++){
+ if(*pstr=='\\'){
+ switch(pstr[1]){
+ case 'n': *pstr='\n'; break;
+ case 't': *pstr='\t'; break;
+ case 'r': *pstr='\r'; break;
+ default: *pstr=pstr[1]; break;
+ }
+ MoveMemory(pstr+1,pstr+2,lstrlenA(pstr+2)+1);
+ } } }
+ case 'u':
+ case 'U':
+ DBWriteContactSettingStringUtf(NULL,szSection,szName,szValue+1);
+ break;
+ case 'n':
+ case 'h':
+ case 'N':
+ case 'H':
+ { PBYTE buf;
+ int len;
+ char *pszValue,*pszEnd;
+ DBCONTACTWRITESETTING cws;
+
+ buf=(PBYTE)mir_alloc(lstrlenA(szValue+1));
+ for(len=0,pszValue=szValue+1;;len++) {
+ buf[len]=(BYTE)strtol(pszValue,&pszEnd,0x10);
+ if(pszValue==pszEnd) break;
+ pszValue=pszEnd;
+ }
+ cws.szModule=szSection;
+ cws.szSetting=szName;
+ cws.value.type=DBVT_BLOB;
+ cws.value.pbVal=buf;
+ cws.value.cpbVal=len;
+ CallService(MS_DB_CONTACT_WRITESETTING,(WPARAM)(HANDLE)NULL,(LPARAM)&cws);
+ mir_free(buf);
+ }
+ break;
+ default:
+ MessageBox(NULL,TranslateT("Invalid setting type. The first character of every value must be b, w, d, l, s, e, u, g, h or n."),TranslateT("Install Database Settings"),MB_OK);
+ break;
+ }
+ }
+ fclose(fp);
+}
+
+static void DoAutoExec(void)
+{
+ TCHAR szUse[7], szIniPath[MAX_PATH], szFindPath[MAX_PATH];
+ TCHAR *str2;
+ TCHAR buf[2048], szSecurity[11], szOverrideSecurityFilename[MAX_PATH], szOnCreateFilename[MAX_PATH];
+ char *szSafeSections, *szUnsafeSections;
+ int secur;
+
+ GetPrivateProfileString(_T("AutoExec"),_T("Use"),_T("prompt"),szUse,SIZEOF(szUse),mirandabootini);
+ if(!lstrcmpi(szUse,_T("no"))) return;
+ GetPrivateProfileString(_T("AutoExec"),_T("Safe"),_T("CLC Icons CLUI CList SkinSounds"),buf,SIZEOF(buf),mirandabootini);
+ szSafeSections = mir_t2a(buf);
+ GetPrivateProfileString(_T("AutoExec"),_T("Unsafe"),_T("ICQ MSN"),buf,SIZEOF(buf),mirandabootini);
+ szUnsafeSections = mir_t2a(buf);
+ GetPrivateProfileString(_T("AutoExec"),_T("Warn"),_T("notsafe"),szSecurity,SIZEOF(szSecurity),mirandabootini);
+ if (!lstrcmpi(szSecurity,_T("none"))) secur = 0;
+ else if (!lstrcmpi(szSecurity,_T("notsafe"))) secur = 1;
+ else if (!lstrcmpi(szSecurity,_T("onlyunsafe"))) secur = 2;
+
+ GetPrivateProfileString(_T("AutoExec"),_T("OverrideSecurityFilename"),_T(""),szOverrideSecurityFilename,SIZEOF(szOverrideSecurityFilename),mirandabootini);
+ GetPrivateProfileString(_T("AutoExec"),_T("OnCreateFilename"),_T(""),szOnCreateFilename,SIZEOF(szOnCreateFilename),mirandabootini);
+ GetPrivateProfileString(_T("AutoExec"),_T("Glob"),_T("autoexec_*.ini"),szFindPath,SIZEOF(szFindPath),mirandabootini);
+
+ if (dbCreated && szOnCreateFilename[0]) {
+ str2 = Utils_ReplaceVarsT(szOnCreateFilename);
+ pathToAbsoluteT(str2, szIniPath, NULL);
+ mir_free(str2);
+
+ ProcessIniFile(szIniPath, szSafeSections, szUnsafeSections, 0, 1);
+ }
+
+ str2 = Utils_ReplaceVarsT(szFindPath);
+ pathToAbsoluteT(str2, szFindPath, NULL);
+ mir_free(str2);
+
+ WIN32_FIND_DATA fd;
+ HANDLE hFind = FindFirstFile(szFindPath, &fd);
+ if (hFind == INVALID_HANDLE_VALUE) {
+ mir_free(szSafeSections);
+ mir_free(szUnsafeSections);
+ return;
+ }
+
+ str2 = _tcsrchr(szFindPath, '\\');
+ if (str2 == NULL) szFindPath[0] = 0;
+ else str2[1] = 0;
+
+ do {
+ bool secFN = lstrcmpi(fd.cFileName,szOverrideSecurityFilename) == 0;
+
+ mir_sntprintf(szIniPath, SIZEOF(szIniPath), _T("%s%s"), szFindPath, fd.cFileName);
+ if(!lstrcmpi(szUse,_T("prompt")) && !secFN) {
+ int result=DialogBoxParam(hMirandaInst,MAKEINTRESOURCE(IDD_INSTALLINI),NULL,InstallIniDlgProc,(LPARAM)szIniPath);
+ if(result==IDC_NOTOALL) break;
+ if(result==IDCANCEL) continue;
+ }
+
+ ProcessIniFile(szIniPath, szSafeSections, szUnsafeSections, secur, secFN);
+
+ if(secFN)
+ DeleteFile(szIniPath);
+ else {
+ TCHAR szOnCompletion[8];
+ GetPrivateProfileString(_T("AutoExec"),_T("OnCompletion"),_T("recycle"),szOnCompletion,SIZEOF(szOnCompletion),mirandabootini);
+ if(!lstrcmpi(szOnCompletion,_T("delete")))
+ DeleteFile(szIniPath);
+ else if(!lstrcmpi(szOnCompletion,_T("recycle"))) {
+ SHFILEOPSTRUCT shfo={0};
+ shfo.wFunc=FO_DELETE;
+ shfo.pFrom=szIniPath;
+ szIniPath[lstrlen(szIniPath)+1]=0;
+ shfo.fFlags=FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT | FOF_ALLOWUNDO;
+ SHFileOperation(&shfo);
+ }
+ else if(!lstrcmpi(szOnCompletion,_T("rename"))) {
+ TCHAR szRenamePrefix[MAX_PATH];
+ TCHAR szNewPath[MAX_PATH];
+ GetPrivateProfileString(_T("AutoExec"),_T("RenamePrefix"),_T("done_"),szRenamePrefix,SIZEOF(szRenamePrefix),mirandabootini);
+ lstrcpy(szNewPath,szFindPath);
+ lstrcat(szNewPath,szRenamePrefix);
+ lstrcat(szNewPath,fd.cFileName);
+ MoveFile(szIniPath,szNewPath);
+ }
+ else if(!lstrcmpi(szOnCompletion,_T("ask")))
+ DialogBoxParam(hMirandaInst,MAKEINTRESOURCE(IDD_INIIMPORTDONE),NULL,IniImportDoneDlgProc,(LPARAM)szIniPath);
+ }
+ } while (FindNextFile(hFind, &fd));
+ FindClose(hFind);
+ mir_free(szSafeSections);
+ mir_free(szUnsafeSections);
+}
+
+static INT_PTR CheckIniImportNow(WPARAM, LPARAM)
+{
+ DoAutoExec();
+ FindNextChangeNotification(hIniChangeNotification);
+ return 0;
+}
+
+int InitIni(void)
+{
+ TCHAR szMirandaDir[MAX_PATH];
+
+ bModuleInitialized = true;
+
+ DoAutoExec();
+ pathToAbsoluteT(_T("."), szMirandaDir, NULL);
+ hIniChangeNotification=FindFirstChangeNotification(szMirandaDir, 0, FILE_NOTIFY_CHANGE_FILE_NAME);
+ if (hIniChangeNotification != INVALID_HANDLE_VALUE) {
+ CreateServiceFunction("DB/Ini/CheckImportNow", CheckIniImportNow);
+ CallService(MS_SYSTEM_WAITONHANDLE, (WPARAM)hIniChangeNotification, (LPARAM)"DB/Ini/CheckImportNow");
+ }
+ return 0;
+}
+
+void UninitIni(void)
+{
+ if ( !bModuleInitialized ) return;
+ CallService(MS_SYSTEM_REMOVEWAIT,(WPARAM)hIniChangeNotification,0);
+ FindCloseChangeNotification(hIniChangeNotification);
+}
diff --git a/src/modules/database/dblists.cpp b/src/modules/database/dblists.cpp
new file mode 100644
index 0000000000..02332ab283
--- /dev/null
+++ b/src/modules/database/dblists.cpp
@@ -0,0 +1,282 @@
+/*
+
+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"
+
+/* a simple sorted list implementation */
+
+SortedList* List_Create( int p_limit, int p_increment )
+{
+ SortedList* result = ( SortedList* )mir_calloc( sizeof( SortedList ));
+ if ( result == NULL )
+ return(NULL);
+
+ result->increment = p_increment;
+ result->limit = p_limit;
+ return(result);
+}
+
+void List_Destroy( SortedList* p_list )
+{
+ if ( p_list == NULL )
+ return;
+
+ if ( p_list->items != NULL ) {
+ mir_free( p_list->items );
+ p_list->items = NULL;
+ }
+
+ p_list->realCount = p_list->limit = 0;
+}
+
+void* List_Find( SortedList* p_list, void* p_value )
+{
+ int index;
+
+ if ( !List_GetIndex( p_list, p_value, &index ))
+ return(NULL);
+
+ return(p_list->items[ index ]);
+}
+
+#ifdef _DEBUG
+#pragma optimize( "gt", on )
+#endif
+
+int List_GetIndex( SortedList* p_list, void* p_value, int* p_index )
+{
+ if (p_value == NULL)
+ {
+ *p_index = -1;
+ return 0;
+ }
+
+ switch ((INT_PTR)p_list->sortFunc)
+ {
+ case 0:
+ break;
+
+ case HandleKeySort:
+#ifdef _WIN64
+ {
+ const unsigned __int64 val = *(unsigned __int64 *)p_value;
+ int low = 0;
+ int high = p_list->realCount - 1;
+
+ while (low <= high)
+ {
+ int i = (low + high) / 2;
+ unsigned __int64 vali = *(unsigned __int64 *)p_list->items[i];
+ if (vali == val)
+ {
+ *p_index = i;
+ return 1;
+ }
+
+ if (vali < val)
+ low = i + 1;
+ else
+ high = i - 1;
+ }
+
+ *p_index = low;
+ }
+ break;
+#endif
+
+ case NumericKeySort:
+ {
+ const unsigned val = *(unsigned *)p_value;
+ int low = 0;
+ int high = p_list->realCount - 1;
+
+ while (low <= high)
+ {
+ int i = (low + high) / 2;
+ unsigned vali = *(unsigned *)p_list->items[i];
+ if (vali == val)
+ {
+ *p_index = i;
+ return 1;
+ }
+
+ if (vali < val)
+ low = i + 1;
+ else
+ high = i - 1;
+ }
+
+ *p_index = low;
+ }
+ break;
+
+ case PtrKeySort:
+ {
+ int low = 0;
+ int high = p_list->realCount - 1;
+
+ while (low <= high)
+ {
+ int i = (low + high) / 2;
+ const void* vali = p_list->items[i];
+ if (vali == p_value)
+ {
+ *p_index = i;
+ return 1;
+ }
+
+ if (vali < p_value)
+ low = i + 1;
+ else
+ high = i - 1;
+ }
+
+ *p_index = low;
+ }
+ break;
+
+ default:
+ {
+ int low = 0;
+ int high = p_list->realCount - 1;
+
+ while (low <= high)
+ {
+ int i = (low + high) / 2;
+ int result = p_list->sortFunc(p_list->items[i], p_value);
+ if (result == 0)
+ {
+ *p_index = i;
+ return 1;
+ }
+
+ if (result < 0)
+ low = i + 1;
+ else
+ high = i - 1;
+ }
+
+ *p_index = low;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+int List_IndexOf( SortedList* p_list, void* p_value )
+{
+ if ( p_value == NULL )
+ return -1;
+
+ int i;
+ for ( i=0; i < p_list->realCount; i++ )
+ if ( p_list->items[i] == p_value )
+ return i;
+
+ return -1;
+}
+
+#ifdef _DEBUG
+#pragma optimize( "", on )
+#endif
+
+int List_Insert( SortedList* p_list, void* p_value, int p_index)
+{
+ if ( p_value == NULL || p_index > p_list->realCount )
+ return 0;
+
+ if ( p_list->realCount == p_list->limit )
+ {
+ p_list->items = ( void** )mir_realloc( p_list->items, sizeof( void* )*(p_list->realCount + p_list->increment));
+ p_list->limit += p_list->increment;
+ }
+
+ if ( p_index < p_list->realCount )
+ memmove( p_list->items+p_index+1, p_list->items+p_index, sizeof( void* )*( p_list->realCount-p_index ));
+
+ p_list->realCount++;
+
+ p_list->items[ p_index ] = p_value;
+ return 1;
+}
+
+int List_InsertPtr( SortedList* list, void* p )
+{
+ if ( p == NULL )
+ return -1;
+
+ int idx = list->realCount;
+ List_GetIndex( list, p, &idx );
+ return List_Insert( list, p, idx );
+}
+
+int List_Remove( SortedList* p_list, int index )
+{
+ if ( index < 0 || index > p_list->realCount )
+ return(0);
+
+ p_list->realCount--;
+ if ( p_list->realCount > index )
+ {
+ memmove( p_list->items+index, p_list->items+index+1, sizeof( void* )*( p_list->realCount-index ));
+ p_list->items[ p_list->realCount ] = NULL;
+ }
+
+ return 1;
+}
+
+int List_RemovePtr( SortedList* list, void* p )
+{
+ int idx = -1;
+ if ( List_GetIndex( list, p, &idx ))
+ List_Remove( list, idx );
+
+ return idx;
+}
+
+void List_Copy( SortedList* s, SortedList* d, size_t itemSize )
+{
+ int i;
+
+ d->increment = s->increment;
+ d->sortFunc = s->sortFunc;
+
+ for ( i = 0; i < s->realCount; i++ ) {
+ void* item = mir_alloc( itemSize );
+ memcpy( item, s->items[i], itemSize );
+ List_Insert( d, item, i );
+} }
+
+void List_ObjCopy( SortedList* s, SortedList* d, size_t itemSize )
+{
+ int i;
+
+ d->increment = s->increment;
+ d->sortFunc = s->sortFunc;
+
+ for ( i = 0; i < s->realCount; i++ ) {
+ void* item = new char[ itemSize ];
+ memcpy( item, s->items[i], itemSize );
+ List_Insert( d, item, i );
+} }
diff --git a/src/modules/database/dblists.h b/src/modules/database/dblists.h
new file mode 100644
index 0000000000..30886973a4
--- /dev/null
+++ b/src/modules/database/dblists.h
@@ -0,0 +1,39 @@
+/*
+
+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.
+*/
+
+/* a simple sorted list implementation */
+
+SortedList* List_Create( int, int );
+void List_Destroy( SortedList* );
+
+void* List_Find( SortedList*, void* );
+int List_GetIndex( SortedList*, void*, int* );
+int List_Insert( SortedList*, void*, int );
+int List_Remove( SortedList*, int );
+int List_IndexOf( SortedList*, void* );
+
+int List_InsertPtr( SortedList* list, void* p );
+int List_RemovePtr( SortedList* list, void* p );
+
+void List_Copy( SortedList*, SortedList*, size_t );
+void List_ObjCopy( SortedList*, SortedList*, size_t ); \ No newline at end of file
diff --git a/src/modules/database/dbutils.cpp b/src/modules/database/dbutils.cpp
new file mode 100644
index 0000000000..1e73ddd18e
--- /dev/null
+++ b/src/modules/database/dbutils.cpp
@@ -0,0 +1,365 @@
+/*
+
+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 "profilemanager.h"
+
+static int CompareEventTypes( const DBEVENTTYPEDESCR* p1, const DBEVENTTYPEDESCR* p2 )
+{
+ int result = strcmp( p1->module, p2->module );
+ if ( result )
+ return result;
+
+ return p1->eventType - p2->eventType;
+}
+
+static LIST<DBEVENTTYPEDESCR> eventTypes( 10, CompareEventTypes );
+
+static BOOL bModuleInitialized = FALSE;
+
+static INT_PTR DbEventTypeRegister(WPARAM, LPARAM lParam)
+{
+ DBEVENTTYPEDESCR* et = ( DBEVENTTYPEDESCR* )lParam;
+ if ( eventTypes.getIndex( et ) == -1 ) {
+ DBEVENTTYPEDESCR* p = ( DBEVENTTYPEDESCR* )mir_alloc( sizeof( DBEVENTTYPEDESCR ));
+ p->cbSize = DBEVENTTYPEDESCR_SIZE;
+ p->module = mir_strdup( et->module );
+ p->eventType = et->eventType;
+ p->descr = mir_strdup( et->descr );
+ p->textService = NULL;
+ p->iconService = NULL;
+ p->eventIcon = NULL;
+ p->flags = 0;
+ if ( et->cbSize == DBEVENTTYPEDESCR_SIZE ) {
+ if ( et->textService )
+ p->textService = mir_strdup( et->textService );
+ if ( et->iconService )
+ p->iconService = mir_strdup( et->iconService );
+ p->eventIcon = et->eventIcon;
+ p->flags = et->flags;
+ }
+ if ( !p->textService ) {
+ char szServiceName[100];
+ mir_snprintf( szServiceName, sizeof(szServiceName), "%s/GetEventText%d", p->module, p->eventType );
+ p->textService = mir_strdup( szServiceName );
+ }
+ if ( !p->iconService ) {
+ char szServiceName[100];
+ mir_snprintf( szServiceName, sizeof(szServiceName), "%s/GetEventIcon%d", p->module, p->eventType );
+ p->iconService = mir_strdup( szServiceName );
+ }
+ eventTypes.insert( p );
+ }
+
+ return 0;
+}
+
+static INT_PTR DbEventTypeGet(WPARAM wParam, LPARAM lParam)
+{
+ DBEVENTTYPEDESCR tmp;
+ int idx;
+
+ tmp.module = ( char* )wParam;
+ tmp.eventType = lParam;
+ if ( !List_GetIndex(( SortedList* )&eventTypes, &tmp, &idx ))
+ return 0;
+
+ return ( INT_PTR )eventTypes[idx];
+}
+
+static INT_PTR DbEventGetText(WPARAM wParam, LPARAM lParam)
+{
+ DBEVENTGETTEXT* egt = (DBEVENTGETTEXT*)lParam;
+ BOOL bIsDenyUnicode = (egt->datatype & DBVTF_DENYUNICODE);
+
+ DBEVENTINFO* dbei = egt->dbei;
+ DBEVENTTYPEDESCR* et = ( DBEVENTTYPEDESCR* )DbEventTypeGet( ( WPARAM )dbei->szModule, ( LPARAM )dbei->eventType );
+
+ if ( et && ServiceExists( et->textService ))
+ return CallService( et->textService, wParam, lParam );
+
+ if ( !dbei->pBlob ) return 0;
+
+ if ( dbei->eventType == EVENTTYPE_FILE ) {
+ char* filename = ((char *)dbei->pBlob) + sizeof(DWORD);
+ char* descr = filename + lstrlenA( filename ) + 1;
+ char* str = (*descr == 0) ? filename : descr;
+ switch ( egt->datatype ) {
+ case DBVT_WCHAR:
+ return ( INT_PTR )(( dbei->flags & DBEF_UTF ) ?
+ Utf8DecodeT( str ) : mir_a2t( str ));
+ case DBVT_ASCIIZ:
+ return ( INT_PTR )(( dbei->flags & DBEF_UTF ) ? Utf8Decode( mir_strdup( str ), NULL ) : mir_strdup( str ));
+ }
+ return 0;
+ }
+
+ // temporary fix for bug with event types conflict between jabber chat states notifications
+ // and srmm's status changes, must be commented out in future releases
+ if ( dbei->eventType == 25368 && dbei->cbBlob == 1 && dbei->pBlob[0] == 1 )
+ return 0;
+
+ egt->datatype &= ~DBVTF_DENYUNICODE;
+ if ( egt->datatype == DBVT_WCHAR )
+ {
+ WCHAR* msg = NULL;
+ if ( dbei->flags & DBEF_UTF ) {
+ char* str = (char*)alloca(dbei->cbBlob + 1);
+ if (str == NULL) return NULL;
+ memcpy(str, dbei->pBlob, dbei->cbBlob);
+ str[dbei->cbBlob] = 0;
+ Utf8DecodeCP( str, egt->codepage, &msg );
+ }
+ else {
+ size_t msglen = strlen(( char* )dbei->pBlob) + 1, msglenW = 0;
+ if ( msglen != dbei->cbBlob ) {
+ size_t i, count = (( dbei->cbBlob - msglen ) / sizeof( WCHAR ));
+ WCHAR* p = ( WCHAR* )&dbei->pBlob[ msglen ];
+ for ( i=0; i < count; i++ ) {
+ if ( p[i] == 0 ) {
+ msglenW = i;
+ break;
+ } } }
+
+ if ( msglenW > 0 && msglenW < msglen && !bIsDenyUnicode )
+ msg = mir_wstrdup(( WCHAR* )&dbei->pBlob[ msglen ] );
+ else {
+ msg = ( WCHAR* )mir_alloc( sizeof(WCHAR) * msglen );
+ MultiByteToWideChar( egt->codepage, 0, (char *) dbei->pBlob, -1, msg, (int)msglen );
+ } }
+ return ( INT_PTR )msg;
+ }
+ else if ( egt->datatype == DBVT_ASCIIZ ) {
+ char* msg = mir_strdup(( char* )dbei->pBlob );
+ if (dbei->flags & DBEF_UTF)
+ Utf8DecodeCP( msg, egt->codepage, NULL );
+
+ return ( INT_PTR )msg;
+ }
+ return 0;
+}
+
+static INT_PTR DbEventGetIcon( WPARAM wParam, LPARAM lParam )
+{
+ DBEVENTINFO* dbei = ( DBEVENTINFO* )lParam;
+ HICON icon = NULL;
+ DBEVENTTYPEDESCR* et = ( DBEVENTTYPEDESCR* )DbEventTypeGet( ( WPARAM )dbei->szModule, ( LPARAM )dbei->eventType );
+
+ if ( et && ServiceExists( et->iconService )) {
+ icon = ( HICON )CallService( et->iconService, wParam, lParam );
+ if ( icon )
+ return ( INT_PTR )icon;
+ }
+ if ( et && et->eventIcon )
+ icon = ( HICON )CallService( MS_SKIN2_GETICONBYHANDLE, 0, ( LPARAM )et->eventIcon );
+ if ( !icon ) {
+ char szName[100];
+ mir_snprintf( szName, sizeof( szName ), "eventicon_%s%d", dbei->szModule, dbei->eventType );
+ icon = ( HICON )CallService( MS_SKIN2_GETICON, 0, ( LPARAM )szName );
+ }
+
+ if ( !icon )
+ {
+ switch( dbei->eventType ) {
+ case EVENTTYPE_URL:
+ icon = LoadSkinIcon( SKINICON_EVENT_URL );
+ break;
+
+ case EVENTTYPE_FILE:
+ icon = LoadSkinIcon( SKINICON_EVENT_FILE );
+ break;
+
+ default: // EVENTTYPE_MESSAGE and unknown types
+ icon = LoadSkinIcon( SKINICON_EVENT_MESSAGE );
+ break;
+ }
+ }
+
+ if ( wParam & LR_SHARED )
+ return ( INT_PTR )icon;
+ else
+ return ( INT_PTR )CopyIcon( icon );
+}
+
+static INT_PTR DbEventGetStringT( WPARAM wParam, LPARAM lParam )
+{
+ DBEVENTINFO* dbei = ( DBEVENTINFO* )wParam;
+ char* string = ( char* )lParam;
+
+ #if defined( _UNICODE )
+ if ( dbei->flags & DBEF_UTF )
+ return ( INT_PTR )Utf8DecodeUcs2( string );
+
+ return ( INT_PTR )mir_a2t( string );
+ #else
+ char* res = mir_strdup( string );
+ if ( dbei->flags & DBEF_UTF )
+ Utf8Decode( res, NULL );
+ return ( INT_PTR )res;
+ #endif
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static int sttEnumVars( const char* szVarName, LPARAM lParam )
+{
+ LIST<char>* vars = ( LIST<char>* )lParam;
+ vars->insert( mir_strdup( szVarName ));
+ return 0;
+}
+
+static INT_PTR DbDeleteModule( WPARAM, LPARAM lParam )
+{
+ LIST<char> vars( 20 );
+
+ DBCONTACTENUMSETTINGS dbces = { 0 };
+ dbces.pfnEnumProc = sttEnumVars;
+ dbces.lParam = ( LPARAM )&vars;
+ dbces.szModule = ( char* )lParam;
+ CallService( MS_DB_CONTACT_ENUMSETTINGS, NULL, (LPARAM)&dbces );
+
+ for ( int i=vars.getCount()-1; i >= 0; i-- ) {
+ DBDeleteContactSetting( NULL, ( char* )lParam, vars[i] );
+ mir_free( vars[i] );
+ }
+ vars.destroy();
+ return 0;
+}
+
+static INT_PTR GetProfilePath(WPARAM wParam, LPARAM lParam)
+{
+ if (!wParam || !lParam)
+ return 1;
+
+ char* dst = (char*)lParam;
+
+ #if defined( _UNICODE )
+ char* tmp = mir_t2a( g_profileDir );
+ strncpy( dst, tmp, wParam );
+ mir_free( tmp );
+ #else
+ strncpy( dst, g_profileDir, wParam );
+ #endif
+
+ if (wParam <= _tcslen(g_profileName))
+ {
+ dst[wParam - 1] = 0;
+ return 1;
+ }
+ return 0;
+}
+
+static INT_PTR GetProfileName(WPARAM wParam, LPARAM lParam)
+{
+ if (!wParam || !lParam)
+ return 1;
+
+ char* dst = (char*)lParam;
+
+ #if defined( _UNICODE )
+ char* tmp = makeFileName( g_profileName );
+ strncpy( dst, tmp, wParam );
+ mir_free( tmp );
+ #else
+ strncpy( dst, g_profileName, wParam );
+ #endif
+
+ if (wParam <= _tcslen(g_profileName))
+ {
+ dst[wParam - 1] = 0;
+ return 1;
+ }
+ return 0;
+}
+
+#if defined( _UNICODE )
+
+static INT_PTR GetProfilePathW(WPARAM wParam, LPARAM lParam)
+{
+ if (!wParam || !lParam)
+ return 1;
+
+ wchar_t* dst = (wchar_t*)lParam;
+ wcsncpy(dst, g_profileDir, wParam);
+ if (wParam <= wcslen(g_profileDir))
+ {
+ dst[wParam - 1] = 0;
+ return 1;
+ }
+ return 0;
+}
+
+static INT_PTR GetProfileNameW(WPARAM wParam, LPARAM lParam)
+{
+ wchar_t* dst = (wchar_t*)lParam;
+ wcsncpy(dst, g_profileName, wParam );
+ if (wParam <= wcslen(g_profileName))
+ {
+ dst[wParam - 1] = 0;
+ return 1;
+ }
+ return 0;
+}
+
+#endif
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int InitUtils()
+{
+ bModuleInitialized = TRUE;
+
+ CreateServiceFunction(MS_DB_EVENT_REGISTERTYPE, DbEventTypeRegister);
+ CreateServiceFunction(MS_DB_EVENT_GETTYPE, DbEventTypeGet);
+ CreateServiceFunction(MS_DB_EVENT_GETTEXT, DbEventGetText);
+ CreateServiceFunction(MS_DB_EVENT_GETICON, DbEventGetIcon);
+ CreateServiceFunction(MS_DB_EVENT_GETSTRINGT, DbEventGetStringT);
+
+ CreateServiceFunction(MS_DB_MODULE_DELETE, DbDeleteModule);
+
+ CreateServiceFunction(MS_DB_GETPROFILEPATH,GetProfilePath);
+ CreateServiceFunction(MS_DB_GETPROFILENAME,GetProfileName);
+ #if defined( _UNICODE )
+ CreateServiceFunction(MS_DB_GETPROFILEPATHW,GetProfilePathW);
+ CreateServiceFunction(MS_DB_GETPROFILENAMEW,GetProfileNameW);
+ #endif
+ return 0;
+}
+
+void UnloadEventsModule()
+{
+ int i;
+
+ if ( !bModuleInitialized ) return;
+
+ for ( i=0; i < eventTypes.getCount(); i++ ) {
+ DBEVENTTYPEDESCR* p = eventTypes[i];
+ mir_free( p->module );
+ mir_free( p->descr );
+ mir_free( p->textService );
+ mir_free( p->iconService );
+ mir_free( p );
+ }
+
+ eventTypes.destroy();
+}
diff --git a/src/modules/database/profilemanager.cpp b/src/modules/database/profilemanager.cpp
new file mode 100644
index 0000000000..06cd356d7c
--- /dev/null
+++ b/src/modules/database/profilemanager.cpp
@@ -0,0 +1,850 @@
+/*
+
+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 "profilemanager.h"
+#include <sys/stat.h>
+
+#define WM_INPUTCHANGED (WM_USER + 0x3000)
+#define WM_FOCUSTEXTBOX (WM_USER + 0x3001)
+
+typedef BOOL (__cdecl *ENUMPROFILECALLBACK) (TCHAR * fullpath, TCHAR * profile, LPARAM lParam);
+
+struct DetailsPageInit {
+ int pageCount;
+ OPTIONSDIALOGPAGE *odp;
+};
+
+struct DetailsPageData {
+ DLGTEMPLATE *pTemplate;
+ HINSTANCE hInst;
+ DLGPROC dlgProc;
+ HWND hwnd;
+ int changed;
+};
+
+struct DlgProfData {
+ PROPSHEETHEADER * psh;
+ HWND hwndOK; // handle to OK button
+ PROFILEMANAGERDATA * pd;
+ HANDLE hFileNotify;
+};
+
+struct DetailsData {
+ HINSTANCE hInstIcmp;
+ HFONT hBoldFont;
+ int pageCount;
+ int currentPage;
+ struct DetailsPageData *opd;
+ RECT rcDisplay;
+ struct DlgProfData * prof;
+};
+
+struct ProfileEnumData {
+ HWND hwnd;
+ TCHAR* szProfile;
+};
+
+extern TCHAR mirandabootini[MAX_PATH];
+
+char **GetSeviceModePluginsList(void);
+void SetServiceModePlugin( int idx );
+
+static void ThemeDialogBackground(HWND hwnd)
+{
+ if (enableThemeDialogTexture)
+ enableThemeDialogTexture(hwnd, ETDT_ENABLETAB);
+}
+
+static int findProfiles(TCHAR * szProfileDir, ENUMPROFILECALLBACK callback, LPARAM lParam)
+{
+ // find in Miranda IM profile subfolders
+ HANDLE hFind = INVALID_HANDLE_VALUE;
+ WIN32_FIND_DATA ffd;
+ TCHAR searchspec[MAX_PATH];
+ mir_sntprintf(searchspec, SIZEOF(searchspec), _T("%s\\*.*"), szProfileDir);
+ hFind = FindFirstFile(searchspec, &ffd);
+ if ( hFind == INVALID_HANDLE_VALUE )
+ return 0;
+
+ do {
+ // find all subfolders except "." and ".."
+ if ( (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && _tcscmp(ffd.cFileName, _T(".")) && _tcscmp(ffd.cFileName, _T("..")) ) {
+ TCHAR buf[MAX_PATH], profile[MAX_PATH];
+ mir_sntprintf(buf, SIZEOF(buf), _T("%s\\%s\\%s.dat"), szProfileDir, ffd.cFileName, ffd.cFileName);
+ if (_taccess(buf, 0) == 0) {
+ mir_sntprintf(profile, SIZEOF(profile), _T("%s.dat"), ffd.cFileName);
+ if ( !callback(buf, profile, lParam ))
+ break;
+ }
+ }
+ }
+ while ( FindNextFile(hFind, &ffd) );
+ FindClose(hFind);
+
+ return 1;
+}
+
+static LRESULT CALLBACK ProfileNameValidate(HWND edit, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ if ( msg == WM_CHAR ) {
+ if ( _tcschr( _T(".?/\\#' "), (TCHAR)wParam) != 0 )
+ return 0;
+ PostMessage(GetParent(edit),WM_INPUTCHANGED,0,0);
+ }
+ return CallWindowProc((WNDPROC)GetWindowLongPtr(edit,GWLP_USERDATA),edit,msg,wParam,lParam);
+}
+
+static int FindDbProviders(const char*, DATABASELINK * dblink, LPARAM lParam)
+{
+ HWND hwndDlg = (HWND)lParam;
+ HWND hwndCombo = GetDlgItem(hwndDlg, IDC_PROFILEDRIVERS);
+ char szName[64];
+
+ if ( dblink->getFriendlyName(szName,SIZEOF(szName),1) == 0 ) {
+ // add to combo box
+ TCHAR* p = LangPackPcharToTchar( szName );
+ LRESULT index = SendMessage( hwndCombo, CB_ADDSTRING, 0, (LPARAM)p );
+ mir_free( p );
+ SendMessage(hwndCombo, CB_SETITEMDATA, index, (LPARAM)dblink);
+ }
+ return DBPE_CONT;
+}
+
+static INT_PTR CALLBACK DlgProfileNew(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct DlgProfData * dat = (struct DlgProfData *)GetWindowLongPtr(hwndDlg,GWLP_USERDATA);
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault( hwndDlg );
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
+ dat = (struct DlgProfData *)lParam;
+ {
+ // fill in the db plugins present
+ PLUGIN_DB_ENUM dbe;
+ dbe.cbSize = sizeof(dbe);
+ dbe.pfnEnumCallback = (int(*)(const char*,void*,LPARAM))FindDbProviders;
+ dbe.lParam = (LPARAM)hwndDlg;
+ if ( CallService( MS_PLUGINS_ENUMDBPLUGINS, 0, ( LPARAM )&dbe ) == -1 ) {
+ // no plugins?!
+ EnableWindow( GetDlgItem(hwndDlg, IDC_PROFILEDRIVERS ), FALSE );
+ EnableWindow( GetDlgItem(hwndDlg, IDC_PROFILENAME ), FALSE );
+ ShowWindow( GetDlgItem(hwndDlg, IDC_NODBDRIVERS ), TRUE );
+ }
+ // default item
+ SendDlgItemMessage(hwndDlg, IDC_PROFILEDRIVERS, CB_SETCURSEL, 0, 0);
+ }
+ // subclass the profile name box
+ {
+ HWND hwndProfile = GetDlgItem(hwndDlg, IDC_PROFILENAME);
+ WNDPROC proc = (WNDPROC)GetWindowLongPtr(hwndProfile, GWLP_WNDPROC);
+ SetWindowLongPtr(hwndProfile,GWLP_USERDATA,(LONG_PTR)proc);
+ SetWindowLongPtr(hwndProfile,GWLP_WNDPROC,(LONG_PTR)ProfileNameValidate);
+ }
+
+ // decide if there is a default profile name given in the INI and if it should be used
+ if (dat->pd->noProfiles || (shouldAutoCreate(dat->pd->szProfile) && _taccess(dat->pd->szProfile, 0)))
+ {
+ TCHAR* profile = _tcsrchr(dat->pd->szProfile, '\\');
+ if (profile) ++profile;
+ else profile = dat->pd->szProfile;
+
+ TCHAR *p = _tcsrchr(profile, '.');
+ TCHAR c = 0;
+ if (p) { c = *p; *p = 0; }
+
+ SetDlgItemText(hwndDlg, IDC_PROFILENAME, profile);
+ if (c) *p = c;
+ }
+
+ // focus on the textbox
+ PostMessage( hwndDlg, WM_FOCUSTEXTBOX, 0, 0 );
+ return TRUE;
+
+ case WM_FOCUSTEXTBOX:
+ SetFocus( GetDlgItem( hwndDlg, IDC_PROFILENAME ));
+ break;
+
+ case WM_INPUTCHANGED: // when input in the edit box changes
+ SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
+ EnableWindow( dat->hwndOK, GetWindowTextLength( GetDlgItem( hwndDlg, IDC_PROFILENAME )) > 0 );
+ break;
+
+ case WM_SHOWWINDOW:
+ if ( wParam ) {
+ SetWindowText( dat->hwndOK, TranslateT("&Create"));
+ SendMessage( hwndDlg, WM_INPUTCHANGED, 0, 0 );
+ }
+ break;
+
+ case WM_NOTIFY:
+ {
+ NMHDR* hdr = ( NMHDR* )lParam;
+ if ( hdr && hdr->code == PSN_APPLY && dat && IsWindowVisible( hwndDlg )) {
+ TCHAR szName[MAX_PATH];
+ LRESULT curSel = SendDlgItemMessage(hwndDlg,IDC_PROFILEDRIVERS,CB_GETCURSEL,0,0);
+ if ( curSel == CB_ERR ) break; // should never happen
+ GetDlgItemText(hwndDlg, IDC_PROFILENAME, szName, SIZEOF( szName ));
+ if ( szName[0] == 0 )
+ break;
+
+ // profile placed in "profile_name" subfolder
+ mir_sntprintf( dat->pd->szProfile, MAX_PATH, _T("%s\\%s\\%s.dat"), dat->pd->szProfileDir, szName, szName );
+ dat->pd->newProfile = 1;
+ dat->pd->dblink = (DATABASELINK *)SendDlgItemMessage( hwndDlg, IDC_PROFILEDRIVERS, CB_GETITEMDATA, ( WPARAM )curSel, 0 );
+
+ if ( makeDatabase( dat->pd->szProfile, dat->pd->dblink, hwndDlg ) == 0 ) {
+ SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE );
+ } } }
+ break;
+ }
+
+ return FALSE;
+}
+
+static int DetectDbProvider(const char*, DATABASELINK * dblink, LPARAM lParam)
+{
+ int error;
+
+#ifdef _UNICODE
+ char* fullpath = makeFileName(( TCHAR* )lParam );
+#else
+ char* fullpath = (char*)lParam;
+#endif
+
+ int ret = dblink->grokHeader(fullpath, &error);
+#ifdef _UNICODE
+ mir_free( fullpath );
+#endif
+ if ( ret == 0) {
+#ifdef _UNICODE
+ char tmp[ MAX_PATH ];
+ dblink->getFriendlyName(tmp, SIZEOF(tmp), 1);
+ MultiByteToWideChar(CP_ACP, 0, tmp, -1, (TCHAR*)lParam, MAX_PATH);
+#else
+ dblink->getFriendlyName((TCHAR*)lParam, MAX_PATH, 1);
+#endif
+ return DBPE_HALT;
+ }
+
+ return DBPE_CONT;
+}
+
+BOOL EnumProfilesForList(TCHAR * fullpath, TCHAR * profile, LPARAM lParam)
+{
+ ProfileEnumData *ped = (ProfileEnumData*)lParam;
+ HWND hwndList = GetDlgItem(ped->hwnd, IDC_PROFILELIST);
+
+ TCHAR sizeBuf[64];
+ int iItem=0;
+ struct _stat statbuf;
+ bool bFileExists = false, bFileLocked = true;
+
+ TCHAR* p = _tcsrchr(profile, '.');
+ _tcscpy(sizeBuf, _T("0 KB"));
+ if ( p != NULL ) *p=0;
+
+ LVITEM item = { 0 };
+ item.mask = LVIF_TEXT | LVIF_IMAGE;
+ item.pszText = profile;
+ item.iItem = 0;
+
+ if ( _tstat(fullpath, &statbuf) == 0) {
+ if ( statbuf.st_size > 1000000 ) {
+ mir_sntprintf(sizeBuf,SIZEOF(sizeBuf), _T("%.3lf"), (double)statbuf.st_size / 1048576.0 );
+ _tcscpy(sizeBuf+5, _T(" MB"));
+ }
+ else {
+ mir_sntprintf(sizeBuf,SIZEOF(sizeBuf), _T("%.3lf"), (double)statbuf.st_size / 1024.0 );
+ _tcscpy(sizeBuf+5, _T(" KB"));
+ }
+ bFileExists = TRUE;
+
+ bFileLocked = !fileExist(fullpath);
+ }
+
+ item.iImage = bFileLocked;
+
+ iItem = SendMessage( hwndList, LVM_INSERTITEM, 0, (LPARAM)&item );
+ if ( lstrcmpi(ped->szProfile, fullpath) == 0 )
+ ListView_SetItemState(hwndList, iItem, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
+
+ item.iItem = iItem;
+ item.iSubItem = 2;
+ item.pszText = sizeBuf;
+ SendMessage( hwndList, LVM_SETITEMTEXT, iItem, (LPARAM)&item );
+
+ if ( bFileExists ) {
+ PLUGIN_DB_ENUM dbe;
+ TCHAR szPath[MAX_PATH];
+
+ LVITEM item2;
+ item2.mask = LVIF_TEXT;
+ item2.iItem = iItem;
+
+ dbe.cbSize = sizeof(dbe);
+ dbe.pfnEnumCallback = (int(*)(const char*,void*,LPARAM))DetectDbProvider;
+ dbe.lParam = (LPARAM)szPath;
+ _tcscpy(szPath, fullpath);
+ if ( CallService( MS_PLUGINS_ENUMDBPLUGINS, 0, ( LPARAM )&dbe ) == 1 ) {
+ if (bFileLocked) {
+ // file locked
+ item2.pszText = TranslateT( "<In Use>" );
+ item2.iSubItem = 1;
+ SendMessage( hwndList, LVM_SETITEMTEXT, iItem, ( LPARAM )&item2 );
+ }
+ else {
+ item.pszText = szPath;
+ item.iSubItem = 1;
+ SendMessage( hwndList, LVM_SETITEMTEXT, iItem, (LPARAM)&item );
+ } }
+
+ item2.iSubItem = 3;
+ item2.pszText = rtrim( _tctime( &statbuf.st_ctime ));
+ SendMessage( hwndList, LVM_SETITEMTEXT, iItem, (LPARAM)&item2 );
+
+ item2.iSubItem = 4;
+ item2.pszText = rtrim( _tctime( &statbuf.st_mtime ));
+ SendMessage( hwndList, LVM_SETITEMTEXT, iItem, (LPARAM)&item2 );
+ }
+ return TRUE;
+}
+
+void DeleteProfile(HWND hwndList, int iItem, DlgProfData* dat)
+{
+ if (iItem < 0)
+ return;
+
+ TCHAR profile[MAX_PATH], profilef[MAX_PATH*2];
+
+ LVITEM item = {0};
+ item.mask = LVIF_TEXT;
+ item.iItem = iItem;
+ item.pszText = profile;
+ item.cchTextMax = SIZEOF(profile);
+ if (!ListView_GetItem(hwndList, &item))
+ return;
+
+ mir_sntprintf(profilef, SIZEOF(profilef), TranslateT("Are you sure you want to remove profile \"%s\"?"), profile);
+
+ if (IDYES != MessageBox(NULL, profilef, _T("Miranda IM"), MB_YESNO | MB_TASKMODAL | MB_ICONWARNING))
+ return;
+
+ mir_sntprintf(profilef, SIZEOF(profilef), _T("%s\\%s%c"), dat->pd->szProfileDir, profile, 0);
+
+ SHFILEOPSTRUCT sf = {0};
+ sf.wFunc = FO_DELETE;
+ sf.pFrom = profilef;
+ sf.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_ALLOWUNDO;
+ SHFileOperation(&sf);
+ ListView_DeleteItem(hwndList, item.iItem);
+}
+
+static INT_PTR CALLBACK DlgProfileSelect(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ DlgProfData* dat = (struct DlgProfData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ HWND hwndList = GetDlgItem(hwndDlg, IDC_PROFILELIST);
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ {
+ HIMAGELIST hImgList;
+ LVCOLUMN col;
+
+ TranslateDialogDefault( hwndDlg );
+
+ dat = (DlgProfData*) lParam;
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)dat);
+
+ // set columns
+ col.mask = LVCF_TEXT | LVCF_WIDTH;
+ col.pszText = TranslateT("Profile");
+ col.cx=122;
+ ListView_InsertColumn( hwndList, 0, &col );
+
+ col.pszText = TranslateT("Driver");
+ col.cx=100;
+ ListView_InsertColumn( hwndList, 1, &col );
+
+ col.pszText = TranslateT("Size");
+ col.cx=60;
+ ListView_InsertColumn( hwndList, 2, &col );
+
+ col.pszText = TranslateT("Created");
+ col.cx=145;
+ ListView_InsertColumn( hwndList, 3, &col );
+
+ col.pszText = TranslateT("Modified");
+ col.cx=145;
+ ListView_InsertColumn( hwndList, 4, &col );
+
+ // icons
+ hImgList = ImageList_Create(16, 16, ILC_MASK | (IsWinVerXPPlus() ? ILC_COLOR32 : ILC_COLOR16), 2, 1);
+ ImageList_AddIcon_NotShared(hImgList, MAKEINTRESOURCE(IDI_USERDETAILS));
+ ImageList_AddIcon_NotShared(hImgList, MAKEINTRESOURCE(IDI_DELETE));
+
+ // LV will destroy the image list
+ SetWindowLongPtr(hwndList, GWL_STYLE, GetWindowLongPtr(hwndList, GWL_STYLE) | LVS_SORTASCENDING);
+ ListView_SetImageList(hwndList, hImgList, LVSIL_SMALL);
+ ListView_SetExtendedListViewStyle(hwndList,
+ ListView_GetExtendedListViewStyle(hwndList) | LVS_EX_DOUBLEBUFFER | LVS_EX_LABELTIP | LVS_EX_FULLROWSELECT);
+
+ // find all the profiles
+ ProfileEnumData ped = { hwndDlg, dat->pd->szProfile };
+ findProfiles(dat->pd->szProfileDir, EnumProfilesForList, (LPARAM)&ped);
+ PostMessage(hwndDlg, WM_FOCUSTEXTBOX, 0, 0);
+
+ dat->hFileNotify = FindFirstChangeNotification(dat->pd->szProfileDir, TRUE,
+ FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE);
+ if (dat->hFileNotify != INVALID_HANDLE_VALUE)
+ SetTimer(hwndDlg, 0, 1200, NULL);
+ return TRUE;
+ }
+
+ case WM_DESTROY:
+ KillTimer(hwndDlg, 0);
+ FindCloseChangeNotification(dat->hFileNotify);
+ break;
+
+ case WM_TIMER:
+ if (WaitForSingleObject(dat->hFileNotify, 0) == WAIT_OBJECT_0)
+ {
+ ListView_DeleteAllItems(hwndList);
+ ProfileEnumData ped = { hwndDlg, dat->pd->szProfile };
+ findProfiles(dat->pd->szProfileDir, EnumProfilesForList, (LPARAM)&ped);
+ FindNextChangeNotification(dat->hFileNotify);
+ }
+ break;
+
+ case WM_FOCUSTEXTBOX:
+ SetFocus(hwndList);
+ if (dat->pd->szProfile[0] == 0 || ListView_GetSelectedCount(hwndList) == 0)
+ ListView_SetItemState(hwndList, 0, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
+ break;
+
+ case WM_SHOWWINDOW:
+ if ( wParam )
+ {
+ SetWindowText(dat->hwndOK, TranslateT("&Run"));
+ EnableWindow(dat->hwndOK, ListView_GetSelectedCount(hwndList)==1);
+ }
+ break;
+
+ case WM_CONTEXTMENU:
+ {
+ LVHITTESTINFO lvht = {0};
+ lvht.pt.x = GET_X_LPARAM(lParam);
+ lvht.pt.y = GET_Y_LPARAM(lParam);
+ ScreenToClient(hwndList, &lvht.pt);
+ if (ListView_HitTest(hwndList, &lvht) < 0) break;
+
+ lvht.pt.x = GET_X_LPARAM(lParam);
+ lvht.pt.y = GET_Y_LPARAM(lParam);
+
+ HMENU hMenu = CreatePopupMenu();
+ AppendMenu(hMenu, MF_STRING, 1, TranslateT("Run"));
+ AppendMenu(hMenu, MF_SEPARATOR, 2, NULL);
+ AppendMenu(hMenu, MF_STRING, 3, TranslateT("Delete"));
+ int index = TrackPopupMenu(hMenu, TPM_RETURNCMD, lvht.pt.x, lvht.pt.y, 0, hwndDlg, NULL);
+ switch (index) {
+ case 1:
+ SendMessage(GetParent(hwndDlg), WM_COMMAND, IDOK, 0);
+ break;
+
+ case 3:
+ DeleteProfile(hwndList, lvht.iItem, dat);
+ break;
+ }
+ DestroyMenu(hMenu);
+ break;
+ }
+
+
+ case WM_NOTIFY:
+ {
+ LPNMHDR hdr = (LPNMHDR) lParam;
+ if (hdr && hdr->code == PSN_INFOCHANGED)
+ break;
+
+ if (hdr && hdr->idFrom == IDC_PROFILELIST)
+ {
+ switch (hdr->code)
+ {
+ case LVN_ITEMCHANGED:
+ EnableWindow(dat->hwndOK, ListView_GetSelectedCount(hwndList) == 1);
+
+ case NM_DBLCLK:
+ {
+ LVITEM item = {0};
+ TCHAR profile[MAX_PATH];
+
+ if (dat == NULL) break;
+
+ item.mask = LVIF_TEXT;
+ item.iItem = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED | LVNI_ALL);
+ item.pszText = profile;
+ item.cchTextMax = SIZEOF(profile);
+
+ if (ListView_GetItem(hwndList, &item)) {
+ // profile is placed in "profile_name" subfolder
+ TCHAR tmpPath[MAX_PATH];
+ mir_sntprintf(tmpPath, SIZEOF(tmpPath), _T("%s\\%s.dat"), dat->pd->szProfileDir, profile);
+ HANDLE hFile = CreateFile(tmpPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ if (hFile == INVALID_HANDLE_VALUE)
+ mir_sntprintf(dat->pd->szProfile, MAX_PATH, _T("%s\\%s\\%s.dat"), dat->pd->szProfileDir, profile, profile);
+ else
+ _tcscpy(dat->pd->szProfile, tmpPath);
+ CloseHandle(hFile);
+ if (hdr->code == NM_DBLCLK) EndDialog(GetParent(hwndDlg), 1);
+ }
+ return TRUE;
+ }
+
+ case LVN_KEYDOWN:
+ {
+ LPNMLVKEYDOWN hdrk = (LPNMLVKEYDOWN) lParam;
+ if (hdrk->wVKey == VK_DELETE)
+ DeleteProfile(hwndList, ListView_GetNextItem(hwndList, -1, LVNI_SELECTED | LVNI_ALL), dat);
+ break;
+ }
+ }
+ }
+ break;
+ } }
+
+ return FALSE;
+}
+
+static INT_PTR CALLBACK DlgProfileManager(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct DetailsData* dat = ( struct DetailsData* )GetWindowLongPtr( hwndDlg, GWLP_USERDATA );
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ {
+ struct DlgProfData * prof = (struct DlgProfData *)lParam;
+ PROPSHEETHEADER *psh = prof->psh;
+ TranslateDialogDefault(hwndDlg);
+ SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)LoadImage(hMirandaInst, MAKEINTRESOURCE(IDI_USERDETAILS),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0));
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadImage(hMirandaInst, MAKEINTRESOURCE(IDI_USERDETAILS),IMAGE_ICON,GetSystemMetrics(SM_CXICON),GetSystemMetrics(SM_CYICON),0));
+ dat = (struct DetailsData*)mir_alloc(sizeof(struct DetailsData));
+ dat->prof = prof;
+ prof->hwndOK = GetDlgItem( hwndDlg, IDOK );
+ EnableWindow( prof->hwndOK, FALSE );
+ SetWindowLongPtr( hwndDlg, GWLP_USERDATA, (LONG_PTR)dat );
+
+ {
+ TCHAR buf[512];
+ mir_sntprintf(buf, SIZEOF(buf), _T("%s: %s\n%s"), TranslateT("Miranda Profiles from"), prof->pd->szProfileDir,
+ TranslateT("Select or create your Miranda IM user profile"));
+ SetDlgItemText(hwndDlg, IDC_NAME, buf);
+ }
+
+ { OPTIONSDIALOGPAGE *odp;
+ int i;
+ TCITEM tci;
+
+ dat->currentPage = 0;
+ dat->pageCount = psh->nPages;
+ dat->opd = ( struct DetailsPageData* )mir_calloc( sizeof( struct DetailsPageData )*dat->pageCount );
+ odp = ( OPTIONSDIALOGPAGE* )psh->ppsp;
+
+ tci.mask = TCIF_TEXT;
+ for( i=0; i < dat->pageCount; i++ ) {
+ dat->opd[i].pTemplate = (DLGTEMPLATE *)LockResource(LoadResource(odp[i].hInstance,FindResourceA(odp[i].hInstance,odp[i].pszTemplate,MAKEINTRESOURCEA(5))));
+ dat->opd[i].dlgProc = odp[i].pfnDlgProc;
+ dat->opd[i].hInst = odp[i].hInstance;
+ dat->opd[i].hwnd = NULL;
+ dat->opd[i].changed = 0;
+ tci.pszText = ( TCHAR* )odp[i].ptszTitle;
+ if (dat->prof->pd->noProfiles || shouldAutoCreate(dat->prof->pd->szProfile))
+ dat->currentPage = 1;
+ TabCtrl_InsertItem( GetDlgItem(hwndDlg,IDC_TABS), i, &tci );
+ } }
+
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_TABS),&dat->rcDisplay);
+ TabCtrl_AdjustRect(GetDlgItem(hwndDlg,IDC_TABS),FALSE,&dat->rcDisplay);
+ {
+ POINT pt = {0,0};
+ ClientToScreen( hwndDlg, &pt );
+ OffsetRect( &dat->rcDisplay, -pt.x, -pt.y );
+ }
+
+ TabCtrl_SetCurSel( GetDlgItem( hwndDlg, IDC_TABS ), dat->currentPage );
+ dat->opd[dat->currentPage].hwnd = CreateDialogIndirectParam(dat->opd[dat->currentPage].hInst,dat->opd[dat->currentPage].pTemplate,hwndDlg,dat->opd[dat->currentPage].dlgProc,(LPARAM)dat->prof);
+ ThemeDialogBackground( dat->opd[dat->currentPage].hwnd );
+ SetWindowPos( dat->opd[dat->currentPage].hwnd, HWND_TOP, dat->rcDisplay.left, dat->rcDisplay.top, 0, 0, SWP_NOSIZE );
+ { PSHNOTIFY pshn;
+ pshn.hdr.code = PSN_INFOCHANGED;
+ pshn.hdr.hwndFrom = dat->opd[dat->currentPage].hwnd;
+ pshn.hdr.idFrom = 0;
+ pshn.lParam = ( LPARAM )0;
+ SendMessage( dat->opd[dat->currentPage].hwnd, WM_NOTIFY, 0, ( LPARAM )&pshn );
+ }
+ // service mode combobox
+ {
+ char **list = GetSeviceModePluginsList();
+ if ( !list ) {
+ ShowWindow( GetDlgItem(hwndDlg, IDC_SM_LABEL ), FALSE );
+ ShowWindow( GetDlgItem(hwndDlg, IDC_SM_COMBO ), FALSE );
+ } else {
+ int i = 0;
+ LRESULT index;
+ HWND hwndCombo = GetDlgItem(hwndDlg, IDC_SM_COMBO );
+ index = SendMessage( hwndCombo, CB_ADDSTRING, 0, (LPARAM)_T("") );
+ SendMessage( hwndCombo, CB_SETITEMDATA, index, (LPARAM)-1 );
+ SendMessage( hwndCombo, CB_SETCURSEL, 0, 0);
+ while ( list[i] ) {
+ TCHAR *str = LangPackPcharToTchar( list[i] );
+ index = SendMessage( hwndCombo, CB_ADDSTRING, 0, (LPARAM)str );
+ mir_free(str);
+ SendMessage( hwndCombo, CB_SETITEMDATA, index, (LPARAM)i );
+ i++;
+ }
+ mir_free(list);
+ }
+ }
+ ShowWindow( dat->opd[dat->currentPage].hwnd, SW_SHOW );
+ return TRUE;
+ }
+ case WM_CTLCOLORSTATIC:
+ switch ( GetDlgCtrlID(( HWND )lParam )) {
+ case IDC_WHITERECT:
+ SetBkColor(( HDC )wParam, GetSysColor( COLOR_WINDOW ));
+ return ( INT_PTR )GetSysColorBrush( COLOR_WINDOW );
+ }
+ break;
+
+ case PSM_CHANGED:
+ dat->opd[dat->currentPage].changed=1;
+ return TRUE;
+
+ case PSM_FORCECHANGED:
+ { PSHNOTIFY pshn;
+ int i;
+
+ pshn.hdr.code = PSN_INFOCHANGED;
+ pshn.hdr.idFrom = 0;
+ pshn.lParam = (LPARAM)0;
+ for ( i=0; i < dat->pageCount; i++ ) {
+ pshn.hdr.hwndFrom = dat->opd[i].hwnd;
+ if ( dat->opd[i].hwnd != NULL )
+ SendMessage(dat->opd[i].hwnd,WM_NOTIFY,0,(LPARAM)&pshn);
+ }
+ break;
+ }
+ case WM_NOTIFY:
+ switch(wParam) {
+ case IDC_TABS:
+ switch(((LPNMHDR)lParam)->code) {
+ case TCN_SELCHANGING:
+ { PSHNOTIFY pshn;
+ if ( dat->currentPage == -1 || dat->opd[dat->currentPage].hwnd == NULL )
+ break;
+ pshn.hdr.code = PSN_KILLACTIVE;
+ pshn.hdr.hwndFrom = dat->opd[dat->currentPage].hwnd;
+ pshn.hdr.idFrom = 0;
+ pshn.lParam = 0;
+ if ( SendMessage( dat->opd[dat->currentPage].hwnd, WM_NOTIFY, 0, ( LPARAM )&pshn )) {
+ SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, TRUE );
+ return TRUE;
+ }
+ break;
+ }
+ case TCN_SELCHANGE:
+ if ( dat->currentPage != -1 && dat->opd[dat->currentPage].hwnd != NULL )
+ ShowWindow( dat->opd[ dat->currentPage ].hwnd, SW_HIDE );
+
+ dat->currentPage = TabCtrl_GetCurSel(GetDlgItem(hwndDlg,IDC_TABS));
+ if ( dat->currentPage != -1 ) {
+ if ( dat->opd[dat->currentPage].hwnd == NULL ) {
+ PSHNOTIFY pshn;
+ dat->opd[dat->currentPage].hwnd=CreateDialogIndirectParam(dat->opd[dat->currentPage].hInst,dat->opd[dat->currentPage].pTemplate,hwndDlg,dat->opd[dat->currentPage].dlgProc,(LPARAM)dat->prof);
+ ThemeDialogBackground(dat->opd[dat->currentPage].hwnd);
+ SetWindowPos(dat->opd[dat->currentPage].hwnd,HWND_TOP,dat->rcDisplay.left,dat->rcDisplay.top,0,0,SWP_NOSIZE);
+ pshn.hdr.code=PSN_INFOCHANGED;
+ pshn.hdr.hwndFrom=dat->opd[dat->currentPage].hwnd;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=(LPARAM)0;
+ SendMessage(dat->opd[dat->currentPage].hwnd,WM_NOTIFY,0,(LPARAM)&pshn);
+ }
+ ShowWindow(dat->opd[dat->currentPage].hwnd,SW_SHOW);
+ }
+ break;
+ }
+ break;
+ }
+ break;
+
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDCANCEL:
+ { int i;
+ PSHNOTIFY pshn;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=0;
+ pshn.hdr.code=PSN_RESET;
+ for(i=0;i<dat->pageCount;i++) {
+ if (dat->opd[i].hwnd==NULL || !dat->opd[i].changed) continue;
+ pshn.hdr.hwndFrom=dat->opd[i].hwnd;
+ SendMessage(dat->opd[i].hwnd,WM_NOTIFY,0,(LPARAM)&pshn);
+ }
+ EndDialog(hwndDlg,0);
+ }
+ break;
+
+ case IDC_REMOVE:
+ if (!dat->prof->pd->noProfiles) {
+ HWND hwndList = GetDlgItem(dat->opd[0].hwnd, IDC_PROFILELIST);
+ DeleteProfile(hwndList, ListView_GetNextItem(hwndList, -1, LVNI_SELECTED | LVNI_ALL), dat->prof);
+ }
+ break;
+
+ case IDOK:
+ {
+ int i;
+ PSHNOTIFY pshn;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=(LPARAM)0;
+ if ( dat->currentPage != -1 ) {
+ pshn.hdr.code = PSN_KILLACTIVE;
+ pshn.hdr.hwndFrom = dat->opd[dat->currentPage].hwnd;
+ if ( SendMessage(dat->opd[dat->currentPage].hwnd, WM_NOTIFY, 0, ( LPARAM )&pshn ))
+ break;
+ }
+
+ pshn.hdr.code=PSN_APPLY;
+ for ( i=0; i < dat->pageCount; i++ ) {
+ if ( dat->opd[i].hwnd == NULL || !dat->opd[i].changed )
+ continue;
+
+ pshn.hdr.hwndFrom = dat->opd[i].hwnd;
+ SendMessage( dat->opd[i].hwnd, WM_NOTIFY, 0, ( LPARAM )&pshn );
+ if ( GetWindowLongPtr( dat->opd[i].hwnd, DWLP_MSGRESULT ) == PSNRET_INVALID_NOCHANGEPAGE) {
+ TabCtrl_SetCurSel( GetDlgItem( hwndDlg, IDC_TABS ), i );
+ if ( dat->currentPage != -1 )
+ ShowWindow( dat->opd[ dat->currentPage ].hwnd, SW_HIDE );
+ dat->currentPage = i;
+ ShowWindow( dat->opd[dat->currentPage].hwnd, SW_SHOW );
+ return 0;
+ } }
+ EndDialog(hwndDlg,1);
+ break;
+ } }
+ break;
+
+ case WM_DESTROY:
+ {
+ LRESULT curSel = SendDlgItemMessage(hwndDlg,IDC_SM_COMBO,CB_GETCURSEL,0,0);
+ if ( curSel != CB_ERR ) {
+ int idx = SendDlgItemMessage( hwndDlg, IDC_SM_COMBO, CB_GETITEMDATA, ( WPARAM )curSel, 0 );
+ SetServiceModePlugin(idx);
+ }
+ }
+ DestroyIcon(( HICON )SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, 0));
+ DestroyIcon(( HICON )SendMessage(hwndDlg, WM_SETICON, ICON_BIG, 0));
+ DeleteObject( dat->hBoldFont );
+ { int i;
+ for ( i=0; i < dat->pageCount; i++ )
+ if ( dat->opd[i].hwnd != NULL )
+ DestroyWindow( dat->opd[i].hwnd );
+ }
+ mir_free( dat->opd );
+ mir_free( dat );
+ break;
+ }
+ return FALSE;
+}
+
+static int AddProfileManagerPage(struct DetailsPageInit * opi, OPTIONSDIALOGPAGE * odp)
+{
+ if ( odp->cbSize != sizeof( OPTIONSDIALOGPAGE ))
+ return 1;
+
+ opi->odp = ( OPTIONSDIALOGPAGE* )mir_realloc( opi->odp, sizeof( OPTIONSDIALOGPAGE )*( opi->pageCount+1 ));
+ {
+ OPTIONSDIALOGPAGE* p = opi->odp + opi->pageCount++;
+ p->cbSize = sizeof(OPTIONSDIALOGPAGE);
+ p->hInstance = odp->hInstance;
+ p->pfnDlgProc = odp->pfnDlgProc;
+ p->position = odp->position;
+ p->ptszTitle = LangPackPcharToTchar(odp->pszTitle);
+ p->pszGroup = NULL;
+ p->groupPosition = odp->groupPosition;
+ p->hGroupIcon = odp->hGroupIcon;
+ p->hIcon = odp->hIcon;
+ if (( DWORD_PTR )odp->pszTemplate & 0xFFFF0000 )
+ p->pszTemplate = mir_strdup( odp->pszTemplate );
+ else
+ p->pszTemplate = odp->pszTemplate;
+ }
+ return 0;
+}
+
+int getProfileManager(PROFILEMANAGERDATA * pd)
+{
+ DetailsPageInit opi;
+ opi.pageCount=0;
+ opi.odp=NULL;
+
+ {
+ OPTIONSDIALOGPAGE odp = { 0 };
+ odp.cbSize = sizeof(odp);
+ odp.pszTitle = LPGEN("My Profiles");
+ odp.pfnDlgProc = DlgProfileSelect;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_PROFILE_SELECTION);
+ odp.hInstance = hMirandaInst;
+ AddProfileManagerPage(&opi, &odp);
+
+ odp.pszTitle = LPGEN("New Profile");
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_PROFILE_NEW);
+ odp.pfnDlgProc = DlgProfileNew;
+ AddProfileManagerPage(&opi, &odp);
+ }
+
+ PROPSHEETHEADER psh = { 0 };
+ psh.dwSize = sizeof(psh);
+ psh.dwFlags = PSH_PROPSHEETPAGE|PSH_NOAPPLYNOW;
+ psh.hwndParent = NULL;
+ psh.nPages = opi.pageCount;
+ psh.pStartPage = 0;
+ psh.ppsp = (PROPSHEETPAGE*)opi.odp;
+
+ DlgProfData prof;
+ prof.pd = pd;
+ prof.psh = &psh;
+ int rc = DialogBoxParam(hMirandaInst,MAKEINTRESOURCE(IDD_PROFILEMANAGER),NULL,DlgProfileManager,(LPARAM)&prof);
+
+ if ( rc != -1 )
+ for ( int i=0; i < opi.pageCount; i++ ) {
+ mir_free(( char* )opi.odp[i].pszTitle );
+ mir_free( opi.odp[i].pszGroup );
+ if (( DWORD_PTR )opi.odp[i].pszTemplate & 0xFFFF0000 )
+ mir_free(( char* )opi.odp[i].pszTemplate );
+ }
+
+ if ( opi.odp != NULL )
+ mir_free(opi.odp);
+
+ return rc;
+}
diff --git a/src/modules/database/profilemanager.h b/src/modules/database/profilemanager.h
new file mode 100644
index 0000000000..fc6bd56020
--- /dev/null
+++ b/src/modules/database/profilemanager.h
@@ -0,0 +1,43 @@
+/*
+
+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.
+*/
+
+typedef struct {
+ TCHAR * szProfile; // in/out
+ TCHAR * szProfileDir; // in/out
+ BOOL noProfiles; // in
+ BOOL newProfile; // out
+ DATABASELINK * dblink; // out
+} PROFILEMANAGERDATA;
+
+int InitUtils(void);
+
+char* makeFileName( const TCHAR* tszOriginalName );
+int makeDatabase(TCHAR * profile, DATABASELINK * link, HWND hwndDlg);
+int getProfileManager(PROFILEMANAGERDATA * pd);
+int getProfilePath(TCHAR * buf, size_t cch);
+int isValidProfileName(const TCHAR * name);
+bool fileExist(TCHAR* fname);
+bool shouldAutoCreate(TCHAR *szProfile);
+
+extern TCHAR g_profileDir[MAX_PATH];
+extern TCHAR g_profileName[MAX_PATH];
diff --git a/src/modules/findadd/findadd.cpp b/src/modules/findadd/findadd.cpp
new file mode 100644
index 0000000000..b0bef4fef4
--- /dev/null
+++ b/src/modules/findadd/findadd.cpp
@@ -0,0 +1,1033 @@
+/*
+
+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 "findadd.h"
+
+#define TIMERID_THROBBER 111
+
+#define HM_SEARCHACK (WM_USER+10)
+#define M_SETGROUPVISIBILITIES (WM_USER+11)
+
+static HWND hwndFindAdd=NULL;
+static HANDLE hHookModulesLoaded = 0;
+static HANDLE hMainMenuItem = NULL;
+static int OnSystemModulesLoaded(WPARAM wParam,LPARAM lParam);
+
+static int FindAddDlgResizer(HWND,LPARAM lParam,UTILRESIZECONTROL *urc)
+{
+ static int y,nextY,oldTop;
+ struct FindAddDlgData *dat;
+
+ dat=(struct FindAddDlgData*)lParam;
+ switch(urc->wId) {
+ case IDC_RESULTS:
+ return RD_ANCHORX_WIDTH|RD_ANCHORY_HEIGHT;
+ case IDOK:
+ dat->minDlgHeight=nextY+urc->rcItem.bottom-urc->rcItem.top;
+ return RD_ANCHORX_LEFT|RD_ANCHORY_BOTTOM;
+ case IDC_ADD:
+ case IDC_MOREOPTIONS:
+ return RD_ANCHORX_RIGHT|RD_ANCHORY_BOTTOM;
+ case IDC_STATUSBAR:
+ return RD_ANCHORX_WIDTH|RD_ANCHORY_BOTTOM;
+ case IDC_PROTOIDGROUP: //the resize is always processed in template order
+ nextY=y=urc->rcItem.top;
+ if(dat->showProtoId) nextY=y+urc->rcItem.bottom-urc->rcItem.top+7;
+ break;
+ case IDC_EMAILGROUP:
+ oldTop=urc->rcItem.top;
+ y=nextY;
+ if(dat->showEmail) nextY=y+urc->rcItem.bottom-urc->rcItem.top+7;
+ OffsetRect(&urc->rcItem,0,y-oldTop);
+ return RD_ANCHORX_LEFT|RD_ANCHORY_CUSTOM;
+ case IDC_NAMEGROUP:
+ oldTop=urc->rcItem.top;
+ y=nextY;
+ if(dat->showName) nextY=y+urc->rcItem.bottom-urc->rcItem.top+7;
+ OffsetRect(&urc->rcItem,0,y-oldTop);
+ return RD_ANCHORX_LEFT|RD_ANCHORY_CUSTOM;
+ case IDC_ADVANCEDGROUP:
+ oldTop=urc->rcItem.top;
+ y=nextY;
+ if(dat->showAdvanced) nextY=y+urc->rcItem.bottom-urc->rcItem.top+7;
+ OffsetRect(&urc->rcItem,0,y-oldTop);
+ return RD_ANCHORX_LEFT|RD_ANCHORY_CUSTOM;
+ case IDC_TINYEXTENDEDGROUP:
+ oldTop=urc->rcItem.top;
+ y=nextY;
+ if(dat->showTiny)
+ {
+ int height= urc->dlgNewSize.cy-y-(urc->dlgOriginalSize.cy-urc->rcItem.bottom);
+ nextY=y+200; //min height for custom dialog
+ urc->rcItem.top=urc->rcItem.bottom-height;
+ }
+ return RD_ANCHORX_LEFT|RD_ANCHORY_BOTTOM;
+ case IDC_BYEMAIL:
+ case IDC_EMAIL:
+ case IDC_BYNAME:
+ case IDC_STNAMENICK:
+ case IDC_STNAMEFIRST:
+ case IDC_STNAMELAST:
+ case IDC_NAMENICK:
+ case IDC_NAMEFIRST:
+ case IDC_NAMELAST:
+ case IDC_BYADVANCED:
+ case IDC_BYCUSTOM:
+ case IDC_ADVANCED:
+ OffsetRect(&urc->rcItem,0,y-oldTop);
+ return RD_ANCHORX_LEFT|RD_ANCHORY_CUSTOM;
+ case IDC_HEADERBAR:
+ return RD_ANCHORX_LEFT|RD_ANCHORY_TOP|RD_ANCHORX_WIDTH;
+ }
+ return RD_ANCHORX_LEFT|RD_ANCHORY_TOP;
+}
+
+static void RenderThrobber(HDC hdc,RECT *rcItem,int *throbbing,int *pivot)
+{
+ HBRUSH hBr;
+ HDC hMemDC;
+ HBITMAP hBitmap;
+ HPEN hPen;
+ RECT rc;
+ int x,width,height,height2;
+
+ InflateRect(rcItem,-1,0);
+ width=rcItem->right-rcItem->left;
+ height=rcItem->bottom-rcItem->top;
+ height2=height/2;
+
+ if (*throbbing) {
+ /* create memdc */
+ hMemDC=CreateCompatibleDC(0);
+ hBitmap=( HBITMAP )SelectObject(hMemDC, CreateCompatibleBitmap(hdc,width,height));
+ /* flush it */
+ rc.left=rc.top=0;
+ rc.right=width;
+ rc.bottom=height;
+ hBr=GetSysColorBrush(COLOR_BTNFACE);
+ FillRect(hMemDC,&rc,hBr);
+ DeleteObject(hBr);
+ /* set up the pen */
+ hPen=(HPEN)SelectObject(hMemDC,CreatePen(PS_SOLID,4,GetSysColor(COLOR_BTNSHADOW)));
+ /* draw everything before the pivot */
+ x=*pivot;
+ while (x>(-height)) {
+ MoveToEx(hMemDC,x+height2,0,NULL);
+ LineTo(hMemDC,x-height2,height);
+ x-=12;
+ }
+
+ /* draw everything after the pivot */
+ x = *pivot;
+ while (x < width+height) {
+ MoveToEx(hMemDC,x+height2,0,NULL);
+ LineTo(hMemDC,x-height2,height);
+ x+=12;
+ }
+
+ /* move the pivot */
+ *pivot+=2;
+ /* reset the pivot point if it gets past the rect */
+ if (*pivot>width) *pivot=0;
+ /* put back the old pen and delete the new one */
+ DeleteObject(SelectObject(hMemDC,hPen));
+ /* cap the top and bottom */
+ hPen=(HPEN)SelectObject(hMemDC,CreatePen(PS_SOLID,1,GetSysColor(COLOR_BTNFACE)));
+ MoveToEx(hMemDC,0,0,NULL);
+ LineTo(hMemDC,width,0);
+ MoveToEx(hMemDC,0,height-1,NULL);
+ LineTo(hMemDC,width,height-1);
+ /* select in the old pen and delete the new pen */
+ DeleteObject(SelectObject(hMemDC,hPen));
+ /* paint to screen */
+ BitBlt(hdc,rcItem->left,rcItem->top,width,height,hMemDC,0,0,SRCCOPY);
+ /* select back in the old bitmap and delete the created one, as well as freeing the mem dc. */
+ hBitmap=( HBITMAP )SelectObject(hMemDC,hBitmap);
+ DeleteObject(hBitmap);
+ DeleteDC(hMemDC);
+ }
+ else {
+ /* just flush the DC */
+ hBr=GetSysColorBrush(COLOR_BTNFACE);
+ FillRect(hdc,rcItem,hBr);
+ DeleteObject(hBr);
+} }
+
+static void StartThrobber(HWND hwndDlg,struct FindAddDlgData *dat)
+{
+ dat->throbbing=1;
+ SetTimer(hwndDlg,TIMERID_THROBBER,25,NULL);
+}
+
+static void StopThrobber(HWND hwndDlg,struct FindAddDlgData *dat)
+{
+ KillTimer(hwndDlg,TIMERID_THROBBER);
+ dat->throbbing=0;
+ dat->pivot=0;
+ InvalidateRect(GetDlgItem(hwndDlg,IDC_STATUSBAR),NULL,FALSE);
+}
+
+static void ShowAdvancedSearchDlg(HWND hwndDlg,struct FindAddDlgData *dat)
+{
+ char *szProto=(char*)SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETCURSEL,0,0),0);
+
+ if(szProto==NULL) return;
+ if(dat->hwndAdvSearch==NULL) {
+ RECT rc;
+ dat->hwndAdvSearch=(HWND)CallProtoService(szProto,PS_CREATEADVSEARCHUI,0,(LPARAM)hwndDlg);
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_RESULTS),&rc);
+ SetWindowPos(dat->hwndAdvSearch,0,rc.left,rc.top,0,0,SWP_NOZORDER|SWP_NOSIZE);
+ }
+ if(animateWindow) {
+ animateWindow(dat->hwndAdvSearch,150,AW_ACTIVATE|AW_SLIDE|AW_HOR_POSITIVE);
+ RedrawWindow(dat->hwndAdvSearch,NULL,NULL,RDW_INVALIDATE|RDW_UPDATENOW|RDW_ALLCHILDREN);
+ } else ShowWindow(dat->hwndAdvSearch,SW_SHOW);
+ CheckDlgButton(hwndDlg,IDC_ADVANCED,BST_CHECKED);
+}
+
+static void ReposTinySearchDlg(HWND hwndDlg,struct FindAddDlgData *dat)
+{
+ if ( dat->hwndTinySearch != NULL ) {
+ RECT rc;
+ RECT clientRect;
+ POINT pt={0,0};
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_TINYEXTENDEDGROUP),&rc);
+ GetWindowRect(dat->hwndTinySearch,&clientRect);
+ pt.x=rc.left;
+ pt.y=rc.top;
+ ScreenToClient(hwndDlg,&pt);
+ SetWindowPos(dat->hwndTinySearch,0,pt.x+5,pt.y+15,rc.right-rc.left-10,rc.bottom-rc.top-30,SWP_NOZORDER);
+ //SetWindowPos(GetDlgItem(hwndDlg,IDC_TINYEXTENDEDGROUP),0,0,0,rc.right-rc.left,clientRect.bottom-clientRect.top+20,SWP_NOMOVE|SWP_NOZORDER);
+} }
+
+static void ShowTinySearchDlg(HWND hwndDlg,struct FindAddDlgData *dat)
+{
+ char *szProto=(char*)SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETCURSEL,0,0),0);
+ if(szProto==NULL) return;
+ if(dat->hwndTinySearch==NULL) {
+ dat->hwndTinySearch=(HWND)CallProtoService(szProto,PS_CREATEADVSEARCHUI,0,(LPARAM)/*GetDlgItem(*/hwndDlg/*,IDC_TINYEXTENDEDGROUP)*/);
+ if (dat->hwndTinySearch)
+ ReposTinySearchDlg(hwndDlg, dat);
+ else
+ dat->showTiny = false;
+ }
+ ShowWindow(dat->hwndTinySearch,SW_SHOW);
+}
+
+static void HideAdvancedSearchDlg(HWND hwndDlg,struct FindAddDlgData *dat)
+{
+ if(dat->hwndAdvSearch==NULL) return;
+ if(animateWindow && IsWinVerXPPlus()) //blending is quite slow on win2k
+ animateWindow(dat->hwndAdvSearch,150,AW_HIDE|AW_BLEND);
+ else ShowWindow(dat->hwndAdvSearch,SW_HIDE);
+ CheckDlgButton(hwndDlg,IDC_ADVANCED,BST_UNCHECKED);
+}
+
+void EnableResultButtons(HWND hwndDlg,int enable)
+{
+ EnableWindow(GetDlgItem(hwndDlg,IDC_ADD), enable || IsDlgButtonChecked(hwndDlg, IDC_BYPROTOID));
+ EnableWindow(GetDlgItem(hwndDlg,IDC_MOREOPTIONS),enable);
+}
+
+static void CheckSearchTypeRadioButton(HWND hwndDlg,int idControl)
+{
+ int i;
+ static const int controls[]={IDC_BYPROTOID,IDC_BYEMAIL,IDC_BYNAME,IDC_BYADVANCED,IDC_BYCUSTOM};
+ for( i=0; i < SIZEOF(controls); i++ )
+ CheckDlgButton(hwndDlg,controls[i],idControl==controls[i]?BST_CHECKED:BST_UNCHECKED);
+}
+
+#define sttErrMsg TranslateT("You haven't filled in the search field. Please enter a search term and try again.")
+#define sttErrTitle TranslateT("Search")
+
+static void SetListItemText( HWND hwndList, int idx, int col, TCHAR* szText )
+{
+ if ( szText && szText[0] )
+ {
+ ListView_SetItemText( hwndList, idx, col, szText );
+ }
+ else
+ {
+ ListView_SetItemText( hwndList, idx, col, TranslateT("<not specified>"));
+ }
+}
+
+static INT_PTR CALLBACK DlgProcFindAdd(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct FindAddDlgData* dat = ( struct FindAddDlgData* )GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ HWND hwndList = GetDlgItem(hwndDlg, IDC_RESULTS);
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ {
+ int i,netProtoCount;
+ COMBOBOXEXITEM cbei;
+ HICON hIcon;
+
+ TranslateDialogDefault(hwndDlg);
+ Window_SetIcon_IcoLib(hwndDlg, SKINICON_OTHER_FINDUSER);
+ dat=(struct FindAddDlgData*)mir_calloc(sizeof(struct FindAddDlgData));
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)dat);
+ dat->notSearchedYet=1;
+ dat->iLastColumnSortIndex=1;
+ dat->bSortAscending=1;
+ dat->hBmpSortUp=(HBITMAP)LoadImage(hMirandaInst,MAKEINTRESOURCE(IDB_SORTCOLUP),IMAGE_BITMAP,0,0,LR_LOADMAP3DCOLORS);
+ dat->hBmpSortDown=(HBITMAP)LoadImage(hMirandaInst,MAKEINTRESOURCE(IDB_SORTCOLDOWN),IMAGE_BITMAP,0,0,LR_LOADMAP3DCOLORS);
+ SendDlgItemMessage(hwndDlg,IDC_MOREOPTIONS,BUTTONSETARROW,1,0);
+ ListView_SetExtendedListViewStyle(hwndList,LVS_EX_FULLROWSELECT|LVS_EX_HEADERDRAGDROP);
+
+ { LVCOLUMN lvc;
+ RECT rc;
+ LVITEM lvi;
+
+ GetClientRect(hwndList,&rc);
+ lvc.mask = LVCF_TEXT | LVCF_WIDTH;
+ lvc.pszText = TranslateT("Results");
+ lvc.cx = rc.right-1;
+ ListView_InsertColumn(hwndList, 0, &lvc);
+ lvi.mask=LVIF_TEXT;
+ lvi.iItem=0;
+ lvi.iSubItem=0;
+ lvi.pszText=TranslateT("There are no results to display.");
+ ListView_InsertItem(hwndList, &lvi);
+ }
+
+ // Allocate a reasonable amount of space in the status bar
+ { int partWidth[3];
+ SIZE textSize;
+ HDC hdc;
+
+ hdc=GetDC(GetDlgItem(hwndDlg,IDC_STATUSBAR));
+ SelectObject(hdc,(HFONT)SendDlgItemMessage(hwndDlg,IDC_STATUSBAR,WM_GETFONT,0,0));
+ GetTextExtentPoint32(hdc,TranslateT("Searching"),lstrlen(TranslateT("Searching")),&textSize);
+ partWidth[0]=textSize.cx;
+ GetTextExtentPoint32(hdc,_T("01234567890123456789"), 20, &textSize );
+ partWidth[0]+=textSize.cx;
+ ReleaseDC(GetDlgItem(hwndDlg,IDC_STATUSBAR),hdc);
+ partWidth[1]=partWidth[0]+150;
+ partWidth[2]=-1;
+ SendDlgItemMessage(hwndDlg,IDC_STATUSBAR,SB_SETPARTS,SIZEOF(partWidth),(LPARAM)partWidth);
+ SendDlgItemMessage(hwndDlg,IDC_STATUSBAR,SB_SETTEXT,1|SBT_OWNERDRAW,0);
+ SetStatusBarSearchInfo(GetDlgItem(hwndDlg,IDC_STATUSBAR),dat);
+ }
+ {
+ TCHAR *szProto = NULL;
+ int index = 0;
+ DBVARIANT dbv={0};
+ HDC hdc;
+ SIZE textSize;
+ RECT rect;
+ int cbwidth = 0;
+
+ if ( !DBGetContactSettingTString( NULL, "FindAdd", "LastSearched", &dbv ))
+ szProto = dbv.ptszVal;
+
+ for( i=0, netProtoCount=0; i < accounts.getCount(); i++ ) {
+ if (!Proto_IsAccountEnabled( accounts[i] )) continue;
+ DWORD caps = (DWORD)CallProtoService( accounts[i]->szModuleName, PS_GETCAPS, PFLAGNUM_1, 0 );
+ if (caps & PF1_BASICSEARCH || caps & PF1_EXTSEARCH || caps & PF1_SEARCHBYEMAIL || caps & PF1_SEARCHBYNAME)
+ netProtoCount++;
+ }
+ dat->himlComboIcons=ImageList_Create(GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),(IsWinVerXPPlus()?ILC_COLOR32:ILC_COLOR16)|ILC_MASK,netProtoCount+1,netProtoCount+1);
+ SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CBEM_SETIMAGELIST,0,(LPARAM)dat->himlComboIcons);
+ cbei.mask=CBEIF_IMAGE|CBEIF_SELECTEDIMAGE|CBEIF_TEXT|CBEIF_LPARAM;
+ cbei.iItem=0;
+ hdc=GetDC(hwndDlg);
+ SelectObject(hdc,(HFONT)SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,WM_GETFONT,0,0));
+ if(netProtoCount>1) {
+ cbei.pszText=TranslateT("All Networks");
+ GetTextExtentPoint32(hdc,cbei.pszText,lstrlen(cbei.pszText),&textSize);
+ if (textSize.cx>cbwidth) cbwidth = textSize.cx;
+ cbei.iImage=cbei.iSelectedImage=ImageList_AddIcon_IconLibLoaded(dat->himlComboIcons, SKINICON_OTHER_SEARCHALL);
+ cbei.lParam=0;
+ SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CBEM_INSERTITEM,0,(LPARAM)&cbei);
+ cbei.iItem++;
+ }
+ for( i=0; i < accounts.getCount(); i++ ) {
+ PROTOACCOUNT* pa = accounts[i];
+ if (!Proto_IsAccountEnabled(pa)) continue;
+ DWORD caps=(DWORD)CallProtoService( pa->szModuleName, PS_GETCAPS, PFLAGNUM_1, 0 );
+ if ( !(caps&PF1_BASICSEARCH) && !(caps&PF1_EXTSEARCH) && !(caps&PF1_SEARCHBYEMAIL) && !(caps&PF1_SEARCHBYNAME))
+ continue;
+
+ cbei.pszText = pa->tszAccountName;
+ GetTextExtentPoint32(hdc,cbei.pszText,lstrlen(cbei.pszText),&textSize);
+ if (textSize.cx>cbwidth) cbwidth = textSize.cx;
+ hIcon=(HICON)CallProtoService( pa->szModuleName,PS_LOADICON,PLI_PROTOCOL|PLIF_SMALL,0);
+ cbei.iImage=cbei.iSelectedImage=ImageList_AddIcon(dat->himlComboIcons,hIcon);
+ DestroyIcon(hIcon);
+ cbei.lParam=(LPARAM)pa->szModuleName;
+ SendDlgItemMessageA(hwndDlg,IDC_PROTOLIST,CBEM_INSERTITEM,0,(LPARAM)&cbei);
+ if (szProto && cbei.pszText && !lstrcmp( szProto, pa->tszAccountName ))
+ index = cbei.iItem;
+ cbei.iItem++;
+ }
+ cbwidth+=32;
+ SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETDROPPEDCONTROLRECT,0,(LPARAM)&rect);
+ if ((rect.right-rect.left)<cbwidth)
+ SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_SETDROPPEDWIDTH,cbwidth,0);
+ SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_SETCURSEL,index,0);
+ DBFreeVariant(&dbv); /* free string szProto was fetched with */
+ }
+ SendMessage(hwndDlg,M_SETGROUPVISIBILITIES,0,0);
+ Utils_RestoreWindowPosition(hwndDlg,NULL,"FindAdd","");
+
+ return TRUE;
+ }
+ case WM_SIZE:
+ { UTILRESIZEDIALOG urd={0};
+ urd.cbSize=sizeof(urd);
+ urd.hwndDlg=hwndDlg;
+ urd.hInstance=hMirandaInst;
+ urd.lpTemplate=MAKEINTRESOURCEA(IDD_FINDADD);
+ urd.lParam=(LPARAM)dat;
+ urd.pfnResizer=FindAddDlgResizer;
+ CallService(MS_UTILS_RESIZEDIALOG,0,(LPARAM)&urd);
+ ReposTinySearchDlg(hwndDlg, dat);
+ SendDlgItemMessage(hwndDlg,IDC_STATUSBAR,WM_SIZE,0,0);
+ if(dat->notSearchedYet) {
+ RECT rc;
+ GetClientRect(hwndList,&rc);
+ ListView_SetColumnWidth(hwndList,0,rc.right);
+ }
+ }
+ //fall through
+ case WM_MOVE:
+ if (dat && dat->hwndAdvSearch)
+ {
+ RECT rc;
+ GetWindowRect(hwndList,&rc);
+ SetWindowPos(dat->hwndAdvSearch,0,rc.left,rc.top,0,0,SWP_NOZORDER|SWP_NOSIZE);
+ }
+ break;
+ case WM_GETMINMAXINFO:
+ { MINMAXINFO *mmi=(MINMAXINFO*)lParam;
+ RECT rc,rc2;
+ GetWindowRect(hwndList,&rc);
+ GetWindowRect(hwndDlg,&rc2);
+ mmi->ptMinTrackSize.x=rc.left-rc2.left+10+GetSystemMetrics(SM_CXFRAME);
+ GetClientRect(GetDlgItem(hwndDlg,IDC_MOREOPTIONS),&rc);
+ mmi->ptMinTrackSize.x+=rc.right+5;
+ GetClientRect(GetDlgItem(hwndDlg,IDC_ADD),&rc);
+ mmi->ptMinTrackSize.x+=rc.right+5;
+ GetClientRect(GetDlgItem(hwndDlg,IDC_STATUSBAR),&rc);
+ mmi->ptMinTrackSize.y=dat->minDlgHeight+20+GetSystemMetrics(SM_CYCAPTION)+2*GetSystemMetrics(SM_CYFRAME);
+ GetClientRect(GetDlgItem(hwndDlg,IDC_STATUSBAR),&rc);
+ mmi->ptMinTrackSize.y+=rc.bottom;
+ return 0;
+ }
+ case M_SETGROUPVISIBILITIES:
+ { char *szProto;
+ int i;
+ DWORD protoCaps;
+ MINMAXINFO mmi;
+ RECT rc;
+ int checkmarkVisible;
+
+ dat->showAdvanced = dat->showEmail = dat->showName = dat->showProtoId = dat->showTiny = 0;
+ szProto=(char*)SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETCURSEL,0,0),0);
+ if ( szProto == (char *)CB_ERR )
+ break;
+ if ( szProto == NULL ) {
+ for ( i=0; i < accounts.getCount(); i++ ) {
+ PROTOACCOUNT* pa = accounts[i];
+ if (!Proto_IsAccountEnabled(pa)) continue;
+ protoCaps=(DWORD)CallProtoService(pa->szModuleName,PS_GETCAPS,PFLAGNUM_1,0);
+ if(protoCaps&PF1_SEARCHBYEMAIL) dat->showEmail=1;
+ if(protoCaps&PF1_SEARCHBYNAME) dat->showName=1;
+ }
+ }
+ else {
+ protoCaps=(DWORD)CallProtoService(szProto,PS_GETCAPS,PFLAGNUM_1,0);
+ if(protoCaps&PF1_BASICSEARCH) dat->showProtoId=1;
+ if(protoCaps&PF1_SEARCHBYEMAIL) dat->showEmail=1;
+ if(protoCaps&PF1_SEARCHBYNAME) dat->showName=1;
+ if(protoCaps&PF1_EXTSEARCH && !(protoCaps&PF1_EXTSEARCHUI)) dat->showTiny=1;
+ if(protoCaps&PF1_EXTSEARCHUI) dat->showAdvanced=1;
+ if(protoCaps&PF1_USERIDISEMAIL && dat->showProtoId) {dat->showProtoId=0; dat->showEmail=1;}
+ if(dat->showProtoId) {
+ char *szUniqueId;
+ szUniqueId=(char*)CallProtoService(szProto,PS_GETCAPS,PFLAG_UNIQUEIDTEXT,0);
+ if(szUniqueId) {
+ #if defined( _UNICODE )
+ TCHAR* p = mir_a2u(szUniqueId);
+ SetDlgItemText(hwndDlg,IDC_BYPROTOID,p);
+ mir_free(p);
+ #else
+ SetDlgItemTextA(hwndDlg,IDC_BYPROTOID,szUniqueId);
+ #endif
+ }
+ else SetDlgItemText(hwndDlg,IDC_BYPROTOID,TranslateT("Handle"));
+ if(protoCaps&PF1_NUMERICUSERID) SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_PROTOID),GWL_STYLE,GetWindowLongPtr(GetDlgItem(hwndDlg,IDC_PROTOID),GWL_STYLE)|ES_NUMBER);
+ else SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_PROTOID),GWL_STYLE,GetWindowLongPtr(GetDlgItem(hwndDlg,IDC_PROTOID),GWL_STYLE)&~ES_NUMBER);
+ }
+ }
+
+ if (dat->showTiny)
+ ShowTinySearchDlg(hwndDlg, dat);
+ else {
+ if (dat->hwndTinySearch) {
+ DestroyWindow(dat->hwndTinySearch);
+ dat->hwndTinySearch=NULL;
+ } }
+
+#define en(id,t) ShowWindow(GetDlgItem(hwndDlg,IDC_##id),dat->show##t?SW_SHOW:SW_HIDE)
+ en(PROTOIDGROUP,ProtoId); en(BYPROTOID,ProtoId); en(PROTOID,ProtoId);
+ en(EMAILGROUP,Email); en(BYEMAIL,Email); en(EMAIL,Email);
+ en(NAMEGROUP,Name); en(BYNAME,Name);
+ en(STNAMENICK,Name); en(NAMENICK,Name);
+ en(STNAMEFIRST,Name); en(NAMEFIRST,Name);
+ en(STNAMELAST,Name); en(NAMELAST,Name);
+ en(ADVANCEDGROUP,Advanced); en(BYADVANCED,Advanced); en(ADVANCED,Advanced);
+ en(BYCUSTOM, Tiny); en(TINYEXTENDEDGROUP, Tiny);
+#undef en
+
+ checkmarkVisible=(dat->showAdvanced && IsDlgButtonChecked(hwndDlg,IDC_BYADVANCED)) ||
+ (dat->showEmail && IsDlgButtonChecked(hwndDlg,IDC_BYEMAIL)) ||
+ (dat->showTiny && IsDlgButtonChecked(hwndDlg,IDC_BYCUSTOM)) ||
+ (dat->showName && IsDlgButtonChecked(hwndDlg,IDC_BYNAME)) ||
+ (dat->showProtoId && IsDlgButtonChecked(hwndDlg,IDC_BYPROTOID));
+ if(!checkmarkVisible) {
+ if(dat->showProtoId) CheckSearchTypeRadioButton(hwndDlg,IDC_BYPROTOID);
+ else if(dat->showEmail) CheckSearchTypeRadioButton(hwndDlg,IDC_BYEMAIL);
+ else if(dat->showName) CheckSearchTypeRadioButton(hwndDlg,IDC_BYNAME);
+ else if(dat->showAdvanced) CheckSearchTypeRadioButton(hwndDlg,IDC_BYADVANCED);
+ else if(dat->showTiny) CheckSearchTypeRadioButton(hwndDlg,IDC_BYCUSTOM);
+ }
+
+ SendMessage(hwndDlg,WM_SIZE,0,0);
+ SendMessage(hwndDlg,WM_GETMINMAXINFO,0,(LPARAM)&mmi);
+ GetWindowRect(hwndDlg,&rc);
+ if(rc.bottom-rc.top<mmi.ptMinTrackSize.y) SetWindowPos(hwndDlg,0,0,0,rc.right-rc.left,mmi.ptMinTrackSize.y,SWP_NOZORDER|SWP_NOMOVE);
+ break;
+ }
+ case WM_TIMER:
+ if(wParam==TIMERID_THROBBER) {
+ RECT rc;
+ HDC hdc;
+ int borders[3];
+ SendDlgItemMessage(hwndDlg,IDC_STATUSBAR,SB_GETBORDERS,0,(LPARAM)borders);
+ SendDlgItemMessage(hwndDlg,IDC_STATUSBAR,SB_GETRECT,1,(LPARAM)&rc);
+ InflateRect(&rc,-borders[2]/2,-borders[1]/2);
+ hdc=GetDC(GetDlgItem(hwndDlg,IDC_STATUSBAR));
+ RenderThrobber(hdc,&rc,&dat->throbbing,&dat->pivot);
+ ReleaseDC(GetDlgItem(hwndDlg,IDC_STATUSBAR),hdc);
+ }
+ break;
+ case WM_DRAWITEM:
+ { DRAWITEMSTRUCT *dis=(DRAWITEMSTRUCT*)lParam;
+ if(dis->CtlID==IDC_STATUSBAR && dis->itemID==1) {
+ RenderThrobber(dis->hDC,&dis->rcItem,&dat->throbbing,&dat->pivot);
+ return TRUE;
+ }
+ break;
+ }
+ case WM_NOTIFY:
+ if (wParam == IDC_RESULTS) {
+ switch(((LPNMHDR)lParam)->code) {
+ case LVN_ITEMCHANGED:
+ { int count=ListView_GetSelectedCount(hwndList);
+ if(dat->notSearchedYet) count=0;
+ EnableResultButtons(hwndDlg,count);
+ break;
+ }
+ case LVN_COLUMNCLICK:
+ {
+ LPNMLISTVIEW nmlv=(LPNMLISTVIEW)lParam;
+ HDITEM hdi;
+
+ hdi.mask=HDI_BITMAP|HDI_FORMAT;
+ hdi.fmt=HDF_LEFT|HDF_STRING;
+ Header_SetItem(ListView_GetHeader(hwndList),dat->iLastColumnSortIndex,&hdi);
+
+ if(nmlv->iSubItem!=dat->iLastColumnSortIndex)
+ {
+ dat->bSortAscending=TRUE;
+ dat->iLastColumnSortIndex=nmlv->iSubItem;
+ }
+ else dat->bSortAscending=!dat->bSortAscending;
+
+ hdi.fmt=HDF_LEFT|HDF_BITMAP|HDF_STRING|HDF_BITMAP_ON_RIGHT;
+ hdi.hbm=dat->bSortAscending?dat->hBmpSortDown:dat->hBmpSortUp;
+ Header_SetItem(ListView_GetHeader(hwndList),dat->iLastColumnSortIndex,&hdi);
+
+ ListView_SortItemsEx(hwndList, SearchResultsCompareFunc, (LPARAM)hwndDlg);
+ }
+ break;
+ } }
+ break;
+
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDC_PROTOLIST:
+ if(HIWORD(wParam)==CBN_SELCHANGE) {
+ HideAdvancedSearchDlg(hwndDlg,dat);
+ if(dat->hwndAdvSearch) {
+ DestroyWindow(dat->hwndAdvSearch);
+ dat->hwndAdvSearch=NULL;
+ }
+ if(dat->hwndTinySearch) {
+ DestroyWindow(dat->hwndTinySearch);
+ dat->hwndTinySearch=NULL;
+ }
+ SendMessage(hwndDlg,M_SETGROUPVISIBILITIES,0,0);
+ }
+ break;
+ case IDC_BYPROTOID:
+ EnableWindow(GetDlgItem(hwndDlg,IDC_ADD),TRUE);
+ HideAdvancedSearchDlg(hwndDlg,dat);
+ break;
+ case IDC_BYEMAIL:
+ case IDC_BYNAME:
+ EnableWindow(GetDlgItem(hwndDlg,IDC_ADD), ListView_GetSelectedCount(hwndList) > 0);
+ HideAdvancedSearchDlg(hwndDlg,dat);
+ break;
+ case IDC_PROTOID:
+ if(HIWORD(wParam)==EN_CHANGE) {
+ HideAdvancedSearchDlg(hwndDlg,dat);
+ CheckSearchTypeRadioButton(hwndDlg,IDC_BYPROTOID);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_ADD),TRUE);
+ }
+ break;
+ case IDC_EMAIL:
+ if(HIWORD(wParam)==EN_CHANGE) {
+ HideAdvancedSearchDlg(hwndDlg,dat);
+ CheckSearchTypeRadioButton(hwndDlg,IDC_BYEMAIL);
+ }
+ break;
+ case IDC_NAMENICK:
+ case IDC_NAMEFIRST:
+ case IDC_NAMELAST:
+ if(HIWORD(wParam)==EN_CHANGE) {
+ HideAdvancedSearchDlg(hwndDlg,dat);
+ CheckSearchTypeRadioButton(hwndDlg,IDC_BYNAME);
+ }
+ break;
+ case IDC_ADVANCED:
+ EnableWindow(GetDlgItem(hwndDlg,IDC_ADD), ListView_GetSelectedCount(hwndList) > 0);
+ if(IsDlgButtonChecked(hwndDlg,IDC_ADVANCED))
+ ShowAdvancedSearchDlg(hwndDlg,dat);
+ else
+ HideAdvancedSearchDlg(hwndDlg,dat);
+ CheckSearchTypeRadioButton(hwndDlg,IDC_BYADVANCED);
+ break;
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ break;
+ case IDOK:
+ {
+ HideAdvancedSearchDlg(hwndDlg,dat);
+ if(dat->searchCount) { //cancel search
+ SetDlgItemText(hwndDlg,IDOK,TranslateT("&Search"));
+ if(dat->hResultHook) {UnhookEvent(dat->hResultHook); dat->hResultHook=NULL;}
+ if(dat->search) {mir_free(dat->search); dat->search=NULL;}
+ dat->searchCount=0;
+ StopThrobber(hwndDlg,dat);
+ SetStatusBarSearchInfo(GetDlgItem(hwndDlg,IDC_STATUSBAR),dat);
+ break;
+ }
+ char *szProto=(char*)SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETCURSEL,0,0),0);
+ if(dat->search) {mir_free(dat->search); dat->search=NULL;}
+ dat->searchCount=0;
+ dat->hResultHook=HookEventMessage(ME_PROTO_ACK,hwndDlg,HM_SEARCHACK);
+ if (IsDlgButtonChecked(hwndDlg,IDC_BYCUSTOM))
+ {
+ BeginSearch(hwndDlg,dat,szProto,PS_SEARCHBYADVANCED,PF1_EXTSEARCHUI,dat->hwndTinySearch);
+ }
+ else if(IsDlgButtonChecked(hwndDlg,IDC_BYPROTOID)) {
+ TCHAR str[256];
+ GetDlgItemText(hwndDlg,IDC_PROTOID,str,SIZEOF(str));
+ rtrim(str);
+ if(str[0]==0)
+ MessageBox(hwndDlg,sttErrMsg,sttErrTitle,MB_OK);
+ else
+ BeginSearch(hwndDlg,dat,szProto,PS_BASICSEARCHT,PF1_BASICSEARCH,str);
+ }
+ else if(IsDlgButtonChecked(hwndDlg,IDC_BYEMAIL)) {
+ TCHAR str[256];
+ GetDlgItemText(hwndDlg,IDC_EMAIL,str,SIZEOF(str));
+ rtrim(str);
+ if(str[0]==0)
+ MessageBox(hwndDlg,sttErrMsg,sttErrTitle,MB_OK);
+ else
+ BeginSearch(hwndDlg,dat,szProto,PS_SEARCHBYEMAILT,PF1_SEARCHBYEMAIL,str);
+ }
+ else if(IsDlgButtonChecked(hwndDlg,IDC_BYNAME)) {
+ TCHAR nick[256],first[256],last[256];
+ PROTOSEARCHBYNAME psbn;
+ GetDlgItemText(hwndDlg,IDC_NAMENICK,nick,SIZEOF(nick));
+ GetDlgItemText(hwndDlg,IDC_NAMEFIRST,first,SIZEOF(first));
+ GetDlgItemText(hwndDlg,IDC_NAMELAST,last,SIZEOF(last));
+ psbn.pszFirstName = first;
+ psbn.pszLastName = last;
+ psbn.pszNick = nick;
+ if(nick[0]==0 && first[0]==0 && last[0]==0)
+ MessageBox(hwndDlg,sttErrMsg,sttErrTitle,MB_OK);
+ else
+ BeginSearch(hwndDlg,dat,szProto,PS_SEARCHBYNAMET,PF1_SEARCHBYNAME,&psbn);
+ }
+ else if(IsDlgButtonChecked(hwndDlg,IDC_BYADVANCED)) {
+ if(dat->hwndAdvSearch==NULL)
+ MessageBox(hwndDlg,sttErrMsg,sttErrTitle,MB_OK);
+ else
+ BeginSearch(hwndDlg,dat,szProto,PS_SEARCHBYADVANCED,PF1_EXTSEARCHUI,dat->hwndAdvSearch);
+ }
+
+ if(dat->searchCount==0) {
+ if(dat->hResultHook) {UnhookEvent(dat->hResultHook); dat->hResultHook=NULL;}
+ break;
+ }
+
+ dat->notSearchedYet=0;
+ FreeSearchResults(hwndList);
+
+ CreateResultsColumns(hwndList,dat,szProto);
+ SetStatusBarSearchInfo(GetDlgItem(hwndDlg,IDC_STATUSBAR),dat);
+ SetStatusBarResultInfo(hwndDlg);
+ StartThrobber(hwndDlg,dat);
+ SetDlgItemText(hwndDlg, IDOK, TranslateT("Cancel"));
+ break;
+ }
+ case IDC_ADD:
+ { LVITEM lvi;
+ struct ListSearchResult *lsr;
+ ADDCONTACTSTRUCT acs = {0};
+
+ if (ListView_GetSelectedCount(hwndList) == 1)
+ {
+ lvi.mask = LVIF_PARAM;
+ lvi.iItem = ListView_GetNextItem(hwndList, -1, LVNI_ALL | LVNI_SELECTED);
+ ListView_GetItem(hwndList, &lvi);
+ lsr = (struct ListSearchResult*)lvi.lParam;
+ acs.szProto = lsr->szProto;
+ acs.psr = &lsr->psr;
+ }
+ else
+ {
+ TCHAR str[256];
+ GetDlgItemText(hwndDlg, IDC_PROTOID, str, SIZEOF(str));
+ if (*rtrim(str) == 0) break;
+
+ PROTOSEARCHRESULT psr = {0};
+ psr.cbSize = sizeof(psr);
+ psr.flags = PSR_TCHAR;
+ psr.id = str;
+
+ acs.psr = &psr;
+ acs.szProto = (char*)SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CB_GETITEMDATA,
+ SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CB_GETCURSEL, 0, 0), 0);
+ }
+
+ acs.handleType = HANDLE_SEARCHRESULT;
+ CallService(MS_ADDCONTACT_SHOW, (WPARAM)hwndDlg, (LPARAM)&acs);
+ break;
+ }
+ case IDC_MOREOPTIONS:
+ { RECT rc;
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_MOREOPTIONS),&rc);
+ ShowMoreOptionsMenu(hwndDlg,rc.left,rc.bottom);
+ break;
+ }
+ }
+ if (lParam && dat->hwndTinySearch==(HWND)lParam
+ && HIWORD(wParam)==EN_SETFOCUS && LOWORD(wParam)==0
+ && !IsDlgButtonChecked(hwndDlg, IDC_BYCUSTOM)) {
+ CheckSearchTypeRadioButton(hwndDlg, IDC_BYCUSTOM);
+ }
+ break;
+ case WM_CONTEXTMENU:
+ { POINT pt;
+ LVHITTESTINFO lvhti;
+
+ pt.x=(short)LOWORD(lParam); pt.y=(short)HIWORD(lParam);
+ lvhti.pt=pt;
+ ScreenToClient(hwndDlg,&pt);
+ switch(GetDlgCtrlID(ChildWindowFromPoint(hwndDlg,pt))) {
+ case IDC_RESULTS:
+ if(dat->notSearchedYet) return TRUE;
+ ScreenToClient(hwndList,&lvhti.pt);
+ if(ListView_HitTest(hwndList,&lvhti)==-1) break;
+ ShowMoreOptionsMenu(hwndDlg,(short)LOWORD(lParam),(short)HIWORD(lParam));
+ return TRUE;
+ }
+ break;
+ }
+ case HM_SEARCHACK:
+ { ACKDATA *ack=(ACKDATA*)lParam;
+ int i;
+
+ if(ack->type!=ACKTYPE_SEARCH) break;
+ for(i=0;i<dat->searchCount;i++)
+ if(dat->search[i].hProcess==ack->hProcess && dat->search[i].hProcess != NULL && !lstrcmpA(dat->search[i].szProto,ack->szModule)) break;
+ if(i==dat->searchCount) break;
+ if(ack->result==ACKRESULT_SUCCESS || ack->result==ACKRESULT_FAILED) {
+ dat->searchCount--;
+ memmove(dat->search+i,dat->search+i+1,sizeof(struct ProtoSearchInfo)*(dat->searchCount-i));
+ if(dat->searchCount==0) {
+ mir_free(dat->search);
+ dat->search=NULL;
+ UnhookEvent(dat->hResultHook);
+ dat->hResultHook=NULL;
+ SetDlgItemText(hwndDlg, IDOK, TranslateT("&Search"));
+ StopThrobber(hwndDlg,dat);
+ }
+ ListView_SortItemsEx(hwndList, SearchResultsCompareFunc, (LPARAM)hwndDlg);
+ SetStatusBarSearchInfo(GetDlgItem(hwndDlg,IDC_STATUSBAR),dat);
+ }
+ else if(ack->result==ACKRESULT_SEARCHRESULT && ack->lParam) {
+
+ PROTOSEARCHRESULT *psr;
+ CUSTOMSEARCHRESULTS * csr=(CUSTOMSEARCHRESULTS*)ack->lParam;
+ dat->bFlexSearchResult=TRUE;
+ psr=&(csr->psr);
+ // check if this is column names data (psr->cbSize==0)
+ if ( psr->cbSize==0 ){ // blob contain info about columns
+
+ int iColumn;
+ LVCOLUMN lvc={0};
+
+ //firstly remove all exist items
+ FreeSearchResults(hwndList);
+ ListView_DeleteAllItems(hwndList); //not sure if previous delete list items too
+ //secondly remove all columns
+ while (ListView_DeleteColumn(hwndList,1)); //will delete fist column till it possible
+ //now will add columns and captions;
+ lvc.mask=LVCF_TEXT;
+ for (iColumn=0; iColumn<csr->nFieldCount; iColumn++)
+ {
+ lvc.pszText=TranslateTS(csr->pszFields[iColumn]);
+ ListView_InsertColumn (hwndList, iColumn+1, &lvc) ;
+ }
+ // Column inserting Done
+ } else { // blob contain info about found contacts
+
+ LVITEM lvi = {0};
+ int i, col;
+ struct ListSearchResult *lsr;
+ char *szComboProto;
+ COMBOBOXEXITEM cbei = {0};
+
+ lsr = (struct ListSearchResult*)mir_alloc(offsetof(struct ListSearchResult,psr)+psr->cbSize);
+ lsr->szProto = ack->szModule;
+ memcpy(&lsr->psr, psr, psr->cbSize);
+
+ /* Next block is not needed but behavior will be kept */
+ bool isUnicode = (psr->flags & PSR_UNICODE) != 0;
+ if (psr->id)
+ {
+ BOOL validPtr = isUnicode ? IsBadStringPtrW((wchar_t*)psr->id, 25) : IsBadStringPtrA((char*)psr->id, 25);
+ if (!validPtr)
+ {
+ isUnicode = false;
+ lsr->psr.id = NULL;
+ }
+ else
+ lsr->psr.id = isUnicode ? mir_u2t((wchar_t*)psr->id) : mir_a2t((char*)psr->id);
+ }
+
+ lsr->psr.nick = isUnicode ? mir_u2t((wchar_t*)psr->nick) : mir_a2t((char*)psr->nick);
+ lsr->psr.firstName = isUnicode ? mir_u2t((wchar_t*)psr->firstName) : mir_a2t((char*)psr->firstName);
+ lsr->psr.lastName = isUnicode ? mir_u2t((wchar_t*)psr->lastName) : mir_a2t((char*)psr->lastName);
+ lsr->psr.email = isUnicode ? mir_u2t((wchar_t*)psr->email) : mir_a2t((char*)psr->email);
+ lsr->psr.flags = psr->flags & ~PSR_UNICODE | PSR_TCHAR;
+
+ lvi.mask = LVIF_PARAM | LVIF_IMAGE;
+ lvi.lParam = (LPARAM)lsr;
+ for (i = SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CB_GETCOUNT, 0, 0); i--; )
+ {
+ szComboProto=(char*)SendDlgItemMessage(hwndDlg, IDC_PROTOLIST, CB_GETITEMDATA, i, 0);
+ if (szComboProto==NULL) continue;
+ if (!lstrcmpA(szComboProto,ack->szModule))
+ {
+ cbei.mask = CBEIF_IMAGE;
+ cbei.iItem = i;
+ SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CBEM_GETITEM,0,(LPARAM)&cbei);
+ lvi.iImage = cbei.iImage;
+ }
+ }
+ i = ListView_InsertItem(hwndList, &lvi);
+ for (col=0; col<csr->nFieldCount; col++) {
+ SetListItemText(hwndList, i, col+1 , csr->pszFields[col] );
+ }
+ ListView_SortItemsEx(hwndList, SearchResultsCompareFunc, (LPARAM)hwndDlg);
+ i=0;
+ while (ListView_SetColumnWidth(hwndList, i++, LVSCW_AUTOSIZE_USEHEADER));
+ SetStatusBarResultInfo(hwndDlg);
+ }
+ break;
+ }
+ else if(ack->result==ACKRESULT_DATA) {
+ LVITEM lvi={0};
+ int i,col;
+ PROTOSEARCHRESULT *psr=(PROTOSEARCHRESULT*)ack->lParam;
+ struct ListSearchResult *lsr;
+ char *szComboProto;
+ COMBOBOXEXITEM cbei={0};
+ dat->bFlexSearchResult=FALSE;
+ lsr=(struct ListSearchResult*)mir_alloc(offsetof(struct ListSearchResult,psr)+psr->cbSize);
+ lsr->szProto=ack->szModule;
+
+ CopyMemory(&lsr->psr, psr, psr->cbSize);
+ lsr->psr.nick = psr->flags & PSR_UNICODE ? mir_u2t((wchar_t*)psr->nick) : mir_a2t((char*)psr->nick);
+ lsr->psr.firstName = psr->flags & PSR_UNICODE ? mir_u2t((wchar_t*)psr->firstName) : mir_a2t((char*)psr->firstName);
+ lsr->psr.lastName = psr->flags & PSR_UNICODE ? mir_u2t((wchar_t*)psr->lastName) : mir_a2t((char*)psr->lastName);
+ lsr->psr.email = psr->flags & PSR_UNICODE ? mir_u2t((wchar_t*)psr->email) : mir_a2t((char*)psr->email);
+ lsr->psr.id = psr->flags & PSR_UNICODE ? mir_u2t((wchar_t*)psr->id) : mir_a2t((char*)psr->id);
+ lsr->psr.flags = psr->flags & ~PSR_UNICODE | PSR_TCHAR;
+
+ lvi.mask = LVIF_PARAM|LVIF_IMAGE;
+ lvi.lParam=(LPARAM)lsr;
+ for(i = SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETCOUNT,0,0); i--; )
+ {
+ szComboProto=(char*)SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETITEMDATA,i,0);
+ if(szComboProto==NULL) continue;
+ if(!lstrcmpA(szComboProto,ack->szModule)) {
+ cbei.mask=CBEIF_IMAGE;
+ cbei.iItem=i;
+ SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CBEM_GETITEM,0,(LPARAM)&cbei);
+ lvi.iImage=cbei.iImage;
+ break;
+ }
+ }
+ i=ListView_InsertItem(hwndList, &lvi);
+ col=1;
+ SetListItemText(hwndList, i, col++, lsr->psr.id );
+ SetListItemText(hwndList, i, col++, lsr->psr.nick );
+ SetListItemText(hwndList, i, col++, lsr->psr.firstName );
+ SetListItemText(hwndList, i, col++, lsr->psr.lastName );
+ SetListItemText(hwndList, i, col++, lsr->psr.email );
+ SetStatusBarResultInfo(hwndDlg);
+ }
+ break;
+ }
+ case WM_CLOSE:
+ DestroyWindow(hwndDlg);
+ break;
+ case WM_DESTROY:
+ {
+ TCHAR *szProto;
+ int len = SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETLBTEXTLEN,SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETCURSEL,0,0),0);
+ szProto = ( TCHAR* )alloca( sizeof(TCHAR)*( len+1 ));
+ *szProto='\0';
+ SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETLBTEXT,SendDlgItemMessage(hwndDlg,IDC_PROTOLIST,CB_GETCURSEL,0,0),(LPARAM)szProto);
+ DBWriteContactSettingTString(NULL, "FindAdd", "LastSearched", szProto?szProto:_T(""));
+ }
+ SaveColumnSizes(hwndList);
+ if(dat->hResultHook!=NULL) UnhookEvent(dat->hResultHook);
+ FreeSearchResults(hwndList);
+ ImageList_Destroy(dat->himlComboIcons);
+ mir_free(dat->search);
+ if(dat->hwndAdvSearch) {
+ DestroyWindow(dat->hwndAdvSearch);
+ dat->hwndAdvSearch=NULL;
+ }
+ if(dat->hwndTinySearch) {
+ DestroyWindow(dat->hwndTinySearch);
+ dat->hwndTinySearch=NULL;
+ }
+ DeleteObject(dat->hBmpSortDown);
+ DeleteObject(dat->hBmpSortUp);
+ mir_free(dat);
+ Window_FreeIcon_IcoLib(hwndDlg);
+ Utils_SaveWindowPosition(hwndDlg,NULL,"FindAdd","");
+
+ break;
+ }
+ return FALSE;
+}
+
+static INT_PTR FindAddCommand(WPARAM, LPARAM)
+{
+ if(IsWindow(hwndFindAdd)) {
+ ShowWindow(hwndFindAdd,SW_SHOWNORMAL);
+ SetForegroundWindow(hwndFindAdd);
+ SetFocus(hwndFindAdd);
+ }
+ else {
+ int netProtoCount, i;
+
+ // Make sure we have some networks to search on. This is not ideal since
+ // this check will be repeated every time the dialog is requested, but it
+ // must be done since this service can be called from other places than the menu.
+ // One alternative would be to only create the service if we have network
+ // protocols loaded but that would delay the creation until MODULE_LOADED and
+ // that is not good either...
+ for ( i=0, netProtoCount=0; i < accounts.getCount(); i++ ) {
+ PROTOACCOUNT* pa = accounts[i];
+ if (!Proto_IsAccountEnabled(pa)) continue;
+ int protoCaps=CallProtoService( pa->szModuleName, PS_GETCAPS, PFLAGNUM_1, 0 );
+ if ( protoCaps&PF1_BASICSEARCH || protoCaps&PF1_SEARCHBYEMAIL || protoCaps&PF1_SEARCHBYNAME
+ || protoCaps&PF1_EXTSEARCHUI ) netProtoCount++;
+ }
+ if (netProtoCount > 0)
+ hwndFindAdd=CreateDialog(hMirandaInst, MAKEINTRESOURCE(IDD_FINDADD), NULL, DlgProcFindAdd);
+ }
+ return 0;
+}
+
+int FindAddPreShutdown(WPARAM, LPARAM)
+{
+ if ( IsWindow( hwndFindAdd ))
+ DestroyWindow(hwndFindAdd);
+ hwndFindAdd = NULL;
+ return 0;
+}
+
+int LoadFindAddModule(void)
+{
+ CreateServiceFunction(MS_FINDADD_FINDADD,FindAddCommand);
+ HookEvent(ME_SYSTEM_MODULESLOADED, OnSystemModulesLoaded);
+ HookEvent(ME_PROTO_ACCLISTCHANGED, OnSystemModulesLoaded);
+ HookEvent(ME_SYSTEM_PRESHUTDOWN,FindAddPreShutdown);
+
+ CLISTMENUITEM mi = { 0 };
+ mi.cbSize = sizeof(mi);
+ mi.position = 500020000;
+ mi.flags = CMIF_ICONFROMICOLIB;
+ mi.icolibItem = GetSkinIconHandle( SKINICON_OTHER_FINDUSER );
+ mi.pszName = LPGEN("&Find/Add Contacts...");
+ mi.pszService = MS_FINDADD_FINDADD;
+ hMainMenuItem = ( HANDLE )CallService(MS_CLIST_ADDMAINMENUITEM, 0, (LPARAM)&mi);
+ return 0;
+}
+
+static int OnSystemModulesLoaded(WPARAM, LPARAM)
+{
+ int netProtoCount, i;
+
+ // Make sure we have some networks to search on.
+ for ( i=0, netProtoCount=0; i < accounts.getCount(); i++ ) {
+ PROTOACCOUNT* pa = accounts[i];
+ int protoCaps = CallProtoService( pa->szModuleName, PS_GETCAPS, PFLAGNUM_1, 0 );
+ if ( protoCaps & ( PF1_BASICSEARCH | PF1_SEARCHBYEMAIL | PF1_SEARCHBYNAME | PF1_EXTSEARCHUI ))
+ netProtoCount++;
+ }
+
+ CLISTMENUITEM cmi = { 0 };
+ cmi.cbSize = sizeof(cmi);
+ cmi.flags = CMIM_FLAGS;
+ if ( netProtoCount == 0 )
+ cmi.flags |= CMIF_HIDDEN;
+ CallService( MS_CLIST_MODIFYMENUITEM, (WPARAM)hMainMenuItem, (LPARAM)&cmi );
+ return 0;
+}
diff --git a/src/modules/findadd/findadd.h b/src/modules/findadd/findadd.h
new file mode 100644
index 0000000000..8e5fcb29e1
--- /dev/null
+++ b/src/modules/findadd/findadd.h
@@ -0,0 +1,59 @@
+/*
+
+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.
+*/
+struct ListSearchResult {
+ const char *szProto;
+ PROTOSEARCHRESULT psr;
+};
+
+struct ProtoSearchInfo {
+ const char *szProto;
+ HANDLE hProcess;
+};
+
+struct FindAddDlgData {
+ HANDLE hResultHook;
+ int bSortAscending;
+ int iLastColumnSortIndex;
+ HIMAGELIST himlComboIcons;
+ int showProtoId,showEmail,showName,showAdvanced,showTiny;
+ int minDlgHeight;
+ int notSearchedYet;
+ struct ProtoSearchInfo *search;
+ int searchCount;
+ HBITMAP hBmpSortUp,hBmpSortDown;
+ int throbbing;
+ int pivot;
+ HWND hwndAdvSearch;
+ HWND hwndTinySearch;
+ BOOL bFlexSearchResult;
+};
+
+int CALLBACK SearchResultsCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
+void FreeSearchResults(HWND hwndResults);
+int BeginSearch(HWND hwndDlg,struct FindAddDlgData *dat,const char *szProto,const char *szSearchService,DWORD requiredCapability,void *pvSearchParams);
+void SetStatusBarSearchInfo(HWND hwndStatus,struct FindAddDlgData *dat);
+void SetStatusBarResultInfo(HWND hwndDlg);
+void CreateResultsColumns(HWND hwndResults,struct FindAddDlgData *dat,char *szProto);
+void EnableResultButtons(HWND hwndDlg,int enable);
+void ShowMoreOptionsMenu(HWND hwndDlg,int x,int y);
+void SaveColumnSizes(HWND hwndResults);
diff --git a/src/modules/findadd/searchresults.cpp b/src/modules/findadd/searchresults.cpp
new file mode 100644
index 0000000000..4c8b7cf46c
--- /dev/null
+++ b/src/modules/findadd/searchresults.cpp
@@ -0,0 +1,398 @@
+/*
+
+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 "findadd.h"
+
+enum {
+ COLUMNID_PROTO,
+ COLUMNID_HANDLE,
+ COLUMNID_NICK,
+ COLUMNID_FIRST,
+ COLUMNID_LAST,
+ COLUMNID_EMAIL,
+ NUM_COLUMNID
+};
+
+void SaveColumnSizes(HWND hwndResults)
+{
+ int columnOrder[NUM_COLUMNID];
+ int columnCount;
+ char szSetting[32];
+ int i;
+ struct FindAddDlgData *dat;
+
+ dat=(struct FindAddDlgData*)GetWindowLongPtr(GetParent(hwndResults),GWLP_USERDATA);
+ columnCount=Header_GetItemCount(ListView_GetHeader(hwndResults));
+ if (columnCount != NUM_COLUMNID) return;
+ ListView_GetColumnOrderArray(hwndResults,columnCount,columnOrder);
+ for(i=0; i < NUM_COLUMNID; i++) {
+ mir_snprintf(szSetting, SIZEOF(szSetting), "ColOrder%d", i);
+ DBWriteContactSettingByte(NULL,"FindAdd",szSetting,(BYTE)columnOrder[i]);
+ if(i>=columnCount) continue;
+ mir_snprintf(szSetting, SIZEOF(szSetting), "ColWidth%d", i);
+ DBWriteContactSettingWord(NULL,"FindAdd",szSetting,(WORD)ListView_GetColumnWidth(hwndResults,i));
+ }
+ DBWriteContactSettingByte(NULL,"FindAdd","SortColumn",(BYTE)dat->iLastColumnSortIndex);
+ DBWriteContactSettingByte(NULL,"FindAdd","SortAscending",(BYTE)dat->bSortAscending);
+}
+
+static const TCHAR *szColumnNames[] = { NULL, NULL, _T("Nick"), _T("First Name"), _T("Last Name"), _T("E-mail") };
+static int defaultColumnSizes[]={0,90,100,100,100,2000};
+void LoadColumnSizes(HWND hwndResults,const char *szProto)
+{
+ HDITEM hdi;
+ int columnOrder[NUM_COLUMNID];
+ int columnCount;
+ char szSetting[32];
+ int i;
+ FindAddDlgData *dat;
+ bool colOrdersValid;
+
+ defaultColumnSizes[COLUMNID_PROTO] = GetSystemMetrics(SM_CXSMICON) + 4;
+ dat = (FindAddDlgData*)GetWindowLongPtr(GetParent(hwndResults), GWLP_USERDATA);
+
+ columnCount = NUM_COLUMNID;
+ colOrdersValid = true;
+ for(i=0; i < NUM_COLUMNID; i++)
+ {
+ LVCOLUMN lvc;
+ if( i < columnCount )
+ {
+ int bNeedsFree = FALSE;
+ lvc.mask = LVCF_TEXT | LVCF_WIDTH;
+ if( szColumnNames[i] != NULL )
+ lvc.pszText = TranslateTS( szColumnNames[i] );
+ else if( i == COLUMNID_HANDLE )
+ {
+ if (szProto)
+ {
+ #if defined( _UNICODE )
+ bNeedsFree = TRUE;
+ lvc.pszText = mir_a2t((char*)CallProtoService(szProto,PS_GETCAPS,PFLAG_UNIQUEIDTEXT,0));
+ #else
+ lvc.pszText = (char*)CallProtoService(szProto,PS_GETCAPS,PFLAG_UNIQUEIDTEXT,0);
+ #endif
+ }
+ else
+ lvc.pszText = _T("ID");
+ }
+ else lvc.mask &= ~LVCF_TEXT;
+ mir_snprintf(szSetting, SIZEOF(szSetting), "ColWidth%d", i);
+ lvc.cx = DBGetContactSettingWord(NULL, "FindAdd", szSetting, defaultColumnSizes[i]);
+ ListView_InsertColumn(hwndResults, i, (LPARAM)&lvc);
+ #if defined( _UNICODE )
+ if (bNeedsFree)
+ mir_free(lvc.pszText);
+ #endif
+ }
+ mir_snprintf(szSetting, SIZEOF(szSetting), "ColOrder%d", i);
+ columnOrder[i] = DBGetContactSettingByte(NULL, "FindAdd", szSetting, -1);
+ if (columnOrder[i] == -1 || columnOrder[i] >= NUM_COLUMNID) colOrdersValid = false;
+ }
+
+ if (colOrdersValid)
+ ListView_SetColumnOrderArray(hwndResults, columnCount, columnOrder);
+
+ dat->iLastColumnSortIndex = DBGetContactSettingByte(NULL, "FindAdd", "SortColumn", COLUMNID_NICK);
+ if (dat->iLastColumnSortIndex >= columnCount) dat->iLastColumnSortIndex = COLUMNID_NICK;
+ dat->bSortAscending = DBGetContactSettingByte(NULL, "FindAdd", "SortAscending", TRUE);
+
+ hdi.mask = HDI_BITMAP | HDI_FORMAT;
+ hdi.fmt = HDF_LEFT | HDF_BITMAP | HDF_STRING | HDF_BITMAP_ON_RIGHT;
+ hdi.hbm = dat->bSortAscending ? dat->hBmpSortDown : dat->hBmpSortUp;
+ Header_SetItem(ListView_GetHeader(hwndResults), dat->iLastColumnSortIndex, &hdi);
+}
+
+static LPARAM ListView_GetItemLParam(HWND hwndList, int idx)
+{
+ LVITEM lv;
+ lv.iItem = idx;
+ lv.mask = LVIF_PARAM;
+ ListView_GetItem(hwndList,&lv);
+ return lv.lParam;
+}
+
+int CALLBACK SearchResultsCompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
+{
+ struct FindAddDlgData *dat=(struct FindAddDlgData*)GetWindowLongPtr((HWND) lParamSort, GWLP_USERDATA);
+ int sortMultiplier;
+ int sortCol;
+ struct ListSearchResult *lsr1, *lsr2;
+ HWND hList=GetDlgItem((HWND) lParamSort, IDC_RESULTS);
+
+ sortMultiplier=dat->bSortAscending?1:-1;
+ sortCol=dat->iLastColumnSortIndex;
+ if (!dat->bFlexSearchResult)
+ {
+ lsr1=(struct ListSearchResult*)ListView_GetItemLParam(hList, (int)lParam1);
+ lsr2=(struct ListSearchResult*)ListView_GetItemLParam(hList, (int)lParam2);
+
+ if ( lsr1 == NULL || lsr2 == NULL ) return 0;
+ switch(sortCol)
+ {
+ case COLUMNID_PROTO:
+ return lstrcmpA(lsr1->szProto, lsr2->szProto)*sortMultiplier;
+ case COLUMNID_HANDLE:
+ return lstrcmpi(lsr1->psr.id, lsr2->psr.id)*sortMultiplier;
+ case COLUMNID_NICK:
+ return lstrcmpi(lsr1->psr.nick, lsr2->psr.nick)*sortMultiplier;
+ case COLUMNID_FIRST:
+ return lstrcmpi(lsr1->psr.firstName, lsr2->psr.firstName)*sortMultiplier;
+ case COLUMNID_LAST:
+ return lstrcmpi(lsr1->psr.lastName, lsr2->psr.lastName)*sortMultiplier;
+ case COLUMNID_EMAIL:
+ return lstrcmpi(lsr1->psr.email, lsr2->psr.email)*sortMultiplier;
+ }
+ }
+ else
+ {
+ TCHAR szText1[100];
+ TCHAR szText2[100];
+ ListView_GetItemText(hList,(int)lParam1,sortCol,szText1,SIZEOF(szText1));
+ ListView_GetItemText(hList,(int)lParam2,sortCol,szText2,SIZEOF(szText2));
+ return _tcsicmp(szText1, szText2)*sortMultiplier;
+ }
+ return 0;
+}
+
+void FreeSearchResults(HWND hwndResults)
+{
+ LV_ITEM lvi;
+ struct ListSearchResult *lsr;
+ for(lvi.iItem=ListView_GetItemCount(hwndResults)-1;lvi.iItem>=0;lvi.iItem--) {
+ lvi.mask=LVIF_PARAM;
+ ListView_GetItem(hwndResults,&lvi);
+ lsr=(struct ListSearchResult*)lvi.lParam;
+ if(lsr==NULL) continue;
+ mir_free(lsr->psr.id);
+ mir_free(lsr->psr.email);
+ mir_free(lsr->psr.nick);
+ mir_free(lsr->psr.firstName);
+ mir_free(lsr->psr.lastName);
+ mir_free(lsr);
+ }
+ ListView_DeleteAllItems(hwndResults);
+ EnableResultButtons(GetParent(hwndResults),0);
+}
+
+// on its own thread
+static void BeginSearchFailed(void * arg)
+{
+ TCHAR buf[128];
+ if ( arg != NULL ) {
+ const TCHAR* protoName = (TCHAR*)arg;
+ mir_sntprintf(buf,SIZEOF(buf),
+ TranslateT("Could not start a search on '%s', there was a problem - is %s connected?"),
+ protoName,protoName);
+ mir_free((char*)arg);
+ }
+ else lstrcpyn(buf,TranslateT("Could not search on any of the protocols, are you online?"),SIZEOF(buf));
+ MessageBox(0,buf,TranslateT("Problem with search"),MB_OK | MB_ICONERROR);
+}
+
+int BeginSearch(HWND,struct FindAddDlgData *dat,const char *szProto,const char *szSearchService,DWORD requiredCapability,void *pvSearchParams)
+{
+ int i;
+ if ( szProto == NULL ) {
+ int failures = 0;
+ dat->searchCount = 0;
+ dat->search = (struct ProtoSearchInfo*)mir_calloc(sizeof(struct ProtoSearchInfo) * accounts.getCount());
+ for( i=0; i < accounts.getCount();i++) {
+ PROTOACCOUNT* pa = accounts[i];
+ if (!Proto_IsAccountEnabled(pa)) continue;
+ DWORD caps=(DWORD)CallProtoService(pa->szModuleName,PS_GETCAPS,PFLAGNUM_1,0);
+ if(!(caps&requiredCapability)) continue;
+ dat->search[dat->searchCount].hProcess = (HANDLE)CallProtoService(pa->szModuleName,szSearchService,0,(LPARAM)pvSearchParams);
+ dat->search[dat->searchCount].szProto = pa->szModuleName;
+ if ( dat->search[dat->searchCount].hProcess == NULL ) failures++;
+ else dat->searchCount++;
+ }
+ if(failures) {
+ //infuriatingly vague error message. fixme.
+ if(dat->searchCount==0) {
+ forkthread(BeginSearchFailed,0,NULL);
+ mir_free(dat->search);
+ dat->search=NULL;
+ return 1;
+ } }
+ }
+ else {
+ dat->search=(struct ProtoSearchInfo*)mir_alloc(sizeof(struct ProtoSearchInfo));
+ dat->searchCount=1;
+ dat->search[0].hProcess=(HANDLE)CallProtoService(szProto,szSearchService,0,(LPARAM)pvSearchParams);
+ dat->search[0].szProto=szProto;
+ if(dat->search[0].hProcess==NULL) {
+ //infuriatingly vague error message. fixme.
+ PROTOACCOUNT* pa = Proto_GetAccount(szProto);
+ forkthread(BeginSearchFailed, 0, mir_tstrdup(pa->tszAccountName));
+ mir_free(dat->search);
+ dat->search=NULL;
+ dat->searchCount=0;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+// !!!!!!!! this code is dangerous like a hell
+void SetStatusBarSearchInfo(HWND hwndStatus,struct FindAddDlgData *dat)
+{
+ TCHAR str[256];
+
+ if (dat->searchCount != 0 ) {
+ int i;
+
+ lstrcpy( str, TranslateT("Searching"));
+ for( i=0; i < dat->searchCount; i++ ) {
+ PROTOACCOUNT* pa = Proto_GetAccount( dat->search[i].szProto );
+ if ( !pa )
+ continue;
+
+ lstrcat(str, i ? _T(",") : _T( " " ));
+ lstrcat(str, pa->tszAccountName );
+ } }
+ else lstrcpy(str, TranslateT("Idle"));
+
+ SendMessage( hwndStatus, SB_SETTEXT, 0, (LPARAM)str );
+}
+
+struct ProtoResultsSummary {
+ const char *szProto;
+ int count;
+};
+void SetStatusBarResultInfo(HWND hwndDlg)
+{
+ HWND hwndStatus=GetDlgItem(hwndDlg,IDC_STATUSBAR);
+ HWND hwndResults=GetDlgItem(hwndDlg,IDC_RESULTS);
+ LV_ITEM lvi;
+ struct ListSearchResult *lsr;
+ struct ProtoResultsSummary *subtotal=NULL;
+ int subtotalCount=0;
+ int i,total;
+ TCHAR str[256];
+
+ total=ListView_GetItemCount(hwndResults);
+ for(lvi.iItem=total-1;lvi.iItem>=0;lvi.iItem--) {
+ lvi.mask=LVIF_PARAM;
+ ListView_GetItem(hwndResults,&lvi);
+ lsr=(struct ListSearchResult*)lvi.lParam;
+ if(lsr==NULL) continue;
+ for(i=0;i<subtotalCount;i++) {
+ if(subtotal[i].szProto==lsr->szProto) {
+ subtotal[i].count++;
+ break;
+ }
+ }
+ if(i==subtotalCount) {
+ subtotal=(struct ProtoResultsSummary*)mir_realloc(subtotal,sizeof(struct ProtoResultsSummary)*(subtotalCount+1));
+ subtotal[subtotalCount].szProto=lsr->szProto;
+ subtotal[subtotalCount++].count=1;
+ }
+ }
+ if ( total != 0 ) {
+ TCHAR substr[64];
+ PROTOACCOUNT* pa = Proto_GetAccount( subtotal[0].szProto );
+ if ( pa == NULL )
+ return;
+
+ if ( subtotalCount == 1 ) {
+ if(total==1) mir_sntprintf( str, SIZEOF(str), TranslateT("1 %s user found"), pa->tszAccountName );
+ else mir_sntprintf( str, SIZEOF(str), TranslateT("%d %s users found"), total, pa->tszAccountName );
+ }
+ else {
+ mir_sntprintf( str, SIZEOF(str), TranslateT("%d users found ("),total);
+ for( i=0; i < subtotalCount; i++ ) {
+ if ( i ) {
+ if (( pa = Proto_GetAccount( subtotal[i].szProto )) == NULL )
+ return;
+ lstrcat( str, _T(", "));
+ }
+ mir_sntprintf( substr, SIZEOF(substr), _T("%d %s"), subtotal[i].count, pa->tszAccountName );
+ lstrcat( str, substr );
+ }
+ lstrcat( str, _T(")"));
+ }
+ mir_free(subtotal);
+ }
+ else lstrcpy(str, TranslateT("No users found"));
+ SendMessage(hwndStatus, SB_SETTEXT, 2, (LPARAM)str );
+}
+
+void CreateResultsColumns(HWND hwndResults,struct FindAddDlgData *dat,char *szProto)
+{
+ SaveColumnSizes(hwndResults);
+ while(ListView_DeleteColumn(hwndResults,0));
+ ListView_SetImageList(hwndResults,dat->himlComboIcons,LVSIL_SMALL);
+ LoadColumnSizes(hwndResults,szProto);
+}
+
+void ShowMoreOptionsMenu(HWND hwndDlg,int x,int y)
+{
+ struct FindAddDlgData *dat;
+ HMENU hPopupMenu,hMenu;
+ int commandId;
+ struct ListSearchResult *lsr;
+
+ dat=(struct FindAddDlgData*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA);
+
+ { LVITEM lvi;
+ if(ListView_GetSelectedCount(GetDlgItem(hwndDlg,IDC_RESULTS))!=1) return;
+ lvi.mask=LVIF_PARAM;
+ lvi.iItem=ListView_GetNextItem(GetDlgItem(hwndDlg,IDC_RESULTS),-1,LVNI_ALL|LVNI_SELECTED);
+ ListView_GetItem(GetDlgItem(hwndDlg,IDC_RESULTS),&lvi);
+ lsr=(struct ListSearchResult*)lvi.lParam;
+ }
+
+ hMenu=LoadMenu(hMirandaInst,MAKEINTRESOURCE(IDR_CONTEXT));
+ hPopupMenu=GetSubMenu(hMenu,4);
+ CallService(MS_LANGPACK_TRANSLATEMENU,(WPARAM)hPopupMenu,0);
+ commandId=TrackPopupMenu(hPopupMenu,TPM_RIGHTBUTTON|TPM_RETURNCMD,x,y,0,hwndDlg,NULL);
+ switch(commandId) {
+ case IDC_ADD:
+ { ADDCONTACTSTRUCT acs;
+
+ acs.handle=NULL;
+ acs.handleType=HANDLE_SEARCHRESULT;
+ acs.szProto=lsr->szProto;
+ acs.psr=&lsr->psr;
+ CallService(MS_ADDCONTACT_SHOW,(WPARAM)hwndDlg,(LPARAM)&acs);
+ break;
+ }
+ case IDC_DETAILS:
+ { HANDLE hContact;
+ hContact=(HANDLE)CallProtoService(lsr->szProto,PS_ADDTOLIST,PALF_TEMPORARY,(LPARAM)&lsr->psr);
+ CallService(MS_USERINFO_SHOWDIALOG,(WPARAM)hContact,0);
+ break;
+ }
+ case IDC_SENDMESSAGE:
+ { HANDLE hContact;
+ hContact=(HANDLE)CallProtoService(lsr->szProto,PS_ADDTOLIST,PALF_TEMPORARY,(LPARAM)&lsr->psr);
+ CallService(MS_MSG_SENDMESSAGE,(WPARAM)hContact,(LPARAM)(const char*)NULL);
+ break;
+ }
+ }
+ DestroyMenu(hPopupMenu);
+ DestroyMenu(hMenu);
+}
+
+
diff --git a/src/modules/fonts/FontOptions.cpp b/src/modules/fonts/FontOptions.cpp
new file mode 100644
index 0000000000..cbd19d23de
--- /dev/null
+++ b/src/modules/fonts/FontOptions.cpp
@@ -0,0 +1,1523 @@
+/*
+
+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 "FontService.h"
+
+// *_w2 is working copy of list
+// *_w3 is stores initial configuration
+
+static int sttCompareFont( const TFontID* p1, const TFontID* p2 )
+{
+ int result = _tcscmp( p1->group, p2->group );
+ if ( result != 0 )
+ return result;
+ result = p1->order - p2->order;
+ if ( result != 0 )
+ return result;
+ return _tcscmp( TranslateTS(p1->name), TranslateTS(p2->name) );
+}
+
+OBJLIST<TFontID> font_id_list( 20, sttCompareFont ), font_id_list_w2( 20, sttCompareFont ), font_id_list_w3( 20, sttCompareFont );
+
+static int sttCompareColour( const TColourID* p1, const TColourID* p2 )
+{
+ int result = _tcscmp( p1->group, p2->group );
+ if ( result != 0 )
+ return result;
+ result = p1->order - p2->order;
+ if ( result != 0 )
+ return result;
+
+ return _tcscmp( TranslateTS(p1->name), TranslateTS(p2->name) );
+}
+
+OBJLIST<TColourID> colour_id_list( 10, sttCompareColour ), colour_id_list_w2( 10, sttCompareColour ), colour_id_list_w3( 10, sttCompareColour );
+
+
+static int sttCompareEffect( const TEffectID* p1, const TEffectID* p2 )
+{
+ int result = _tcscmp( p1->group, p2->group );
+ if ( result != 0 )
+ return result;
+ result = p1->order - p2->order;
+ if ( result != 0 )
+ return result;
+
+ return _tcscmp( TranslateTS(p1->name), TranslateTS(p2->name) );
+}
+
+OBJLIST<TEffectID> effect_id_list( 10, sttCompareEffect ), effect_id_list_w2( 10, sttCompareEffect ), effect_id_list_w3( 10, sttCompareEffect );
+
+typedef struct DrawTextWithEffectParam_tag
+{
+ int cbSize;
+ HDC hdc; // handle to DC
+ LPCTSTR lpchText; // text to draw
+ int cchText; // length of text to draw
+ LPRECT lprc; // rectangle coordinates
+ UINT dwDTFormat; // formatting options
+ FONTEFFECT * pEffect; // effect to be drawn on
+
+} DrawTextWithEffectParam;
+
+#define MS_DRAW_TEXT_WITH_EFFECTA "Modern/SkinEngine/DrawTextWithEffectA"
+#define MS_DRAW_TEXT_WITH_EFFECTW "Modern/SkinEngine/DrawTextWithEffectW"
+
+#ifdef _UNICODE
+ #define MS_DRAW_TEXT_WITH_EFFECT MS_DRAW_TEXT_WITH_EFFECTW
+#else
+ #define MS_DRAW_TEXT_WITH_EFFECT MS_DRAW_TEXT_WITH_EFFECTA
+#endif
+
+// Helper
+int __inline DrawTextWithEffect( HDC hdc, LPCTSTR lpchText, int cchText, RECT * lprc, UINT dwDTFormat, FONTEFFECT * pEffect )
+{
+ DrawTextWithEffectParam params;
+ static BYTE bIfServiceExists = ServiceExists( MS_DRAW_TEXT_WITH_EFFECT ) ? 1 : 0;
+
+ if ( pEffect == NULL || pEffect->effectIndex == 0 )
+ return DrawText ( hdc, lpchText, cchText, lprc, dwDTFormat ); // If no effect specified draw by GDI it just more careful with ClearType
+
+ if ( bIfServiceExists == 0)
+ return DrawText ( hdc, lpchText, cchText, lprc, dwDTFormat );
+
+ // else
+ params.cbSize = sizeof( DrawTextWithEffectParam );
+ params.hdc = hdc;
+ params.lpchText = lpchText;
+ params.cchText = cchText;
+ params.lprc = lprc;
+ params.dwDTFormat = dwDTFormat;
+ params.pEffect = pEffect;
+ return CallService( MS_DRAW_TEXT_WITH_EFFECT, (WPARAM)&params, 0 );
+}
+
+
+#define UM_SETFONTGROUP (WM_USER + 101)
+#define TIMER_ID 11015
+
+#define FSUI_COLORBOXWIDTH 50
+#define FSUI_COLORBOXLEFT 5
+#define FSUI_FONTFRAMEHORZ 5
+#define FSUI_FONTFRAMEVERT 4
+#define FSUI_FONTLEFT (FSUI_COLORBOXLEFT+FSUI_COLORBOXWIDTH+5)
+
+extern void UpdateFontSettings(TFontID *font_id, TFontSettings *fontsettings);
+extern void UpdateColourSettings(TColourID *colour_id, COLORREF *colour);
+extern void UpdateEffectSettings(TEffectID* effect_id, TEffectSettings* effectsettings);
+
+void WriteLine(HANDLE fhand, char *line)
+{
+ DWORD wrote;
+ strcat(line, "\r\n");
+ WriteFile(fhand, line, (DWORD)strlen(line), &wrote, 0);
+}
+
+BOOL ExportSettings(HWND hwndDlg, TCHAR *filename, OBJLIST<TFontID>& flist, OBJLIST<TColourID>& clist, OBJLIST<TEffectID>& elist)
+{
+ int i;
+ char header[512], buff[1024], abuff[1024];
+
+ HANDLE fhand = CreateFile(filename, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
+ if(fhand == INVALID_HANDLE_VALUE) {
+ MessageBox(hwndDlg, filename, TranslateT("Failed to create file"), MB_ICONWARNING | MB_OK);
+ return FALSE;
+ }
+
+ header[0] = 0;
+
+ strcpy(buff, "SETTINGS:\r\n");
+ WriteLine(fhand, buff);
+
+ for ( i = 0; i < flist.getCount(); i++ ) {
+ TFontID& F = flist[i];
+
+ mir_snprintf(buff, SIZEOF(buff), "\r\n[%s]", F.dbSettingsGroup);
+ if ( strcmp( buff, header ) != 0) {
+ strcpy(header, buff);
+ WriteLine(fhand, buff);
+ }
+
+ if ( F.flags & FIDF_APPENDNAME )
+ mir_snprintf( buff, SIZEOF(buff), "%sName=s", F.prefix );
+ else
+ mir_snprintf( buff, SIZEOF(buff), "%s=s", F.prefix );
+
+ #if defined( _UNICODE )
+ WideCharToMultiByte(code_page, 0, F.value.szFace, -1, abuff, 1024, 0, 0);
+ abuff[1023]=0;
+ strcat( buff, abuff );
+ #else
+ strcat( buff, F.value.szFace );
+ #endif
+ WriteLine(fhand, buff);
+
+ mir_snprintf(buff, SIZEOF(buff), "%sSize=b", F.prefix);
+ if ( F.flags & FIDF_SAVEACTUALHEIGHT ) {
+ HDC hdc;
+ SIZE size;
+ HFONT hFont, hOldFont;
+ LOGFONT lf;
+ CreateFromFontSettings( &F.value, &lf );
+ hFont = CreateFontIndirect(&lf);
+
+ hdc = GetDC(hwndDlg);
+ hOldFont = (HFONT)SelectObject(hdc, hFont);
+ GetTextExtentPoint32(hdc, _T("_W"), 2, &size);
+ ReleaseDC(hwndDlg, hdc);
+ SelectObject(hdc, hOldFont);
+ DeleteObject(hFont);
+
+ strcat(buff, _itoa((BYTE)size.cy, abuff, 10));
+ }
+ else if(F.flags & FIDF_SAVEPOINTSIZE) {
+ HDC hdc = GetDC(hwndDlg);
+ strcat(buff, _itoa((BYTE)-MulDiv(F.value.size, 72, GetDeviceCaps(hdc, LOGPIXELSY)), abuff, 10));
+ ReleaseDC(hwndDlg, hdc);
+ }
+ else strcat(buff, _itoa((BYTE)F.value.size, abuff, 10));
+
+ WriteLine(fhand, buff);
+
+ mir_snprintf(buff, SIZEOF(buff), "%sSty=b%d", F.prefix, (BYTE)F.value.style);
+ WriteLine(fhand, buff);
+ mir_snprintf(buff, SIZEOF(buff), "%sSet=b%d", F.prefix, (BYTE)F.value.charset);
+ WriteLine(fhand, buff);
+ mir_snprintf(buff, SIZEOF(buff), "%sCol=d%d", F.prefix, (DWORD)F.value.colour);
+ WriteLine(fhand, buff);
+ if(F.flags & FIDF_NOAS) {
+ mir_snprintf(buff, SIZEOF(buff), "%sAs=w%d", F.prefix, (WORD)0x00FF);
+ WriteLine(fhand, buff);
+ }
+ mir_snprintf(buff, SIZEOF(buff), "%sFlags=w%d", F.prefix, (WORD)F.flags);
+ WriteLine(fhand, buff);
+ }
+
+ header[0] = 0;
+ for ( i=0; i < clist.getCount(); i++ ) {
+ TColourID& C = clist[i];
+
+ mir_snprintf(buff, SIZEOF(buff), "\r\n[%s]", C.dbSettingsGroup );
+ if(strcmp(buff, header) != 0) {
+ strcpy(header, buff);
+ WriteLine(fhand, buff);
+ }
+ mir_snprintf(buff, SIZEOF(buff), "%s=d%d", C.setting, (DWORD)C.value );
+ WriteLine(fhand, buff);
+ }
+
+ header[0] = 0;
+ for ( i=0; i < elist.getCount(); i++ ) {
+ TEffectID& E = elist[i];
+
+ mir_snprintf(buff, SIZEOF(buff), "\r\n[%s]", E.dbSettingsGroup );
+ if(strcmp(buff, header) != 0) {
+ strcpy(header, buff);
+ WriteLine(fhand, buff);
+ }
+ mir_snprintf(buff, SIZEOF(buff), "%sEffect=b%d", E.setting, E.value.effectIndex );
+ WriteLine(fhand, buff);
+ mir_snprintf(buff, SIZEOF(buff), "%sEffectCol1=d%d", E.setting, E.value.baseColour );
+ WriteLine(fhand, buff);
+ mir_snprintf(buff, SIZEOF(buff), "%sEffectCol2=d%d", E.setting, E.value.secondaryColour );
+ WriteLine(fhand, buff);
+ }
+
+
+ CloseHandle(fhand);
+ return TRUE;
+}
+
+void OptionsChanged()
+{
+ NotifyEventHooks(hFontReloadEvent, 0, 0);
+ NotifyEventHooks(hColourReloadEvent, 0, 0);
+}
+
+TOOLINFO ti;
+int x, y;
+
+UINT_PTR CALLBACK CFHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam) {
+ switch(uiMsg) {
+ case WM_INITDIALOG: {
+ CHOOSEFONT* cf = (CHOOSEFONT *)lParam;
+
+ TranslateDialogDefault(hdlg);
+ ShowWindow(GetDlgItem(hdlg, 1095), SW_HIDE);
+ if(cf && (cf->lCustData & FIDF_DISABLESTYLES)) {
+ EnableWindow(GetDlgItem(hdlg, 1137), FALSE);
+ ShowWindow(GetDlgItem(hdlg, 1137), SW_HIDE);
+ ShowWindow(GetDlgItem(hdlg, 1095), SW_SHOW);
+ }
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+struct FSUIListItemData
+{
+ int font_id;
+ int colour_id;
+ int effect_id;
+};
+
+
+static BOOL sttFsuiBindColourIdToFonts(HWND hwndList, const TCHAR *name, const TCHAR *backgroundGroup, const TCHAR *backgroundName, int colourId)
+{
+ int i;
+ BOOL res = FALSE;
+ for (i = SendMessage(hwndList, LB_GETCOUNT, 0, 0); i--; )
+ {
+ FSUIListItemData *itemData = (FSUIListItemData *)SendMessage(hwndList, LB_GETITEMDATA, i, 0);
+ if ( itemData && itemData->font_id >= 0) {
+ TFontID& F = font_id_list_w2[itemData->font_id];
+
+ if ( name && !_tcscmp( F.name, name )) {
+ itemData->colour_id = colourId;
+ res = TRUE;
+ }
+
+ if ( backgroundGroup && backgroundName && !_tcscmp( F.backgroundGroup, backgroundGroup) && !_tcscmp( F.backgroundName, backgroundName)) {
+ itemData->colour_id = colourId;
+ res = TRUE;
+ } } }
+
+ return res;
+}
+
+static BOOL sttFsuiBindEffectIdToFonts(HWND hwndList, const TCHAR *name, int effectId)
+{
+ int i;
+ BOOL res = FALSE;
+ for (i = SendMessage(hwndList, LB_GETCOUNT, 0, 0); i--; )
+ {
+ FSUIListItemData *itemData = (FSUIListItemData *)SendMessage(hwndList, LB_GETITEMDATA, i, 0);
+ if ( itemData && itemData->font_id >= 0) {
+ TFontID& F = font_id_list_w2[itemData->font_id];
+
+ if ( name && !_tcscmp( F.name, name )) {
+ itemData->effect_id = effectId;
+ res = TRUE;
+ }
+
+ } }
+
+ return res;
+}
+
+static HTREEITEM sttFindNamedTreeItemAt(HWND hwndTree, HTREEITEM hItem, const TCHAR *name)
+{
+ TVITEM tvi = {0};
+ TCHAR str[MAX_PATH];
+
+ if (hItem)
+ tvi.hItem = TreeView_GetChild(hwndTree, hItem);
+ else
+ tvi.hItem = TreeView_GetRoot(hwndTree);
+
+ if (!name)
+ return tvi.hItem;
+
+ tvi.mask = TVIF_TEXT;
+ tvi.pszText = str;
+ tvi.cchTextMax = MAX_PATH;
+
+ while (tvi.hItem)
+ {
+ TreeView_GetItem(hwndTree, &tvi);
+
+ if (!lstrcmp(tvi.pszText, name))
+ return tvi.hItem;
+
+ tvi.hItem = TreeView_GetNextSibling(hwndTree, tvi.hItem);
+ }
+ return NULL;
+}
+
+static void sttFsuiCreateSettingsTreeNode(HWND hwndTree, const TCHAR *groupName)
+{
+ TCHAR itemName[1024];
+ TCHAR* sectionName;
+ int sectionLevel = 0;
+
+ HTREEITEM hSection = NULL;
+ lstrcpy(itemName, groupName);
+ sectionName = itemName;
+
+ while (sectionName) {
+ // allow multi-level tree
+ TCHAR* pItemName = sectionName;
+ HTREEITEM hItem;
+
+ if (sectionName = _tcschr(sectionName, '/')) {
+ // one level deeper
+ *sectionName = 0;
+ }
+
+ pItemName = TranslateTS( pItemName );
+
+ hItem = sttFindNamedTreeItemAt(hwndTree, hSection, pItemName);
+ if (!sectionName || !hItem) {
+ if (!hItem) {
+ TVINSERTSTRUCT tvis = {0};
+ TreeItem *treeItem = (TreeItem *)mir_alloc(sizeof(TreeItem));
+ treeItem->groupName = sectionName ? NULL : mir_tstrdup(groupName);
+ treeItem->paramName = mir_t2a(itemName);
+
+ tvis.hParent = hSection;
+ tvis.hInsertAfter = TVI_SORT;//TVI_LAST;
+ tvis.item.mask = TVIF_TEXT|TVIF_PARAM;
+ tvis.item.pszText = pItemName;
+ tvis.item.lParam = (LPARAM)treeItem;
+
+ hItem = TreeView_InsertItem(hwndTree, &tvis);
+
+ ZeroMemory(&tvis.item, sizeof(tvis.item));
+ tvis.item.hItem = hItem;
+ tvis.item.mask = TVIF_HANDLE|TVIF_STATE;
+ tvis.item.state = tvis.item.stateMask = DBGetContactSettingByte(NULL, "FontServiceUI", treeItem->paramName, TVIS_EXPANDED );
+ TreeView_SetItem(hwndTree, &tvis.item);
+ } }
+
+ if (sectionName) {
+ *sectionName = '/';
+ sectionName++;
+ }
+
+ sectionLevel++;
+
+ hSection = hItem;
+ }
+}
+
+static void sttSaveCollapseState( HWND hwndTree )
+{
+ HTREEITEM hti;
+ TVITEM tvi;
+
+ hti = TreeView_GetRoot( hwndTree );
+ while( hti != NULL ) {
+ HTREEITEM ht;
+ TreeItem *treeItem;
+
+ tvi.mask = TVIF_STATE | TVIF_HANDLE | TVIF_CHILDREN | TVIF_PARAM;
+ tvi.hItem = hti;
+ tvi.stateMask = (DWORD)-1;
+ TreeView_GetItem( hwndTree, &tvi );
+
+ if( tvi.cChildren > 0 ) {
+ treeItem = (TreeItem *)tvi.lParam;
+ if ( tvi.state & TVIS_EXPANDED )
+ DBWriteContactSettingByte(NULL, "FontServiceUI", treeItem->paramName, TVIS_EXPANDED );
+ else
+ DBWriteContactSettingByte(NULL, "FontServiceUI", treeItem->paramName, 0 );
+ }
+
+ ht = TreeView_GetChild( hwndTree, hti );
+ if( ht == NULL ) {
+ ht = TreeView_GetNextSibling( hwndTree, hti );
+ while( ht == NULL ) {
+ hti = TreeView_GetParent( hwndTree, hti );
+ if( hti == NULL ) break;
+ ht = TreeView_GetNextSibling( hwndTree, hti );
+ } }
+
+ hti = ht;
+} }
+
+static void sttFreeListItems(HWND hList)
+{
+ int idx = 0;
+ LRESULT res;
+ FSUIListItemData *itemData;
+ int count = SendMessage( hList, LB_GETCOUNT, 0, 0 );
+ if ( count > 0 ) {
+ while ( idx < count) {
+ res = SendMessage( hList, LB_GETITEMDATA, idx++, 0 );
+ itemData = (FSUIListItemData *)res;
+ if ( itemData && res != LB_ERR )
+ mir_free( itemData );
+ }
+ }
+}
+
+static BOOL ShowEffectButton( HWND hwndDlg, BOOL bShow )
+{
+ ShowWindow(GetDlgItem(hwndDlg, IDC_BKGCOLOUR), bShow ? SW_HIDE : SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_BKGCOLOUR_STATIC), bShow ? SW_HIDE : SW_SHOW);
+
+ ShowWindow(GetDlgItem(hwndDlg, IDC_EFFECT), bShow ? SW_SHOW : SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_EFFECT_STATIC), bShow ? SW_SHOW : SW_HIDE);
+ return TRUE;
+}
+
+static INT_PTR CALLBACK ChooseEffectDlgProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
+{
+ static TEffectSettings * pEffect = NULL;
+
+ switch (uMsg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ pEffect = ( TEffectSettings*) lParam;
+ {
+ int i;
+ TCHAR * ModernEffectNames[]=
+ {
+ _T("<none>"),
+ _T("Shadow at left"),
+ _T("Shadow at right"),
+ _T("Outline"),
+ _T("Outline smooth"),
+ _T("Smooth bump"),
+ _T("Contour thin"),
+ _T("Contour heavy"),
+ };
+
+ for ( i=0; i<SIZEOF(ModernEffectNames) ; i++ )
+ {
+ int itemid = SendDlgItemMessage(hwndDlg, IDC_EFFECT_COMBO, CB_ADDSTRING,0,(LPARAM)TranslateTS(ModernEffectNames[i]));
+ SendDlgItemMessage(hwndDlg, IDC_EFFECT_COMBO, CB_SETITEMDATA, itemid, i );
+ SendDlgItemMessage(hwndDlg, IDC_EFFECT_COMBO, CB_SETCURSEL, 0, 0 );
+ }
+
+ int cnt=SendDlgItemMessage(hwndDlg, IDC_EFFECT_COMBO, CB_GETCOUNT, 0, 0 );
+ for ( i = 0; i < cnt; i++ ) {
+ if (SendDlgItemMessage(hwndDlg,IDC_EFFECT_COMBO,CB_GETITEMDATA,i,0)==pEffect->effectIndex ) {
+ SendDlgItemMessage(hwndDlg,IDC_EFFECT_COMBO,CB_SETCURSEL, i, 0 );
+ break;
+ } } }
+
+ SendDlgItemMessage(hwndDlg,IDC_EFFECT_COLOUR1,CPM_SETCOLOUR,0,pEffect->baseColour&0x00FFFFFF);
+ SendDlgItemMessage(hwndDlg,IDC_EFFECT_COLOUR2,CPM_SETCOLOUR,0,pEffect->secondaryColour&0x00FFFFFF);
+
+ SendDlgItemMessage(hwndDlg,IDC_EFFECT_COLOUR_SPIN1,UDM_SETRANGE,0,MAKELONG(255,0));
+ SendDlgItemMessage(hwndDlg,IDC_EFFECT_COLOUR_SPIN2,UDM_SETRANGE,0,MAKELONG(255,0));
+ SendDlgItemMessage(hwndDlg,IDC_EFFECT_COLOUR_SPIN1,UDM_SETPOS,0,MAKELONG((BYTE)~((BYTE)((pEffect->baseColour&0xFF000000)>>24)),0));
+ SendDlgItemMessage(hwndDlg,IDC_EFFECT_COLOUR_SPIN2,UDM_SETPOS,0,MAKELONG((BYTE)~((BYTE)((pEffect->secondaryColour&0xFF000000)>>24)),0));
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDOK:
+ {
+ int i = SendDlgItemMessage(hwndDlg,IDC_EFFECT_COMBO,CB_GETCURSEL, 0, 0 );
+ pEffect->effectIndex=(BYTE)SendDlgItemMessage(hwndDlg,IDC_EFFECT_COMBO,CB_GETITEMDATA,i,0);
+ pEffect->baseColour=SendDlgItemMessage(hwndDlg,IDC_EFFECT_COLOUR1,CPM_GETCOLOUR,0,0)|((~(BYTE)SendDlgItemMessage(hwndDlg,IDC_EFFECT_COLOUR_SPIN1,UDM_GETPOS,0,0))<<24);
+ pEffect->secondaryColour=SendDlgItemMessage(hwndDlg,IDC_EFFECT_COLOUR2,CPM_GETCOLOUR,0,0)|((~(BYTE)SendDlgItemMessage(hwndDlg,IDC_EFFECT_COLOUR_SPIN2,UDM_GETPOS,0,0))<<24);;
+ }
+ EndDialog( hwndDlg, IDOK );
+ return TRUE;
+
+ case IDCANCEL:
+ EndDialog( hwndDlg, IDCANCEL );
+ return TRUE;
+ }
+ break;
+ case WM_DESTROY:
+ pEffect = NULL;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static BOOL ChooseEffectDialog( HWND hwndParent, TEffectSettings * es)
+{
+ return ( DialogBoxParam( hMirandaInst, MAKEINTRESOURCE(IDD_CHOOSE_FONT_EFFECT), hwndParent, ChooseEffectDlgProc, (LPARAM) es ) == IDOK );
+}
+
+static void sttSaveFontData(HWND hwndDlg, TFontID &F)
+{
+ LOGFONT lf;
+ char str[128];
+
+ if ( F.flags & FIDF_APPENDNAME )
+ mir_snprintf(str, SIZEOF(str), "%sName", F.prefix);
+ else
+ mir_snprintf(str, SIZEOF(str), "%s", F.prefix);
+
+ if ( DBWriteContactSettingTString( NULL, F.dbSettingsGroup, str, F.value.szFace )) {
+ #if defined( _UNICODE )
+ char buff[1024];
+ WideCharToMultiByte(code_page, 0, F.value.szFace, -1, buff, 1024, 0, 0);
+ DBWriteContactSettingString(NULL, F.dbSettingsGroup, str, buff);
+ #endif
+ }
+
+ mir_snprintf(str, SIZEOF(str), "%sSize", F.prefix);
+ if ( F.flags & FIDF_SAVEACTUALHEIGHT ) {
+ HDC hdc;
+ SIZE size;
+ HFONT hFont, hOldFont;
+ CreateFromFontSettings( &F.value, &lf );
+ hFont = CreateFontIndirect( &lf );
+ hdc = GetDC(hwndDlg);
+ hOldFont = (HFONT)SelectObject( hdc, hFont );
+ GetTextExtentPoint32( hdc, _T("_W"), 2, &size);
+ ReleaseDC(hwndDlg, hdc);
+ SelectObject(hdc, hOldFont);
+ DeleteObject(hFont);
+
+ DBWriteContactSettingByte(NULL, F.dbSettingsGroup, str, (char)size.cy);
+ }
+ else if ( F.flags & FIDF_SAVEPOINTSIZE ) {
+ HDC hdc = GetDC(hwndDlg);
+ DBWriteContactSettingByte(NULL, F.dbSettingsGroup, str, (BYTE)-MulDiv(F.value.size, 72, GetDeviceCaps(hdc, LOGPIXELSY)));
+ ReleaseDC(hwndDlg, hdc);
+ }
+ else DBWriteContactSettingByte(NULL, F.dbSettingsGroup, str, F.value.size);
+
+ mir_snprintf(str, SIZEOF(str), "%sSty", F.prefix);
+ DBWriteContactSettingByte(NULL, F.dbSettingsGroup, str, F.value.style);
+ mir_snprintf(str, SIZEOF(str), "%sSet", F.prefix);
+ DBWriteContactSettingByte(NULL, F.dbSettingsGroup, str, F.value.charset);
+ mir_snprintf(str, SIZEOF(str), "%sCol", F.prefix);
+ DBWriteContactSettingDword(NULL, F.dbSettingsGroup, str, F.value.colour);
+ if ( F.flags & FIDF_NOAS ) {
+ mir_snprintf(str, SIZEOF(str), "%sAs", F.prefix);
+ DBWriteContactSettingWord(NULL, F.dbSettingsGroup, str, (WORD)0x00FF);
+ }
+ mir_snprintf(str, SIZEOF(str), "%sFlags", F.prefix);
+ DBWriteContactSettingWord(NULL, F.dbSettingsGroup, str, (WORD)F.flags);
+}
+
+static INT_PTR CALLBACK DlgProcLogOptions(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ int i;
+ LOGFONT lf;
+
+ static HBRUSH hBkgColourBrush = 0;
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ {
+ font_id_list_w2 = font_id_list;
+ font_id_list_w3 = font_id_list;
+
+ colour_id_list_w2 = colour_id_list;
+ colour_id_list_w3 = colour_id_list;
+
+ effect_id_list_w2 = effect_id_list;
+ effect_id_list_w3 = effect_id_list;
+
+ for ( i = 0; i < font_id_list_w2.getCount(); i++ ) {
+ TFontID& F = font_id_list_w2[i];
+ // sync settings with database
+ UpdateFontSettings( &F, &F.value );
+ sttFsuiCreateSettingsTreeNode(GetDlgItem(hwndDlg, IDC_FONTGROUP), F.group);
+ }
+
+ for ( i = 0; i < colour_id_list_w2.getCount(); i++ ) {
+ TColourID& C = colour_id_list_w2[i];
+
+ // sync settings with database
+ UpdateColourSettings( &C, &C.value );
+ sttFsuiCreateSettingsTreeNode(GetDlgItem(hwndDlg, IDC_FONTGROUP), C.group);
+ }
+
+ for ( i = 0; i < effect_id_list_w2.getCount(); i++ ) {
+ TEffectID& E = effect_id_list_w2[i];
+
+ // sync settings with database
+ UpdateEffectSettings( &E, &E.value );
+ sttFsuiCreateSettingsTreeNode(GetDlgItem(hwndDlg, IDC_FONTGROUP), E.group);
+ }
+ }
+
+ SendDlgItemMessage(hwndDlg, IDC_BKGCOLOUR, CPM_SETDEFAULTCOLOUR, 0, (LPARAM)GetSysColor(COLOR_WINDOW));
+ return TRUE;
+
+ case UM_SETFONTGROUP:
+ {
+ TreeItem *treeItem;
+ TCHAR *group_buff = NULL;
+ TVITEM tvi = {0};
+ tvi.hItem = TreeView_GetSelection(GetDlgItem(hwndDlg, IDC_FONTGROUP));
+ tvi.mask = TVIF_HANDLE|TVIF_PARAM;
+ TreeView_GetItem(GetDlgItem(hwndDlg, IDC_FONTGROUP), &tvi);
+ treeItem = (TreeItem *)tvi.lParam;
+ group_buff = treeItem->groupName;
+
+ sttFreeListItems(GetDlgItem(hwndDlg, IDC_FONTLIST));
+ SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_RESETCONTENT, 0, 0);
+
+ if (group_buff) {
+ BOOL need_restart = FALSE;
+ int fontId = 0, itemId;
+ int first_font_index = -1;
+ int colourId = 0;
+ int first_colour_index = -1;
+ int effectId = 0;
+ int first_effect_index = -1;
+
+ SendDlgItemMessage(hwndDlg, IDC_FONTLIST, WM_SETREDRAW, FALSE, 0);
+
+ for ( fontId = 0; fontId < font_id_list_w2.getCount(); fontId++ ) {
+ TFontID& F = font_id_list_w2[fontId];
+ if ( _tcsncmp( F.group, group_buff, 64 ) == 0 ) {
+ FSUIListItemData *itemData = ( FSUIListItemData* )mir_alloc(sizeof(FSUIListItemData));
+ itemData->colour_id = -1;
+ itemData->effect_id = -1;
+ itemData->font_id = fontId;
+
+ if ( first_font_index == -1 )
+ first_font_index = fontId;
+
+ itemId = SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_ADDSTRING, (WPARAM)-1, (LPARAM)itemData);
+ need_restart |= (F.flags & FIDF_NEEDRESTART);
+ } }
+
+// ShowWindow( GetDlgItem(hwndDlg, IDC_STAT_RESTART), (need_restart ? SW_SHOW : SW_HIDE));
+
+ if ( hBkgColourBrush ) {
+ DeleteObject( hBkgColourBrush );
+ hBkgColourBrush = 0;
+ }
+
+ for ( colourId = 0; colourId < colour_id_list_w2.getCount(); colourId++ ) {
+ TColourID& C = colour_id_list_w2[colourId];
+ if ( _tcsncmp( C.group, group_buff, 64 ) == 0 ) {
+ FSUIListItemData *itemData = NULL;
+ if ( first_colour_index == -1 )
+ first_colour_index = colourId;
+
+ if (!sttFsuiBindColourIdToFonts(GetDlgItem(hwndDlg, IDC_FONTLIST), C.name, C.group, C.name, colourId)) {
+ itemData = ( FSUIListItemData* )mir_alloc(sizeof(FSUIListItemData));
+ itemData->colour_id = colourId;
+ itemData->font_id = -1;
+ itemData->effect_id = -1;
+
+ itemId = SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_ADDSTRING, (WPARAM)-1, (LPARAM)itemData);
+ }
+
+ if ( _tcscmp( C.name, _T("Background") ) == 0 )
+ hBkgColourBrush = CreateSolidBrush( C.value );
+ } }
+
+ if ( !hBkgColourBrush )
+ hBkgColourBrush = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
+
+ for ( effectId = 0; effectId < effect_id_list_w2.getCount(); effectId++ ) {
+ TEffectID& E = effect_id_list_w2[effectId];
+ if ( _tcsncmp( E.group, group_buff, 64 ) == 0 ) {
+ FSUIListItemData *itemData = NULL;
+ if ( first_effect_index == -1 )
+ first_effect_index = effectId;
+
+ if (!sttFsuiBindEffectIdToFonts(GetDlgItem(hwndDlg, IDC_FONTLIST), E.name, effectId)) {
+ itemData = ( FSUIListItemData* )mir_alloc(sizeof(FSUIListItemData));
+ itemData->effect_id = effectId;
+ itemData->font_id = -1;
+ itemData->colour_id = -1;
+
+ itemId = SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_ADDSTRING, (WPARAM)-1, (LPARAM)itemData);
+ } } }
+
+ SendDlgItemMessage(hwndDlg, IDC_FONTLIST, WM_SETREDRAW, TRUE, 0);
+ UpdateWindow(GetDlgItem(hwndDlg, IDC_FONTLIST));
+
+ SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_SETSEL, TRUE, 0);
+ SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_FONTLIST, LBN_SELCHANGE), 0);
+ }
+ else {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BKGCOLOUR), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_FONTCOLOUR), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CHOOSEFONT), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_RESET), FALSE);
+ ShowEffectButton(hwndDlg, FALSE);
+ }
+ return TRUE;
+ }
+
+ case WM_MEASUREITEM:
+ {
+ MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT *)lParam;
+ HFONT hFont = NULL, hoFont = NULL;
+ SIZE fontSize;
+ BOOL bIsFont = FALSE;
+ FSUIListItemData *itemData = (FSUIListItemData *)mis->itemData;
+ TCHAR *itemName = NULL;
+ HDC hdc;
+
+ if ((mis->CtlID != IDC_FONTLIST) || (mis->itemID == -1))
+ break;
+
+ if (!itemData) return FALSE;
+
+ if (itemData->font_id >= 0) {
+ int iItem = itemData->font_id;
+ bIsFont = TRUE;
+ CreateFromFontSettings( &font_id_list_w2[iItem].value, &lf );
+ hFont = CreateFontIndirect(&lf);
+ itemName = TranslateTS(font_id_list_w2[iItem].name);
+ }
+
+ if (itemData->colour_id >= 0) {
+ int iItem = itemData->colour_id;
+ if ( !itemName )
+ itemName = TranslateTS( colour_id_list_w2[iItem].name );
+ }
+
+ hdc = GetDC(GetDlgItem(hwndDlg, mis->CtlID));
+ if ( hFont )
+ hoFont = (HFONT) SelectObject(hdc, hFont);
+ else
+ hoFont = (HFONT) SelectObject(hdc, (HFONT)SendDlgItemMessage(hwndDlg, mis->CtlID, WM_GETFONT, 0, 0));
+
+ GetTextExtentPoint32(hdc, itemName, lstrlen(itemName), &fontSize);
+ if (hoFont) SelectObject(hdc, hoFont);
+ if (hFont) DeleteObject(hFont);
+ ReleaseDC(GetDlgItem(hwndDlg, mis->CtlID), hdc);
+ mis->itemWidth = fontSize.cx + 2*FSUI_FONTFRAMEHORZ + 4;
+ mis->itemHeight = fontSize.cy + 2*FSUI_FONTFRAMEVERT + 4;
+ return TRUE;
+ }
+
+ case WM_DRAWITEM:
+ {
+ DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *) lParam;
+ HFONT hFont = NULL, hoFont = NULL;
+ COLORREF clBack = (COLORREF)-1;
+ COLORREF clText = GetSysColor(COLOR_WINDOWTEXT);
+ BOOL bIsFont = FALSE;
+ TCHAR *itemName = NULL;
+
+ FSUIListItemData *itemData = (FSUIListItemData *)dis->itemData;
+
+ FONTEFFECT Effect;
+ FONTEFFECT * pEffect = NULL;
+
+ if(dis->CtlID != IDC_FONTLIST)
+ break;
+
+ if (!itemData) return FALSE;
+
+ if ( itemData->font_id >= 0 ) {
+ int iItem = itemData->font_id;
+ bIsFont = TRUE;
+ CreateFromFontSettings(&font_id_list_w2[iItem].value, &lf );
+ hFont = CreateFontIndirect(&lf);
+ itemName = TranslateTS(font_id_list_w2[iItem].name);
+ clText = font_id_list_w2[iItem].value.colour;
+ }
+
+ if ( itemData->colour_id >= 0 ) {
+ int iItem = itemData->colour_id;
+ if (bIsFont)
+ clBack = colour_id_list_w2[iItem].value;
+ else {
+ clText = colour_id_list_w2[iItem].value;
+ itemName = TranslateTS(colour_id_list_w2[iItem].name);
+
+ } }
+
+ if ( itemData->effect_id >= 0 ) {
+ int iItem = itemData->effect_id;
+
+ Effect.effectIndex = effect_id_list_w2[iItem].value.effectIndex;
+ Effect.baseColour = effect_id_list_w2[iItem].value.baseColour;
+ Effect.secondaryColour = effect_id_list_w2[iItem].value.secondaryColour;
+ pEffect = &Effect;
+
+ if (!bIsFont)
+ itemName = TranslateTS(effect_id_list_w2[iItem].name);
+ }
+
+ if (hFont)
+ hoFont = (HFONT) SelectObject(dis->hDC, hFont);
+ else
+ hoFont = (HFONT) SelectObject(dis->hDC, (HFONT)SendDlgItemMessage(hwndDlg, dis->CtlID, WM_GETFONT, 0, 0));
+
+ SetBkMode(dis->hDC, TRANSPARENT);
+
+ if (dis->itemState & ODS_SELECTED) {
+ SetTextColor(dis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
+ FillRect(dis->hDC, &dis->rcItem, GetSysColorBrush(COLOR_HIGHLIGHT));
+ }
+ else {
+ SetTextColor(dis->hDC, bIsFont?clText:GetSysColor(COLOR_WINDOWTEXT));
+ if (bIsFont && (clBack != (COLORREF)-1)) {
+ HBRUSH hbrTmp = CreateSolidBrush(clBack);
+ FillRect(dis->hDC, &dis->rcItem, hbrTmp);
+ DeleteObject(hbrTmp);
+ }
+ else FillRect(dis->hDC, &dis->rcItem, bIsFont ? hBkgColourBrush : GetSysColorBrush(COLOR_WINDOW));
+ }
+
+ if ( bIsFont ) {
+ HBRUSH hbrBack;
+ RECT rc;
+
+ if (clBack != (COLORREF)-1)
+ hbrBack = CreateSolidBrush(clBack);
+ else {
+ LOGBRUSH lb;
+ GetObject(hBkgColourBrush, sizeof(lf), &lb);
+ hbrBack = CreateBrushIndirect(&lb);
+ }
+
+ SetRect(&rc,
+ dis->rcItem.left+FSUI_COLORBOXLEFT,
+ dis->rcItem.top+FSUI_FONTFRAMEVERT,
+ dis->rcItem.left+FSUI_COLORBOXLEFT+FSUI_COLORBOXWIDTH,
+ dis->rcItem.bottom-FSUI_FONTFRAMEVERT);
+
+ FillRect(dis->hDC, &rc, hbrBack);
+ DeleteObject(hbrBack);
+
+ FrameRect(dis->hDC, &rc, GetSysColorBrush(COLOR_HIGHLIGHT));
+ rc.left += 1;
+ rc.top += 1;
+ rc.right -= 1;
+ rc.bottom -= 1;
+ FrameRect(dis->hDC, &rc, GetSysColorBrush(COLOR_HIGHLIGHTTEXT));
+
+ SetTextColor(dis->hDC, clText);
+
+ DrawTextWithEffect(dis->hDC, _T("abc"), 3, &rc, DT_CENTER|DT_NOPREFIX|DT_SINGLELINE|DT_VCENTER|DT_WORD_ELLIPSIS, pEffect );
+
+ if (dis->itemState & ODS_SELECTED) {
+ SetTextColor(dis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
+ pEffect = NULL; // Do not draw effect on selected item name text
+ }
+ rc = dis->rcItem;
+ rc.left += FSUI_FONTLEFT;
+ DrawTextWithEffect(dis->hDC, itemName, (int)_tcslen(itemName), &rc, DT_LEFT|DT_NOPREFIX|DT_SINGLELINE|DT_VCENTER|DT_WORD_ELLIPSIS, pEffect );
+ } else
+ {
+ RECT rc;
+ HBRUSH hbrTmp;
+ SetRect(&rc,
+ dis->rcItem.left+FSUI_COLORBOXLEFT,
+ dis->rcItem.top+FSUI_FONTFRAMEVERT,
+ dis->rcItem.left+FSUI_COLORBOXLEFT+FSUI_COLORBOXWIDTH,
+ dis->rcItem.bottom-FSUI_FONTFRAMEVERT);
+
+ hbrTmp = CreateSolidBrush(clText);
+ FillRect(dis->hDC, &rc, hbrTmp);
+ DeleteObject(hbrTmp);
+
+ FrameRect(dis->hDC, &rc, GetSysColorBrush(COLOR_HIGHLIGHT));
+ rc.left += 1;
+ rc.top += 1;
+ rc.right -= 1;
+ rc.bottom -= 1;
+ FrameRect(dis->hDC, &rc, GetSysColorBrush(COLOR_HIGHLIGHTTEXT));
+
+ rc = dis->rcItem;
+ rc.left += FSUI_FONTLEFT;
+
+ DrawTextWithEffect(dis->hDC, itemName, (int)_tcslen(itemName), &rc, DT_LEFT|DT_NOPREFIX|DT_SINGLELINE|DT_VCENTER|DT_WORD_ELLIPSIS, pEffect );
+ }
+ if (hoFont) SelectObject(dis->hDC, hoFont);
+ if (hFont) DeleteObject(hFont);
+ return TRUE;
+ }
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDC_FONTLIST:
+ if (HIWORD(wParam) == LBN_SELCHANGE) {
+ int selCount, i;
+
+ char bEnableFont = 1;
+ char bEnableClText = 1;
+ char bEnableClBack = 1;
+ char bEnableEffect = 1;
+ char bEnableReset = 1;
+
+ COLORREF clBack = 0xffffffff;
+ COLORREF clText = 0xffffffff;
+
+ if (selCount = SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_GETSELCOUNT, (WPARAM)0, (LPARAM)0)) {
+ int *selItems = (int *)mir_alloc(font_id_list_w2.getCount() * sizeof(int));
+ SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_GETSELITEMS, (WPARAM)selCount, (LPARAM)selItems);
+ for (i = 0; i < selCount; ++i) {
+ FSUIListItemData *itemData = (FSUIListItemData *)SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_GETITEMDATA, selItems[i], 0);
+ if (IsBadReadPtr(itemData, sizeof(FSUIListItemData))) continue; // prevent possible problems with corrupted itemData
+
+ if (bEnableClBack && (itemData->colour_id < 0))
+ bEnableClBack = 0;
+ if (bEnableEffect && (itemData->effect_id < 0))
+ bEnableEffect = 0;
+ if (bEnableFont && (itemData->font_id < 0))
+ bEnableFont = 0;
+ if (!bEnableFont || bEnableClText && (itemData->font_id < 0))
+ bEnableClText = 0;
+ if (bEnableReset && (itemData->font_id >= 0) && !(font_id_list_w2[itemData->font_id].flags&FIDF_DEFAULTVALID))
+ bEnableReset = 0;
+
+ if (bEnableClBack && (itemData->colour_id >= 0) && (clBack == 0xffffffff))
+ clBack = colour_id_list_w2[itemData->colour_id].value;
+ if (bEnableClText && (itemData->font_id >= 0) && (clText == 0xffffffff))
+ clText = font_id_list_w2[itemData->font_id].value.colour;
+ }
+ mir_free(selItems);
+ }
+ else {
+ bEnableFont = 0;
+ bEnableClText = 0;
+ bEnableClBack = 0;
+ bEnableReset = 0;
+ bEnableEffect = 0;
+ }
+
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BKGCOLOUR), bEnableClBack);
+ ShowEffectButton( hwndDlg, bEnableEffect && !bEnableClBack );
+
+ EnableWindow(GetDlgItem(hwndDlg, IDC_FONTCOLOUR), bEnableClText);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CHOOSEFONT), bEnableFont);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_RESET), bEnableReset);
+
+ if (bEnableClBack) SendDlgItemMessage(hwndDlg, IDC_BKGCOLOUR, CPM_SETCOLOUR, 0, clBack);
+ if (bEnableClText) SendDlgItemMessage(hwndDlg, IDC_FONTCOLOUR, CPM_SETCOLOUR, 0, clText);
+
+ return TRUE;
+ }
+
+ if (HIWORD(wParam) != LBN_DBLCLK)
+ return TRUE;
+
+ //fall through
+
+ case IDC_CHOOSEFONT:
+ {
+ int selCount;
+ if (selCount = SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_GETSELCOUNT, 0, 0)) {
+ FSUIListItemData *itemData;
+ CHOOSEFONT cf = { 0 };
+ int i;
+ int *selItems = (int *)mir_alloc(selCount * sizeof(int));
+ SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_GETSELITEMS, (WPARAM)selCount, (LPARAM) selItems);
+ itemData = (FSUIListItemData *)SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_GETITEMDATA, selItems[0], 0);
+ if (itemData->font_id < 0) {
+ mir_free(selItems);
+ if (itemData->colour_id >= 0)
+ SendDlgItemMessage(hwndDlg, IDC_BKGCOLOUR, WM_LBUTTONUP, 0, 0);
+ return TRUE;
+ }
+
+ TFontID& F = font_id_list_w2[itemData->font_id];
+
+ CreateFromFontSettings(&F.value, &lf );
+
+ cf.lStructSize = sizeof(cf);
+ cf.hwndOwner = hwndDlg;
+ cf.lpLogFont = &lf;
+ cf.lCustData = 0;
+
+ if ( F.flags & FIDF_ALLOWEFFECTS )
+ {
+ cf.Flags = CF_FORCEFONTEXIST | CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS | CF_EFFECTS | CF_ENABLETEMPLATE | CF_ENABLEHOOK;
+ // use custom font dialog to disable colour selection
+ cf.hInstance = hMirandaInst;
+ cf.lpTemplateName = MAKEINTRESOURCE(IDD_CUSTOM_FONT);
+ cf.lpfnHook = CFHookProc;
+ }
+ else if ( F.flags & FIDF_DISABLESTYLES ) { // no style selection, mutually exclusive with FIDF_ALLOWEFFECTS
+ cf.Flags = CF_FORCEFONTEXIST | CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS | CF_ENABLETEMPLATE | CF_ENABLEHOOK | CF_TTONLY | CF_NOOEMFONTS;
+ cf.lCustData = F.flags;
+ cf.hInstance = hMirandaInst;
+ cf.lpTemplateName = MAKEINTRESOURCE(IDD_CUSTOM_FONT);
+ cf.lpfnHook = CFHookProc;
+ lf.lfWeight = FW_NORMAL;
+ lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = FALSE;
+ }
+ else cf.Flags = CF_FORCEFONTEXIST | CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
+
+ if (ChooseFont(&cf)) {
+ for (i = 0; i < selCount; ++i) {
+ FSUIListItemData *itemData = (FSUIListItemData *)SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_GETITEMDATA, selItems[i], 0);
+ if (itemData->font_id < 0)
+ continue;
+
+ TFontID& F1 = font_id_list_w2[itemData->font_id];
+ F1.value.size = (char)lf.lfHeight;
+ F1.value.style = (lf.lfWeight >= FW_BOLD ? DBFONTF_BOLD : 0) | (lf.lfItalic ? DBFONTF_ITALIC : 0) | (lf.lfUnderline ? DBFONTF_UNDERLINE : 0) | (lf.lfStrikeOut ? DBFONTF_STRIKEOUT : 0);
+ F1.value.charset = lf.lfCharSet;
+ _tcscpy(F1.value.szFace, lf.lfFaceName);
+
+ MEASUREITEMSTRUCT mis = { 0 };
+ mis.CtlID = IDC_FONTLIST;
+ mis.itemID = selItems[i];
+ mis.itemData = SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_GETITEMDATA, selItems[i], 0);
+ SendMessage(hwndDlg, WM_MEASUREITEM, 0, (LPARAM) & mis);
+ SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_SETITEMHEIGHT, selItems[i], mis.itemHeight);
+ }
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_FONTLIST), NULL, TRUE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_UNDO), TRUE);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+
+ mir_free(selItems);
+ }
+ return TRUE;
+ }
+ case IDC_EFFECT:
+ {
+ int selCount;
+ if (selCount = SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_GETSELCOUNT, 0, 0)) {
+ FSUIListItemData *itemData;
+ TEffectSettings es = { 0 };
+ int i;
+ int *selItems = (int *)mir_alloc(selCount * sizeof(int));
+ SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_GETSELITEMS, (WPARAM)selCount, (LPARAM) selItems);
+ itemData = (FSUIListItemData *)SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_GETITEMDATA, selItems[0], 0);
+ TEffectID& E = effect_id_list_w2[itemData->effect_id];
+ es = E.value;
+ if ( ChooseEffectDialog(hwndDlg, &es) ) {
+ for (i = 0; i < selCount; ++i) {
+ FSUIListItemData *itemData = (FSUIListItemData *)SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_GETITEMDATA, selItems[i], 0);
+ if (itemData->effect_id < 0)
+ continue;
+
+ TEffectID& E1 = effect_id_list_w2[itemData->effect_id];
+ E1.value = es;
+ }
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_FONTLIST), NULL, TRUE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_UNDO), TRUE);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+
+ mir_free(selItems);
+ }
+ break;
+ }
+ case IDC_FONTCOLOUR:
+ {
+ int selCount, i;
+ if (selCount = SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_GETSELCOUNT, 0, 0)) {
+ int *selItems = (int *)mir_alloc(selCount * sizeof(int));
+ SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_GETSELITEMS, (WPARAM)selCount, (LPARAM) selItems);
+ for (i = 0; i < selCount; i++) {
+ FSUIListItemData *itemData = (FSUIListItemData *)SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_GETITEMDATA, selItems[i], 0);
+ if (itemData->font_id < 0) continue;
+ font_id_list_w2[itemData->font_id].value.colour = SendDlgItemMessage(hwndDlg, IDC_FONTCOLOUR, CPM_GETCOLOUR, 0, 0);
+ }
+ mir_free(selItems);
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_FONTLIST), NULL, FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_UNDO), TRUE);
+ }
+ break;
+ }
+ case IDC_BKGCOLOUR:
+ {
+ int selCount, i;
+ if (selCount = SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_GETSELCOUNT, 0, 0)) {
+ int *selItems = (int *)mir_alloc(selCount * sizeof(int));
+ SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_GETSELITEMS, (WPARAM)selCount, (LPARAM) selItems);
+ for (i = 0; i < selCount; i++) {
+ FSUIListItemData *itemData = (FSUIListItemData *)SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_GETITEMDATA, selItems[i], 0);
+ if (itemData->colour_id < 0) continue;
+ colour_id_list_w2[itemData->colour_id].value = SendDlgItemMessage(hwndDlg, IDC_BKGCOLOUR, CPM_GETCOLOUR, 0, 0);
+
+ if ( _tcscmp( colour_id_list_w2[itemData->colour_id].name, _T("Background") ) == 0 )
+ {
+ if ( hBkgColourBrush ) DeleteObject( hBkgColourBrush );
+ hBkgColourBrush = CreateSolidBrush( colour_id_list_w2[itemData->colour_id].value );
+ }
+ }
+ mir_free(selItems);
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_FONTLIST), NULL, FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_UNDO), TRUE);
+ }
+ break;
+ }
+ case IDC_BTN_RESET:
+ {
+ int selCount;
+ if (font_id_list_w2.getCount() && (selCount = SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_GETSELCOUNT, (WPARAM)0, (LPARAM)0))) {
+ int *selItems = (int *)mir_alloc(font_id_list_w2.getCount() * sizeof(int));
+ SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_GETSELITEMS, (WPARAM)selCount, (LPARAM)selItems);
+ for (i = 0; i < selCount; ++i) {
+ FSUIListItemData *itemData = (FSUIListItemData *)SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_GETITEMDATA, selItems[i], 0);
+ if (IsBadReadPtr(itemData, sizeof(FSUIListItemData))) continue; // prevent possible problems with corrupted itemData
+
+ if((itemData->font_id >= 0) && (font_id_list_w2[itemData->font_id].flags & FIDF_DEFAULTVALID)) {
+ font_id_list_w2[itemData->font_id].value = font_id_list_w2[itemData->font_id].deffontsettings;
+
+ MEASUREITEMSTRUCT mis = { 0 };
+ mis.CtlID = IDC_FONTLIST;
+ mis.itemID = selItems[i];
+ mis.itemData = SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_GETITEMDATA, selItems[i], 0);
+ SendMessage(hwndDlg, WM_MEASUREITEM, 0, (LPARAM) & mis);
+ SendDlgItemMessage(hwndDlg, IDC_FONTLIST, LB_SETITEMHEIGHT, selItems[i], mis.itemHeight);
+ }
+
+ if (itemData->colour_id >= 0)
+ colour_id_list_w2[itemData->colour_id].value = colour_id_list_w2[itemData->colour_id].defcolour;
+
+ if (itemData->effect_id >= 0)
+ effect_id_list_w2[itemData->effect_id].value = effect_id_list_w2[itemData->effect_id].defeffect;
+
+ }
+ mir_free(selItems);
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_FONTLIST), NULL, TRUE);
+ SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_FONTLIST, LBN_SELCHANGE), 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_UNDO), TRUE);
+ }
+ break;
+ }
+ case IDC_BTN_EXPORT:
+ {
+ TCHAR fname_buff[MAX_PATH], filter[MAX_PATH];
+ mir_sntprintf(filter, SIZEOF(filter), _T("%s (*.ini)%c*.ini%c%s (*.txt)%c*.TXT%c%s (*.*)%c*.*%c"), TranslateT("Configuration Files"), 0, 0, TranslateT("Text Files"), 0, 0, TranslateT("All Files"), 0, 0);
+
+ OPENFILENAME ofn = {0};
+ ofn.lStructSize = sizeof(ofn);
+ ofn.lpstrFile = fname_buff;
+ ofn.lpstrFile[0] = '\0';
+ ofn.nMaxFile = MAX_PATH;
+ ofn.hwndOwner = hwndDlg;
+ ofn.Flags = OFN_NOREADONLYRETURN | OFN_CREATEPROMPT | OFN_OVERWRITEPROMPT;
+ ofn.lpstrFilter = filter;
+ ofn.nFilterIndex = 1;
+
+ ofn.lpstrDefExt = _T("ini");
+
+ if ( GetSaveFileName( &ofn ) == TRUE )
+ if ( !ExportSettings( hwndDlg, ofn.lpstrFile, font_id_list, colour_id_list, effect_id_list ))
+ MessageBox(hwndDlg, TranslateT("Error writing file"), TranslateT("Error"), MB_ICONWARNING | MB_OK);
+ return TRUE;
+ }
+ case IDC_BTN_UNDO:
+ font_id_list_w2 = font_id_list_w3;
+ colour_id_list_w2 = colour_id_list_w3;
+ effect_id_list_w2 = effect_id_list_w3;
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BTN_UNDO), FALSE);
+
+ SendMessage(hwndDlg, UM_SETFONTGROUP, 0, 0);
+ break;
+
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case WM_NOTIFY:
+ if (((LPNMHDR) lParam)->idFrom == 0 && ((LPNMHDR) lParam)->code == PSN_APPLY ) {
+ char str[32];
+
+ font_id_list_w3 = font_id_list;
+ colour_id_list_w3 = colour_id_list;
+ effect_id_list_w3 = effect_id_list;
+
+ EnableWindow( GetDlgItem(hwndDlg, IDC_BTN_UNDO), TRUE );
+
+ font_id_list = font_id_list_w2;
+ colour_id_list = colour_id_list_w2;
+ effect_id_list = effect_id_list_w2;
+
+ for ( i=0; i < font_id_list_w2.getCount(); i++ ) {
+ TFontID& F = font_id_list_w2[i];
+ sttSaveFontData(hwndDlg, F);
+ }
+
+ for ( i=0; i < colour_id_list_w2.getCount(); i++ ) {
+ TColourID& C = colour_id_list_w2[i];
+
+ mir_snprintf(str, SIZEOF(str), "%s", C.setting);
+ DBWriteContactSettingDword(NULL, C.dbSettingsGroup, str, C.value);
+ }
+
+ for ( i=0; i < effect_id_list_w2.getCount(); i++ ) {
+ TEffectID& E = effect_id_list_w2[i];
+
+ mir_snprintf(str, SIZEOF(str), "%sEffect", E.setting);
+ DBWriteContactSettingByte(NULL, E.dbSettingsGroup, str, E.value.effectIndex);
+
+ mir_snprintf(str, SIZEOF(str), "%sEffectCol1", E.setting);
+ DBWriteContactSettingDword(NULL, E.dbSettingsGroup, str, E.value.baseColour);
+
+ mir_snprintf(str, SIZEOF(str), "%sEffectCol2", E.setting);
+ DBWriteContactSettingDword(NULL, E.dbSettingsGroup, str, E.value.secondaryColour);
+ }
+
+ OptionsChanged();
+ return TRUE;
+ }
+
+ if (((LPNMHDR) lParam)->idFrom == IDC_FONTGROUP) {
+ switch(((NMHDR*)lParam)->code) {
+ case TVN_SELCHANGEDA: // !!!! This needs to be here - both !!
+ case TVN_SELCHANGEDW:
+ SendMessage(hwndDlg, UM_SETFONTGROUP, 0, 0);
+ break;
+
+ case TVN_DELETEITEMA: // no idea why both TVN_SELCHANGEDA/W should be there but let's keep this both too...
+ case TVN_DELETEITEMW:
+ {
+ TreeItem *treeItem = (TreeItem *)(((LPNMTREEVIEW)lParam)->itemOld.lParam);
+ if (treeItem) {
+ mir_free(treeItem->groupName);
+ mir_free(treeItem->paramName);
+ mir_free(treeItem);
+ }
+ break;
+ }
+ }
+ }
+ break;
+
+ case WM_DESTROY:
+ KillTimer(hwndDlg, TIMER_ID);
+ sttSaveCollapseState(GetDlgItem(hwndDlg, IDC_FONTGROUP));
+ DeleteObject(hBkgColourBrush);
+ font_id_list_w2.destroy();
+ font_id_list_w3.destroy();
+ colour_id_list_w2.destroy();
+ colour_id_list_w3.destroy();
+ effect_id_list_w2.destroy();
+ effect_id_list_w3.destroy();
+ sttFreeListItems(GetDlgItem(hwndDlg, IDC_FONTLIST));
+ break;
+ }
+ return FALSE;
+}
+
+int OptInit(WPARAM wParam, LPARAM)
+{
+ OPTIONSDIALOGPAGE odp = {0};
+
+ odp.cbSize = sizeof(odp);
+ odp.cbSize = OPTIONPAGE_OLD_SIZE2;
+ odp.position = -790000000;
+ odp.hInstance = hMirandaInst;;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_FONTS);
+ odp.pszTitle = LPGEN("Fonts & Colors");
+ odp.pszGroup = LPGEN("Customize");
+ odp.flags = ODPF_BOLDGROUPS;
+ odp.nIDBottomSimpleControl = 0;
+ odp.pfnDlgProc = DlgProcLogOptions;
+ CallService( MS_OPT_ADDPAGE, wParam,( LPARAM )&odp );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static TFontID *sttFindFont(OBJLIST<TFontID> &fonts, char *module, char *prefix)
+{
+ for ( int i = 0; i < fonts.getCount(); i++ )
+ {
+ TFontID& F = fonts[i];
+ if ( !lstrcmpA(F.dbSettingsGroup, module) && !lstrcmpA(F.prefix, prefix) )
+ return &F;
+ }
+
+ return 0;
+}
+
+static INT_PTR CALLBACK DlgProcModernOptions(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ int i;
+ LOGFONT lf;
+
+ static TFontID fntHeader={0}, fntGeneral={0}, fntSmall={0};
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ {
+ TranslateDialogDefault(hwndDlg);
+
+ fntHeader = *sttFindFont(font_id_list, "Fonts", "Header");
+ UpdateFontSettings(&fntHeader, &fntHeader.value);
+ fntGeneral = *sttFindFont(font_id_list, "Fonts", "Generic");
+ UpdateFontSettings(&fntGeneral, &fntGeneral.value);
+ fntSmall = *sttFindFont(font_id_list, "Fonts", "Small");
+ UpdateFontSettings(&fntSmall, &fntSmall.value);
+
+ return TRUE;
+ }
+
+ case WM_DRAWITEM:
+ {
+ TFontID *pf = 0;
+ DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *) lParam;
+ switch (dis->CtlID)
+ {
+ case IDC_PREVIEWHEADER:
+ pf = &fntHeader;
+ break;
+ case IDC_PREVIEWGENERAL:
+ pf = &fntGeneral;
+ break;
+ case IDC_PREVIEWSMALL:
+ pf = &fntSmall;
+ break;
+ }
+
+ if (!pf) break;
+
+ HFONT hFont = NULL, hoFont = NULL;
+ COLORREF clText = GetSysColor(COLOR_WINDOWTEXT);
+ CreateFromFontSettings(&pf->value, &lf);
+ hFont = CreateFontIndirect(&lf);
+ hoFont = (HFONT) SelectObject(dis->hDC, hFont);
+ SetBkMode(dis->hDC, TRANSPARENT);
+ SetTextColor(dis->hDC, GetSysColor(COLOR_BTNTEXT));
+ FillRect(dis->hDC, &dis->rcItem, GetSysColorBrush(COLOR_BTNFACE));
+ DrawText(dis->hDC, TranslateT("Sample Text"), (int)_tcslen(TranslateT("Sample Text")), &dis->rcItem, DT_LEFT|DT_NOPREFIX|DT_SINGLELINE|DT_VCENTER|DT_WORD_ELLIPSIS|DT_CENTER);
+ if (hoFont) SelectObject(dis->hDC, hoFont);
+ return TRUE;
+ }
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDC_CHOOSEFONTHEADER:
+ case IDC_CHOOSEFONTGENERAL:
+ case IDC_CHOOSEFONTSMALL:
+ {
+ CHOOSEFONT cf = { 0 };
+ TFontID *pf = NULL;
+ switch (LOWORD(wParam))
+ {
+ case IDC_CHOOSEFONTHEADER:
+ pf = &fntHeader;
+ break;
+ case IDC_CHOOSEFONTGENERAL:
+ pf = &fntGeneral;
+ break;
+ case IDC_CHOOSEFONTSMALL:
+ pf = &fntSmall;
+ break;
+ };
+
+ CreateFromFontSettings(&pf->value, &lf);
+
+ cf.lStructSize = sizeof(cf);
+ cf.hwndOwner = hwndDlg;
+ cf.lpLogFont = &lf;
+ cf.Flags = CF_FORCEFONTEXIST | CF_INITTOLOGFONTSTRUCT | CF_SCREENFONTS;
+ if ( pf->flags & FIDF_ALLOWEFFECTS )
+ {
+ cf.Flags |= CF_EFFECTS | CF_ENABLETEMPLATE | CF_ENABLEHOOK;
+ // use custom font dialog to disable colour selection
+ cf.hInstance = hMirandaInst;
+ cf.lpTemplateName = MAKEINTRESOURCE(IDD_CUSTOM_FONT);
+ cf.lpfnHook = CFHookProc;
+ }
+
+ if (ChooseFont(&cf))
+ {
+ pf->value.size = (char)lf.lfHeight;
+ pf->value.style = (lf.lfWeight >= FW_BOLD ? DBFONTF_BOLD : 0) | (lf.lfItalic ? DBFONTF_ITALIC : 0) | (lf.lfUnderline ? DBFONTF_UNDERLINE : 0) | (lf.lfStrikeOut ? DBFONTF_STRIKEOUT : 0);
+ pf->value.charset = lf.lfCharSet;
+ _tcscpy(pf->value.szFace, lf.lfFaceName);
+
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_PREVIEWHEADER), NULL, TRUE);
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_PREVIEWGENERAL), NULL, TRUE);
+ InvalidateRect(GetDlgItem(hwndDlg, IDC_PREVIEWSMALL), NULL, TRUE);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ return TRUE;
+ }
+ }
+ break;
+
+ case WM_NOTIFY:
+ if (((LPNMHDR) lParam)->idFrom == 0 && ((LPNMHDR) lParam)->code == PSN_APPLY ) {
+ for ( i=0; i < font_id_list.getCount(); i++ )
+ {
+ TFontID &F = font_id_list[i];
+ if (F.deffontsettings.charset == SYMBOL_CHARSET) continue;
+
+ COLORREF cl = F.value.colour;
+ if ((F.flags&FIDF_CLASSMASK) == FIDF_CLASSHEADER ||
+ (F.flags&FIDF_CLASSMASK) == 0 &&
+ (_tcsstr(F.name, _T("Incoming nick")) ||
+ _tcsstr(F.name, _T("Outgoing nick")) ||
+ _tcsstr(F.name, _T("Incoming timestamp")) ||
+ _tcsstr(F.name, _T("Outgoing timestamp")))
+ )
+ {
+ F.value = fntHeader.value;
+ } else
+ if ((F.flags&FIDF_CLASSMASK) == FIDF_CLASSSMALL)
+ {
+ F.value = fntSmall.value;
+ } else
+ {
+ F.value = fntGeneral.value;
+ }
+ F.value.colour = cl;
+ sttSaveFontData(hwndDlg, F);
+ }
+
+ OptionsChanged();
+ }
+ break;
+ }
+ return FALSE;
+}
+
+INT_PTR CALLBACK AccMgrDlgProc(HWND, UINT, WPARAM, LPARAM);
+INT_PTR CALLBACK DlgPluginOpt(HWND, UINT, WPARAM, LPARAM);
+
+int FontsModernOptInit(WPARAM wParam, LPARAM lParam)
+{
+ static int iBoldControls[] =
+ {
+ IDC_TXT_TITLE1, IDC_TXT_TITLE2, IDC_TXT_TITLE3,
+ MODERNOPT_CTRL_LAST
+ };
+
+ MODERNOPTOBJECT obj = {0};
+ obj.cbSize = sizeof(obj);
+ obj.dwFlags = MODEROPT_FLG_TCHAR|MODEROPT_FLG_NORESIZE;
+ obj.hIcon = LoadSkinnedIcon(SKINICON_OTHER_MIRANDA);
+ obj.hInstance = hMirandaInst;
+ obj.iSection = MODERNOPT_PAGE_SKINS;
+ obj.iType = MODERNOPT_TYPE_SUBSECTIONPAGE;
+ obj.iBoldControls = iBoldControls;
+ obj.lptzSubsection = LPGENT("Fonts");
+ obj.lpzClassicGroup = "Customize";
+ obj.lpzClassicPage = "Fonts";
+ obj.lpzHelpUrl = "http://wiki.miranda-im.org/";
+
+ obj.lpzTemplate = MAKEINTRESOURCEA(IDD_MODERNOPT_FONTS);
+ obj.pfnDlgProc = DlgProcModernOptions;
+ CallService(MS_MODERNOPT_ADDOBJECT, wParam, (LPARAM)&obj);
+
+ obj.iSection = MODERNOPT_PAGE_ACCOUNTS;
+ obj.iType = MODERNOPT_TYPE_SECTIONPAGE;
+ obj.lpzTemplate = MAKEINTRESOURCEA(IDD_MODERNOPT_ACCOUNTS);
+ obj.pfnDlgProc = AccMgrDlgProc;
+ obj.lpzClassicGroup = NULL;
+ obj.lpzClassicPage = "Network";
+ obj.lpzHelpUrl = "http://wiki.miranda-im.org/";
+ CallService(MS_MODERNOPT_ADDOBJECT, wParam, (LPARAM)&obj);
+
+ obj.iSection = MODERNOPT_PAGE_MODULES;
+ obj.iType = MODERNOPT_TYPE_SECTIONPAGE;
+// obj.lptzSubsection = LPGENT("Installed Plugins");
+ obj.lpzTemplate = MAKEINTRESOURCEA(IDD_MODERNOPT_MODULES);
+ obj.pfnDlgProc = DlgPluginOpt;
+ obj.iBoldControls = iBoldControls;
+ obj.lpzClassicGroup = NULL;
+ obj.lpzClassicPage = NULL;
+ obj.lpzHelpUrl = "http://wiki.miranda-im.org/";
+ CallService(MS_MODERNOPT_ADDOBJECT, wParam, (LPARAM)&obj);
+ return 0;
+}
diff --git a/src/modules/fonts/FontService.cpp b/src/modules/fonts/FontService.cpp
new file mode 100644
index 0000000000..f0f1afae16
--- /dev/null
+++ b/src/modules/fonts/FontService.cpp
@@ -0,0 +1,126 @@
+/*
+
+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_fontservice.h"
+
+#include "FontService.h"
+
+int code_page = CP_ACP;
+HANDLE hFontReloadEvent, hColourReloadEvent;
+
+int OptInit( WPARAM, LPARAM );
+int FontsModernOptInit(WPARAM wParam, LPARAM lParam);
+
+INT_PTR RegisterFont(WPARAM wParam, LPARAM lParam);
+INT_PTR RegisterFontW(WPARAM wParam, LPARAM lParam);
+
+INT_PTR GetFont(WPARAM wParam, LPARAM lParam);
+INT_PTR GetFontW(WPARAM wParam, LPARAM lParam);
+
+INT_PTR RegisterColour(WPARAM wParam, LPARAM lParam);
+INT_PTR RegisterColourW(WPARAM wParam, LPARAM lParam);
+
+INT_PTR GetColour(WPARAM wParam, LPARAM lParam);
+INT_PTR GetColourW(WPARAM wParam, LPARAM lParam);
+
+INT_PTR RegisterEffect(WPARAM wParam, LPARAM lParam);
+INT_PTR RegisterEffectW(WPARAM wParam, LPARAM lParam);
+
+INT_PTR GetEffect(WPARAM wParam, LPARAM lParam);
+INT_PTR GetEffectW(WPARAM wParam, LPARAM lParam);
+
+static int OnModulesLoaded(WPARAM, LPARAM)
+{
+ HookEvent(ME_OPT_INITIALISE, OptInit);
+ HookEvent(ME_MODERNOPT_INITIALIZE, FontsModernOptInit);
+ return 0;
+}
+
+static int OnPreShutdown(WPARAM, LPARAM)
+{
+ DestroyHookableEvent(hFontReloadEvent);
+ DestroyHookableEvent(hColourReloadEvent);
+
+ font_id_list.destroy();
+ colour_id_list.destroy();
+ return 0;
+}
+
+int LoadFontserviceModule( void )
+{
+ code_page = LangPackGetDefaultCodePage();
+
+ CreateServiceFunction(MS_FONT_REGISTER, RegisterFont);
+ CreateServiceFunction(MS_FONT_GET, GetFont);
+
+ CreateServiceFunction(MS_COLOUR_REGISTER, RegisterColour);
+ CreateServiceFunction(MS_COLOUR_GET, GetColour);
+
+ CreateServiceFunction(MS_EFFECT_REGISTER, RegisterEffect);
+ CreateServiceFunction(MS_EFFECT_GET, GetEffect);
+
+#if defined( _UNICODE )
+ CreateServiceFunction(MS_FONT_REGISTERW, RegisterFontW);
+ CreateServiceFunction(MS_FONT_GETW, GetFontW);
+
+ CreateServiceFunction(MS_COLOUR_REGISTERW, RegisterColourW);
+ CreateServiceFunction(MS_COLOUR_GETW, GetColourW);
+
+ CreateServiceFunction(MS_EFFECT_REGISTERW, RegisterEffectW);
+ CreateServiceFunction(MS_EFFECT_GETW, GetEffectW);
+#endif
+
+ hFontReloadEvent = CreateHookableEvent(ME_FONT_RELOAD);
+ hColourReloadEvent = CreateHookableEvent(ME_COLOUR_RELOAD);
+
+ // cretae generic fonts
+ FontIDT fontid = {0};
+
+ fontid.cbSize = sizeof(FontID);
+ strncpy(fontid.dbSettingsGroup, "Fonts", sizeof(fontid.dbSettingsGroup));
+ _tcsncpy(fontid.group, _T("General"), SIZEOF(fontid.group));
+
+ _tcsncpy(fontid.name, _T("Headers"), SIZEOF(fontid.name));
+ fontid.flags = FIDF_APPENDNAME | FIDF_NOAS | FIDF_SAVEPOINTSIZE | FIDF_ALLOWEFFECTS | FIDF_CLASSHEADER;
+ strncpy(fontid.prefix, "Header", SIZEOF(fontid.prefix));
+ fontid.order = 0;
+ FontRegisterT( &fontid );
+
+ _tcsncpy(fontid.name, _T("Generic text"), SIZEOF(fontid.name));
+ fontid.flags = FIDF_APPENDNAME | FIDF_NOAS | FIDF_SAVEPOINTSIZE | FIDF_ALLOWEFFECTS | FIDF_CLASSGENERAL;
+ strncpy(fontid.prefix, "Generic", SIZEOF(fontid.prefix));
+ fontid.order = 0;
+ FontRegisterT( &fontid );
+
+ _tcsncpy(fontid.name, _T("Small text"), SIZEOF(fontid.name));
+ fontid.flags = FIDF_APPENDNAME | FIDF_NOAS | FIDF_SAVEPOINTSIZE | FIDF_ALLOWEFFECTS | FIDF_CLASSSMALL;
+ strncpy(fontid.prefix, "Small", SIZEOF(fontid.prefix));
+ fontid.order = 0;
+ FontRegisterT( &fontid );
+
+ // do last for silly dyna plugin
+ HookEvent(ME_SYSTEM_MODULESLOADED, OnModulesLoaded);
+ HookEvent(ME_SYSTEM_PRESHUTDOWN, OnPreShutdown);
+ return 0;
+}
diff --git a/src/modules/fonts/FontService.h b/src/modules/fonts/FontService.h
new file mode 100644
index 0000000000..4f665ae6d3
--- /dev/null
+++ b/src/modules/fonts/FontService.h
@@ -0,0 +1,112 @@
+/*
+
+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 "m_fontservice.h"
+
+
+// settings to be used for the value of 'deffontsettings' in the FontID structure below - i.e. defaults
+typedef struct TFontSettings_tag
+{
+ COLORREF colour;
+ char size;
+ BYTE style; // see the DBFONTF_* flags above
+ BYTE charset;
+ TCHAR szFace[LF_FACESIZE];
+}
+ TFontSettings;
+
+// a font identifier structure - used for registering a font, and getting one out again
+
+struct TFontID
+{
+ int cbSize;
+ TCHAR group[64]; // group the font belongs to - this is the 'Font Group' list in the options page
+ TCHAR name[64]; // this is the name of the font setting - e.g. 'contacts' in the 'contact list' group
+ char dbSettingsGroup[32]; // the 'module' in the database where the font data is stored
+ char prefix[32]; // this is prepended to the settings used to store this font's data in the db
+ DWORD flags; // bitwise OR of the FIDF_* flags above
+ TFontSettings deffontsettings; // defaults, valid if flags & FIDF_DEFAULTVALID
+ int order; // controls the order in the font group in which the fonts are listed in the UI (if order fields are equal,
+ // they will be ordered alphabetically by name)
+ TCHAR backgroundGroup[64];
+ TCHAR backgroundName[64];
+ TFontSettings value;
+};
+
+struct TColourID
+{
+ int cbSize;
+ TCHAR group[64];
+ TCHAR name[64];
+ char dbSettingsGroup[32];
+ char setting[32];
+ DWORD flags;
+ COLORREF defcolour;
+ int order;
+
+ COLORREF value;
+};
+
+// clist_modern related tune-up, adding clist_modern effects to FontService
+
+typedef struct TEffectSettings_tag
+{
+ BYTE effectIndex;
+ DWORD baseColour; // ARGB
+ DWORD secondaryColour; // ARGB
+}
+TEffectSettings;
+
+
+struct TEffectID
+{
+ int cbSize;
+ TCHAR group[64];
+ TCHAR name[64];
+ char dbSettingsGroup[32];
+ char setting[32];
+ DWORD flags;
+ TEffectSettings defeffect;
+ int order;
+
+ TEffectSettings value;
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// global data & functions
+
+typedef struct
+{
+ char *paramName;
+ TCHAR *groupName;
+}
+ TreeItem;
+
+extern OBJLIST<TFontID> font_id_list;
+extern OBJLIST<TColourID> colour_id_list;
+extern OBJLIST<TEffectID> effect_id_list;
+
+extern int code_page;
+extern HANDLE hFontReloadEvent, hColourReloadEvent;
+
+int CreateFromFontSettings(TFontSettings *fs, LOGFONT *lf );
diff --git a/src/modules/fonts/services.cpp b/src/modules/fonts/services.cpp
new file mode 100644
index 0000000000..3106060d8b
--- /dev/null
+++ b/src/modules/fonts/services.cpp
@@ -0,0 +1,534 @@
+/*
+
+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 "FontService.h"
+
+COLORREF GetColorFromDefault(COLORREF cl);
+
+#if defined( _UNICODE )
+void ConvertFontSettings( FontSettings* fs, TFontSettings* fsw)
+{
+ fsw->colour = fs->colour;
+ fsw->size = fs->size;
+ fsw->style = fs->style;
+ fsw->charset = fs->charset;
+
+ MultiByteToWideChar( code_page, 0, fs->szFace, -1, fsw->szFace, LF_FACESIZE);
+}
+
+void ConvertFontID( FontID *fid, TFontID* fidw )
+{
+ memset(fidw, 0, sizeof(TFontID));
+ fidw->cbSize = sizeof(TFontID);
+ strcpy(fidw->dbSettingsGroup, fid->dbSettingsGroup);
+ strcpy(fidw->prefix, fid->prefix);
+ fidw->flags = fid->flags;
+ fidw->order = fid->order;
+ ConvertFontSettings(&fid->deffontsettings, &fidw->deffontsettings);
+
+ MultiByteToWideChar( code_page, 0, fid->group, -1, fidw->group, 64);
+ MultiByteToWideChar( code_page, 0, fid->name, -1, fidw->name, 64);
+ if (fid->cbSize >= FontID_SIZEOF_V2A) {
+ MultiByteToWideChar( code_page, 0, fid->backgroundGroup, -1, fidw->backgroundGroup, 64);
+ MultiByteToWideChar( code_page, 0, fid->backgroundName, -1, fidw->backgroundName, 64);
+ }
+}
+
+void ConvertColourID(ColourID *cid, TColourID* cidw)
+{
+ cidw->cbSize = sizeof(TColourID);
+
+ strcpy(cidw->dbSettingsGroup, cid->dbSettingsGroup);
+ strcpy(cidw->setting, cid->setting);
+ cidw->flags = cid->flags;
+ cidw->defcolour = cid->defcolour;
+ cidw->order = cid->order;
+
+ MultiByteToWideChar( code_page, 0, cid->group, -1, cidw->group, 64);
+ MultiByteToWideChar( code_page, 0, cid->name, -1, cidw->name, 64);
+}
+
+void ConvertEffectID(EffectID *eid, TEffectID* eidw)
+{
+ eidw->cbSize = sizeof(TEffectID);
+
+ strcpy(eidw->dbSettingsGroup, eid->dbSettingsGroup);
+ strcpy(eidw->setting, eid->setting);
+ eidw->flags = eid->flags;
+ eidw->defeffect.effectIndex = eid->defeffect.effectIndex;
+ eidw->defeffect.baseColour = eid->defeffect.baseColour;
+ eidw->defeffect.secondaryColour = eid->defeffect.secondaryColour;
+ eidw->order = eid->order;
+
+ MultiByteToWideChar( code_page, 0, eid->group, -1, eidw->group, 64);
+ MultiByteToWideChar( code_page, 0, eid->name, -1, eidw->name, 64);
+}
+
+
+void ConvertLOGFONT(LOGFONTW *lfw, LOGFONTA *lfa)
+{
+ lfa->lfHeight = lfw->lfHeight;
+ lfa->lfWidth = lfw->lfWidth;
+ lfa->lfEscapement = lfw->lfEscapement;
+ lfa->lfOrientation = lfw->lfOrientation;
+ lfa->lfWeight = lfw->lfWeight;
+ lfa->lfItalic = lfw->lfItalic;
+ lfa->lfUnderline = lfw->lfUnderline;
+ lfa->lfStrikeOut = lfw->lfStrikeOut;
+ lfa->lfCharSet = lfw->lfCharSet;
+ lfa->lfOutPrecision = lfw->lfOutPrecision;
+ lfa->lfClipPrecision = lfw->lfClipPrecision;
+ lfa->lfQuality = lfw->lfQuality;
+ lfa->lfPitchAndFamily = lfw->lfPitchAndFamily;
+
+ WideCharToMultiByte( code_page, 0, lfw->lfFaceName, -1, lfa->lfFaceName, LF_FACESIZE, 0, 0);
+}
+#endif
+
+static void GetDefaultFontSetting(LOGFONT* lf, COLORREF* colour)
+{
+ SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), lf, FALSE);
+ if ( colour )
+ *colour = GetSysColor(COLOR_WINDOWTEXT);
+
+ lf->lfHeight = 10;
+
+ HDC hdc = GetDC(0);
+ lf->lfHeight = -MulDiv(lf->lfHeight,GetDeviceCaps(hdc, LOGPIXELSY), 72);
+ ReleaseDC(0, hdc);
+}
+
+int GetFontSettingFromDB(char *settings_group, char *prefix, LOGFONT* lf, COLORREF * colour, DWORD flags)
+{
+ DBVARIANT dbv;
+ char idstr[256];
+ BYTE style;
+ int retval = 0;
+
+ GetDefaultFontSetting(lf, colour);
+
+ if(flags & FIDF_APPENDNAME) mir_snprintf(idstr, SIZEOF(idstr), "%sName", prefix);
+ else mir_snprintf(idstr, SIZEOF(idstr), "%s", prefix);
+
+ if ( !DBGetContactSettingTString(NULL, settings_group, idstr, &dbv )) {
+ _tcscpy(lf->lfFaceName, dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ }
+ else retval = 1;
+
+ if (colour) {
+ mir_snprintf(idstr, SIZEOF(idstr), "%sCol", prefix);
+ *colour = DBGetContactSettingDword(NULL, settings_group, idstr, *colour);
+ }
+
+ mir_snprintf(idstr, SIZEOF(idstr), "%sSize", prefix);
+ lf->lfHeight = (char)DBGetContactSettingByte(NULL, settings_group, idstr, lf->lfHeight);
+
+
+ //wsprintf(idstr, "%sFlags", prefix);
+ //if(DBGetContactSettingDword(NULL, settings_group, idstr, 0) & FIDF_SAVEACTUALHEIGHT) {
+ // HDC hdc = GetDC(0);
+ // lf->lfHeight = -lf->lfHeight;
+ // ReleaseDC(0, hdc);
+ //}
+
+ mir_snprintf(idstr, SIZEOF(idstr), "%sSty", prefix);
+ style = (BYTE) DBGetContactSettingByte(NULL, settings_group, idstr,
+ (lf->lfWeight == FW_NORMAL ? 0 : DBFONTF_BOLD) | (lf->lfItalic ? DBFONTF_ITALIC : 0) | (lf->lfUnderline ? DBFONTF_UNDERLINE : 0) | lf->lfStrikeOut ? DBFONTF_STRIKEOUT : 0);
+
+ lf->lfWidth = lf->lfEscapement = lf->lfOrientation = 0;
+ lf->lfWeight = style & DBFONTF_BOLD ? FW_BOLD : FW_NORMAL;
+ lf->lfItalic = (style & DBFONTF_ITALIC) != 0;
+ lf->lfUnderline = (style & DBFONTF_UNDERLINE) != 0;
+ lf->lfStrikeOut = (style & DBFONTF_STRIKEOUT) != 0;
+
+ mir_snprintf(idstr, SIZEOF(idstr), "%sSet", prefix);
+ lf->lfCharSet = DBGetContactSettingByte(NULL, settings_group, idstr, lf->lfCharSet);
+
+ lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
+ lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ lf->lfQuality = DEFAULT_QUALITY;
+ lf->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+
+ if(lf->lfHeight > 0) {
+ HDC hdc = GetDC(0);
+ if(flags & FIDF_SAVEPOINTSIZE) {
+ lf->lfHeight = -MulDiv(lf->lfHeight,GetDeviceCaps(hdc, LOGPIXELSY), 72);
+ } else { // assume SAVEACTUALHEIGHT
+ TEXTMETRIC tm;
+ HFONT hFont = CreateFontIndirect(lf);
+ HFONT hOldFont = (HFONT)SelectObject(hdc, hFont);
+
+ GetTextMetrics(hdc, &tm);
+
+ lf->lfHeight = -(lf->lfHeight - tm.tmInternalLeading);
+
+ SelectObject(hdc, hOldFont);
+ DeleteObject(hFont);
+ }
+ //lf->lfHeight = -MulDiv(lf->lfHeight, GetDeviceCaps(hdc, LOGPIXELSY), 72);
+ ReleaseDC(0, hdc);
+ }
+
+ return retval;
+}
+
+int CreateFromFontSettings(TFontSettings* fs, LOGFONT* lf )
+{
+ GetDefaultFontSetting(lf, 0);
+
+ _tcscpy(lf->lfFaceName, fs->szFace);
+
+ lf->lfWidth = lf->lfEscapement = lf->lfOrientation = 0;
+ lf->lfWeight = fs->style & DBFONTF_BOLD ? FW_BOLD : FW_NORMAL;
+ lf->lfItalic = (fs->style & DBFONTF_ITALIC) != 0;
+ lf->lfUnderline = (fs->style & DBFONTF_UNDERLINE) != 0;
+ lf->lfStrikeOut = (fs->style & DBFONTF_STRIKEOUT) != 0;;
+ lf->lfCharSet = fs->charset;
+ lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
+ lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ lf->lfQuality = DEFAULT_QUALITY;
+ lf->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+
+ lf->lfHeight = fs->size;
+ return 0;
+}
+
+void UpdateFontSettings(TFontID* font_id, TFontSettings* fontsettings)
+{
+ LOGFONT lf;
+ COLORREF colour;
+ if ( GetFontSettingFromDB(font_id->dbSettingsGroup, font_id->prefix, &lf, &colour, font_id->flags) && (font_id->flags & FIDF_DEFAULTVALID)) {
+ CreateFromFontSettings(&font_id->deffontsettings, &lf );
+ colour = GetColorFromDefault(font_id->deffontsettings.colour);
+ }
+
+ fontsettings->style =
+ (lf.lfWeight == FW_NORMAL ? 0 : DBFONTF_BOLD) | (lf.lfItalic ? DBFONTF_ITALIC : 0) | (lf.lfUnderline ? DBFONTF_UNDERLINE : 0) | (lf.lfStrikeOut ? DBFONTF_STRIKEOUT : 0);
+
+ fontsettings->size = (char)lf.lfHeight;
+ fontsettings->charset = lf.lfCharSet;
+ fontsettings->colour = colour;
+ _tcscpy(fontsettings->szFace, lf.lfFaceName);
+}
+
+static COLORREF sttMixColor(COLORREF cl1, COLORREF cl2, int q)
+{
+ return RGB(
+ (GetRValue(cl1) * q + GetRValue(cl2) * (255 - q)) / 255,
+ (GetGValue(cl1) * q + GetGValue(cl2) * (255 - q)) / 255,
+ (GetBValue(cl1) * q + GetBValue(cl2) * (255 - q)) / 255
+ );
+}
+
+COLORREF GetColorFromDefault(COLORREF cl)
+{
+/*
+ if (cl & 0x80000000)
+ return GetSysColor(cl & 0x7fffffff);
+
+ if (cl & 0x40000000)
+ {
+ switch (cl)
+ {
+ case MIRCOLOR_BTNHALF: return sttMixColor(GetSysColor(COLOR_BTNFACE), GetSysColor(COLOR_BTNTEXT), 128);
+ case MIRCOLOR_WNDHALF: return sttMixColor(GetSysColor(COLOR_WINDOW), GetSysColor(COLOR_WINDOWTEXT), 128);
+ case MIRCOLOR_SELHALF: return sttMixColor(GetSysColor(COLOR_HIGHLIGHT), GetSysColor(COLOR_HIGHLIGHTTEXT), 128);
+ case MIRCOLOR_INBACK: return sttMixColor(GetSysColor(COLOR_WINDOW), RGB(0,0,255), 245);
+ case MIRCOLOR_INTEXT: return GetSysColor(COLOR_WINDOWTEXT);
+ case MIRCOLOR_INHALF: return sttMixColor(GetColorFromDefault(MIRCOLOR_INBACK), GetColorFromDefault(MIRCOLOR_INTEXT), 128);
+ case MIRCOLOR_OUTBACK: return sttMixColor(GetSysColor(COLOR_WINDOW), RGB(0,255,0), 245);
+ case MIRCOLOR_OUTTEXT: return GetSysColor(COLOR_WINDOWTEXT);
+ case MIRCOLOR_OUTHALF: return sttMixColor(GetColorFromDefault(MIRCOLOR_OUTBACK), GetColorFromDefault(MIRCOLOR_OUTTEXT), 128);
+ }
+ }
+*/
+ return cl;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// RegisterFont service
+
+static int sttRegisterFontWorker( TFontID* font_id )
+{
+ for ( int i = 0; i < font_id_list.getCount(); i++ ) {
+ TFontID& F = font_id_list[i];
+ if ( !lstrcmp( F.group, font_id->group ) && !lstrcmp( F.name, font_id->name ) && !( F.flags & FIDF_ALLOWREREGISTER ))
+ return 1;
+ }
+
+ char idstr[256];
+ mir_snprintf(idstr, SIZEOF(idstr), "%sFlags", font_id->prefix);
+ DBWriteContactSettingDword(0, font_id->dbSettingsGroup, idstr, font_id->flags);
+ {
+ TFontID* newItem = new TFontID;
+ memset( newItem, 0, sizeof( TFontID ));
+ memcpy( newItem, font_id, font_id->cbSize);
+
+ if (!lstrcmp(newItem->deffontsettings.szFace, _T("MS Shell Dlg")))
+ {
+ LOGFONT lf;
+ SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &lf, FALSE);
+ lstrcpyn(newItem->deffontsettings.szFace, lf.lfFaceName, SIZEOF(newItem->deffontsettings.szFace));
+ if (!newItem->deffontsettings.size)
+ newItem->deffontsettings.size = lf.lfHeight;
+ }
+
+ UpdateFontSettings( font_id, &newItem->value );
+ font_id_list.insert( newItem );
+ }
+ return 0;
+}
+
+#if defined( _UNICODE )
+INT_PTR RegisterFontW(WPARAM wParam, LPARAM )
+{
+ return sttRegisterFontWorker(( TFontID* )wParam );
+}
+#endif
+
+INT_PTR RegisterFont(WPARAM wParam, LPARAM)
+{
+ #if defined( _UNICODE )
+ TFontID temp;
+ ConvertFontID( ( FontID* )wParam, &temp );
+ return sttRegisterFontWorker( &temp );
+ #else
+ return sttRegisterFontWorker(( TFontID* )wParam );
+ #endif
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// GetFont service
+
+static int sttGetFontWorker( TFontID* font_id, LOGFONT* lf )
+{
+ COLORREF colour;
+
+ for ( int i = 0; i < font_id_list.getCount(); i++ ) {
+ TFontID& F = font_id_list[i];
+ if ( !_tcsncmp( F.name, font_id->name, SIZEOF(F.name)) && !_tcsncmp( F.group, font_id->group, SIZEOF(F.group))) {
+ if ( GetFontSettingFromDB( F.dbSettingsGroup, F.prefix, lf, &colour, F.flags) && ( F.flags & FIDF_DEFAULTVALID )) {
+ CreateFromFontSettings( &F.deffontsettings, lf );
+ colour = GetColorFromDefault(F.deffontsettings.colour);
+ }
+
+ return (int)colour;
+ } }
+
+ GetDefaultFontSetting( lf, &colour );
+ return (int)colour;
+}
+
+#if defined( _UNICODE )
+INT_PTR GetFontW(WPARAM wParam, LPARAM lParam)
+{
+ return sttGetFontWorker(( TFontID* )wParam, ( LOGFONT* )lParam );
+}
+#endif
+
+INT_PTR GetFont(WPARAM wParam, LPARAM lParam)
+{
+ #if defined( _UNICODE )
+ TFontID temp;
+ LOGFONT lftemp;
+ ConvertFontID((FontID *)wParam, &temp);
+ { int ret = sttGetFontWorker( &temp, &lftemp );
+ ConvertLOGFONT( &lftemp, ( LOGFONTA* )lParam );
+ return ret;
+ }
+ #else
+ return sttGetFontWorker(( TFontID* )wParam, ( LOGFONT* )lParam );
+ #endif
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// RegisterColour service
+
+void UpdateColourSettings( TColourID* colour_id, COLORREF *colour)
+{
+ *colour = ( COLORREF )DBGetContactSettingDword(NULL, colour_id->dbSettingsGroup, colour_id->setting, GetColorFromDefault(colour_id->defcolour) );
+}
+
+static int sttRegisterColourWorker( TColourID* colour_id )
+{
+ for ( int i = 0; i < colour_id_list.getCount(); i++ ) {
+ TColourID& C = colour_id_list[i];
+ if ( !_tcscmp( C.group, colour_id->group ) && !_tcscmp( C.name, colour_id->name ))
+ return 1;
+ }
+
+ TColourID* newItem = new TColourID;
+ memcpy( newItem, colour_id, sizeof( TColourID ));
+ UpdateColourSettings( colour_id, &newItem->value );
+ colour_id_list.insert( newItem );
+ return 0;
+}
+
+#if defined( _UNICODE )
+INT_PTR RegisterColourW(WPARAM wParam, LPARAM)
+{
+ return sttRegisterColourWorker(( TColourID* )wParam );
+}
+#endif
+
+INT_PTR RegisterColour(WPARAM wParam, LPARAM)
+{
+ #if defined( _UNICODE )
+ TColourID temp;
+ ConvertColourID(( ColourID* )wParam, &temp );
+ return sttRegisterColourWorker( &temp );
+ #else
+ return sttRegisterColourWorker(( TColourID* )wParam );
+ #endif
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// GetColour service
+
+static int sttGetColourWorker( TColourID* colour_id )
+{
+ int i;
+
+ for ( i = 0; i < colour_id_list.getCount(); i++ ) {
+ TColourID& C = colour_id_list[i];
+ if ( !_tcscmp( C.group, colour_id->group ) && !_tcscmp( C.name, colour_id->name ))
+ return (int)DBGetContactSettingDword(NULL, C.dbSettingsGroup, C.setting, GetColorFromDefault(C.defcolour));
+ }
+
+ return -1;
+}
+
+#if defined( _UNICODE )
+INT_PTR GetColourW(WPARAM wParam, LPARAM)
+{
+ return sttGetColourWorker(( TColourID* )wParam );
+}
+#endif
+
+INT_PTR GetColour(WPARAM wParam, LPARAM)
+{
+ #if defined( _UNICODE )
+ TColourID temp;
+ ConvertColourID(( ColourID* )wParam, &temp );
+ return sttGetColourWorker( &temp );
+ #else
+ return sttGetColourWorker(( TColourID* )wParam );
+ #endif
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+// Effects
+
+void UpdateEffectSettings(TEffectID* effect_id, TEffectSettings* effectsettings)
+{
+ char str[256];
+
+ mir_snprintf(str, SIZEOF(str), "%sEffect", effect_id->setting);
+ effectsettings->effectIndex = DBGetContactSettingByte(NULL, effect_id->dbSettingsGroup, str, effect_id->defeffect.effectIndex);
+
+ mir_snprintf(str, SIZEOF(str), "%sEffectCol1", effect_id->setting);
+ effectsettings->baseColour = DBGetContactSettingDword(NULL, effect_id->dbSettingsGroup, str, effect_id->defeffect.baseColour);
+
+ mir_snprintf(str, SIZEOF(str), "%sEffectCol2", effect_id->setting);
+ effectsettings->secondaryColour = DBGetContactSettingDword(NULL, effect_id->dbSettingsGroup, str, effect_id->defeffect.secondaryColour);
+
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// RegisterFont service
+
+static int sttRegisterEffectWorker( TEffectID* effect_id )
+{
+ for ( int i = 0; i < effect_id_list.getCount(); i++ ) {
+ TEffectID& E = effect_id_list[i];
+ if ( !_tcscmp( E.group, effect_id->group ) && !_tcscmp( E.name, effect_id->name ))
+ return 1;
+ }
+
+ TEffectID* newItem = new TEffectID;
+ memcpy( newItem, effect_id, sizeof( TEffectID ));
+ UpdateEffectSettings( effect_id, &newItem->value );
+ effect_id_list.insert( newItem );
+ return 0;
+}
+
+#if defined( _UNICODE )
+INT_PTR RegisterEffectW(WPARAM wParam, LPARAM lParam)
+{
+ return sttRegisterEffectWorker(( TEffectID* )wParam );
+}
+#endif
+
+INT_PTR RegisterEffect(WPARAM wParam, LPARAM lParam)
+{
+#if defined( _UNICODE )
+ TEffectID temp;
+ ConvertEffectID( ( EffectID* )wParam, &temp );
+ return sttRegisterEffectWorker( &temp );
+#else
+ return sttRegisterEffectWorker(( TEffectID* )wParam );
+#endif
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// GetEffect service
+
+static int sttGetEffectWorker( TEffectID* effect_id, FONTEFFECT* effect )
+{
+ for ( int i = 0; i < effect_id_list.getCount(); i++ ) {
+ TEffectID& E = effect_id_list[i];
+ if ( !_tcsncmp( E.name, effect_id->name, SIZEOF(E.name)) && !_tcsncmp( E.group, effect_id->group, SIZEOF(E.group)))
+ {
+ TEffectSettings temp;
+ UpdateEffectSettings( effect_id, &temp );
+
+ effect->effectIndex = temp.effectIndex;
+ effect->baseColour = temp.baseColour;
+ effect->secondaryColour = temp.secondaryColour;
+
+ return (int) TRUE;
+ } }
+
+ return (int)FALSE;
+}
+
+#if defined( _UNICODE )
+INT_PTR GetEffectW(WPARAM wParam, LPARAM lParam)
+{
+ return sttGetEffectWorker(( TEffectID* )wParam, ( FONTEFFECT* )lParam );
+}
+#endif
+
+INT_PTR GetEffect(WPARAM wParam, LPARAM lParam)
+{
+#if defined( _UNICODE )
+ TEffectID temp;
+ ConvertEffectID((EffectID *)wParam, &temp);
+ return sttGetEffectWorker( &temp, ( FONTEFFECT* )lParam );
+#else
+ return sttGetEffectWorker(( TEffectID* )wParam, ( FONTEFFECT* )lParam );
+#endif
+}
diff --git a/src/modules/help/about.cpp b/src/modules/help/about.cpp
new file mode 100644
index 0000000000..37c949260a
--- /dev/null
+++ b/src/modules/help/about.cpp
@@ -0,0 +1,148 @@
+/*
+
+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"
+
+#if defined( _UNICODE )
+ #define STR_VERSION_FORMAT "%s%S%S"
+#else
+ #define STR_VERSION_FORMAT "%s%s%s"
+#endif
+
+INT_PTR CALLBACK DlgProcAbout(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static int iState = 0;
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ { TCHAR filename[MAX_PATH], *productCopyright;
+ DWORD unused;
+ DWORD verInfoSize;
+ UINT blockSize;
+ PVOID pVerInfo;
+
+ GetModuleFileName(NULL,filename,SIZEOF(filename));
+ verInfoSize=GetFileVersionInfoSize(filename,&unused);
+ pVerInfo=mir_alloc(verInfoSize);
+ GetFileVersionInfo(filename,0,verInfoSize,pVerInfo);
+ VerQueryValue(pVerInfo,_T("\\StringFileInfo\\000004b0\\LegalCopyright"),(LPVOID*)&productCopyright,&blockSize);
+ SetDlgItemText(hwndDlg,IDC_DEVS,productCopyright);
+ mir_free(pVerInfo);
+ }
+ { char productVersion[56], *p;
+ int isAnsi = 0;
+ TCHAR str[64];
+ CallService(MS_SYSTEM_GETVERSIONTEXT,SIZEOF(productVersion),(LPARAM)productVersion);
+ // Hide Unicode from version text as it is assumed at this point
+ p = strstr(productVersion, " Unicode");
+ if (p)
+ *p = '\0';
+ else
+ isAnsi = 1;
+ mir_sntprintf(str,SIZEOF(str),_T(STR_VERSION_FORMAT), TranslateT("v"), productVersion, isAnsi?" ANSI":"");
+ {
+ TCHAR oldTitle[256], newTitle[256];
+ GetDlgItemText( hwndDlg, IDC_HEADERBAR, oldTitle, SIZEOF( oldTitle ));
+ mir_sntprintf( newTitle, SIZEOF(newTitle), oldTitle, str );
+ SetDlgItemText( hwndDlg, IDC_HEADERBAR, newTitle );
+ }
+
+ mir_sntprintf(str,SIZEOF(str),TranslateT("Built %s %s"),_T(__DATE__),_T(__TIME__));
+ SetDlgItemText(hwndDlg,IDC_BUILDTIME,str);
+ }
+ ShowWindow(GetDlgItem(hwndDlg, IDC_CREDITSFILE), SW_HIDE);
+ {
+ HRSRC hResInfo = FindResource(hMirandaInst,MAKEINTRESOURCE(IDR_CREDITS),_T("TEXT"));
+ DWORD ResSize = SizeofResource(hMirandaInst,hResInfo);
+ HGLOBAL hRes = LoadResource(hMirandaInst,hResInfo);
+ char* pszMsg = (char*)LockResource(hRes);
+ if (pszMsg)
+ {
+ char* pszMsgt = (char*)alloca(ResSize + 1);
+ memcpy(pszMsgt, pszMsg, ResSize); pszMsgt[ResSize] = 0;
+
+ TCHAR *ptszMsg;
+ if (ResSize >=3 && pszMsgt[0] == '\xef' && pszMsgt[1] == '\xbb' && pszMsgt[2] == '\xbf')
+ ptszMsg = Utf8DecodeT(pszMsgt + 3);
+ else
+ ptszMsg = mir_a2t_cp(pszMsgt, 1252);
+
+ SetDlgItemText(hwndDlg, IDC_CREDITSFILE, ptszMsg);
+ UnlockResource(pszMsg);
+ mir_free(ptszMsg);
+ }
+ FreeResource(hRes);
+ }
+ Window_SetIcon_IcoLib(hwndDlg, SKINICON_OTHER_MIRANDA);
+ return TRUE;
+
+ case WM_COMMAND:
+ switch( LOWORD( wParam )) {
+ case IDOK:
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ return TRUE;
+ case IDC_CONTRIBLINK:
+ if (iState) {
+ iState = 0;
+ SetDlgItemText(hwndDlg, IDC_CONTRIBLINK, TranslateT("Credits >"));
+ ShowWindow(GetDlgItem(hwndDlg, IDC_DEVS), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_BUILDTIME), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_CREDITSFILE), SW_HIDE);
+ }
+ else {
+ iState = 1;
+ SetDlgItemText(hwndDlg, IDC_CONTRIBLINK, TranslateT("< Copyright"));
+ ShowWindow(GetDlgItem(hwndDlg, IDC_DEVS), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_BUILDTIME), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_CREDITSFILE), SW_SHOW);
+ }
+ break;
+ }
+ break;
+
+ case WM_CTLCOLOREDIT:
+ case WM_CTLCOLORSTATIC:
+ switch ( GetWindowLongPtr(( HWND )lParam, GWL_ID )) {
+ case IDC_WHITERECT:
+ case IDC_BUILDTIME:
+ case IDC_CREDITSFILE:
+ case IDC_DEVS:
+ SetTextColor((HDC)wParam,GetSysColor(COLOR_WINDOWTEXT));
+ break;
+ default:
+ return FALSE;
+ }
+ SetBkColor((HDC)wParam, GetSysColor(COLOR_WINDOW));
+ return (INT_PTR)GetSysColorBrush(COLOR_WINDOW);
+
+ case WM_DESTROY:
+ Window_FreeIcon_IcoLib( hwndDlg );
+ {
+ HFONT hFont=(HFONT)SendDlgItemMessage(hwndDlg,IDC_VERSION,WM_GETFONT,0,0);
+ SendDlgItemMessage(hwndDlg,IDC_VERSION,WM_SETFONT,SendDlgItemMessage(hwndDlg,IDOK,WM_GETFONT,0,0),0);
+ DeleteObject(hFont);
+ }
+ break;
+ }
+ return FALSE;
+}
diff --git a/src/modules/help/help.cpp b/src/modules/help/help.cpp
new file mode 100644
index 0000000000..432049e2d1
--- /dev/null
+++ b/src/modules/help/help.cpp
@@ -0,0 +1,117 @@
+/*
+
+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_PTR CALLBACK DlgProcAbout(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+HWND hAboutDlg=NULL;
+static HANDLE hBugEvent = NULL;
+
+static INT_PTR AboutCommand(WPARAM wParam,LPARAM)
+{
+ if (IsWindow(hAboutDlg)) {
+ SetForegroundWindow(hAboutDlg);
+ SetFocus(hAboutDlg);
+ return 0;
+ }
+ hAboutDlg=CreateDialog(hMirandaInst,MAKEINTRESOURCE(IDD_ABOUT),(HWND)wParam,DlgProcAbout);
+ return 0;
+}
+
+static INT_PTR IndexCommand(WPARAM, LPARAM)
+{
+ CallService(MS_UTILS_OPENURL,1,(LPARAM)Translate("http://wiki.miranda-im.org/"));
+ return 0;
+}
+
+static INT_PTR WebsiteCommand(WPARAM, LPARAM)
+{
+ CallService(MS_UTILS_OPENURL,1,(LPARAM)"http://www.miranda-im.org");
+ return 0;
+}
+
+static int BugCommandEvent(WPARAM wParam, LPARAM lParam) {
+ char *szUrl = (char*)lParam;
+
+ if (szUrl) {
+ CallService(MS_UTILS_OPENURL,1,(LPARAM)szUrl);
+ }
+ return 0;
+}
+
+static INT_PTR BugCommand(WPARAM, LPARAM)
+{
+ NotifyEventHooks(hBugEvent, 0, (LPARAM)"http://code.google.com/p/miranda/issues/list");
+ return 0;
+}
+
+
+int ShutdownHelpModule(WPARAM, LPARAM)
+{
+ if (IsWindow(hAboutDlg)) DestroyWindow(hAboutDlg);
+ hAboutDlg=NULL;
+ return 0;
+}
+
+int LoadHelpModule(void)
+{
+ HookEvent(ME_SYSTEM_PRESHUTDOWN,ShutdownHelpModule);
+
+ CreateServiceFunction("Help/AboutCommand",AboutCommand);
+ CreateServiceFunction("Help/IndexCommand",IndexCommand);
+ CreateServiceFunction("Help/WebsiteCommand",WebsiteCommand);
+ CreateServiceFunction("Help/BugCommand",BugCommand);
+
+ hBugEvent = CreateHookableEvent(ME_HELP_BUGREPORT);
+ SetHookDefaultForHookableEvent(hBugEvent, BugCommandEvent);
+
+ CLISTMENUITEM mi = { 0 };
+ mi.cbSize = sizeof(mi);
+ mi.flags = CMIF_ICONFROMICOLIB;
+ mi.icolibItem = GetSkinIconHandle(SKINICON_OTHER_MIRANDA);
+ mi.pszPopupName = LPGEN("&Help");
+ mi.popupPosition = 2000090000;
+ mi.position = 2000090000;
+ mi.pszName = LPGEN("&About...");
+ mi.pszService = "Help/AboutCommand";
+ CallService(MS_CLIST_ADDMAINMENUITEM,0,(LPARAM)&mi);
+
+ mi.icolibItem = GetSkinIconHandle(SKINICON_OTHER_HELP);
+ mi.position = -500050000;
+ mi.pszName = LPGEN("&Support");
+ mi.pszService = "Help/IndexCommand";
+ CallService(MS_CLIST_ADDMAINMENUITEM,0,(LPARAM)&mi);
+
+ mi.icolibItem = GetSkinIconHandle(SKINICON_OTHER_MIRANDAWEB);
+ mi.position = 2000050000;
+ mi.pszName = LPGEN("&Miranda IM Homepage");
+ mi.pszService = "Help/WebsiteCommand";
+ CallService(MS_CLIST_ADDMAINMENUITEM,0,(LPARAM)&mi);
+
+ mi.icolibItem = GetSkinIconHandle(SKINICON_EVENT_URL);
+ mi.position = 2000040000;
+ mi.pszName = LPGEN("&Report Bug");
+ mi.pszService = "Help/BugCommand";
+ CallService(MS_CLIST_ADDMAINMENUITEM,0,(LPARAM)&mi);
+ return 0;
+}
diff --git a/src/modules/history/history.cpp b/src/modules/history/history.cpp
new file mode 100644
index 0000000000..3b6b805a7f
--- /dev/null
+++ b/src/modules/history/history.cpp
@@ -0,0 +1,434 @@
+/*
+
+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 SUMMARY 0
+#define DETAIL 1
+#define DM_FINDNEXT (WM_USER+10)
+#define DM_HREBUILD (WM_USER+11)
+
+static INT_PTR CALLBACK DlgProcHistory(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+static INT_PTR CALLBACK DlgProcHistoryFind(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+static HANDLE hWindowList=0;
+
+static INT_PTR UserHistoryCommand(WPARAM wParam, LPARAM)
+{
+ HWND hwnd = WindowList_Find( hWindowList,( HANDLE )wParam );
+ if ( hwnd ) {
+ SetForegroundWindow(hwnd);
+ SetFocus(hwnd);
+ return 0;
+ }
+ CreateDialogParam(hMirandaInst,MAKEINTRESOURCE(IDD_HISTORY),NULL,DlgProcHistory,wParam);
+ return 0;
+}
+
+static int HistoryContactDelete(WPARAM wParam, LPARAM)
+{
+ HWND hwnd = WindowList_Find(hWindowList,(HANDLE)wParam);
+ if ( hwnd != NULL )
+ DestroyWindow(hwnd);
+ return 0;
+}
+
+int PreShutdownHistoryModule(WPARAM, LPARAM)
+{
+ if (hWindowList)
+ WindowList_BroadcastAsync(hWindowList,WM_DESTROY,0,0);
+ return 0;
+}
+
+int LoadHistoryModule(void)
+{
+ CLISTMENUITEM mi = { 0 };
+ mi.cbSize = sizeof(mi);
+ mi.position = 1000090000;
+ mi.flags = CMIF_ICONFROMICOLIB;
+ mi.icolibItem = GetSkinIconHandle( SKINICON_OTHER_HISTORY );
+ mi.pszName = LPGEN("View &History");
+ mi.pszService = MS_HISTORY_SHOWCONTACTHISTORY;
+ CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&mi);
+
+ CreateServiceFunction(MS_HISTORY_SHOWCONTACTHISTORY,UserHistoryCommand);
+ hWindowList=(HANDLE)CallService(MS_UTILS_ALLOCWINDOWLIST,0,0);
+ HookEvent(ME_DB_CONTACT_DELETED,HistoryContactDelete);
+ HookEvent(ME_SYSTEM_PRESHUTDOWN,PreShutdownHistoryModule);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Fills the events list
+
+static void GetMessageDescription( DBEVENTINFO *dbei, TCHAR* buf, int cbBuf )
+{
+ TCHAR* msg = DbGetEventTextT( dbei, CP_ACP );
+ _tcsncpy( buf, msg ? msg : TranslateT("Invalid Message"), cbBuf );
+ buf[ cbBuf-1 ] = 0;
+ mir_free( msg );
+}
+
+static void GetUrlDescription( DBEVENTINFO *dbei, TCHAR* buf, int cbBuf )
+{
+ int len = dbei->cbBlob;
+ if ( len >= cbBuf )
+ len = cbBuf-1;
+
+ #if !defined( _UNICODE )
+ memcpy( buf, dbei->pBlob, len );
+ #else
+ MultiByteToWideChar( CP_ACP, 0, ( LPCSTR )dbei->pBlob, len, buf, cbBuf );
+ #endif
+ buf[ len ] = 0;
+
+ if ( len < cbBuf-3 )
+ _tcscat( buf, _T( "\r\n" ));
+}
+
+static void GetFileDescription( DBEVENTINFO *dbei, TCHAR* buf, int cbBuf )
+{
+ int len = dbei->cbBlob - sizeof( DWORD );
+ if ( len >= cbBuf )
+ len = cbBuf-1;
+
+ #if !defined( _UNICODE )
+ memcpy( buf, dbei->pBlob + sizeof( DWORD ), len );
+ #else
+ MultiByteToWideChar( CP_ACP, 0, ( LPCSTR )dbei->pBlob + sizeof( DWORD ), len, buf, cbBuf );
+ #endif
+ buf[ len ] = 0;
+
+ if ( len < cbBuf-3 )
+ _tcscat( buf, _T( "\r\n" ));
+}
+
+static void GetObjectDescription( DBEVENTINFO *dbei, TCHAR* str, int cbStr )
+{
+ switch( dbei->eventType ) {
+ case EVENTTYPE_MESSAGE:
+ GetMessageDescription( dbei, str, cbStr );
+ break;
+
+ case EVENTTYPE_URL:
+ GetUrlDescription( dbei, str, cbStr );
+ break;
+
+ case EVENTTYPE_FILE:
+ GetFileDescription( dbei, str, cbStr );
+ break;
+
+ default:
+ {
+ DBEVENTTYPEDESCR* et = ( DBEVENTTYPEDESCR* )CallService( MS_DB_EVENT_GETTYPE, ( WPARAM )dbei->szModule, ( LPARAM )dbei->eventType );
+ if ( et && ( et->flags & DETF_HISTORY )) {
+ GetMessageDescription( dbei, str, cbStr );
+ }
+ else
+ str[ 0 ] = 0;
+} } }
+
+static void GetObjectSummary( DBEVENTINFO *dbei, TCHAR* str, int cbStr )
+{
+ TCHAR* pszSrc, *pszTmp = NULL;
+
+ switch( dbei->eventType ) {
+ case EVENTTYPE_MESSAGE:
+ if ( dbei->flags & DBEF_SENT ) pszSrc = TranslateT( "Outgoing Message" );
+ else pszSrc = TranslateT( "Incoming Message" );
+ break;
+
+ case EVENTTYPE_URL:
+ if ( dbei->flags & DBEF_SENT ) pszSrc = TranslateT( "Outgoing URL" );
+ else pszSrc = TranslateT( "Incoming URL" );
+ break;
+
+ case EVENTTYPE_FILE:
+ if ( dbei->flags & DBEF_SENT ) pszSrc = TranslateT( "Outgoing File" );
+ else pszSrc = TranslateT( "Incoming File" );
+ break;
+
+ default:
+ {
+ DBEVENTTYPEDESCR* et = ( DBEVENTTYPEDESCR* )CallService( MS_DB_EVENT_GETTYPE, ( WPARAM )dbei->szModule, ( LPARAM )dbei->eventType );
+ if ( et && ( et->flags & DETF_HISTORY )) {
+ pszTmp = mir_a2t( et->descr );
+ pszSrc = TranslateTS( pszTmp );
+ break;
+ }
+ else {
+ str[ 0 ] = 0;
+ return;
+ } } }
+
+ _tcsncpy( str, ( const TCHAR* )pszSrc, cbStr );
+ str[ cbStr-1 ] = 0;
+
+ mir_free( pszTmp );
+}
+
+typedef struct {
+ HANDLE hContact;
+ HWND hwnd;
+} THistoryThread;
+
+static void FillHistoryThread(void* param)
+{
+ TCHAR str[200], eventText[256], strdatetime[64];
+ HANDLE hDbEvent;
+ DBEVENTINFO dbei;
+ int newBlobSize,oldBlobSize,i;
+ HWND hwndList;
+ THistoryThread *hInfo = ( THistoryThread* )param;
+
+ SendDlgItemMessage(hInfo->hwnd,IDC_LIST,LB_RESETCONTENT,0,0);
+ i=CallService(MS_DB_EVENT_GETCOUNT,(WPARAM)hInfo->hContact,0);
+ SendDlgItemMessage(hInfo->hwnd,IDC_LIST,LB_INITSTORAGE,i,i*40);
+
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ oldBlobSize=0;
+ hDbEvent=(HANDLE)CallService(MS_DB_EVENT_FINDLAST,(WPARAM)hInfo->hContact,0);
+ hwndList = GetDlgItem(hInfo->hwnd,IDC_LIST);
+ while ( hDbEvent != NULL ) {
+ if ( !IsWindow( hInfo->hwnd ))
+ break;
+ newBlobSize=CallService(MS_DB_EVENT_GETBLOBSIZE,(WPARAM)hDbEvent,0);
+ if(newBlobSize>oldBlobSize) {
+ dbei.pBlob=(PBYTE)mir_realloc(dbei.pBlob,newBlobSize);
+ oldBlobSize=newBlobSize;
+ }
+ dbei.cbBlob = oldBlobSize;
+ CallService( MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM)&dbei );
+ GetObjectSummary(&dbei,str,SIZEOF(str));
+ if(str[0]) {
+ tmi.printTimeStamp(NULL, dbei.timestamp, _T("d t"), strdatetime, SIZEOF(strdatetime), 0);
+ mir_sntprintf( eventText, SIZEOF(eventText), _T("%s: %s"), strdatetime, str );
+ i = SendMessage(hwndList, LB_ADDSTRING, 0, (LPARAM)eventText );
+ SendMessage(hwndList, LB_SETITEMDATA, i, (LPARAM)hDbEvent);
+ }
+ hDbEvent=(HANDLE)CallService(MS_DB_EVENT_FINDPREV,(WPARAM)hDbEvent,0);
+ }
+ mir_free(dbei.pBlob);
+
+ SendDlgItemMessage(hInfo->hwnd,IDC_LIST,LB_SETCURSEL,0,0);
+ SendMessage(hInfo->hwnd,WM_COMMAND,MAKEWPARAM(IDC_LIST,LBN_SELCHANGE),0);
+ EnableWindow(GetDlgItem(hInfo->hwnd, IDC_LIST), TRUE);
+ mir_free(hInfo);
+}
+
+static int HistoryDlgResizer(HWND, LPARAM, UTILRESIZECONTROL *urc)
+{
+ switch(urc->wId) {
+ case IDC_LIST:
+ return RD_ANCHORX_WIDTH|RD_ANCHORY_HEIGHT;
+ case IDC_EDIT:
+ return RD_ANCHORX_WIDTH|RD_ANCHORY_BOTTOM;
+ case IDC_FIND:
+ case IDC_DELETEHISTORY:
+ return RD_ANCHORX_LEFT|RD_ANCHORY_BOTTOM;
+ case IDOK:
+ return RD_ANCHORX_RIGHT|RD_ANCHORY_BOTTOM;
+ }
+ return RD_ANCHORX_LEFT|RD_ANCHORY_TOP;
+}
+
+static INT_PTR CALLBACK DlgProcHistory(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ HANDLE hContact;
+
+ hContact=(HANDLE)GetWindowLongPtr(hwndDlg,GWLP_USERDATA);
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ SetWindowLongPtr(hwndDlg,GWLP_USERDATA,(LONG_PTR)lParam);
+ hContact = (HANDLE)lParam;
+ WindowList_Add(hWindowList,hwndDlg,hContact);
+ Utils_RestoreWindowPosition(hwndDlg,hContact,"History","");
+ {
+ TCHAR* contactName, str[200];
+ contactName = cli.pfnGetContactDisplayName( hContact, 0 );
+ mir_sntprintf(str,SIZEOF(str),TranslateT("History for %s"),contactName);
+ SetWindowText(hwndDlg,str);
+ }
+ Window_SetIcon_IcoLib(hwndDlg, SKINICON_OTHER_HISTORY);
+ SendMessage(hwndDlg,DM_HREBUILD,0,0);
+ return TRUE;
+
+ case DM_HREBUILD:
+ {
+ THistoryThread* hInfo = (THistoryThread*)mir_alloc(sizeof(THistoryThread));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_LIST), FALSE);
+ hInfo->hContact = hContact;
+ hInfo->hwnd = hwndDlg;
+ forkthread(FillHistoryThread, 0, hInfo);
+ }
+ return TRUE;
+
+ case WM_DESTROY:
+ Window_FreeIcon_IcoLib(hwndDlg);
+ Utils_SaveWindowPosition(hwndDlg,hContact,"History","");
+ WindowList_Remove(hWindowList,hwndDlg);
+ return TRUE;
+
+ case WM_GETMINMAXINFO:
+ ((MINMAXINFO*)lParam)->ptMinTrackSize.x=300;
+ ((MINMAXINFO*)lParam)->ptMinTrackSize.y=230;
+
+ case WM_SIZE:
+ {
+ UTILRESIZEDIALOG urd={0};
+ urd.cbSize=sizeof(urd);
+ urd.hwndDlg=hwndDlg;
+ urd.hInstance=hMirandaInst;
+ urd.lpTemplate=MAKEINTRESOURCEA(IDD_HISTORY);
+ urd.lParam=(LPARAM)NULL;
+ urd.pfnResizer=HistoryDlgResizer;
+ CallService(MS_UTILS_RESIZEDIALOG,0,(LPARAM)&urd);
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDOK:
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ return TRUE;
+
+ case IDC_FIND:
+ ShowWindow(CreateDialogParam(hMirandaInst, MAKEINTRESOURCE(IDD_HISTORY_FIND), hwndDlg, DlgProcHistoryFind, (LPARAM)hwndDlg), SW_SHOW);
+ return TRUE;
+
+ case IDC_DELETEHISTORY:
+ {
+ HANDLE hDbevent;
+ int index = SendDlgItemMessage(hwndDlg,IDC_LIST,LB_GETCURSEL,0,0);
+ if ( index == LB_ERR )
+ break;
+
+ if ( MessageBox(hwndDlg,TranslateT("Are you sure you want to delete this history item?"),TranslateT("Delete History"),MB_YESNO|MB_ICONQUESTION)==IDYES) {
+ hDbevent = (HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,LB_GETITEMDATA,index,0);
+ CallService(MS_DB_EVENT_DELETE,(WPARAM)hContact,(LPARAM)hDbevent);
+ SendMessage(hwndDlg,DM_HREBUILD,0,0);
+ }
+ return TRUE;
+ }
+ case IDC_LIST:
+ if ( HIWORD(wParam) == LBN_SELCHANGE ) {
+ TCHAR str[8192],*contactName;
+ HANDLE hDbEvent;
+ DBEVENTINFO dbei;
+ int sel;
+ sel=SendDlgItemMessage(hwndDlg,IDC_LIST,LB_GETCURSEL,0,0);
+ if(sel==LB_ERR) { EnableWindow(GetDlgItem(hwndDlg,IDC_DELETEHISTORY),FALSE); break; }
+ EnableWindow(GetDlgItem(hwndDlg,IDC_DELETEHISTORY),TRUE);
+ contactName = cli.pfnGetContactDisplayName( hContact, 0 );
+ hDbEvent=(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,LB_GETITEMDATA,sel,0);
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.cbBlob=CallService(MS_DB_EVENT_GETBLOBSIZE,(WPARAM)hDbEvent,0);
+ if ((int)dbei.cbBlob != -1)
+ {
+ dbei.pBlob=(PBYTE)mir_alloc(dbei.cbBlob);
+ if (CallService(MS_DB_EVENT_GET,(WPARAM)hDbEvent,(LPARAM)&dbei) == 0)
+ {
+ GetObjectDescription(&dbei,str,SIZEOF(str));
+ if ( str[0] )
+ SetDlgItemText(hwndDlg, IDC_EDIT, str);
+ }
+ mir_free(dbei.pBlob);
+ }
+ }
+ return TRUE;
+ }
+ break;
+ case DM_FINDNEXT:
+ {
+ TCHAR str[1024];
+ HANDLE hDbEvent,hDbEventStart;
+ DBEVENTINFO dbei;
+ int newBlobSize,oldBlobSize;
+
+ int index = SendDlgItemMessage(hwndDlg,IDC_LIST,LB_GETCURSEL,0,0);
+ if ( index == LB_ERR )
+ break;
+
+ hDbEventStart=(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,LB_GETITEMDATA,index,0);
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.pBlob=NULL;
+ oldBlobSize=0;
+ for(;;) {
+ hDbEvent = (HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,LB_GETITEMDATA,++index,0);
+ if(hDbEvent == ( HANDLE )LB_ERR) {
+ index = -1;
+ continue;
+ }
+ if(hDbEvent==hDbEventStart) break;
+ newBlobSize=CallService(MS_DB_EVENT_GETBLOBSIZE,(WPARAM)hDbEvent,0);
+ if(newBlobSize>oldBlobSize) {
+ dbei.pBlob=(PBYTE)mir_realloc(dbei.pBlob,newBlobSize);
+ oldBlobSize=newBlobSize;
+ }
+ dbei.cbBlob=oldBlobSize;
+ CallService(MS_DB_EVENT_GET,(WPARAM)hDbEvent,(LPARAM)&dbei);
+ GetObjectDescription(&dbei,str,SIZEOF(str));
+ if(str[0]) {
+ CharUpperBuff(str,lstrlen(str));
+ if( _tcsstr(str,(const TCHAR*)lParam)!=NULL) {
+ SendDlgItemMessage(hwndDlg,IDC_LIST,LB_SETCURSEL,index,0);
+ SendMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_LIST,LBN_SELCHANGE),0);
+ break;
+ } } }
+
+ mir_free(dbei.pBlob);
+ break;
+ }
+ }
+ return FALSE;
+}
+
+static INT_PTR CALLBACK DlgProcHistoryFind(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)lParam);
+ return TRUE;
+
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDOK://find Next
+ {
+ TCHAR str[128];
+ HWND hwndParent = ( HWND )GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ GetDlgItemText(hwndDlg, IDC_FINDWHAT, str, SIZEOF(str));
+ CharUpperBuff(str,lstrlen(str));
+ SendMessage(hwndParent,DM_FINDNEXT,0,(LPARAM)str);
+ return TRUE;
+ }
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ return TRUE;
+ }
+ break;
+ }
+ return FALSE;
+}
diff --git a/src/modules/icolib/IcoLib.h b/src/modules/icolib/IcoLib.h
new file mode 100644
index 0000000000..72e3aa4122
--- /dev/null
+++ b/src/modules/icolib/IcoLib.h
@@ -0,0 +1,83 @@
+/*
+
+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.
+*/
+typedef struct
+{
+ TCHAR* name;
+ int flags;
+ int maxOrder;
+ int ref_count;
+}
+ SectionItem;
+
+typedef struct
+{
+ TCHAR* file;
+ int ref_count;
+}
+ IconSourceFile;
+
+typedef struct
+{
+ IconSourceFile* file;
+ int indx;
+ int cx, cy;
+
+ int ref_count;
+
+ HICON icon;
+ int icon_ref_count;
+
+ BYTE* icon_data;
+ int icon_size;
+}
+ IconSourceItem;
+
+typedef struct
+{
+ char* name;
+ SectionItem* section;
+ int orderID;
+ TCHAR* description;
+ TCHAR* default_file;
+ int default_indx;
+ int cx, cy;
+
+ IconSourceItem* source_small;
+ IconSourceItem* source_big;
+ IconSourceItem* default_icon;
+
+ TCHAR* temp_file;
+ HICON temp_icon;
+ BOOL temp_reset;
+}
+ IconItem;
+
+typedef struct
+{
+ char *paramName;
+ DWORD value;
+}
+ TreeItem;
+
+// extracticon.c
+UINT _ExtractIconEx(LPCTSTR lpszFile, int iconIndex, int cxIcon, int cyIcon, HICON *phicon, UINT flags);
diff --git a/src/modules/icolib/extracticon.cpp b/src/modules/icolib/extracticon.cpp
new file mode 100644
index 0000000000..a886d6510d
--- /dev/null
+++ b/src/modules/icolib/extracticon.cpp
@@ -0,0 +1,280 @@
+/*
+
+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"
+
+#ifdef _ASSERT
+#undef _ASSERT
+#endif
+#define _ASSERT(n)
+// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/resources/introductiontoresources/resourcereference/resourcestructures/newheader.asp
+typedef struct
+{
+ WORD Reserved;
+ WORD ResType;
+ WORD ResCount;
+}
+ NEWHEADER;
+
+#define MAGIC_ICON 0
+#define MAGIC_ICO1 1
+#define MAGIC_CUR 2
+#define MAGIC_BMP ((WORD)'B'+((WORD)'M'<<8))
+
+#define MAGIC_ANI1 ((WORD)'R'+((WORD)'I'<<8))
+#define MAGIC_ANI2 ((WORD)'F'+((WORD)'F'<<8))
+#define MAGIC_ANI3 ((WORD)'A'+((WORD)'C'<<8))
+#define MAGIC_ANI4 ((WORD)'O'+((WORD)'N'<<8))
+
+#define VER30 0x00030000
+
+void* _RelativeVirtualAddresstoPtr(IMAGE_DOS_HEADER* pDosHeader, DWORD rva)
+{
+ IMAGE_NT_HEADERS* pPE = (IMAGE_NT_HEADERS*)((BYTE*)pDosHeader + pDosHeader->e_lfanew);
+ IMAGE_SECTION_HEADER* pSection = IMAGE_FIRST_SECTION( pPE );
+ int i;
+
+ for (i = 0; i < pPE->FileHeader.NumberOfSections; i++) {
+ IMAGE_SECTION_HEADER* cSection = &pSection[i];
+ DWORD size = cSection->Misc.VirtualSize ? cSection->Misc.VirtualSize : cSection->SizeOfRawData;
+
+ if (rva >= cSection->VirtualAddress && rva < cSection->VirtualAddress + size)
+ return (LPBYTE)pDosHeader + cSection->PointerToRawData + (rva - cSection->VirtualAddress);
+ }
+
+ return NULL;
+}
+
+void* _GetResourceTable(IMAGE_DOS_HEADER* pDosHeader)
+{
+ IMAGE_NT_HEADERS* pPE = (IMAGE_NT_HEADERS*)((BYTE*)pDosHeader + pDosHeader->e_lfanew);
+
+ if (pPE->Signature != IMAGE_NT_SIGNATURE)
+ return NULL;
+ if (pPE->FileHeader.SizeOfOptionalHeader < 2)
+ return NULL;
+
+ // The DataDirectory is an array of 16 structures.
+ // Each array entry has a predefined meaning for what it refers to.
+
+ switch (pPE->OptionalHeader.Magic)
+ {
+ case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
+ if (pPE->FileHeader.SizeOfOptionalHeader >= sizeof(IMAGE_OPTIONAL_HEADER32))
+ return _RelativeVirtualAddresstoPtr(pDosHeader, ((PIMAGE_NT_HEADERS32)pPE)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress);
+ break;
+
+ case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
+ if (pPE->FileHeader.SizeOfOptionalHeader >= sizeof(IMAGE_OPTIONAL_HEADER64))
+ return _RelativeVirtualAddresstoPtr(pDosHeader, ((PIMAGE_NT_HEADERS64)pPE)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress);
+ break;
+ }
+
+ return NULL;
+}
+
+IMAGE_RESOURCE_DIRECTORY_ENTRY* _FindResourceBase(void* prt, int resType, int* pCount)
+{
+ IMAGE_RESOURCE_DIRECTORY* pDir = (IMAGE_RESOURCE_DIRECTORY*)prt;
+ IMAGE_RESOURCE_DIRECTORY_ENTRY* pRes;
+ int i, count;
+
+ *pCount = 0;
+
+ count = pDir->NumberOfIdEntries + pDir->NumberOfNamedEntries;
+ pRes = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(pDir+1);
+
+ for(i = 0; i < count; i++)
+ if (pRes[i].Name == (DWORD)resType) break;
+
+ if (i == count) return NULL;
+
+ pDir = (IMAGE_RESOURCE_DIRECTORY*)((LPBYTE)prt +
+ (pRes[i].OffsetToData & ~IMAGE_RESOURCE_DATA_IS_DIRECTORY));
+
+ count = pDir->NumberOfIdEntries + pDir->NumberOfNamedEntries;
+ *pCount = count;
+ pRes = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(pDir+1);
+
+ return pRes;
+}
+
+int _FindResourceCount(void* prt, int resType)
+{
+ int count;
+
+ _FindResourceBase(prt, resType, &count);
+ return count;
+}
+
+void* _FindResource(IMAGE_DOS_HEADER* pDosHeader, void* prt, int resIndex, int resType, DWORD* pcbSize)
+{
+ int count, index = 0;
+ IMAGE_RESOURCE_DIRECTORY_ENTRY* pRes;
+ IMAGE_RESOURCE_DATA_ENTRY* pEntry;
+
+ pRes = _FindResourceBase(prt, resType, &count);
+ if (resIndex < 0) {
+ for(index = 0; index < count; index++)
+ if (pRes[index].Name == (DWORD)(-resIndex))
+ break;
+ }
+ else index = resIndex;
+
+ if (index >= count)
+ return NULL;
+
+ if (pRes[index].OffsetToData & IMAGE_RESOURCE_DATA_IS_DIRECTORY) {
+ IMAGE_RESOURCE_DIRECTORY* pDir;
+ pDir = (IMAGE_RESOURCE_DIRECTORY*)((LPBYTE)prt + (pRes[index].OffsetToData & ~IMAGE_RESOURCE_DATA_IS_DIRECTORY) );
+ pRes = (IMAGE_RESOURCE_DIRECTORY_ENTRY*)(pDir+1);
+ index = 0;
+ }
+
+ if ( pRes[index].OffsetToData & IMAGE_RESOURCE_DATA_IS_DIRECTORY )
+ return NULL;
+
+ pEntry = (IMAGE_RESOURCE_DATA_ENTRY*)((LPBYTE)prt + pRes[index].OffsetToData);
+ *pcbSize = pEntry->Size;
+ return _RelativeVirtualAddresstoPtr(pDosHeader, pEntry->OffsetToData);
+}
+
+UINT _ExtractFromExe(HANDLE hFile, int iconIndex, int cxIconSize, int cyIconSize, HICON *phicon, UINT flags)
+{
+ int retval = 0;
+ DWORD fileLen = GetFileSize(hFile, NULL);
+ HANDLE hFileMap = INVALID_HANDLE_VALUE, pFile = NULL;
+ IMAGE_DOS_HEADER* pDosHeader;
+ void* pRes;
+ DWORD cbSize = 0;
+ NEWHEADER* pIconDir;
+ int idIcon;
+ LPBITMAPINFOHEADER pIcon;
+ // UINT res = 0;
+
+ hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
+ if (hFileMap == NULL) goto cleanup;
+
+ pFile = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 0);
+ if (pFile == NULL) goto cleanup;
+
+ pDosHeader = (IMAGE_DOS_HEADER*)(void*)pFile;
+ if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) goto cleanup;
+ if (pDosHeader->e_lfanew <= 0) goto cleanup;
+ if ((DWORD)(pDosHeader->e_lfanew) >= fileLen) goto cleanup;
+
+ pRes = _GetResourceTable(pDosHeader);
+ if (!pRes) goto cleanup;
+ if (!phicon) {
+ retval = _FindResourceCount(pRes, (int)RT_GROUP_ICON);
+ goto cleanup;
+ }
+
+ pIconDir = (NEWHEADER*)_FindResource(pDosHeader, pRes, iconIndex, (int)RT_GROUP_ICON, &cbSize);
+ if (!pIconDir) goto cleanup;
+ if (pIconDir->Reserved || pIconDir->ResType != RES_ICON) goto cleanup;
+
+ idIcon = LookupIconIdFromDirectoryEx((LPBYTE)pIconDir, TRUE, cxIconSize, cyIconSize, flags);
+ pIcon = (LPBITMAPINFOHEADER)_FindResource(pDosHeader, pRes, -idIcon, (int)RT_ICON, &cbSize);
+ if (!pIcon) goto cleanup;
+
+ if ( pIcon->biSize != sizeof(BITMAPINFOHEADER) && pIcon->biSize != sizeof(BITMAPCOREHEADER)) {
+ _ASSERT(0);
+ goto cleanup;
+ }
+
+ *phicon = CreateIconFromResourceEx((LPBYTE)pIcon, cbSize, TRUE, VER30, cxIconSize, cyIconSize, flags);
+ retval = 1;
+
+cleanup:
+ if (pFile) UnmapViewOfFile(pFile);
+ if (hFileMap != INVALID_HANDLE_VALUE) CloseHandle(hFileMap);
+
+ return retval;
+}
+
+UINT _ExtractFromICO( LPCTSTR pFileName, int iconIndex, int cxIcon, int cyIcon, HICON* phicon, UINT flags )
+{
+ HICON hicon;
+
+ if ( iconIndex >= 1 )
+ return 0;
+
+ // do we just want a count?
+ if (!phicon)
+ return 1;
+
+ flags |= LR_LOADFROMFILE;
+ hicon = (HICON)LoadImage( NULL, pFileName, IMAGE_ICON, cxIcon, cyIcon, flags );
+ if (!hicon)
+ return 0;
+
+ *phicon = hicon;
+ return 1;
+}
+
+UINT _ExtractIconEx(LPCTSTR lpszFile, int iconIndex, int cxIcon, int cyIcon, HICON *phicon, UINT flags)
+{
+ HANDLE hFile;
+ WORD magic[6];
+ DWORD read = 0;
+ UINT res = 0;
+
+ if (cxIcon == GetSystemMetrics(SM_CXICON) && cyIcon == GetSystemMetrics(SM_CYICON))
+ res = ExtractIconEx(lpszFile, iconIndex, phicon, NULL, 1);
+ else if (cxIcon == GetSystemMetrics(SM_CXSMICON) && cyIcon == GetSystemMetrics(SM_CYSMICON))
+ res = ExtractIconEx(lpszFile, iconIndex, NULL, phicon, 1);
+ else if (cxIcon == 0 || cyIcon == 0)
+ res = ExtractIconEx(lpszFile, iconIndex, NULL, phicon, 1);
+ // check if the api succeded, if not try our method too
+ if (res) return res;
+
+ hFile = CreateFile(lpszFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
+ if (hFile == INVALID_HANDLE_VALUE)
+ return 0;
+
+ // failed to read file signature
+ if ( !ReadFile(hFile,&magic, sizeof(magic), &read, NULL ) || (read != sizeof(magic))) {
+ CloseHandle(hFile);
+ return 0;
+ }
+
+ switch ( magic[0] ) {
+ case IMAGE_DOS_SIGNATURE:
+ res = _ExtractFromExe(hFile, iconIndex, cxIcon, cyIcon, phicon, flags);
+ break;
+
+ case MAGIC_ANI1: // ani cursors are RIFF file of type 'ACON'
+ if (magic[1] == MAGIC_ANI2 && magic[4] == MAGIC_ANI3 && magic[5] == MAGIC_ANI4)
+ res = _ExtractFromICO(lpszFile, iconIndex, cxIcon, cyIcon, phicon, flags);
+ break;
+
+ case MAGIC_ICON:
+ if ((magic[1] == MAGIC_ICO1 || magic[1] == MAGIC_CUR ) && magic[2] >= 1 )
+ res = _ExtractFromICO(lpszFile, iconIndex, cxIcon, cyIcon, phicon, flags);
+
+ break;
+ }
+
+ CloseHandle(hFile);
+ return res;
+}
diff --git a/src/modules/icolib/skin2icons.cpp b/src/modules/icolib/skin2icons.cpp
new file mode 100644
index 0000000000..a1a3e670b2
--- /dev/null
+++ b/src/modules/icolib/skin2icons.cpp
@@ -0,0 +1,1992 @@
+/*
+
+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 "IcoLib.h"
+
+static BOOL bModuleInitialized = FALSE;
+static HANDLE hIcons2ChangedEvent, hIconsChangedEvent;
+static HICON hIconBlank = NULL;
+
+HANDLE hIcoLib_AddNewIcon, hIcoLib_RemoveIcon, hIcoLib_GetIcon, hIcoLib_GetIcon2,
+ hIcoLib_GetIconHandle, hIcoLib_IsManaged, hIcoLib_AddRef, hIcoLib_ReleaseIcon;
+
+static int iconEventActive = 0;
+
+static BOOL bNeedRebuild = FALSE;
+
+struct IcoLibOptsData {
+ HWND hwndIndex;
+};
+
+CRITICAL_SECTION csIconList;
+
+#define SECTIONPARAM_MAKE(index, level, flags) MAKELONG( (index)&0xFFFF, MAKEWORD( level, flags ) )
+#define SECTIONPARAM_INDEX(lparam) LOWORD( lparam )
+#define SECTIONPARAM_LEVEL(lparam) LOBYTE( HIWORD(lparam) )
+#define SECTIONPARAM_FLAGS(lparam) HIBYTE( HIWORD(lparam) )
+#define SECTIONPARAM_HAVEPAGE 0x0001
+
+static int sttCompareSections( const SectionItem* p1, const SectionItem* p2 )
+{ return _tcscmp( p1->name, p2->name );
+}
+
+static LIST<SectionItem> sectionList( 20, sttCompareSections );
+
+static int sttCompareIconSourceFiles( const IconSourceFile* p1, const IconSourceFile* p2 )
+{ return _tcsicmp( p1->file, p2->file );
+}
+
+static LIST<IconSourceFile> iconSourceFileList( 10, sttCompareIconSourceFiles );
+
+static int sttCompareIconSourceItems( const IconSourceItem* p1, const IconSourceItem* p2 )
+{ if (p1->indx < p2->indx)
+ return -1;
+
+ if (p1->indx > p2->indx)
+ return 1;
+
+ if (p1->cx < p2->cx)
+ return -1;
+
+ if (p1->cx > p2->cx)
+ return 1;
+
+ if (p1->cy < p2->cy)
+ return -1;
+
+ if (p1->cy > p2->cy)
+ return 1;
+
+ if ( p1->file == p2->file )
+ return 0;
+
+ return ( p1->file > p2->file ) ? 1 : -1;
+}
+
+static LIST<IconSourceItem> iconSourceList( 20, sttCompareIconSourceItems );
+
+static int sttCompareIcons( const IconItem* p1, const IconItem* p2 )
+{ return strcmp( p1->name, p2->name );
+}
+
+static LIST<IconItem> iconList( 20, sttCompareIcons );
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Utility functions
+
+static void __fastcall MySetCursor(TCHAR* nCursor)
+{ SetCursor( LoadCursor( NULL, nCursor ));
+}
+
+static void __fastcall SAFE_FREE(void** p)
+{
+ if ( *p ) {
+ mir_free( *p );
+ *p = NULL;
+} }
+
+static void __fastcall SafeDestroyIcon( HICON* icon )
+{
+ if ( *icon ) {
+ DestroyIcon( *icon );
+ *icon = NULL;
+} }
+
+
+// Helper functions to manage Icon resources
+
+IconSourceFile* IconSourceFile_Get( const TCHAR* file, bool isPath )
+{
+ TCHAR fileFull[ MAX_PATH ];
+
+ if ( !file )
+ return NULL;
+
+ if (isPath)
+ pathToAbsoluteT( file, fileFull, NULL );
+ /// TODO: convert path to long - eliminate duplicate items
+ else
+ _tcscpy( fileFull, file );
+
+ IconSourceFile key = { fileFull };
+ int ix;
+ if (( ix = iconSourceFileList.getIndex( &key )) != -1 ) {
+ iconSourceFileList[ ix ]->ref_count++;
+ return iconSourceFileList[ ix ];
+ }
+
+ IconSourceFile* newItem = (IconSourceFile*)mir_calloc( sizeof( IconSourceFile ));
+ newItem->file = mir_tstrdup( fileFull );
+ newItem->ref_count = 1;
+ iconSourceFileList.insert( newItem );
+
+ return newItem;
+}
+
+int IconSourceFile_Release( IconSourceFile** pitem )
+{
+ if ( pitem && *pitem && (*pitem)->ref_count ) {
+ IconSourceFile* item = *pitem;
+ if ( --item->ref_count <= 0 ) {
+ int indx;
+ if (( indx = iconSourceFileList.getIndex( item )) != -1 ) {
+ SAFE_FREE(( void** )&item->file );
+ iconSourceFileList.remove( indx );
+ SAFE_FREE(( void** )&item );
+ }
+ }
+ *pitem = NULL;
+ return 0;
+ }
+ return 1;
+}
+
+static int BytesPerScanLine(int PixelsPerScanline, int BitsPerPixel, int Alignment)
+{ Alignment--;
+ int bytes = ((PixelsPerScanline * BitsPerPixel) + Alignment) & ~Alignment;
+ return bytes / 8;
+}
+
+static int InitializeBitmapInfoHeader( HBITMAP bitmap, BITMAPINFOHEADER* bi )
+{
+ DIBSECTION DS;
+ int bytes;
+
+ DS.dsBmih.biSize = 0;
+ bytes = GetObject( bitmap, sizeof(DS), &DS );
+ if ( bytes == 0 ) return 1; // Failure
+ else if (( bytes >= (sizeof(DS.dsBm) + sizeof(DS.dsBmih))) &&
+ (DS.dsBmih.biSize >= DWORD(sizeof(DS.dsBmih))))
+ *bi = DS.dsBmih;
+ else {
+ memset(bi, 0, sizeof(BITMAPINFOHEADER));
+ bi->biSize = sizeof(BITMAPINFOHEADER);
+ bi->biWidth = DS.dsBm.bmWidth;
+ bi->biHeight = DS.dsBm.bmHeight;
+ }
+ bi->biBitCount = DS.dsBm.bmBitsPixel * DS.dsBm.bmPlanes;
+ bi->biPlanes = 1;
+ if ( bi->biClrImportant > bi->biClrUsed )
+ bi->biClrImportant = bi->biClrUsed;
+ if ( !bi->biSizeImage )
+ bi->biSizeImage = BytesPerScanLine( bi->biWidth, bi->biBitCount, 32 ) * abs( bi->biHeight );
+ return 0; // Success
+}
+
+static int InternalGetDIBSizes( HBITMAP bitmap, int* InfoHeaderSize, int* ImageSize )
+{
+ BITMAPINFOHEADER bi;
+
+ if ( InitializeBitmapInfoHeader( bitmap, &bi )) return 1; // Failure
+ if ( bi.biBitCount > 8 ) {
+ *InfoHeaderSize = sizeof(BITMAPINFOHEADER);
+ if ((bi.biCompression & BI_BITFIELDS) != 0 )
+ *InfoHeaderSize += 12;
+ }
+ else {
+ if ( bi.biClrUsed == 0 )
+ *InfoHeaderSize = sizeof(BITMAPINFOHEADER) +
+ sizeof(RGBQUAD) * (int)(1 << bi.biBitCount);
+ else
+ *InfoHeaderSize = sizeof(BITMAPINFOHEADER) +
+ sizeof(RGBQUAD) * bi.biClrUsed;
+ }
+ *ImageSize = bi.biSizeImage;
+ return 0; // Success
+}
+
+static int InternalGetDIB( HBITMAP bitmap, HPALETTE palette, void* bitmapInfo, void* Bits )
+{
+ HPALETTE oldPal = 0;
+
+ if ( InitializeBitmapInfoHeader( bitmap, (BITMAPINFOHEADER*)bitmapInfo )) return 1; // Failure
+
+ HDC DC = CreateCompatibleDC(0);
+ if ( palette ) {
+ oldPal = SelectPalette( DC, palette, FALSE );
+ RealizePalette( DC );
+ }
+ int result = GetDIBits( DC, bitmap, 0, ((BITMAPINFOHEADER*)bitmapInfo)->biHeight, Bits, (BITMAPINFO*)bitmapInfo, DIB_RGB_COLORS) == 0;
+
+ if ( oldPal ) SelectPalette( DC, oldPal, FALSE );
+ DeleteDC( DC );
+ return result;
+}
+
+static int GetIconData( HICON icon, BYTE** data, int* size )
+{
+ ICONINFO iconInfo;
+ int MonoInfoSize, ColorInfoSize;
+ int MonoBitsSize, ColorBitsSize;
+
+ if ( !data || !size ) return 1; // Failure
+
+ if ( !GetIconInfo( icon, &iconInfo )) return 1; // Failure
+
+ if ( InternalGetDIBSizes( iconInfo.hbmMask, &MonoInfoSize, &MonoBitsSize ) ||
+ InternalGetDIBSizes( iconInfo.hbmColor, &ColorInfoSize, &ColorBitsSize )) {
+ DeleteObject( iconInfo.hbmColor );
+ DeleteObject( iconInfo.hbmMask );
+ return 1; // Failure
+ }
+ void* MonoInfo = mir_alloc( MonoInfoSize );
+ void* MonoBits = mir_alloc( MonoBitsSize );
+ void* ColorInfo = mir_alloc( ColorInfoSize );
+ void* ColorBits = mir_alloc( ColorBitsSize );
+
+ if ( InternalGetDIB( iconInfo.hbmMask, 0, MonoInfo, MonoBits ) ||
+ InternalGetDIB( iconInfo.hbmColor, 0, ColorInfo, ColorBits )) {
+ SAFE_FREE( &MonoInfo );
+ SAFE_FREE( &MonoBits );
+ SAFE_FREE( &ColorInfo );
+ SAFE_FREE( &ColorBits );
+ DeleteObject( iconInfo.hbmColor );
+ DeleteObject( iconInfo.hbmMask );
+ return 1; // Failure
+ }
+
+ *size = ColorInfoSize + ColorBitsSize + MonoBitsSize;
+ *data = (BYTE*)mir_alloc(*size);
+
+ BYTE* buf = *data;
+ ((BITMAPINFOHEADER*)ColorInfo)->biHeight *= 2; // color height includes mono bits
+ memcpy( buf, ColorInfo, ColorInfoSize );
+ buf += ColorInfoSize;
+ memcpy( buf, ColorBits, ColorBitsSize );
+ buf += ColorBitsSize;
+ memcpy( buf, MonoBits, MonoBitsSize );
+
+ SAFE_FREE( &MonoInfo );
+ SAFE_FREE( &MonoBits );
+ SAFE_FREE( &ColorInfo );
+ SAFE_FREE( &ColorBits );
+ DeleteObject( iconInfo.hbmColor );
+ DeleteObject( iconInfo.hbmMask );
+ return 0; // Success
+}
+
+#define VER30 0x00030000
+
+static HICON IconSourceItem_GetIcon( IconSourceItem* item )
+{
+ if ( item->icon ) {
+ item->icon_ref_count++;
+ return item->icon;
+ }
+
+ if ( item->icon_size ) {
+ item->icon = CreateIconFromResourceEx( item->icon_data, item->icon_size, TRUE, VER30, item->cx, item->cy, LR_COLOR );
+ if ( item->icon ) {
+ item->icon_ref_count++;
+ return item->icon;
+ }
+ }
+ //SHOULD BE REPLACED WITH GOOD ENOUGH FUNCTION
+ _ExtractIconEx( item->file->file, item->indx, item->cx, item->cy, &item->icon, LR_COLOR );
+
+ if ( item->icon )
+ item->icon_ref_count++;
+
+ return item->icon;
+}
+
+static int IconSourceItem_ReleaseIcon( IconSourceItem* item )
+{
+ if ( item && item->icon_ref_count )
+ {
+ item->icon_ref_count--;
+ if ( !item->icon_ref_count ) {
+ if ( !item->icon_size )
+ if ( GetIconData( item->icon, &item->icon_data, &item->icon_size ))
+ item->icon_size = 0; // Failure
+ SafeDestroyIcon( &item->icon );
+ }
+ return 0; // Success
+ }
+ return 1; // Failure
+}
+
+IconSourceItem* GetIconSourceItem( const TCHAR* file, int indx, int cxIcon, int cyIcon )
+{
+ if ( !file )
+ return NULL;
+
+ IconSourceFile* r_file = IconSourceFile_Get( file, true );
+ IconSourceItem key = { r_file, indx, cxIcon, cyIcon };
+ int ix;
+ if (( ix = iconSourceList.getIndex( &key )) != -1 ) {
+ IconSourceFile_Release( &r_file );
+ iconSourceList[ ix ]->ref_count++;
+ return iconSourceList[ ix ];
+ }
+
+ IconSourceItem* newItem = (IconSourceItem*)mir_calloc( sizeof( IconSourceItem ));
+ newItem->file = r_file;
+ newItem->indx = indx;
+ newItem->ref_count = 1;
+ newItem->cx = cxIcon;
+ newItem->cy = cyIcon;
+ iconSourceList.insert( newItem );
+
+ return newItem;
+}
+
+IconSourceItem* GetIconSourceItemFromPath( const TCHAR* path, int cxIcon, int cyIcon )
+{
+ TCHAR *comma;
+ TCHAR file[ MAX_PATH ];
+ int n;
+
+ if ( !path )
+ return NULL;
+
+ lstrcpyn( file, path, SIZEOF( file ));
+ comma = _tcsrchr( file, ',' );
+ if ( !comma )
+ n = 0;
+ else {
+ n = _ttoi( comma+1 );
+ *comma = 0;
+ }
+ return GetIconSourceItem( file, n, cxIcon, cyIcon );
+}
+
+IconSourceItem* CreateStaticIconSourceItem( int cxIcon, int cyIcon )
+{
+ TCHAR sourceName[ MAX_PATH ];
+ IconSourceFile key = { sourceName };
+
+ int i = 0;
+ do { // find new unique name
+ mir_sntprintf( sourceName, SIZEOF( sourceName ), _T("*StaticIcon_%d"), ++i);
+ } while ( iconSourceFileList.getIndex( &key ) != -1 );
+
+ IconSourceItem* newItem = (IconSourceItem*)mir_calloc( sizeof( IconSourceItem ));
+ newItem->file = IconSourceFile_Get( sourceName, false );
+ newItem->indx = 0;
+ newItem->ref_count = 1;
+ newItem->cx = cxIcon;
+ newItem->cy = cyIcon;
+ iconSourceList.insert( newItem );
+
+ return newItem;
+}
+
+static int IconSourceItem_Release( IconSourceItem** pitem )
+{
+ if ( pitem && *pitem && (*pitem)->ref_count ) {
+ IconSourceItem* item = *pitem;
+ item->ref_count--;
+ if ( !item->ref_count ) {
+ int indx;
+ if (( indx = iconSourceList.getIndex( item )) != -1 ) {
+ IconSourceFile_Release( &item->file );
+ SafeDestroyIcon( &item->icon );
+ SAFE_FREE(( void** )&item->icon_data );
+ iconSourceList.remove( indx );
+ SAFE_FREE(( void** )&item );
+ }
+ }
+ *pitem = NULL;
+ return 0;
+ }
+ return 1;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Service functions
+
+static HICON ExtractIconFromPath( const TCHAR *path, int cxIcon, int cyIcon )
+{
+ TCHAR *comma;
+ TCHAR file[ MAX_PATH ], fileFull[ MAX_PATH ];
+ int n;
+ HICON hIcon;
+
+ if ( !path )
+ return (HICON)NULL;
+
+ lstrcpyn( file, path, SIZEOF( file ));
+ comma = _tcsrchr( file, ',' );
+ if ( !comma )
+ n = 0;
+ else {
+ n = _ttoi( comma+1 );
+ *comma = 0;
+ }
+ pathToAbsoluteT( file, fileFull, NULL );
+ hIcon = NULL;
+
+ //SHOULD BE REPLACED WITH GOOD ENOUGH FUNCTION
+ _ExtractIconEx( fileFull, n, cxIcon, cyIcon, &hIcon, LR_COLOR );
+ return hIcon;
+}
+
+static SectionItem* IcoLib_AddSection(TCHAR *sectionName, BOOL create_new)
+{
+ if ( !sectionName )
+ return NULL;
+
+ int indx;
+ SectionItem key = { sectionName, 0 };
+ if (( indx = sectionList.getIndex( &key )) != -1 )
+ return sectionList[ indx ];
+
+ if ( create_new ) {
+ SectionItem* newItem = ( SectionItem* )mir_calloc( sizeof( SectionItem ));
+ newItem->name = mir_tstrdup( sectionName );
+ newItem->flags = 0;
+ sectionList.insert( newItem );
+ bNeedRebuild = TRUE;
+ return newItem;
+ }
+
+ return NULL;
+}
+
+static void IcoLib_RemoveSection(SectionItem* section)
+{
+ if ( !section )
+ return;
+
+ int indx;
+
+ if (( indx = sectionList.getIndex( section )) != -1 ) {
+ sectionList.remove( indx );
+ SAFE_FREE(( void** )&section->name);
+ SAFE_FREE(( void** )&section );
+ bNeedRebuild = TRUE;
+ }
+}
+
+static IconItem* IcoLib_FindIcon(const char* pszIconName)
+{
+ int indx;
+ IconItem key = { (char*)pszIconName };
+ if (( indx = iconList.getIndex( &key )) != -1 )
+ return iconList[ indx ];
+
+ return NULL;
+}
+
+static IconItem* IcoLib_FindHIcon(HICON hIcon, bool &big)
+{
+ IconItem* item = NULL;
+ int indx;
+
+ for ( indx = 0; indx < iconList.getCount(); indx++ ) {
+ if ( iconList[ indx ]->source_small && iconList[ indx ]->source_small->icon == hIcon) {
+ item = iconList[ indx ];
+ big = false;
+ break;
+ }
+ else if ( iconList[ indx ]->source_big && iconList[ indx ]->source_big->icon == hIcon) {
+ item = iconList[ indx ];
+ big = true;
+ break;
+ }
+ }
+
+ return item;
+}
+
+static void IcoLib_FreeIcon(IconItem* icon)
+{
+ if ( !icon) return;
+
+ SAFE_FREE(( void** )&icon->name );
+ SAFE_FREE(( void** )&icon->description );
+ SAFE_FREE(( void** )&icon->default_file );
+ SAFE_FREE(( void** )&icon->temp_file );
+ if ( icon->section) {
+ if ( !--icon->section->ref_count)
+ IcoLib_RemoveSection( icon->section );
+ icon->section = NULL;
+ }
+ IconSourceItem_Release( &icon->source_small );
+ IconSourceItem_Release( &icon->source_big );
+ IconSourceItem_Release( &icon->default_icon );
+ SafeDestroyIcon( &icon->temp_icon );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// IcoLib_AddNewIcon
+
+HANDLE IcoLib_AddNewIcon( SKINICONDESC* sid )
+{
+ int utf = 0, utf_path = 0;
+ IconItem* item;
+
+ if ( !sid->cbSize )
+ return NULL;
+
+ if ( sid->cbSize < SKINICONDESC_SIZE_V1 )
+ return NULL;
+
+ if ( sid->cbSize >= SKINICONDESC_SIZE ) {
+ utf = sid->flags & SIDF_UNICODE ? 1 : 0;
+ utf_path = sid->flags & SIDF_PATH_UNICODE ? 1 : 0;
+ }
+
+ EnterCriticalSection( &csIconList );
+
+ item = IcoLib_FindIcon( sid->pszName );
+ if ( !item ) {
+ item = ( IconItem* )mir_alloc( sizeof( IconItem ));
+ item->name = sid->pszName;
+ iconList.insert( item );
+ }
+ else IcoLib_FreeIcon( item );
+
+ ZeroMemory( item, sizeof( *item ));
+ item->name = mir_strdup( sid->pszName );
+ if ( utf ) {
+ item->description = mir_u2t( sid->pwszDescription );
+ #ifdef _UNICODE
+ item->section = IcoLib_AddSection( sid->pwszSection, TRUE );
+ #else
+ char* pszSection = sid->pwszSection ? mir_u2a( sid->pwszSection ) : NULL;
+ item->section = IcoLib_AddSection( pszSection, TRUE );
+ SAFE_FREE(( void** )&pszSection );
+ #endif
+ }
+ else {
+ item->description = mir_a2t( sid->pszDescription );
+ #ifdef _UNICODE
+ WCHAR* pwszSection = sid->pszSection ? mir_a2u( sid->pszSection ) : NULL;
+
+ item->section = IcoLib_AddSection( pwszSection, TRUE );
+ SAFE_FREE(( void** )&pwszSection );
+ #else
+ item->section = IcoLib_AddSection( sid->pszSection, TRUE );
+ #endif
+ }
+ if ( item->section ) {
+ item->section->ref_count++;
+ item->orderID = ++item->section->maxOrder;
+ }
+ else
+ item->orderID = 0;
+
+ if ( sid->pszDefaultFile ) {
+ if ( utf_path ) {
+ #ifdef _UNICODE
+ WCHAR fileFull[ MAX_PATH ];
+
+ pathToAbsoluteW( sid->pwszDefaultFile, fileFull, NULL );
+ item->default_file = mir_wstrdup( fileFull );
+ #else
+ char* file = mir_u2a( sid->pwszDefaultFile );
+ char fileFull[ MAX_PATH ];
+
+ pathToAbsolute( file, fileFull, NULL );
+ SAFE_FREE(( void** )&file );
+ item->default_file = mir_strdup( fileFull );
+ #endif
+ }
+ else {
+ #ifdef _UNICODE
+ WCHAR *file = mir_a2u( sid->pszDefaultFile );
+ WCHAR fileFull[ MAX_PATH ];
+
+ pathToAbsoluteW( file, fileFull, NULL );
+ SAFE_FREE(( void** )&file );
+ item->default_file = mir_wstrdup( fileFull );
+ #else
+ char fileFull[ MAX_PATH ];
+
+ pathToAbsolute( sid->pszDefaultFile, fileFull, NULL );
+ item->default_file = mir_strdup( fileFull );
+ #endif
+ } }
+ item->default_indx = sid->iDefaultIndex;
+
+ if ( sid->cbSize >= SKINICONDESC_SIZE_V3 ) {
+ item->cx = sid->cx;
+ item->cy = sid->cy;
+ }
+
+ if ( sid->cbSize >= SKINICONDESC_SIZE_V2 && sid->hDefaultIcon ) {
+ bool big;
+ IconItem* def_item = IcoLib_FindHIcon( sid->hDefaultIcon, big );
+ if ( def_item ) {
+ item->default_icon = big ? def_item->source_big : def_item->source_small;
+ item->default_icon->ref_count++;
+ }
+ else {
+ int cx = item->cx ? item->cx : GetSystemMetrics(SM_CXSMICON);
+ int cy = item->cy ? item->cy : GetSystemMetrics(SM_CYSMICON);
+ item->default_icon = CreateStaticIconSourceItem( cx, cy );
+ if ( GetIconData( sid->hDefaultIcon, &item->default_icon->icon_data, &item->default_icon->icon_size )) {
+ IconSourceItem_Release( &item->default_icon );
+ }
+ }
+ }
+
+ if ( sid->cbSize >= SKINICONDESC_SIZE && item->section )
+ item->section->flags = sid->flags & SIDF_SORTED;
+
+ LeaveCriticalSection( &csIconList );
+ return item;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// IcoLib_RemoveIcon
+
+static INT_PTR IcoLib_RemoveIcon( WPARAM, LPARAM lParam )
+{
+ if ( lParam ) {
+ int indx;
+ EnterCriticalSection( &csIconList );
+
+ if (( indx = iconList.getIndex(( IconItem* )&lParam )) != -1 ) {
+ IconItem *item = iconList[ indx ];
+ IcoLib_FreeIcon( item );
+ iconList.remove( indx );
+ SAFE_FREE(( void** )&item );
+ }
+
+ LeaveCriticalSection( &csIconList );
+ return ( indx == -1 ) ? 1 : 0;
+ }
+ return 1; // Failed
+}
+
+HICON IconItem_GetDefaultIcon( IconItem* item, bool big )
+{
+ HICON hIcon = NULL;
+
+ if ( item->default_icon && !big ) {
+ IconSourceItem_Release( &item->source_small );
+ item->source_small = item->default_icon;
+ item->source_small->ref_count++;
+ hIcon = IconSourceItem_GetIcon( item->source_small );
+ }
+
+ if ( !hIcon && item->default_file ) {
+ int cx = item->cx ? item->cx : GetSystemMetrics(big ? SM_CXICON : SM_CXSMICON);
+ int cy = item->cy ? item->cy : GetSystemMetrics(big ? SM_CYICON : SM_CYSMICON);
+ IconSourceItem* def_icon = GetIconSourceItem( item->default_file, item->default_indx, cx, cy );
+ if ( big ) {
+ if ( def_icon != item->source_big ) {
+ IconSourceItem_Release( &item->source_big );
+ item->source_big = def_icon;
+ if ( def_icon ) {
+ def_icon->ref_count++;
+ hIcon = IconSourceItem_GetIcon( def_icon );
+ }
+ }
+ else
+ IconSourceItem_Release( &def_icon );
+ }
+ else {
+ if ( def_icon != item->default_icon ) {
+ IconSourceItem_Release( &item->default_icon );
+ item->default_icon = def_icon;
+ if ( def_icon ) {
+ IconSourceItem_Release( &item->source_small );
+ item->source_small = def_icon;
+ def_icon->ref_count++;
+ hIcon = IconSourceItem_GetIcon( def_icon );
+ }
+ }
+ else
+ IconSourceItem_Release( &def_icon );
+ }
+ }
+ return hIcon;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// IconItem_GetIcon
+
+HICON IconItem_GetIcon( IconItem* item, bool big )
+{
+ DBVARIANT dbv = {0};
+ HICON hIcon = NULL;
+
+ big = big && !item->cx;
+ IconSourceItem* &source = big ? item->source_big : item->source_small;
+
+ if ( !source && !DBGetContactSettingTString( NULL, "SkinIcons", item->name, &dbv )) {
+ int cx = item->cx ? item->cx : GetSystemMetrics(big ? SM_CXICON : SM_CXSMICON);
+ int cy = item->cy ? item->cy : GetSystemMetrics(big ? SM_CYICON : SM_CYSMICON);
+ source = GetIconSourceItemFromPath( dbv.ptszVal, cx, cy );
+ DBFreeVariant( &dbv );
+ }
+
+ if ( source )
+ hIcon = IconSourceItem_GetIcon( source );
+
+ if ( !hIcon )
+ hIcon = IconItem_GetDefaultIcon( item, big );
+
+ if ( !hIcon )
+ return hIconBlank;
+
+ return hIcon;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// IconItem_GetIcon_Preview
+
+HICON IconItem_GetIcon_Preview( IconItem* item )
+{
+ HICON hIcon = NULL;
+
+ if ( !item->temp_reset ) {
+ HICON hRefIcon = IconItem_GetIcon( item, false );
+ hIcon = CopyIcon( hRefIcon );
+ if ( item->source_small && item->source_small->icon == hRefIcon )
+ IconSourceItem_ReleaseIcon( item->source_small );
+ }
+ else {
+ if ( item->default_icon ) {
+ HICON hRefIcon = IconSourceItem_GetIcon( item->default_icon );
+ if ( hRefIcon ) {
+ hIcon = CopyIcon( hRefIcon );
+ if ( item->default_icon->icon == hRefIcon )
+ IconSourceItem_ReleaseIcon( item->default_icon );
+ } }
+
+ if ( !hIcon && item->default_file ) {
+ IconSourceItem_Release( &item->default_icon );
+ item->default_icon = GetIconSourceItem( item->default_file, item->default_indx, item->cx, item->cy );
+ if ( item->default_icon ) {
+ HICON hRefIcon = IconSourceItem_GetIcon( item->default_icon );
+ if ( hRefIcon ) {
+ hIcon = CopyIcon( hRefIcon );
+ if ( item->default_icon->icon == hRefIcon )
+ IconSourceItem_ReleaseIcon( item->default_icon );
+ } } }
+
+ if ( !hIcon )
+ return CopyIcon(hIconBlank);
+ }
+ return hIcon;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// IcoLib_GetIcon
+// lParam: pszIconName
+// wParam: PLOADIMAGEPARAM or NULL.
+// if wParam == NULL, default is used:
+// uType = IMAGE_ICON
+// cx/cyDesired = GetSystemMetrics(SM_CX/CYSMICON)
+// fuLoad = 0
+
+HICON IcoLib_GetIcon( const char* pszIconName, bool big )
+{
+ IconItem* item;
+ HICON result = NULL;
+
+ if ( !pszIconName )
+ return hIconBlank;
+
+ EnterCriticalSection( &csIconList );
+
+ item = IcoLib_FindIcon( pszIconName );
+ if ( item ) {
+ result = IconItem_GetIcon( item, big );
+ }
+ LeaveCriticalSection( &csIconList );
+ return result;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// IcoLib_GetIconHandle
+// lParam: pszIconName
+
+HANDLE IcoLib_GetIconHandle( const char* pszIconName )
+{
+ IconItem* item;
+
+ if ( !pszIconName )
+ return NULL;
+
+ EnterCriticalSection( &csIconList );
+ item = IcoLib_FindIcon( pszIconName );
+ LeaveCriticalSection( &csIconList );
+
+ return (HANDLE)item;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// IcoLib_GetIconByHandle
+// lParam: icolib item handle
+// wParam: 0
+
+HICON IcoLib_GetIconByHandle( HANDLE hItem, bool big )
+{
+ if ( hItem == NULL )
+ return NULL;
+
+ HICON result = hIconBlank;
+ IconItem* pi = ( IconItem* )hItem;
+
+ EnterCriticalSection( &csIconList );
+
+ // we can get any junk here... but getIndex() is MUCH faster than indexOf().
+ __try
+ {
+ if ( iconList.getIndex( pi ) != -1 )
+ result = IconItem_GetIcon( pi, big );
+ }
+ __except( EXCEPTION_EXECUTE_HANDLER )
+ {
+ }
+
+ LeaveCriticalSection( &csIconList );
+ return result;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// IcoLib_IsManaged
+// lParam: NULL
+// wParam: HICON
+
+HANDLE IcoLib_IsManaged( HICON hIcon )
+{
+ IconItem* item;
+
+ EnterCriticalSection( &csIconList );
+
+ bool big;
+ item = IcoLib_FindHIcon( hIcon, big );
+ if ( item ) {
+ IconSourceItem* source = big && !item->cx ? item->source_big : item->source_small;
+ if ( source->icon_ref_count == 0 )
+ item = NULL;
+ }
+
+ LeaveCriticalSection( &csIconList );
+ return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// IcoLib_AddRef
+// lParam: NULL
+// wParam: HICON
+
+static INT_PTR IcoLib_AddRef( WPARAM wParam, LPARAM )
+{
+ EnterCriticalSection( &csIconList );
+
+ bool big;
+ IconItem *item = IcoLib_FindHIcon(( HICON )wParam, big);
+
+ INT_PTR res = 1;
+ if ( item ) {
+ IconSourceItem* source = big && !item->cx ? item->source_big : item->source_small;
+ if ( source->icon_ref_count ) {
+ source->icon_ref_count++;
+ res = 0;
+ }
+ }
+
+ LeaveCriticalSection( &csIconList );
+ return res;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// IcoLib_ReleaseIcon
+// lParam: pszIconName or NULL
+// wParam: HICON or NULL
+
+int IcoLib_ReleaseIcon( HICON hIcon, char* szIconName, bool big )
+{
+ IconItem *item = NULL;
+
+ EnterCriticalSection(&csIconList);
+
+ if ( szIconName )
+ item = IcoLib_FindIcon( szIconName );
+
+ if ( !item && hIcon ) // find by HICON
+ item = IcoLib_FindHIcon( hIcon, big );
+
+ int res = 1;
+ if ( item ) {
+ IconSourceItem* source = big && !item->cx ? item->source_big : item->source_small;
+ if ( source && source->icon_ref_count ) {
+ if ( iconEventActive )
+ source->icon_ref_count--;
+ else
+ IconSourceItem_ReleaseIcon( source );
+ res = 0;
+ }
+ }
+
+ LeaveCriticalSection( &csIconList );
+ return res;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// IcoLib GUI service routines
+
+static void LoadSectionIcons(TCHAR *filename, SectionItem* sectionActive)
+{
+ TCHAR path[ MAX_PATH ];
+ int suffIndx;
+ HICON hIcon;
+ int indx;
+
+ mir_sntprintf( path, SIZEOF(path), _T("%s,"), filename );
+ suffIndx = lstrlen( path );
+
+ EnterCriticalSection( &csIconList );
+
+ for ( indx = 0; indx < iconList.getCount(); indx++ ) {
+ IconItem *item = iconList[ indx ];
+
+ if ( item->default_file && item->section == sectionActive ) {
+ _itot( item->default_indx, path + suffIndx, 10 );
+ hIcon = ExtractIconFromPath( path, item->cx, item->cy );
+ if ( hIcon ) {
+ SAFE_FREE(( void** )&item->temp_file );
+ SafeDestroyIcon( &item->temp_icon );
+
+ item->temp_file = mir_tstrdup( path );
+ item->temp_icon = hIcon;
+ item->temp_reset = FALSE;
+ } } }
+
+ LeaveCriticalSection( &csIconList );
+}
+
+void LoadSubIcons(HWND htv, TCHAR *filename, HTREEITEM hItem)
+{
+ TVITEM tvi;
+ TreeItem *treeItem;
+ SectionItem* sectionActive;
+
+ tvi.mask = TVIF_HANDLE | TVIF_PARAM;
+ tvi.hItem = hItem;
+
+ TreeView_GetItem( htv, &tvi );
+ treeItem = (TreeItem *)tvi.lParam;
+ sectionActive = sectionList[ SECTIONPARAM_INDEX(treeItem->value) ];
+
+ tvi.hItem = TreeView_GetChild( htv, tvi.hItem );
+ while ( tvi.hItem ) {
+ LoadSubIcons( htv, filename, tvi.hItem );
+ tvi.hItem = TreeView_GetNextSibling( htv, tvi.hItem );
+ }
+
+ if ( SECTIONPARAM_FLAGS(treeItem->value) & SECTIONPARAM_HAVEPAGE )
+ LoadSectionIcons( filename, sectionActive );
+}
+
+static void UndoChanges( int iconIndx, int cmd )
+{
+ IconItem *item = iconList[ iconIndx ];
+
+ if ( !item->temp_file && !item->temp_icon && item->temp_reset && cmd == ID_CANCELCHANGE )
+ item->temp_reset = FALSE;
+ else
+ {
+ SAFE_FREE(( void** )&item->temp_file );
+ SafeDestroyIcon( &item->temp_icon );
+ }
+
+ if ( cmd == ID_RESET )
+ item->temp_reset = TRUE;
+}
+
+void UndoSubItemChanges( HWND htv, HTREEITEM hItem, int cmd )
+{
+ TVITEM tvi = {0};
+ TreeItem *treeItem;
+ int indx;
+
+ tvi.mask = TVIF_HANDLE | TVIF_PARAM;
+ tvi.hItem = hItem;
+ TreeView_GetItem( htv, &tvi );
+ treeItem = (TreeItem *)tvi.lParam;
+
+ if ( SECTIONPARAM_FLAGS( treeItem->value ) & SECTIONPARAM_HAVEPAGE ) {
+ EnterCriticalSection( &csIconList );
+
+ for ( indx = 0; indx < iconList.getCount(); indx++ )
+ if ( iconList[ indx ]->section == sectionList[ SECTIONPARAM_INDEX(treeItem->value) ])
+ UndoChanges( indx, cmd );
+
+ LeaveCriticalSection( &csIconList );
+ }
+
+ tvi.hItem = TreeView_GetChild( htv, tvi.hItem );
+ while ( tvi.hItem ) {
+ UndoSubItemChanges( htv, tvi.hItem, cmd );
+ tvi.hItem = TreeView_GetNextSibling( htv, tvi.hItem );
+} }
+
+static void OpenIconsPage()
+{
+ CallService( MS_UTILS_OPENURL, 1, (LPARAM)"http://addons.miranda-im.org/index.php?action=display&id=35" );
+}
+
+static int OpenPopupMenu(HWND hwndDlg)
+{
+ HMENU hMenu, hPopup;
+ POINT pt;
+ int cmd;
+
+ GetCursorPos(&pt);
+ hMenu = LoadMenu( hMirandaInst, MAKEINTRESOURCE( IDR_ICOLIB_CONTEXT ));
+ hPopup = GetSubMenu( hMenu, 0 );
+ CallService( MS_LANGPACK_TRANSLATEMENU, ( WPARAM )hPopup, 0 );
+ cmd = TrackPopupMenu( hPopup, TPM_RIGHTBUTTON|TPM_RETURNCMD, pt.x, pt.y, 0, hwndDlg, NULL );
+ DestroyMenu( hMenu );
+ return cmd;
+}
+
+static TCHAR* OpenFileDlg( HWND hParent, const TCHAR* szFile, BOOL bAll )
+{
+ OPENFILENAME ofn = {0};
+ TCHAR filter[512],*pfilter,file[MAX_PATH*2];
+
+ ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
+ ofn.hwndOwner = hParent;
+
+ lstrcpy(filter,TranslateT("Icon Sets"));
+ if (bAll)
+ lstrcat(filter,_T(" (*.dll;*.icl;*.exe;*.ico)"));
+ else
+ lstrcat(filter,_T(" (*.dll)"));
+
+ pfilter=filter+lstrlen(filter)+1;
+ if (bAll)
+ lstrcpy(pfilter,_T("*.DLL;*.ICL;*.EXE;*.ICO"));
+ else
+ lstrcpy(pfilter,_T("*.DLL"));
+
+ pfilter += lstrlen(pfilter) + 1;
+ lstrcpy(pfilter, TranslateT("All Files"));
+ lstrcat(pfilter,_T(" (*)"));
+ pfilter += lstrlen(pfilter) + 1;
+ lstrcpy(pfilter,_T("*"));
+ pfilter += lstrlen(pfilter) + 1;
+ *pfilter='\0';
+
+ ofn.lpstrFilter = filter;
+ ofn.lpstrDefExt = _T("dll");
+ lstrcpyn(file, szFile, SIZEOF(file));
+ ofn.lpstrFile = file;
+ ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_DONTADDTORECENT;
+ ofn.nMaxFile = MAX_PATH*2;
+
+ if (!GetOpenFileName(&ofn))
+ return NULL;
+
+ return mir_tstrdup(file);
+}
+
+//
+// User interface
+//
+
+#define DM_REBUILDICONSPREVIEW (WM_USER+10)
+#define DM_CHANGEICON (WM_USER+11)
+#define DM_CHANGESPECIFICICON (WM_USER+12)
+#define DM_UPDATEICONSPREVIEW (WM_USER+13)
+#define DM_REBUILD_CTREE (WM_USER+14)
+
+INT_PTR CALLBACK DlgProcIconImport(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+void DoOptionsChanged(HWND hwndDlg)
+{
+ SendMessage(hwndDlg, DM_UPDATEICONSPREVIEW, 0, 0);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+}
+
+void DoIconsChanged(HWND hwndDlg)
+{
+ SendMessage(hwndDlg, DM_UPDATEICONSPREVIEW, 0, 0);
+
+ iconEventActive = 1; // Disable icon destroying - performance boost
+ NotifyEventHooks(hIconsChangedEvent, 0, 0);
+ NotifyEventHooks(hIcons2ChangedEvent, 0, 0);
+ iconEventActive = 0;
+
+ EnterCriticalSection(&csIconList); // Destroy unused icons
+ for (int indx = 0; indx < iconList.getCount(); indx++) {
+ IconItem *item = iconList[indx];
+ if ( item->source_small && !item->source_small->icon_ref_count) {
+ item->source_small->icon_ref_count++;
+ IconSourceItem_ReleaseIcon( item->source_small );
+ }
+ if ( item->source_big && !item->source_big->icon_ref_count) {
+ item->source_big->icon_ref_count++;
+ IconSourceItem_ReleaseIcon( item->source_big );
+ }
+ }
+ LeaveCriticalSection(&csIconList);
+}
+
+static HTREEITEM FindNamedTreeItemAt(HWND hwndTree, HTREEITEM hItem, const TCHAR *name)
+{
+ TVITEM tvi = {0};
+ TCHAR str[MAX_PATH];
+
+ if (hItem)
+ tvi.hItem = TreeView_GetChild(hwndTree, hItem);
+ else
+ tvi.hItem = TreeView_GetRoot(hwndTree);
+
+ if (!name)
+ return tvi.hItem;
+
+ tvi.mask = TVIF_TEXT;
+ tvi.pszText = str;
+ tvi.cchTextMax = MAX_PATH;
+
+ while (tvi.hItem)
+ {
+ TreeView_GetItem(hwndTree, &tvi);
+
+ if (!lstrcmp(tvi.pszText, name))
+ return tvi.hItem;
+
+ tvi.hItem = TreeView_GetNextSibling(hwndTree, tvi.hItem);
+ }
+ return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// icon import dialog's window procedure
+
+static int IconDlg_Resize(HWND, LPARAM, UTILRESIZECONTROL *urc)
+{
+ switch (urc->wId) {
+ case IDC_ICONSET:
+ return RD_ANCHORX_WIDTH | RD_ANCHORY_TOP;
+
+ case IDC_BROWSE:
+ return RD_ANCHORX_RIGHT | RD_ANCHORY_TOP;
+
+ case IDC_PREVIEW:
+ return RD_ANCHORX_WIDTH | RD_ANCHORY_HEIGHT;
+
+ case IDC_GETMORE:
+ return RD_ANCHORX_CENTRE | RD_ANCHORY_BOTTOM;
+ }
+ return RD_ANCHORX_LEFT | RD_ANCHORY_TOP; // default
+}
+
+INT_PTR CALLBACK DlgProcIconImport(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static HWND hwndParent,hwndDragOver;
+ static int dragging;
+ static int dragItem,dropHiLite;
+ static HWND hPreview = NULL;
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ hwndParent = (HWND)lParam;
+ hPreview = GetDlgItem(hwndDlg, IDC_PREVIEW);
+ dragging = dragItem = 0;
+ ListView_SetImageList(hPreview, ImageList_Create(GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),ILC_COLOR32|ILC_MASK,0,100), LVSIL_NORMAL);
+ ListView_SetIconSpacing(hPreview, 56, 67);
+ {
+ RECT rcThis, rcParent;
+ int cxScreen = GetSystemMetrics(SM_CXSCREEN);
+
+ GetWindowRect(hwndDlg,&rcThis);
+ GetWindowRect(hwndParent,&rcParent);
+ OffsetRect(&rcThis,rcParent.right-rcThis.left,0);
+ OffsetRect(&rcThis,0,rcParent.top-rcThis.top);
+ GetWindowRect(GetParent(hwndParent),&rcParent);
+ if (rcThis.right > cxScreen) {
+ OffsetRect(&rcParent,cxScreen-rcThis.right,0);
+ OffsetRect(&rcThis,cxScreen-rcThis.right,0);
+ MoveWindow(GetParent(hwndParent),rcParent.left,rcParent.top,rcParent.right-rcParent.left,rcParent.bottom-rcParent.top,TRUE);
+ }
+ MoveWindow(hwndDlg,rcThis.left,rcThis.top,rcThis.right-rcThis.left,rcThis.bottom-rcThis.top,FALSE);
+ GetClientRect(hwndDlg, &rcThis);
+ SendMessage(hwndDlg, WM_SIZE, 0, MAKELPARAM(rcThis.right-rcThis.left, rcThis.bottom-rcThis.top));
+ }
+
+ if (shAutoComplete) shAutoComplete(GetDlgItem(hwndDlg,IDC_ICONSET), 1);
+ SetDlgItemText(hwndDlg,IDC_ICONSET,_T("icons.dll"));
+ return TRUE;
+
+ case DM_REBUILDICONSPREVIEW:
+ {
+ LVITEM lvi;
+ TCHAR filename[MAX_PATH],caption[64];
+ HIMAGELIST hIml;
+ int count,i;
+ HICON hIcon;
+
+ MySetCursor(IDC_WAIT);
+ ListView_DeleteAllItems(hPreview);
+ hIml = ListView_GetImageList(hPreview, LVSIL_NORMAL);
+ ImageList_RemoveAll(hIml);
+ GetDlgItemText(hwndDlg, IDC_ICONSET, filename, SIZEOF(filename));
+ {
+ RECT rcPreview,rcGroup;
+
+ GetWindowRect(hPreview, &rcPreview);
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_IMPORTMULTI),&rcGroup);
+ //SetWindowPos(hPreview,0,0,0,rcPreview.right-rcPreview.left,rcGroup.bottom-rcPreview.top,SWP_NOZORDER|SWP_NOMOVE);
+ }
+
+ if (_taccess(filename,0) != 0) {
+ MySetCursor(IDC_ARROW);
+ break;
+ }
+
+ lvi.mask = LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM;
+ lvi.iSubItem = 0;
+ lvi.iItem = 0;
+ count = (int)_ExtractIconEx( filename, -1, 16,16, NULL, LR_DEFAULTCOLOR );
+ for (i = 0; i < count; lvi.iItem++, i++) {
+ mir_sntprintf(caption, SIZEOF(caption), _T("%d"), i+1);
+ lvi.pszText = caption;
+ //hIcon = ExtractIcon(hMirandaInst, filename, i);
+ _ExtractIconEx( filename, i, 16,16, &hIcon, LR_DEFAULTCOLOR );
+ lvi.iImage = ImageList_AddIcon(hIml, hIcon);
+ DestroyIcon(hIcon);
+ lvi.lParam = i;
+ ListView_InsertItem(hPreview, &lvi);
+ }
+ MySetCursor(IDC_ARROW);
+ }
+ break;
+
+ case WM_COMMAND:
+ switch( LOWORD( wParam )) {
+ case IDC_BROWSE:
+ {
+ TCHAR str[MAX_PATH];
+ TCHAR *file;
+
+ GetDlgItemText(hwndDlg,IDC_ICONSET,str,SIZEOF(str));
+ if (!(file = OpenFileDlg(GetParent(hwndDlg), str, TRUE))) break;
+ SetDlgItemText(hwndDlg,IDC_ICONSET,file);
+ SAFE_FREE(( void** )&file );
+ }
+ break;
+
+ case IDC_GETMORE:
+ OpenIconsPage();
+ break;
+
+ case IDC_ICONSET:
+ if (HIWORD(wParam) == EN_CHANGE)
+ SendMessage(hwndDlg, DM_REBUILDICONSPREVIEW, 0, 0);
+ break;
+ }
+ break;
+
+ case WM_MOUSEMOVE:
+ if (dragging) {
+ LVHITTESTINFO lvhti;
+ int onItem=0;
+ HWND hwndOver;
+ RECT rc;
+ POINT ptDrag;
+ HWND hPPreview = GetDlgItem(hwndParent, IDC_PREVIEW);
+
+ lvhti.pt.x = (short)LOWORD(lParam); lvhti.pt.y = (short)HIWORD(lParam);
+ ClientToScreen(hwndDlg, &lvhti.pt);
+ hwndOver = WindowFromPoint(lvhti.pt);
+ GetWindowRect(hwndOver, &rc);
+ ptDrag.x = lvhti.pt.x - rc.left; ptDrag.y = lvhti.pt.y - rc.top;
+ if (hwndOver != hwndDragOver) {
+ ImageList_DragLeave(hwndDragOver);
+ hwndDragOver = hwndOver;
+ ImageList_DragEnter(hwndDragOver, ptDrag.x, ptDrag.y);
+ }
+
+ ImageList_DragMove(ptDrag.x, ptDrag.y);
+ if (hwndOver == hPPreview) {
+ ScreenToClient(hPPreview, &lvhti.pt);
+
+ if (ListView_HitTest(hPPreview, &lvhti) != -1) {
+ if (lvhti.iItem != dropHiLite) {
+ ImageList_DragLeave(hwndDragOver);
+ if (dropHiLite != -1)
+ ListView_SetItemState(hPPreview, dropHiLite, 0, LVIS_DROPHILITED);
+ dropHiLite = lvhti.iItem;
+ ListView_SetItemState(hPPreview, dropHiLite, LVIS_DROPHILITED, LVIS_DROPHILITED);
+ UpdateWindow(hPPreview);
+ ImageList_DragEnter(hwndDragOver, ptDrag.x, ptDrag.y);
+ }
+ onItem = 1;
+ } }
+
+ if (!onItem && dropHiLite != -1) {
+ ImageList_DragLeave(hwndDragOver);
+ ListView_SetItemState(hPPreview, dropHiLite, 0, LVIS_DROPHILITED);
+ UpdateWindow(hPPreview);
+ ImageList_DragEnter(hwndDragOver, ptDrag.x, ptDrag.y);
+ dropHiLite = -1;
+ }
+ MySetCursor(onItem ? IDC_ARROW : IDC_NO);
+ }
+ break;
+
+ case WM_LBUTTONUP:
+ if (dragging) {
+ ReleaseCapture();
+ ImageList_EndDrag();
+ dragging = 0;
+ if (dropHiLite != -1) {
+ TCHAR path[MAX_PATH],fullPath[MAX_PATH],filename[MAX_PATH];
+ LVITEM lvi;
+
+ GetDlgItemText(hwndDlg, IDC_ICONSET, fullPath, SIZEOF(fullPath));
+ CallService(MS_UTILS_PATHTORELATIVET, (WPARAM)fullPath, (LPARAM)filename);
+ lvi.mask=LVIF_PARAM;
+ lvi.iItem = dragItem; lvi.iSubItem = 0;
+ ListView_GetItem(hPreview, &lvi);
+ mir_sntprintf(path, MAX_PATH, _T("%s,%d"), filename, (int)lvi.lParam);
+ SendMessage(hwndParent, DM_CHANGEICON, dropHiLite, (LPARAM)path);
+ ListView_SetItemState(GetDlgItem(hwndParent, IDC_PREVIEW), dropHiLite, 0, LVIS_DROPHILITED);
+ } }
+ break;
+
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case IDC_PREVIEW:
+ switch (((LPNMHDR)lParam)->code) {
+ case LVN_BEGINDRAG:
+ SetCapture(hwndDlg);
+ dragging = 1;
+ dragItem = ((LPNMLISTVIEW)lParam)->iItem;
+ dropHiLite = -1;
+ ImageList_BeginDrag(ListView_GetImageList(hPreview, LVSIL_NORMAL), dragItem, GetSystemMetrics(SM_CXICON)/2, GetSystemMetrics(SM_CYICON)/2);
+ {
+ POINT pt;
+ RECT rc;
+
+ GetCursorPos(&pt);
+ GetWindowRect(hwndDlg, &rc);
+ ImageList_DragEnter(hwndDlg, pt.x - rc.left, pt.y - rc.top);
+ hwndDragOver = hwndDlg;
+ }
+ break;
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ DestroyWindow(hwndDlg);
+ EnableWindow(GetDlgItem(hwndParent,IDC_IMPORT),TRUE);
+ break;
+
+ case WM_SIZE:
+ { // make the dlg resizeable
+ UTILRESIZEDIALOG urd = {0};
+
+ if (IsIconic(hwndDlg)) break;
+ urd.cbSize = sizeof(urd);
+ urd.hInstance = hMirandaInst;
+ urd.hwndDlg = hwndDlg;
+ urd.lParam = 0; // user-defined
+ urd.lpTemplate = MAKEINTRESOURCEA(IDD_ICOLIB_IMPORT);
+ urd.pfnResizer = IconDlg_Resize;
+ CallService(MS_UTILS_RESIZEDIALOG, 0, (LPARAM)&urd);
+ break;
+ } }
+
+ return FALSE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// IcoLib options window procedure
+
+static int CALLBACK DoSortIconsFunc(LPARAM lParam1, LPARAM lParam2, LPARAM )
+{ return lstrcmpi(TranslateTS(iconList[lParam1]->description), TranslateTS(iconList[lParam2]->description));
+}
+
+static int CALLBACK DoSortIconsFuncByOrder(LPARAM lParam1, LPARAM lParam2, LPARAM )
+{ return iconList[lParam1]->orderID - iconList[lParam2]->orderID;
+}
+
+static void SaveCollapseState( HWND hwndTree )
+{
+ HTREEITEM hti;
+ TVITEM tvi;
+
+ hti = TreeView_GetRoot( hwndTree );
+ while( hti != NULL ) {
+ HTREEITEM ht;
+ TreeItem *treeItem;
+
+ tvi.mask = TVIF_STATE | TVIF_HANDLE | TVIF_CHILDREN | TVIF_PARAM;
+ tvi.hItem = hti;
+ tvi.stateMask = (DWORD)-1;
+ TreeView_GetItem( hwndTree, &tvi );
+
+ if( tvi.cChildren > 0 ) {
+ treeItem = (TreeItem *)tvi.lParam;
+ if ( tvi.state & TVIS_EXPANDED )
+ DBWriteContactSettingByte(NULL, "SkinIconsUI", treeItem->paramName, TVIS_EXPANDED );
+ else
+ DBWriteContactSettingByte(NULL, "SkinIconsUI", treeItem->paramName, 0 );
+ }
+
+ ht = TreeView_GetChild( hwndTree, hti );
+ if( ht == NULL ) {
+ ht = TreeView_GetNextSibling( hwndTree, hti );
+ while( ht == NULL ) {
+ hti = TreeView_GetParent( hwndTree, hti );
+ if( hti == NULL ) break;
+ ht = TreeView_GetNextSibling( hwndTree, hti );
+ } }
+
+ hti = ht;
+} }
+
+INT_PTR CALLBACK DlgProcIcoLibOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct IcoLibOptsData *dat;
+ static HTREEITEM prevItem = 0;
+ static HWND hPreview = NULL;
+
+ dat = (struct IcoLibOptsData*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ hPreview = GetDlgItem(hwndDlg, IDC_PREVIEW);
+ dat = (struct IcoLibOptsData*)mir_alloc(sizeof(struct IcoLibOptsData));
+ dat->hwndIndex = NULL;
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)dat);
+ //
+ // Reset temporary data & upload sections list
+ //
+ EnterCriticalSection(&csIconList);
+ {
+ int indx;
+ for (indx = 0; indx < iconList.getCount(); indx++) {
+ iconList[indx]->temp_file = NULL;
+ iconList[indx]->temp_icon = NULL;
+ iconList[indx]->temp_reset = FALSE;
+ }
+ bNeedRebuild = FALSE;
+ }
+ LeaveCriticalSection(&csIconList);
+ //
+ // Setup preview listview
+ //
+ ListView_SetUnicodeFormat(hPreview, TRUE);
+ ListView_SetExtendedListViewStyleEx(hPreview, LVS_EX_INFOTIP, LVS_EX_INFOTIP);
+ ListView_SetImageList(hPreview, ImageList_Create(GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),ILC_COLOR32|ILC_MASK,0,30), LVSIL_NORMAL);
+ ListView_SetIconSpacing(hPreview, 56, 67);
+
+ SendMessage(hwndDlg, DM_REBUILD_CTREE, 0, 0);
+ return TRUE;
+
+ case DM_REBUILD_CTREE:
+ {
+ HWND hwndTree = GetDlgItem(hwndDlg, IDC_CATEGORYLIST);
+ int indx;
+ TCHAR itemName[1024];
+ HTREEITEM hSection;
+
+ if (!hwndTree) break;
+
+ TreeView_SelectItem(hwndTree, NULL);
+ TreeView_DeleteAllItems(hwndTree);
+
+ for (indx = 0; indx < sectionList.getCount(); indx++) {
+ TCHAR* sectionName;
+ int sectionLevel = 0;
+
+ hSection = NULL;
+ lstrcpy(itemName, sectionList[indx]->name);
+ sectionName = itemName;
+
+ while (sectionName) {
+ // allow multi-level tree
+ TCHAR* pItemName = sectionName;
+ HTREEITEM hItem;
+
+ if (sectionName = _tcschr(sectionName, '/')) {
+ // one level deeper
+ *sectionName = 0;
+ }
+
+ pItemName = TranslateTS( pItemName );
+
+ hItem = FindNamedTreeItemAt(hwndTree, hSection, pItemName);
+ if (!sectionName || !hItem) {
+ if (!hItem) {
+ TVINSERTSTRUCT tvis = {0};
+ TreeItem *treeItem = (TreeItem *)mir_alloc(sizeof(TreeItem));
+ treeItem->value = SECTIONPARAM_MAKE( indx, sectionLevel, sectionName?0:SECTIONPARAM_HAVEPAGE );
+ treeItem->paramName = mir_t2a(itemName);
+
+ tvis.hParent = hSection;
+ tvis.hInsertAfter = TVI_SORT; //TVI_LAST;
+ tvis.item.mask = TVIF_TEXT|TVIF_PARAM|TVIF_STATE;
+ tvis.item.pszText = pItemName;
+ tvis.item.lParam = (LPARAM) treeItem;
+
+ tvis.item.state = tvis.item.stateMask = DBGetContactSettingByte(NULL, "SkinIconsUI", treeItem->paramName, TVIS_EXPANDED );
+ hItem = TreeView_InsertItem(hwndTree, &tvis);
+ }
+ else {
+ TVITEM tvi = {0};
+ TreeItem *treeItem;
+ tvi.hItem = hItem;
+ tvi.mask = TVIF_HANDLE | TVIF_PARAM;
+ TreeView_GetItem( hwndTree, &tvi );
+ treeItem = (TreeItem *)tvi.lParam;
+ treeItem->value = SECTIONPARAM_MAKE( indx, sectionLevel, SECTIONPARAM_HAVEPAGE );
+ } }
+
+ if (sectionName) {
+ *sectionName = '/';
+ sectionName++;
+ }
+ sectionLevel++;
+
+ hSection = hItem;
+ } }
+
+ ShowWindow(hwndTree, SW_SHOW);
+
+ TreeView_SelectItem(hwndTree, FindNamedTreeItemAt(hwndTree, 0, NULL));
+ }
+ break;
+
+ // Rebuild preview to new section
+ case DM_REBUILDICONSPREVIEW:
+ {
+ LVITEM lvi = {0};
+ HIMAGELIST hIml;
+ HICON hIcon;
+ SectionItem* sectionActive = ( SectionItem* )lParam;
+ int indx;
+
+ EnableWindow(hPreview, sectionActive != NULL );
+
+ ListView_DeleteAllItems(hPreview);
+ hIml = ListView_GetImageList(hPreview, LVSIL_NORMAL);
+ ImageList_RemoveAll(hIml);
+
+ if (sectionActive == NULL)
+ break;
+
+ lvi.mask = LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM;
+
+ EnterCriticalSection(&csIconList);
+
+ for (indx = 0; indx < iconList.getCount(); indx++) {
+ IconItem *item = iconList[indx];
+
+ if (item->section == sectionActive) {
+ lvi.pszText = TranslateTS(item->description);
+ hIcon = item->temp_icon;
+ if ( !hIcon )
+ hIcon = IconItem_GetIcon_Preview( item );
+ lvi.iImage = ImageList_AddIcon(hIml, hIcon);
+ lvi.lParam = indx;
+ ListView_InsertItem(hPreview, &lvi);
+ if (hIcon != item->temp_icon) SafeDestroyIcon( &hIcon );
+ } }
+
+ LeaveCriticalSection(&csIconList);
+
+ if ( sectionActive->flags & SIDF_SORTED )
+ ListView_SortItems(hPreview, DoSortIconsFunc, 0);
+ else
+ ListView_SortItems(hPreview, DoSortIconsFuncByOrder, 0);
+ }
+ break;
+
+ // Refresh preview to new section
+ case DM_UPDATEICONSPREVIEW:
+ {
+ LVITEM lvi = {0};
+ HICON hIcon;
+ int indx, count;
+ HIMAGELIST hIml = ListView_GetImageList(hPreview, LVSIL_NORMAL);
+
+ lvi.mask = LVIF_IMAGE|LVIF_PARAM;
+ count = ListView_GetItemCount(hPreview);
+
+ for (indx = 0; indx < count; indx++) {
+ lvi.iItem = indx;
+ ListView_GetItem(hPreview, &lvi);
+ EnterCriticalSection(&csIconList);
+ hIcon = iconList[lvi.lParam]->temp_icon;
+ if (!hIcon)
+ hIcon = IconItem_GetIcon_Preview( iconList[lvi.lParam] );
+ LeaveCriticalSection(&csIconList);
+
+ if (hIcon)
+ ImageList_ReplaceIcon(hIml, lvi.iImage, hIcon);
+ if (hIcon != iconList[lvi.lParam]->temp_icon) SafeDestroyIcon( &hIcon );
+ }
+ ListView_RedrawItems(hPreview, 0, count);
+ }
+ break;
+
+ // Temporary change icon - only inside options dialog
+ case DM_CHANGEICON:
+ {
+ TCHAR *path=(TCHAR*)lParam;
+ LVITEM lvi = {0};
+ IconItem *item;
+
+ lvi.mask = LVIF_PARAM;
+ lvi.iItem = wParam;
+ ListView_GetItem( hPreview, &lvi );
+
+ EnterCriticalSection( &csIconList );
+ item = iconList[ lvi.lParam ];
+
+ SAFE_FREE(( void** )&item->temp_file );
+ SafeDestroyIcon( &item->temp_icon );
+ item->temp_file = mir_tstrdup( path );
+ item->temp_icon = ( HICON )ExtractIconFromPath( path, item->cx, item->cy );
+ item->temp_reset = FALSE;
+
+ LeaveCriticalSection( &csIconList );
+ DoOptionsChanged( hwndDlg );
+ }
+ break;
+
+ case WM_COMMAND:
+ if ( LOWORD(wParam) == IDC_IMPORT ) {
+ dat->hwndIndex = CreateDialogParam(hMirandaInst, MAKEINTRESOURCE(IDD_ICOLIB_IMPORT), GetParent(hwndDlg), DlgProcIconImport, (LPARAM)hwndDlg);
+ EnableWindow((HWND)lParam, FALSE);
+ }
+ else if ( LOWORD(wParam) == IDC_GETMORE ) {
+ OpenIconsPage();
+ break;
+ }
+ else if (LOWORD(wParam) == IDC_LOADICONS ) {
+ TCHAR filetmp[1] = {0};
+ TCHAR *file;
+
+ if ( file = OpenFileDlg( hwndDlg, filetmp, FALSE )) {
+ HWND htv = GetDlgItem( hwndDlg, IDC_CATEGORYLIST );
+ TCHAR filename[ MAX_PATH ];
+
+ CallService( MS_UTILS_PATHTORELATIVET, ( WPARAM )file, ( LPARAM )filename );
+ SAFE_FREE(( void** )&file );
+
+ MySetCursor( IDC_WAIT );
+ LoadSubIcons( htv, filename, TreeView_GetSelection( htv ));
+ MySetCursor( IDC_ARROW );
+
+ DoOptionsChanged( hwndDlg );
+ } }
+ break;
+
+ case WM_CONTEXTMENU:
+ if (( HWND )wParam == hPreview ) {
+ UINT count = ListView_GetSelectedCount( hPreview );
+
+ if ( count > 0 ) {
+ int cmd = OpenPopupMenu( hwndDlg );
+ switch( cmd ) {
+ case ID_CANCELCHANGE:
+ case ID_RESET:
+ {
+ LVITEM lvi = {0};
+ int itemIndx = -1;
+
+ while (( itemIndx = ListView_GetNextItem( hPreview, itemIndx, LVNI_SELECTED )) != -1 ) {
+ lvi.mask = LVIF_PARAM;
+ lvi.iItem = itemIndx; //lvhti.iItem;
+ ListView_GetItem( hPreview, &lvi );
+
+ UndoChanges( lvi.lParam, cmd );
+ }
+
+ DoOptionsChanged( hwndDlg );
+ break;
+ } } }
+ }
+ else {
+ HWND htv = GetDlgItem( hwndDlg, IDC_CATEGORYLIST );
+ if (( HWND )wParam == htv ) {
+ int cmd = OpenPopupMenu( hwndDlg );
+
+ switch( cmd ) {
+ case ID_CANCELCHANGE:
+ case ID_RESET:
+ UndoSubItemChanges( htv, TreeView_GetSelection( htv ), cmd );
+ DoOptionsChanged( hwndDlg );
+ break;
+ } } }
+ break;
+
+ case WM_NOTIFY:
+ switch(((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch(((LPNMHDR)lParam)->code) {
+ case PSN_APPLY:
+ {
+ int indx;
+
+ EnterCriticalSection(&csIconList);
+
+ for (indx = 0; indx < iconList.getCount(); indx++) {
+ IconItem *item = iconList[indx];
+ if (item->temp_reset) {
+ DBDeleteContactSetting(NULL, "SkinIcons", item->name);
+ if (item->source_small != item->default_icon) {
+ IconSourceItem_Release( &item->source_small );
+ }
+ }
+ else if (item->temp_file) {
+ DBWriteContactSettingTString(NULL, "SkinIcons", item->name, item->temp_file);
+ IconSourceItem_Release( &item->source_small );
+ SafeDestroyIcon( &item->temp_icon );
+ }
+ }
+ LeaveCriticalSection(&csIconList);
+
+ DoIconsChanged(hwndDlg);
+ return TRUE;
+ } }
+ break;
+
+ case IDC_PREVIEW:
+ if(((LPNMHDR)lParam)->code == LVN_GETINFOTIP)
+ {
+ IconItem *item;
+ NMLVGETINFOTIP *pInfoTip = (NMLVGETINFOTIP *)lParam;
+ LVITEM lvi;
+ lvi.mask = LVIF_PARAM;
+ lvi.iItem = pInfoTip->iItem;
+ ListView_GetItem(pInfoTip->hdr.hwndFrom, &lvi);
+
+ if( lvi.lParam < iconList.getCount() ) {
+ item = iconList[lvi.lParam];
+ if( item->temp_file )
+ _tcsncpy( pInfoTip->pszText, item->temp_file, pInfoTip->cchTextMax );
+ else if( item->default_file )
+ mir_sntprintf( pInfoTip->pszText, pInfoTip->cchTextMax, _T("%s,%d"), item->default_file, item->default_indx );
+ }
+ }
+ if ( bNeedRebuild ) {
+ EnterCriticalSection(&csIconList);
+ bNeedRebuild = FALSE;
+ LeaveCriticalSection(&csIconList);
+ SendMessage(hwndDlg, DM_REBUILD_CTREE, 0, 0);
+ }
+ break;
+
+ case IDC_CATEGORYLIST:
+ switch(((NMHDR*)lParam)->code) {
+ case TVN_SELCHANGEDA: // !!!! This needs to be here - both !!
+ case TVN_SELCHANGEDW:
+ {
+ NMTREEVIEW *pnmtv = (NMTREEVIEW*)lParam;
+ TVITEM tvi = pnmtv->itemNew;
+ TreeItem *treeItem = (TreeItem *)tvi.lParam;
+ if ( treeItem )
+ SendMessage(hwndDlg, DM_REBUILDICONSPREVIEW, 0, ( LPARAM )(
+ (SECTIONPARAM_FLAGS(treeItem->value)&SECTIONPARAM_HAVEPAGE)?
+ sectionList[ SECTIONPARAM_INDEX(treeItem->value) ] : NULL ) );
+ break;
+ }
+ case TVN_DELETEITEMA: // no idea why both TVN_SELCHANGEDA/W should be there but let's keep this both too...
+ case TVN_DELETEITEMW:
+ {
+ TreeItem *treeItem = (TreeItem *)(((LPNMTREEVIEW)lParam)->itemOld.lParam);
+ if (treeItem) {
+ mir_free(treeItem->paramName);
+ mir_free(treeItem);
+ }
+ break;
+ } }
+ if ( bNeedRebuild ) {
+ EnterCriticalSection(&csIconList);
+ bNeedRebuild = FALSE;
+ LeaveCriticalSection(&csIconList);
+ SendMessage(hwndDlg, DM_REBUILD_CTREE, 0, 0);
+ } }
+ break;
+ case WM_DESTROY:
+ {
+ int indx;
+
+ SaveCollapseState( GetDlgItem(hwndDlg, IDC_CATEGORYLIST) );
+ DestroyWindow(dat->hwndIndex);
+
+ EnterCriticalSection(&csIconList);
+ for (indx = 0; indx < iconList.getCount(); indx++) {
+ IconItem *item = iconList[indx];
+
+ SAFE_FREE(( void** )&item->temp_file);
+ SafeDestroyIcon(&item->temp_icon);
+ }
+ LeaveCriticalSection(&csIconList);
+
+ SAFE_FREE(( void** )&dat);
+ break;
+ } }
+
+ return FALSE;
+}
+
+static UINT iconsExpertOnlyControls[]={IDC_IMPORT};
+
+static int SkinOptionsInit( WPARAM wParam,LPARAM )
+{
+ OPTIONSDIALOGPAGE odp = {0};
+
+ odp.cbSize = sizeof(odp);
+ odp.hInstance = hMirandaInst;
+ odp.flags = ODPF_BOLDGROUPS;
+ odp.position = -180000000;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_ICOLIB);
+ odp.pszTitle = LPGEN("Icons");
+ odp.pszGroup = LPGEN("Customize");
+ odp.pfnDlgProc = DlgProcIcoLibOpts;
+ odp.expertOnlyControls = iconsExpertOnlyControls;
+ odp.nExpertOnlyControls = SIZEOF(iconsExpertOnlyControls);
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM)&odp);
+ return 0;
+}
+
+static int SkinSystemModulesLoaded( WPARAM, LPARAM )
+{
+ HookEvent(ME_OPT_INITIALISE, SkinOptionsInit);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Module initialization and finalization procedure
+
+static INT_PTR sttIcoLib_AddNewIcon( WPARAM, LPARAM lParam )
+{ return (INT_PTR)IcoLib_AddNewIcon(( SKINICONDESC* )lParam );
+}
+
+static INT_PTR sttIcoLib_GetIcon( WPARAM wParam, LPARAM lParam )
+{ return (INT_PTR)IcoLib_GetIcon(( const char* )lParam, wParam != 0 );
+}
+
+static INT_PTR sttIcoLib_GetIconHandle( WPARAM, LPARAM lParam )
+{ return (INT_PTR)IcoLib_GetIconHandle(( const char* )lParam );
+}
+
+static INT_PTR sttIcoLib_GetIconByHandle( WPARAM wParam, LPARAM lParam )
+{ return (INT_PTR)IcoLib_GetIconByHandle(( HANDLE )lParam, wParam != 0 );
+}
+
+static INT_PTR sttIcoLib_ReleaseIcon( WPARAM wParam, LPARAM lParam )
+{ return (INT_PTR)IcoLib_ReleaseIcon(( HICON )wParam, ( char* )lParam, false );
+}
+
+static INT_PTR sttIcoLib_ReleaseIconBig( WPARAM wParam, LPARAM lParam )
+{ return (INT_PTR)IcoLib_ReleaseIcon(( HICON )wParam, ( char* )lParam, true );
+}
+
+static INT_PTR sttIcoLib_IsManaged( WPARAM wParam, LPARAM )
+{ return (INT_PTR)IcoLib_IsManaged(( HICON )wParam );
+}
+
+int LoadIcoLibModule(void)
+{
+ bModuleInitialized = TRUE;
+
+ hIconBlank = LoadIconEx(NULL, MAKEINTRESOURCE(IDI_BLANK),0);
+
+ InitializeCriticalSection(&csIconList);
+ hIcoLib_AddNewIcon = CreateServiceFunction(MS_SKIN2_ADDICON, sttIcoLib_AddNewIcon);
+ hIcoLib_RemoveIcon = CreateServiceFunction(MS_SKIN2_REMOVEICON, IcoLib_RemoveIcon);
+ hIcoLib_GetIcon = CreateServiceFunction(MS_SKIN2_GETICON, sttIcoLib_GetIcon);
+ hIcoLib_GetIconHandle = CreateServiceFunction(MS_SKIN2_GETICONHANDLE, sttIcoLib_GetIconHandle);
+ hIcoLib_GetIcon2 = CreateServiceFunction(MS_SKIN2_GETICONBYHANDLE, sttIcoLib_GetIconByHandle);
+ hIcoLib_IsManaged = CreateServiceFunction(MS_SKIN2_ISMANAGEDICON, sttIcoLib_IsManaged);
+ hIcoLib_AddRef = CreateServiceFunction(MS_SKIN2_ADDREFICON, IcoLib_AddRef);
+ hIcoLib_ReleaseIcon = CreateServiceFunction(MS_SKIN2_RELEASEICON, sttIcoLib_ReleaseIcon);
+ hIcoLib_ReleaseIcon = CreateServiceFunction(MS_SKIN2_RELEASEICONBIG, sttIcoLib_ReleaseIconBig);
+
+ hIcons2ChangedEvent = CreateHookableEvent(ME_SKIN2_ICONSCHANGED);
+ hIconsChangedEvent = CreateHookableEvent(ME_SKIN_ICONSCHANGED);
+
+ HookEvent(ME_SYSTEM_MODULESLOADED, SkinSystemModulesLoaded);
+
+ return 0;
+}
+
+void UnloadIcoLibModule(void)
+{
+ int indx;
+
+ if ( !bModuleInitialized ) return;
+
+ DestroyHookableEvent(hIconsChangedEvent);
+ DestroyHookableEvent(hIcons2ChangedEvent);
+
+ DestroyServiceFunction(hIcoLib_AddNewIcon);
+ DestroyServiceFunction(hIcoLib_RemoveIcon);
+ DestroyServiceFunction(hIcoLib_GetIcon);
+ DestroyServiceFunction(hIcoLib_GetIconHandle);
+ DestroyServiceFunction(hIcoLib_GetIcon2);
+ DestroyServiceFunction(hIcoLib_IsManaged);
+ DestroyServiceFunction(hIcoLib_AddRef);
+ DestroyServiceFunction(hIcoLib_ReleaseIcon);
+ DeleteCriticalSection(&csIconList);
+
+ for (indx = iconList.getCount()-1; indx >= 0; indx-- ) {
+ IconItem* I = iconList[indx];
+ iconList.remove( indx );
+ IcoLib_FreeIcon( I );
+ mir_free( I );
+ }
+ iconList.destroy();
+
+ for (indx = iconSourceList.getCount()-1; indx >= 0; indx-- ) {
+ IconSourceItem* I = iconSourceList[indx];
+ iconSourceList.remove( indx );
+ IconSourceFile_Release( &I->file );
+ SafeDestroyIcon( &I->icon );
+ SAFE_FREE(( void** )&I->icon_data );
+ SAFE_FREE(( void** )&I );
+ }
+ iconSourceList.destroy();
+
+ for (indx = iconSourceFileList.getCount()-1; indx >= 0; indx-- ) {
+ IconSourceFile* I = iconSourceFileList[indx];
+ iconSourceFileList.remove( indx );
+ SAFE_FREE(( void** )&I->file );
+ SAFE_FREE(( void** )&I );
+ }
+ iconSourceFileList.destroy();
+
+ for (indx = 0; indx < sectionList.getCount(); indx++) {
+ SAFE_FREE(( void** )&sectionList[indx]->name );
+ mir_free( sectionList[indx] );
+ }
+ sectionList.destroy();
+
+ SafeDestroyIcon(&hIconBlank);
+}
diff --git a/src/modules/idle/idle.cpp b/src/modules/idle/idle.cpp
new file mode 100644
index 0000000000..bc8b3ec4ef
--- /dev/null
+++ b/src/modules/idle/idle.cpp
@@ -0,0 +1,520 @@
+/*
+
+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"
+
+#define IDLEMOD "Idle"
+#define IDL_USERIDLECHECK "UserIdleCheck"
+#define IDL_IDLEMETHOD "IdleMethod"
+#define IDL_IDLETIME1ST "IdleTime1st"
+#define IDL_IDLEONSAVER "IdleOnSaver" // IDC_SCREENSAVER
+#define IDL_IDLEONFULLSCR "IdleOnFullScr" // IDC_FULLSCREEN
+#define IDL_IDLEONLOCK "IdleOnLock" // IDC_LOCKED
+#define IDL_IDLEONTSDC "IdleOnTerminalDisconnect" //
+#define IDL_IDLEPRIVATE "IdlePrivate" // IDC_IDLEPRIVATE
+#define IDL_IDLESTATUSLOCK "IdleStatusLock" // IDC_IDLESTATUSLOCK
+#define IDL_AAENABLE "AAEnable"
+#define IDL_AASTATUS "AAStatus"
+
+#define IdleObject_IsIdle(obj) (obj->state&0x1)
+#define IdleObject_SetIdle(obj) (obj->state|=0x1)
+#define IdleObject_ClearIdle(obj) (obj->state&=~0x1)
+
+// either use meth 0,1 or figure out which one
+#define IdleObject_UseMethod0(obj) (obj->state&=~0x2)
+#define IdleObject_UseMethod1(obj) (obj->state|=0x2)
+#define IdleObject_GetMethod(obj) (obj->state&0x2)
+
+#define IdleObject_IdleCheckSaver(obj) (obj->state&0x4)
+#define IdleObject_SetSaverCheck(obj) (obj->state|=0x4)
+
+#define IdleObject_IdleCheckWorkstation(obj) (obj->state&0x8)
+#define IdleObject_SetWorkstationCheck(obj) (obj->state|=0x8)
+
+#define IdleObject_IsPrivacy(obj) (obj->state&0x10)
+#define IdleObject_SetPrivacy(obj) (obj->state|=0x10)
+
+#define IdleObject_SetStatusLock(obj) (obj->state|=0x20)
+
+#define IdleObject_IdleCheckTerminal(obj) (obj->state&0x40)
+#define IdleObject_SetTerminalCheck(obj) (obj->state|=0x40)
+
+#define IdleObject_IdleCheckFullScr(obj) (obj->state&0x80)
+#define IdleObject_SetFullScrCheck(obj) (obj->state|=0x80)
+
+//#include <Wtsapi32.h>
+
+#ifndef _INC_WTSAPI
+
+#define WTS_CURRENT_SERVER_HANDLE ((HANDLE)NULL)
+#define WTS_CURRENT_SESSION ((DWORD)-1)
+
+typedef enum _WTS_CONNECTSTATE_CLASS {
+ WTSActive, // User logged on to WinStation
+ WTSConnected, // WinStation connected to client
+ WTSConnectQuery, // In the process of connecting to client
+ WTSShadow, // Shadowing another WinStation
+ WTSDisconnected, // WinStation logged on without client
+ WTSIdle, // Waiting for client to connect
+ WTSListen, // WinStation is listening for connection
+ WTSReset, // WinStation is being reset
+ WTSDown, // WinStation is down due to error
+ WTSInit, // WinStation in initialization
+} WTS_CONNECTSTATE_CLASS;
+
+
+typedef enum _WTS_INFO_CLASS {
+ WTSInitialProgram,
+ WTSApplicationName,
+ WTSWorkingDirectory,
+ WTSOEMId,
+ WTSSessionId,
+ WTSUserName,
+ WTSWinStationName,
+ WTSDomainName,
+ WTSConnectState,
+ WTSClientBuildNumber,
+ WTSClientName,
+ WTSClientDirectory,
+ WTSClientProductId,
+ WTSClientHardwareId,
+ WTSClientAddress,
+ WTSClientDisplay,
+ WTSClientProtocolType,
+} WTS_INFO_CLASS;
+
+#endif
+
+VOID (WINAPI *_WTSFreeMemory)(PVOID);
+BOOL (WINAPI *_WTSQuerySessionInformation)(HANDLE, DWORD, WTS_INFO_CLASS, PVOID, DWORD*);
+
+BOOL bIsWTSApiPresent = FALSE;
+
+static BOOL bModuleInitialized = FALSE;
+
+BOOL InitWTSAPI()
+{
+ HMODULE hDll = LoadLibraryA("wtsapi32.dll");
+ if (hDll) {
+ _WTSFreeMemory = (VOID (WINAPI *)(PVOID))GetProcAddress(hDll, "WTSFreeMemory");
+ #ifdef UNICODE
+ _WTSQuerySessionInformation = (BOOL (WINAPI *)(HANDLE, DWORD, WTS_INFO_CLASS, PVOID, DWORD*))GetProcAddress(hDll, "WTSQuerySessionInformationW");
+ #else
+ _WTSQuerySessionInformation = (BOOL (WINAPI *)(HANDLE, DWORD, WTS_INFO_CLASS, PVOID, DWORD*))GetProcAddress(hDll, "WTSQuerySessionInformationA");
+ #endif
+
+ if (_WTSFreeMemory && _WTSQuerySessionInformation) return 1;
+ }
+ return 0;
+}
+
+BOOL IsTerminalDisconnected()
+{
+ PVOID pBuffer = NULL;
+ DWORD pBytesReturned = 0;
+ BOOL result = FALSE;
+
+ if ( !bIsWTSApiPresent )
+ return FALSE;
+
+ if ( _WTSQuerySessionInformation( WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, WTSConnectState, &pBuffer, &pBytesReturned)) {
+ if ( *( PDWORD )pBuffer == WTSDisconnected)
+ result = TRUE;
+ }
+ else bIsWTSApiPresent = FALSE;
+
+ if ( pBuffer )
+ _WTSFreeMemory( pBuffer );
+ return result;
+}
+
+typedef struct {
+ UINT_PTR hTimer;
+ unsigned int useridlecheck;
+ unsigned int state;
+ unsigned int minutes; // user setting, number of minutes of inactivity to wait for
+ POINT mousepos;
+ unsigned int mouseidle;
+ int aastatus;
+ int idleType;
+}
+ IdleObject;
+
+static const WORD aa_Status[] = {ID_STATUS_AWAY, ID_STATUS_NA, ID_STATUS_OCCUPIED, ID_STATUS_DND, ID_STATUS_ONTHEPHONE, ID_STATUS_OUTTOLUNCH};
+
+static IdleObject gIdleObject;
+static HANDLE hIdleEvent;
+static BOOL (WINAPI * MyGetLastInputInfo)(PLASTINPUTINFO);
+
+void CALLBACK IdleTimer(HWND hwnd, UINT umsg, UINT_PTR idEvent, DWORD dwTime);
+
+static void IdleObject_ReadSettings(IdleObject * obj)
+{
+ obj->useridlecheck = DBGetContactSettingByte(NULL, IDLEMOD, IDL_USERIDLECHECK, 0);
+ obj->minutes = DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLETIME1ST, 10);
+ obj->aastatus = !DBGetContactSettingByte(NULL, IDLEMOD, IDL_AAENABLE, 0) ? 0 : DBGetContactSettingWord(NULL, IDLEMOD, IDL_AASTATUS, 0);
+ if ( DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLEMETHOD, 0) ) IdleObject_UseMethod1(obj);
+ else IdleObject_UseMethod0(obj);
+ if ( DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLEONSAVER, 0) ) IdleObject_SetSaverCheck(obj);
+ if ( DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLEONFULLSCR, 0) ) IdleObject_SetFullScrCheck(obj);
+ if ( DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLEONLOCK, 0 ) ) IdleObject_SetWorkstationCheck(obj);
+ if ( DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLEPRIVATE, 0) ) IdleObject_SetPrivacy(obj);
+ if ( DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLESTATUSLOCK, 0) ) IdleObject_SetStatusLock(obj);
+ if ( DBGetContactSettingByte(NULL, IDLEMOD, IDL_IDLEONTSDC, 0) ) IdleObject_SetTerminalCheck(obj);
+}
+
+static void IdleObject_Create(IdleObject * obj)
+{
+ ZeroMemory(obj, sizeof(IdleObject));
+ obj->hTimer=SetTimer(NULL, 0, 2000, IdleTimer);
+ IdleObject_ReadSettings(obj);
+}
+
+static void IdleObject_Destroy(IdleObject * obj)
+{
+ if (IdleObject_IsIdle(obj))
+ NotifyEventHooks(hIdleEvent, 0, 0);
+ IdleObject_ClearIdle(obj);
+ KillTimer(NULL, obj->hTimer);
+}
+
+static int IdleObject_IsUserIdle(IdleObject * obj)
+{
+ DWORD dwTick;
+ if ( IdleObject_GetMethod(obj) ) {
+ CallService(MS_SYSTEM_GETIDLE, 0, (LPARAM)&dwTick);
+ return GetTickCount() - dwTick > (obj->minutes * 60 * 1000);
+ }
+
+ if ( MyGetLastInputInfo != NULL ) {
+ LASTINPUTINFO ii;
+ ZeroMemory(&ii,sizeof(ii));
+ ii.cbSize=sizeof(ii);
+ if ( MyGetLastInputInfo(&ii) )
+ return GetTickCount() - ii.dwTime > (obj->minutes * 60 * 1000);
+ }
+ else {
+ POINT pt;
+ GetCursorPos(&pt);
+ if ( pt.x != obj->mousepos.x || pt.y != obj->mousepos.y ) {
+ obj->mousepos=pt;
+ obj->mouseidle=0;
+ }
+ else obj->mouseidle += 2;
+
+ if ( obj->mouseidle )
+ return obj->mouseidle * 1000 >= (obj->minutes * 60 * 1000);
+ }
+ return FALSE;
+}
+
+static bool IsWorkstationLocked (void)
+{
+ bool rc = false;
+
+ if (openInputDesktop != NULL) {
+ HDESK hDesk = openInputDesktop(0, FALSE, DESKTOP_SWITCHDESKTOP);
+ if (hDesk == NULL)
+ rc = true;
+ else if (closeDesktop != NULL)
+ closeDesktop(hDesk);
+ }
+ return rc;
+}
+
+static bool IsScreenSaverRunning(void)
+{
+ BOOL rc = FALSE;
+ SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &rc, FALSE);
+ return rc != 0;
+}
+
+bool IsFullScreen(void)
+{
+ RECT rcScreen = {0};
+
+ rcScreen.right = GetSystemMetrics(SM_CXSCREEN);
+ rcScreen.bottom = GetSystemMetrics(SM_CYSCREEN);
+
+ if (MyMonitorFromWindow)
+ {
+ HMONITOR hMon = MyMonitorFromWindow(cli.hwndContactList, MONITOR_DEFAULTTONEAREST);
+ MONITORINFO mi;
+ mi.cbSize = sizeof(mi);
+ if (MyGetMonitorInfo(hMon, &mi))
+ rcScreen = mi.rcMonitor;
+ }
+
+ HWND hWndDesktop = GetDesktopWindow();
+ HWND hWndShell = GetShellWindow();
+
+ // check foregroundwindow
+ HWND hWnd = GetForegroundWindow();
+ if (hWnd && hWnd != hWndDesktop && hWnd != hWndShell)
+ {
+ TCHAR tszClassName[128] = _T("");
+ GetClassName(hWnd, tszClassName, SIZEOF(tszClassName));
+ if (_tcscmp(tszClassName, _T("WorkerW")))
+ {
+ RECT rect, rectw, recti;
+ GetWindowRect(hWnd, &rectw);
+
+ GetClientRect(hWnd, &rect);
+ ClientToScreen(hWnd, (LPPOINT)&rect);
+ ClientToScreen(hWnd, (LPPOINT)&rect.right);
+
+ if (EqualRect(&rect, &rectw) && IntersectRect(&recti, &rect, &rcScreen) &&
+ EqualRect(&recti, &rcScreen))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static void IdleObject_Tick(IdleObject * obj)
+{
+ bool idle = false;
+ int idleType = 0, flags = 0;
+
+ if ( obj->useridlecheck && IdleObject_IsUserIdle(obj)) {
+ idleType = 1; idle = true;
+ }
+ else if ( IdleObject_IdleCheckSaver(obj) && IsScreenSaverRunning()) {
+ idleType = 2; idle = true;
+ }
+ else if ( IdleObject_IdleCheckFullScr(obj) && IsFullScreen()) {
+ idleType = 5; idle = true;
+ }
+ else if ( IdleObject_IdleCheckWorkstation(obj) && IsWorkstationLocked()) {
+ idleType = 3; idle = true;
+ }
+ else if ( IdleObject_IdleCheckTerminal(obj) && IsTerminalDisconnected()) {
+ idleType = 4; idle = true;
+ }
+
+ if ( IdleObject_IsPrivacy(obj))
+ flags |= IDF_PRIVACY;
+
+ if ( !IdleObject_IsIdle(obj) && idle ) {
+ IdleObject_SetIdle(obj);
+ obj->idleType = idleType;
+ NotifyEventHooks(hIdleEvent, 0, IDF_ISIDLE | flags);
+ }
+ if ( IdleObject_IsIdle(obj) && !idle ) {
+ IdleObject_ClearIdle(obj);
+ obj->idleType = 0;
+ NotifyEventHooks(hIdleEvent, 0, flags);
+} }
+
+void CALLBACK IdleTimer(HWND, UINT, UINT_PTR idEvent, DWORD)
+{
+ if ( gIdleObject.hTimer == idEvent )
+ IdleObject_Tick( &gIdleObject );
+}
+
+int IdleGetStatusIndex(WORD status)
+{
+ int j;
+ for (j = 0; j < SIZEOF(aa_Status); j++ )
+ if ( aa_Status[j] == status )
+ return j;
+
+ return 0;
+}
+
+static INT_PTR CALLBACK IdleOptsDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ {
+ int j;
+ int method = DBGetContactSettingByte(NULL,IDLEMOD,IDL_IDLEMETHOD, 0);
+ TranslateDialogDefault(hwndDlg);
+ CheckDlgButton(hwndDlg, IDC_IDLESHORT, DBGetContactSettingByte(NULL,IDLEMOD,IDL_USERIDLECHECK,0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_IDLEONWINDOWS, method == 0 ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_IDLEONMIRANDA, method ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_SCREENSAVER, DBGetContactSettingByte(NULL,IDLEMOD,IDL_IDLEONSAVER,0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_FULLSCREEN, DBGetContactSettingByte(NULL,IDLEMOD,IDL_IDLEONFULLSCR,0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_LOCKED, DBGetContactSettingByte(NULL,IDLEMOD,IDL_IDLEONLOCK,0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_IDLEPRIVATE, DBGetContactSettingByte(NULL,IDLEMOD,IDL_IDLEPRIVATE,0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_IDLESTATUSLOCK, DBGetContactSettingByte(NULL,IDLEMOD,IDL_IDLESTATUSLOCK,0) ? BST_CHECKED : BST_UNCHECKED);
+ if ( !bIsWTSApiPresent )
+ EnableWindow( GetDlgItem( hwndDlg, IDC_IDLETERMINAL ), FALSE );
+ else
+ CheckDlgButton(hwndDlg, IDC_IDLETERMINAL, DBGetContactSettingByte(NULL,IDLEMOD,IDL_IDLEONTSDC,0) ? BST_CHECKED : BST_UNCHECKED);
+ SendDlgItemMessage(hwndDlg, IDC_IDLESPIN, UDM_SETBUDDY, (WPARAM)GetDlgItem(hwndDlg, IDC_IDLE1STTIME), 0);
+ SendDlgItemMessage(hwndDlg, IDC_IDLESPIN, UDM_SETRANGE32, 1, 60);
+ SendDlgItemMessage(hwndDlg, IDC_IDLESPIN, UDM_SETPOS, 0, MAKELONG((short) DBGetContactSettingByte(NULL,IDLEMOD,IDL_IDLETIME1ST, 10), 0));
+ SendDlgItemMessage(hwndDlg, IDC_IDLE1STTIME, EM_LIMITTEXT, (WPARAM)2, 0);
+
+ CheckDlgButton(hwndDlg, IDC_AASHORTIDLE, DBGetContactSettingByte(NULL, IDLEMOD, IDL_AAENABLE, 0) ? BST_CHECKED:BST_UNCHECKED);
+ for ( j = 0; j < SIZEOF(aa_Status); j++ )
+ SendDlgItemMessage(hwndDlg, IDC_AASTATUS, CB_ADDSTRING, 0, ( LPARAM )cli.pfnGetStatusModeDescription( aa_Status[j], 0 ));
+
+ j = IdleGetStatusIndex((WORD)(DBGetContactSettingWord(NULL, IDLEMOD, IDL_AASTATUS, 0)));
+ SendDlgItemMessage(hwndDlg, IDC_AASTATUS, CB_SETCURSEL, j, 0);
+ SendMessage(hwndDlg, WM_USER+2, 0, 0);
+ return TRUE;
+ }
+ case WM_USER+2:
+ {
+ BOOL checked = IsDlgButtonChecked(hwndDlg, IDC_IDLESHORT) == BST_CHECKED;
+ EnableWindow(GetDlgItem(hwndDlg, IDC_IDLEONWINDOWS), checked);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_IDLEONMIRANDA), checked);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_IDLE1STTIME), checked);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_AASTATUS), IsDlgButtonChecked(hwndDlg, IDC_AASHORTIDLE)==BST_CHECKED?1:0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_IDLESTATUSLOCK), IsDlgButtonChecked(hwndDlg, IDC_AASHORTIDLE)==BST_CHECKED?1:0);
+ break;
+ }
+ case WM_NOTIFY:
+ {
+ NMHDR * hdr = (NMHDR *)lParam;
+ if ( hdr && hdr->code == PSN_APPLY ) {
+ int method = IsDlgButtonChecked(hwndDlg, IDC_IDLEONWINDOWS) == BST_CHECKED;
+ int mins = SendDlgItemMessage(hwndDlg, IDC_IDLESPIN, UDM_GETPOS, 0, 0);
+ DBWriteContactSettingByte(NULL, IDLEMOD, IDL_IDLETIME1ST, (BYTE)(HIWORD(mins) == 0 ? LOWORD(mins) : 10));
+ DBWriteContactSettingByte(NULL, IDLEMOD, IDL_USERIDLECHECK, (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_IDLESHORT) == BST_CHECKED));
+ DBWriteContactSettingByte(NULL, IDLEMOD, IDL_IDLEMETHOD, (BYTE)(method ? 0 : 1));
+ DBWriteContactSettingByte(NULL, IDLEMOD, IDL_IDLEONSAVER, (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_SCREENSAVER) == BST_CHECKED));
+ DBWriteContactSettingByte(NULL, IDLEMOD, IDL_IDLEONFULLSCR, (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_FULLSCREEN) == BST_CHECKED));
+ DBWriteContactSettingByte(NULL, IDLEMOD, IDL_IDLEONLOCK, (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_LOCKED) == BST_CHECKED));
+ DBWriteContactSettingByte(NULL, IDLEMOD, IDL_IDLEONTSDC, (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_IDLETERMINAL) == BST_CHECKED));
+ DBWriteContactSettingByte(NULL, IDLEMOD, IDL_IDLEPRIVATE, (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_IDLEPRIVATE) == BST_CHECKED));
+ DBWriteContactSettingByte(NULL, IDLEMOD, IDL_AAENABLE, (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_AASHORTIDLE)==BST_CHECKED?1:0));
+ DBWriteContactSettingByte(NULL, IDLEMOD, IDL_IDLESTATUSLOCK, (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_IDLESTATUSLOCK)==BST_CHECKED?1:0));
+ {
+ int curSel = SendDlgItemMessage(hwndDlg, IDC_AASTATUS, CB_GETCURSEL, 0, 0);
+ if ( curSel != CB_ERR ) {
+ DBWriteContactSettingWord(NULL, IDLEMOD, IDL_AASTATUS, (WORD)(aa_Status[curSel]));
+ }
+ }
+ // destroy any current idle and reset settings.
+ IdleObject_Destroy(&gIdleObject);
+ IdleObject_Create(&gIdleObject);
+ }
+ break;
+ }
+ case WM_COMMAND:
+ switch ( LOWORD( wParam )) {
+ case IDC_IDLE1STTIME:
+ {
+ int min;
+ if ( (HWND)lParam != GetFocus() || HIWORD(wParam) != EN_CHANGE ) return FALSE;
+ min=GetDlgItemInt(hwndDlg, IDC_IDLE1STTIME, NULL, FALSE);
+ if ( min == 0 && GetWindowTextLength(GetDlgItem(hwndDlg, IDC_IDLE1STTIME)) )
+ SendDlgItemMessage(hwndDlg, IDC_IDLESPIN, UDM_SETPOS, 0, MAKELONG((short) 1, 0));
+ break;
+ }
+ case IDC_IDLESHORT:
+ case IDC_AASHORTIDLE:
+ SendMessage(hwndDlg, WM_USER+2, 0, 0);
+ break;
+
+ case IDC_AASTATUS:
+ if ( HIWORD(wParam) != CBN_SELCHANGE )
+ return TRUE;
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+ return FALSE;
+}
+
+static int IdleOptInit(WPARAM wParam, LPARAM)
+{
+ OPTIONSDIALOGPAGE odp = { 0 };
+ odp.cbSize = sizeof(odp);
+ odp.position = 100000000;
+ odp.hInstance = hMirandaInst;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_IDLE);
+ odp.pszGroup = LPGEN("Status");
+ odp.pszTitle = LPGEN("Idle");
+ odp.pfnDlgProc = IdleOptsDlgProc;
+ odp.flags = ODPF_BOLDGROUPS;
+ CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
+ return 0;
+}
+
+static INT_PTR IdleGetInfo(WPARAM, LPARAM lParam)
+{
+ MIRANDA_IDLE_INFO *mii = ( MIRANDA_IDLE_INFO* )lParam;
+ if ( !mii || ( mii->cbSize != sizeof(MIRANDA_IDLE_INFO) && mii->cbSize != MIRANDA_IDLE_INFO_SIZE_1 ))
+ return 1;
+
+ mii->idleTime = gIdleObject.minutes;
+ mii->privacy = gIdleObject.state&0x10;
+ mii->aaStatus = gIdleObject.aastatus;
+ mii->aaLock = gIdleObject.state&0x20;
+
+ if ( mii->cbSize == sizeof(MIRANDA_IDLE_INFO))
+ mii->idleType = gIdleObject.idleType;
+ return 0;
+}
+
+static int IdleModernOptInit(WPARAM wParam, LPARAM)
+{
+ static const int iBoldControls[] =
+ {
+ IDC_TXT_TITLE1, IDC_TXT_TITLE2, IDC_TXT_TITLE3,
+ MODERNOPT_CTRL_LAST
+ };
+
+ MODERNOPTOBJECT obj = {0};
+ obj.cbSize = sizeof(obj);
+ obj.hInstance = hMirandaInst;
+ obj.dwFlags = MODEROPT_FLG_TCHAR | MODEROPT_FLG_NORESIZE;
+ obj.iSection = MODERNOPT_PAGE_STATUS;
+ obj.iType = MODERNOPT_TYPE_SECTIONPAGE;
+ obj.iBoldControls = (int*)iBoldControls;
+ obj.lpzTemplate = MAKEINTRESOURCEA(IDD_MODERNOPT_IDLE);
+ obj.pfnDlgProc = IdleOptsDlgProc;
+// obj.lpzClassicGroup = "Status";
+// obj.lpzClassicPage = "Messages";
+ obj.lpzHelpUrl = "http://wiki.miranda-im.org/";
+ CallService(MS_MODERNOPT_ADDOBJECT, wParam, (LPARAM)&obj);
+ return 0;
+}
+
+int LoadIdleModule(void)
+{
+ bModuleInitialized = TRUE;
+
+ bIsWTSApiPresent = InitWTSAPI();
+ MyGetLastInputInfo=(BOOL (WINAPI *)(LASTINPUTINFO*))GetProcAddress(GetModuleHandleA("user32"), "GetLastInputInfo");
+ hIdleEvent=CreateHookableEvent(ME_IDLE_CHANGED);
+ IdleObject_Create(&gIdleObject);
+ CreateServiceFunction(MS_IDLE_GETIDLEINFO, IdleGetInfo);
+ HookEvent(ME_OPT_INITIALISE, IdleOptInit);
+ HookEvent(ME_MODERNOPT_INITIALIZE, IdleModernOptInit);
+ return 0;
+}
+
+void UnloadIdleModule()
+{
+ if ( !bModuleInitialized ) return;
+
+ IdleObject_Destroy(&gIdleObject);
+ DestroyHookableEvent(hIdleEvent);
+ hIdleEvent=NULL;
+}
diff --git a/src/modules/ignore/ignore.cpp b/src/modules/ignore/ignore.cpp
new file mode 100644
index 0000000000..18ded9d972
--- /dev/null
+++ b/src/modules/ignore/ignore.cpp
@@ -0,0 +1,481 @@
+/*
+
+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 IGNOREEVENT_MAX 7
+
+static const DWORD ignoreIdToPf1[IGNOREEVENT_MAX]={PF1_IMRECV,PF1_URLRECV,PF1_FILERECV,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF};
+static const DWORD ignoreIdToPf4[IGNOREEVENT_MAX]={0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,PF4_SUPPORTTYPING};
+
+static DWORD GetMask(HANDLE hContact)
+{
+ DWORD mask=DBGetContactSettingDword(hContact,"Ignore","Mask1",(DWORD)(-1));
+ if(mask==(DWORD)(-1)) {
+ if(hContact==NULL) mask=0;
+ else {
+ if(DBGetContactSettingByte(hContact,"CList","Hidden",0) || DBGetContactSettingByte(hContact,"CList","NotOnList",0))
+ mask=DBGetContactSettingDword(NULL,"Ignore","Mask1",0);
+ else
+ mask=DBGetContactSettingDword(NULL,"Ignore","Default1",0);
+ }
+ }
+ return mask;
+}
+
+static void SetListGroupIcons(HWND hwndList,HANDLE hFirstItem,HANDLE hParentItem,int *groupChildCount)
+{
+ int typeOfFirst;
+ int iconOn[IGNOREEVENT_MAX]={1,1,1,1,1,1,1};
+ int childCount[IGNOREEVENT_MAX]={0,0,0,0,0,0,0},i;
+ int iImage;
+ HANDLE hItem,hChildItem;
+
+ typeOfFirst=SendMessage(hwndList,CLM_GETITEMTYPE,(WPARAM)hFirstItem,0);
+ //check groups
+ if(typeOfFirst==CLCIT_GROUP) hItem=hFirstItem;
+ else hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTGROUP,(LPARAM)hFirstItem);
+ while(hItem) {
+ hChildItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_CHILD,(LPARAM)hItem);
+ if(hChildItem) SetListGroupIcons(hwndList,hChildItem,hItem,childCount);
+ for(i=0; i < SIZEOF(iconOn); i++)
+ if(iconOn[i] && SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,i)==0) iconOn[i]=0;
+ hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTGROUP,(LPARAM)hItem);
+ }
+ //check contacts
+ if(typeOfFirst==CLCIT_CONTACT) hItem=hFirstItem;
+ else hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTCONTACT,(LPARAM)hFirstItem);
+ while(hItem) {
+ for( i=0; i < SIZEOF(iconOn); i++ ) {
+ iImage=SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,i);
+ if(iconOn[i] && iImage==0) iconOn[i]=0;
+ if(iImage!=0xFF) childCount[i]++;
+ }
+ hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTCONTACT,(LPARAM)hItem);
+ }
+ //set icons
+ for( i=0; i < SIZEOF(iconOn); i++ ) {
+ SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hParentItem,MAKELPARAM(i,childCount[i]?(iconOn[i]?i+3:0):0xFF));
+ if(groupChildCount) groupChildCount[i]+=childCount[i];
+ }
+ SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hParentItem,MAKELPARAM(IGNOREEVENT_MAX,1));
+ SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hParentItem,MAKELPARAM(IGNOREEVENT_MAX+1,2));
+}
+
+static void SetAllChildIcons(HWND hwndList,HANDLE hFirstItem,int iColumn,int iImage)
+{
+ int typeOfFirst,iOldIcon;
+ HANDLE hItem,hChildItem;
+
+ typeOfFirst=SendMessage(hwndList,CLM_GETITEMTYPE,(WPARAM)hFirstItem,0);
+ //check groups
+ if(typeOfFirst==CLCIT_GROUP) hItem=hFirstItem;
+ else hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTGROUP,(LPARAM)hFirstItem);
+ while(hItem) {
+ hChildItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_CHILD,(LPARAM)hItem);
+ if(hChildItem) SetAllChildIcons(hwndList,hChildItem,iColumn,iImage);
+ hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTGROUP,(LPARAM)hItem);
+ }
+ //check contacts
+ if(typeOfFirst==CLCIT_CONTACT) hItem=hFirstItem;
+ else hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTCONTACT,(LPARAM)hFirstItem);
+ while(hItem) {
+ iOldIcon=SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,iColumn);
+ if(iOldIcon!=0xFF && iOldIcon!=iImage) SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(iColumn,iImage));
+ hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTCONTACT,(LPARAM)hItem);
+ }
+}
+
+static void ResetListOptions(HWND hwndList)
+{
+ int i;
+
+ SendMessage(hwndList,CLM_SETBKBITMAP,0,(LPARAM)(HBITMAP)NULL);
+ SendMessage(hwndList,CLM_SETBKCOLOR,GetSysColor(COLOR_WINDOW),0);
+ SendMessage(hwndList,CLM_SETGREYOUTFLAGS,0,0);
+ SendMessage(hwndList,CLM_SETLEFTMARGIN,4,0);
+ SendMessage(hwndList,CLM_SETINDENT,10,0);
+ SendMessage(hwndList,CLM_SETHIDEEMPTYGROUPS,1,0);
+ for(i=0;i<=FONTID_MAX;i++)
+ SendMessage(hwndList,CLM_SETTEXTCOLOR,i,GetSysColor(COLOR_WINDOWTEXT));
+}
+
+static void SetIconsForColumn(HWND hwndList,HANDLE hItem,HANDLE hItemAll,int iColumn,int iImage)
+{
+ int itemType;
+
+ itemType=SendMessage(hwndList,CLM_GETITEMTYPE,(WPARAM)hItem,0);
+ if(itemType==CLCIT_CONTACT) {
+ int oldiImage = SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,iColumn);
+ if (oldiImage!=0xFF&&oldiImage!=iImage)
+ SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(iColumn,iImage));
+ }
+ else if(itemType==CLCIT_INFO) {
+ if(hItem==hItemAll) SetAllChildIcons(hwndList,hItem,iColumn,iImage);
+ else SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(iColumn,iImage)); //hItemUnknown
+ }
+ else if(itemType==CLCIT_GROUP) {
+ hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_CHILD,(LPARAM)hItem);
+ if(hItem) SetAllChildIcons(hwndList,hItem,iColumn,iImage);
+ }
+}
+
+static void InitialiseItem(HWND hwndList,HANDLE hContact,HANDLE hItem,DWORD proto1Caps,DWORD proto4Caps)
+{
+ DWORD mask;
+ int i;
+
+ mask=GetMask(hContact);
+ for(i=0;i<IGNOREEVENT_MAX;i++)
+ if((ignoreIdToPf1[i]==0xFFFFFFFF&&ignoreIdToPf4[i]==0xFFFFFFFF) || (proto1Caps&ignoreIdToPf1[i]||proto4Caps&ignoreIdToPf4[i]))
+ SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(i,mask&(1<<i)?i+3:0));
+ SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(IGNOREEVENT_MAX,1));
+ SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(IGNOREEVENT_MAX+1,2));
+}
+
+static void SaveItemMask(HWND hwndList,HANDLE hContact,HANDLE hItem,const char *pszSetting)
+{
+ DWORD mask;
+ int i,iImage;
+
+ mask=0;
+ for(i=0;i<IGNOREEVENT_MAX;i++) {
+ iImage=SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(i,0));
+ if(iImage && iImage!=0xFF) mask|=1<<i;
+ }
+ DBWriteContactSettingDword(hContact,"Ignore",pszSetting,mask);
+}
+
+static void SetAllContactIcons(HWND hwndList)
+{
+ HANDLE hContact,hItem;
+ DWORD proto1Caps, proto4Caps;
+ char *szProto;
+
+ hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDFIRST,0,0);
+ do {
+ hItem=(HANDLE)SendMessage(hwndList,CLM_FINDCONTACT,(WPARAM)hContact,0);
+ if(hItem && SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(IGNOREEVENT_MAX,0))==0xFF) {
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hContact,0);
+ if(szProto==NULL) proto1Caps=proto4Caps=0;
+ else {
+ proto1Caps=CallProtoService(szProto,PS_GETCAPS,PFLAGNUM_1,0);
+ proto4Caps=CallProtoService(szProto,PS_GETCAPS,PFLAGNUM_4,0);
+ }
+ InitialiseItem(hwndList,hContact,hItem,proto1Caps,proto4Caps);
+ if(!DBGetContactSettingByte(hContact,"CList","Hidden",0))
+ SendMessage(hwndList,CLM_SETCHECKMARK,(WPARAM)hItem,1);
+ }
+ } while(hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)hContact,0));
+}
+
+static INT_PTR CALLBACK DlgProcIgnoreOpts(HWND hwndDlg, UINT msg, WPARAM, LPARAM lParam)
+{
+ static HICON hIcons[IGNOREEVENT_MAX+2];
+ static HANDLE hItemAll,hItemUnknown;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ { HIMAGELIST hIml;
+ int i;
+ hIml=ImageList_Create(GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),(IsWinVerXPPlus()?ILC_COLOR32:ILC_COLOR16)|ILC_MASK,3+IGNOREEVENT_MAX,3+IGNOREEVENT_MAX);
+ ImageList_AddIcon_IconLibLoaded(hIml,SKINICON_OTHER_SMALLDOT);
+ ImageList_AddIcon_IconLibLoaded(hIml,SKINICON_OTHER_FILLEDBLOB);
+ ImageList_AddIcon_IconLibLoaded(hIml,SKINICON_OTHER_EMPTYBLOB);
+ ImageList_AddIcon_IconLibLoaded(hIml,SKINICON_EVENT_MESSAGE);
+ ImageList_AddIcon_IconLibLoaded(hIml,SKINICON_EVENT_URL);
+ ImageList_AddIcon_IconLibLoaded(hIml,SKINICON_EVENT_FILE);
+ ImageList_AddIcon_IconLibLoaded(hIml,SKINICON_OTHER_USERONLINE);
+ ImageList_AddIcon_IconLibLoaded(hIml,SKINICON_OTHER_MIRANDA);
+ ImageList_AddIcon_IconLibLoaded(hIml,SKINICON_OTHER_ADDCONTACT);
+ ImageList_AddIcon_IconLibLoaded(hIml,SKINICON_OTHER_TYPING);
+
+ SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_SETEXTRAIMAGELIST,0,(LPARAM)hIml);
+ for( i=0; i < SIZEOF(hIcons); i++ )
+ hIcons[i]=ImageList_GetIcon(hIml,1+i,ILD_NORMAL);
+ }
+
+ SendDlgItemMessage(hwndDlg,IDC_ALLICON,STM_SETICON,(WPARAM)hIcons[0],0);
+ SendDlgItemMessage(hwndDlg,IDC_NONEICON,STM_SETICON,(WPARAM)hIcons[1],0);
+ SendDlgItemMessage(hwndDlg,IDC_MSGICON,STM_SETICON,(WPARAM)hIcons[2],0);
+ SendDlgItemMessage(hwndDlg,IDC_URLICON,STM_SETICON,(WPARAM)hIcons[3],0);
+ SendDlgItemMessage(hwndDlg,IDC_FILEICON,STM_SETICON,(WPARAM)hIcons[4],0);
+ SendDlgItemMessage(hwndDlg,IDC_ONLINEICON,STM_SETICON,(WPARAM)hIcons[5],0);
+ SendDlgItemMessage(hwndDlg,IDC_AUTHICON,STM_SETICON,(WPARAM)hIcons[6],0);
+ SendDlgItemMessage(hwndDlg,IDC_ADDED,STM_SETICON,(WPARAM)hIcons[7],0);
+ SendDlgItemMessage(hwndDlg,IDC_TYPINGICON,STM_SETICON,(WPARAM)hIcons[8],0);
+
+ if(!SendMessage(GetParent(hwndDlg),PSM_ISEXPERT,0,0)) {
+ SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_LIST),GWL_STYLE,GetWindowLongPtr(GetDlgItem(hwndDlg,IDC_LIST),GWL_STYLE)&~(CLS_CHECKBOXES|CLS_GROUPCHECKBOXES|CLS_SHOWHIDDEN));
+ SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_AUTOREBUILD,0,0);
+ }
+
+ ResetListOptions(GetDlgItem(hwndDlg,IDC_LIST));
+ SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_SETEXTRACOLUMNS,IGNOREEVENT_MAX+2,0);
+
+ { CLCINFOITEM cii={0};
+ cii.cbSize=sizeof(cii);
+ cii.flags=CLCIIF_GROUPFONT;
+ cii.pszText=TranslateT("** All contacts **");
+ hItemAll=(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_ADDINFOITEM,0,(LPARAM)&cii);
+
+ cii.pszText=TranslateT("** Unknown contacts **");
+ hItemUnknown=(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_ADDINFOITEM,0,(LPARAM)&cii);
+ InitialiseItem(GetDlgItem(hwndDlg,IDC_LIST),NULL,hItemUnknown,0xFFFFFFFF,0xFFFFFFFF);
+ }
+
+ SetAllContactIcons(GetDlgItem(hwndDlg,IDC_LIST));
+ SetListGroupIcons(GetDlgItem(hwndDlg,IDC_LIST),(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETNEXTITEM,CLGN_ROOT,0),hItemAll,NULL);
+ return TRUE;
+ case WM_SETFOCUS:
+ SetFocus(GetDlgItem(hwndDlg,IDC_LIST));
+ break;
+ case WM_NOTIFY:
+ switch(((LPNMHDR)lParam)->idFrom) {
+ case IDC_LIST:
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case CLN_NEWCONTACT:
+ case CLN_LISTREBUILT:
+ SetAllContactIcons(GetDlgItem(hwndDlg,IDC_LIST));
+ //fall through
+ case CLN_CONTACTMOVED:
+ SetListGroupIcons(GetDlgItem(hwndDlg,IDC_LIST),(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETNEXTITEM,CLGN_ROOT,0),hItemAll,NULL);
+ break;
+ case CLN_OPTIONSCHANGED:
+ ResetListOptions(GetDlgItem(hwndDlg,IDC_LIST));
+ break;
+ case CLN_CHECKCHANGED:
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case NM_CLICK:
+ { HANDLE hItem;
+ NMCLISTCONTROL *nm=(NMCLISTCONTROL*)lParam;
+ DWORD hitFlags;
+ int iImage;
+
+ if(nm->iColumn==-1) break;
+ hItem=(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_HITTEST,(WPARAM)&hitFlags,MAKELPARAM(nm->pt.x,nm->pt.y));
+ if(hItem==NULL) break;
+ if(!(hitFlags&CLCHT_ONITEMEXTRA)) break;
+ if(nm->iColumn==IGNOREEVENT_MAX) { //ignore all
+ for(iImage=0;iImage<IGNOREEVENT_MAX;iImage++)
+ SetIconsForColumn(GetDlgItem(hwndDlg,IDC_LIST),hItem,hItemAll,iImage,iImage+3);
+ }
+ else if(nm->iColumn==IGNOREEVENT_MAX+1) { //ignore none
+ for(iImage=0;iImage<IGNOREEVENT_MAX;iImage++)
+ SetIconsForColumn(GetDlgItem(hwndDlg,IDC_LIST),hItem,hItemAll,iImage,0);
+ }
+ else {
+ iImage=SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(nm->iColumn,0));
+ if(iImage==0) iImage=nm->iColumn+3;
+ else if(iImage!=0xFF) iImage=0;
+ SetIconsForColumn(GetDlgItem(hwndDlg,IDC_LIST),hItem,hItemAll,nm->iColumn,iImage);
+ }
+ SetListGroupIcons(GetDlgItem(hwndDlg,IDC_LIST),(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETNEXTITEM,CLGN_ROOT,0),hItemAll,NULL);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+ }
+ break;
+ case 0:
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case PSN_APPLY:
+ { HANDLE hContact,hItem;
+
+ hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDFIRST,0,0);
+ do {
+ hItem=(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_FINDCONTACT,(WPARAM)hContact,0);
+ if(hItem) SaveItemMask(GetDlgItem(hwndDlg,IDC_LIST),hContact,hItem,"Mask1");
+ if(SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETCHECKMARK,(WPARAM)hItem,0))
+ DBDeleteContactSetting(hContact,"CList","Hidden");
+ else
+ DBWriteContactSettingByte(hContact,"CList","Hidden",1);
+ } while(hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)hContact,0));
+ SaveItemMask(GetDlgItem(hwndDlg,IDC_LIST),NULL,hItemAll,"Default1");
+ SaveItemMask(GetDlgItem(hwndDlg,IDC_LIST),NULL,hItemUnknown,"Mask1");
+ return TRUE;
+ }
+ case PSN_EXPERTCHANGED:
+ SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_LIST),GWL_STYLE,((PSHNOTIFY*)lParam)->lParam?GetWindowLongPtr(GetDlgItem(hwndDlg,IDC_LIST),GWL_STYLE)|CLS_CHECKBOXES|CLS_GROUPCHECKBOXES|CLS_SHOWHIDDEN:GetWindowLongPtr(GetDlgItem(hwndDlg,IDC_LIST),GWL_STYLE)&~(CLS_CHECKBOXES|CLS_GROUPCHECKBOXES|CLS_SHOWHIDDEN));
+ SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_AUTOREBUILD,0,0);
+ break;
+ }
+ break;
+ }
+ break;
+ case WM_DESTROY:
+ { int i;
+ HIMAGELIST hIml;
+ for( i=0; i < SIZEOF(hIcons); i++ )
+ DestroyIcon(hIcons[i]);
+ hIml=(HIMAGELIST)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETEXTRAIMAGELIST,0,0);
+ ImageList_Destroy(hIml);
+ break;
+ }
+ }
+ return FALSE;
+}
+
+static UINT expertOnlyControls[]={IDC_STCHECKMARKS};
+static int IgnoreOptInitialise(WPARAM wParam, LPARAM)
+{
+ OPTIONSDIALOGPAGE odp = { 0 };
+ odp.cbSize = sizeof(odp);
+ odp.position = 900000000;
+ odp.hInstance = hMirandaInst;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_IGNORE);
+ odp.pszTitle = LPGEN("Ignore");
+ odp.pszGroup = LPGEN("Events");
+ odp.pfnDlgProc = DlgProcIgnoreOpts;
+ odp.flags = ODPF_BOLDGROUPS;
+ odp.expertOnlyControls = expertOnlyControls;
+ odp.nExpertOnlyControls = SIZEOF( expertOnlyControls );
+ CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp);
+ return 0;
+}
+
+static INT_PTR IsIgnored(WPARAM wParam,LPARAM lParam)
+{
+ DWORD mask=GetMask((HANDLE)wParam);
+ if(lParam<1 || lParam>IGNOREEVENT_MAX) return 1;
+ return (mask>>(lParam-1))&1;
+}
+
+static INT_PTR Ignore(WPARAM wParam,LPARAM lParam)
+{
+ DWORD mask=GetMask((HANDLE)wParam);
+ if((lParam<1 || lParam>IGNOREEVENT_MAX) && lParam!=IGNOREEVENT_ALL) return 1;
+ if(lParam==IGNOREEVENT_ALL) mask=(1<<IGNOREEVENT_MAX)-1;
+ else mask|=1<<(lParam-1);
+ DBWriteContactSettingDword((HANDLE)wParam,"Ignore","Mask1",mask);
+ return 0;
+}
+
+static INT_PTR Unignore(WPARAM wParam,LPARAM lParam)
+{
+ DWORD mask=GetMask((HANDLE)wParam);
+ if((lParam<1 || lParam>IGNOREEVENT_MAX) && lParam!=IGNOREEVENT_ALL) return 1;
+ if(lParam==IGNOREEVENT_ALL) mask=0;
+ else mask&=~(1<<(lParam-1));
+ DBWriteContactSettingDword((HANDLE)wParam,"Ignore","Mask1",mask);
+ return 0;
+}
+
+static int IgnoreContactAdded(WPARAM wParam, LPARAM)
+{
+ CallService(MS_PROTO_ADDTOCONTACT,wParam,(LPARAM)"Ignore");
+ return 0;
+}
+
+static INT_PTR IgnoreRecvMessage(WPARAM wParam,LPARAM lParam)
+{
+ if(IsIgnored((WPARAM)((CCSDATA*)lParam)->hContact,IGNOREEVENT_MESSAGE)) return 1;
+ return CallService(MS_PROTO_CHAINRECV,wParam,lParam);
+}
+
+static INT_PTR IgnoreRecvUrl(WPARAM wParam,LPARAM lParam)
+{
+ if(IsIgnored((WPARAM)((CCSDATA*)lParam)->hContact,IGNOREEVENT_URL)) return 1;
+ return CallService(MS_PROTO_CHAINRECV,wParam,lParam);
+}
+
+static INT_PTR IgnoreRecvFile(WPARAM wParam,LPARAM lParam)
+{
+ if(IsIgnored((WPARAM)((CCSDATA*)lParam)->hContact,IGNOREEVENT_FILE)) return 1;
+ return CallService(MS_PROTO_CHAINRECV,wParam,lParam);
+}
+
+static INT_PTR IgnoreRecvAuth(WPARAM wParam,LPARAM lParam)
+{
+ if(IsIgnored((WPARAM)((CCSDATA*)lParam)->hContact,IGNOREEVENT_AUTHORIZATION)) return 1;
+ return CallService(MS_PROTO_CHAINRECV,wParam,lParam);
+}
+
+static int IgnoreAddedNotify(WPARAM, LPARAM lParam)
+{
+ DBEVENTINFO *dbei=(DBEVENTINFO*)lParam;
+ if (dbei && dbei->eventType==EVENTTYPE_ADDED && dbei->pBlob!=NULL) {
+ HANDLE hContact;
+
+ hContact=*((PHANDLE)(dbei->pBlob+sizeof(DWORD)));
+ if (CallService(MS_DB_CONTACT_IS,(WPARAM)hContact,0) && IsIgnored((WPARAM)hContact,IGNOREEVENT_YOUWEREADDED))
+ return 1;
+ }
+ return 0;
+}
+
+static int IgnoreModernOptInit(WPARAM wParam, LPARAM)
+{
+ static int iBoldControls[] =
+ {
+ IDC_TXT_TITLE1, IDC_TXT_TITLE2, IDC_TXT_TITLE3,
+ MODERNOPT_CTRL_LAST
+ };
+
+ MODERNOPTOBJECT obj = {0};
+ obj.cbSize = sizeof(obj);
+ obj.hInstance = hMirandaInst;
+ obj.dwFlags = MODEROPT_FLG_TCHAR;
+ obj.iSection = MODERNOPT_PAGE_IGNORE;
+ obj.iType = MODERNOPT_TYPE_SECTIONPAGE;
+ obj.iBoldControls = iBoldControls;
+ obj.lpzTemplate = MAKEINTRESOURCEA(IDD_MODERNOPT_IGNORE);
+ obj.pfnDlgProc = DlgProcIgnoreOpts;
+// obj.lpzClassicGroup = "Events";
+// obj.lpzClassicPage = "Ignore";
+ CallService(MS_MODERNOPT_ADDOBJECT, wParam, (LPARAM)&obj);
+ return 0;
+}
+
+int LoadIgnoreModule(void)
+{
+ PROTOCOLDESCRIPTOR pd = { 0 };
+ pd.cbSize=sizeof(pd);
+ pd.szName="Ignore";
+ pd.type=PROTOTYPE_IGNORE;
+ CallService(MS_PROTO_REGISTERMODULE,0,(LPARAM)&pd);
+
+ HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST,0,0);
+ while ( hContact != NULL ) {
+ if (!CallService(MS_PROTO_ISPROTOONCONTACT,(WPARAM)hContact,(LPARAM)"Ignore"))
+ CallService(MS_PROTO_ADDTOCONTACT,(WPARAM)hContact,(LPARAM)"Ignore");
+ hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)hContact,0);
+ }
+
+ CreateServiceFunction("Ignore"PSR_MESSAGE,IgnoreRecvMessage);
+ CreateServiceFunction("Ignore"PSR_URL,IgnoreRecvUrl);
+ CreateServiceFunction("Ignore"PSR_FILE,IgnoreRecvFile);
+ CreateServiceFunction("Ignore"PSR_AUTH,IgnoreRecvAuth);
+ CreateServiceFunction(MS_IGNORE_ISIGNORED,IsIgnored);
+ CreateServiceFunction(MS_IGNORE_IGNORE,Ignore);
+ CreateServiceFunction(MS_IGNORE_UNIGNORE,Unignore);
+
+ HookEvent(ME_DB_CONTACT_ADDED,IgnoreContactAdded);
+ HookEvent(ME_DB_EVENT_FILTER_ADD,IgnoreAddedNotify);
+ HookEvent(ME_MODERNOPT_INITIALIZE, IgnoreModernOptInit);
+ HookEvent(ME_OPT_INITIALISE,IgnoreOptInitialise);
+ return 0;
+}
diff --git a/src/modules/keybindings/keybindings.cpp b/src/modules/keybindings/keybindings.cpp
new file mode 100644
index 0000000000..6255cc78e9
--- /dev/null
+++ b/src/modules/keybindings/keybindings.cpp
@@ -0,0 +1,616 @@
+/*
+
+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 "keybindings.h"
+#include "m_keybindings.h"
+
+static HANDLE hKeyBindings_Register;
+static HANDLE hKeyBindings_Get;
+static WNDPROC OldEditProc;
+static TCHAR *keySeparator = _T(" + ");
+static TreeItem *currentTreeItem = NULL;
+static DWORD tempModifiers;
+static DWORD modifiers;
+static DWORD virtualKey;
+
+static int addKeyBinding(KEYBINDINGDESC *desc) {
+ int i, len;
+ TCHAR *sectionName;
+ TCHAR *actionName;
+ KeyBindingItem *item = (KeyBindingItem *)mir_alloc(sizeof(KeyBindingItem));
+ ZeroMemory(item, sizeof(KeyBindingItem));
+ if (desc->flags & KBDF_UNICODE) {
+ #ifdef _UNICODE
+ sectionName = mir_tstrdup(desc->ptszSection);
+ actionName = mir_tstrdup(desc->ptszActionName);
+ #else
+ sectionName = u2a(desc->pwszSection);
+ actionName = u2a(desc->pwszActionName);
+ #endif
+ } else {
+ #ifdef _UNICODE
+ sectionName = a2u(desc->pszSection);
+ actionName = a2u(desc->pszActionName);
+ #else
+ sectionName = mir_tstrdup(desc->ptszSection);
+ actionName = mir_tstrdup(desc->ptszActionName);
+ #endif
+ }
+ len = _tcslen(sectionName) + _tcslen(actionName) + 2;
+ item->fullActionName = (TCHAR *)mir_alloc(len * sizeof(TCHAR));
+ _tcscpy(item->fullActionName, sectionName);
+ _tcscat(item->fullActionName, _T("/"));
+ _tcscat(item->fullActionName, actionName);
+ item->actionName = actionName;
+ mir_free(sectionName);
+ item->actionGroupName = mir_strdup(desc->pszActionGroup);
+ item->action = desc->action;
+ for (i = 0; i < 5; i++) {
+ item->defaultKey[i] = desc->key[i];
+ item->key[i] = desc->key[i];
+ }
+
+ item->next = keyBindingList;
+ keyBindingList = item;
+ if (item->next != NULL)
+ item->next->prev = item;
+ {
+ DBVARIANT dbv;
+ char *paramName = mir_t2a(item->fullActionName);
+ if ( !DBGetContactSettingString(NULL, "KeyBindings", paramName, &dbv )) {
+ for (i = 0; i < 5; i++)
+ item->key[i] = 0;
+ sscanf(dbv.pszVal, "%X,%X,%X,%X,%X", &item->key[0],&item->key[1],&item->key[2],&item->key[3],&item->key[4]);
+ DBFreeVariant(&dbv);
+ }
+ mir_free(paramName);
+ }
+ return 0;
+}
+
+static KeyBindingItem* findKeyBinding(char *actionGroup, DWORD key)
+{
+ int i;
+ KeyBindingItem *ptr = NULL;
+ if (key != 0) {
+ for (ptr = keyBindingList; ptr != NULL; ptr = ptr->next)
+ if (strcmp(ptr->actionGroupName, actionGroup) == 0)
+ for (i = 0; i < 5; i++)
+ if (ptr->key[i] == key) return ptr;
+ }
+ return ptr;
+}
+
+static KeyBindingItem* findTempKeyBinding(char *actionGroup, DWORD key)
+{
+ int i;
+ KeyBindingItem *ptr = NULL;
+ if (key != 0) {
+ for (ptr = keyBindingList; ptr != NULL; ptr = ptr->next)
+ if (strcmp(ptr->actionGroupName, actionGroup) == 0)
+ for (i = 0; i < 5; i++)
+ if (ptr->tempKey[i] == key) return ptr;
+ }
+ return ptr;
+}
+
+static void removeTempKeyBinding(char *actionGroup, DWORD key)
+{
+ KeyBindingItem *ptr = NULL;
+ int i, j;
+ if (key != 0) {
+ for (ptr = keyBindingList; ptr != NULL; ptr = ptr->next)
+ if (strcmp(ptr->actionGroupName, actionGroup) == 0)
+ for (i = 0; i < 5; i++)
+ if (ptr->tempKey[i] == key) {
+ for (j = i+1; j < 5; j++)
+ ptr->tempKey[j-1] = ptr->tempKey[j];
+ ptr->tempKey[4] = 0;
+ }
+ }
+}
+
+static void loadTempKeyBinding(KeyBindingItem *item)
+{
+ int i;
+ for (i = 0; i < 5; i ++)
+ item->tempKey[i] = item->key[i];
+}
+
+static void loadTempKeyBindings()
+{
+ KeyBindingItem *ptr;
+ for (ptr = keyBindingList; ptr != NULL; ptr = ptr->next)
+ loadTempKeyBinding(ptr);
+}
+
+static void saveKeyBinding(KeyBindingItem *item)
+{
+ BOOL save = FALSE;
+ int i;
+ char buff[128];
+ for (i = 0; i < 5; i ++) {
+ if (item->key[i] != item->tempKey[i]) {
+ item->key[i] = item->tempKey[i];
+ save = TRUE;
+ }
+ }
+ if (save) {
+ char *paramName = mir_t2a(item->fullActionName);
+ mir_snprintf(buff, sizeof(buff), "%X,%X,%X,%X,%X", item->key[0],item->key[1],item->key[2],item->key[3],item->key[4]);
+ DBWriteContactSettingString(NULL, "KeyBindings", paramName, buff);
+ mir_free(paramName);
+ }
+}
+
+static void saveKeyBindings()
+{
+ KeyBindingItem *ptr;
+ for (ptr = keyBindingList; ptr != NULL; ptr = ptr->next)
+ saveKeyBinding(ptr);
+}
+
+static HTREEITEM findNamedTreeItemAt(HWND hwndTree, HTREEITEM hItem, const TCHAR *name)
+{
+ TVITEM tvi = {0};
+ TCHAR str[MAX_PATH];
+
+ if (hItem)
+ tvi.hItem = TreeView_GetChild(hwndTree, hItem);
+ else
+ tvi.hItem = TreeView_GetRoot(hwndTree);
+
+ if (!name)
+ return tvi.hItem;
+
+ tvi.mask = TVIF_TEXT;
+ tvi.pszText = str;
+ tvi.cchTextMax = MAX_PATH;
+
+ while (tvi.hItem)
+ {
+ TreeView_GetItem(hwndTree, &tvi);
+ if (!lstrcmp(tvi.pszText, name))
+ return tvi.hItem;
+
+ tvi.hItem = TreeView_GetNextSibling(hwndTree, tvi.hItem);
+ }
+ return NULL;
+}
+
+static void createSettingsTreeNode(HWND hwndTree, KeyBindingItem *keyBindingItem)
+{
+ TCHAR itemName[1024];
+ TCHAR* sectionName;
+ int sectionLevel = 0;
+
+ HTREEITEM hSection = NULL;
+ lstrcpy(itemName, keyBindingItem->fullActionName);
+ sectionName = itemName;
+
+ while (sectionName) {
+ HTREEITEM hItem;
+ TCHAR* pTranslatedItemName;
+ TCHAR* pItemName = sectionName;
+
+ if (sectionName = _tcschr(sectionName, '/')) {
+ *sectionName = 0;
+ }
+ pTranslatedItemName = TranslateTS( pItemName );
+ hItem = findNamedTreeItemAt(hwndTree, hSection, pTranslatedItemName);
+ if (!sectionName || !hItem) {
+ if (!hItem) {
+ TVINSERTSTRUCT tvis = {0};
+ TreeItem *treeItem = (TreeItem *)mir_alloc(sizeof(TreeItem));
+ treeItem->keyBinding = !sectionName ? keyBindingItem : NULL;
+ treeItem->paramName = mir_t2a(itemName);
+ tvis.hParent = hSection;
+ tvis.hInsertAfter = TVI_SORT; //!sectionName ? TVI_LAST : TVI_SORT;
+ tvis.item.mask = TVIF_TEXT|TVIF_PARAM|TVIF_STATE;
+ tvis.item.pszText = pTranslatedItemName;
+ tvis.item.lParam = (LPARAM)treeItem;
+ tvis.item.state = tvis.item.stateMask = DBGetContactSettingByte(NULL, "KeyBindingsUI", treeItem->paramName, TVIS_EXPANDED );
+ hItem = TreeView_InsertItem(hwndTree, &tvis);
+ }
+ }
+ if (sectionName) {
+ *sectionName = '/';
+ sectionName++;
+ }
+ sectionLevel++;
+ hSection = hItem;
+ }
+}
+
+static void saveCollapseState( HWND hwndTree )
+{
+ HTREEITEM hti;
+ TVITEM tvi;
+ hti = TreeView_GetRoot( hwndTree );
+ while( hti != NULL ) {
+ HTREEITEM ht;
+ tvi.mask = TVIF_STATE | TVIF_HANDLE | TVIF_CHILDREN | TVIF_PARAM;
+ tvi.hItem = hti;
+ tvi.stateMask = (DWORD)-1;
+ TreeView_GetItem( hwndTree, &tvi );
+ if( tvi.cChildren > 0 ) {
+ TreeItem *treeItem = (TreeItem *)tvi.lParam;
+ if ( tvi.state & TVIS_EXPANDED )
+ DBWriteContactSettingByte(NULL, "KeyBindingsUI", treeItem->paramName, TVIS_EXPANDED );
+ else
+ DBWriteContactSettingByte(NULL, "KeyBindingsUI", treeItem->paramName, 0 );
+ }
+ ht = TreeView_GetChild( hwndTree, hti );
+ if( ht == NULL ) {
+ ht = TreeView_GetNextSibling( hwndTree, hti );
+ while( ht == NULL ) {
+ hti = TreeView_GetParent( hwndTree, hti );
+ if( hti == NULL ) break;
+ ht = TreeView_GetNextSibling( hwndTree, hti );
+ } }
+ hti = ht;
+} }
+
+
+static const TCHAR* getKeyName(DWORD key) {
+ static TCHAR keyName[64];
+ int nameLen = 0;
+ ZeroMemory(keyName, sizeof(keyName));
+ if (key & KB_CTRL_FLAG) {
+ GetKeyNameText(MAKELPARAM(0, MapVirtualKey(VK_CONTROL, 0)), keyName, 64);
+ _tcscat(keyName, keySeparator);
+ nameLen = _tcslen(keyName);
+ }
+ if (key & KB_SHIFT_FLAG) {
+ GetKeyNameText(MAKELPARAM(0, MapVirtualKey(VK_SHIFT, 0)), &keyName[nameLen], 64 - nameLen);
+ _tcscat(keyName, keySeparator);
+ nameLen = _tcslen(keyName);
+ }
+ if (key & KB_ALT_FLAG) {
+ GetKeyNameText(MAKELPARAM(0, MapVirtualKey(VK_MENU, 0)), &keyName[nameLen], 64 - nameLen);
+ _tcscat(keyName, keySeparator);
+ nameLen = _tcslen(keyName);
+ }
+ if ((key & 0xFFFF) != 0) {
+ DWORD scanCode = MapVirtualKey(key & 0xFFFF, 0);
+ switch(key & 0xFFFF) {
+ case VK_INSERT:
+ case VK_DELETE:
+ case VK_HOME:
+ case VK_END:
+ case VK_NEXT:
+ case VK_PRIOR:
+ case VK_LEFT:
+ case VK_RIGHT:
+ case VK_UP:
+ case VK_DOWN:
+ scanCode |= 0x100; // Add extended bit
+ }
+ GetKeyNameText(MAKELPARAM(0, scanCode), &keyName[nameLen], 64 - nameLen);
+ nameLen = _tcslen(keyName);
+ }
+ return keyName;
+}
+
+static refreshPreview(HWND hwnd)
+{
+ TCHAR warning[1024];
+ ZeroMemory(warning, sizeof(warning));
+ SetWindowText(hwnd, getKeyName(virtualKey | modifiers));
+ if (currentTreeItem != NULL && currentTreeItem->keyBinding != NULL) {
+ KeyBindingItem *item = findTempKeyBinding(currentTreeItem->keyBinding->actionGroupName, virtualKey | modifiers);
+ if (item != NULL)
+ mir_sntprintf(warning, 1024, TranslateT("Shortcut already assigned to \"%s\" action.\nIf you click \"Add\" the shortcut will be reassigned."), item->actionName);
+ }
+ SetDlgItemText(GetParent(hwnd), IDC_MESSAGE, warning);
+ EnableWindow(GetDlgItem(GetParent(hwnd), IDC_ADD), virtualKey != 0);
+}
+
+static LRESULT CALLBACK KeyBindingsEditProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_CREATE:
+ virtualKey = 0;
+ break;
+ case WM_SYSKEYDOWN:
+ case WM_KEYDOWN:
+ if (virtualKey != 0) {
+ virtualKey = 0;
+ }
+ switch (wParam)
+ {
+ case VK_SHIFT:
+ tempModifiers |= KB_SHIFT_FLAG;
+ break;
+ case VK_CONTROL:
+ tempModifiers |= KB_CTRL_FLAG;
+ break;
+ case VK_MENU:
+ tempModifiers |= KB_ALT_FLAG;
+ break;
+ default:
+ virtualKey = wParam;
+ break;
+ }
+ modifiers = tempModifiers;
+ refreshPreview(hwnd);
+ return 0;
+ case WM_KEYUP:
+ case WM_SYSKEYUP:
+ switch (wParam)
+ {
+ case VK_SHIFT:
+ tempModifiers &= ~KB_SHIFT_FLAG;
+ break;
+ case VK_CONTROL:
+ tempModifiers &= ~KB_CTRL_FLAG;
+ break;
+ case VK_MENU:
+ tempModifiers &= ~KB_ALT_FLAG;
+ break;
+ default:
+ break;
+ }
+ if (virtualKey == 0) {
+ modifiers = tempModifiers;
+ refreshPreview(hwnd);
+ }
+ case WM_CHAR:
+ case WM_PASTE:
+ return 0;
+ case WM_SETFOCUS:
+ modifiers = 0;
+ tempModifiers = 0;
+ virtualKey = 0;
+ refreshPreview(hwnd);
+ break;
+ case WM_GETDLGCODE:
+ return DLGC_WANTARROWS|DLGC_WANTALLKEYS| DLGC_WANTTAB;
+ }
+ return CallWindowProc(OldEditProc, hwnd, msg, wParam, lParam);
+}
+
+static void buildTree(HWND hwnd) {
+ KeyBindingItem *ptr;
+ for (ptr = keyBindingList; ptr != NULL; ptr=ptr->next) {
+ createSettingsTreeNode(hwnd, ptr);
+ }
+}
+
+static void refreshListBox(HWND hwnd) {
+ int count = 0;
+ BOOL nonDefault = FALSE;
+ BOOL canUndo = FALSE;
+ SendDlgItemMessage(hwnd, IDC_LIST, LB_RESETCONTENT, 0, 0);
+ if (currentTreeItem->keyBinding != NULL) {
+ int i;
+ for (i=0; i<5; i++) {
+ if (currentTreeItem->keyBinding->tempKey[i] != currentTreeItem->keyBinding->defaultKey[i]) nonDefault = TRUE;
+ if (currentTreeItem->keyBinding->tempKey[i] != currentTreeItem->keyBinding->key[i]) canUndo = TRUE;
+ if (currentTreeItem->keyBinding->tempKey[i] != 0) {
+ SendDlgItemMessage(hwnd, IDC_LIST, LB_ADDSTRING, 0, (LPARAM)getKeyName(currentTreeItem->keyBinding->tempKey[i]));
+ count++;
+ }
+ }
+ }
+ EnableWindow(GetDlgItem(hwnd, IDC_PREVIEW), currentTreeItem->keyBinding != NULL && count < 5);
+ SetDlgItemText(hwnd, IDC_PREVIEW, _T(""));
+ SetDlgItemText(hwnd, IDC_MESSAGE, _T(""));
+ EnableWindow(GetDlgItem(hwnd, IDC_ADD), FALSE);
+ EnableWindow(GetDlgItem(hwnd, IDC_DELETE), FALSE);
+ EnableWindow(GetDlgItem(hwnd, IDC_BTN_RESET), nonDefault);
+ EnableWindow(GetDlgItem(hwnd, IDC_BTN_UNDO), canUndo);
+}
+
+BOOL CALLBACK DlgProcKeyBindingsOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ {
+ TranslateDialogDefault(hwndDlg);
+ OldEditProc = (WNDPROC) SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_PREVIEW), GWLP_WNDPROC, (LONG_PTR) KeyBindingsEditProc);
+ currentTreeItem = NULL;
+ loadTempKeyBindings();
+ buildTree(GetDlgItem(hwndDlg, IDC_CATEGORYLIST));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ADD), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_DELETE), FALSE);
+ }
+ return TRUE;
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ SendDlgItemMessage(hwndDlg, IDC_PREVIEW, msg, wParam, lParam);
+ return TRUE;
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDC_ADD:
+ if (currentTreeItem->keyBinding != NULL) {
+ int i;
+ removeTempKeyBinding(currentTreeItem->keyBinding->actionGroupName, modifiers | virtualKey);
+ for (i=0; i<5; i++) {
+ if (currentTreeItem->keyBinding->tempKey[i] == 0) {
+ currentTreeItem->keyBinding->tempKey[i] = modifiers | virtualKey;
+ break;
+ }
+ }
+ }
+ refreshListBox(hwndDlg);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case IDC_DELETE:
+ if (currentTreeItem->keyBinding != NULL) {
+ int index = SendDlgItemMessage(hwndDlg, IDC_LIST, LB_GETCURSEL, 0, 0);
+ if (index != LB_ERR && index <5) {
+ if (currentTreeItem->keyBinding->tempKey[index] != 0) {
+ int i;
+ for (i = index + 1; i < 5; i++) {
+ currentTreeItem->keyBinding->tempKey[i-1] = currentTreeItem->keyBinding->tempKey[i];
+ }
+ currentTreeItem->keyBinding->tempKey[4] = 0;
+ }
+ }
+ }
+ refreshListBox(hwndDlg);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case IDC_BTN_RESET:
+ if (currentTreeItem->keyBinding != NULL) {
+ int i;
+ for (i = 0; i < 5; i++) {
+ removeTempKeyBinding(currentTreeItem->keyBinding->actionGroupName, currentTreeItem->keyBinding->defaultKey[i]);
+ currentTreeItem->keyBinding->tempKey[i] = currentTreeItem->keyBinding->defaultKey[i];
+ }
+ }
+ refreshListBox(hwndDlg);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case IDC_BTN_UNDO:
+ if (currentTreeItem->keyBinding != NULL) {
+ int i;
+ for (i = 0; i < 5; i++) {
+ removeTempKeyBinding(currentTreeItem->keyBinding->actionGroupName, currentTreeItem->keyBinding->key[i]);
+ currentTreeItem->keyBinding->tempKey[i] = currentTreeItem->keyBinding->key[i];
+ }
+ }
+ refreshListBox(hwndDlg);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case IDC_LIST:
+ if (HIWORD(wParam) == LBN_SELCHANGE) {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_DELETE), TRUE);
+ }
+ break;
+ }
+ break;
+ case WM_NOTIFY:
+ if (((LPNMHDR) lParam)->idFrom == IDC_CATEGORYLIST)
+ {
+ switch(((NMHDR*)lParam)->code) {
+ case TVN_SELCHANGEDA:
+ case TVN_SELCHANGEDW:
+ {
+ TVITEM tvi = {0};
+ tvi.hItem = TreeView_GetSelection(GetDlgItem(hwndDlg, IDC_CATEGORYLIST));
+ tvi.mask = TVIF_HANDLE|TVIF_PARAM;
+ TreeView_GetItem(GetDlgItem(hwndDlg, IDC_CATEGORYLIST), &tvi);
+ currentTreeItem = (TreeItem *) tvi.lParam;
+ refreshListBox(hwndDlg);
+ break;
+ }
+ case TVN_DELETEITEMA:
+ case TVN_DELETEITEMW:
+ {
+ TreeItem *treeItem = (TreeItem *)(((LPNMTREEVIEW)lParam)->itemOld.lParam);
+ if (treeItem) {
+ mir_free(treeItem->paramName);
+ mir_free(treeItem);
+ }
+ break;
+ }
+ }
+ }
+ if (((LPNMHDR) lParam)->idFrom == 0 && ((LPNMHDR) lParam)->code == PSN_APPLY ) {
+ saveKeyBindings();
+ }
+ break;
+ case WM_DESTROY:
+ saveCollapseState(GetDlgItem(hwndDlg, IDC_CATEGORYLIST));
+
+ }
+ return FALSE;
+}
+
+static INT_PTR KBRegister( WPARAM wParam, LPARAM lParam )
+{
+ return (int)addKeyBinding(( KEYBINDINGDESC* )lParam );
+}
+
+static INT_PTR KBGet( WPARAM wParam, LPARAM lParam )
+{
+ KEYBINDINGDESC* desc = ( KEYBINDINGDESC* )lParam;
+ KeyBindingItem* item = (KeyBindingItem*)findKeyBinding(desc->pszActionGroup, desc->key[0]);
+ if (item != NULL) {
+ desc->action = item->action;
+ return 0;
+ }
+ return 1;
+}
+
+static void InitKeyBinding()
+{
+ keyBindingList = NULL;
+ hKeyBindings_Register = CreateServiceFunction(MS_KEYBINDINGS_REGISTER, KBRegister);
+ hKeyBindings_Get = CreateServiceFunction(MS_KEYBINDINGS_GET, KBGet);
+}
+
+static void UninitKeyBinding()
+{
+ KeyBindingItem *ptr, *ptr2;
+ ptr = keyBindingList;
+ keyBindingList = NULL;
+ for (; ptr != NULL; ptr = ptr2) {
+ ptr2 = ptr->next;
+ mir_free(ptr->actionName);
+ mir_free(ptr->fullActionName);
+ mir_free(ptr->actionGroupName);
+ mir_free(ptr);
+ }
+ DestroyServiceFunction(hKeyBindings_Register);
+ DestroyServiceFunction(hKeyBindings_Get);
+}
+
+static int KeyBindingsOptionsInit(WPARAM wParam,LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp = {0};
+ odp.cbSize = sizeof(odp);
+ odp.hInstance = GetModuleHandle(NULL);
+ odp.flags = ODPF_BOLDGROUPS | ODPF_TCHAR;
+ odp.position = -180000000;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_KEYBINDINGS);
+ odp.ptszTitle = TranslateT("Key Bindings");
+ odp.ptszGroup = TranslateT("Customize");
+ odp.pfnDlgProc = DlgProcKeyBindingsOpts;
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM)&odp);
+ return 0;
+}
+
+static int KeyBindingsSystemModulesLoaded(WPARAM wParam,LPARAM lParam)
+{
+ HookEvent(ME_OPT_INITIALISE, KeyBindingsOptionsInit);
+ return 0;
+}
+
+static int OnPreShutdown(WPARAM wParam, LPARAM lParam)
+{
+ UninitKeyBinding();
+ return 0;
+}
+
+int LoadKeyBindingsModule( void )
+{
+ HookEvent(ME_SYSTEM_MODULESLOADED, KeyBindingsSystemModulesLoaded);
+ HookEvent(ME_SYSTEM_PRESHUTDOWN, OnPreShutdown);
+ InitKeyBinding();
+ return 0;
+}
diff --git a/src/modules/keybindings/keybindings.h b/src/modules/keybindings/keybindings.h
new file mode 100644
index 0000000000..a4fbdd0c8f
--- /dev/null
+++ b/src/modules/keybindings/keybindings.h
@@ -0,0 +1,43 @@
+/*
+
+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.
+*/
+
+typedef struct KeyBindingItemStruct
+{
+ TCHAR* actionName;
+ TCHAR* fullActionName;
+ char* actionGroupName;
+ DWORD action;
+ DWORD defaultKey[5];
+ DWORD tempKey[5];
+ DWORD key[5];
+ struct KeyBindingItemStruct *prev;
+ struct KeyBindingItemStruct *next;
+}KeyBindingItem;
+
+static KeyBindingItem* keyBindingList = NULL;
+
+typedef struct
+{
+ char *paramName;
+ KeyBindingItem *keyBinding;
+}TreeItem;
diff --git a/src/modules/langpack/langpack.cpp b/src/modules/langpack/langpack.cpp
new file mode 100644
index 0000000000..0603a24b90
--- /dev/null
+++ b/src/modules/langpack/langpack.cpp
@@ -0,0 +1,569 @@
+/*
+
+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 "../netlib/netlib.h"
+
+#define LANGPACK_BUF_SIZE 4000
+
+int LoadLangPackServices(void);
+
+struct LangPackMuuid
+{
+ MUUID muuid;
+ PLUGININFOEX* pInfo;
+};
+
+static int CompareMuuids( const LangPackMuuid* p1, const LangPackMuuid* p2 )
+{
+ return memcmp( &p1->muuid, &p2->muuid, sizeof( MUUID ));
+}
+
+static LIST<LangPackMuuid> lMuuids( 10, CompareMuuids );
+static LangPackMuuid* pCurrentMuuid = NULL;
+
+static BOOL bModuleInitialized = FALSE;
+
+struct LangPackEntry {
+ DWORD englishHash;
+ char *local;
+ wchar_t *wlocal;
+ LangPackMuuid* pMuuid;
+ LangPackEntry* pNext; // for langpack items with the same hash value
+};
+
+struct LangPackStruct {
+ TCHAR filename[MAX_PATH];
+ TCHAR filePath[MAX_PATH];
+ char language[64];
+ char lastModifiedUsing[64];
+ char authors[256];
+ char authorEmail[128];
+ LangPackEntry *entry;
+ int entryCount, entriesAlloced;
+ LCID localeID;
+ UINT defaultANSICp;
+} static langPack;
+
+static int IsEmpty(char *str)
+{
+ int i = 0;
+
+ while (str[i])
+ {
+ if (str[i]!=' '&&str[i]!='\r'&&str[i]!='\n')
+ return 0;
+ i++;
+ }
+ return 1;
+}
+
+void ConvertBackslashes(char *str, UINT fileCp)
+{
+ char *pstr;
+ for ( pstr = str; *pstr; pstr = CharNextExA( fileCp, pstr, 0 )) {
+ if( *pstr == '\\' ) {
+ switch( pstr[1] ) {
+ case 'n': *pstr = '\n'; break;
+ case 't': *pstr = '\t'; break;
+ case 'r': *pstr = '\r'; break;
+ default: *pstr = pstr[1]; break;
+ }
+ memmove(pstr+1, pstr+2, strlen(pstr+2) + 1);
+} } }
+
+#ifdef _DEBUG
+//#pragma optimize( "gt", on )
+#endif
+
+// MurmurHash2
+unsigned int __fastcall hash(const void * key, unsigned int len)
+{
+ // 'm' and 'r' are mixing constants generated offline.
+ // They're not really 'magic', they just happen to work well.
+ const unsigned int m = 0x5bd1e995;
+ const int r = 24;
+
+ // Initialize the hash to a 'random' value
+ unsigned int h = len;
+
+ // Mix 4 bytes at a time into the hash
+ const unsigned char * data = (const unsigned char *)key;
+
+ while(len >= 4)
+ {
+ unsigned int k = *(unsigned int *)data;
+
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+
+ h *= m;
+ h ^= k;
+
+ data += 4;
+ len -= 4;
+ }
+
+ // Handle the last few bytes of the input array
+ switch(len)
+ {
+ case 3: h ^= data[2] << 16;
+ case 2: h ^= data[1] << 8;
+ case 1: h ^= data[0];
+ h *= m;
+ };
+
+ // Do a few final mixes of the hash to ensure the last few
+ // bytes are well-incorporated.
+ h ^= h >> 13;
+ h *= m;
+ h ^= h >> 15;
+
+ return h;
+}
+
+unsigned int __fastcall hashstrW(const char * key)
+{
+ if (key == NULL) return 0;
+ const unsigned int len = (unsigned int)wcslen((const wchar_t*)key);
+ char* buf = (char*)alloca(len + 1);
+ for (unsigned i = 0; i <= len ; ++i)
+ buf[i] = key[i << 1];
+ return hash(buf, len);
+}
+
+static int SortLangPackHashesProc(LangPackEntry *arg1,LangPackEntry *arg2)
+{
+ if (arg1->englishHash < arg2->englishHash) return -1;
+ if (arg1->englishHash > arg2->englishHash) return 1;
+
+ return (arg1->pMuuid < arg2->pMuuid) ? -1 : 1;
+}
+
+static void swapBytes( void* p, size_t iSize )
+{
+ char *head = (char *)p; // here
+ char *tail = head + iSize - 1;
+
+ for (; tail > head; --tail, ++head) {
+ char temp = *head;
+ *head = *tail;
+ *tail = temp;
+ }
+}
+
+static bool EnterMuuid( const char* p, MUUID& result )
+{
+ if ( *p++ != '{' )
+ return false;
+
+ BYTE* d = (BYTE*)&result;
+
+ for ( int nBytes = 0; *p && nBytes < 24; p++ ) {
+ if ( *p == '-' )
+ continue;
+
+ if ( *p == '}' )
+ break;
+
+ if ( !isxdigit( *p ))
+ return false;
+
+ if ( !isxdigit( p[1] ))
+ return false;
+
+ int c = 0;
+ if ( sscanf( p, "%2x", &c ) != 1 )
+ return false;
+
+ *d++ = ( BYTE )c;
+ nBytes++;
+ p++;
+ }
+
+ if ( *p != '}' )
+ return false;
+
+ swapBytes( &result.a, sizeof( result.a ));
+ swapBytes( &result.b, sizeof( result.b ));
+ swapBytes( &result.c, sizeof( result.c ));
+ return true;
+}
+
+static void LoadLangPackFile( FILE* fp, char* line, UINT fileCp )
+{
+ while ( !feof( fp )) {
+ if ( fgets( line, LANGPACK_BUF_SIZE, fp ) == NULL )
+ break;
+
+ if ( IsEmpty(line) || line[0] == ';' || line[0] == 0 )
+ continue;
+
+ rtrim( line );
+
+ if ( line[0] == '#' ) {
+ strlwr( line );
+
+ if ( !memcmp( line+1, "include", 7 )) {
+ TCHAR tszFileName[ MAX_PATH ];
+ TCHAR* fileName = mir_a2t( ltrim( line+9 ));
+ mir_sntprintf( tszFileName, SIZEOF(tszFileName), _T("%s%s"), langPack.filePath, fileName );
+ mir_free( fileName );
+
+ FILE* p = _tfopen( tszFileName, _T("r"));
+ if ( p ) {
+ line[0] = 0;
+ fgets( line, SIZEOF(line), p );
+
+ UINT fileCp = CP_ACP;
+ if (strlen(line) >= 3 && line[0]=='\xef' && line[1]=='\xbb' && line[2]=='\xbf')
+ {
+ fileCp = CP_UTF8;
+ fseek(p, 3, SEEK_SET);
+ }
+ else
+ {
+ fileCp = langPack.defaultANSICp;
+ fseek(p, 0, SEEK_SET);
+ }
+
+ LoadLangPackFile( p, line, fileCp );
+ fclose( p );
+ }
+ }
+ else if ( !memcmp( line+1, "muuid", 5 )) {
+ MUUID t;
+ if ( !EnterMuuid( line+7, t )) {
+ NetlibLogf( NULL, "Invalid MUUID: %s\n", line+7 );
+ continue;
+ }
+
+ LangPackMuuid* pNew = ( LangPackMuuid* )mir_alloc( sizeof( LangPackMuuid ));
+ memcpy( &pNew->muuid, &t, sizeof( t ));
+ pNew->pInfo = NULL;
+ lMuuids.insert( pNew );
+ pCurrentMuuid = pNew;
+ }
+
+ continue;
+ }
+
+ ConvertBackslashes( line, fileCp );
+
+ if ( line[0] == '[' && line[ lstrlenA(line)-1 ] == ']' ) {
+ if ( langPack.entryCount && langPack.entry[ langPack.entryCount-1].local == NULL )
+ langPack.entryCount--;
+
+ char* pszLine = line+1;
+ line[ lstrlenA(line)-1 ] = '\0';
+ if ( ++langPack.entryCount > langPack.entriesAlloced ) {
+ langPack.entriesAlloced += 128;
+ langPack.entry = ( LangPackEntry* )mir_realloc( langPack.entry, sizeof(LangPackEntry)*langPack.entriesAlloced );
+ }
+
+ LangPackEntry* E = &langPack.entry[ langPack.entryCount-1 ];
+ E->englishHash = hashstr(pszLine);
+ E->local = NULL;
+ E->wlocal = NULL;
+ E->pMuuid = pCurrentMuuid;
+ E->pNext = NULL;
+ continue;
+ }
+
+ if ( !langPack.entryCount )
+ continue;
+
+ LangPackEntry* E = &langPack.entry[ langPack.entryCount-1 ];
+ if ( E->local == NULL ) {
+ E->local = mir_strdup( line );
+ if ( fileCp == CP_UTF8 )
+ Utf8DecodeCP( E->local, langPack.defaultANSICp, NULL );
+
+ int iNeeded = MultiByteToWideChar(fileCp, 0, line, -1, 0, 0);
+ E->wlocal = (wchar_t *)mir_alloc((iNeeded+1) * sizeof(wchar_t));
+ MultiByteToWideChar( fileCp, 0, line, -1, E->wlocal, iNeeded );
+ }
+ else {
+ size_t iOldLenA = strlen( E->local );
+ E->local = ( char* )mir_realloc( E->local, iOldLenA + strlen(line) + 2 );
+ strcat( E->local, "\n" );
+ strcat( E->local, line );
+
+ if ( fileCp == CP_UTF8 )
+ Utf8DecodeCP( E->local + iOldLenA + 1, langPack.defaultANSICp, NULL );
+
+ int iNeeded = MultiByteToWideChar( fileCp, 0, line, -1, 0, 0 );
+ size_t iOldLen = wcslen( E->wlocal );
+ E->wlocal = ( wchar_t* )mir_realloc( E->wlocal, ( sizeof(wchar_t) * ( iOldLen + iNeeded + 2)));
+ wcscat( E->wlocal, L"\n" );
+ MultiByteToWideChar( fileCp, 0, line, -1, E->wlocal + iOldLen + 1, iNeeded );
+ }
+ }
+}
+
+static int LoadLangPack(const TCHAR *szLangPack)
+{
+ int startOfLine=0;
+ USHORT langID;
+
+ lstrcpy( langPack.filename, szLangPack );
+ lstrcpy( langPack.filePath, szLangPack );
+ TCHAR* p = _tcsrchr( langPack.filePath, '\\' );
+ if ( p )
+ p[1] = 0;
+
+ FILE *fp = _tfopen(szLangPack,_T("rt"));
+ if ( fp == NULL )
+ return 1;
+
+ char line[ LANGPACK_BUF_SIZE ] = "";
+ fgets( line, SIZEOF(line), fp );
+
+ UINT fileCp = CP_ACP;
+ size_t lineLen = strlen(line);
+ if (lineLen >= 3 && line[0]=='\xef' && line[1]=='\xbb' && line[2]=='\xbf')
+ {
+ fileCp = CP_UTF8;
+ memmove(line, line + 3, lineLen - 2);
+ }
+
+ lrtrim( line );
+ if ( lstrcmpA( line, "Miranda Language Pack Version 1" )) {
+ fclose(fp);
+ return 2;
+ }
+
+ //headers
+ while ( !feof( fp )) {
+ startOfLine = ftell( fp );
+ if ( fgets( line, SIZEOF(line), fp ) == NULL )
+ break;
+
+ lrtrim( line );
+ if( IsEmpty( line ) || line[0]==';' || line[0]==0)
+ continue;
+
+ if ( line[0] == '[' || line[0] == '#' )
+ break;
+
+ char* pszColon = strchr( line,':' );
+ if ( pszColon == NULL ) {
+ fclose( fp );
+ return 3;
+ }
+
+ *pszColon++ = 0;
+ if(!lstrcmpA(line,"Language")) {mir_snprintf(langPack.language,sizeof(langPack.language),"%s",pszColon); lrtrim(langPack.language);}
+ else if(!lstrcmpA(line,"Last-Modified-Using")) {mir_snprintf(langPack.lastModifiedUsing,sizeof(langPack.lastModifiedUsing),"%s",pszColon); lrtrim(langPack.lastModifiedUsing);}
+ else if(!lstrcmpA(line,"Authors")) {mir_snprintf(langPack.authors,sizeof(langPack.authors),"%s",pszColon); lrtrim(langPack.authors);}
+ else if(!lstrcmpA(line,"Author-email")) {mir_snprintf(langPack.authorEmail,sizeof(langPack.authorEmail),"%s",pszColon); lrtrim(langPack.authorEmail);}
+ else if(!lstrcmpA(line, "Locale")) {
+ char szBuf[20], *stopped;
+
+ lrtrim(pszColon + 1);
+ langID = (USHORT)strtol(pszColon, &stopped, 16);
+ langPack.localeID = MAKELCID(langID, 0);
+ GetLocaleInfoA(langPack.localeID, LOCALE_IDEFAULTANSICODEPAGE, szBuf, 10);
+ szBuf[5] = 0; // codepages have max. 5 digits
+ langPack.defaultANSICp = atoi(szBuf);
+ if (fileCp == CP_ACP)
+ fileCp = langPack.defaultANSICp;
+ }
+ }
+
+ //body
+ fseek( fp, startOfLine, SEEK_SET );
+ langPack.entriesAlloced = 0;
+
+ LoadLangPackFile( fp, line, fileCp );
+ fclose(fp);
+
+ qsort(langPack.entry,langPack.entryCount,sizeof(LangPackEntry),(int(*)(const void*,const void*))SortLangPackHashesProc);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static int SortLangPackHashesProc2(LangPackEntry *arg1,LangPackEntry *arg2)
+{
+ if (arg1->englishHash < arg2->englishHash) return -1;
+ if (arg1->englishHash > arg2->englishHash) return 1;
+ return 0;
+}
+
+char *LangPackTranslateString(LangPackMuuid* pUuid, const char *szEnglish, const int W)
+{
+ if ( langPack.entryCount == 0 || szEnglish == NULL )
+ return (char*)szEnglish;
+
+ LangPackEntry key,*entry;
+ key.englishHash = W ? hashstrW(szEnglish) : hashstr(szEnglish);
+ entry = (LangPackEntry*)bsearch(&key, langPack.entry, langPack.entryCount, sizeof(LangPackEntry), (int(*)(const void*,const void*))SortLangPackHashesProc2 );
+ if ( entry == NULL )
+ return (char*)szEnglish;
+
+ // try to find the exact match, otherwise the first entry will be returned
+ if ( pUuid ) {
+ for ( LangPackEntry* p = entry->pNext; p != NULL; p = p->pNext ) {
+ if (p->pMuuid == pUuid) {
+ entry = p;
+ break;
+ } } }
+
+ return W ? (char *)entry->wlocal : entry->local;
+}
+
+int LangPackGetDefaultCodePage()
+{
+ return langPack.defaultANSICp;
+}
+
+int LangPackGetDefaultLocale()
+{
+ return (langPack.localeID == 0) ? LOCALE_USER_DEFAULT : langPack.localeID;
+}
+
+TCHAR* LangPackPcharToTchar( const char* pszStr )
+{
+ if ( pszStr == NULL )
+ return NULL;
+
+ #if defined( _UNICODE )
+ { int len = (int)strlen( pszStr );
+ TCHAR* result = ( TCHAR* )alloca(( len+1 )*sizeof( TCHAR ));
+ MultiByteToWideChar( LangPackGetDefaultCodePage(), 0, pszStr, -1, result, len );
+ result[len] = 0;
+ return mir_wstrdup( TranslateW( result ));
+ }
+ #else
+ return mir_strdup( Translate( pszStr ));
+ #endif
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+LangPackMuuid* __fastcall LangPackLookupUuid( WPARAM wParam )
+{
+ int idx = (wParam >> 16) & 0xFFFF;
+ return ( idx > 0 && idx <= lMuuids.getCount()) ? lMuuids[ idx-1 ] : NULL;
+}
+
+int LangPackMarkPluginLoaded( PLUGININFOEX* pInfo )
+{
+ LangPackMuuid tmp; tmp.muuid = pInfo->uuid;
+ int idx = lMuuids.getIndex( &tmp );
+ if ( idx == -1 )
+ return 0;
+
+ lMuuids[ idx ]->pInfo = pInfo;
+ return (idx+1) << 16;
+}
+
+void LangPackDropUnusedItems( void )
+{
+ if ( langPack.entryCount == 0 )
+ return;
+
+ LangPackEntry *s = langPack.entry+1, *d = s, *pLast = langPack.entry;
+ DWORD dwSavedHash = langPack.entry->englishHash;
+ bool bSortNeeded = false;
+
+ for ( int i=1; i < langPack.entryCount; i++, s++ ) {
+ if ( s->pMuuid != NULL && s->pMuuid->pInfo == NULL )
+ s->pMuuid = NULL;
+
+ if ( s->englishHash != dwSavedHash ) {
+ pLast = d;
+ if ( s != d )
+ *d++ = *s;
+ else
+ d++;
+ dwSavedHash = s->englishHash;
+ }
+ else {
+ bSortNeeded = true;
+ LangPackEntry* p = ( LangPackEntry* )mir_alloc( sizeof( LangPackEntry ));
+ *p = *s;
+ pLast->pNext = p; pLast = p;
+ }
+ }
+
+ if ( bSortNeeded ) {
+ langPack.entryCount = ( int )( d - langPack.entry );
+ qsort(langPack.entry,langPack.entryCount,sizeof(LangPackEntry),(int(*)(const void*,const void*))SortLangPackHashesProc);
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int LoadLangPackModule(void)
+{
+ HANDLE hFind;
+ TCHAR szSearch[MAX_PATH];
+ WIN32_FIND_DATA fd;
+
+ bModuleInitialized = TRUE;
+
+ ZeroMemory(&langPack,sizeof(langPack));
+ LoadLangPackServices();
+ pathToAbsoluteT(_T("langpack_*.txt"), szSearch, NULL);
+ hFind = FindFirstFile( szSearch, &fd );
+ if( hFind != INVALID_HANDLE_VALUE ) {
+ pathToAbsoluteT(fd.cFileName, szSearch, NULL);
+ FindClose(hFind);
+ LoadLangPack(szSearch);
+ }
+ return 0;
+}
+
+void UnloadLangPackModule()
+{
+ int i;
+
+ if ( !bModuleInitialized ) return;
+
+ for ( i=0; i < lMuuids.getCount(); i++ )
+ mir_free( lMuuids[i] );
+ lMuuids.destroy();
+
+ LangPackEntry* p = langPack.entry;
+ for ( i=0; i < langPack.entryCount; i++, p++ ) {
+ if ( p->pNext != NULL ) {
+ for ( LangPackEntry* p1 = p->pNext; p1 != NULL; ) {
+ LangPackEntry* p2 = p1; p1 = p1->pNext;
+ mir_free( p2->local);
+ mir_free( p2->wlocal);
+ mir_free( p2 );
+ }
+ }
+
+ mir_free( p->local );
+ mir_free( p->wlocal );
+ }
+
+ if ( langPack.entryCount ) {
+ mir_free(langPack.entry);
+ langPack.entry=0;
+ langPack.entryCount=0;
+} }
diff --git a/src/modules/langpack/lpservices.cpp b/src/modules/langpack/lpservices.cpp
new file mode 100644
index 0000000000..26586dfda3
--- /dev/null
+++ b/src/modules/langpack/lpservices.cpp
@@ -0,0 +1,168 @@
+/*
+
+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"
+
+#if defined( _UNICODE )
+ #define FLAGS LANG_UNICODE
+#else
+ #define FLAGS 0
+#endif
+
+LangPackMuuid* __fastcall LangPackLookupUuid( WPARAM );
+int LangPackMarkPluginLoaded( PLUGININFOEX* pInfo );
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static INT_PTR TranslateString(WPARAM wParam,LPARAM lParam)
+{
+ return (INT_PTR)LangPackTranslateString( LangPackLookupUuid(wParam), (const char *)lParam, (wParam & LANG_UNICODE) ? 1 : 0);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static INT_PTR TranslateMenu(WPARAM wParam, LPARAM lParam)
+{
+ HMENU hMenu = ( HMENU )wParam;
+ int i;
+ MENUITEMINFO mii;
+ TCHAR str[256];
+ LangPackMuuid* uuid = LangPackLookupUuid( lParam );
+
+ mii.cbSize = MENUITEMINFO_V4_SIZE;
+ for ( i = GetMenuItemCount( hMenu )-1; i >= 0; i--) {
+ mii.fMask = MIIM_TYPE|MIIM_SUBMENU;
+ mii.dwTypeData = ( TCHAR* )str;
+ mii.cch = SIZEOF(str);
+ GetMenuItemInfo(hMenu, i, TRUE, &mii);
+
+ if ( mii.cch && mii.dwTypeData ) {
+ TCHAR* result = ( TCHAR* )LangPackTranslateString( uuid, ( const char* )mii.dwTypeData, FLAGS );
+ if ( result != mii.dwTypeData ) {
+ mii.dwTypeData = result;
+ mii.fMask = MIIM_TYPE;
+ SetMenuItemInfo( hMenu, i, TRUE, &mii );
+ } }
+
+ if ( mii.hSubMenu != NULL ) TranslateMenu(( WPARAM )mii.hSubMenu, lParam );
+ }
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static void TranslateWindow( LangPackMuuid* pUuid, HWND hwnd )
+{
+ TCHAR title[2048];
+ GetWindowText(hwnd, title, SIZEOF( title ));
+ {
+ TCHAR* result = ( TCHAR* )LangPackTranslateString( pUuid, ( const char* )title, FLAGS );
+ if ( result != title )
+ SetWindowText(hwnd, result );
+} }
+
+static BOOL CALLBACK TranslateDialogEnumProc(HWND hwnd,LPARAM lParam)
+{
+ LANGPACKTRANSLATEDIALOG *lptd = (LANGPACKTRANSLATEDIALOG*)lParam;
+ TCHAR szClass[32];
+ int i,id = GetDlgCtrlID( hwnd );
+
+ if ( lptd->ignoreControls != NULL )
+ for ( i=0; lptd->ignoreControls[i]; i++ )
+ if ( lptd->ignoreControls[i] == id )
+ return TRUE;
+
+ LangPackMuuid* uuid = LangPackLookupUuid( lptd->flags );
+
+ GetClassName( hwnd, szClass, SIZEOF(szClass));
+ if(!lstrcmpi(szClass,_T("static")) || !lstrcmpi(szClass,_T("hyperlink")) || !lstrcmpi(szClass,_T("button")) || !lstrcmpi(szClass,_T("MButtonClass")) || !lstrcmpi(szClass,_T("MHeaderbarCtrl")))
+ TranslateWindow( uuid, hwnd );
+ else if ( !lstrcmpi( szClass,_T("edit"))) {
+ if( lptd->flags & LPTDF_NOIGNOREEDIT || GetWindowLongPtr(hwnd,GWL_STYLE) & ES_READONLY )
+ TranslateWindow( uuid, hwnd );
+ }
+ return TRUE;
+}
+
+static INT_PTR TranslateDialog(WPARAM wParam, LPARAM lParam)
+{
+ LANGPACKTRANSLATEDIALOG *lptd = (LANGPACKTRANSLATEDIALOG*)lParam;
+ if ( lptd == NULL || lptd->cbSize != sizeof(LANGPACKTRANSLATEDIALOG))
+ return 1;
+
+ if ( !( lptd->flags & LPTDF_NOTITLE ))
+ TranslateWindow( LangPackLookupUuid( lptd->flags ), lptd->hwndDlg );
+
+ EnumChildWindows( lptd->hwndDlg, TranslateDialogEnumProc, lParam );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static INT_PTR LPRegister(WPARAM wParam, LPARAM lParam)
+{
+ *( int* )wParam = LangPackMarkPluginLoaded(( PLUGININFOEX* )lParam );
+ return 0;
+}
+
+static INT_PTR GetDefaultCodePage(WPARAM,LPARAM)
+{
+ return LangPackGetDefaultCodePage();
+}
+
+static INT_PTR GetDefaultLocale(WPARAM, LPARAM)
+{
+ return LangPackGetDefaultLocale();
+}
+
+static INT_PTR PcharToTchar(WPARAM wParam, LPARAM lParam)
+{
+ char* pszStr = ( char* )lParam;
+ if ( pszStr == NULL )
+ return NULL;
+
+ LangPackMuuid* uuid = LangPackLookupUuid( wParam );
+
+ #if defined( _UNICODE )
+ { int len = (int)strlen( pszStr );
+ TCHAR* result = ( TCHAR* )alloca(( len+1 )*sizeof( TCHAR ));
+ MultiByteToWideChar( LangPackGetDefaultCodePage(), 0, pszStr, -1, result, len );
+ result[len] = 0;
+ return ( INT_PTR )mir_wstrdup(( wchar_t* )LangPackTranslateString( uuid, ( char* )result, 1 ));
+ }
+ #else
+ return ( INT_PTR )mir_strdup( LangPackTranslateString( uuid, pszStr, 0 ));
+ #endif
+}
+
+int LoadLangPackServices(void)
+{
+ CreateServiceFunction(MS_LANGPACK_TRANSLATESTRING,TranslateString);
+ CreateServiceFunction(MS_LANGPACK_TRANSLATEMENU,TranslateMenu);
+ CreateServiceFunction(MS_LANGPACK_TRANSLATEDIALOG,TranslateDialog);
+ CreateServiceFunction(MS_LANGPACK_GETCODEPAGE,GetDefaultCodePage);
+ CreateServiceFunction(MS_LANGPACK_GETLOCALE,GetDefaultLocale);
+ CreateServiceFunction(MS_LANGPACK_PCHARTOTCHAR,PcharToTchar);
+ CreateServiceFunction(MS_LANGPACK_REGISTER,LPRegister);
+ return 0;
+}
+
diff --git a/src/modules/netlib/netlib.cpp b/src/modules/netlib/netlib.cpp
new file mode 100644
index 0000000000..000639474f
--- /dev/null
+++ b/src/modules/netlib/netlib.cpp
@@ -0,0 +1,640 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2012 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 "netlib.h"
+
+static BOOL bModuleInitialized = FALSE;
+
+HANDLE hConnectionHeaderMutex, hConnectionOpenMutex;
+DWORD g_LastConnectionTick;
+int connectionTimeout;
+HANDLE hSendEvent=NULL, hRecvEvent=NULL;
+
+typedef BOOL (WINAPI *tGetProductInfo)(DWORD, DWORD, DWORD, DWORD, PDWORD);
+
+static int CompareNetlibUser(const NetlibUser* p1, const NetlibUser* p2)
+{
+ return strcmp(p1->user.szSettingsModule, p2->user.szSettingsModule);
+}
+
+LIST<NetlibUser> netlibUser(5, CompareNetlibUser);
+CRITICAL_SECTION csNetlibUser;
+
+SSL_API si;
+
+void NetlibFreeUserSettingsStruct(NETLIBUSERSETTINGS *settings)
+{
+ mir_free(settings->szIncomingPorts);
+ mir_free(settings->szOutgoingPorts);
+ mir_free(settings->szProxyAuthPassword);
+ mir_free(settings->szProxyAuthUser);
+ mir_free(settings->szProxyServer);
+}
+
+void NetlibInitializeNestedCS(struct NetlibNestedCriticalSection *nlncs)
+{
+ nlncs->dwOwningThreadId= 0;
+ nlncs->lockCount=0;
+ nlncs->hMutex=CreateMutex(NULL,FALSE,NULL);
+}
+
+void NetlibDeleteNestedCS(struct NetlibNestedCriticalSection *nlncs)
+{
+ CloseHandle(nlncs->hMutex);
+}
+
+int NetlibEnterNestedCS(struct NetlibConnection *nlc,int which)
+{
+ struct NetlibNestedCriticalSection *nlncs;
+ DWORD dwCurrentThreadId=GetCurrentThreadId();
+
+ WaitForSingleObject(hConnectionHeaderMutex,INFINITE);
+ if(nlc==NULL || nlc->handleType!=NLH_CONNECTION) {
+ ReleaseMutex(hConnectionHeaderMutex);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ nlncs = (which == NLNCS_SEND) ? &nlc->ncsSend : &nlc->ncsRecv;
+ if(nlncs->lockCount && nlncs->dwOwningThreadId==dwCurrentThreadId) {
+ nlncs->lockCount++;
+ ReleaseMutex(hConnectionHeaderMutex);
+ return 1;
+ }
+ InterlockedIncrement(&nlc->dontCloseNow);
+ ResetEvent(nlc->hOkToCloseEvent);
+ ReleaseMutex(hConnectionHeaderMutex);
+ WaitForSingleObject(nlncs->hMutex,INFINITE);
+ nlncs->dwOwningThreadId=dwCurrentThreadId;
+ nlncs->lockCount=1;
+ if(InterlockedDecrement(&nlc->dontCloseNow)==0)
+ SetEvent(nlc->hOkToCloseEvent);
+ return 1;
+}
+
+void NetlibLeaveNestedCS(struct NetlibNestedCriticalSection *nlncs)
+{
+ if(--nlncs->lockCount==0) {
+ nlncs->dwOwningThreadId=0;
+ ReleaseMutex(nlncs->hMutex);
+ }
+}
+
+static INT_PTR GetNetlibUserSettingInt(const char *szUserModule,const char *szSetting,int defValue)
+{
+ DBVARIANT dbv;
+ if(DBGetContactSetting(NULL,szUserModule,szSetting,&dbv)
+ && DBGetContactSetting(NULL,"Netlib",szSetting,&dbv))
+ return defValue;
+ if(dbv.type==DBVT_BYTE) return dbv.bVal;
+ if(dbv.type==DBVT_WORD) return dbv.wVal;
+ return dbv.dVal;
+}
+
+static char *GetNetlibUserSettingString(const char *szUserModule,const char *szSetting,int decode)
+{
+ DBVARIANT dbv;
+ if(DBGetContactSettingString(NULL,szUserModule,szSetting,&dbv)
+ && DBGetContactSettingString(NULL,"Netlib",szSetting,&dbv)) {
+ return NULL;
+ }
+ else {
+ char *szRet;
+ if(decode) CallService(MS_DB_CRYPT_DECODESTRING, strlen(dbv.pszVal) + 1, (LPARAM)dbv.pszVal);
+ szRet=mir_strdup(dbv.pszVal);
+ DBFreeVariant(&dbv);
+ if(szRet==NULL) SetLastError(ERROR_OUTOFMEMORY);
+ return szRet;
+ }
+}
+
+static INT_PTR NetlibRegisterUser(WPARAM,LPARAM lParam)
+{
+ NETLIBUSER *nlu=(NETLIBUSER*)lParam;
+ struct NetlibUser *thisUser;
+
+ if(nlu==NULL || nlu->cbSize!=sizeof(NETLIBUSER) || nlu->szSettingsModule==NULL
+ || (!(nlu->flags&NUF_NOOPTIONS) && nlu->szDescriptiveName==NULL)
+ || (nlu->flags&NUF_HTTPGATEWAY && (nlu->pfnHttpGatewayInit==NULL))) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+
+ thisUser = (struct NetlibUser*)mir_calloc(sizeof(struct NetlibUser));
+ thisUser->handleType = NLH_USER;
+ thisUser->user = *nlu;
+
+ EnterCriticalSection(&csNetlibUser);
+ if (netlibUser.getIndex(thisUser) >= 0)
+ {
+ LeaveCriticalSection(&csNetlibUser);
+ mir_free(thisUser);
+ SetLastError(ERROR_DUP_NAME);
+ return 0;
+ }
+ LeaveCriticalSection(&csNetlibUser);
+
+ if (nlu->szDescriptiveName) {
+ thisUser->user.ptszDescriptiveName = (thisUser->user.flags&NUF_UNICODE ? mir_u2t((WCHAR*)nlu->ptszDescriptiveName) : mir_a2t(nlu->szDescriptiveName));
+ }
+ if((thisUser->user.szSettingsModule=mir_strdup(nlu->szSettingsModule))==NULL
+ || (nlu->szDescriptiveName && thisUser->user.ptszDescriptiveName ==NULL)
+ || (nlu->szHttpGatewayUserAgent && (thisUser->user.szHttpGatewayUserAgent=mir_strdup(nlu->szHttpGatewayUserAgent))==NULL))
+ {
+ mir_free(thisUser);
+ SetLastError(ERROR_OUTOFMEMORY);
+ return 0;
+ }
+ if (nlu->szHttpGatewayHello)
+ thisUser->user.szHttpGatewayHello=mir_strdup(nlu->szHttpGatewayHello);
+ else
+ thisUser->user.szHttpGatewayHello=NULL;
+
+ thisUser->settings.cbSize=sizeof(NETLIBUSERSETTINGS);
+ thisUser->settings.useProxy=GetNetlibUserSettingInt(thisUser->user.szSettingsModule,"NLUseProxy",0);
+ thisUser->settings.proxyType=GetNetlibUserSettingInt(thisUser->user.szSettingsModule,"NLProxyType",PROXYTYPE_SOCKS5);
+ if(thisUser->user.flags&NUF_NOHTTPSOPTION && thisUser->settings.proxyType==PROXYTYPE_HTTPS)
+ thisUser->settings.proxyType=PROXYTYPE_HTTP;
+ if(!(thisUser->user.flags&(NUF_HTTPCONNS|NUF_HTTPGATEWAY)) && thisUser->settings.proxyType==PROXYTYPE_HTTP) {
+ thisUser->settings.useProxy=0;
+ thisUser->settings.proxyType=PROXYTYPE_SOCKS5;
+ }
+ thisUser->settings.szProxyServer=GetNetlibUserSettingString(thisUser->user.szSettingsModule,"NLProxyServer",0);
+ thisUser->settings.wProxyPort=GetNetlibUserSettingInt(thisUser->user.szSettingsModule,"NLProxyPort",1080);
+ thisUser->settings.useProxyAuth=GetNetlibUserSettingInt(thisUser->user.szSettingsModule,"NLUseProxyAuth",0);
+ thisUser->settings.szProxyAuthUser=GetNetlibUserSettingString(thisUser->user.szSettingsModule,"NLProxyAuthUser",0);
+ thisUser->settings.szProxyAuthPassword=GetNetlibUserSettingString(thisUser->user.szSettingsModule,"NLProxyAuthPassword",1);
+ thisUser->settings.dnsThroughProxy=GetNetlibUserSettingInt(thisUser->user.szSettingsModule,"NLDnsThroughProxy",1);
+ thisUser->settings.specifyIncomingPorts=GetNetlibUserSettingInt(thisUser->user.szSettingsModule,"NLSpecifyIncomingPorts",0);
+ thisUser->settings.szIncomingPorts=GetNetlibUserSettingString(thisUser->user.szSettingsModule,"NLIncomingPorts",0);
+ thisUser->settings.specifyOutgoingPorts=GetNetlibUserSettingInt(thisUser->user.szSettingsModule,"NLSpecifyOutgoingPorts",0);
+ thisUser->settings.szOutgoingPorts=GetNetlibUserSettingString(thisUser->user.szSettingsModule,"NLOutgoingPorts",0);
+ thisUser->settings.enableUPnP=GetNetlibUserSettingInt(thisUser->user.szSettingsModule,"NLEnableUPnP",1); //default to on
+ thisUser->settings.validateSSL=GetNetlibUserSettingInt(thisUser->user.szSettingsModule,"NLValidateSSL",0);
+
+ thisUser->toLog=GetNetlibUserSettingInt(thisUser->user.szSettingsModule,"NLlog",1);
+
+ EnterCriticalSection(&csNetlibUser);
+ netlibUser.insert(thisUser);
+ LeaveCriticalSection(&csNetlibUser);
+ return (INT_PTR)thisUser;
+}
+
+static INT_PTR NetlibGetUserSettings(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBUSERSETTINGS *nlus=(NETLIBUSERSETTINGS*)lParam;
+ struct NetlibUser *nlu=(struct NetlibUser*)wParam;
+
+ if(GetNetlibHandleType(nlu)!=NLH_USER || nlus==NULL || nlus->cbSize!=sizeof(NETLIBUSERSETTINGS)) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ *nlus=nlu->settings;
+ return 1;
+}
+
+static INT_PTR NetlibSetUserSettings(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBUSERSETTINGS *nlus=(NETLIBUSERSETTINGS*)lParam;
+ struct NetlibUser *nlu=(struct NetlibUser*)wParam;
+
+ if(GetNetlibHandleType(nlu)!=NLH_USER || nlus==NULL || nlus->cbSize!=sizeof(NETLIBUSERSETTINGS)) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ NetlibSaveUserSettingsStruct(nlu->user.szSettingsModule,nlus);
+ return 1;
+}
+
+void NetlibDoClose(NetlibConnection *nlc, bool noShutdown)
+{
+ if (nlc->s == INVALID_SOCKET) return;
+
+ NetlibLogf(nlc->nlu, "(%p:%u) Connection closed internal", nlc, nlc->s);
+ if (nlc->hSsl)
+ {
+ if (!noShutdown) si.shutdown(nlc->hSsl);
+ si.sfree(nlc->hSsl);
+ nlc->hSsl = NULL;
+ }
+ closesocket(nlc->s);
+ nlc->s = INVALID_SOCKET;
+}
+
+INT_PTR NetlibCloseHandle(WPARAM wParam, LPARAM)
+{
+ switch(GetNetlibHandleType(wParam)) {
+ case NLH_USER:
+ { struct NetlibUser *nlu=(struct NetlibUser*)wParam;
+ int i;
+
+ EnterCriticalSection(&csNetlibUser);
+ i = netlibUser.getIndex(nlu);
+ if (i >= 0) netlibUser.remove(i);
+ LeaveCriticalSection(&csNetlibUser);
+
+ NetlibFreeUserSettingsStruct(&nlu->settings);
+ mir_free(nlu->user.szSettingsModule);
+ mir_free(nlu->user.szDescriptiveName);
+ mir_free(nlu->user.szHttpGatewayHello);
+ mir_free(nlu->user.szHttpGatewayUserAgent);
+ mir_free(nlu->szStickyHeaders);
+ break;
+ }
+ case NLH_CONNECTION:
+ { struct NetlibConnection *nlc=(struct NetlibConnection*)wParam;
+ HANDLE waitHandles[4];
+ DWORD waitResult;
+
+ WaitForSingleObject(hConnectionHeaderMutex,INFINITE);
+ if (nlc->usingHttpGateway)
+ {
+ HttpGatewayRemovePacket(nlc, -1);
+ }
+ else
+ {
+ if(nlc->s != INVALID_SOCKET) {
+ NetlibDoClose(nlc);
+ }
+ if (nlc->s2 != INVALID_SOCKET) closesocket(nlc->s2);
+ nlc->s2 = INVALID_SOCKET;
+ }
+ ReleaseMutex(hConnectionHeaderMutex);
+
+ waitHandles[0]=hConnectionHeaderMutex;
+ waitHandles[1]=nlc->hOkToCloseEvent;
+ waitHandles[2]=nlc->ncsRecv.hMutex;
+ waitHandles[3]=nlc->ncsSend.hMutex;
+ waitResult=WaitForMultipleObjects( SIZEOF(waitHandles),waitHandles,TRUE,INFINITE);
+ if(waitResult<WAIT_OBJECT_0 || waitResult >= WAIT_OBJECT_0 + SIZEOF(waitHandles)) {
+ ReleaseMutex(hConnectionHeaderMutex);
+ SetLastError(ERROR_INVALID_PARAMETER); //already been closed
+ return 0;
+ }
+ nlc->handleType=0;
+ mir_free(nlc->nlhpi.szHttpPostUrl);
+ mir_free(nlc->nlhpi.szHttpGetUrl);
+ mir_free(nlc->dataBuffer);
+ mir_free((char*)nlc->nloc.szHost);
+ mir_free(nlc->szNewUrl);
+ mir_free(nlc->szProxyServer);
+ NetlibDeleteNestedCS(&nlc->ncsRecv);
+ NetlibDeleteNestedCS(&nlc->ncsSend);
+ CloseHandle(nlc->hOkToCloseEvent);
+ DeleteCriticalSection(&nlc->csHttpSequenceNums);
+ ReleaseMutex(hConnectionHeaderMutex);
+ NetlibLogf(nlc->nlu,"(%p:%u) Connection closed",nlc,nlc->s);
+ break;
+ }
+ case NLH_BOUNDPORT:
+ return NetlibFreeBoundPort((struct NetlibBoundPort*)wParam);
+ case NLH_PACKETRECVER:
+ { struct NetlibPacketRecver *nlpr=(struct NetlibPacketRecver*)wParam;
+ mir_free(nlpr->packetRecver.buffer);
+ break;
+ }
+ default:
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ mir_free((void*)wParam);
+ return 1;
+}
+
+static INT_PTR NetlibGetSocket(WPARAM wParam, LPARAM)
+{
+ SOCKET s;
+ if(wParam==0) {
+ s=INVALID_SOCKET;
+ SetLastError(ERROR_INVALID_PARAMETER);
+ }
+ else {
+ WaitForSingleObject(hConnectionHeaderMutex,INFINITE);
+ switch(GetNetlibHandleType(wParam)) {
+ case NLH_CONNECTION:
+ s=((struct NetlibConnection*)wParam)->s;
+ break;
+ case NLH_BOUNDPORT:
+ s=((struct NetlibBoundPort*)wParam)->s;
+ break;
+ default:
+ s=INVALID_SOCKET;
+ SetLastError(ERROR_INVALID_PARAMETER);
+ break;
+ }
+ ReleaseMutex(hConnectionHeaderMutex);
+ }
+ return s;
+}
+
+INT_PTR NetlibShutdown(WPARAM wParam, LPARAM)
+{
+ if (wParam)
+ {
+ WaitForSingleObject(hConnectionHeaderMutex,INFINITE);
+ switch(GetNetlibHandleType(wParam)) {
+ case NLH_CONNECTION:
+ {
+ struct NetlibConnection* nlc = (struct NetlibConnection*)wParam;
+ if (nlc->hSsl) si.shutdown(nlc->hSsl);
+ if (nlc->s != INVALID_SOCKET) shutdown(nlc->s, 2);
+ if (nlc->s2 != INVALID_SOCKET) shutdown(nlc->s2, 2);
+ nlc->termRequested = true;
+ }
+ break;
+ case NLH_BOUNDPORT:
+ {
+ struct NetlibBoundPort* nlb = (struct NetlibBoundPort*)wParam;
+ if (nlb->s != INVALID_SOCKET) shutdown(nlb->s, 2);
+ }
+ break;
+ }
+ ReleaseMutex(hConnectionHeaderMutex);
+
+ }
+ return 0;
+}
+
+static const char szHexDigits[]="0123456789ABCDEF";
+INT_PTR NetlibHttpUrlEncode(WPARAM,LPARAM lParam)
+{
+ unsigned char *szOutput,*szInput=(unsigned char*)lParam;
+ unsigned char *pszIn,*pszOut;
+ int outputLen;
+
+ if(szInput==NULL) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return (INT_PTR)(char*)NULL;
+ }
+ for(outputLen=0,pszIn=szInput;*pszIn;pszIn++) {
+ if ( (48 <= *pszIn && *pszIn <= 57) ||//0-9
+ (65 <= *pszIn && *pszIn <= 90) ||//ABC...XYZ
+ (97 <= *pszIn && *pszIn <= 122) ||//abc...xyz
+ *pszIn == '-' || *pszIn == '_' || *pszIn == '.' || *pszIn == ' ') outputLen++;
+ else outputLen+=3;
+ }
+ szOutput=(unsigned char*)HeapAlloc(GetProcessHeap(),0,outputLen+1);
+ if(szOutput==NULL) {
+ SetLastError(ERROR_OUTOFMEMORY);
+ return (INT_PTR)(unsigned char*)NULL;
+ }
+ for(pszOut=szOutput,pszIn=szInput;*pszIn;pszIn++) {
+ if ( (48 <= *pszIn && *pszIn <= 57) ||
+ (65 <= *pszIn && *pszIn <= 90) ||
+ (97 <= *pszIn && *pszIn <= 122) ||
+ *pszIn == '-' || *pszIn == '_' || *pszIn == '.') *pszOut++=*pszIn;
+ else if(*pszIn==' ') *pszOut++='+';
+ else {
+ *pszOut++='%';
+ *pszOut++=szHexDigits[*pszIn>>4];
+ *pszOut++=szHexDigits[*pszIn&0xF];
+ }
+ }
+ *pszOut='\0';
+ return (INT_PTR)szOutput;
+}
+
+static const char base64chars[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+INT_PTR NetlibBase64Encode(WPARAM, LPARAM lParam)
+{
+ NETLIBBASE64 *nlb64=(NETLIBBASE64*)lParam;
+ int iIn;
+ char *pszOut;
+ PBYTE pbIn;
+
+ if(nlb64==NULL || nlb64->pszEncoded==NULL || nlb64->pbDecoded==NULL) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ if(nlb64->cchEncoded<Netlib_GetBase64EncodedBufferSize(nlb64->cbDecoded)) {
+ SetLastError(ERROR_BUFFER_OVERFLOW);
+ return 0;
+ }
+ nlb64->cchEncoded=Netlib_GetBase64EncodedBufferSize(nlb64->cbDecoded);
+ for(iIn=0,pbIn=nlb64->pbDecoded,pszOut=nlb64->pszEncoded;iIn<nlb64->cbDecoded;iIn+=3,pbIn+=3,pszOut+=4) {
+ pszOut[0]=base64chars[pbIn[0]>>2];
+ if(nlb64->cbDecoded-iIn==1) {
+ pszOut[1]=base64chars[(pbIn[0]&3)<<4];
+ pszOut[2]='=';
+ pszOut[3]='=';
+ pszOut+=4;
+ break;
+ }
+ pszOut[1]=base64chars[((pbIn[0]&3)<<4)|(pbIn[1]>>4)];
+ if(nlb64->cbDecoded-iIn==2) {
+ pszOut[2]=base64chars[(pbIn[1]&0xF)<<2];
+ pszOut[3]='=';
+ pszOut+=4;
+ break;
+ }
+ pszOut[2]=base64chars[((pbIn[1]&0xF)<<2)|(pbIn[2]>>6)];
+ pszOut[3]=base64chars[pbIn[2]&0x3F];
+ }
+ pszOut[0]='\0';
+ return 1;
+}
+
+static BYTE Base64CharToInt(char c)
+{
+ if(c>='A' && c<='Z') return c-'A';
+ if(c>='a' && c<='z') return c-'a'+26;
+ if(c>='0' && c<='9') return c-'0'+52;
+ if(c=='+') return 62;
+ if(c=='/') return 63;
+ if(c=='=') return 64;
+ return 255;
+}
+
+INT_PTR NetlibBase64Decode(WPARAM, LPARAM lParam)
+{
+ NETLIBBASE64 *nlb64=(NETLIBBASE64*)lParam;
+ char *pszIn;
+ PBYTE pbOut;
+ BYTE b1,b2,b3,b4;
+ int iIn;
+
+ if(nlb64==NULL || nlb64->pszEncoded==NULL || nlb64->pbDecoded==NULL) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ if(nlb64->cchEncoded&3) {
+ SetLastError(ERROR_INVALID_DATA);
+ return 0;
+ }
+ if(nlb64->cbDecoded<Netlib_GetBase64DecodedBufferSize(nlb64->cchEncoded)) {
+ SetLastError(ERROR_BUFFER_OVERFLOW);
+ return 0;
+ }
+ nlb64->cbDecoded=Netlib_GetBase64DecodedBufferSize(nlb64->cchEncoded);
+ for(iIn=0,pszIn=nlb64->pszEncoded,pbOut=nlb64->pbDecoded;iIn<nlb64->cchEncoded;iIn+=4,pszIn+=4,pbOut+=3) {
+ b1=Base64CharToInt(pszIn[0]);
+ b2=Base64CharToInt(pszIn[1]);
+ b3=Base64CharToInt(pszIn[2]);
+ b4=Base64CharToInt(pszIn[3]);
+ if(b1==255 || b1==64 || b2==255 || b2==64 || b3==255 || b4==255) {
+ SetLastError(ERROR_INVALID_DATA);
+ return 0;
+ }
+ pbOut[0]=(b1<<2)|(b2>>4);
+ if(b3==64) {nlb64->cbDecoded-=2; break;}
+ pbOut[1]=(b2<<4)|(b3>>2);
+ if(b4==64) {nlb64->cbDecoded--; break;}
+ pbOut[2]=b4|(b3<<6);
+ }
+ return 1;
+}
+
+void UnloadNetlibModule(void)
+{
+ if (!bModuleInitialized) return;
+
+ if (hConnectionHeaderMutex != NULL)
+ {
+ int i;
+
+ NetlibUnloadIeProxy();
+ NetlibSecurityDestroy();
+ NetlibUPnPDestroy();
+ NetlibLogShutdown();
+
+ DestroyHookableEvent(hRecvEvent); hRecvEvent = NULL;
+ DestroyHookableEvent(hSendEvent); hSendEvent = NULL;
+
+ for (i = netlibUser.getCount(); i > 0; i--)
+ NetlibCloseHandle((WPARAM)netlibUser[i-1], 0);
+
+ netlibUser.destroy();
+
+ CloseHandle(hConnectionHeaderMutex);
+ if (hConnectionOpenMutex) CloseHandle(hConnectionOpenMutex);
+ DeleteCriticalSection(&csNetlibUser);
+ WSACleanup();
+ }
+}
+
+int LoadNetlibModule(void)
+{
+ WSADATA wsadata;
+
+ bModuleInitialized = TRUE;
+
+ WSAStartup(MAKEWORD(2,2), &wsadata);
+
+ HookEvent(ME_OPT_INITIALISE,NetlibOptInitialise);
+
+ InitializeCriticalSection(&csNetlibUser);
+ hConnectionHeaderMutex=CreateMutex(NULL,FALSE,NULL);
+ NetlibLogInit();
+
+ connectionTimeout = 0;
+
+ OSVERSIONINFOEX osvi = {0};
+ osvi.dwOSVersionInfoSize = sizeof(osvi);
+ if (GetVersionEx((LPOSVERSIONINFO)&osvi))
+ {
+ // Connection limiting was introduced in Windows XP SP2 and later and set to 10 / sec
+ if (osvi.dwMajorVersion == 5 && ((osvi.dwMinorVersion == 1 && osvi.wServicePackMajor >= 2) || osvi.dwMinorVersion > 1))
+ connectionTimeout = 150;
+ // Connection limiting has limits based on addition Windows Vista pre SP2
+ else if (osvi.dwMajorVersion == 6 && osvi.wServicePackMajor < 2)
+ {
+ DWORD dwType = 0;
+ tGetProductInfo pGetProductInfo = (tGetProductInfo) GetProcAddress(GetModuleHandleA("kernel32"), "GetProductInfo");
+ if (pGetProductInfo != NULL) pGetProductInfo(6, 0, 0, 0, &dwType);
+ switch( dwType )
+ {
+ case 0x01: // Vista Ultimate edition have connection limit of 25 / sec - plenty for Miranda
+ case 0x1c:
+ break;
+
+ case 0x02: // Vista Home Basic edition have connection limit of 2 / sec
+ case 0x05:
+ connectionTimeout = 1000;
+ break;
+
+ default: // all other editions have connection limit of 10 / sec
+ connectionTimeout = 150;
+ break;
+ }
+ }
+ // Connection limiting is disabled by default and is controlled by registry setting in Windows Vista SP2 and later
+ else if (osvi.dwMajorVersion >= 6)
+ {
+ static const char keyn[] = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters";
+ static const char valn[] = "EnableConnectionRateLimiting";
+
+ HKEY hSettings;
+ if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, keyn, 0, KEY_QUERY_VALUE, &hSettings) == ERROR_SUCCESS)
+ {
+ DWORD tValueLen, enabled;
+ tValueLen = sizeof(enabled);
+ if (RegQueryValueExA(hSettings, valn, NULL, NULL, (BYTE*)&enabled, &tValueLen) == ERROR_SUCCESS && enabled)
+ connectionTimeout = 150; // if enabled limit is set to 10 / sec
+ RegCloseKey(hSettings);
+ }
+
+ }
+ }
+
+ hConnectionOpenMutex = connectionTimeout ? CreateMutex(NULL,FALSE,NULL) : NULL;
+ g_LastConnectionTick = GetTickCount();
+
+ CreateServiceFunction(MS_NETLIB_REGISTERUSER,NetlibRegisterUser);
+ CreateServiceFunction(MS_NETLIB_GETUSERSETTINGS,NetlibGetUserSettings);
+ CreateServiceFunction(MS_NETLIB_SETUSERSETTINGS,NetlibSetUserSettings);
+ CreateServiceFunction(MS_NETLIB_CLOSEHANDLE,NetlibCloseHandle);
+ CreateServiceFunction(MS_NETLIB_BINDPORT,NetlibBindPort);
+ CreateServiceFunction(MS_NETLIB_OPENCONNECTION,NetlibOpenConnection);
+ CreateServiceFunction(MS_NETLIB_SETHTTPPROXYINFO,NetlibHttpGatewaySetInfo);
+ CreateServiceFunction(MS_NETLIB_SETSTICKYHEADERS,NetlibHttpSetSticky);
+ CreateServiceFunction(MS_NETLIB_GETSOCKET,NetlibGetSocket);
+ CreateServiceFunction(MS_NETLIB_URLENCODE,NetlibHttpUrlEncode);
+ CreateServiceFunction(MS_NETLIB_BASE64ENCODE,NetlibBase64Encode);
+ CreateServiceFunction(MS_NETLIB_BASE64DECODE,NetlibBase64Decode);
+ CreateServiceFunction(MS_NETLIB_SENDHTTPREQUEST,NetlibHttpSendRequest);
+ CreateServiceFunction(MS_NETLIB_RECVHTTPHEADERS,NetlibHttpRecvHeaders);
+ CreateServiceFunction(MS_NETLIB_FREEHTTPREQUESTSTRUCT,NetlibHttpFreeRequestStruct);
+ CreateServiceFunction(MS_NETLIB_HTTPTRANSACTION,NetlibHttpTransaction);
+ CreateServiceFunction(MS_NETLIB_SEND,NetlibSend);
+ CreateServiceFunction(MS_NETLIB_RECV,NetlibRecv);
+ CreateServiceFunction(MS_NETLIB_SELECT,NetlibSelect);
+ CreateServiceFunction(MS_NETLIB_SELECTEX,NetlibSelectEx);
+ CreateServiceFunction(MS_NETLIB_SHUTDOWN,NetlibShutdown);
+ CreateServiceFunction(MS_NETLIB_CREATEPACKETRECVER,NetlibPacketRecverCreate);
+ CreateServiceFunction(MS_NETLIB_GETMOREPACKETS,NetlibPacketRecverGetMore);
+ CreateServiceFunction(MS_NETLIB_SETPOLLINGTIMEOUT,NetlibHttpSetPollingTimeout);
+ CreateServiceFunction(MS_NETLIB_STARTSSL,NetlibStartSsl);
+
+ hRecvEvent = CreateHookableEvent(ME_NETLIB_FASTRECV);
+ hSendEvent = CreateHookableEvent(ME_NETLIB_FASTSEND);
+
+ NetlibUPnPInit();
+ NetlibSecurityInit();
+ NetlibLoadIeProxy();
+
+ return 0;
+}
+
+void NetlibInitSsl(void)
+{
+ mir_getSI(&si);
+}
diff --git a/src/modules/netlib/netlib.h b/src/modules/netlib/netlib.h
new file mode 100644
index 0000000000..575e77f18c
--- /dev/null
+++ b/src/modules/netlib/netlib.h
@@ -0,0 +1,209 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2012 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.
+*/
+#define GetNetlibHandleType(h) (h?*(int*)h:NLH_INVALID)
+#define NLH_INVALID 0
+#define NLH_USER 'USER'
+#define NLH_CONNECTION 'CONN'
+#define NLH_BOUNDPORT 'BIND'
+#define NLH_PACKETRECVER 'PCKT'
+
+struct NetlibUser
+{
+ int handleType;
+ NETLIBUSER user;
+ NETLIBUSERSETTINGS settings;
+ char * szStickyHeaders;
+ int toLog;
+ int inportnum;
+ int outportnum;
+};
+
+struct NetlibNestedCriticalSection
+{
+ HANDLE hMutex;
+ DWORD dwOwningThreadId;
+ int lockCount;
+};
+
+struct NetlibHTTPProxyPacketQueue
+{
+ struct NetlibHTTPProxyPacketQueue *next;
+ PBYTE dataBuffer;
+ int dataBufferLen;
+};
+
+struct NetlibConnection
+{
+ int handleType;
+ SOCKET s, s2;
+ bool usingHttpGateway;
+ bool usingDirectHttpGateway;
+ bool proxyAuthNeeded;
+ bool dnsThroughProxy;
+ bool termRequested;
+ struct NetlibUser *nlu;
+ NETLIBHTTPPROXYINFO nlhpi;
+ PBYTE dataBuffer;
+ int dataBufferLen;
+ CRITICAL_SECTION csHttpSequenceNums;
+ HANDLE hOkToCloseEvent;
+ LONG dontCloseNow;
+ struct NetlibNestedCriticalSection ncsSend,ncsRecv;
+ HSSL hSsl;
+ struct NetlibHTTPProxyPacketQueue * pHttpProxyPacketQueue;
+ char *szNewUrl;
+ char *szProxyServer;
+ WORD wProxyPort;
+ int proxyType;
+ int pollingTimeout;
+ unsigned lastPost;
+ NETLIBOPENCONNECTION nloc;
+};
+
+struct NetlibBoundPort {
+ int handleType;
+ SOCKET s;
+ WORD wPort;
+ WORD wExPort;
+ struct NetlibUser *nlu;
+ NETLIBNEWCONNECTIONPROC_V2 pfnNewConnectionV2;
+ HANDLE hThread;
+ void *pExtra;
+};
+
+struct NetlibPacketRecver {
+ int handleType;
+ struct NetlibConnection *nlc;
+ NETLIBPACKETRECVER packetRecver;
+};
+
+//netlib.c
+void NetlibFreeUserSettingsStruct(NETLIBUSERSETTINGS *settings);
+void NetlibDoClose(NetlibConnection *nlc, bool noShutdown = false);
+INT_PTR NetlibCloseHandle(WPARAM wParam,LPARAM lParam);
+void NetlibInitializeNestedCS(struct NetlibNestedCriticalSection *nlncs);
+void NetlibDeleteNestedCS(struct NetlibNestedCriticalSection *nlncs);
+#define NLNCS_SEND 0
+#define NLNCS_RECV 1
+int NetlibEnterNestedCS(struct NetlibConnection *nlc,int which);
+void NetlibLeaveNestedCS(struct NetlibNestedCriticalSection *nlncs);
+INT_PTR NetlibBase64Encode(WPARAM wParam,LPARAM lParam);
+INT_PTR NetlibBase64Decode(WPARAM wParam,LPARAM lParam);
+INT_PTR NetlibHttpUrlEncode(WPARAM wParam,LPARAM lParam);
+
+extern CRITICAL_SECTION csNetlibUser;
+extern LIST<NetlibUser> netlibUser;
+
+//netlibautoproxy.c
+void NetlibLoadIeProxy(void);
+void NetlibUnloadIeProxy(void);
+char* NetlibGetIeProxy(char *szUrl);
+bool NetlibGetIeProxyConn(NetlibConnection *nlc, bool forceHttps);
+
+//netlibbind.c
+int NetlibFreeBoundPort(struct NetlibBoundPort *nlbp);
+INT_PTR NetlibBindPort(WPARAM wParam,LPARAM lParam);
+bool BindSocketToPort(const char *szPorts, SOCKET s, int* portn);
+
+//netlibhttp.c
+INT_PTR NetlibHttpSendRequest(WPARAM wParam,LPARAM lParam);
+INT_PTR NetlibHttpRecvHeaders(WPARAM wParam,LPARAM lParam);
+INT_PTR NetlibHttpFreeRequestStruct(WPARAM wParam,LPARAM lParam);
+INT_PTR NetlibHttpTransaction(WPARAM wParam,LPARAM lParam);
+void NetlibHttpSetLastErrorUsingHttpResult(int result);
+NETLIBHTTPREQUEST* NetlibHttpRecv(NetlibConnection* nlc, DWORD hflags, DWORD dflags, bool isConnect = false);
+void NetlibConnFromUrl(const char* szUrl, bool secur, NETLIBOPENCONNECTION &nloc);
+
+//netlibhttpproxy.c
+int NetlibInitHttpConnection(struct NetlibConnection *nlc,struct NetlibUser *nlu,NETLIBOPENCONNECTION *nloc);
+int NetlibHttpGatewayRecv(struct NetlibConnection *nlc,char *buf,int len,int flags);
+int NetlibHttpGatewayPost(struct NetlibConnection *nlc,const char *buf,int len,int flags);
+void HttpGatewayRemovePacket(NetlibConnection *nlc, int pck);
+
+INT_PTR NetlibHttpGatewaySetInfo(WPARAM wParam,LPARAM lParam);
+INT_PTR NetlibHttpSetPollingTimeout(WPARAM wParam,LPARAM lParam);
+INT_PTR NetlibHttpSetSticky(WPARAM wParam, LPARAM lParam);
+
+//netliblog.c
+void NetlibLogShowOptions(void);
+void NetlibDumpData(struct NetlibConnection *nlc,PBYTE buf,int len,int sent,int flags);
+void NetlibLogf(NetlibUser* nlu, const char *fmt, ...);
+void NetlibLogInit(void);
+void NetlibLogShutdown(void);
+
+//netlibopenconn.c
+DWORD DnsLookup(struct NetlibUser *nlu,const char *szHost);
+int WaitUntilReadable(SOCKET s,DWORD dwTimeout, bool check = false);
+int WaitUntilWritable(SOCKET s,DWORD dwTimeout);
+bool NetlibDoConnect(NetlibConnection *nlc);
+bool NetlibReconnect(NetlibConnection *nlc);
+INT_PTR NetlibOpenConnection(WPARAM wParam,LPARAM lParam);
+INT_PTR NetlibStartSsl(WPARAM wParam, LPARAM lParam);
+
+//netlibopts.c
+int NetlibOptInitialise(WPARAM wParam,LPARAM lParam);
+void NetlibSaveUserSettingsStruct(const char *szSettingsModule,NETLIBUSERSETTINGS *settings);
+
+//netlibpktrecver.c
+INT_PTR NetlibPacketRecverCreate(WPARAM wParam,LPARAM lParam);
+INT_PTR NetlibPacketRecverGetMore(WPARAM wParam,LPARAM lParam);
+
+//netlibsock.c
+#define NL_SELECT_READ 0x0001
+#define NL_SELECT_WRITE 0x0002
+#define NL_SELECT_ALL (NL_SELECT_READ+NL_SELECT_WRITE)
+
+INT_PTR NetlibSend(WPARAM wParam,LPARAM lParam);
+INT_PTR NetlibRecv(WPARAM wParam,LPARAM lParam);
+INT_PTR NetlibSelect(WPARAM wParam,LPARAM lParam);
+INT_PTR NetlibSelectEx(WPARAM wParam,LPARAM lParam);
+INT_PTR NetlibShutdown(WPARAM wParam,LPARAM lParam);
+
+//netlibupnp.c
+bool NetlibUPnPAddPortMapping(WORD intport, char *proto,
+ WORD *extport, DWORD *extip, bool search);
+void NetlibUPnPDeletePortMapping(WORD extport, char* proto);
+void NetlibUPnPCleanup(void*);
+void NetlibUPnPInit(void);
+void NetlibUPnPDestroy(void);
+
+//netlibsecurity.c
+void NetlibSecurityInit(void);
+void NetlibSecurityDestroy(void);
+void NetlibDestroySecurityProvider(HANDLE hSecurity);
+HANDLE NetlibInitSecurityProvider(const TCHAR* szProvider, const TCHAR* szPrincipal);
+#ifdef UNICODE
+HANDLE NetlibInitSecurityProvider(const char* szProvider, const char* szPrincipal);
+#endif
+char* NtlmCreateResponseFromChallenge(HANDLE hSecurity, const char *szChallenge, const TCHAR* login, const TCHAR* psw,
+ bool http, unsigned& complete);
+
+
+static __inline INT_PTR NLSend(struct NetlibConnection *nlc,const char *buf,int len,int flags) {
+ NETLIBBUFFER nlb={(char*)buf,len,flags};
+ return NetlibSend((WPARAM)nlc,(LPARAM)&nlb);
+}
+static __inline INT_PTR NLRecv(struct NetlibConnection *nlc,char *buf,int len,int flags) {
+ NETLIBBUFFER nlb={buf,len,flags};
+ return NetlibRecv((WPARAM)nlc,(LPARAM)&nlb);
+}
diff --git a/src/modules/netlib/netlibautoproxy.cpp b/src/modules/netlib/netlibautoproxy.cpp
new file mode 100644
index 0000000000..e169cf9c89
--- /dev/null
+++ b/src/modules/netlib/netlibautoproxy.cpp
@@ -0,0 +1,460 @@
+/*
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2010-2011 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 "netlib.h"
+
+#include <wininet.h>
+/*
+/////////////////////////////////////////////////////////////////////
+// ResolveHostName (a helper function)
+/////////////////////////////////////////////////////////////////////
+DWORD __stdcall ResolveHostName(LPSTR lpszHostName,
+ LPSTR lpszIPAddress, LPDWORD lpdwIPAddressSize)
+{
+ if (*lpdwIPAddressSize < 17 || lpszIPAddress == NULL)
+ {
+ *lpdwIPAddressSize = 17;
+ return ERROR_INSUFFICIENT_BUFFER;
+ }
+
+ IN_ADDR ip;
+ ip.s_addr = inet_addr(lpszHostName);
+ if (ip.s_addr == INADDR_NONE)
+ {
+ PHOSTENT myhost = gethostbyname(lpszHostName);
+ if (myhost != NULL)
+ ip = *(PIN_ADDR)myhost->h_addr;
+ else
+ return SOCKET_ERROR;
+ }
+ mir_snprintf(lpszIPAddress, *lpdwIPAddressSize, "%u.%u.%u.%u",
+ ip.s_net, ip.s_host, ip.s_lh, ip.s_impno);
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////
+// IsResolvable (a helper function)
+/////////////////////////////////////////////////////////////////////
+BOOL __stdcall IsResolvable(LPSTR lpszHost)
+{
+ char szDummy[255];
+ DWORD dwDummySize = sizeof (szDummy) - 1;
+
+ if (ResolveHostName(lpszHost, szDummy, &dwDummySize))
+ return FALSE;
+ return TRUE;
+}
+
+/////////////////////////////////////////////////////////////////////
+// GetIPAddress (a helper function)
+/////////////////////////////////////////////////////////////////////
+DWORD __stdcall GetIPAddress(LPSTR lpszIPAddress, LPDWORD lpdwIPAddressSize)
+{
+ char szHostBuffer[255];
+
+ if (gethostname(szHostBuffer, sizeof (szHostBuffer) - 1) != ERROR_SUCCESS)
+ return (ERROR_INTERNET_INTERNAL_ERROR);
+ return (ResolveHostName(szHostBuffer, lpszIPAddress, lpdwIPAddressSize));
+}
+
+/////////////////////////////////////////////////////////////////////
+// IsInNet (a helper function)
+/////////////////////////////////////////////////////////////////////
+BOOL __stdcall IsInNet(LPSTR lpszIPAddress, LPSTR lpszDest, LPSTR lpszMask)
+{
+ DWORD dwDest;
+ DWORD dwIpAddr;
+ DWORD dwMask;
+
+ dwIpAddr = inet_addr(lpszIPAddress);
+ dwDest = inet_addr(lpszDest);
+ dwMask = inet_addr(lpszMask);
+
+ if ((dwDest == INADDR_NONE) ||
+ (dwIpAddr == INADDR_NONE) || ((dwIpAddr & dwMask) != dwDest))
+ return (FALSE);
+
+ return (TRUE);
+}
+
+static const AutoProxyHelperVtbl OurVtbl =
+{
+ IsResolvable,
+ GetIPAddress,
+ ResolveHostName,
+ IsInNet,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+static AutoProxyHelperFunctions HelperFunctions = { &OurVtbl };
+*/
+
+static char *szProxyHost[3];
+static LIST<char> proxyBypass(5);
+
+static HMODULE hModJS;
+
+static pfnInternetInitializeAutoProxyDll pInternetInitializeAutoProxyDll;
+static pfnInternetDeInitializeAutoProxyDll pInternetDeInitializeAutoProxyDll;
+static pfnInternetGetProxyInfo pInternetGetProxyInfo;
+
+static bool bEnabled, bOneProxy;
+
+static void GetFile(char* szUrl, AUTO_PROXY_SCRIPT_BUFFER &buf)
+{
+ NetlibUser nlu = {0};
+ NETLIBHTTPREQUEST nlhr = {0};
+
+ nlu.handleType = NLH_USER;
+ nlu.user.flags = NUF_OUTGOING | NUF_HTTPCONNS;
+ nlu.user.szSettingsModule = "(NULL)";
+ nlu.toLog = 1;
+
+ // initialize the netlib request
+ nlhr.cbSize = sizeof(nlhr);
+ nlhr.requestType = REQUEST_GET;
+ nlhr.flags = NLHRF_HTTP11 | NLHRF_DUMPASTEXT | NLHRF_REDIRECT;
+ nlhr.szUrl = szUrl;
+
+ // download the page
+ NETLIBHTTPREQUEST *nlhrReply = (NETLIBHTTPREQUEST*)NetlibHttpTransaction((WPARAM)&nlu, (LPARAM)&nlhr);
+
+ if (nlhrReply)
+ {
+ if (nlhrReply->resultCode == 200)
+ {
+ buf.lpszScriptBuffer = nlhrReply->pData;
+ buf.dwScriptBufferSize = nlhrReply->dataLength + 1;
+
+ nlhrReply->dataLength = 0;
+ nlhrReply->pData = NULL;
+ }
+ CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)nlhrReply);
+ }
+}
+
+bool NetlibGetIeProxyConn(NetlibConnection *nlc, bool forceHttps)
+{
+ bool noHttp = false;
+ bool usingSsl = false;
+ char szUrl[256] = "";
+
+ if ((nlc->nloc.flags & (NLOCF_HTTP | NLOCF_HTTPGATEWAY) && nlc->nloc.flags & NLOCF_SSL) ||
+ nlc->nloc.wPort == 443 || forceHttps)
+ {
+ mir_snprintf(szUrl, sizeof(szUrl), "https://%s", nlc->nloc.szHost);
+ usingSsl = true;
+ }
+ else if (nlc->nloc.flags & (NLOCF_HTTPGATEWAY | NLOCF_HTTP) || nlc->usingHttpGateway)
+ mir_snprintf(szUrl, sizeof(szUrl), "http://%s", nlc->nloc.szHost);
+ else
+ {
+ mir_snprintf(szUrl, sizeof(szUrl), "%s", nlc->nloc.szHost);
+ noHttp = true;
+ }
+
+ mir_free(nlc->szProxyServer); nlc->szProxyServer = NULL;
+ nlc->wProxyPort = 0;
+ nlc->proxyType = 0;
+
+ char *mt = NetlibGetIeProxy(szUrl);
+ char *m = NEWSTR_ALLOCA(mt);
+ mir_free(mt);
+
+ if (m == NULL) return false;
+
+ // if multiple servers, use the first one
+ char *c = strchr(m, ';'); if (c) *c = 0;
+
+ // if 'direct' no proxy
+ if (_stricmp(lrtrim(m), "direct") == 0) return false;
+
+ // find proxy address
+ char *h = strchr(m, ' ');
+ if (h) { *h = 0; ++h; } else return false;
+
+ // find proxy port
+ char *p = strchr(h, ':');
+ if (p) { *p = 0; ++p; }
+
+ lrtrim(h); ltrim(p);
+ if (_stricmp(m, "proxy") == 0 && h[0])
+ {
+ nlc->proxyType = (usingSsl || noHttp) ? PROXYTYPE_HTTPS : PROXYTYPE_HTTP;
+ nlc->wProxyPort = p ? atol(p) : 8080;
+ nlc->szProxyServer = mir_strdup(h);
+ }
+ else if (_stricmp(m, "socks") == 0 && h[0])
+ {
+ nlc->proxyType = PROXYTYPE_SOCKS4;
+ nlc->wProxyPort = p ? atol(p) : 1080;
+ nlc->szProxyServer = mir_strdup(h);
+ }
+ else if (_stricmp(m, "socks5") == 0 && h[0])
+ {
+ nlc->proxyType = PROXYTYPE_SOCKS5;
+ nlc->wProxyPort = p ? atol(p) : 1080;
+ nlc->szProxyServer = mir_strdup(h);
+ }
+ else
+ return false;
+
+ return true;
+}
+
+static char szAutoUrlStr[MAX_PATH] = "";
+static AUTO_PROXY_SCRIPT_BUFFER abuf = {0};
+static HANDLE hIeProxyMutex;
+static bool bAutoProxyInit;
+
+static void NetlibInitAutoProxy(void)
+{
+ if (bAutoProxyInit) return;
+
+ if (!hModJS)
+ {
+ if (!(hModJS = LoadLibraryA("jsproxy.dll")))
+ return;
+
+ pInternetInitializeAutoProxyDll = (pfnInternetInitializeAutoProxyDll)
+ GetProcAddress(hModJS, "InternetInitializeAutoProxyDll");
+
+ pInternetDeInitializeAutoProxyDll = (pfnInternetDeInitializeAutoProxyDll)
+ GetProcAddress(hModJS, "InternetDeInitializeAutoProxyDll");
+
+ pInternetGetProxyInfo = (pfnInternetGetProxyInfo)
+ GetProcAddress(hModJS, "InternetGetProxyInfo");
+ }
+
+ if (strstr(szAutoUrlStr, "file://") == NULL && strstr(szAutoUrlStr, "://") != NULL)
+ {
+ abuf.dwStructSize = sizeof(abuf);
+ GetFile(szAutoUrlStr, abuf);
+ }
+ bAutoProxyInit = true;
+}
+
+struct IeProxyParam
+{
+ char *szUrl;
+ char *szHost;
+ char *szProxy;
+};
+
+static unsigned __stdcall NetlibIeProxyThread(void * arg)
+{
+ IeProxyParam *param = (IeProxyParam*)arg;
+ param->szProxy = NULL;
+
+ if (!bAutoProxyInit)
+ {
+ WaitForSingleObject(hIeProxyMutex, INFINITE);
+ NetlibInitAutoProxy();
+ ReleaseMutex(hIeProxyMutex);
+ }
+
+ BOOL res;
+ char *loc = strstr(szAutoUrlStr, "file://");
+ if (loc || strstr(szAutoUrlStr, "://") == NULL)
+ {
+ NetlibLogf(NULL, "Autoproxy Init file: %s", loc);
+ loc = loc ? loc + 7 : szAutoUrlStr;
+ res = pInternetInitializeAutoProxyDll(0, loc, NULL, NULL /*&HelperFunctions*/, NULL);
+ }
+ else
+ {
+ NetlibLogf(NULL, "Autoproxy Init %d", abuf.dwScriptBufferSize);
+ if (abuf.dwScriptBufferSize)
+ res = pInternetInitializeAutoProxyDll(0, NULL, NULL, NULL /*&HelperFunctions*/, &abuf);
+ else
+ res = false;
+ }
+
+ if (res)
+ {
+ char proxyBuffer[1024];
+ char *proxy = proxyBuffer;
+ DWORD dwProxyLen = sizeof(proxyBuffer);
+
+ if (pInternetGetProxyInfo(param->szUrl, (DWORD)strlen(param->szUrl),
+ param->szHost, (DWORD)strlen(param->szHost), &proxy, &dwProxyLen))
+ param->szProxy = mir_strdup(lrtrim(proxy));
+
+ NetlibLogf(NULL, "Autoproxy got response %s, Param: %s %s", param->szProxy, param->szUrl, param->szHost);
+ pInternetDeInitializeAutoProxyDll(NULL, 0);
+ }
+ else
+ NetlibLogf(NULL, "Autoproxy init failed");
+
+ return 0;
+}
+
+char* NetlibGetIeProxy(char *szUrl)
+{
+ char *res = NULL;
+ char* p = strstr(szUrl, "://");
+ if (p) p += 3; else p = szUrl;
+
+ char *szHost = NEWSTR_ALLOCA(p);
+ p = strchr(szHost, '/'); if (p) *p = 0;
+ p = strchr(szHost, ':'); if (p) *p = 0;
+ _strlwr(szHost);
+
+ if (bEnabled)
+ {
+ for (int i = 0; i < proxyBypass.getCount(); ++i)
+ {
+ if (strcmp(proxyBypass[i], "<local>") == 0)
+ {
+ if (strchr(szHost, '.') == NULL) return NULL;
+ }
+ else if (wildcmp(szHost, proxyBypass[i])) return NULL;
+ }
+
+ int ind = -1;
+ if (strstr(szUrl, "http://"))
+ ind = szProxyHost[0] ? 0 : 2;
+ else if (strstr(szUrl, "https://"))
+ ind = bOneProxy ? 0 : (szProxyHost[1] ? 1 : 2);
+ else
+ ind = szProxyHost[2] ? 2 : (bOneProxy ? 0 : (szProxyHost[1] ? 1 : 2));
+
+ if (ind < 0 || !szProxyHost[ind]) return NULL;
+
+ size_t len = strlen(szHost) + 20;
+ res = (char*)mir_alloc(len);
+ mir_snprintf(res, len, "%s %s", ind == 2 ? "SOCKS" : "PROXY", szProxyHost[ind]);
+ return res;
+ }
+
+ if (szAutoUrlStr[0])
+ {
+ unsigned dwThreadId;
+ IeProxyParam param = { szUrl, szHost, NULL };
+ HANDLE hThread = (HANDLE)forkthreadex(NULL, 0, NetlibIeProxyThread, 0, &param, &dwThreadId);
+ WaitForSingleObject(hThread, INFINITE);
+ CloseHandle(hThread);
+ res = param.szProxy;
+ }
+ return res;
+}
+
+void NetlibLoadIeProxy(void)
+{
+ HKEY hSettings;
+ if (RegOpenKeyExA(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings",
+ 0, KEY_QUERY_VALUE, &hSettings))
+ return;
+
+ DWORD tValueLen, enabled = 0;
+ char szHostStr[256] = "", szProxyBypassStr[4096] = "";
+
+ tValueLen = sizeof(enabled);
+ int tResult = RegQueryValueExA(hSettings, "ProxyEnable", NULL, NULL, (BYTE*)&enabled, &tValueLen);
+ bEnabled = enabled && tResult == ERROR_SUCCESS;
+
+ tValueLen = SIZEOF(szHostStr);
+ tResult = RegQueryValueExA(hSettings, "ProxyServer", NULL, NULL, (BYTE*)szHostStr, &tValueLen);
+ bEnabled = bEnabled && tResult == ERROR_SUCCESS;
+
+ tValueLen = SIZEOF(szAutoUrlStr);
+ tResult = RegQueryValueExA(hSettings, "AutoConfigUrl", NULL, NULL, (BYTE*)szAutoUrlStr, &tValueLen);
+
+ tValueLen = SIZEOF(szProxyBypassStr);
+ tResult = RegQueryValueExA(hSettings, "ProxyOverride", NULL, NULL, (BYTE*)szProxyBypassStr, &tValueLen);
+
+ RegCloseKey(hSettings);
+
+ if (bEnabled)
+ {
+ char* szProxy = ltrim(szHostStr);
+ if (szProxy[0] == 0) { enabled = false; return; }
+
+ for (;;)
+ {
+ char *szProxyEnd = strchr(szProxy, ';');
+ if (szProxyEnd) *szProxyEnd = 0;
+
+ int ind = -1;
+ if (strncmp(szProxy, "http=", 5) == 0) { ind = 0; szProxy += 5; }
+ else if (strncmp(szProxy, "https=", 6) == 0) { ind = 1; szProxy += 6; }
+ else if (strncmp(szProxy, "socks=", 6) == 0) { ind = 2; szProxy += 6; }
+ else if (strchr(szProxy, '=')) ind = -2;
+
+ if (ind != -2)
+ {
+ bOneProxy = ind < 0; if (ind < 0) ind = 0;
+
+ lrtrim(szProxy);
+
+ if (strchr(szProxy, ':'))
+ szProxyHost[ind] = mir_strdup(szProxy);
+ else
+ {
+ size_t len = strlen(szProxy) + 10;
+ szProxyHost[ind] = (char*)mir_alloc(len);
+ mir_snprintf(szProxyHost[ind], len, "%s:%u", szProxy, ind == 2 ? 1080 : 8080);
+ }
+ if (bOneProxy) break;
+ }
+ if (szProxyEnd == NULL) break;
+ szProxy = szProxyEnd + 1;
+ }
+
+ char* szProxyBypass = szProxyBypassStr;
+ for(;;)
+ {
+ char *szProxyBypassEnd = strchr(szProxyBypass, ';');
+ if (szProxyBypassEnd) *szProxyBypassEnd = 0;
+
+ lrtrim(szProxyBypass);
+
+ proxyBypass.insert(_strlwr(mir_strdup(szProxyBypass)));
+ if (szProxyBypassEnd == NULL) break;
+
+ szProxyBypass = szProxyBypassEnd + 1;
+ }
+ }
+
+ if (bEnabled || szAutoUrlStr[0])
+ hIeProxyMutex = CreateMutex(NULL, FALSE, NULL);
+}
+
+void NetlibUnloadIeProxy(void)
+{
+ int i;
+
+ for (i = 0; i < 3; ++i)
+ mir_free(szProxyHost[i]);
+
+ for (i = 0; i < proxyBypass.getCount(); ++i)
+ mir_free(proxyBypass[i]);
+
+ proxyBypass.destroy();
+ mir_free(abuf.lpszScriptBuffer);
+
+ CloseHandle(hIeProxyMutex);
+}
diff --git a/src/modules/netlib/netlibbind.cpp b/src/modules/netlib/netlibbind.cpp
new file mode 100644
index 0000000000..6c0c4c19e9
--- /dev/null
+++ b/src/modules/netlib/netlibbind.cpp
@@ -0,0 +1,287 @@
+/*
+
+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 "netlib.h"
+
+bool BindSocketToPort(const char *szPorts, SOCKET s, int* portn)
+{
+ SOCKADDR_IN sin = {0};
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ EnterCriticalSection(&csNetlibUser);
+
+ if (--*portn < 0 && s != INVALID_SOCKET)
+ {
+ BindSocketToPort(szPorts, INVALID_SOCKET, portn);
+ if (*portn == 0)
+ {
+ LeaveCriticalSection(&csNetlibUser);
+ return false;
+ }
+ WORD num;
+ CallService(MS_UTILS_GETRANDOM, sizeof(WORD), (LPARAM)&num);
+ *portn = num % *portn;
+ }
+
+ bool before=false;
+ for (;;)
+ {
+ const char *psz;
+ char *pszEnd;
+ int portMin, portMax, port, portnum = 0;
+
+ for(psz=szPorts;*psz;)
+ {
+ while (*psz == ' ' || *psz == ',') psz++;
+ portMin = strtol(psz, &pszEnd, 0);
+ if (pszEnd == psz) break;
+ while (*pszEnd == ' ') pszEnd++;
+ if(*pszEnd == '-')
+ {
+ psz = pszEnd + 1;
+ portMax = strtol(psz, &pszEnd, 0);
+ if (pszEnd == psz) portMax = 65535;
+ if (portMin > portMax)
+ {
+ port = portMin;
+ portMin = portMax;
+ portMax = port;
+ }
+ }
+ else portMax = portMin;
+ if (portMax >= 1)
+ {
+ if (portMin <= 0) portMin = 1;
+ for (port = portMin; port <= portMax; port++)
+ {
+ if (port > 65535) break;
+
+ ++portnum;
+
+ if (s == INVALID_SOCKET) continue;
+ if (!before && portnum <= *portn) continue;
+ if (before && portnum >= *portn)
+ {
+ LeaveCriticalSection(&csNetlibUser);
+ return false;
+ }
+
+ sin.sin_port = htons((WORD)port);
+ if (bind(s, (SOCKADDR*)&sin, sizeof(sin)) == 0)
+ {
+ LeaveCriticalSection(&csNetlibUser);
+ *portn = portnum + 1;
+ return true;
+ }
+ }
+ }
+ psz = pszEnd;
+ }
+ if (*portn < 0)
+ {
+ *portn = portnum;
+ LeaveCriticalSection(&csNetlibUser);
+ return true;
+ }
+ else if (*portn >= portnum)
+ *portn = 0;
+ else
+ before = true;
+ }
+}
+
+
+int NetlibFreeBoundPort(struct NetlibBoundPort *nlbp)
+{
+ closesocket(nlbp->s);
+ WaitForSingleObject(nlbp->hThread,INFINITE);
+ CloseHandle(nlbp->hThread);
+ NetlibLogf(nlbp->nlu, "(%u) Port %u closed for incoming connections", nlbp->s, nlbp->wPort);
+ mir_free(nlbp);
+ return 1;
+}
+
+static unsigned __stdcall NetlibBindAcceptThread(void* param)
+{
+ SOCKET s;
+ SOCKADDR_IN sin;
+ int sinLen;
+ struct NetlibConnection *nlc;
+ struct NetlibBoundPort *nlbp = (NetlibBoundPort*)param;
+
+ NetlibLogf(nlbp->nlu, "(%u) Port %u opened for incoming connections", nlbp->s, nlbp->wPort);
+ for(;;)
+ {
+ sinLen = sizeof(sin);
+ s = accept(nlbp->s, (struct sockaddr*)&sin, &sinLen);
+ if (s == INVALID_SOCKET) break;
+ NetlibLogf(nlbp->nlu, "New incoming connection on port %u from %s (%d)", nlbp->wPort, inet_ntoa(sin.sin_addr), s);
+ nlc = (NetlibConnection*)mir_calloc(sizeof(NetlibConnection));
+ nlc->handleType = NLH_CONNECTION;
+ nlc->nlu = nlbp->nlu;
+ nlc->s = s;
+ nlc->s2 = INVALID_SOCKET;
+ InitializeCriticalSection(&nlc->csHttpSequenceNums);
+ nlc->hOkToCloseEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+ nlc->dontCloseNow = 0;
+ NetlibInitializeNestedCS(&nlc->ncsSend);
+ NetlibInitializeNestedCS(&nlc->ncsRecv);
+ nlbp->pfnNewConnectionV2((HANDLE)nlc,ntohl(sin.sin_addr.S_un.S_addr), nlbp->pExtra);
+ }
+ NetlibUPnPDeletePortMapping(nlbp->wExPort, "TCP");
+ return 0;
+}
+
+INT_PTR NetlibBindPort(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBBIND *nlb = (NETLIBBIND*)lParam;
+ struct NetlibUser *nlu = (struct NetlibUser*)wParam;
+ struct NetlibBoundPort *nlbp;
+ SOCKADDR_IN sin;
+ int foundPort = 0;
+ UINT dwThreadId;
+
+ if (GetNetlibHandleType(nlu) != NLH_USER || !(nlu->user.flags & NUF_INCOMING) ||
+ nlb == NULL || nlb->pfnNewConnection == NULL)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ if (nlb->cbSize != sizeof(NETLIBBIND) &&
+ nlb->cbSize != NETLIBBIND_SIZEOF_V2 &&
+ nlb->cbSize != NETLIBBIND_SIZEOF_V1)
+ {
+ return 0;
+ }
+ nlbp = (NetlibBoundPort*)mir_calloc(sizeof(NetlibBoundPort));
+ nlbp->handleType = NLH_BOUNDPORT;
+ nlbp->nlu = nlu;
+ nlbp->pfnNewConnectionV2 = nlb->pfnNewConnectionV2;
+ nlbp->s = socket(AF_INET, SOCK_STREAM, 0);
+ nlbp->pExtra = (nlb->cbSize != NETLIBBIND_SIZEOF_V1) ? nlb->pExtra : NULL;
+ if (nlbp->s == INVALID_SOCKET)
+ {
+ NetlibLogf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"socket",WSAGetLastError());
+ mir_free(nlbp);
+ return 0;
+ }
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = htonl(INADDR_ANY);
+ sin.sin_port = 0;
+
+ /* if the netlib user wanted a free port given in the range, then
+ they better have given wPort==0, let's hope so */
+ if (nlu->settings.specifyIncomingPorts && nlu->settings.szIncomingPorts && nlb->wPort == 0)
+ {
+ if (!BindSocketToPort(nlu->settings.szIncomingPorts, nlbp->s, &nlu->outportnum))
+ {
+ NetlibLogf(nlu, "Netlib bind: Not enough ports for incoming connections specified");
+ SetLastError(WSAEADDRINUSE);
+ }
+ else
+ foundPort = 1;
+ }
+ else
+ {
+ /* if ->wPort==0 then they'll get any free port, otherwise they'll
+ be asking for whatever was in nlb->wPort*/
+ if (nlb->wPort != 0)
+ {
+ NetlibLogf(nlu,"%s %d: trying to bind port %d, this 'feature' can be abused, please be sure you want to allow it.",__FILE__,__LINE__,nlb->wPort);
+ sin.sin_port = htons(nlb->wPort);
+ }
+ if (bind(nlbp->s, (PSOCKADDR)&sin, sizeof(sin)) == 0)
+ foundPort = 1;
+ }
+ if (!foundPort)
+ {
+ NetlibLogf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"bind",WSAGetLastError());
+ closesocket(nlbp->s);
+ mir_free(nlbp);
+ return 0;
+ }
+
+ if (listen(nlbp->s, 5))
+ {
+ NetlibLogf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"listen",WSAGetLastError());
+ closesocket(nlbp->s);
+ mir_free(nlbp);
+ return 0;
+ }
+
+ { int len;
+ DWORD extIP;
+
+ ZeroMemory(&sin,sizeof(sin));
+ len = sizeof(sin);
+ if (getsockname(nlbp->s,(SOCKADDR *)&sin,&len))
+ {
+ NetlibLogf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"getsockname",WSAGetLastError());
+ closesocket(nlbp->s);
+ mir_free(nlbp);
+ return 0;
+ }
+ nlb->wPort = ntohs(sin.sin_port);
+ nlbp->wPort = nlb->wPort;
+ nlb->dwInternalIP = ntohl(sin.sin_addr.S_un.S_addr);
+
+ if (nlb->dwInternalIP == 0)
+ {
+ char hostname[64];
+ struct hostent *he;
+
+ gethostname(hostname, SIZEOF(hostname));
+ he = gethostbyname(hostname);
+ if (he && he->h_addr_list[0])
+ nlb->dwInternalIP = ntohl(*(PDWORD)he->h_addr_list[0]);
+ }
+ if (nlu->settings.enableUPnP &&
+ NetlibUPnPAddPortMapping(nlb->wPort, "TCP", &nlbp->wExPort, &extIP, nlb->cbSize > NETLIBBIND_SIZEOF_V2))
+ {
+ NetlibLogf(NULL, "UPnP port mapping succeeded. Internal Port: %u External Port: %u\n",
+ nlb->wPort, nlbp->wExPort);
+ if (nlb->cbSize > NETLIBBIND_SIZEOF_V2)
+ {
+ nlb->wExPort = nlbp->wExPort;
+ nlb->dwExternalIP = extIP;
+ }
+ }
+ else
+ {
+ if (nlu->settings.enableUPnP)
+ NetlibLogf(NULL, "UPnP port mapping failed. Internal Port: %u\n", nlb->wPort);
+ else
+ NetlibLogf(NULL, "UPnP disabled. Internal Port: %u\n", nlb->wPort);
+
+ nlbp->wExPort = 0;
+ if (nlb->cbSize > NETLIBBIND_SIZEOF_V2)
+ {
+ nlb->wExPort = nlb->wPort;
+ nlb->dwExternalIP = nlb->dwInternalIP;
+ }
+ }
+ }
+ nlbp->hThread = (HANDLE)forkthreadex(NULL, 0, NetlibBindAcceptThread, 0, nlbp, &dwThreadId);
+ return (INT_PTR)nlbp;
+}
diff --git a/src/modules/netlib/netlibhttp.cpp b/src/modules/netlib/netlibhttp.cpp
new file mode 100644
index 0000000000..970a28cb10
--- /dev/null
+++ b/src/modules/netlib/netlibhttp.cpp
@@ -0,0 +1,1331 @@
+/*
+
+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 "../plugins/zlib/zlib.h"
+#include "netlib.h"
+
+#define HTTPRECVHEADERSTIMEOUT 30000 //in ms
+#define HTTPRECVDATATIMEOUT 20000
+
+struct ResizableCharBuffer
+{
+ char *sz;
+ int iEnd, cbAlloced;
+};
+
+struct ProxyAuth
+{
+ char *szServer;
+ char *szMethod;
+// char *szUserName;
+// char *szPassword;
+
+ ProxyAuth(const char *pszServer, const char *pszMethod)
+ {
+ szServer = mir_strdup(pszServer);
+ szMethod = mir_strdup(pszMethod);
+ }
+ ~ProxyAuth()
+ {
+ mir_free(szServer);
+ mir_free(szMethod);
+ }
+ static int Compare(const ProxyAuth* p1, const ProxyAuth* p2 )
+ { return lstrcmpiA(p1->szServer, p2->szServer); }
+};
+
+struct ProxyAuthList : OBJLIST<ProxyAuth>
+{
+ ProxyAuthList() : OBJLIST<ProxyAuth>(2, ProxyAuth::Compare) {}
+
+ void add(const char *szServer, const char *szMethod)
+ {
+ if (szServer == NULL) return;
+ int i = getIndex((ProxyAuth*)&szServer);
+ if (i >= 0)
+ {
+ ProxyAuth &rec = (*this)[i];
+ if (szMethod == NULL)
+ remove(i);
+ else if (_stricmp(rec.szMethod, szMethod))
+ {
+ mir_free(rec.szMethod);
+ rec.szMethod = mir_strdup(szMethod);
+ }
+ }
+ else
+ insert(new ProxyAuth(szServer, szMethod));
+ }
+
+ const char* find(const char *szServer)
+ {
+ ProxyAuth * rec = szServer ? OBJLIST<ProxyAuth>::find((ProxyAuth*)&szServer) : NULL;
+ return rec ? rec->szMethod : NULL;
+ }
+};
+
+ProxyAuthList proxyAuthList;
+
+static void AppendToCharBuffer(struct ResizableCharBuffer *rcb, const char *fmt, ...)
+{
+ va_list va;
+ int charsDone;
+
+ if (rcb->cbAlloced == 0)
+ {
+ rcb->cbAlloced = 512;
+ rcb->sz = (char*)mir_alloc(rcb->cbAlloced);
+ }
+ va_start(va, fmt);
+ for (;;)
+ {
+ charsDone = mir_vsnprintf(rcb->sz + rcb->iEnd, rcb->cbAlloced-rcb->iEnd, fmt, va);
+ if(charsDone >= 0) break;
+ rcb->cbAlloced += 512;
+ rcb->sz = (char*)mir_realloc(rcb->sz, rcb->cbAlloced);
+ }
+ va_end(va);
+ rcb->iEnd += charsDone;
+}
+
+static int RecvWithTimeoutTime(struct NetlibConnection *nlc, unsigned dwTimeoutTime, char *buf, int len, int flags)
+{
+ DWORD dwTimeNow;
+
+ if (!si.pending(nlc->hSsl))
+ {
+ while ((dwTimeNow = GetTickCount()) < dwTimeoutTime)
+ {
+ unsigned dwDeltaTime = min(dwTimeoutTime - dwTimeNow, 1000);
+ int res = WaitUntilReadable(nlc->s, dwDeltaTime);
+
+ switch (res)
+ {
+ case SOCKET_ERROR:
+ return SOCKET_ERROR;
+
+ case 1:
+ return NLRecv(nlc, buf, len, flags);
+ }
+
+ if (nlc->termRequested || Miranda_Terminated()) return 0;
+ }
+ SetLastError(ERROR_TIMEOUT);
+ return SOCKET_ERROR;
+ }
+ return NLRecv(nlc, buf, len, flags);
+}
+
+static char* NetlibHttpFindHeader(NETLIBHTTPREQUEST *nlhrReply, const char *hdr)
+{
+ for (int i = 0; i < nlhrReply->headersCount; i++)
+ {
+ if (_stricmp(nlhrReply->headers[i].szName, hdr) == 0)
+ {
+ return nlhrReply->headers[i].szValue;
+ }
+ }
+ return NULL;
+}
+
+static char* NetlibHttpFindAuthHeader(NETLIBHTTPREQUEST *nlhrReply, const char *hdr, const char *szProvider)
+{
+ char *szBasicHdr = NULL;
+ char *szNegoHdr = NULL;
+ char *szNtlmHdr = NULL;
+
+ for (int i = 0; i < nlhrReply->headersCount; i++)
+ {
+ if (_stricmp(nlhrReply->headers[i].szName, hdr) == 0)
+ {
+ if (_strnicmp(nlhrReply->headers[i].szValue, "Negotiate", 9) == 0)
+ szNegoHdr = nlhrReply->headers[i].szValue;
+ else if (_strnicmp(nlhrReply->headers[i].szValue, "NTLM", 4) == 0)
+ szNtlmHdr = nlhrReply->headers[i].szValue;
+ else if (_strnicmp(nlhrReply->headers[i].szValue, "Basic", 5) == 0)
+ szBasicHdr = nlhrReply->headers[i].szValue;
+ }
+ }
+
+ if (szNegoHdr && (!szProvider || !_stricmp(szProvider, "Negotiate"))) return szNegoHdr;
+ if (szNtlmHdr && (!szProvider || !_stricmp(szProvider, "NTLM"))) return szNtlmHdr;
+ if (!szProvider || !_stricmp(szProvider, "Basic")) return szBasicHdr;
+ return NULL;
+}
+
+void NetlibConnFromUrl(const char* szUrl, bool secur, NETLIBOPENCONNECTION &nloc)
+{
+ secur = secur || _strnicmp(szUrl, "https", 5) == 0;
+ const char* phost = strstr(szUrl, "://");
+
+ char* szHost = mir_strdup(phost ? phost + 3 : szUrl);
+
+ char* ppath = strchr(szHost, '/');
+ if (ppath) *ppath = '\0';
+
+ memset(&nloc, 0, sizeof(nloc));
+ nloc.cbSize = sizeof(nloc);
+ nloc.szHost = szHost;
+
+ char* pcolon = strrchr(szHost, ':');
+ if (pcolon)
+ {
+ *pcolon = '\0';
+ nloc.wPort = (WORD)strtol(pcolon+1, NULL, 10);
+ }
+ else nloc.wPort = secur ? 443 : 80;
+ nloc.flags = (secur ? NLOCF_SSL : 0);
+}
+
+static NetlibConnection* NetlibHttpProcessUrl(NETLIBHTTPREQUEST *nlhr, NetlibUser *nlu, NetlibConnection* nlc,
+ const char* szUrl = NULL)
+{
+ NETLIBOPENCONNECTION nloc;
+
+ if (szUrl == NULL)
+ NetlibConnFromUrl(nlhr->szUrl, (nlhr->flags & NLHRF_SSL) != 0, nloc);
+ else
+ NetlibConnFromUrl(szUrl, false, nloc);
+
+ nloc.flags |= NLOCF_HTTP;
+ if (nloc.flags & NLOCF_SSL) nlhr->flags |= NLHRF_SSL; else nlhr->flags &= ~NLHRF_SSL;
+
+ if (nlc != NULL)
+ {
+ bool httpProxy = !(nloc.flags & NLOCF_SSL) && nlc->proxyType == PROXYTYPE_HTTP;
+ bool sameHost = lstrcmpA(nlc->nloc.szHost, nloc.szHost) == 0 && nlc->nloc.wPort == nloc.wPort;
+
+ if (!httpProxy && !sameHost)
+ {
+ NetlibDoClose(nlc);
+
+ mir_free((char*)nlc->nloc.szHost);
+ nlc->nloc = nloc;
+ return NetlibDoConnect(nlc) ? nlc : NULL;
+ }
+ }
+ else
+ nlc = (NetlibConnection*)NetlibOpenConnection((WPARAM)nlu, (LPARAM)&nloc);
+
+ mir_free((char*)nloc.szHost);
+
+ return nlc;
+}
+
+struct HttpSecurityContext
+{
+ HANDLE m_hNtlmSecurity;
+ char *m_szHost;
+ char *m_szProvider;
+
+ HttpSecurityContext()
+ { m_hNtlmSecurity = NULL; m_szHost = NULL; m_szProvider = NULL; }
+
+ ~HttpSecurityContext() { Destroy(); }
+
+ void Destroy(void)
+ {
+ if (!m_hNtlmSecurity) return;
+
+ NetlibDestroySecurityProvider(m_hNtlmSecurity);
+ m_hNtlmSecurity = NULL;
+ mir_free(m_szHost); m_szHost = NULL;
+ mir_free(m_szProvider); m_szProvider = NULL;
+ }
+
+ bool TryBasic(void)
+ {
+ return m_hNtlmSecurity && m_szProvider && _stricmp(m_szProvider, "Basic");
+ }
+
+ char* Execute(NetlibConnection *nlc, char* szHost, const char* szProvider,
+ const char* szChallenge, unsigned& complete)
+ {
+ char* szAuthHdr = NULL;
+ bool justCreated = false;
+
+ if (m_hNtlmSecurity)
+ {
+ bool newAuth = !m_szProvider || !szProvider || _stricmp(m_szProvider, szProvider);
+ newAuth = newAuth || (m_szHost != szHost && (!m_szHost || !szHost || _stricmp(m_szHost, szHost)));
+ if (newAuth)
+ Destroy();
+ }
+
+ if (m_hNtlmSecurity == NULL)
+ {
+ char szSpnStr[256] = "";
+ if (szHost && _stricmp(szProvider, "Basic"))
+ {
+ unsigned long ip = inet_addr(szHost);
+ PHOSTENT host = (ip == INADDR_NONE) ? gethostbyname(szHost) : gethostbyaddr((char*)&ip, 4, AF_INET);
+ mir_snprintf(szSpnStr, SIZEOF(szSpnStr), "HTTP/%s", host && host->h_name ? host->h_name : szHost);
+ _strlwr(szSpnStr + 5);
+ NetlibLogf(nlc->nlu, "Host SPN: %s", szSpnStr);
+ }
+ m_hNtlmSecurity = NetlibInitSecurityProvider(szProvider, szSpnStr[0] ? szSpnStr : NULL);
+ if (m_hNtlmSecurity)
+ {
+ m_szProvider = mir_strdup(szProvider);
+ m_szHost = mir_strdup(szHost);
+ justCreated = true;
+ }
+ }
+
+ if (m_hNtlmSecurity)
+ {
+ TCHAR *szLogin = NULL, *szPassw = NULL;
+
+ if (nlc->nlu->settings.useProxyAuth)
+ {
+ EnterCriticalSection(&csNetlibUser);
+ szLogin = mir_a2t(nlc->nlu->settings.szProxyAuthUser);
+ szPassw = mir_a2t(nlc->nlu->settings.szProxyAuthPassword);
+ LeaveCriticalSection(&csNetlibUser);
+ }
+
+ szAuthHdr = NtlmCreateResponseFromChallenge(m_hNtlmSecurity,
+ szChallenge, szLogin, szPassw, true, complete);
+
+ if (!szAuthHdr)
+ {
+ NetlibLogf(NULL, "Security login %s failed, user: " TCHAR_STR_PARAM " pssw: " TCHAR_STR_PARAM,
+ szProvider, szLogin ? szLogin : _T("(no user)"), szPassw ? _T("(exist)") : _T("(no psw)"));
+ }
+ else if (justCreated)
+ proxyAuthList.add(m_szHost, m_szProvider);
+
+ mir_free(szLogin);
+ mir_free(szPassw);
+ }
+ else
+ complete = 1;
+
+ return szAuthHdr;
+ }
+};
+
+static int HttpPeekFirstResponseLine(NetlibConnection *nlc, DWORD dwTimeoutTime,
+ DWORD recvFlags, int *resultCode,
+ char **ppszResultDescr, int *length)
+{
+ int bytesPeeked;
+ char buffer[2048];
+ char *peol;
+
+ for(;;)
+ {
+ bytesPeeked = RecvWithTimeoutTime(nlc, dwTimeoutTime, buffer, SIZEOF(buffer) - 1,
+ MSG_PEEK | recvFlags);
+
+ if (bytesPeeked == 0)
+ {
+ SetLastError(ERROR_HANDLE_EOF);
+ return 0;
+ }
+ if (bytesPeeked == SOCKET_ERROR)
+ return 0;
+
+ buffer[bytesPeeked] = '\0';
+ peol = strchr(buffer, '\n');
+ if (peol == NULL)
+ {
+ if ((int)strlen(buffer) < bytesPeeked)
+ {
+ SetLastError(ERROR_BAD_FORMAT);
+ return 0;
+ }
+ if (bytesPeeked == SIZEOF(buffer) - 1)
+ {
+ SetLastError(ERROR_BUFFER_OVERFLOW);
+ return 0;
+ }
+ if (Miranda_Terminated()) return 0;
+ Sleep(10);
+ }
+ else
+ break;
+ }
+
+ if (peol == buffer)
+ {
+ SetLastError(ERROR_BAD_FORMAT);
+ return 0;
+ }
+
+ *peol = '\0';
+
+ if (_strnicmp(buffer, "HTTP/", 5))
+ {
+ SetLastError(ERROR_BAD_FORMAT);
+ return 0;
+ }
+
+ size_t off = strcspn(buffer, " \t");
+ if (off >= (unsigned)bytesPeeked)
+ return 0;
+
+ char* pResultCode = buffer + off;
+ *(pResultCode++) = 0;
+
+ char* pResultDescr;
+ *resultCode = strtol(pResultCode, &pResultDescr, 10);
+
+ if (ppszResultDescr)
+ *ppszResultDescr = mir_strdup(lrtrimp(pResultDescr));
+
+ if (length) *length = peol - buffer + 1;
+ return 1;
+}
+
+static int SendHttpRequestAndData(struct NetlibConnection *nlc,struct ResizableCharBuffer *httpRequest,NETLIBHTTPREQUEST *nlhr,int sendContentLengthHeader)
+{
+ bool sendData = (nlhr->requestType==REQUEST_POST || nlhr->requestType==REQUEST_PUT);
+
+ if(sendContentLengthHeader && sendData)
+ AppendToCharBuffer(httpRequest,"Content-Length: %d\r\n\r\n", nlhr->dataLength);
+ else
+ AppendToCharBuffer(httpRequest,"\r\n");
+
+ DWORD hflags = (nlhr->flags & NLHRF_DUMPASTEXT ? MSG_DUMPASTEXT : 0) |
+ (nlhr->flags & (NLHRF_NODUMP | NLHRF_NODUMPSEND | NLHRF_NODUMPHEADERS) ?
+ MSG_NODUMP : (nlhr->flags & NLHRF_DUMPPROXY ? MSG_DUMPPROXY : 0)) |
+ (nlhr->flags & NLHRF_NOPROXY ? MSG_RAW : 0);
+
+ int bytesSent = NLSend(nlc, httpRequest->sz, httpRequest->iEnd, hflags);
+ if (bytesSent != SOCKET_ERROR && sendData && nlhr->dataLength)
+ {
+ DWORD sflags = (nlhr->flags & NLHRF_DUMPASTEXT ? MSG_DUMPASTEXT : 0) |
+ (nlhr->flags & (NLHRF_NODUMP | NLHRF_NODUMPSEND) ?
+ MSG_NODUMP : (nlhr->flags & NLHRF_DUMPPROXY ? MSG_DUMPPROXY : 0)) |
+ (nlhr->flags & NLHRF_NOPROXY ? MSG_RAW : 0);
+
+ int sendResult = NLSend(nlc,nlhr->pData,nlhr->dataLength, sflags);
+
+ bytesSent = sendResult != SOCKET_ERROR ? bytesSent + sendResult : SOCKET_ERROR;
+ }
+ mir_free(httpRequest->sz);
+ memset(httpRequest, 0, sizeof(*httpRequest));
+
+ return bytesSent;
+}
+
+INT_PTR NetlibHttpSendRequest(WPARAM wParam, LPARAM lParam)
+{
+ struct NetlibConnection *nlc=(struct NetlibConnection*)wParam;
+ NETLIBHTTPREQUEST *nlhr=(NETLIBHTTPREQUEST*)lParam;
+ NETLIBHTTPREQUEST *nlhrReply = NULL;
+ HttpSecurityContext httpSecurity;
+
+ struct ResizableCharBuffer httpRequest={0};
+ const char *pszRequest, *pszUrl, *pszFullUrl;
+ char *szHost = NULL, *szNewUrl = NULL;
+ char *pszProxyAuthHdr = NULL, *pszAuthHdr = NULL;
+ int i, doneHostHeader, doneContentLengthHeader, doneProxyAuthHeader, doneAuthHeader;
+ int bytesSent;
+ bool lastFirstLineFail = false;
+
+ if (nlhr == NULL || nlhr->cbSize < NETLIBHTTPREQUEST_V1_SIZE || nlhr->szUrl == NULL || nlhr->szUrl[0] == '\0')
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return SOCKET_ERROR;
+ }
+
+ int hdrTimeout = nlhr->cbSize > NETLIBHTTPREQUEST_V1_SIZE && nlhr->timeout ? nlhr->timeout : HTTPRECVHEADERSTIMEOUT;
+
+ switch(nlhr->requestType)
+ {
+ case REQUEST_GET: pszRequest = "GET"; break;
+ case REQUEST_POST: pszRequest = "POST"; break;
+ case REQUEST_CONNECT: pszRequest = "CONNECT"; break;
+ case REQUEST_HEAD: pszRequest = "HEAD"; break;
+ case REQUEST_PUT: pszRequest = "PUT"; break;
+ case REQUEST_DELETE: pszRequest = "DELETE"; break;
+ default:
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return SOCKET_ERROR;
+ }
+
+ if (!nlc->usingHttpGateway)
+ {
+ if (!NetlibEnterNestedCS(nlc, NLNCS_SEND))
+ return SOCKET_ERROR;
+ }
+
+ pszFullUrl = nlhr->szUrl;
+ pszUrl = NULL;
+
+ unsigned complete = false;
+ int count = 11;
+ while (--count)
+ {
+ if (!NetlibReconnect(nlc))
+ {
+ bytesSent = SOCKET_ERROR;
+ break;
+ }
+
+ if (!pszUrl)
+ {
+ pszUrl = pszFullUrl;
+ if (nlhr->flags & (NLHRF_SMARTREMOVEHOST | NLHRF_REMOVEHOST | NLHRF_GENERATEHOST))
+ {
+ bool usingProxy = nlc->proxyType == PROXYTYPE_HTTP && !(nlhr->flags & NLHRF_SSL);
+
+ mir_free(szHost);
+ szHost = NULL;
+
+ const char *ppath, *phost;
+ phost = strstr(pszUrl, "://");
+ if (phost == NULL) phost = pszUrl;
+ else phost += 3;
+ ppath = strchr(phost, '/');
+ if (ppath == phost) phost = NULL;
+
+ if (nlhr->flags & NLHRF_GENERATEHOST)
+ {
+ szHost = mir_strdup(phost);
+ if (ppath && phost) szHost[ppath - phost] = 0;
+ }
+
+ if (nlhr->flags & NLHRF_REMOVEHOST || (nlhr->flags & NLHRF_SMARTREMOVEHOST && !usingProxy))
+ {
+ pszUrl = ppath ? ppath : "/";
+ }
+
+ if (usingProxy && phost && !nlc->dnsThroughProxy)
+ {
+ char* tszHost = mir_strdup(phost);
+ if (ppath && phost) tszHost[ppath - phost] = 0;
+ char* cln = strchr(tszHost, ':'); if (cln) *cln = 0;
+
+ if (inet_addr(tszHost) == INADDR_NONE)
+ {
+ DWORD ip = DnsLookup(nlc->nlu, tszHost);
+ if (ip && szHost)
+ {
+ mir_free(szHost);
+ szHost = (char*)mir_alloc(30);
+ if (cln) *cln = ':';
+ mir_snprintf(szHost, 30, "%s%s", inet_ntoa(*(PIN_ADDR)&ip), cln ? cln : "");
+ }
+/*
+ if (ip && pszUrl[0] != '/')
+ {
+ mir_free(szNewUrl);
+ szNewUrl = (char*)mir_alloc(strlen(pszUrl) + 60);
+ szNewUrl[0] = 0;
+
+ phost = strstr(pszUrl, "://");
+ if (phost)
+ {
+ phost += 3;
+ size_t len = phost - pszUrl;
+ memcpy(szNewUrl, pszUrl, len);
+ szNewUrl[len] = 0;
+ }
+ strcat(szNewUrl, inet_ntoa(*(PIN_ADDR)&ip));
+ ppath = strchr(phost, '/');
+ if (ppath) strcat(szNewUrl, ppath);
+ pszUrl = szNewUrl;
+ }
+*/
+ }
+ mir_free(tszHost);
+ }
+ }
+ }
+
+ if (nlc->proxyAuthNeeded && proxyAuthList.getCount())
+ {
+ if (httpSecurity.m_szProvider == NULL && nlc->szProxyServer)
+ {
+ const char* szAuthMethodNlu = proxyAuthList.find(nlc->szProxyServer);
+
+ if (szAuthMethodNlu)
+ {
+ mir_free(pszProxyAuthHdr);
+ pszProxyAuthHdr = httpSecurity.Execute(nlc, nlc->szProxyServer, szAuthMethodNlu, "", complete);
+ }
+ }
+ }
+ nlc->proxyAuthNeeded = false;
+
+ AppendToCharBuffer(&httpRequest, "%s %s HTTP/1.%d\r\n", pszRequest, pszUrl, (nlhr->flags & NLHRF_HTTP11) != 0);
+
+ //HTTP headers
+ doneHostHeader = doneContentLengthHeader = doneProxyAuthHeader = doneAuthHeader = 0;
+ for (i=0; i < nlhr->headersCount; i++)
+ {
+ if (!lstrcmpiA(nlhr->headers[i].szName, "Host")) doneHostHeader = 1;
+ else if (!lstrcmpiA(nlhr->headers[i].szName, "Content-Length")) doneContentLengthHeader = 1;
+ else if (!lstrcmpiA(nlhr->headers[i].szName, "Proxy-Authorization")) doneProxyAuthHeader = 1;
+ else if (!lstrcmpiA(nlhr->headers[i].szName, "Authorization")) doneAuthHeader = 1;
+ else if (!lstrcmpiA(nlhr->headers[i].szName, "Connection")) continue;
+ if (nlhr->headers[i].szValue == NULL) continue;
+ AppendToCharBuffer(&httpRequest, "%s: %s\r\n", nlhr->headers[i].szName, nlhr->headers[i].szValue);
+ }
+ if (szHost && !doneHostHeader)
+ AppendToCharBuffer(&httpRequest, "%s: %s\r\n", "Host", szHost);
+ if (pszProxyAuthHdr && !doneProxyAuthHeader)
+ AppendToCharBuffer(&httpRequest, "%s: %s\r\n", "Proxy-Authorization", pszProxyAuthHdr);
+ if (pszAuthHdr && !doneAuthHeader)
+ AppendToCharBuffer(&httpRequest, "%s: %s\r\n", "Authorization", pszAuthHdr);
+ AppendToCharBuffer(&httpRequest, "%s: %s\r\n", "Connection", "Keep-Alive");
+ AppendToCharBuffer(&httpRequest, "%s: %s\r\n", "Proxy-Connection", "Keep-Alive");
+
+ // Add Sticky Headers
+ if (nlc->nlu->szStickyHeaders != NULL)
+ AppendToCharBuffer(&httpRequest, "%s\r\n", nlc->nlu->szStickyHeaders);
+
+ //send it
+ bytesSent = SendHttpRequestAndData(nlc, &httpRequest, nlhr, !doneContentLengthHeader);
+ if (bytesSent == SOCKET_ERROR) break;
+
+ //ntlm reply
+ if (!doneContentLengthHeader || nlhr->requestType == REQUEST_HEAD)
+ {
+ int resultCode = 0;
+
+ DWORD fflags = MSG_PEEK | MSG_NODUMP | ((nlhr->flags & NLHRF_NOPROXY) ? MSG_RAW : 0);
+ DWORD dwTimeOutTime = hdrTimeout < 0 ? -1 : GetTickCount() + hdrTimeout;
+ if (!HttpPeekFirstResponseLine(nlc, dwTimeOutTime, fflags, &resultCode, NULL, NULL))
+ {
+ NetlibLogf(nlc->nlu, "%s %d: %s Failed (%u %u)",__FILE__,__LINE__,"HttpPeekFirstResponseLine",GetLastError(), count);
+ DWORD err = GetLastError();
+ if (err == ERROR_TIMEOUT || err == ERROR_BAD_FORMAT || err == ERROR_BUFFER_OVERFLOW ||
+ lastFirstLineFail || nlc->termRequested || nlhr->requestType == REQUEST_CONNECT)
+ {
+ bytesSent = SOCKET_ERROR;
+ break;
+ }
+ else
+ {
+ lastFirstLineFail = true;
+ continue;
+ }
+ }
+ lastFirstLineFail = false;
+
+ DWORD hflags = (nlhr->flags & (NLHRF_NODUMP|NLHRF_NODUMPHEADERS|NLHRF_NODUMPSEND) ?
+ MSG_NODUMP : (nlhr->flags & NLHRF_DUMPPROXY ? MSG_DUMPPROXY : 0)) |
+ (nlhr->flags & NLHRF_NOPROXY ? MSG_RAW : 0);
+
+ DWORD dflags = (nlhr->flags & (NLHRF_NODUMP | NLHRF_NODUMPSEND) ?
+ MSG_NODUMP : MSG_DUMPASTEXT | MSG_DUMPPROXY) |
+ (nlhr->flags & NLHRF_NOPROXY ? MSG_RAW : 0) | MSG_NODUMP;
+
+ if (resultCode == 100)
+ {
+ nlhrReply = (NETLIBHTTPREQUEST*)NetlibHttpRecvHeaders((WPARAM)nlc, hflags);
+ }
+ else if (resultCode == 307 || ((resultCode == 301 || resultCode == 302) // redirect
+ && (nlhr->flags & NLHRF_REDIRECT)))
+ {
+ pszUrl = NULL;
+
+ if (nlhr->requestType == REQUEST_HEAD)
+ nlhrReply = (NETLIBHTTPREQUEST*)NetlibHttpRecvHeaders((WPARAM)nlc, hflags);
+ else
+ nlhrReply = NetlibHttpRecv(nlc, hflags, dflags);
+
+ if (nlhrReply)
+ {
+ char* tmpUrl = NetlibHttpFindHeader(nlhrReply, "Location");
+ if (tmpUrl)
+ {
+ size_t rlen = 0;
+ if (tmpUrl[0] == '/')
+ {
+ const char *ppath, *phost;
+ phost = strstr(pszFullUrl, "://");
+ phost = phost ? phost + 3 : pszFullUrl;
+ ppath = strchr(phost, '/');
+ rlen = ppath ? ppath - pszFullUrl : strlen(pszFullUrl);
+ }
+
+ nlc->szNewUrl = (char*)mir_realloc(nlc->szNewUrl, rlen + strlen(tmpUrl) * 3 + 1);
+
+ strncpy(nlc->szNewUrl, pszFullUrl, rlen);
+ strcpy(nlc->szNewUrl + rlen, tmpUrl);
+ pszFullUrl = nlc->szNewUrl;
+ pszUrl = NULL;
+
+ if (NetlibHttpProcessUrl(nlhr, nlc->nlu, nlc, pszFullUrl) == NULL)
+ {
+ bytesSent = SOCKET_ERROR;
+ break;
+ }
+ }
+ else
+ {
+ NetlibHttpSetLastErrorUsingHttpResult(resultCode);
+ bytesSent = SOCKET_ERROR;
+ break;
+ }
+ }
+ else
+ {
+ NetlibHttpSetLastErrorUsingHttpResult(resultCode);
+ bytesSent = SOCKET_ERROR;
+ break;
+ }
+ }
+ else if (resultCode == 401 && !doneAuthHeader) //auth required
+ {
+ if (nlhr->requestType == REQUEST_HEAD)
+ nlhrReply = (NETLIBHTTPREQUEST*)NetlibHttpRecvHeaders((WPARAM)nlc, hflags);
+ else
+ nlhrReply = NetlibHttpRecv(nlc, hflags, dflags);
+
+ mir_free(pszAuthHdr); pszAuthHdr = NULL;
+ if (nlhrReply)
+ {
+ char *szAuthStr = NULL;
+ if (!complete)
+ {
+ szAuthStr = NetlibHttpFindAuthHeader(nlhrReply, "WWW-Authenticate",
+ httpSecurity.m_szProvider);
+ if (szAuthStr)
+ {
+ char *szChallenge = strchr(szAuthStr, ' ');
+ if (!szChallenge || !*lrtrimp(szChallenge)) complete = true;
+ }
+ }
+ if (complete && httpSecurity.m_hNtlmSecurity)
+ {
+ szAuthStr = httpSecurity.TryBasic() ?
+ NetlibHttpFindAuthHeader(nlhrReply, "WWW-Authenticate", "Basic") : NULL;
+ }
+
+ if (szAuthStr)
+ {
+ char *szChallenge = strchr(szAuthStr, ' ');
+ if (szChallenge) { *szChallenge = 0; szChallenge = lrtrimp(szChallenge + 1); }
+
+ pszAuthHdr = httpSecurity.Execute(nlc, szHost, szAuthStr, szChallenge, complete);
+ }
+ }
+ if (pszAuthHdr == NULL)
+ {
+ proxyAuthList.add(szHost, NULL);
+ NetlibHttpSetLastErrorUsingHttpResult(resultCode);
+ bytesSent = SOCKET_ERROR;
+ break;
+ }
+ }
+ else if (resultCode == 407 && !doneProxyAuthHeader) //proxy auth required
+ {
+ if (nlhr->requestType == REQUEST_HEAD)
+ nlhrReply = (NETLIBHTTPREQUEST*)NetlibHttpRecvHeaders((WPARAM)nlc, hflags);
+ else
+ nlhrReply = NetlibHttpRecv(nlc, hflags, dflags);
+
+ mir_free(pszProxyAuthHdr); pszProxyAuthHdr = NULL;
+ if (nlhrReply)
+ {
+ char *szAuthStr = NULL;
+ if (!complete)
+ {
+ szAuthStr = NetlibHttpFindAuthHeader(nlhrReply, "Proxy-Authenticate",
+ httpSecurity.m_szProvider);
+ if (szAuthStr)
+ {
+ char *szChallenge = strchr(szAuthStr, ' ');
+ if (!szChallenge || !*lrtrimp(szChallenge + 1)) complete = true;
+ }
+ }
+ if (complete && httpSecurity.m_hNtlmSecurity)
+ {
+ szAuthStr = httpSecurity.TryBasic() ?
+ NetlibHttpFindAuthHeader(nlhrReply, "Proxy-Authenticate", "Basic") : NULL;
+ }
+
+ if (szAuthStr)
+ {
+ char *szChallenge = strchr(szAuthStr, ' ');
+ if (szChallenge) { *szChallenge = 0; szChallenge = lrtrimp(szChallenge + 1); }
+
+ pszProxyAuthHdr = httpSecurity.Execute(nlc, nlc->szProxyServer, szAuthStr, szChallenge, complete);
+ }
+ }
+ if (pszProxyAuthHdr == NULL)
+ {
+ proxyAuthList.add(nlc->szProxyServer, NULL);
+ NetlibHttpSetLastErrorUsingHttpResult(resultCode);
+ bytesSent = SOCKET_ERROR;
+ break;
+ }
+ }
+ else
+ break;
+
+ if (pszProxyAuthHdr && resultCode != 407 && !doneProxyAuthHeader)
+ {
+ mir_free(pszProxyAuthHdr); pszProxyAuthHdr = NULL;
+ }
+ if (pszAuthHdr && resultCode != 401 && !doneAuthHeader)
+ {
+ mir_free(pszAuthHdr); pszAuthHdr = NULL;
+ }
+
+ if (nlhrReply)
+ {
+ NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);
+ nlhrReply = NULL;
+ }
+ }
+ else
+ break;
+ }
+ if (count == 0) bytesSent = SOCKET_ERROR;
+ if (nlhrReply) NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);
+
+ //clean up
+ mir_free(pszProxyAuthHdr);
+ mir_free(pszAuthHdr);
+ mir_free(szHost);
+ mir_free(szNewUrl);
+
+ if (!nlc->usingHttpGateway)
+ NetlibLeaveNestedCS(&nlc->ncsSend);
+
+ return bytesSent;
+}
+
+INT_PTR NetlibHttpFreeRequestStruct(WPARAM, LPARAM lParam)
+{
+ NETLIBHTTPREQUEST *nlhr=(NETLIBHTTPREQUEST*)lParam;
+
+ if (nlhr == NULL || nlhr->cbSize != sizeof(NETLIBHTTPREQUEST) || nlhr->requestType != REQUEST_RESPONSE)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ if(nlhr->headers)
+ {
+ int i;
+ for(i=0; i<nlhr->headersCount; i++)
+ {
+ mir_free(nlhr->headers[i].szName);
+ mir_free(nlhr->headers[i].szValue);
+ }
+ mir_free(nlhr->headers);
+ }
+ mir_free(nlhr->pData);
+ mir_free(nlhr->szResultDescr);
+ mir_free(nlhr->szUrl);
+ mir_free(nlhr);
+ return 1;
+}
+
+INT_PTR NetlibHttpRecvHeaders(WPARAM wParam,LPARAM lParam)
+{
+ struct NetlibConnection *nlc = (struct NetlibConnection*)wParam;
+ NETLIBHTTPREQUEST *nlhr;
+ char *peol, *pbuffer;
+ char *buffer = NULL;
+ DWORD dwRequestTimeoutTime;
+ int bytesPeeked, firstLineLength = 0;
+ int headersCount = 0, bufferSize = 8192;
+ bool headersCompleted = false;
+
+ if(!NetlibEnterNestedCS(nlc,NLNCS_RECV))
+ return 0;
+
+ dwRequestTimeoutTime = GetTickCount() + HTTPRECVDATATIMEOUT;
+ nlhr = (NETLIBHTTPREQUEST*)mir_calloc(sizeof(NETLIBHTTPREQUEST));
+ nlhr->cbSize = sizeof(NETLIBHTTPREQUEST);
+ nlhr->nlc = nlc; // Needed to id connection in the protocol HTTP gateway wrapper functions
+ nlhr->requestType = REQUEST_RESPONSE;
+
+ if (!HttpPeekFirstResponseLine(nlc, dwRequestTimeoutTime, lParam | MSG_PEEK,
+ &nlhr->resultCode, &nlhr->szResultDescr, &firstLineLength))
+ {
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ NetlibHttpFreeRequestStruct(0, (LPARAM)nlhr);
+ return 0;
+ }
+
+ buffer = (char*)mir_alloc(bufferSize + 1);
+ bytesPeeked = NLRecv(nlc, buffer, min(firstLineLength, bufferSize), lParam | MSG_DUMPASTEXT);
+ if (bytesPeeked != firstLineLength)
+ {
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ NetlibHttpFreeRequestStruct(0, (LPARAM)nlhr);
+ if (bytesPeeked != SOCKET_ERROR) SetLastError(ERROR_HANDLE_EOF);
+ mir_free(buffer);
+ return 0;
+ }
+
+ // Make sure all headers arrived
+ bytesPeeked = 0;
+ while (!headersCompleted)
+ {
+ if (bytesPeeked >= bufferSize)
+ {
+ bufferSize += 8192;
+ mir_free(buffer);
+ if (bufferSize > 32 * 1024)
+ {
+ bytesPeeked = 0;
+ break;
+ }
+ buffer = (char*)mir_alloc(bufferSize + 1);
+ }
+
+ bytesPeeked = RecvWithTimeoutTime(nlc, dwRequestTimeoutTime, buffer, bufferSize,
+ MSG_PEEK | MSG_NODUMP | lParam);
+ if (bytesPeeked == 0) break;
+
+ if (bytesPeeked == SOCKET_ERROR)
+ {
+ bytesPeeked = 0;
+ break;
+ }
+ buffer[bytesPeeked] = 0;
+
+ for (pbuffer = buffer, headersCount = 0; ; pbuffer = peol + 1, ++headersCount)
+ {
+ peol = strchr(pbuffer, '\n');
+ if (peol == NULL) break;
+ if (peol == pbuffer || (peol == (pbuffer + 1) && *pbuffer == '\r'))
+ {
+ bytesPeeked = peol - buffer + 1;
+ headersCompleted = true;
+ break;
+ }
+ }
+ }
+
+ // Recieve headers
+ if (bytesPeeked > 0)
+ bytesPeeked = NLRecv(nlc, buffer, bytesPeeked, lParam | MSG_DUMPASTEXT);
+ if (bytesPeeked <= 0)
+ {
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ NetlibHttpFreeRequestStruct(0, (LPARAM)nlhr);
+ mir_free(buffer);
+ return 0;
+ }
+ buffer[bytesPeeked] = 0;
+
+ nlhr->headersCount = headersCount;
+ nlhr->headers = (NETLIBHTTPHEADER*)mir_calloc(sizeof(NETLIBHTTPHEADER) * headersCount);
+
+ for (pbuffer = buffer, headersCount = 0; ; pbuffer = peol + 1, ++headersCount)
+ {
+ peol = strchr(pbuffer, '\n');
+ if (peol == NULL || peol == pbuffer || (peol == (pbuffer + 1) && *pbuffer == '\r')) break;
+ *peol = 0;
+
+ char *pColon = strchr(pbuffer, ':');
+ if (pColon == NULL)
+ {
+ NetlibHttpFreeRequestStruct(0, (LPARAM)nlhr); nlhr = NULL;
+ SetLastError(ERROR_INVALID_DATA);
+ break;
+ }
+
+ *(pColon++) = 0;
+ nlhr->headers[headersCount].szName = mir_strdup(rtrim(pbuffer));
+ nlhr->headers[headersCount].szValue = mir_strdup(lrtrimp(pColon));
+ }
+
+ NetlibLeaveNestedCS(&nlc->ncsRecv);
+ mir_free(buffer);
+ return (INT_PTR)nlhr;
+}
+
+INT_PTR NetlibHttpTransaction(WPARAM wParam, LPARAM lParam)
+{
+ NetlibUser *nlu = (NetlibUser*)wParam;
+ NETLIBHTTPREQUEST *nlhr = (NETLIBHTTPREQUEST*)lParam, *nlhrReply;
+ DWORD dflags, hflags;
+
+ if (GetNetlibHandleType(nlu) != NLH_USER || !(nlu->user.flags & NUF_OUTGOING) ||
+ nlhr == NULL || nlhr->cbSize < NETLIBHTTPREQUEST_V1_SIZE ||
+ nlhr->szUrl == NULL || nlhr->szUrl[0] == 0)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+
+ NetlibConnection* nlc = NetlibHttpProcessUrl(nlhr, nlu, (NetlibConnection*)nlhr->nlc);
+ if (nlc == NULL) return 0;
+
+ {
+ NETLIBHTTPREQUEST nlhrSend;
+ char szUserAgent[64];
+
+ nlhrSend = *nlhr;
+ nlhrSend.flags &= ~NLHRF_REMOVEHOST;
+ nlhrSend.flags |= NLHRF_GENERATEHOST | NLHRF_SMARTREMOVEHOST | NLHRF_SMARTAUTHHEADER;
+
+ bool doneUserAgentHeader = NetlibHttpFindHeader(nlhr, "User-Agent") != NULL;
+ bool doneAcceptEncoding = NetlibHttpFindHeader(nlhr, "Accept-Encoding") != NULL;
+
+ if (!doneUserAgentHeader || !doneAcceptEncoding)
+ {
+ nlhrSend.headers = (NETLIBHTTPHEADER*)mir_alloc(sizeof(NETLIBHTTPHEADER) * (nlhrSend.headersCount + 2));
+ memcpy(nlhrSend.headers, nlhr->headers, sizeof(NETLIBHTTPHEADER) * nlhr->headersCount);
+ }
+ if (!doneUserAgentHeader)
+ {
+ char *pspace,szMirandaVer[64];
+
+ nlhrSend.headers[nlhrSend.headersCount].szName = "User-Agent";
+ nlhrSend.headers[nlhrSend.headersCount].szValue = szUserAgent;
+ ++nlhrSend.headersCount;
+ CallService(MS_SYSTEM_GETVERSIONTEXT,SIZEOF(szMirandaVer),(LPARAM)szMirandaVer);
+ pspace=strchr(szMirandaVer,' ');
+ if(pspace)
+ {
+ *pspace++ = '\0';
+ mir_snprintf(szUserAgent, SIZEOF(szUserAgent), "Miranda/%s (%s)", szMirandaVer, pspace);
+ }
+ else
+ mir_snprintf(szUserAgent, SIZEOF(szUserAgent), "Miranda/%s", szMirandaVer);
+ }
+ if (!doneAcceptEncoding)
+ {
+ nlhrSend.headers[nlhrSend.headersCount].szName = "Accept-Encoding";
+ nlhrSend.headers[nlhrSend.headersCount].szValue = "deflate, gzip";
+ ++nlhrSend.headersCount;
+ }
+ if (NetlibHttpSendRequest((WPARAM)nlc, (LPARAM)&nlhrSend) == SOCKET_ERROR)
+ {
+ if (!doneUserAgentHeader || !doneAcceptEncoding) mir_free(nlhrSend.headers);
+ NetlibCloseHandle((WPARAM)nlc, 0);
+ return 0;
+ }
+ if (!doneUserAgentHeader || !doneAcceptEncoding) mir_free(nlhrSend.headers);
+ }
+
+ dflags = (nlhr->flags & NLHRF_DUMPASTEXT ? MSG_DUMPASTEXT:0) |
+ (nlhr->flags & NLHRF_NODUMP ? MSG_NODUMP : (nlhr->flags & NLHRF_DUMPPROXY ? MSG_DUMPPROXY : 0)) |
+ (nlhr->flags & NLHRF_NOPROXY ? MSG_RAW : 0);
+
+ hflags =
+ (nlhr->flags & NLHRF_NODUMP ? MSG_NODUMP : (nlhr->flags & NLHRF_DUMPPROXY ? MSG_DUMPPROXY : 0)) |
+ (nlhr->flags & NLHRF_NOPROXY ? MSG_RAW : 0);
+
+
+ if (nlhr->requestType == REQUEST_HEAD)
+ nlhrReply = (NETLIBHTTPREQUEST*)NetlibHttpRecvHeaders((WPARAM)nlc, 0);
+ else
+ nlhrReply = NetlibHttpRecv(nlc, hflags, dflags);
+
+ if (nlhrReply)
+ {
+ nlhrReply->szUrl = nlc->szNewUrl;
+ nlc->szNewUrl = NULL;
+ }
+
+ if ((nlhr->flags & NLHRF_PERSISTENT) == 0 || nlhrReply == NULL)
+ {
+ NetlibCloseHandle((WPARAM)nlc, 0);
+ if (nlhrReply) nlhrReply->nlc = NULL;
+ }
+ else
+ nlhrReply->nlc = nlc;
+
+ return (INT_PTR)nlhrReply;
+}
+
+void NetlibHttpSetLastErrorUsingHttpResult(int result)
+{
+ if (result >= 200 && result < 300)
+ {
+ SetLastError(ERROR_SUCCESS);
+ return;
+ }
+ switch(result)
+ {
+ case 400: SetLastError(ERROR_BAD_FORMAT); break;
+ case 401:
+ case 402:
+ case 403:
+ case 407: SetLastError(ERROR_ACCESS_DENIED); break;
+ case 404: SetLastError(ERROR_FILE_NOT_FOUND); break;
+ case 405:
+ case 406: SetLastError(ERROR_INVALID_FUNCTION); break;
+ case 408: SetLastError(ERROR_TIMEOUT); break;
+ default: SetLastError(ERROR_GEN_FAILURE); break;
+ }
+}
+
+char* gzip_decode(char *gzip_data, int *len_ptr, int window)
+{
+ if (*len_ptr == 0) return NULL;
+
+ int gzip_len = *len_ptr * 5;
+ char* output_data = NULL;
+
+ int gzip_err;
+ z_stream zstr;
+
+ do
+ {
+ output_data = (char*)mir_realloc(output_data, gzip_len+1);
+
+ zstr.next_in = (Bytef*)gzip_data;
+ zstr.avail_in = *len_ptr;
+ zstr.zalloc = Z_NULL;
+ zstr.zfree = Z_NULL;
+ zstr.opaque = Z_NULL;
+ inflateInit2_(&zstr, window, ZLIB_VERSION, sizeof(z_stream));
+
+ zstr.next_out = (Bytef*)output_data;
+ zstr.avail_out = gzip_len;
+
+ gzip_err = inflate(&zstr, Z_FINISH);
+
+ inflateEnd(&zstr);
+ gzip_len *= 2;
+ }
+ while (gzip_err == Z_BUF_ERROR);
+
+ gzip_len = gzip_err == Z_STREAM_END ? zstr.total_out : -1;
+
+ if (gzip_len <= 0)
+ {
+ mir_free(output_data);
+ output_data = NULL;
+ }
+ else
+ output_data[gzip_len] = 0;
+
+ *len_ptr = gzip_len;
+ return output_data;
+}
+
+static int NetlibHttpRecvChunkHeader(NetlibConnection* nlc, bool first, DWORD flags)
+{
+ char data[64], *peol1;
+
+ for (;;)
+ {
+ int recvResult = NLRecv(nlc, data, 31, MSG_RAW | MSG_PEEK);
+ if (recvResult <= 0) return SOCKET_ERROR;
+
+ data[recvResult] = 0;
+
+ peol1 = strchr(data, '\n');
+ if (peol1 != NULL)
+ {
+ char *peol2 = first ? peol1 : strchr(peol1 + 1, '\n');
+ if (peol2 != NULL)
+ {
+ int sz = peol2 - data + 1;
+ int r = strtol(first ? data : peol1 + 1, NULL, 16);
+ if (r == 0)
+ {
+ char *peol3 = strchr(peol2 + 1, '\n');
+ if (peol3 == NULL) continue;
+ sz = peol3 - data + 1;
+ }
+ NLRecv(nlc, data, sz, MSG_RAW | flags);
+ return r;
+ }
+ else
+ if (recvResult >= 31) return SOCKET_ERROR;
+ }
+ }
+}
+
+NETLIBHTTPREQUEST* NetlibHttpRecv(NetlibConnection* nlc, DWORD hflags, DWORD dflags, bool isConnect)
+{
+ int dataLen = -1, i, chunkhdr = 0;
+ bool chunked = false;
+ int cenc = 0, cenctype = 0, close = 0;
+
+next:
+ NETLIBHTTPREQUEST *nlhrReply = (NETLIBHTTPREQUEST*)NetlibHttpRecvHeaders((WPARAM)nlc, hflags);
+ if (nlhrReply == NULL)
+ return NULL;
+
+ if (nlhrReply->resultCode == 100)
+ {
+ NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);
+ goto next;
+ }
+
+ for (i=0; i<nlhrReply->headersCount; i++)
+ {
+ if (!lstrcmpiA(nlhrReply->headers[i].szName, "Content-Length"))
+ dataLen = atoi(nlhrReply->headers[i].szValue);
+
+ if (!lstrcmpiA(nlhrReply->headers[i].szName, "Content-Encoding"))
+ {
+ cenc = i;
+ if (strstr(nlhrReply->headers[i].szValue, "gzip"))
+ cenctype = 1;
+ else if (strstr(nlhrReply->headers[i].szValue, "deflate"))
+ cenctype = 2;
+ }
+
+ if (!lstrcmpiA(nlhrReply->headers[i].szName, "Connection"))
+ close = !lstrcmpiA(nlhrReply->headers[i].szValue, "close");
+
+ if (!lstrcmpiA(nlhrReply->headers[i].szName, "Transfer-Encoding") &&
+ !lstrcmpiA(nlhrReply->headers[i].szValue, "chunked"))
+ {
+ chunked = true;
+ chunkhdr = i;
+ dataLen = -1;
+ }
+ }
+
+ if (nlhrReply->resultCode >= 200 && (dataLen > 0 || (!isConnect && dataLen < 0)))
+ {
+ int recvResult, chunksz = -1;
+ int dataBufferAlloced;
+
+ if (chunked)
+ {
+ chunksz = NetlibHttpRecvChunkHeader(nlc, true, dflags);
+ if (chunksz == SOCKET_ERROR)
+ {
+ NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);
+ return NULL;
+ }
+ dataLen = chunksz;
+ }
+ dataBufferAlloced = dataLen < 0 ? 2048 : dataLen + 1;
+ nlhrReply->pData = (char*)mir_realloc(nlhrReply->pData, dataBufferAlloced);
+
+ while (chunksz != 0)
+ {
+ for(;;)
+ {
+ recvResult = RecvWithTimeoutTime(nlc, GetTickCount() + HTTPRECVDATATIMEOUT,
+ nlhrReply->pData + nlhrReply->dataLength,
+ dataBufferAlloced - nlhrReply->dataLength - 1,
+ dflags | (cenctype ? MSG_NODUMP : 0));
+
+ if (recvResult == 0) break;
+ if (recvResult == SOCKET_ERROR)
+ {
+ NetlibHttpFreeRequestStruct(0,(LPARAM)nlhrReply);
+ return NULL;
+ }
+ nlhrReply->dataLength += recvResult;
+
+ if (dataLen >= 0)
+ {
+ if (nlhrReply->dataLength >= dataLen) break;
+ }
+ else
+ {
+ if ((dataBufferAlloced - nlhrReply->dataLength) < 256)
+ {
+ dataBufferAlloced += 2048;
+ nlhrReply->pData = (char*)mir_realloc(nlhrReply->pData, dataBufferAlloced);
+ if(nlhrReply->pData == NULL)
+ {
+ SetLastError(ERROR_OUTOFMEMORY);
+ NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);
+ return NULL;
+ }
+ }
+ }
+ Sleep(10);
+ }
+
+ if (chunked)
+ {
+ chunksz = NetlibHttpRecvChunkHeader(nlc, false, dflags);
+ if (chunksz == SOCKET_ERROR)
+ {
+ NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);
+ return NULL;
+ }
+ dataLen += chunksz;
+ dataBufferAlloced += chunksz;
+
+ nlhrReply->pData = (char*)mir_realloc(nlhrReply->pData, dataBufferAlloced);
+ }
+ else
+ break;
+ }
+
+ nlhrReply->pData[nlhrReply->dataLength] = '\0';
+ }
+
+ if (chunked)
+ {
+ nlhrReply->headers[chunkhdr].szName = ( char* )mir_realloc(nlhrReply->headers[chunkhdr].szName, 16);
+ lstrcpyA(nlhrReply->headers[chunkhdr].szName, "Content-Length");
+
+ nlhrReply->headers[chunkhdr].szValue = ( char* )mir_realloc(nlhrReply->headers[chunkhdr].szValue, 16);
+ mir_snprintf(nlhrReply->headers[chunkhdr].szValue, 16, "%u", nlhrReply->dataLength);
+ }
+
+ if (cenctype)
+ {
+ int bufsz = nlhrReply->dataLength;
+ char* szData = NULL;
+
+ switch (cenctype)
+ {
+ case 1:
+ szData = gzip_decode(nlhrReply->pData, &bufsz, 0x10 | MAX_WBITS);
+ break;
+
+ case 2:
+ szData = gzip_decode(nlhrReply->pData, &bufsz, -MAX_WBITS);
+ if (bufsz < 0)
+ {
+ bufsz = nlhrReply->dataLength;
+ szData = gzip_decode(nlhrReply->pData, &bufsz, MAX_WBITS);
+ }
+ break;
+ }
+
+ if (bufsz > 0)
+ {
+ NetlibDumpData(nlc, (PBYTE)szData, bufsz, 0, dflags);
+ mir_free(nlhrReply->pData);
+ nlhrReply->pData = szData;
+ nlhrReply->dataLength = bufsz;
+
+ mir_free(nlhrReply->headers[cenc].szName);
+ mir_free(nlhrReply->headers[cenc].szValue);
+ memmove(&nlhrReply->headers[cenc], &nlhrReply->headers[cenc+1], (--nlhrReply->headersCount-cenc)*sizeof(nlhrReply->headers[0]));
+ }
+ else if (bufsz == 0)
+ {
+ mir_free(nlhrReply->pData);
+ nlhrReply->pData = NULL;
+ nlhrReply->dataLength = 0;
+ }
+ }
+
+ if (close &&
+ (nlc->proxyType != PROXYTYPE_HTTP || nlc->nloc.flags & NLOCF_SSL) &&
+ (!isConnect || nlhrReply->resultCode != 200))
+ NetlibDoClose(nlc);
+
+ return nlhrReply;
+}
diff --git a/src/modules/netlib/netlibhttpproxy.cpp b/src/modules/netlib/netlibhttpproxy.cpp
new file mode 100644
index 0000000000..153d53660f
--- /dev/null
+++ b/src/modules/netlib/netlibhttpproxy.cpp
@@ -0,0 +1,522 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2012 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 "netlib.h"
+
+typedef enum
+{
+ reqHelloGet,
+ reqOldGet,
+ reqOldPost,
+ reqNewPost,
+}
+RequestType;
+
+
+static int HttpGatewayReadSetResult(NetlibConnection *nlc, char *buf, int num, int peek)
+{
+ if (nlc->dataBufferLen == 0) return 0;
+
+ int bytes = min(num, nlc->dataBufferLen);
+ int rbytes = nlc->dataBufferLen - bytes;
+
+ memcpy(buf, nlc->dataBuffer, bytes);
+ if (!peek)
+ {
+ memmove(nlc->dataBuffer, nlc->dataBuffer + bytes, rbytes);
+ nlc->dataBufferLen = rbytes;
+ }
+
+ return bytes;
+}
+
+void HttpGatewayRemovePacket(NetlibConnection *nlc, int pck)
+{
+ EnterCriticalSection(&nlc->csHttpSequenceNums);
+ while (pck-- && nlc->pHttpProxyPacketQueue != NULL)
+ {
+ NetlibHTTPProxyPacketQueue *p = nlc->pHttpProxyPacketQueue;
+ nlc->pHttpProxyPacketQueue = nlc->pHttpProxyPacketQueue->next;
+
+ mir_free(p->dataBuffer);
+ mir_free(p);
+ }
+ LeaveCriticalSection(&nlc->csHttpSequenceNums);
+}
+
+
+static bool NetlibHttpGatewaySend(struct NetlibConnection *nlc, RequestType reqType, const char *buf, int len)
+{
+ NETLIBHTTPREQUEST nlhrSend = {0};
+ char szUrl[512];
+
+ nlhrSend.cbSize = sizeof(nlhrSend);
+ nlhrSend.nlc = nlc;
+
+ nlhrSend.pData = (char*)buf;
+ nlhrSend.dataLength = len;
+
+ nlhrSend.flags = NLHRF_GENERATEHOST | NLHRF_DUMPPROXY | NLHRF_SMARTAUTHHEADER | NLHRF_NOPROXY | NLHRF_REDIRECT;
+ if (nlc->nlhpi.flags & NLHPIF_HTTP11) nlhrSend.flags |= NLHRF_HTTP11;
+
+ switch (reqType)
+ {
+ case reqHelloGet:
+ nlhrSend.requestType = REQUEST_GET;
+ nlhrSend.szUrl=nlc->nlu->user.szHttpGatewayHello;
+ break;
+
+ case reqOldGet:
+ nlhrSend.requestType = REQUEST_GET;
+ nlhrSend.timeout = -1;
+ if ((nlc->nlhpi.flags & NLHPIF_USEGETSEQUENCE) && (nlc->nlhpi.szHttpGetUrl != NULL))
+ {
+ EnterCriticalSection(&nlc->csHttpSequenceNums);
+
+ mir_snprintf(szUrl, SIZEOF(szUrl), "%s%u", nlc->nlhpi.szHttpGetUrl, nlc->nlhpi.firstGetSequence++);
+ if (nlc->nlhpi.flags & NLHPIF_GETPOSTSAMESEQUENCE) nlc->nlhpi.firstPostSequence++;
+
+ LeaveCriticalSection(&nlc->csHttpSequenceNums);
+ nlhrSend.szUrl = szUrl;
+ }
+ else
+ nlhrSend.szUrl = nlc->nlhpi.szHttpGetUrl;
+ break;
+
+ case reqOldPost:
+ nlhrSend.requestType = REQUEST_POST;
+ if ((nlc->nlhpi.flags & NLHPIF_USEPOSTSEQUENCE) && (nlc->nlhpi.szHttpPostUrl != NULL))
+ {
+ mir_snprintf(szUrl, SIZEOF(szUrl), "%s%u", nlc->nlhpi.szHttpPostUrl, nlc->nlhpi.firstPostSequence);
+ nlhrSend.szUrl = szUrl;
+ }
+ else
+ nlhrSend.szUrl = nlc->nlhpi.szHttpPostUrl;
+ break;
+
+ case reqNewPost:
+ nlhrSend.requestType = REQUEST_POST;
+ nlhrSend.szUrl = nlc->nlhpi.szHttpPostUrl;
+ break;
+ }
+
+ if (nlc->usingDirectHttpGateway)
+ {
+ NETLIBOPENCONNECTION nloc;
+ NetlibConnFromUrl(nlhrSend.szUrl, false, nloc);
+
+ bool sameHost = lstrcmpA(nlc->nloc.szHost, nloc.szHost) == 0 && nlc->nloc.wPort == nloc.wPort;
+
+ if (!sameHost)
+ {
+ NetlibDoClose(nlc);
+
+ mir_free((char*)nlc->nloc.szHost);
+ nlc->nloc = nloc;
+ if (!NetlibDoConnect(nlc))
+ return false;
+ }
+ else
+ mir_free((char*)nloc.szHost);
+ }
+
+ nlhrSend.headersCount = 3;
+ nlhrSend.headers = (NETLIBHTTPHEADER*)alloca(sizeof(NETLIBHTTPHEADER) * nlhrSend.headersCount);
+ nlhrSend.headers[0].szName = "User-Agent";
+ nlhrSend.headers[0].szValue = nlc->nlu->user.szHttpGatewayUserAgent;
+ nlhrSend.headers[1].szName = "Cache-Control";
+ nlhrSend.headers[1].szValue = "no-cache, no-store ";
+ nlhrSend.headers[2].szName = "Pragma";
+ nlhrSend.headers[2].szValue = "no-cache";
+// nlhrSend.headers[3].szName = "Accept-Encoding";
+// nlhrSend.headers[3].szValue = "deflate, gzip";
+
+ return NetlibHttpSendRequest((WPARAM)nlc,(LPARAM)&nlhrSend) != SOCKET_ERROR;
+}
+
+static bool NetlibHttpGatewayStdPost(NetlibConnection *nlc, int& numPackets)
+{
+ int np = 0, len = 0;
+
+ EnterCriticalSection(&nlc->csHttpSequenceNums);
+
+ NetlibHTTPProxyPacketQueue *p = nlc->pHttpProxyPacketQueue;
+ while (p != NULL && np < nlc->nlhpi.combinePackets) { ++np; len += p->dataBufferLen; p = p->next;}
+
+ char *buf = (char*)alloca(len);
+
+ numPackets = np;
+ int dlen = 0;
+
+ p = nlc->pHttpProxyPacketQueue;
+ while (np--)
+ {
+ memcpy(buf + dlen, p->dataBuffer, p->dataBufferLen);
+ dlen += p->dataBufferLen;
+ p = p->next;
+ }
+
+ LeaveCriticalSection(&nlc->csHttpSequenceNums);
+
+ return NetlibHttpGatewaySend(nlc, reqNewPost, buf, len);
+}
+
+static bool NetlibHttpGatewayOscarPost(NetlibConnection *nlc, const char *buf, int len, int flags)
+{
+ NETLIBHTTPREQUEST *nlhrReply = NULL;
+ NetlibConnection nlcSend = {0};
+
+ nlcSend.handleType = NLH_CONNECTION;
+ nlcSend.nlu = nlc->nlu;
+ nlcSend.nlhpi = nlc->nlhpi;
+ nlcSend.s = nlc->s2;
+ nlcSend.usingHttpGateway = nlc->usingHttpGateway;
+ nlcSend.szProxyServer = nlc->szProxyServer;
+ nlcSend.wProxyPort = nlc->wProxyPort;
+ nlcSend.proxyType = nlc->proxyType;
+
+ if (!NetlibReconnect(&nlcSend)) return false;
+ nlc->s2 = nlcSend.s;
+
+ nlcSend.hOkToCloseEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+ NetlibInitializeNestedCS(&nlcSend.ncsRecv);
+ NetlibInitializeNestedCS(&nlcSend.ncsSend);
+
+ bool res = NetlibHttpGatewaySend(&nlcSend, reqOldPost, buf, len);
+ if (res)
+ {
+ NETLIBHTTPREQUEST *nlhrReply = NetlibHttpRecv(&nlcSend, flags | MSG_RAW | MSG_DUMPPROXY, MSG_RAW | MSG_DUMPPROXY);
+ if (nlhrReply != NULL)
+ {
+ if (nlhrReply->resultCode != 200)
+ {
+ NetlibHttpSetLastErrorUsingHttpResult(nlhrReply->resultCode);
+ res = false;
+ }
+ NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);
+ }
+ else
+ res = false;
+ }
+
+ NetlibDeleteNestedCS(&nlcSend.ncsSend);
+ NetlibDeleteNestedCS(&nlcSend.ncsRecv);
+ CloseHandle(nlcSend.hOkToCloseEvent);
+
+ nlc->s2 = nlcSend.s;
+ mir_free((char*)nlcSend.nloc.szHost);
+
+ EnterCriticalSection(&nlc->csHttpSequenceNums);
+
+ nlc->nlhpi.firstPostSequence++;
+ if (nlc->nlhpi.flags & NLHPIF_GETPOSTSAMESEQUENCE) nlc->nlhpi.firstGetSequence++;
+
+ LeaveCriticalSection(&nlc->csHttpSequenceNums);
+
+ return res;
+}
+
+ int NetlibHttpGatewayPost(struct NetlibConnection *nlc, const char *buf, int len, int flags)
+{
+ struct NetlibHTTPProxyPacketQueue *p;
+
+ if (nlc->nlhpi.szHttpGetUrl != NULL)
+ {
+ return NetlibHttpGatewayOscarPost(nlc, buf, len, flags) ? len : SOCKET_ERROR;
+ }
+
+ /*
+ * Gena01 - many changes here, do compare against the other version.
+ *
+ * Change #1: simplify to use similar code to GET
+ * Change #2: we need to allow to parse POST reply if szHttpGetUrl is NULL
+ * Change #3: Keep connection open if we need to.
+ *
+ * Impact: NONE! Since currently miranda doesn't allow szHttpGetUrl to be NULL, it will not connect
+ * with the new plugins that use this code.
+ */
+
+ p = ( NetlibHTTPProxyPacketQueue* )mir_alloc(sizeof(struct NetlibHTTPProxyPacketQueue));
+ p->dataBuffer = ( PBYTE )mir_alloc(len);
+ memcpy(p->dataBuffer, buf, len);
+ p->dataBufferLen = len;
+ p->next = NULL;
+
+ /*
+ * Now check to see where to insert this in our queue
+ */
+ EnterCriticalSection(&nlc->csHttpSequenceNums);
+ if (nlc->pHttpProxyPacketQueue == NULL)
+ {
+ nlc->pHttpProxyPacketQueue = p;
+ }
+ else
+ {
+ struct NetlibHTTPProxyPacketQueue *t = nlc->pHttpProxyPacketQueue;
+
+ while (t->next != NULL) t = t->next;
+ t->next = p;
+ }
+ LeaveCriticalSection(&nlc->csHttpSequenceNums);
+
+ /*
+ * Gena01 - fake a Send!! tell 'em all is ok. We catch errors in Recv.
+ */
+ return len;
+}
+
+#define NETLIBHTTP_RETRYCOUNT 3
+#define NETLIBHTTP_RETRYTIMEOUT 2000
+
+int NetlibHttpGatewayRecv(struct NetlibConnection *nlc, char *buf, int len, int flags)
+{
+ bool peek = (flags & MSG_PEEK) != 0;
+
+ if (nlc->dataBufferLen != 0 && (!peek || nlc->dataBufferLen >= len))
+ {
+ return HttpGatewayReadSetResult(nlc, buf, len, peek);
+ }
+
+ for (int retryCount = 0; retryCount < NETLIBHTTP_RETRYCOUNT; )
+ {
+ if (nlc->nlhpi.szHttpGetUrl == NULL && retryCount == 0)
+ {
+ if (nlc->pollingTimeout == 0) nlc->pollingTimeout = 30;
+
+ /* We Need to sleep/wait for the data to send before we do receive */
+ for (int pollCount = nlc->pollingTimeout; pollCount--; )
+ {
+ if (nlc->pHttpProxyPacketQueue != NULL && GetTickCount() - nlc->lastPost > 1000)
+ break;
+
+ if (nlc->termRequested || (SleepEx(1000, TRUE) && Miranda_Terminated()))
+ return SOCKET_ERROR;
+ }
+
+ nlc->lastPost = GetTickCount();
+ if (nlc->pHttpProxyPacketQueue == NULL && nlc->nlu->user.pfnHttpGatewayWrapSend != NULL)
+ {
+ if (nlc->nlu->user.pfnHttpGatewayWrapSend(nlc, (PBYTE)"", 0, MSG_NOHTTPGATEWAYWRAP, NetlibSend) == SOCKET_ERROR)
+ return SOCKET_ERROR;
+ }
+ }
+
+ int numPackets = 0;
+ if (nlc->nlhpi.szHttpGetUrl)
+ {
+ if (!NetlibHttpGatewaySend(nlc, reqOldGet, NULL, 0))
+ {
+ if (GetLastError() == ERROR_ACCESS_DENIED || nlc->termRequested)
+ break;
+
+ ++retryCount;
+ continue;
+ }
+ }
+ else
+ {
+ if (!NetlibHttpGatewayStdPost(nlc, numPackets))
+ {
+ if (GetLastError() == ERROR_ACCESS_DENIED || nlc->termRequested)
+ break;
+
+ ++retryCount;
+ continue;
+ }
+ }
+ NETLIBHTTPREQUEST *nlhrReply = NetlibHttpRecv(nlc, flags | MSG_RAW | MSG_DUMPPROXY, MSG_RAW | MSG_DUMPPROXY);
+ if (nlhrReply == NULL) return SOCKET_ERROR;
+
+ if (nlc->nlu->user.pfnHttpGatewayUnwrapRecv && !(flags & MSG_NOHTTPGATEWAYWRAP))
+ {
+ nlhrReply->pData = (char*)nlc->nlu->user.pfnHttpGatewayUnwrapRecv(nlhrReply,
+ (PBYTE)nlhrReply->pData, nlhrReply->dataLength, &nlhrReply->dataLength, mir_realloc);
+/*
+ if (newBuffer == NULL)
+ {
+ NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);
+ return SOCKET_ERROR;
+ }
+ else
+ nlhrReply->pData = (char*)newBuffer;
+*/
+ }
+
+ if (nlhrReply->resultCode >= 300)
+ {
+ int resultCode = nlhrReply->resultCode;
+ NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);
+
+ if (nlc->nlhpi.szHttpGetUrl && resultCode != 404)
+ {
+ NetlibLogf(nlc->nlu, "Error received from proxy, retrying");
+ continue;
+ }
+ else
+ {
+ NetlibLogf(nlc->nlu, "Error received from proxy, retry attempts exceeded (%u)", retryCount);
+ SetLastError(ERROR_GEN_FAILURE);
+ return SOCKET_ERROR;
+ }
+ }
+ else
+ {
+ retryCount = 0;
+ HttpGatewayRemovePacket(nlc, numPackets);
+ }
+
+ if (nlhrReply->dataLength)
+ {
+ if (peek)
+ {
+ int rbytes = nlc->dataBufferLen + nlhrReply->dataLength;
+
+ nlc->dataBuffer = (PBYTE)mir_realloc(nlc->dataBuffer, rbytes);
+ memcpy(nlc->dataBuffer + nlc->dataBufferLen, nlhrReply->pData, nlhrReply->dataLength);
+ nlc->dataBufferLen = rbytes;
+
+ NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);
+
+ return HttpGatewayReadSetResult(nlc, buf, len, peek);
+ }
+ else
+ {
+ int bytes = min(len, nlhrReply->dataLength);
+ int rbytes = nlhrReply->dataLength - bytes;
+
+ memcpy(buf, nlhrReply->pData, bytes);
+
+ nlc->dataBuffer = (PBYTE)mir_realloc(nlc->dataBuffer, rbytes);
+ if (rbytes) memcpy(nlc->dataBuffer, nlhrReply->pData + bytes, rbytes);
+ nlc->dataBufferLen = rbytes;
+
+ NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);
+ return bytes;
+ }
+ }
+ else
+ {
+ if ((peek && nlc->dataBufferLen != 0) || nlhrReply->pData)
+ {
+ NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);
+ return HttpGatewayReadSetResult(nlc, buf, len, peek);
+ }
+ }
+ NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);
+ }
+
+ SetLastError(ERROR_GEN_FAILURE);
+ return SOCKET_ERROR;
+}
+
+int NetlibInitHttpConnection(struct NetlibConnection *nlc, struct NetlibUser *nlu, NETLIBOPENCONNECTION *nloc)
+{
+ NETLIBHTTPREQUEST *nlhrReply = NULL;
+
+ nlc->nlhpi.firstGetSequence = 1;
+ nlc->nlhpi.firstPostSequence = 1;
+
+ if (nlu->user.szHttpGatewayHello != NULL)
+ {
+ nlc->usingHttpGateway = true;
+ if (NetlibHttpGatewaySend(nlc, reqHelloGet, NULL, 0))
+ nlhrReply = NetlibHttpRecv(nlc, MSG_DUMPPROXY | MSG_RAW, MSG_DUMPPROXY | MSG_RAW);
+ nlc->usingHttpGateway = false;
+ if (nlhrReply == NULL) return 0;
+
+ if (nlhrReply->resultCode != 200)
+ {
+ NetlibHttpSetLastErrorUsingHttpResult(nlhrReply->resultCode);
+ NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);
+ return 0;
+ }
+ }
+ if (!nlu->user.pfnHttpGatewayInit(nlc, nloc, nlhrReply))
+ {
+ NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);
+ return 0;
+ }
+ NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);
+
+ /*
+ * Gena01 - Ok, we should be able to use just POST. Needed for Yahoo, NO GET requests
+ */
+ if(nlc->nlhpi.szHttpPostUrl == NULL)
+ {
+ SetLastError(ERROR_BAD_FORMAT);
+ return 0;
+ }
+
+ nlc->usingHttpGateway = true;
+
+ //now properly connected
+ if (nlu->user.pfnHttpGatewayBegin && !nlu->user.pfnHttpGatewayBegin(nlc, nloc))
+ return 0;
+
+ return 1;
+}
+
+INT_PTR NetlibHttpGatewaySetInfo(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBHTTPPROXYINFO *nlhpi=(NETLIBHTTPPROXYINFO*)lParam;
+ struct NetlibConnection *nlc=(struct NetlibConnection*)wParam;
+
+ if (GetNetlibHandleType(nlc) != NLH_CONNECTION || nlhpi == NULL ||
+ nlhpi->cbSize < (sizeof(NETLIBHTTPPROXYINFO) - sizeof(int)) ||
+ nlhpi->szHttpPostUrl == NULL)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+
+ mir_free(nlc->nlhpi.szHttpGetUrl);
+ mir_free(nlc->nlhpi.szHttpPostUrl);
+
+ nlc->nlhpi.combinePackets = 1;
+ memcpy(&nlc->nlhpi, nlhpi, min(nlhpi->cbSize, sizeof(*nlhpi)));
+ if (nlc->nlhpi.combinePackets == 0) nlc->nlhpi.combinePackets = 1;
+
+ nlc->nlhpi.szHttpGetUrl = mir_strdup(nlc->nlhpi.szHttpGetUrl);
+ nlc->nlhpi.szHttpPostUrl = mir_strdup(nlc->nlhpi.szHttpPostUrl);
+
+ return 1;
+}
+
+INT_PTR NetlibHttpSetSticky(WPARAM wParam, LPARAM lParam)
+{
+ struct NetlibUser * nu = (struct NetlibUser*)wParam;
+ if (GetNetlibHandleType(nu)!=NLH_USER) return ERROR_INVALID_PARAMETER;
+ mir_free(nu->szStickyHeaders);
+ nu->szStickyHeaders = mir_strdup((char*)lParam); // pointer is ours
+ return 0;
+}
+
+INT_PTR NetlibHttpSetPollingTimeout(WPARAM wParam, LPARAM lParam)
+{
+ int oldTimeout;
+ struct NetlibConnection *nlc=(struct NetlibConnection*)wParam;
+ if (GetNetlibHandleType(nlc)!=NLH_CONNECTION) return -1;
+ oldTimeout = nlc->pollingTimeout;
+ nlc->pollingTimeout = lParam;
+ return oldTimeout;
+}
diff --git a/src/modules/netlib/netliblog.cpp b/src/modules/netlib/netliblog.cpp
new file mode 100644
index 0000000000..fb3fe1d5f2
--- /dev/null
+++ b/src/modules/netlib/netliblog.cpp
@@ -0,0 +1,637 @@
+/*
+
+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 "netlib.h"
+#include "../srfile/file.h"
+
+#define MS_NETLIB_LOGWIN "Netlib/Log/Win"
+
+extern HANDLE hConnectionHeaderMutex;
+
+#define TIMEFORMAT_NONE 0
+#define TIMEFORMAT_HHMMSS 1
+#define TIMEFORMAT_MILLISECONDS 2
+#define TIMEFORMAT_MICROSECONDS 3
+struct {
+ HWND hwndOpts;
+ int toOutputDebugString;
+ int toFile;
+ int toLog;
+ TCHAR* szFile;
+ TCHAR* szUserFile;
+ int timeFormat;
+ int showUser;
+ int dumpSent,dumpRecv,dumpProxy,dumpSsl;
+ int textDumps,autoDetectText;
+ CRITICAL_SECTION cs;
+ int save;
+} logOptions = {0};
+
+typedef struct {
+ const char* pszHead;
+ const char* pszMsg;
+} LOGMSG;
+
+static __int64 mirandaStartTime,perfCounterFreq;
+static int bIsActive = TRUE;
+static HANDLE hLogEvent = NULL;
+
+static const TCHAR* szTimeFormats[] =
+{
+ _T( "No times" ),
+ _T( "Standard hh:mm:ss times" ),
+ _T( "Times in milliseconds" ),
+ _T( "Times in microseconds" )
+};
+
+static INT_PTR CALLBACK LogOptionsDlgProc(HWND hwndDlg,UINT message,WPARAM wParam,LPARAM lParam)
+{
+ switch(message) {
+ case WM_INITDIALOG:
+ logOptions.hwndOpts=hwndDlg;
+ TranslateDialogDefault(hwndDlg);
+ CheckDlgButton(hwndDlg,IDC_DUMPRECV,logOptions.dumpRecv?BST_CHECKED:BST_UNCHECKED);
+ CheckDlgButton(hwndDlg,IDC_DUMPSENT,logOptions.dumpSent?BST_CHECKED:BST_UNCHECKED);
+ CheckDlgButton(hwndDlg,IDC_DUMPPROXY,logOptions.dumpProxy?BST_CHECKED:BST_UNCHECKED);
+ CheckDlgButton(hwndDlg,IDC_DUMPSSL,logOptions.dumpSsl?BST_CHECKED:BST_UNCHECKED);
+ CheckDlgButton(hwndDlg,IDC_TEXTDUMPS,logOptions.textDumps?BST_CHECKED:BST_UNCHECKED);
+ CheckDlgButton(hwndDlg,IDC_AUTODETECTTEXT,logOptions.autoDetectText?BST_CHECKED:BST_UNCHECKED);
+ { int i;
+ for( i=0; i < SIZEOF(szTimeFormats); i++ )
+ SendDlgItemMessage(hwndDlg,IDC_TIMEFORMAT,CB_ADDSTRING,0,(LPARAM)TranslateTS( szTimeFormats[i] ));
+ }
+ SendDlgItemMessage(hwndDlg,IDC_TIMEFORMAT,CB_SETCURSEL,logOptions.timeFormat,0);
+ CheckDlgButton(hwndDlg,IDC_SHOWNAMES,logOptions.showUser?BST_CHECKED:BST_UNCHECKED);
+ CheckDlgButton(hwndDlg,IDC_TOOUTPUTDEBUGSTRING,logOptions.toOutputDebugString?BST_CHECKED:BST_UNCHECKED);
+ CheckDlgButton(hwndDlg,IDC_TOFILE,logOptions.toFile?BST_CHECKED:BST_UNCHECKED);
+ SetDlgItemText(hwndDlg,IDC_FILENAME,logOptions.szUserFile);
+ SetDlgItemText(hwndDlg,IDC_PATH,logOptions.szFile);
+ CheckDlgButton(hwndDlg,IDC_SHOWTHISDLGATSTART,DBGetContactSettingByte(NULL, "Netlib", "ShowLogOptsAtStart",0)?BST_CHECKED:BST_UNCHECKED);
+ { DBVARIANT dbv;
+ if(!DBGetContactSettingString(NULL, "Netlib", "RunAtStart",&dbv)) {
+ SetDlgItemTextA(hwndDlg,IDC_RUNATSTART,dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ }
+ logOptions.save = 0;
+ {
+ TVINSERTSTRUCT tvis = {0};
+ int i;
+ HWND hwndFilter = GetDlgItem(hwndDlg,IDC_FILTER);
+
+ SetWindowLongPtr(hwndFilter, GWL_STYLE, GetWindowLongPtr(hwndFilter, GWL_STYLE) | (TVS_NOHSCROLL | TVS_CHECKBOXES));
+
+ tvis.hParent=NULL;
+ tvis.hInsertAfter=TVI_SORT;
+ tvis.item.mask=TVIF_PARAM|TVIF_TEXT|TVIF_STATE;
+ tvis.item.stateMask=TVIS_STATEIMAGEMASK;
+
+ for (i = 0; i < netlibUser.getCount(); ++i)
+ {
+ tvis.item.pszText=netlibUser[i]->user.ptszDescriptiveName;
+ tvis.item.lParam=i;
+ tvis.item.state=INDEXTOSTATEIMAGEMASK( (netlibUser[i]->toLog) ? 2 : 1 );
+ TreeView_InsertItem(hwndFilter, &tvis);
+ }
+ tvis.item.lParam=-1;
+ tvis.item.pszText=TranslateT("(Miranda Core Logging)");
+ tvis.item.state=INDEXTOSTATEIMAGEMASK( (logOptions.toLog) ? 2 : 1 );
+ TreeView_InsertItem(hwndFilter, &tvis);
+ }
+ return TRUE;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+/*
+ case IDC_DUMPRECV:
+ case IDC_DUMPSENT:
+ case IDC_DUMPPROXY:
+ case IDC_TEXTDUMPS:
+ case IDC_AUTODETECTTEXT:
+ case IDC_TIMEFORMAT:
+ case IDC_SHOWNAMES:
+ case IDC_TOOUTPUTDEBUGSTRING:
+ case IDC_TOFILE:
+ case IDC_SHOWTHISDLGATSTART:
+ case IDC_RUNATSTART:
+ break;
+*/
+ case IDC_FILENAME:
+ if(HIWORD(wParam)!=EN_CHANGE) break;
+ if((HWND)lParam==GetFocus())
+ CheckDlgButton(hwndDlg,IDC_TOFILE,BST_CHECKED);
+
+ {
+ TCHAR path[MAX_PATH];
+ GetWindowText((HWND)lParam, path, MAX_PATH);
+
+ TCHAR *pszNewPath = Utils_ReplaceVarsT(path);
+ pathToAbsoluteT(pszNewPath, path, NULL);
+ SetDlgItemText(hwndDlg, IDC_PATH, path);
+ mir_free(pszNewPath);
+ }
+ break;
+ case IDC_FILENAMEBROWSE:
+ case IDC_RUNATSTARTBROWSE:
+ { TCHAR str[MAX_PATH+2];
+ OPENFILENAME ofn={0};
+ TCHAR filter[512],*pfilter;
+
+ GetWindowText(GetWindow((HWND)lParam,GW_HWNDPREV),str,SIZEOF(str));
+ ofn.lStructSize=OPENFILENAME_SIZE_VERSION_400;
+ ofn.hwndOwner=hwndDlg;
+ ofn.Flags=OFN_HIDEREADONLY | OFN_DONTADDTORECENT;
+ if (LOWORD(wParam)==IDC_FILENAMEBROWSE) {
+ ofn.lpstrTitle=TranslateT("Select where log file will be created");
+ } else {
+ ofn.Flags|=OFN_PATHMUSTEXIST|OFN_FILEMUSTEXIST;
+ ofn.lpstrTitle=TranslateT("Select program to be run");
+ }
+ _tcscpy(filter,TranslateT("All Files"));
+ _tcscat(filter,_T(" (*)"));
+ pfilter=filter+lstrlen(filter)+1;
+ _tcscpy(pfilter,_T("*"));
+ pfilter=pfilter+lstrlen(pfilter)+1;
+ *pfilter='\0';
+ ofn.lpstrFilter=filter;
+ ofn.lpstrFile=str;
+ ofn.nMaxFile=SIZEOF(str)-2;
+ ofn.nMaxFileTitle=MAX_PATH;
+ if (LOWORD(wParam)==IDC_FILENAMEBROWSE) {
+ if(!GetSaveFileName(&ofn)) return 1;
+ } else {
+ if(!GetOpenFileName(&ofn)) return 1;
+ }
+ if(LOWORD(wParam)==IDC_RUNATSTARTBROWSE && _tcschr(str,' ')!=NULL) {
+ MoveMemory(str+1,str,SIZEOF(str)-2);
+ str[0]='"';
+ lstrcat(str,_T("\""));
+ }
+ SetWindowText(GetWindow((HWND)lParam,GW_HWNDPREV),str);
+ break;
+ }
+ case IDC_RUNNOW:
+ { TCHAR str[MAX_PATH+1];
+ STARTUPINFO si={0};
+ PROCESS_INFORMATION pi;
+ GetDlgItemText(hwndDlg,IDC_RUNATSTART,str,MAX_PATH);
+ si.cb=sizeof(si);
+ if(str[0]) CreateProcess(NULL,str,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi);
+ }
+ break;
+ case IDC_SAVE:
+ logOptions.save = 1;
+ //
+ case IDOK:
+ {
+ TCHAR str[MAX_PATH];
+
+ GetDlgItemText(hwndDlg, IDC_RUNATSTART, str, MAX_PATH);
+ DBWriteContactSettingTString(NULL, "Netlib", "RunAtStart",str);
+ DBWriteContactSettingByte(NULL, "Netlib", "ShowLogOptsAtStart",(BYTE)IsDlgButtonChecked(hwndDlg,IDC_SHOWTHISDLGATSTART));
+
+ EnterCriticalSection(&logOptions.cs);
+
+ mir_free(logOptions.szUserFile);
+ GetWindowText(GetDlgItem(hwndDlg,IDC_FILENAME), str, MAX_PATH );
+ logOptions.szUserFile = mir_tstrdup(str);
+
+ mir_free(logOptions.szFile);
+ GetWindowText(GetDlgItem(hwndDlg,IDC_PATH), str, MAX_PATH );
+ logOptions.szFile = mir_tstrdup(str);
+
+ logOptions.dumpRecv=IsDlgButtonChecked(hwndDlg,IDC_DUMPRECV);
+ logOptions.dumpSent=IsDlgButtonChecked(hwndDlg,IDC_DUMPSENT);
+ logOptions.dumpProxy=IsDlgButtonChecked(hwndDlg,IDC_DUMPPROXY);
+ logOptions.dumpSsl=IsDlgButtonChecked(hwndDlg,IDC_DUMPSSL);
+ logOptions.textDumps=IsDlgButtonChecked(hwndDlg,IDC_TEXTDUMPS);
+ logOptions.autoDetectText=IsDlgButtonChecked(hwndDlg,IDC_AUTODETECTTEXT);
+ logOptions.timeFormat=SendDlgItemMessage(hwndDlg,IDC_TIMEFORMAT,CB_GETCURSEL,0,0);
+ logOptions.showUser=IsDlgButtonChecked(hwndDlg,IDC_SHOWNAMES);
+ logOptions.toOutputDebugString=IsDlgButtonChecked(hwndDlg,IDC_TOOUTPUTDEBUGSTRING);
+ logOptions.toFile=IsDlgButtonChecked(hwndDlg,IDC_TOFILE);
+
+ LeaveCriticalSection(&logOptions.cs);
+ }
+ {
+ HWND hwndFilter = GetDlgItem(logOptions.hwndOpts, IDC_FILTER);
+ TVITEM tvi={0};
+ BOOL checked;
+
+ tvi.mask=TVIF_HANDLE|TVIF_PARAM|TVIF_STATE|TVIF_TEXT;
+ tvi.hItem=TreeView_GetRoot(hwndFilter);
+
+ while(tvi.hItem)
+ {
+ TreeView_GetItem(hwndFilter,&tvi);
+ checked = ((tvi.state&TVIS_STATEIMAGEMASK)>>12==2);
+
+ if (tvi.lParam == -1) {
+ logOptions.toLog = checked;
+ if ( logOptions.save )
+ DBWriteContactSettingDword(NULL, "Netlib", "NLlog",checked);
+ }
+ else
+ if (tvi.lParam < netlibUser.getCount()) {
+ netlibUser[tvi.lParam]->toLog = checked;
+ if ( logOptions.save )
+ DBWriteContactSettingDword(NULL,netlibUser[tvi.lParam]->user.szSettingsModule,"NLlog",checked);
+ }
+
+ tvi.hItem=TreeView_GetNextSibling(hwndFilter,tvi.hItem);
+ }
+ }
+
+ if ( logOptions.save ) {
+ DBWriteContactSettingByte(NULL, "Netlib", "DumpRecv",(BYTE)logOptions.dumpRecv);
+ DBWriteContactSettingByte(NULL, "Netlib", "DumpSent",(BYTE)logOptions.dumpSent);
+ DBWriteContactSettingByte(NULL, "Netlib", "DumpProxy",(BYTE)logOptions.dumpProxy);
+ DBWriteContactSettingByte(NULL, "Netlib", "DumpSsl",(BYTE)logOptions.dumpSsl);
+ DBWriteContactSettingByte(NULL, "Netlib", "TextDumps",(BYTE)logOptions.textDumps);
+ DBWriteContactSettingByte(NULL, "Netlib", "AutoDetectText",(BYTE)logOptions.autoDetectText);
+ DBWriteContactSettingByte(NULL, "Netlib", "TimeFormat",(BYTE)logOptions.timeFormat);
+ DBWriteContactSettingByte(NULL, "Netlib", "ShowUser",(BYTE)logOptions.showUser);
+ DBWriteContactSettingByte(NULL, "Netlib", "ToOutputDebugString",(BYTE)logOptions.toOutputDebugString);
+ DBWriteContactSettingByte(NULL, "Netlib", "ToFile",(BYTE)logOptions.toFile);
+ DBWriteContactSettingTString(NULL, "Netlib", "File", logOptions.szFile ? logOptions.szUserFile: _T(""));
+ logOptions.save = 0;
+ }
+ else
+ DestroyWindow(hwndDlg);
+
+ break;
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ DestroyWindow(hwndDlg);
+ break;
+ case WM_DESTROY:
+ ImageList_Destroy(TreeView_GetImageList(GetDlgItem(hwndDlg, IDC_FILTER), TVSIL_STATE));
+ logOptions.hwndOpts=NULL;
+ break;
+ }
+ return FALSE;
+}
+
+void NetlibLogShowOptions(void)
+{
+ if(logOptions.hwndOpts==NULL)
+ logOptions.hwndOpts=CreateDialog(hMirandaInst,MAKEINTRESOURCE(IDD_NETLIBLOGOPTS),NULL,LogOptionsDlgProc);
+ SetForegroundWindow(logOptions.hwndOpts);
+}
+
+static INT_PTR ShowOptions(WPARAM, LPARAM)
+{
+ NetlibLogShowOptions();
+ return 0;
+}
+
+static INT_PTR NetlibLog(WPARAM wParam, LPARAM lParam)
+{
+ struct NetlibUser *nlu = (struct NetlibUser*)wParam;
+ struct NetlibUser nludummy;
+ const char *pszMsg = (const char*)lParam;
+ char szTime[32], szHead[128];
+ LARGE_INTEGER liTimeNow;
+ DWORD dwOriginalLastError;
+
+ if (!bIsActive)
+ return 0;
+
+ if ((nlu != NULL && GetNetlibHandleType(nlu) != NLH_USER) || pszMsg == NULL)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ if (nlu == NULL) /* if the Netlib user handle is NULL, just pretend its not */
+ {
+ if (!logOptions.toLog)
+ return 1;
+ nlu = &nludummy;
+ nlu->user.szSettingsModule = "(NULL)";
+ }
+ else if (!nlu->toLog)
+ return 1;
+
+ dwOriginalLastError = GetLastError();
+ switch (logOptions.timeFormat)
+ {
+ case TIMEFORMAT_HHMMSS:
+ GetTimeFormatA(LOCALE_USER_DEFAULT, TIME_FORCE24HOURFORMAT | TIME_NOTIMEMARKER,
+ NULL, NULL, szTime, SIZEOF(szTime));
+ break;
+
+ case TIMEFORMAT_MILLISECONDS:
+ QueryPerformanceCounter(&liTimeNow);
+ liTimeNow.QuadPart -= mirandaStartTime;
+ mir_snprintf(szTime, SIZEOF(szTime), "%I64u.%03I64u", liTimeNow.QuadPart / perfCounterFreq,
+ 1000 * (liTimeNow.QuadPart % perfCounterFreq) / perfCounterFreq);
+ break;
+
+ case TIMEFORMAT_MICROSECONDS:
+ QueryPerformanceCounter(&liTimeNow);
+ liTimeNow.QuadPart -= mirandaStartTime;
+ mir_snprintf(szTime, SIZEOF(szTime), "%I64u.%06I64u", liTimeNow.QuadPart / perfCounterFreq,
+ 1000000 * (liTimeNow.QuadPart % perfCounterFreq) / perfCounterFreq);
+ break;
+
+ default:
+ szTime[0] = '\0';
+ break;
+ }
+ if(logOptions.timeFormat || logOptions.showUser)
+ mir_snprintf(szHead, SIZEOF(szHead) - 1, "[%s%s%s] ", szTime,
+ (logOptions.showUser && logOptions.timeFormat) ? " " : "",
+ logOptions.showUser ? nlu->user.szSettingsModule : "");
+ else
+ szHead[0]=0;
+
+ if(logOptions.toOutputDebugString)
+ {
+ if (szHead[0])
+ OutputDebugStringA(szHead);
+ OutputDebugStringA(pszMsg);
+ OutputDebugStringA("\n");
+ }
+
+ if (logOptions.toFile && logOptions.szFile[0])
+ {
+ EnterCriticalSection(&logOptions.cs);
+
+ FILE *fp;
+ fp = _tfopen(logOptions.szFile, _T("ab"));
+ if (!fp)
+ {
+ CreatePathToFileT(logOptions.szFile);
+ fp = _tfopen(logOptions.szFile, _T("at"));
+ }
+ if (fp)
+ {
+ size_t len = strlen(pszMsg);
+ fprintf(fp,"%s%s%s", szHead, pszMsg, pszMsg[len-1] == '\n' ? "" : "\r\n");
+ fclose(fp);
+ }
+ LeaveCriticalSection(&logOptions.cs);
+ }
+
+ if (((THook*)hLogEvent)->subscriberCount)
+ {
+ LOGMSG logMsg = { szHead, pszMsg };
+ CallHookSubscribers(hLogEvent, (WPARAM)nlu, (LPARAM)&logMsg);
+ }
+
+ SetLastError(dwOriginalLastError);
+ return 1;
+}
+
+static INT_PTR NetlibLogW(WPARAM wParam, LPARAM lParam)
+{
+ const wchar_t *pszMsg = (const wchar_t*)lParam;
+ char* szMsg = Utf8EncodeUcs2(pszMsg);
+ INT_PTR res = NetlibLog(wParam, (LPARAM)szMsg);
+ mir_free(szMsg);
+ return res;
+}
+
+void NetlibLogf(NetlibUser* nlu, const char *fmt, ...)
+{
+ if (nlu == NULL)
+ {
+ if (!logOptions.toLog)
+ return;
+ }
+ else if (!nlu->toLog)
+ return;
+
+ va_list va;
+ char szText[1024];
+
+ va_start(va,fmt);
+ mir_vsnprintf(szText, sizeof(szText), fmt, va);
+ va_end(va);
+
+ NetlibLog((WPARAM)nlu, (LPARAM)szText);
+}
+
+
+void NetlibDumpData(struct NetlibConnection *nlc,PBYTE buf,int len,int sent,int flags)
+{
+ int isText=1;
+ char szTitleLine[128];
+ char *szBuf;
+ int titleLineLen;
+ struct NetlibUser *nlu;
+ bool useStack = false;
+
+ // This section checks a number of conditions and aborts
+ // the dump if the data should not be written to the log
+
+ // Check packet flags
+ if (flags & (MSG_PEEK | MSG_NODUMP))
+ return;
+
+ // Check user's log settings
+ if (!(logOptions.toOutputDebugString ||
+ ((THook*)hLogEvent)->subscriberCount ||
+ (logOptions.toFile && logOptions.szFile[0])))
+ return;
+ if ((sent && !logOptions.dumpSent) ||
+ (!sent && !logOptions.dumpRecv))
+ return;
+ if ((flags & MSG_DUMPPROXY) && !logOptions.dumpProxy)
+ return;
+ if ((flags & MSG_DUMPSSL) && !logOptions.dumpSsl)
+ return;
+
+ WaitForSingleObject(hConnectionHeaderMutex, INFINITE);
+ nlu = nlc ? nlc->nlu : NULL;
+ titleLineLen = mir_snprintf(szTitleLine, SIZEOF(szTitleLine), "(%p:%u) Data %s%s\r\n",
+ nlc, nlc ? nlc->s : 0, sent ? "sent" : "received", flags & MSG_DUMPPROXY ? " (proxy)" : "");
+ ReleaseMutex(hConnectionHeaderMutex);
+
+ // check filter settings
+ if (nlu == NULL)
+ {
+ if (!logOptions.toLog)
+ return;
+ }
+ else if (!nlu->toLog)
+ return;
+
+ if (!logOptions.textDumps)
+ isText = 0;
+ else if (!(flags&MSG_DUMPASTEXT))
+ {
+ if (logOptions.autoDetectText)
+ {
+ int i;
+ for(i = 0; i<len; i++)
+ {
+ if ((buf[i]<' ' && buf[i]!='\t' && buf[i]!='\r' && buf[i]!='\n') || buf[i]>=0x80)
+ {
+ isText = 0;
+ break;
+ }
+ }
+ }
+ else
+ isText = 0;
+ }
+
+ // Text data
+ if ( isText ) {
+ int sz = titleLineLen + len + 1;
+ useStack = sz <= 8192;
+ szBuf = (char*)(useStack ? alloca(sz) : mir_alloc(sz));
+ CopyMemory( szBuf, szTitleLine, titleLineLen );
+ CopyMemory( szBuf + titleLineLen, (const char*)buf, len );
+ szBuf[titleLineLen + len] = '\0';
+ }
+ // Binary data
+ else {
+ int line, col, colsInLine;
+ char *pszBuf;
+ int sz = titleLineLen + ((len+16)>>4) * 78 + 1;
+ useStack = sz <= 8192;
+
+ szBuf = (char*)(useStack ? alloca(sz) : mir_alloc(sz));
+ CopyMemory(szBuf, szTitleLine, titleLineLen);
+ pszBuf = szBuf + titleLineLen;
+ for ( line = 0; ; line += 16 ) {
+ colsInLine = min(16, len - line);
+
+ if (colsInLine == 16) {
+ PBYTE p = buf + line;
+ pszBuf += wsprintfA(
+ pszBuf, "%08X: %02X %02X %02X %02X-%02X %02X %02X %02X-%02X %02X %02X %02X-%02X %02X %02X %02X ",
+ line, p[0],p[1],p[2],p[3],p[4],p[5],p[6],p[7],p[8],p[9],p[10],p[11],p[12],p[13],p[14],p[15] );
+ }
+ else {
+ pszBuf += wsprintfA(pszBuf, "%08X: ", line);
+ // Dump data as hex
+ for (col = 0; col < colsInLine; col++)
+ pszBuf += wsprintfA(pszBuf, "%02X%c", buf[line + col], ((col&3)==3 && col != 15)?'-':' ');
+ // Fill out last line with blanks
+ for ( ; col<16; col++)
+ {
+ lstrcpyA(pszBuf, " ");
+ pszBuf += 3;
+ }
+ *pszBuf++ = ' ';
+ }
+
+ for (col = 0; col < colsInLine; col++)
+ *pszBuf++ = buf[line+col]<' '?'.':(char)buf[line+col];
+
+ if (len-line<=16)
+ break;
+
+ *pszBuf++ = '\r'; // End each line with a break
+ *pszBuf++ = '\n'; // End each line with a break
+ }
+ *pszBuf = '\0';
+ }
+
+ NetlibLog((WPARAM)nlu,(LPARAM)szBuf);
+ if (!useStack) mir_free(szBuf);
+}
+
+void NetlibLogInit(void)
+{
+ DBVARIANT dbv;
+ LARGE_INTEGER li;
+
+ QueryPerformanceFrequency( &li );
+ perfCounterFreq = li.QuadPart;
+ QueryPerformanceCounter( &li );
+ mirandaStartTime = li.QuadPart;
+
+ CreateServiceFunction( MS_NETLIB_LOGWIN, ShowOptions );
+ CreateServiceFunction( MS_NETLIB_LOG, NetlibLog );
+ CreateServiceFunction( MS_NETLIB_LOGW, NetlibLogW );
+ hLogEvent = CreateHookableEvent( ME_NETLIB_FASTDUMP );
+
+ InitializeCriticalSection(&logOptions.cs);
+ logOptions.dumpRecv = DBGetContactSettingByte( NULL, "Netlib", "DumpRecv", 1 );
+ logOptions.dumpSent = DBGetContactSettingByte( NULL, "Netlib", "DumpSent", 1 );
+ logOptions.dumpProxy = DBGetContactSettingByte( NULL, "Netlib", "DumpProxy", 1 );
+ logOptions.dumpSsl = DBGetContactSettingByte( NULL, "Netlib", "DumpSsl", 0 );
+ logOptions.textDumps = DBGetContactSettingByte( NULL, "Netlib", "TextDumps", 1 );
+ logOptions.autoDetectText = DBGetContactSettingByte( NULL, "Netlib", "AutoDetectText", 1 );
+ logOptions.timeFormat = DBGetContactSettingByte( NULL, "Netlib", "TimeFormat", TIMEFORMAT_HHMMSS );
+ logOptions.showUser = DBGetContactSettingByte( NULL, "Netlib", "ShowUser", 1 );
+ logOptions.toOutputDebugString = DBGetContactSettingByte( NULL, "Netlib", "ToOutputDebugString", 0 );
+ logOptions.toFile = DBGetContactSettingByte( NULL, "Netlib", "ToFile", 0 );
+ logOptions.toLog = DBGetContactSettingDword( NULL, "Netlib", "NLlog", 1 );
+
+ if (!DBGetContactSettingTString(NULL, "Netlib", "File", &dbv))
+ {
+ logOptions.szUserFile = mir_tstrdup(dbv.ptszVal);
+ TCHAR *pszNewPath = Utils_ReplaceVarsT(dbv.ptszVal);
+
+ TCHAR path[MAX_PATH];
+ pathToAbsoluteT(pszNewPath, path, NULL);
+ logOptions.szFile = mir_tstrdup(path);
+
+ mir_free(pszNewPath);
+ DBFreeVariant(&dbv);
+ }
+ else
+ {
+ logOptions.szUserFile = mir_tstrdup(_T("%miranda_logpath%\\netlog.txt"));
+ logOptions.szFile = Utils_ReplaceVarsT(logOptions.szUserFile);
+ }
+
+ if ( logOptions.toFile && logOptions.szFile[0] ) {
+ FILE *fp;
+ fp = _tfopen( logOptions.szFile, _T("wt"));
+ if ( fp )
+ fclose(fp);
+ }
+
+ if ( DBGetContactSettingByte( NULL, "Netlib", "ShowLogOptsAtStart", 0 ))
+ NetlibLogShowOptions();
+
+ if ( !DBGetContactSettingTString( NULL, "Netlib", "RunAtStart", &dbv )) {
+ STARTUPINFO si = { 0 };
+ PROCESS_INFORMATION pi;
+ si.cb = sizeof( si );
+ if ( dbv.ptszVal[0] )
+ CreateProcess( NULL, dbv.ptszVal, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi );
+ DBFreeVariant( &dbv );
+ }
+}
+
+void NetlibLogShutdown(void)
+{
+ bIsActive = FALSE;
+ DestroyHookableEvent( hLogEvent ); hLogEvent = NULL;
+ if ( IsWindow( logOptions.hwndOpts ))
+ DestroyWindow( logOptions.hwndOpts );
+ DeleteCriticalSection( &logOptions.cs );
+ mir_free( logOptions.szFile );
+ mir_free( logOptions.szUserFile );
+}
diff --git a/src/modules/netlib/netlibopenconn.cpp b/src/modules/netlib/netlibopenconn.cpp
new file mode 100644
index 0000000000..b9d4753b9a
--- /dev/null
+++ b/src/modules/netlib/netlibopenconn.cpp
@@ -0,0 +1,944 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2012 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 "netlib.h"
+
+extern CRITICAL_SECTION csNetlibUser;
+extern HANDLE hConnectionOpenMutex;
+extern DWORD g_LastConnectionTick;
+extern int connectionTimeout;
+static int iUPnPCleanup = 0;
+
+#define RECV_DEFAULT_TIMEOUT 60000
+
+//returns in network byte order
+DWORD DnsLookup(struct NetlibUser *nlu,const char *szHost)
+{
+ HOSTENT* host;
+ DWORD ip = inet_addr(szHost);
+ if (ip != INADDR_NONE)
+ return ip;
+
+ __try
+ {
+ host = gethostbyname(szHost);
+ if ( host )
+ return *(u_long*)host->h_addr_list[0];
+
+ NetlibLogf(nlu,"%s %d: %s() for host %s failed (%u)",__FILE__,__LINE__,"gethostbyname", szHost, WSAGetLastError());
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER) {}
+
+ return 0;
+}
+
+int WaitUntilReadable(SOCKET s, DWORD dwTimeout, bool check)
+{
+ fd_set readfd;
+ TIMEVAL tv;
+
+ if (s == INVALID_SOCKET) return SOCKET_ERROR;
+
+ tv.tv_sec = dwTimeout / 1000;
+ tv.tv_usec = (dwTimeout % 1000) * 1000;
+
+ FD_ZERO(&readfd);
+ FD_SET(s, &readfd);
+
+ int result = select(0, &readfd, 0, 0, &tv);
+ if (result == 0 && !check) SetLastError(ERROR_TIMEOUT);
+ return result;
+}
+
+int WaitUntilWritable(SOCKET s,DWORD dwTimeout)
+{
+ fd_set writefd;
+ TIMEVAL tv;
+
+ tv.tv_sec = dwTimeout / 1000;
+ tv.tv_usec = (dwTimeout % 1000) * 1000;
+
+ FD_ZERO(&writefd);
+ FD_SET(s, &writefd);
+
+ switch(select(0, 0, &writefd, 0, &tv))
+ {
+ case 0:
+ SetLastError(ERROR_TIMEOUT);
+ case SOCKET_ERROR:
+ return 0;
+ }
+ return 1;
+}
+
+bool RecvUntilTimeout(struct NetlibConnection *nlc, char *buf, int len, int flags, DWORD dwTimeout)
+{
+ int nReceived = 0;
+ DWORD dwTimeNow, dwCompleteTime = GetTickCount() + dwTimeout;
+
+ while ((dwTimeNow = GetTickCount()) < dwCompleteTime)
+ {
+ if (WaitUntilReadable(nlc->s, dwCompleteTime - dwTimeNow) <= 0) return false;
+ nReceived = NLRecv(nlc, buf, len, flags);
+ if (nReceived <= 0) return false;
+
+ buf += nReceived;
+ len -= nReceived;
+ if (len <= 0) return true;
+ }
+ SetLastError( ERROR_TIMEOUT );
+ return false;
+}
+
+static int NetlibInitSocks4Connection(NetlibConnection *nlc, NetlibUser *nlu, NETLIBOPENCONNECTION *nloc)
+{
+ // http://www.socks.nec.com/protocol/socks4.protocol and http://www.socks.nec.com/protocol/socks4a.protocol
+ if (!nloc->szHost || !nloc->szHost[0]) return 0;
+
+ size_t nHostLen = strlen(nloc->szHost) + 1;
+ size_t nUserLen = nlu->settings.szProxyAuthUser ? strlen(nlu->settings.szProxyAuthUser) + 1 : 1;
+ size_t len = 8 + nUserLen;
+
+ char* pInit = (char*)alloca(len + nHostLen);
+ pInit[0] = 4; // SOCKS4
+ pInit[1] = 1; //connect
+ *(PWORD)&pInit[2] = htons(nloc->wPort);
+
+ if (nUserLen <= 1) pInit[8] = 0;
+ else memcpy(&pInit[8], nlu->settings.szProxyAuthUser, nUserLen);
+
+ //if cannot resolve host, try resolving through proxy (requires SOCKS4a)
+ DWORD ip = DnsLookup(nlu, nloc->szHost);
+ *(PDWORD)&pInit[4] = ip ? ip : 0x01000000;
+ if (!ip)
+ {
+ memcpy(&pInit[len], nloc->szHost, nHostLen);
+ len += nHostLen;
+ }
+
+ if (NLSend(nlc, pInit, (int)len, MSG_DUMPPROXY) == SOCKET_ERROR)
+ {
+ NetlibLogf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"NLSend",GetLastError());
+ return 0;
+ }
+
+ char reply[8];
+ if (!RecvUntilTimeout(nlc, reply, sizeof(reply), MSG_DUMPPROXY, RECV_DEFAULT_TIMEOUT))
+ {
+ NetlibLogf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"RecvUntilTimeout",GetLastError());
+ return 0;
+ }
+
+ switch ((BYTE)reply[1])
+ {
+ case 90: return 1;
+ case 91: SetLastError(ERROR_ACCESS_DENIED); break;
+ case 92: SetLastError(ERROR_CONNECTION_UNAVAIL); break;
+ case 93: SetLastError(ERROR_INVALID_ACCESS); break;
+ default: SetLastError(ERROR_INVALID_DATA); break;
+ }
+ NetlibLogf(nlu,"%s %d: Proxy connection failed (%x %u)",__FILE__,__LINE__, (BYTE)reply[1], GetLastError());
+ return 0;
+}
+
+static int NetlibInitSocks5Connection(struct NetlibConnection *nlc,struct NetlibUser *nlu,NETLIBOPENCONNECTION *nloc)
+{ //rfc1928
+ BYTE buf[258];
+
+ buf[0]=5; //yep, socks5
+ buf[1]=1; //one auth method
+ buf[2]=nlu->settings.useProxyAuth?2:0;
+ if(NLSend(nlc,(char*)buf,3,MSG_DUMPPROXY)==SOCKET_ERROR) {
+ NetlibLogf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"NLSend",GetLastError());
+ return 0;
+ }
+
+ //confirmation of auth method
+ if (!RecvUntilTimeout(nlc,(char*)buf,2,MSG_DUMPPROXY,RECV_DEFAULT_TIMEOUT)) {
+ NetlibLogf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"RecvUntilTimeout",GetLastError());
+ return 0;
+ }
+ if((buf[1]!=0 && buf[1]!=2)) {
+ SetLastError(ERROR_INVALID_ID_AUTHORITY);
+ NetlibLogf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"NLRecv",GetLastError());
+ return 0;
+ }
+
+ if(buf[1]==2) { //rfc1929
+ int nUserLen,nPassLen;
+ PBYTE pAuthBuf;
+
+ nUserLen=lstrlenA(nlu->settings.szProxyAuthUser);
+ nPassLen=lstrlenA(nlu->settings.szProxyAuthPassword);
+ pAuthBuf=(PBYTE)mir_alloc(3+nUserLen+nPassLen);
+ pAuthBuf[0]=1; //auth version
+ pAuthBuf[1]=nUserLen;
+ memcpy(pAuthBuf+2,nlu->settings.szProxyAuthUser,nUserLen);
+ pAuthBuf[2+nUserLen]=nPassLen;
+ memcpy(pAuthBuf+3+nUserLen,nlu->settings.szProxyAuthPassword,nPassLen);
+ if(NLSend(nlc,(char*)pAuthBuf,3+nUserLen+nPassLen,MSG_DUMPPROXY)==SOCKET_ERROR) {
+ NetlibLogf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"NLSend",GetLastError());
+ mir_free(pAuthBuf);
+ return 0;
+ }
+ mir_free(pAuthBuf);
+
+ if (!RecvUntilTimeout(nlc,(char*)buf,2,MSG_DUMPPROXY,RECV_DEFAULT_TIMEOUT)) {
+ NetlibLogf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"RecvUntilTimeout",GetLastError());
+ return 0;
+ }
+ if(buf[1]) {
+ SetLastError(ERROR_ACCESS_DENIED);
+ NetlibLogf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"RecvUntilTimeout",GetLastError());
+ return 0;
+ }
+ }
+
+ {
+ PBYTE pInit;
+ int nHostLen;
+ DWORD hostIP;
+
+ if(nlc->dnsThroughProxy) {
+ if((hostIP=inet_addr(nloc->szHost))==INADDR_NONE)
+ nHostLen=lstrlenA(nloc->szHost)+1;
+ else nHostLen=4;
+ }
+ else {
+ if((hostIP=DnsLookup(nlu,nloc->szHost))==0)
+ return 0;
+ nHostLen=4;
+ }
+ pInit=(PBYTE)mir_alloc(6+nHostLen);
+ pInit[0]=5; //SOCKS5
+ pInit[1]= nloc->flags & NLOCF_UDP ? 3 : 1; //connect or UDP
+ pInit[2]=0; //reserved
+ if(hostIP==INADDR_NONE) { //DNS lookup through proxy
+ pInit[3]=3;
+ pInit[4]=nHostLen-1;
+ memcpy(pInit+5,nloc->szHost,nHostLen-1);
+ }
+ else {
+ pInit[3]=1;
+ *(PDWORD)(pInit+4)=hostIP;
+ }
+ *(PWORD)(pInit+4+nHostLen)=htons(nloc->wPort);
+ if(NLSend(nlc,(char*)pInit,6+nHostLen,MSG_DUMPPROXY)==SOCKET_ERROR) {
+ NetlibLogf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"NLSend",GetLastError());
+ mir_free(pInit);
+ return 0;
+ }
+ mir_free(pInit);
+ }
+
+ if (!RecvUntilTimeout(nlc,(char*)buf,5,MSG_DUMPPROXY,RECV_DEFAULT_TIMEOUT)) {
+ NetlibLogf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"RecvUntilTimeout",GetLastError());
+ return 0;
+ }
+
+ if ( buf[0]!=5 || buf[1] ) {
+ const char* err = "Unknown response";
+ if ( buf[0] != 5 )
+ SetLastError(ERROR_BAD_FORMAT);
+ else
+ {
+ switch(buf[1])
+ {
+ case 1: SetLastError(ERROR_GEN_FAILURE); err = "General failure"; break;
+ case 2: SetLastError(ERROR_ACCESS_DENIED); err = "Connection not allowed by ruleset"; break;
+ case 3: SetLastError(WSAENETUNREACH); err = "Network unreachable"; break;
+ case 4: SetLastError(WSAEHOSTUNREACH); err = "Host unreachable"; break;
+ case 5: SetLastError(WSAECONNREFUSED); err = "Connection refused by destination host"; break;
+ case 6: SetLastError(WSAETIMEDOUT); err = "TTL expired"; break;
+ case 7: SetLastError(ERROR_CALL_NOT_IMPLEMENTED); err = "Command not supported / protocol error"; break;
+ case 8: SetLastError(ERROR_INVALID_ADDRESS); err = "Address type not supported"; break;
+ default: SetLastError(ERROR_INVALID_DATA); break;
+ }
+ }
+ NetlibLogf(nlu,"%s %d: Proxy conection failed. %s.",__FILE__,__LINE__, err);
+ return 0;
+ }
+ {
+ int nRecvSize = 0;
+ switch( buf[3] ) {
+ case 1:// ipv4 addr
+ nRecvSize = 5;
+ break;
+ case 3:// dns name addr
+ nRecvSize = buf[4] + 2;
+ break;
+ case 4:// ipv6 addr
+ nRecvSize = 17;
+ break;
+ default:
+ NetlibLogf(nlu,"%s %d: %s() unknown address type (%u)",__FILE__,__LINE__,"NetlibInitSocks5Connection",(int)buf[3]);
+ return 0;
+ }
+ if (!RecvUntilTimeout(nlc,(char*)buf,nRecvSize,MSG_DUMPPROXY,RECV_DEFAULT_TIMEOUT)) {
+ NetlibLogf(nlu,"%s %d: %s() failed (%u)",__FILE__,__LINE__,"RecvUntilTimeout",GetLastError());
+ return 0;
+ }
+ }
+
+ //connected
+ return 1;
+}
+
+static bool NetlibInitHttpsConnection(struct NetlibConnection *nlc, struct NetlibUser *nlu, NETLIBOPENCONNECTION *nloc)
+{ //rfc2817
+ NETLIBHTTPREQUEST nlhrSend = {0}, *nlhrReply;
+ char szUrl[512];
+
+ nlhrSend.cbSize = sizeof(nlhrSend);
+ nlhrSend.requestType = REQUEST_CONNECT;
+ nlhrSend.flags = NLHRF_GENERATEHOST | NLHRF_DUMPPROXY | NLHRF_SMARTAUTHHEADER | NLHRF_HTTP11 | NLHRF_NOPROXY | NLHRF_REDIRECT;
+ if (nlc->dnsThroughProxy)
+ {
+ mir_snprintf(szUrl, SIZEOF(szUrl), "%s:%u", nloc->szHost, nloc->wPort);
+ }
+ else
+ {
+ DWORD ip = DnsLookup(nlu, nloc->szHost);
+ if (ip == 0) return false;
+ mir_snprintf(szUrl, SIZEOF(szUrl), "%s:%u", inet_ntoa(*(PIN_ADDR)&ip), nloc->wPort);
+ }
+ nlhrSend.szUrl = szUrl;
+
+ nlc->usingHttpGateway = true;
+
+ if (NetlibHttpSendRequest((WPARAM)nlc, (LPARAM)&nlhrSend) == SOCKET_ERROR)
+ {
+ nlc->usingHttpGateway = false;
+ return 0;
+ }
+ nlhrReply = NetlibHttpRecv(nlc, MSG_DUMPPROXY | MSG_RAW, MSG_DUMPPROXY | MSG_RAW, true);
+ nlc->usingHttpGateway = false;
+ if (nlhrReply == NULL) return false;
+ if (nlhrReply->resultCode < 200 || nlhrReply->resultCode >= 300)
+ {
+ if (nlhrReply->resultCode == 403 && nlc->dnsThroughProxy)
+ {
+ NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);
+ nlc->dnsThroughProxy = 0;
+ return NetlibInitHttpsConnection(nlc, nlu, nloc);
+ }
+
+ NetlibHttpSetLastErrorUsingHttpResult(nlhrReply->resultCode);
+ NetlibLogf(nlu,"%s %d: %s request failed (%u %s)",__FILE__,__LINE__,nlu->settings.proxyType==PROXYTYPE_HTTP?"HTTP":"HTTPS",nlhrReply->resultCode,nlhrReply->szResultDescr);
+ NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);
+ return 0;
+ }
+ NetlibHttpFreeRequestStruct(0, (LPARAM)nlhrReply);
+ //connected
+ return true;
+}
+
+static void FreePartiallyInitedConnection(struct NetlibConnection *nlc)
+{
+ DWORD dwOriginalLastError=GetLastError();
+
+ if (nlc->s!=INVALID_SOCKET) closesocket(nlc->s);
+ mir_free(nlc->nlhpi.szHttpPostUrl);
+ mir_free(nlc->nlhpi.szHttpGetUrl);
+ mir_free((char*)nlc->nloc.szHost);
+ mir_free(nlc->szProxyServer);
+ NetlibDeleteNestedCS(&nlc->ncsSend);
+ NetlibDeleteNestedCS(&nlc->ncsRecv);
+ CloseHandle(nlc->hOkToCloseEvent);
+ DeleteCriticalSection(&nlc->csHttpSequenceNums);
+ mir_free(nlc);
+ SetLastError(dwOriginalLastError);
+}
+
+static bool my_connectIPv4(NetlibConnection *nlc, NETLIBOPENCONNECTION * nloc)
+{
+ int rc = 0, retrycnt = 0;
+ u_long notblocking = 1;
+ DWORD lasterr = 0;
+ static const TIMEVAL tv = { 1, 0 };
+
+ unsigned int dwTimeout = (nloc->cbSize == sizeof(NETLIBOPENCONNECTION) && nloc->flags & NLOCF_V2) ? nloc->timeout : 0;
+ // if dwTimeout is zero then its an old style connection or new with a 0 timeout, select() will error quicker anyway
+ if (dwTimeout == 0) dwTimeout = 30;
+
+ // this is for XP SP2 where there is a default connection attempt limit of 10/second
+ if (connectionTimeout)
+ {
+ WaitForSingleObject(hConnectionOpenMutex, 10000);
+ int waitdiff = GetTickCount() - g_LastConnectionTick;
+ if (waitdiff < connectionTimeout) SleepEx(connectionTimeout, TRUE);
+ g_LastConnectionTick = GetTickCount();
+ ReleaseMutex(hConnectionOpenMutex);
+
+ // might of died in between the wait
+ if (Miranda_Terminated()) return false;
+ }
+
+ SOCKADDR_IN sin = {0};
+ sin.sin_family = AF_INET;
+
+ if (nlc->proxyType)
+ {
+ if (!nlc->szProxyServer) return false;
+
+ if (nloc)
+ NetlibLogf(nlc->nlu,"(%p) Connecting to proxy %s:%d for %s:%d ....", nlc, nlc->szProxyServer, nlc->wProxyPort, nloc->szHost, nloc->wPort);
+ else
+ NetlibLogf(nlc->nlu,"(%p) Connecting to proxy %s:%d ....", nlc, nlc->szProxyServer, nlc->wProxyPort);
+
+ sin.sin_port = htons(nlc->wProxyPort);
+ sin.sin_addr.s_addr = DnsLookup(nlc->nlu, nlc->szProxyServer);
+ }
+ else
+ {
+ if (!nloc || !nloc->szHost) return false;
+ NetlibLogf(nlc->nlu,"(%p) Connecting to server %s:%d....", nlc, nloc->szHost, nloc->wPort);
+
+ sin.sin_port = htons(nloc->wPort);
+ sin.sin_addr.s_addr = DnsLookup(nlc->nlu, nloc->szHost);
+ }
+
+retry:
+ nlc->s = socket(AF_INET,nloc->flags & NLOCF_UDP ? SOCK_DGRAM : SOCK_STREAM, 0);
+ if (nlc->s == INVALID_SOCKET) return false;
+
+ // return the socket to non blocking
+ if (ioctlsocket(nlc->s, FIONBIO, &notblocking) != 0) return false;
+
+ if (nlc->nlu->settings.specifyOutgoingPorts && nlc->nlu->settings.szOutgoingPorts && nlc->nlu->settings.szOutgoingPorts[0])
+ {
+ if (!BindSocketToPort(nlc->nlu->settings.szOutgoingPorts, nlc->s, &nlc->nlu->inportnum))
+ NetlibLogf(nlc->nlu,"Netlib connect: Not enough ports for outgoing connections specified");
+ }
+
+ // try a connect
+ if (connect(nlc->s, (LPSOCKADDR)&sin, sizeof(sin)) == 0)
+ {
+ goto unblock;
+ }
+
+ // didn't work, was it cos of nonblocking?
+ if (WSAGetLastError() != WSAEWOULDBLOCK)
+ {
+ rc = SOCKET_ERROR;
+ goto unblock;
+ }
+
+ for (;;)
+ {
+ fd_set r, w, e;
+ FD_ZERO(&r); FD_ZERO(&w); FD_ZERO(&e);
+ FD_SET(nlc->s, &r);
+ FD_SET(nlc->s, &w);
+ FD_SET(nlc->s, &e);
+ if ((rc = select(0, &r, &w, &e, &tv)) == SOCKET_ERROR)
+ break;
+
+ if (rc > 0)
+ {
+ if (FD_ISSET(nlc->s, &w))
+ {
+ // connection was successful
+ rc = 0;
+ }
+ if (FD_ISSET(nlc->s, &r))
+ {
+ // connection was closed
+ rc = SOCKET_ERROR;
+ lasterr = WSAECONNRESET;
+ }
+ if (FD_ISSET(nlc->s, &e))
+ {
+ // connection failed.
+ int len = sizeof(lasterr);
+ rc = SOCKET_ERROR;
+ getsockopt(nlc->s, SOL_SOCKET, SO_ERROR, (char*)&lasterr, &len);
+ if (lasterr == WSAEADDRINUSE && ++retrycnt <= 2)
+ {
+ closesocket(nlc->s);
+ goto retry;
+ }
+ }
+ break;
+ }
+ else if (Miranda_Terminated())
+ {
+ rc = SOCKET_ERROR;
+ lasterr = ERROR_TIMEOUT;
+ break;
+ }
+ else if (nloc->cbSize == sizeof(NETLIBOPENCONNECTION) && nloc->flags & NLOCF_V2 &&
+ nloc->waitcallback != NULL && nloc->waitcallback(&dwTimeout) == 0)
+ {
+ rc = SOCKET_ERROR;
+ lasterr = ERROR_TIMEOUT;
+ break;
+ }
+ if (--dwTimeout == 0)
+ {
+ rc = SOCKET_ERROR;
+ lasterr = ERROR_TIMEOUT;
+ break;
+ }
+ }
+
+unblock:
+ notblocking = 0;
+ ioctlsocket(nlc->s, FIONBIO, &notblocking);
+ if (lasterr) SetLastError(lasterr);
+ return rc == 0;
+}
+
+static bool my_connectIPv6(NetlibConnection *nlc, NETLIBOPENCONNECTION * nloc)
+{
+ int rc = SOCKET_ERROR, retrycnt = 0;
+ u_long notblocking = 1;
+ DWORD lasterr = 0;
+ static const TIMEVAL tv = { 1, 0 };
+
+ unsigned int dwTimeout = (nloc->cbSize == sizeof(NETLIBOPENCONNECTION) && nloc->flags & NLOCF_V2) ? nloc->timeout : 0;
+ // if dwTimeout is zero then its an old style connection or new with a 0 timeout, select() will error quicker anyway
+ if (dwTimeout == 0) dwTimeout = 30;
+
+ // this is for XP SP2 where there is a default connection attempt limit of 10/second
+ if (connectionTimeout)
+ {
+ WaitForSingleObject(hConnectionOpenMutex, 10000);
+ int waitdiff = GetTickCount() - g_LastConnectionTick;
+ if (waitdiff < connectionTimeout) SleepEx(connectionTimeout, TRUE);
+ g_LastConnectionTick = GetTickCount();
+ ReleaseMutex(hConnectionOpenMutex);
+
+ // might of died in between the wait
+ if (Miranda_Terminated()) return false;
+ }
+
+ char szPort[6];
+ addrinfo *air = NULL, *ai, hints = {0};
+
+ hints.ai_family = AF_UNSPEC;
+
+ if (nloc->flags & NLOCF_UDP)
+ {
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = IPPROTO_UDP;
+ }
+ else
+ {
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+ }
+
+ if (nlc->proxyType)
+ {
+ if (!nlc->szProxyServer) return false;
+
+ if (nloc)
+ NetlibLogf(nlc->nlu,"(%p) Connecting to proxy %s:%d for %s:%d ....", nlc, nlc->szProxyServer, nlc->wProxyPort, nloc->szHost, nloc->wPort);
+ else
+ NetlibLogf(nlc->nlu,"(%p) Connecting to proxy %s:%d ....", nlc, nlc->szProxyServer, nlc->wProxyPort);
+
+ _itoa(nlc->wProxyPort, szPort, 10);
+ if (MyGetaddrinfo(nlc->szProxyServer, szPort, &hints, &air))
+ {
+ NetlibLogf(nlc->nlu,"%s %d: %s() for host %s failed (%u)",__FILE__,__LINE__,"getaddrinfo", nlc->szProxyServer, WSAGetLastError());
+ return false;
+ }
+ }
+ else
+ {
+ if (!nloc || !nloc->szHost) return false;
+ NetlibLogf(nlc->nlu,"(%p) Connecting to server %s:%d....", nlc, nloc->szHost, nloc->wPort);
+
+ _itoa(nlc->nloc.wPort, szPort, 10);
+
+ if (MyGetaddrinfo(nlc->nloc.szHost, szPort, &hints, &air))
+ {
+ NetlibLogf(nlc->nlu,"%s %d: %s() for host %s failed (%u)",__FILE__,__LINE__,"getaddrinfo", nlc->nloc.szHost, WSAGetLastError());
+ return false;
+ }
+ }
+
+ for (ai = air; ai && !Miranda_Terminated(); ai = ai->ai_next)
+ {
+retry:
+ nlc->s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+ if (nlc->s == INVALID_SOCKET) return false;
+
+ // return the socket to non blocking
+ if (ioctlsocket(nlc->s, FIONBIO, &notblocking) != 0) return false;
+
+ if (nlc->nlu->settings.specifyOutgoingPorts && nlc->nlu->settings.szOutgoingPorts && nlc->nlu->settings.szOutgoingPorts[0])
+ {
+ if (!BindSocketToPort(nlc->nlu->settings.szOutgoingPorts, nlc->s, &nlc->nlu->inportnum))
+ NetlibLogf(nlc->nlu,"Netlib connect: Not enough ports for outgoing connections specified");
+ }
+
+ // try a connect
+ if (connect(nlc->s, ai->ai_addr, (int)ai->ai_addrlen) == 0)
+ {
+ rc = 0;
+ break;
+ }
+
+ // didn't work, was it cos of nonblocking?
+ if (WSAGetLastError() != WSAEWOULDBLOCK)
+ {
+ rc = SOCKET_ERROR;
+ break;
+ }
+
+ for (;;) // timeout loop
+ {
+ fd_set r, w, e;
+ FD_ZERO(&r); FD_ZERO(&w); FD_ZERO(&e);
+ FD_SET(nlc->s, &r);
+ FD_SET(nlc->s, &w);
+ FD_SET(nlc->s, &e);
+ if ((rc = select(0, &r, &w, &e, &tv)) == SOCKET_ERROR)
+ break;
+
+ if (rc > 0)
+ {
+ if (FD_ISSET(nlc->s, &w))
+ {
+ // connection was successful
+ rc = 0;
+ lasterr = 0;
+ }
+ if (FD_ISSET(nlc->s, &r))
+ {
+ // connection was closed
+ rc = SOCKET_ERROR;
+ lasterr = WSAECONNRESET;
+ }
+ if (FD_ISSET(nlc->s, &e))
+ {
+ // connection failed.
+ int len = sizeof(lasterr);
+ rc = SOCKET_ERROR;
+ getsockopt(nlc->s, SOL_SOCKET, SO_ERROR, (char*)&lasterr, &len);
+ if (lasterr == WSAEADDRINUSE && ++retrycnt <= 2)
+ {
+ closesocket(nlc->s);
+ nlc->s = INVALID_SOCKET;
+ goto retry;
+ }
+ }
+ break;
+ }
+ else if (Miranda_Terminated())
+ {
+ rc = SOCKET_ERROR;
+ lasterr = ERROR_TIMEOUT;
+ break;
+ }
+ else if (nloc->cbSize == sizeof(NETLIBOPENCONNECTION) && nloc->flags & NLOCF_V2 &&
+ nloc->waitcallback != NULL && nloc->waitcallback(&dwTimeout) == 0)
+ {
+ rc = SOCKET_ERROR;
+ lasterr = ERROR_TIMEOUT;
+ break;
+ }
+ if (--dwTimeout == 0)
+ {
+ rc = SOCKET_ERROR;
+ lasterr = ERROR_TIMEOUT;
+ break;
+ }
+ }
+
+ if (rc == 0) break;
+
+ closesocket(nlc->s);
+ nlc->s = INVALID_SOCKET;
+ }
+
+ MyFreeaddrinfo(air);
+
+ notblocking = 0;
+ if (nlc->s != INVALID_SOCKET) ioctlsocket(nlc->s, FIONBIO, &notblocking);
+ if (rc && lasterr) SetLastError(lasterr);
+ return rc == 0;
+}
+
+static bool my_connect(NetlibConnection *nlc, NETLIBOPENCONNECTION * nloc)
+{
+ return MyGetaddrinfo && MyFreeaddrinfo ? my_connectIPv6(nlc, nloc) : my_connectIPv4(nlc, nloc);
+}
+
+static int NetlibHttpFallbackToDirect(struct NetlibConnection *nlc, struct NetlibUser *nlu, NETLIBOPENCONNECTION *nloc)
+{
+ NetlibDoClose(nlc, true);
+
+ NetlibLogf(nlu,"Fallback to direct connection");
+
+ nlc->proxyAuthNeeded = false;
+ nlc->proxyType = 0;
+ mir_free(nlc->szProxyServer); nlc->szProxyServer = NULL;
+ if (!my_connect(nlc, nloc))
+ {
+ NetlibLogf(nlu, "%s %d: %s() failed (%u)", __FILE__, __LINE__, "connect", WSAGetLastError());
+ return false;
+ }
+ return true;
+}
+
+bool NetlibDoConnect(NetlibConnection *nlc)
+{
+ NETLIBOPENCONNECTION *nloc = &nlc->nloc;
+ NetlibUser *nlu = nlc->nlu;
+
+ mir_free(nlc->szProxyServer); nlc->szProxyServer = NULL;
+
+ bool usingProxy = false, forceHttps = false;
+ if (nlu->settings.useProxy)
+ {
+ if (nlu->settings.proxyType == PROXYTYPE_IE)
+ {
+ usingProxy = NetlibGetIeProxyConn(nlc, false);
+ }
+ else
+ {
+ if (nlu->settings.szProxyServer && nlu->settings.szProxyServer[0])
+ {
+ nlc->szProxyServer = mir_strdup(nlu->settings.szProxyServer);
+ nlc->wProxyPort = nlu->settings.wProxyPort;
+ nlc->proxyType = nlu->settings.proxyType;
+ usingProxy = true;
+ }
+ }
+ }
+
+retry:
+ if (usingProxy)
+ {
+ if (!my_connect(nlc, nloc))
+ {
+ usingProxy = false;
+ nlc->proxyType = 0;
+ }
+ }
+ if (!usingProxy)
+ {
+ my_connect(nlc, nloc);
+ }
+
+ if (nlc->s == INVALID_SOCKET)
+ {
+ if (usingProxy && (nlc->proxyType == PROXYTYPE_HTTPS || nlc->proxyType == PROXYTYPE_HTTP))
+ {
+ usingProxy = false;
+ if (!NetlibHttpFallbackToDirect(nlc, nlu, nloc))
+ {
+ NetlibLogf(nlu, "%s %d: %s() failed (%u)", __FILE__, __LINE__, "connect", WSAGetLastError());
+ return false;
+ }
+ }
+ else
+ {
+ if (nlu->settings.useProxy && !usingProxy && nlu->settings.proxyType == PROXYTYPE_IE && !forceHttps)
+ {
+ forceHttps = true;
+ usingProxy = NetlibGetIeProxyConn(nlc, true);
+ if (usingProxy) goto retry;
+ }
+ NetlibLogf(nlu, "%s %d: %s() failed (%u)", __FILE__, __LINE__, "connect", WSAGetLastError());
+ return false;
+ }
+ }
+
+ if (usingProxy && !((nloc->flags & (NLOCF_HTTP | NLOCF_SSL)) == NLOCF_HTTP &&
+ (nlc->proxyType == PROXYTYPE_HTTP || nlc->proxyType == PROXYTYPE_HTTPS)))
+ {
+ if (!WaitUntilWritable(nlc->s, 30000)) return false;
+
+ switch (nlc->proxyType)
+ {
+ case PROXYTYPE_SOCKS4:
+ if (!NetlibInitSocks4Connection(nlc, nlu, nloc)) return false;
+ break;
+
+ case PROXYTYPE_SOCKS5:
+ if (!NetlibInitSocks5Connection(nlc, nlu, nloc)) return false;
+ break;
+
+ case PROXYTYPE_HTTPS:
+ nlc->proxyAuthNeeded = true;
+ if (!NetlibInitHttpsConnection(nlc, nlu, nloc))
+ {
+ usingProxy = false;
+ if (!NetlibHttpFallbackToDirect(nlc, nlu, nloc))
+ return false;
+ }
+ break;
+
+ case PROXYTYPE_HTTP:
+ nlc->proxyAuthNeeded = true;
+ if (!(nlu->user.flags & NUF_HTTPGATEWAY || nloc->flags & NLOCF_HTTPGATEWAY) || nloc->flags & NLOCF_SSL)
+ {
+ //NLOCF_HTTP not specified and no HTTP gateway available: try HTTPS
+ if (!NetlibInitHttpsConnection(nlc, nlu, nloc))
+ {
+ //can't do HTTPS: try direct
+ usingProxy = false;
+ if (!NetlibHttpFallbackToDirect(nlc, nlu, nloc))
+ return false;
+ }
+ }
+ else
+ {
+ if (!NetlibInitHttpConnection(nlc, nlu, nloc)) return false;
+ }
+ break;
+
+ default:
+ SetLastError(ERROR_INVALID_PARAMETER);
+ FreePartiallyInitedConnection(nlc);
+ return false;
+ }
+ }
+ else if (nloc->flags & NLOCF_HTTPGATEWAY)
+ {
+ if (!NetlibInitHttpConnection(nlc, nlu, nloc)) return false;
+ nlc->usingDirectHttpGateway = true;
+ }
+
+ NetlibLogf(nlu,"(%d) Connected to %s:%d", nlc->s, nloc->szHost, nloc->wPort);
+
+ if (NLOCF_SSL & nloc->flags)
+ {
+ return NetlibStartSsl((WPARAM)nlc, 0) != 0;
+ }
+
+ return true;
+}
+
+bool NetlibReconnect(NetlibConnection *nlc)
+{
+ char buf[4];
+ bool opened = nlc->s != INVALID_SOCKET;
+
+ if (opened)
+ {
+ switch (WaitUntilReadable(nlc->s, 0, true))
+ {
+ case SOCKET_ERROR:
+ opened = false;
+ break;
+
+ case 0:
+ opened = true;
+ break;
+
+ case 1:
+ opened = recv(nlc->s, buf, 1, MSG_PEEK) > 0;
+ break;
+ }
+
+ if (!opened)
+ NetlibDoClose(nlc, true);
+ }
+
+ if (!opened)
+ {
+ if (Miranda_Terminated()) return false;
+ if (nlc->usingHttpGateway)
+ {
+ nlc->proxyAuthNeeded = true;
+ return my_connect(nlc, &nlc->nloc);
+ }
+ else
+ return NetlibDoConnect(nlc);
+ }
+ return true;
+}
+
+INT_PTR NetlibOpenConnection(WPARAM wParam,LPARAM lParam)
+{
+ NETLIBOPENCONNECTION *nloc = (NETLIBOPENCONNECTION*)lParam;
+ struct NetlibUser *nlu = (struct NetlibUser*)wParam;
+ struct NetlibConnection *nlc;
+
+ NetlibLogf(nlu,"Connection request to %s:%d (Flags %x)....", nloc->szHost, nloc->wPort, nloc->flags);
+
+ if (GetNetlibHandleType(nlu) != NLH_USER || !(nlu->user.flags & NUF_OUTGOING) || nloc == NULL ||
+ (nloc->cbSize != NETLIBOPENCONNECTION_V1_SIZE && nloc->cbSize != sizeof(NETLIBOPENCONNECTION)) ||
+ nloc->szHost == NULL || nloc->wPort == 0)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ nlc = (struct NetlibConnection*)mir_calloc(sizeof(struct NetlibConnection));
+ nlc->handleType = NLH_CONNECTION;
+ nlc->nlu = nlu;
+ nlc->nloc = *nloc;
+ nlc->nloc.szHost = mir_strdup(nloc->szHost);
+ nlc->s = INVALID_SOCKET;
+ nlc->s2 = INVALID_SOCKET;
+ nlc->dnsThroughProxy = nlu->settings.dnsThroughProxy != 0;
+
+ InitializeCriticalSection(&nlc->csHttpSequenceNums);
+ nlc->hOkToCloseEvent = CreateEvent(NULL,TRUE,TRUE,NULL);
+ nlc->dontCloseNow = 0;
+ NetlibInitializeNestedCS(&nlc->ncsSend);
+ NetlibInitializeNestedCS(&nlc->ncsRecv);
+
+ if (!NetlibDoConnect(nlc))
+ {
+ FreePartiallyInitedConnection(nlc);
+ return 0;
+ }
+
+ if (iUPnPCleanup == 0)
+ {
+ EnterCriticalSection(&csNetlibUser);
+ if (iUPnPCleanup == 0)
+ {
+ iUPnPCleanup = 1;
+ forkthread(NetlibUPnPCleanup, 0, NULL);
+ }
+ LeaveCriticalSection(&csNetlibUser);
+ }
+
+ return (INT_PTR)nlc;
+}
+
+INT_PTR NetlibStartSsl(WPARAM wParam, LPARAM lParam)
+{
+ NetlibConnection *nlc = (NetlibConnection*)wParam;
+ if (nlc == NULL) return 0;
+
+ NETLIBSSL *sp = (NETLIBSSL*)lParam;
+ const char *szHost = sp ? sp->host : nlc->nloc.szHost;
+
+ NetlibLogf(nlc->nlu, "(%d %s) Starting SSL negotiation", nlc->s, szHost);
+ nlc->hSsl = si.connect(nlc->s, szHost, nlc->nlu->settings.validateSSL);
+
+ if (nlc->hSsl == NULL)
+ NetlibLogf(nlc->nlu,"(%d %s) Failure to negotiate SSL connection", nlc->s, szHost);
+ else
+ NetlibLogf(nlc->nlu, "(%d %s) SSL negotiation successful", nlc->s, szHost);
+
+ return nlc->hSsl != NULL;
+}
diff --git a/src/modules/netlib/netlibopts.cpp b/src/modules/netlib/netlibopts.cpp
new file mode 100644
index 0000000000..0c562a5cff
--- /dev/null
+++ b/src/modules/netlib/netlibopts.cpp
@@ -0,0 +1,556 @@
+/*
+
+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 "netlib.h"
+
+struct NetlibTempSettings
+{
+ DWORD flags;
+ char *szSettingsModule;
+ NETLIBUSERSETTINGS settings;
+};
+
+static LIST <NetlibTempSettings> tempSettings(5);
+
+static const UINT outgoingConnectionsControls[] =
+{
+ IDC_STATIC12,
+ IDC_USEPROXY,
+ IDC_STATIC21,IDC_PROXYTYPE,
+ IDC_STATIC22,IDC_PROXYHOST,IDC_STATIC23,IDC_PROXYPORT,IDC_STOFTENPORT,
+ IDC_PROXYAUTH,
+ IDC_STATIC31,IDC_PROXYUSER,IDC_STATIC32,IDC_PROXYPASS,
+ IDC_PROXYDNS,
+ IDC_SPECIFYPORTSO,
+ IDC_PORTSRANGEO,
+ IDC_STATIC54,
+ IDC_VALIDATESSL};
+static const UINT useProxyControls[]={
+ IDC_STATIC21,IDC_PROXYTYPE,
+ IDC_STATIC22,IDC_PROXYHOST,IDC_STATIC23,IDC_PROXYPORT,IDC_STOFTENPORT,
+ IDC_PROXYAUTH,
+ IDC_STATIC31,IDC_PROXYUSER,IDC_STATIC32,IDC_PROXYPASS,
+ IDC_PROXYDNS};
+static const UINT specifyOPortsControls[]={
+ IDC_PORTSRANGEO,
+ IDC_STATIC54
+};
+static const UINT incomingConnectionsControls[]={
+ IDC_STATIC43,
+ IDC_SPECIFYPORTS,
+ IDC_PORTSRANGE,
+ IDC_STATIC52,
+ IDC_ENABLEUPNP};
+static const UINT specifyPortsControls[]={
+ IDC_PORTSRANGE,
+ IDC_STATIC52};
+
+static const TCHAR* szProxyTypes[]={_T("<mixed>"),_T("SOCKS4"),_T("SOCKS5"),_T("HTTP"),_T("HTTPS"),_T("Internet Explorer")};
+static const WORD oftenProxyPorts[]={1080,1080,1080,8080,8080,8080};
+
+#define M_REFRESHALL (WM_USER+100)
+#define M_REFRESHENABLING (WM_USER+101)
+
+static void ShowMultipleControls(HWND hwndDlg,const UINT *controls,int cControls,int state)
+{
+ int i;
+ for(i=0;i<cControls;i++) ShowWindow(GetDlgItem(hwndDlg,controls[i]),state);
+}
+
+static void EnableMultipleControls(HWND hwndDlg,const UINT *controls,int cControls,int state)
+{
+ int i;
+ for(i=0;i<cControls;i++) EnableWindow(GetDlgItem(hwndDlg,controls[i]),state);
+}
+
+static void AddProxyTypeItem(HWND hwndDlg,int type,int selectType)
+{
+ int i;
+ i = SendDlgItemMessage(hwndDlg,IDC_PROXYTYPE,CB_ADDSTRING,0,(LPARAM)(type==0?TranslateTS(szProxyTypes[type]):szProxyTypes[type]));
+ SendDlgItemMessage(hwndDlg, IDC_PROXYTYPE, CB_SETITEMDATA, i, type);
+ if (type == selectType) SendDlgItemMessage(hwndDlg, IDC_PROXYTYPE, CB_SETCURSEL, i, 0);
+}
+
+static void CopySettingsStruct(NETLIBUSERSETTINGS *dest,NETLIBUSERSETTINGS *source)
+{
+ *dest=*source;
+ if(dest->szIncomingPorts) dest->szIncomingPorts=mir_strdup(dest->szIncomingPorts);
+ if(dest->szOutgoingPorts) dest->szOutgoingPorts=mir_strdup(dest->szOutgoingPorts);
+ if(dest->szProxyAuthPassword) dest->szProxyAuthPassword=mir_strdup(dest->szProxyAuthPassword);
+ if(dest->szProxyAuthUser) dest->szProxyAuthUser=mir_strdup(dest->szProxyAuthUser);
+ if(dest->szProxyServer) dest->szProxyServer=mir_strdup(dest->szProxyServer);
+}
+
+static void CombineSettingsStrings(char **dest,char **source)
+{
+ if(*dest!=NULL && (*source==NULL || lstrcmpiA(*dest,*source))) {mir_free(*dest); *dest=NULL;}
+}
+
+static void CombineSettingsStructs(NETLIBUSERSETTINGS *dest,DWORD *destFlags,NETLIBUSERSETTINGS *source,DWORD sourceFlags)
+{
+ if(sourceFlags&NUF_OUTGOING) {
+ if(*destFlags&NUF_OUTGOING) {
+ if(dest->validateSSL!=source->validateSSL) dest->validateSSL=2;
+ if(dest->useProxy!=source->useProxy) dest->useProxy=2;
+ if(dest->proxyType!=source->proxyType) dest->proxyType=0;
+ CombineSettingsStrings(&dest->szProxyServer,&source->szProxyServer);
+ if(dest->wProxyPort!=source->wProxyPort) dest->wProxyPort=0;
+ if(dest->useProxyAuth!=source->useProxyAuth) dest->useProxyAuth=2;
+ CombineSettingsStrings(&dest->szProxyAuthUser,&source->szProxyAuthUser);
+ CombineSettingsStrings(&dest->szProxyAuthPassword,&source->szProxyAuthPassword);
+ if(dest->dnsThroughProxy!=source->dnsThroughProxy) dest->dnsThroughProxy=2;
+ if(dest->specifyOutgoingPorts!=source->specifyOutgoingPorts) dest->specifyOutgoingPorts=2;
+ CombineSettingsStrings(&dest->szOutgoingPorts,&source->szOutgoingPorts);
+ }
+ else {
+ dest->validateSSL=source->validateSSL;
+ dest->useProxy=source->useProxy;
+ dest->proxyType=source->proxyType;
+ dest->szProxyServer=source->szProxyServer;
+ if(dest->szProxyServer) dest->szProxyServer=mir_strdup(dest->szProxyServer);
+ dest->wProxyPort=source->wProxyPort;
+ dest->useProxyAuth=source->useProxyAuth;
+ dest->szProxyAuthUser=source->szProxyAuthUser;
+ if(dest->szProxyAuthUser) dest->szProxyAuthUser=mir_strdup(dest->szProxyAuthUser);
+ dest->szProxyAuthPassword=source->szProxyAuthPassword;
+ if(dest->szProxyAuthPassword) dest->szProxyAuthPassword=mir_strdup(dest->szProxyAuthPassword);
+ dest->dnsThroughProxy=source->dnsThroughProxy;
+ dest->specifyOutgoingPorts=source->specifyOutgoingPorts;
+ dest->szOutgoingPorts=source->szOutgoingPorts;
+ if (dest->szOutgoingPorts) dest->szOutgoingPorts=mir_strdup(dest->szOutgoingPorts);
+ }
+ }
+ if(sourceFlags&NUF_INCOMING) {
+ if(*destFlags&NUF_INCOMING) {
+ if(dest->enableUPnP!=source->enableUPnP) dest->enableUPnP=2;
+ if(dest->specifyIncomingPorts!=source->specifyIncomingPorts) dest->specifyIncomingPorts=2;
+ CombineSettingsStrings(&dest->szIncomingPorts,&source->szIncomingPorts);
+ }
+ else {
+ dest->enableUPnP=source->enableUPnP;
+ dest->specifyIncomingPorts=source->specifyIncomingPorts;
+ dest->szIncomingPorts=source->szIncomingPorts;
+ if(dest->szIncomingPorts) dest->szIncomingPorts=mir_strdup(dest->szIncomingPorts);
+ }
+ }
+ if((*destFlags&NUF_NOHTTPSOPTION)!=(sourceFlags&NUF_NOHTTPSOPTION))
+ *destFlags=(*destFlags|sourceFlags)&~NUF_NOHTTPSOPTION;
+ else *destFlags|=sourceFlags;
+}
+
+static void ChangeSettingIntByCheckbox(HWND hwndDlg,UINT ctrlId,int iUser,int memberOffset)
+{
+ int newValue,i;
+
+ newValue=IsDlgButtonChecked(hwndDlg,ctrlId)!=BST_CHECKED;
+ CheckDlgButton(hwndDlg,ctrlId,newValue?BST_CHECKED:BST_UNCHECKED);
+ if (iUser == -1)
+ {
+ for (i=0; i<tempSettings.getCount(); i++)
+ if (!(tempSettings[i]->flags & NUF_NOOPTIONS))
+ *(int*)(((PBYTE)&tempSettings[i]->settings) + memberOffset) = newValue;
+ }
+ else *(int*)(((PBYTE)&tempSettings[iUser]->settings) + memberOffset)=newValue;
+ SendMessage(hwndDlg,M_REFRESHENABLING,0,0);
+}
+
+static void ChangeSettingStringByEdit(HWND hwndDlg,UINT ctrlId,int iUser,int memberOffset)
+{
+ int i,newValueLen;
+ char *szNewValue,**ppszNew;
+
+ newValueLen=GetWindowTextLength(GetDlgItem(hwndDlg,ctrlId));
+ szNewValue=(char*)mir_alloc(newValueLen+1);
+ GetDlgItemTextA(hwndDlg,ctrlId,szNewValue,newValueLen+1);
+ if (iUser == -1)
+ {
+ for (i=0; i<tempSettings.getCount(); ++i)
+ if (!(tempSettings[i]->flags & NUF_NOOPTIONS))
+ {
+ ppszNew=(char**)(((PBYTE)&tempSettings[i]->settings)+memberOffset);
+ if(*ppszNew) mir_free(*ppszNew);
+ *ppszNew=mir_strdup(szNewValue);
+ }
+ mir_free(szNewValue);
+ }
+ else {
+ ppszNew=(char**)(((PBYTE)&tempSettings[iUser]->settings)+memberOffset);
+ if(*ppszNew) mir_free(*ppszNew);
+ *ppszNew=szNewValue;
+ }
+}
+
+static void WriteSettingsStructToDb(const char *szSettingsModule,NETLIBUSERSETTINGS *settings,DWORD flags)
+{
+ if(flags&NUF_OUTGOING) {
+ char szEncodedPassword[512];
+ DBWriteContactSettingByte(NULL,szSettingsModule,"NLValidateSSL",(BYTE)settings->validateSSL);
+ DBWriteContactSettingByte(NULL,szSettingsModule,"NLUseProxy",(BYTE)settings->useProxy);
+ DBWriteContactSettingByte(NULL,szSettingsModule,"NLProxyType",(BYTE)settings->proxyType);
+ DBWriteContactSettingString(NULL,szSettingsModule,"NLProxyServer",settings->szProxyServer?settings->szProxyServer:"");
+ DBWriteContactSettingWord(NULL,szSettingsModule,"NLProxyPort",(WORD)settings->wProxyPort);
+ DBWriteContactSettingByte(NULL,szSettingsModule,"NLUseProxyAuth",(BYTE)settings->useProxyAuth);
+ DBWriteContactSettingString(NULL,szSettingsModule,"NLProxyAuthUser",settings->szProxyAuthUser?settings->szProxyAuthUser:"");
+ lstrcpynA(szEncodedPassword,settings->szProxyAuthPassword?settings->szProxyAuthPassword:"",SIZEOF(szEncodedPassword));
+ CallService(MS_DB_CRYPT_ENCODESTRING,SIZEOF(szEncodedPassword),(LPARAM)szEncodedPassword);
+ DBWriteContactSettingString(NULL,szSettingsModule,"NLProxyAuthPassword",szEncodedPassword);
+ DBWriteContactSettingByte(NULL,szSettingsModule,"NLDnsThroughProxy",(BYTE)settings->dnsThroughProxy);
+ DBWriteContactSettingByte(NULL,szSettingsModule,"NLSpecifyOutgoingPorts",(BYTE)settings->specifyOutgoingPorts);
+ DBWriteContactSettingString(NULL,szSettingsModule,"NLOutgoingPorts",settings->szOutgoingPorts?settings->szOutgoingPorts:"");
+ }
+ if(flags&NUF_INCOMING) {
+ DBWriteContactSettingByte(NULL,szSettingsModule,"NLEnableUPnP",(BYTE)settings->enableUPnP);
+ DBWriteContactSettingByte(NULL,szSettingsModule,"NLSpecifyIncomingPorts",(BYTE)settings->specifyIncomingPorts);
+ DBWriteContactSettingString(NULL,szSettingsModule,"NLIncomingPorts",settings->szIncomingPorts?settings->szIncomingPorts:"");
+ }
+}
+
+void NetlibSaveUserSettingsStruct(const char *szSettingsModule,NETLIBUSERSETTINGS *settings)
+{
+ int i;
+ NETLIBUSERSETTINGS combinedSettings={0};
+ DWORD flags;
+
+ EnterCriticalSection(&csNetlibUser);
+
+ NetlibUser *thisUser, tUser;
+ tUser.user.szSettingsModule = (char*)szSettingsModule;
+ thisUser = netlibUser.find(&tUser);
+
+ if (thisUser == NULL)
+ {
+ LeaveCriticalSection(&csNetlibUser);
+ return;
+ }
+
+ NetlibFreeUserSettingsStruct(&thisUser->settings);
+ CopySettingsStruct(&thisUser->settings, settings);
+ WriteSettingsStructToDb(thisUser->user.szSettingsModule, &thisUser->settings, thisUser->user.flags);
+ combinedSettings.cbSize = sizeof(combinedSettings);
+ for (i=0, flags=0; i < netlibUser.getCount(); ++i)
+ {
+ if (thisUser->user.flags & NUF_NOOPTIONS) continue;
+ CombineSettingsStructs(&combinedSettings, &flags, &thisUser->settings, thisUser->user.flags);
+ }
+ if(combinedSettings.validateSSL==2) combinedSettings.validateSSL=0;
+ if(combinedSettings.useProxy==2) combinedSettings.useProxy=0;
+ if(combinedSettings.proxyType==0) combinedSettings.proxyType=PROXYTYPE_SOCKS5;
+ if(combinedSettings.useProxyAuth==2) combinedSettings.useProxyAuth=0;
+ if(combinedSettings.dnsThroughProxy==2) combinedSettings.dnsThroughProxy=1;
+ if(combinedSettings.enableUPnP==2) combinedSettings.enableUPnP=1;
+ if(combinedSettings.specifyIncomingPorts==2) combinedSettings.specifyIncomingPorts=0;
+ WriteSettingsStructToDb("Netlib",&combinedSettings,flags);
+ NetlibFreeUserSettingsStruct(&combinedSettings);
+ LeaveCriticalSection(&csNetlibUser);
+}
+
+static INT_PTR CALLBACK DlgProcNetlibOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ { int iUser,iItem;
+
+ TranslateDialogDefault(hwndDlg);
+ iItem=SendDlgItemMessage(hwndDlg,IDC_NETLIBUSERS,CB_ADDSTRING,0,(LPARAM)TranslateT("<All connections>"));
+ SendDlgItemMessage(hwndDlg,IDC_NETLIBUSERS,CB_SETITEMDATA,iItem,(LPARAM)-1);
+ SendDlgItemMessage(hwndDlg,IDC_NETLIBUSERS,CB_SETCURSEL,iItem,0);
+
+ EnterCriticalSection(&csNetlibUser);
+ for (iUser = 0; iUser < netlibUser.getCount(); ++iUser)
+ {
+ NetlibTempSettings *thisSettings = (NetlibTempSettings*)mir_calloc(sizeof(NetlibTempSettings));
+ thisSettings->flags = netlibUser[iUser]->user.flags;
+ thisSettings->szSettingsModule = mir_strdup(netlibUser[iUser]->user.szSettingsModule);
+ CopySettingsStruct(&thisSettings->settings, &netlibUser[iUser]->settings);
+ tempSettings.insert(thisSettings);
+
+ if (netlibUser[iUser]->user.flags & NUF_NOOPTIONS) continue;
+ iItem = SendDlgItemMessage(hwndDlg, IDC_NETLIBUSERS, CB_ADDSTRING, 0,
+ (LPARAM)netlibUser[iUser]->user.ptszDescriptiveName);
+ SendDlgItemMessage(hwndDlg, IDC_NETLIBUSERS,CB_SETITEMDATA, iItem, iUser);
+ }
+ LeaveCriticalSection(&csNetlibUser);
+
+ SendMessage(hwndDlg,M_REFRESHALL,0,0);
+ return TRUE;
+ }
+ case M_REFRESHALL:
+ { int iUser=SendDlgItemMessage(hwndDlg,IDC_NETLIBUSERS,CB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_NETLIBUSERS,CB_GETCURSEL,0,0),0);
+ NETLIBUSERSETTINGS settings = {0};
+ DWORD flags;
+
+ if (iUser == -1)
+ {
+ int i;
+ settings.cbSize=sizeof(settings);
+ for (i = 0, flags = 0; i < tempSettings.getCount(); ++i)
+ {
+ if (tempSettings[i]->flags & NUF_NOOPTIONS) continue;
+ CombineSettingsStructs(&settings, &flags, &tempSettings[i]->settings, tempSettings[i]->flags);
+ }
+ }
+ else
+ {
+ NetlibFreeUserSettingsStruct(&settings);
+ CopySettingsStruct(&settings, &tempSettings[iUser]->settings);
+ flags = tempSettings[iUser]->flags;
+ }
+ ShowMultipleControls(hwndDlg,outgoingConnectionsControls,SIZEOF(outgoingConnectionsControls),flags&NUF_OUTGOING?SW_SHOW:SW_HIDE);
+ CheckDlgButton(hwndDlg,IDC_USEPROXY,settings.useProxy);
+ SendDlgItemMessage(hwndDlg,IDC_PROXYTYPE,CB_RESETCONTENT,0,0);
+ if (settings.proxyType == 0) AddProxyTypeItem(hwndDlg,0,settings.proxyType);
+ AddProxyTypeItem(hwndDlg, PROXYTYPE_SOCKS4, settings.proxyType);
+ AddProxyTypeItem(hwndDlg, PROXYTYPE_SOCKS5, settings.proxyType);
+ if (flags & (NUF_HTTPCONNS | NUF_HTTPGATEWAY)) AddProxyTypeItem(hwndDlg,PROXYTYPE_HTTP,settings.proxyType);
+ if (!(flags & NUF_NOHTTPSOPTION)) AddProxyTypeItem(hwndDlg,PROXYTYPE_HTTPS,settings.proxyType);
+ if (flags & (NUF_HTTPCONNS | NUF_HTTPGATEWAY) || !(flags & NUF_NOHTTPSOPTION))
+ AddProxyTypeItem(hwndDlg,PROXYTYPE_IE,settings.proxyType);
+ SetDlgItemTextA(hwndDlg,IDC_PROXYHOST,settings.szProxyServer?settings.szProxyServer:"");
+ if (settings.wProxyPort) SetDlgItemInt(hwndDlg,IDC_PROXYPORT,settings.wProxyPort,FALSE);
+ else SetDlgItemTextA(hwndDlg,IDC_PROXYPORT,"");
+ CheckDlgButton(hwndDlg,IDC_PROXYAUTH,settings.useProxyAuth);
+ SetDlgItemTextA(hwndDlg,IDC_PROXYUSER,settings.szProxyAuthUser?settings.szProxyAuthUser:"");
+ SetDlgItemTextA(hwndDlg,IDC_PROXYPASS,settings.szProxyAuthPassword?settings.szProxyAuthPassword:"");
+ CheckDlgButton(hwndDlg,IDC_PROXYDNS,settings.dnsThroughProxy);
+ CheckDlgButton(hwndDlg,IDC_VALIDATESSL,settings.validateSSL);
+
+ ShowMultipleControls(hwndDlg,incomingConnectionsControls,SIZEOF(incomingConnectionsControls),flags&NUF_INCOMING?SW_SHOW:SW_HIDE);
+ CheckDlgButton(hwndDlg,IDC_SPECIFYPORTS,settings.specifyIncomingPorts);
+ SetDlgItemTextA(hwndDlg,IDC_PORTSRANGE,settings.szIncomingPorts?settings.szIncomingPorts:"");
+
+ CheckDlgButton(hwndDlg,IDC_SPECIFYPORTSO,settings.specifyOutgoingPorts);
+ SetDlgItemTextA(hwndDlg,IDC_PORTSRANGEO,settings.szOutgoingPorts?settings.szOutgoingPorts:"");
+
+ CheckDlgButton(hwndDlg,IDC_ENABLEUPNP,settings.enableUPnP);
+
+ NetlibFreeUserSettingsStruct(&settings);
+ SendMessage(hwndDlg,M_REFRESHENABLING,0,0);
+ break;
+ }
+ case M_REFRESHENABLING:
+ { int selectedProxyType;
+ TCHAR str[80];
+
+ selectedProxyType=SendDlgItemMessage(hwndDlg,IDC_PROXYTYPE,CB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_PROXYTYPE,CB_GETCURSEL,0,0),0);
+ mir_sntprintf(str, SIZEOF(str), TranslateT("(often %d)"),oftenProxyPorts[selectedProxyType]);
+ SetDlgItemText(hwndDlg,IDC_STOFTENPORT,str);
+ if (IsDlgButtonChecked(hwndDlg,IDC_USEPROXY) != BST_UNCHECKED)
+ {
+ int enableAuth = 0, enableUser = 0, enablePass = 0, enableServer = 1;
+ EnableMultipleControls(hwndDlg, useProxyControls, SIZEOF(useProxyControls), TRUE);
+ if (selectedProxyType == 0)
+ {
+ int i;
+ for (i = 0; i < tempSettings.getCount(); ++i)
+ {
+ if (!tempSettings[i]->settings.useProxy ||
+ tempSettings[i]->flags & NUF_NOOPTIONS || !(tempSettings[i]->flags & NUF_OUTGOING))
+ continue;
+
+ if (tempSettings[i]->settings.proxyType==PROXYTYPE_SOCKS4) enableUser=1;
+ else
+ {
+ enableAuth=1;
+ if (tempSettings[i]->settings.useProxyAuth)
+ {
+ enableUser=enablePass=1;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (selectedProxyType == PROXYTYPE_SOCKS4) enableUser=1;
+ else
+ {
+ if (selectedProxyType == PROXYTYPE_IE) enableServer=0;
+ enableAuth=1;
+ if (IsDlgButtonChecked(hwndDlg,IDC_PROXYAUTH) != BST_UNCHECKED)
+ enableUser = enablePass = 1;
+ }
+ }
+ EnableWindow(GetDlgItem(hwndDlg,IDC_PROXYAUTH), enableAuth);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_STATIC31), enableUser);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_PROXYUSER), enableUser);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_STATIC32), enablePass);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_PROXYPASS), enablePass);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_PROXYHOST), enableServer);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_PROXYPORT), enableServer);
+ }
+ else EnableMultipleControls(hwndDlg,useProxyControls,SIZEOF(useProxyControls),FALSE);
+ EnableMultipleControls(hwndDlg,specifyPortsControls,SIZEOF(specifyPortsControls),IsDlgButtonChecked(hwndDlg,IDC_SPECIFYPORTS)!=BST_UNCHECKED);
+ EnableMultipleControls(hwndDlg,specifyOPortsControls,SIZEOF(specifyOPortsControls),IsDlgButtonChecked(hwndDlg,IDC_SPECIFYPORTSO)!=BST_UNCHECKED);
+ break;
+ }
+ case WM_COMMAND:
+ { int iUser=SendDlgItemMessage(hwndDlg,IDC_NETLIBUSERS,CB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_NETLIBUSERS,CB_GETCURSEL,0,0),0);
+ switch(LOWORD(wParam))
+ {
+ case IDC_NETLIBUSERS:
+ if(HIWORD(wParam)==CBN_SELCHANGE) SendMessage(hwndDlg,M_REFRESHALL,0,0);
+ return 0;
+
+ case IDC_LOGOPTIONS:
+ NetlibLogShowOptions();
+ return 0;
+
+ case IDC_PROXYTYPE:
+ if (HIWORD(wParam) != CBN_SELCHANGE) return 0;
+ { int newValue,i;
+ newValue = SendDlgItemMessage(hwndDlg,IDC_PROXYTYPE,CB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_PROXYTYPE,CB_GETCURSEL,0,0),0);
+ if (iUser == -1)
+ {
+ if (newValue == 0) return 0;
+ for (i = 0; i < tempSettings.getCount(); ++i)
+ {
+ if (tempSettings[i]->flags & NUF_NOOPTIONS) continue;
+ if (newValue == PROXYTYPE_HTTP && !(tempSettings[i]->flags & (NUF_HTTPCONNS|NUF_HTTPGATEWAY)))
+ tempSettings[i]->settings.proxyType = PROXYTYPE_HTTPS;
+ else if (newValue == PROXYTYPE_HTTPS && tempSettings[i]->flags & NUF_NOHTTPSOPTION)
+ tempSettings[i]->settings.proxyType = PROXYTYPE_HTTP;
+ else tempSettings[i]->settings.proxyType = newValue;
+ }
+ SendMessage(hwndDlg, M_REFRESHALL, 0, 0);
+ }
+ else
+ {
+ tempSettings[iUser]->settings.proxyType = newValue;
+ SendMessage(hwndDlg,M_REFRESHENABLING,0,0);
+ }
+ }
+ break;
+ case IDC_USEPROXY:
+ ChangeSettingIntByCheckbox(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,useProxy));
+ break;
+ case IDC_PROXYAUTH:
+ ChangeSettingIntByCheckbox(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,useProxyAuth));
+ break;
+ case IDC_PROXYDNS:
+ ChangeSettingIntByCheckbox(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,dnsThroughProxy));
+ break;
+ case IDC_SPECIFYPORTS:
+ ChangeSettingIntByCheckbox(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,specifyIncomingPorts));
+ break;
+ case IDC_SPECIFYPORTSO:
+ ChangeSettingIntByCheckbox(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,specifyOutgoingPorts));
+ break;
+ case IDC_ENABLEUPNP:
+ ChangeSettingIntByCheckbox(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,enableUPnP));
+ break;
+ case IDC_VALIDATESSL:
+ ChangeSettingIntByCheckbox(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,validateSSL));
+ break;
+ case IDC_PROXYHOST:
+ if(HIWORD(wParam)!=EN_CHANGE || (HWND)lParam!=GetFocus()) return 0;
+ ChangeSettingStringByEdit(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,szProxyServer));
+ break;
+ case IDC_PROXYPORT:
+ if(HIWORD(wParam)!=EN_CHANGE || (HWND)lParam!=GetFocus()) return 0;
+ { int newValue,i;
+ newValue=GetDlgItemInt(hwndDlg,LOWORD(wParam),NULL,FALSE);
+ if (iUser == -1)
+ {
+ for (i = 0; i < tempSettings.getCount(); ++i)
+ if (!(tempSettings[i]->flags & NUF_NOOPTIONS))
+ tempSettings[i]->settings.wProxyPort = newValue;
+ }
+ else tempSettings[iUser]->settings.wProxyPort = newValue;
+ }
+ break;
+ case IDC_PROXYUSER:
+ if(HIWORD(wParam)!=EN_CHANGE || (HWND)lParam!=GetFocus()) return 0;
+ ChangeSettingStringByEdit(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,szProxyAuthUser));
+ break;
+ case IDC_PROXYPASS:
+ if(HIWORD(wParam)!=EN_CHANGE || (HWND)lParam!=GetFocus()) return 0;
+ ChangeSettingStringByEdit(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,szProxyAuthPassword));
+ break;
+ case IDC_PORTSRANGE:
+ if(HIWORD(wParam)!=EN_CHANGE || (HWND)lParam!=GetFocus()) return 0;
+ ChangeSettingStringByEdit(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,szIncomingPorts));
+ break;
+ case IDC_PORTSRANGEO:
+ if(HIWORD(wParam)!=EN_CHANGE || (HWND)lParam!=GetFocus()) return 0;
+ ChangeSettingStringByEdit(hwndDlg,LOWORD(wParam),iUser,offsetof(NETLIBUSERSETTINGS,szOutgoingPorts));
+ break;
+ }
+ ShowWindow(GetDlgItem(hwndDlg,IDC_RECONNECTREQD),SW_SHOW);
+ 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 iUser;
+ for (iUser = 0; iUser < tempSettings.getCount(); iUser++)
+ NetlibSaveUserSettingsStruct(tempSettings[iUser]->szSettingsModule,
+ &tempSettings[iUser]->settings);
+ return TRUE;
+ }
+ }
+ break;
+ }
+ break;
+ case WM_DESTROY:
+ { int iUser;
+ for (iUser = 0; iUser < tempSettings.getCount(); ++iUser)
+ {
+ mir_free(tempSettings[iUser]->szSettingsModule);
+ NetlibFreeUserSettingsStruct(&tempSettings[iUser]->settings);
+ mir_free(tempSettings[iUser]);
+ }
+ tempSettings.destroy();
+ break;
+ }
+ }
+ return FALSE;
+}
+
+static UINT expertOnlyControls[]={IDC_LOGOPTIONS};
+int NetlibOptInitialise(WPARAM wParam,LPARAM)
+{
+ int optionsCount = 0;
+ EnterCriticalSection(&csNetlibUser);
+ for (int i = 0; i < netlibUser.getCount(); ++i)
+ if (!(netlibUser[i]->user.flags & NUF_NOOPTIONS)) ++optionsCount;
+ LeaveCriticalSection(&csNetlibUser);
+ if (optionsCount == 0) return 0;
+
+ OPTIONSDIALOGPAGE odp = { 0 };
+
+ odp.cbSize = sizeof(odp);
+ odp.position = 900000000;
+ odp.hInstance = hMirandaInst;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_NETLIB);
+ odp.pszTitle = LPGEN("Network");
+ odp.pfnDlgProc = DlgProcNetlibOpts;
+ odp.flags = ODPF_BOLDGROUPS;
+ odp.expertOnlyControls = expertOnlyControls;
+ odp.nExpertOnlyControls = SIZEOF( expertOnlyControls );
+ CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
+ return 0;
+}
diff --git a/src/modules/netlib/netlibpktrecver.cpp b/src/modules/netlib/netlibpktrecver.cpp
new file mode 100644
index 0000000000..9722324a4f
--- /dev/null
+++ b/src/modules/netlib/netlibpktrecver.cpp
@@ -0,0 +1,85 @@
+/*
+
+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 "netlib.h"
+
+INT_PTR NetlibPacketRecverCreate(WPARAM wParam,LPARAM lParam)
+{
+ struct NetlibConnection *nlc=(struct NetlibConnection*)wParam;
+ struct NetlibPacketRecver *nlpr;
+
+ if(GetNetlibHandleType(nlc)!=NLH_CONNECTION || lParam==0) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return (INT_PTR)(struct NetlibPacketRecver*)NULL;
+ }
+ nlpr=(struct NetlibPacketRecver*)mir_calloc(sizeof(struct NetlibPacketRecver));
+ if(nlpr==NULL) {
+ SetLastError(ERROR_OUTOFMEMORY);
+ return (INT_PTR)(struct NetlibPacketRecver*)NULL;
+ }
+ nlpr->handleType=NLH_PACKETRECVER;
+ nlpr->nlc=nlc;
+ nlpr->packetRecver.cbSize=sizeof(nlpr->packetRecver);
+ nlpr->packetRecver.bufferSize=lParam;
+ nlpr->packetRecver.buffer=(PBYTE)mir_alloc(nlpr->packetRecver.bufferSize);
+ nlpr->packetRecver.bytesUsed=0;
+ nlpr->packetRecver.bytesAvailable=0;
+ return (INT_PTR)nlpr;
+}
+
+INT_PTR NetlibPacketRecverGetMore(WPARAM wParam,LPARAM lParam)
+{
+ struct NetlibPacketRecver *nlpr=(struct NetlibPacketRecver*)wParam;
+ NETLIBPACKETRECVER *nlprParam=(NETLIBPACKETRECVER*)lParam;
+ INT_PTR recvResult;
+
+ if(GetNetlibHandleType(nlpr)!=NLH_PACKETRECVER || nlprParam==NULL || nlprParam->cbSize!=sizeof(NETLIBPACKETRECVER) || nlprParam->bytesUsed>nlpr->packetRecver.bytesAvailable) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return SOCKET_ERROR;
+ }
+ if (Miranda_Terminated()) { /* HACK: Lame, break while loops of protocols that can't kill their while loops, (cough, ICQ, cough) */
+ SetLastError(ERROR_TIMEOUT);
+ return SOCKET_ERROR;
+ }
+ nlpr->packetRecver.dwTimeout=nlprParam->dwTimeout;
+ if(nlprParam->bytesUsed==0) {
+ if(nlpr->packetRecver.bytesAvailable==nlpr->packetRecver.bufferSize) {
+ nlpr->packetRecver.bytesAvailable=0;
+ NetlibLogf(nlpr->nlc->nlu,"Packet recver: packet overflowed buffer, ditching");
+ }
+ }
+ else {
+ MoveMemory(nlpr->packetRecver.buffer,nlpr->packetRecver.buffer+nlprParam->bytesUsed,nlpr->packetRecver.bytesAvailable-nlprParam->bytesUsed);
+ nlpr->packetRecver.bytesAvailable-=nlprParam->bytesUsed;
+ }
+ if(nlprParam->dwTimeout!=INFINITE) {
+ if(!si.pending(nlpr->nlc->hSsl) && WaitUntilReadable(nlpr->nlc->s,nlprParam->dwTimeout) <= 0) {
+ *nlprParam=nlpr->packetRecver;
+ return SOCKET_ERROR;
+ }
+ }
+ recvResult=NLRecv(nlpr->nlc, (char*)nlpr->packetRecver.buffer+nlpr->packetRecver.bytesAvailable,nlpr->packetRecver.bufferSize-nlpr->packetRecver.bytesAvailable,0);
+ if(recvResult>0) nlpr->packetRecver.bytesAvailable+=recvResult;
+ *nlprParam=nlpr->packetRecver;
+ return recvResult;
+}
diff --git a/src/modules/netlib/netlibsecurity.cpp b/src/modules/netlib/netlibsecurity.cpp
new file mode 100644
index 0000000000..c20dcf10a1
--- /dev/null
+++ b/src/modules/netlib/netlibsecurity.cpp
@@ -0,0 +1,570 @@
+/*
+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 "netlib.h"
+
+#define SECURITY_WIN32
+#include <security.h>
+#include <rpcdce.h>
+
+static HMODULE g_hSecurity = NULL;
+static PSecurityFunctionTable g_pSSPI = NULL;
+
+typedef struct
+{
+ CtxtHandle hClientContext;
+ CredHandle hClientCredential;
+ TCHAR* szProvider;
+ TCHAR* szPrincipal;
+ unsigned cbMaxToken;
+ bool hasDomain;
+}
+ NtlmHandleType;
+
+typedef struct
+{
+ WORD len;
+ WORD allocedSpace;
+ DWORD offset;
+}
+ NTLM_String;
+
+typedef struct
+{
+ char sign[8];
+ DWORD type; // == 2
+ NTLM_String targetName;
+ DWORD flags;
+ BYTE challenge[8];
+ BYTE context[8];
+ NTLM_String targetInfo;
+}
+ NtlmType2packet;
+
+static unsigned secCnt = 0, ntlmCnt = 0;
+static HANDLE hSecMutex;
+
+static void ReportSecError(SECURITY_STATUS scRet, int line)
+{
+ char szMsgBuf[256];
+ FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, scRet, LANG_USER_DEFAULT, szMsgBuf, SIZEOF(szMsgBuf), NULL);
+
+ char *p = strchr(szMsgBuf, 13); if (p) *p = 0;
+
+ NetlibLogf(NULL, "Security error 0x%x on line %u (%s)", scRet, line, szMsgBuf);
+}
+
+static void LoadSecurityLibrary(void)
+{
+ INIT_SECURITY_INTERFACE pInitSecurityInterface;
+
+ g_hSecurity = LoadLibraryA("secur32.dll");
+ if (g_hSecurity == NULL)
+ g_hSecurity = LoadLibraryA("security.dll");
+
+ if (g_hSecurity == NULL)
+ return;
+
+ pInitSecurityInterface = (INIT_SECURITY_INTERFACE)GetProcAddress(g_hSecurity, SECURITY_ENTRYPOINT_ANSI);
+ if (pInitSecurityInterface != NULL)
+ {
+ g_pSSPI = pInitSecurityInterface();
+ }
+
+ if (g_pSSPI == NULL)
+ {
+ FreeLibrary(g_hSecurity);
+ g_hSecurity = NULL;
+ }
+}
+
+static void FreeSecurityLibrary(void)
+{
+ FreeLibrary(g_hSecurity);
+ g_hSecurity = NULL;
+ g_pSSPI = NULL;
+}
+
+HANDLE NetlibInitSecurityProvider(const TCHAR* szProvider, const TCHAR* szPrincipal)
+{
+ HANDLE hSecurity = NULL;
+
+ if (_tcsicmp(szProvider, _T("Basic")) == 0)
+ {
+ NtlmHandleType* hNtlm = (NtlmHandleType*)mir_calloc(sizeof(NtlmHandleType));
+ hNtlm->szProvider = mir_tstrdup(szProvider);
+ SecInvalidateHandle(&hNtlm->hClientContext);
+ SecInvalidateHandle(&hNtlm->hClientCredential);
+ ntlmCnt++;
+
+ return hNtlm;
+ }
+
+ WaitForSingleObject(hSecMutex, INFINITE);
+
+ if (secCnt == 0 )
+ {
+ LoadSecurityLibrary();
+ secCnt += g_hSecurity != NULL;
+ }
+ else secCnt++;
+
+ if (g_pSSPI != NULL)
+ {
+ PSecPkgInfo ntlmSecurityPackageInfo;
+ bool isGSSAPI = _tcsicmp(szProvider, _T("GSSAPI")) == 0;
+ const TCHAR *szProviderC = isGSSAPI ? _T("Kerberos") : szProvider;
+ SECURITY_STATUS sc = g_pSSPI->QuerySecurityPackageInfo((LPTSTR)szProviderC, &ntlmSecurityPackageInfo);
+ if (sc == SEC_E_OK)
+ {
+ NtlmHandleType* hNtlm;
+
+ hSecurity = hNtlm = (NtlmHandleType*)mir_calloc(sizeof(NtlmHandleType));
+ hNtlm->cbMaxToken = ntlmSecurityPackageInfo->cbMaxToken;
+ g_pSSPI->FreeContextBuffer(ntlmSecurityPackageInfo);
+
+ hNtlm->szProvider = mir_tstrdup(szProvider);
+ hNtlm->szPrincipal = mir_tstrdup(szPrincipal ? szPrincipal : _T(""));
+ SecInvalidateHandle(&hNtlm->hClientContext);
+ SecInvalidateHandle(&hNtlm->hClientCredential);
+ ntlmCnt++;
+ }
+ }
+
+ ReleaseMutex(hSecMutex);
+ return hSecurity;
+}
+
+#ifdef UNICODE
+HANDLE NetlibInitSecurityProvider(const char* szProvider, const char* szPrincipal)
+{
+ return NetlibInitSecurityProvider(StrConvT(szProvider), StrConvT(szPrincipal));
+}
+#endif
+
+void NetlibDestroySecurityProvider(HANDLE hSecurity)
+{
+ if (hSecurity == NULL) return;
+
+ WaitForSingleObject(hSecMutex, INFINITE);
+
+ if (ntlmCnt != 0)
+ {
+ NtlmHandleType* hNtlm = (NtlmHandleType*)hSecurity;
+ if (SecIsValidHandle(&hNtlm->hClientContext)) g_pSSPI->DeleteSecurityContext(&hNtlm->hClientContext);
+ if (SecIsValidHandle(&hNtlm->hClientCredential)) g_pSSPI->FreeCredentialsHandle(&hNtlm->hClientCredential);
+ mir_free(hNtlm->szProvider);
+ mir_free(hNtlm->szPrincipal);
+
+ --ntlmCnt;
+
+ mir_free(hNtlm);
+ }
+
+ if (secCnt && --secCnt == 0)
+ FreeSecurityLibrary();
+
+ ReleaseMutex(hSecMutex);
+}
+
+char* CompleteGssapi(HANDLE hSecurity, unsigned char *szChallenge, unsigned chlsz)
+{
+ if (!szChallenge || !szChallenge[0]) return NULL;
+
+ NtlmHandleType* hNtlm = (NtlmHandleType*)hSecurity;
+ unsigned char inDataBuffer[1024];
+
+ SecBuffer inBuffers[2] =
+ {
+ { sizeof(inDataBuffer), SECBUFFER_DATA, inDataBuffer },
+ { chlsz, SECBUFFER_STREAM, szChallenge },
+ };
+
+ SecBufferDesc inBuffersDesc = { SECBUFFER_VERSION, 2, inBuffers };
+
+ unsigned long qop = 0;
+ SECURITY_STATUS sc = g_pSSPI->DecryptMessage(&hNtlm->hClientContext, &inBuffersDesc, 0, &qop);
+ if (sc != SEC_E_OK)
+ {
+ ReportSecError(sc, __LINE__);
+ return NULL;
+ }
+
+ unsigned char LayerMask = inDataBuffer[0];
+ unsigned int MaxMessageSize = htonl(*(unsigned*)&inDataBuffer[1]);
+
+ SecPkgContext_Sizes sizes;
+ sc = g_pSSPI->QueryContextAttributes(&hNtlm->hClientContext, SECPKG_ATTR_SIZES, &sizes);
+ if (sc != SEC_E_OK)
+ {
+ ReportSecError(sc, __LINE__);
+ return NULL;
+ }
+
+ unsigned char *tokenBuffer = (unsigned char*)alloca(sizes.cbSecurityTrailer);
+ unsigned char *paddingBuffer = (unsigned char*)alloca(sizes.cbBlockSize);
+
+ unsigned char outDataBuffer[4] = { 1, 0, 16, 0 };
+
+ SecBuffer outBuffers[3] =
+ {
+ { sizes.cbSecurityTrailer, SECBUFFER_TOKEN, tokenBuffer },
+ { sizeof(outDataBuffer), SECBUFFER_DATA, outDataBuffer },
+ { sizes.cbBlockSize, SECBUFFER_PADDING, paddingBuffer }
+ };
+ SecBufferDesc outBuffersDesc = { SECBUFFER_VERSION, 3, outBuffers };
+
+ sc = g_pSSPI->EncryptMessage(&hNtlm->hClientContext, SECQOP_WRAP_NO_ENCRYPT, &outBuffersDesc, 0);
+ if (sc != SEC_E_OK)
+ {
+ ReportSecError(sc, __LINE__);
+ return NULL;
+ }
+
+ unsigned i, ressz = 0;
+ for (i = 0; i < outBuffersDesc.cBuffers; i++)
+ ressz += outBuffersDesc.pBuffers[i].cbBuffer;
+
+
+ unsigned char *response = (unsigned char*)alloca(ressz), *p = response;
+ for (i = 0; i < outBuffersDesc.cBuffers; i++)
+ {
+ memcpy(p, outBuffersDesc.pBuffers[i].pvBuffer, outBuffersDesc.pBuffers[i].cbBuffer);
+ p += outBuffersDesc.pBuffers[i].cbBuffer;
+ }
+
+ NETLIBBASE64 nlb64;
+ nlb64.cbDecoded = ressz;
+ nlb64.pbDecoded = response;
+ nlb64.cchEncoded = Netlib_GetBase64EncodedBufferSize(nlb64.cbDecoded);
+ nlb64.pszEncoded = (char*)alloca(nlb64.cchEncoded);
+ if (!NetlibBase64Encode(0,(LPARAM)&nlb64)) return NULL;
+
+ return mir_strdup(nlb64.pszEncoded);
+}
+
+char* NtlmCreateResponseFromChallenge(HANDLE hSecurity, const char *szChallenge, const TCHAR* login, const TCHAR* psw,
+ bool http, unsigned& complete)
+{
+ SECURITY_STATUS sc;
+ SecBufferDesc outputBufferDescriptor,inputBufferDescriptor;
+ SecBuffer outputSecurityToken,inputSecurityToken;
+ TimeStamp tokenExpiration;
+ ULONG contextAttributes;
+ NETLIBBASE64 nlb64 = { 0 };
+
+ NtlmHandleType* hNtlm = (NtlmHandleType*)hSecurity;
+
+ if (hSecurity == NULL || ntlmCnt == 0) return NULL;
+
+ if (_tcsicmp(hNtlm->szProvider, _T("Basic")))
+ {
+ bool isGSSAPI = _tcsicmp(hNtlm->szProvider, _T("GSSAPI")) == 0;
+ TCHAR *szProvider = isGSSAPI ? _T("Kerberos") : hNtlm->szProvider;
+ bool hasChallenge = szChallenge != NULL && szChallenge[0] != '\0';
+ if (hasChallenge)
+ {
+ nlb64.cchEncoded = lstrlenA(szChallenge);
+ nlb64.pszEncoded = (char*)szChallenge;
+ nlb64.cbDecoded = Netlib_GetBase64DecodedBufferSize(nlb64.cchEncoded);
+ nlb64.pbDecoded = (PBYTE)alloca(nlb64.cbDecoded);
+ if (!NetlibBase64Decode(0, (LPARAM)&nlb64)) return NULL;
+
+ if (isGSSAPI && complete)
+ return CompleteGssapi(hSecurity, nlb64.pbDecoded, nlb64.cbDecoded);
+
+ inputBufferDescriptor.cBuffers = 1;
+ inputBufferDescriptor.pBuffers = &inputSecurityToken;
+ inputBufferDescriptor.ulVersion = SECBUFFER_VERSION;
+ inputSecurityToken.BufferType = SECBUFFER_TOKEN;
+ inputSecurityToken.cbBuffer = nlb64.cbDecoded;
+ inputSecurityToken.pvBuffer = nlb64.pbDecoded;
+
+ // try to decode the domain name from the NTLM challenge
+ if (login != NULL && login[0] != '\0' && !hNtlm->hasDomain)
+ {
+ NtlmType2packet* pkt = ( NtlmType2packet* )nlb64.pbDecoded;
+ if (!strncmp(pkt->sign, "NTLMSSP", 8) && pkt->type == 2)
+ {
+#ifdef UNICODE
+ wchar_t* domainName = (wchar_t*)&nlb64.pbDecoded[pkt->targetName.offset];
+ int domainLen = pkt->targetName.len;
+
+ // Negotiate ANSI? if yes, convert the ANSI name to unicode
+ if ((pkt->flags & 1) == 0)
+ {
+ int bufsz = MultiByteToWideChar(CP_ACP, 0, (char*)domainName, domainLen, NULL, 0);
+ wchar_t* buf = (wchar_t*)alloca(bufsz * sizeof(wchar_t));
+ domainLen = MultiByteToWideChar(CP_ACP, 0, (char*)domainName, domainLen, buf, bufsz) - 1;
+ domainName = buf;
+ }
+ else
+ domainLen /= sizeof(wchar_t);
+#else
+ char* domainName = (char*)&nlb64.pbDecoded[pkt->targetName.offset];
+ int domainLen = pkt->targetName.len;
+
+ // Negotiate Unicode? if yes, convert the unicode name to ANSI
+ if (pkt->flags & 1)
+ {
+ int bufsz = WideCharToMultiByte(CP_ACP, 0, (WCHAR*)domainName, domainLen, NULL, 0, NULL, NULL);
+ char* buf = (char*)alloca(bufsz);
+ domainLen = WideCharToMultiByte(CP_ACP, 0, (WCHAR*)domainName, domainLen, buf, bufsz, NULL, NULL) - 1;
+ domainName = buf;
+ }
+#endif
+
+ if (domainLen)
+ {
+ size_t newLoginLen = _tcslen(login) + domainLen + 1;
+ TCHAR *newLogin = (TCHAR*)alloca(newLoginLen * sizeof(TCHAR));
+
+ _tcsncpy(newLogin, domainName, domainLen);
+ newLogin[domainLen] = '\\';
+ _tcscpy(newLogin + domainLen + 1, login);
+
+ char* szChl = NtlmCreateResponseFromChallenge(hSecurity, NULL, newLogin, psw, http, complete);
+ mir_free(szChl);
+ }
+ }
+ }
+ }
+ else
+ {
+ if (SecIsValidHandle(&hNtlm->hClientContext)) g_pSSPI->DeleteSecurityContext(&hNtlm->hClientContext);
+ if (SecIsValidHandle(&hNtlm->hClientCredential)) g_pSSPI->FreeCredentialsHandle(&hNtlm->hClientCredential);
+
+ SEC_WINNT_AUTH_IDENTITY auth;
+
+ if (login != NULL && login[0] != '\0')
+ {
+ memset(&auth, 0, sizeof(auth));
+#ifdef _UNICODE
+ NetlibLogf(NULL, "Security login requested, user: %S pssw: %s", login, psw ? "(exist)" : "(no psw)");
+#else
+ NetlibLogf(NULL, "Security login requested, user: %s pssw: %s", login, psw ? "(exist)" : "(no psw)");
+#endif
+
+ const TCHAR* loginName = login;
+ const TCHAR* domainName = _tcschr(login, '\\');
+ int domainLen = 0;
+ int loginLen = lstrlen(loginName);
+ if (domainName != NULL)
+ {
+ loginName = domainName + 1;
+ loginLen = lstrlen(loginName);
+ domainLen = domainName - login;
+ domainName = login;
+ }
+ else if ((domainName = _tcschr(login, '@')) != NULL)
+ {
+ loginName = login;
+ loginLen = domainName - login;
+ domainLen = lstrlen(++domainName);
+ }
+
+#ifdef UNICODE
+ auth.User = (PWORD)loginName;
+ auth.UserLength = loginLen;
+ auth.Password = (PWORD)psw;
+ auth.PasswordLength = lstrlen(psw);
+ auth.Domain = (PWORD)domainName;
+ auth.DomainLength = domainLen;
+ auth.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
+#else
+ auth.User = (PBYTE)loginName;
+ auth.UserLength = loginLen;
+ auth.Password = (PBYTE)psw;
+ auth.PasswordLength = lstrlen(psw);
+ auth.Domain = (PBYTE)domainName;
+ auth.DomainLength = domainLen;
+ auth.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
+#endif
+
+ hNtlm->hasDomain = domainLen != 0;
+ }
+
+ sc = g_pSSPI->AcquireCredentialsHandle(NULL, szProvider,
+ SECPKG_CRED_OUTBOUND, NULL, hNtlm->hasDomain ? &auth : NULL, NULL, NULL,
+ &hNtlm->hClientCredential, &tokenExpiration);
+ if (sc != SEC_E_OK)
+ {
+ ReportSecError(sc, __LINE__);
+ return NULL;
+ }
+ }
+
+ outputBufferDescriptor.cBuffers = 1;
+ outputBufferDescriptor.pBuffers = &outputSecurityToken;
+ outputBufferDescriptor.ulVersion = SECBUFFER_VERSION;
+ outputSecurityToken.BufferType = SECBUFFER_TOKEN;
+ outputSecurityToken.cbBuffer = hNtlm->cbMaxToken;
+ outputSecurityToken.pvBuffer = alloca(outputSecurityToken.cbBuffer);
+
+ sc = g_pSSPI->InitializeSecurityContext(&hNtlm->hClientCredential,
+ hasChallenge ? &hNtlm->hClientContext : NULL,
+ hNtlm->szPrincipal, isGSSAPI ? ISC_REQ_MUTUAL_AUTH | ISC_REQ_STREAM : 0, 0, SECURITY_NATIVE_DREP,
+ hasChallenge ? &inputBufferDescriptor : NULL, 0, &hNtlm->hClientContext,
+ &outputBufferDescriptor, &contextAttributes, &tokenExpiration);
+
+ complete = (sc != SEC_I_COMPLETE_AND_CONTINUE && sc != SEC_I_CONTINUE_NEEDED);
+
+ if (sc == SEC_I_COMPLETE_NEEDED || sc == SEC_I_COMPLETE_AND_CONTINUE)
+ {
+ sc = g_pSSPI->CompleteAuthToken(&hNtlm->hClientContext, &outputBufferDescriptor);
+ }
+
+ if (sc != SEC_E_OK && sc != SEC_I_CONTINUE_NEEDED)
+ {
+ ReportSecError(sc, __LINE__);
+ return NULL;
+ }
+
+ nlb64.cbDecoded = outputSecurityToken.cbBuffer;
+ nlb64.pbDecoded = (PBYTE)outputSecurityToken.pvBuffer;
+ }
+ else
+ {
+ if (!login || !psw) return NULL;
+
+ char *szLogin = mir_t2a(login);
+ char *szPassw = mir_t2a(psw);
+
+ size_t authLen = strlen(szLogin) + strlen(szPassw) + 5;
+ char *szAuth = (char*)alloca(authLen);
+
+ nlb64.cbDecoded = mir_snprintf(szAuth, authLen,"%s:%s", szLogin, szPassw);
+ nlb64.pbDecoded=(PBYTE)szAuth;
+ complete = true;
+
+ mir_free(szPassw);
+ mir_free(szLogin);
+ }
+
+ nlb64.cchEncoded = Netlib_GetBase64EncodedBufferSize(nlb64.cbDecoded);
+ nlb64.pszEncoded = (char*)alloca(nlb64.cchEncoded);
+ if (!NetlibBase64Encode(0,(LPARAM)&nlb64)) return NULL;
+
+ char* result;
+ if (http)
+ {
+ char* szProvider = mir_t2a(hNtlm->szProvider);
+ nlb64.cchEncoded += (int)strlen(szProvider) + 10;
+ result = (char*)mir_alloc(nlb64.cchEncoded);
+ mir_snprintf(result, nlb64.cchEncoded, "%s %s", szProvider, nlb64.pszEncoded);
+ mir_free(szProvider);
+ }
+ else
+ result = mir_strdup(nlb64.pszEncoded);
+
+ return result;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static INT_PTR InitSecurityProviderService(WPARAM, LPARAM lParam)
+{
+ HANDLE hSecurity = NetlibInitSecurityProvider((char*)lParam, NULL);
+ return (INT_PTR)hSecurity;
+}
+
+static INT_PTR InitSecurityProviderService2(WPARAM, LPARAM lParam)
+{
+ NETLIBNTLMINIT2 *req = ( NETLIBNTLMINIT2* )lParam;
+ if (req->cbSize < sizeof(*req)) return 0;
+
+ HANDLE hSecurity;
+
+#ifdef UNICODE
+ if (req->flags & NNR_UNICODE)
+ hSecurity = NetlibInitSecurityProvider(req->szProviderName, req->szPrincipal);
+ else
+#endif
+ hSecurity = NetlibInitSecurityProvider((char*)req->szProviderName, (char*)req->szPrincipal);
+
+ return (INT_PTR)hSecurity;
+}
+
+static INT_PTR DestroySecurityProviderService( WPARAM, LPARAM lParam )
+{
+ NetlibDestroySecurityProvider(( HANDLE )lParam );
+ return 0;
+}
+
+static INT_PTR NtlmCreateResponseService( WPARAM wParam, LPARAM lParam )
+{
+ NETLIBNTLMREQUEST* req = ( NETLIBNTLMREQUEST* )lParam;
+ unsigned complete;
+
+ char* response = NtlmCreateResponseFromChallenge(( HANDLE )wParam, req->szChallenge,
+ StrConvT(req->userName), StrConvT(req->password), false, complete );
+
+ return (INT_PTR)response;
+}
+
+static INT_PTR NtlmCreateResponseService2( WPARAM wParam, LPARAM lParam )
+{
+ NETLIBNTLMREQUEST2* req = ( NETLIBNTLMREQUEST2* )lParam;
+ if (req->cbSize < sizeof(*req)) return 0;
+
+ char* response;
+
+#ifdef UNICODE
+ if (req->flags & NNR_UNICODE)
+ {
+ response = NtlmCreateResponseFromChallenge(( HANDLE )wParam, req->szChallenge,
+ req->szUserName, req->szPassword, false, req->complete );
+ }
+ else
+ {
+ TCHAR *szLogin = mir_a2t((char*)req->szUserName);
+ TCHAR *szPassw = mir_a2t((char*)req->szPassword);
+ response = NtlmCreateResponseFromChallenge(( HANDLE )wParam, req->szChallenge,
+ szLogin, szPassw, false, req->complete );
+ mir_free(szLogin);
+ mir_free(szPassw);
+ }
+#else
+ response = NtlmCreateResponseFromChallenge(( HANDLE )wParam, req->szChallenge,
+ req->szUserName, req->szPassword, false, req->complete );
+#endif
+
+ return (INT_PTR)response;
+}
+
+void NetlibSecurityInit(void)
+{
+ hSecMutex = CreateMutex(NULL, FALSE, NULL);
+
+ CreateServiceFunction( MS_NETLIB_INITSECURITYPROVIDER, InitSecurityProviderService );
+ CreateServiceFunction( MS_NETLIB_INITSECURITYPROVIDER2, InitSecurityProviderService2 );
+ CreateServiceFunction( MS_NETLIB_DESTROYSECURITYPROVIDER, DestroySecurityProviderService );
+ CreateServiceFunction( MS_NETLIB_NTLMCREATERESPONSE, NtlmCreateResponseService );
+ CreateServiceFunction( MS_NETLIB_NTLMCREATERESPONSE2, NtlmCreateResponseService2 );
+}
+
+void NetlibSecurityDestroy(void)
+{
+ CloseHandle(hSecMutex);
+} \ No newline at end of file
diff --git a/src/modules/netlib/netlibsock.cpp b/src/modules/netlib/netlibsock.cpp
new file mode 100644
index 0000000000..875c47b0a1
--- /dev/null
+++ b/src/modules/netlib/netlibsock.cpp
@@ -0,0 +1,203 @@
+/*
+
+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 "netlib.h"
+
+extern HANDLE hConnectionHeaderMutex,hSendEvent,hRecvEvent;
+
+INT_PTR NetlibSend(WPARAM wParam,LPARAM lParam)
+{
+ struct NetlibConnection *nlc=(struct NetlibConnection*)wParam;
+ NETLIBBUFFER *nlb=(NETLIBBUFFER*)lParam;
+ INT_PTR result;
+
+ if ( nlb == NULL ) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return SOCKET_ERROR;
+ }
+
+ if ( !NetlibEnterNestedCS( nlc, NLNCS_SEND ))
+ return SOCKET_ERROR;
+
+ if ( nlc->usingHttpGateway && !( nlb->flags & MSG_RAW )) {
+ if ( !( nlb->flags & MSG_NOHTTPGATEWAYWRAP ) && nlc->nlu->user.pfnHttpGatewayWrapSend ) {
+ NetlibDumpData( nlc, ( PBYTE )nlb->buf, nlb->len, 1, nlb->flags );
+ result = nlc->nlu->user.pfnHttpGatewayWrapSend(( HANDLE )nlc, ( PBYTE )nlb->buf, nlb->len, nlb->flags | MSG_NOHTTPGATEWAYWRAP, NetlibSend );
+ }
+ else result = NetlibHttpGatewayPost( nlc, nlb->buf, nlb->len, nlb->flags );
+ }
+ else {
+ NetlibDumpData( nlc, ( PBYTE )nlb->buf, nlb->len, 1, nlb->flags );
+ if (nlc->hSsl)
+ result = si.write( nlc->hSsl, nlb->buf, nlb->len );
+ else
+ result = send( nlc->s, nlb->buf, nlb->len, nlb->flags & 0xFFFF );
+ }
+ NetlibLeaveNestedCS( &nlc->ncsSend );
+
+ if ((( THook* )hSendEvent)->subscriberCount ) {
+ NETLIBNOTIFY nln = { nlb, result };
+ CallHookSubscribers( hSendEvent, (WPARAM)&nln, (LPARAM)&nlc->nlu->user );
+ }
+ return result;
+}
+
+INT_PTR NetlibRecv(WPARAM wParam,LPARAM lParam)
+{
+ struct NetlibConnection *nlc = (struct NetlibConnection*)wParam;
+ NETLIBBUFFER* nlb = ( NETLIBBUFFER* )lParam;
+ int recvResult;
+
+ if ( nlb == NULL ) {
+ SetLastError( ERROR_INVALID_PARAMETER );
+ return SOCKET_ERROR;
+ }
+
+ if ( !NetlibEnterNestedCS( nlc, NLNCS_RECV ))
+ return SOCKET_ERROR;
+
+ if ( nlc->usingHttpGateway && !( nlb->flags & MSG_RAW ))
+ recvResult = NetlibHttpGatewayRecv( nlc, nlb->buf, nlb->len, nlb->flags );
+ else
+ {
+ if (nlc->hSsl)
+ recvResult = si.read( nlc->hSsl, nlb->buf, nlb->len, (nlb->flags & MSG_PEEK) != 0 );
+ else
+ recvResult = recv( nlc->s, nlb->buf, nlb->len, nlb->flags & 0xFFFF );
+ }
+ NetlibLeaveNestedCS( &nlc->ncsRecv );
+ if (recvResult <= 0)
+ return recvResult;
+
+ NetlibDumpData(nlc, (PBYTE)nlb->buf, recvResult, 0, nlb->flags);
+
+ if ((nlb->flags & MSG_PEEK) == 0 && ((THook*)hRecvEvent)->subscriberCount)
+ {
+ NETLIBNOTIFY nln = { nlb, recvResult };
+ CallHookSubscribers(hRecvEvent, (WPARAM)&nln, (LPARAM)&nlc->nlu->user);
+ }
+ return recvResult;
+}
+
+static int ConnectionListToSocketList(HANDLE *hConns, fd_set *fd, int& pending)
+{
+ struct NetlibConnection *nlcCheck;
+ int i;
+
+ FD_ZERO(fd);
+ for(i=0;hConns[i] && hConns[i]!=INVALID_HANDLE_VALUE && i<FD_SETSIZE;i++) {
+ nlcCheck=(struct NetlibConnection*)hConns[i];
+ if (nlcCheck->handleType!=NLH_CONNECTION && nlcCheck->handleType!=NLH_BOUNDPORT) {
+ SetLastError(ERROR_INVALID_DATA);
+ return 0;
+ }
+ FD_SET(nlcCheck->s,fd);
+ if ( si.pending( nlcCheck->hSsl ))
+ pending++;
+ }
+ return 1;
+}
+
+INT_PTR NetlibSelect(WPARAM,LPARAM lParam)
+{
+ NETLIBSELECT *nls=(NETLIBSELECT*)lParam;
+ if (nls==NULL || nls->cbSize!=sizeof(NETLIBSELECT)) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return SOCKET_ERROR;
+ }
+
+ TIMEVAL tv;
+ tv.tv_sec=nls->dwTimeout/1000;
+ tv.tv_usec=(nls->dwTimeout%1000)*1000;
+
+ int pending = 0;
+ fd_set readfd, writefd, exceptfd;
+ WaitForSingleObject(hConnectionHeaderMutex,INFINITE);
+ if (!ConnectionListToSocketList(nls->hReadConns,&readfd,pending)
+ || !ConnectionListToSocketList(nls->hWriteConns,&writefd,pending)
+ || !ConnectionListToSocketList(nls->hExceptConns,&exceptfd,pending)) {
+ ReleaseMutex(hConnectionHeaderMutex);
+ return SOCKET_ERROR;
+ }
+ ReleaseMutex(hConnectionHeaderMutex);
+ if (pending)
+ return 1;
+
+ return select(0,&readfd,&writefd,&exceptfd,nls->dwTimeout==INFINITE?NULL:&tv);
+}
+
+INT_PTR NetlibSelectEx(WPARAM, LPARAM lParam)
+{
+ NETLIBSELECTEX *nls=(NETLIBSELECTEX*)lParam;
+ if (nls==NULL || nls->cbSize!=sizeof(NETLIBSELECTEX)) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return SOCKET_ERROR;
+ }
+
+ TIMEVAL tv;
+ tv.tv_sec=nls->dwTimeout/1000;
+ tv.tv_usec=(nls->dwTimeout%1000)*1000;
+ WaitForSingleObject(hConnectionHeaderMutex,INFINITE);
+
+ int pending = 0;
+ fd_set readfd,writefd,exceptfd;
+ if (!ConnectionListToSocketList(nls->hReadConns,&readfd,pending)
+ || !ConnectionListToSocketList(nls->hWriteConns,&writefd,pending)
+ || !ConnectionListToSocketList(nls->hExceptConns,&exceptfd,pending)) {
+ ReleaseMutex(hConnectionHeaderMutex);
+ return SOCKET_ERROR;
+ }
+ ReleaseMutex(hConnectionHeaderMutex);
+
+ int rc = (pending) ? pending : select(0,&readfd,&writefd,&exceptfd,nls->dwTimeout==INFINITE?NULL:&tv);
+
+ WaitForSingleObject(hConnectionHeaderMutex,INFINITE);
+ /* go thru each passed HCONN array and grab its socket handle, then give it to FD_ISSET()
+ to see if an event happened for that socket, if it has it will be returned as TRUE (otherwise not)
+ This happens for read/write/except */
+ struct NetlibConnection *conn=NULL;
+ int j;
+ for (j=0; j<FD_SETSIZE; j++) {
+ conn=(struct NetlibConnection*)nls->hReadConns[j];
+ if (conn==NULL || conn==INVALID_HANDLE_VALUE) break;
+
+ if (si.pending(conn->hSsl))
+ nls->hReadStatus[j] = TRUE;
+ if (conn->usingHttpGateway && conn->nlhpi.szHttpGetUrl == NULL && conn->dataBuffer == NULL)
+ nls->hReadStatus[j] = (conn->pHttpProxyPacketQueue != NULL);
+ else
+ nls->hReadStatus[j] = FD_ISSET(conn->s,&readfd);
+ }
+ for (j=0; j<FD_SETSIZE; j++) {
+ conn=(struct NetlibConnection*)nls->hWriteConns[j];
+ if (conn==NULL || conn==INVALID_HANDLE_VALUE) break;
+ nls->hWriteStatus[j] = FD_ISSET(conn->s,&writefd);
+ }
+ for (j=0; j<FD_SETSIZE; j++) {
+ conn=(struct NetlibConnection*)nls->hExceptConns[j];
+ if (conn==NULL || conn==INVALID_HANDLE_VALUE) break;
+ nls->hExceptStatus[j] = FD_ISSET(conn->s,&exceptfd);
+ }
+ ReleaseMutex(hConnectionHeaderMutex);
+ return rc;
+}
diff --git a/src/modules/netlib/netlibssl.cpp b/src/modules/netlib/netlibssl.cpp
new file mode 100644
index 0000000000..2db769a3da
--- /dev/null
+++ b/src/modules/netlib/netlibssl.cpp
@@ -0,0 +1,981 @@
+/*
+
+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_popup.h>
+#include "netlib.h"
+
+#define SECURITY_WIN32
+#include <security.h>
+#include <schannel.h>
+
+//#include <SCHNLSP.H>
+
+typedef BOOL (* SSL_EMPTY_CACHE_FN_M)(VOID);
+
+static HMODULE g_hSchannel;
+static PSecurityFunctionTableA g_pSSPI;
+static HANDLE g_hSslMutex;
+static SSL_EMPTY_CACHE_FN_M MySslEmptyCache;
+static CredHandle hCreds;
+static bool bSslInitDone;
+
+typedef BOOL (WINAPI *pfnCertGetCertificateChain)(HCERTCHAINENGINE, PCCERT_CONTEXT, LPFILETIME, HCERTSTORE, PCERT_CHAIN_PARA, DWORD, LPVOID, PCCERT_CHAIN_CONTEXT*);
+static pfnCertGetCertificateChain fnCertGetCertificateChain;
+
+typedef VOID (WINAPI *pfnCertFreeCertificateChain)(PCCERT_CHAIN_CONTEXT);
+static pfnCertFreeCertificateChain fnCertFreeCertificateChain;
+
+typedef BOOL (WINAPI *pfnCertFreeCertificateContext)(PCCERT_CONTEXT);
+static pfnCertFreeCertificateContext fnCertFreeCertificateContext;
+
+typedef BOOL (WINAPI *pfnCertVerifyCertificateChainPolicy)(LPCSTR, PCCERT_CHAIN_CONTEXT, PCERT_CHAIN_POLICY_PARA, PCERT_CHAIN_POLICY_STATUS);
+static pfnCertVerifyCertificateChainPolicy fnCertVerifyCertificateChainPolicy;
+
+typedef enum
+{
+ sockOpen,
+ sockClosed,
+ sockError
+} SocketState;
+
+
+struct SslHandle
+{
+ SOCKET s;
+
+ CtxtHandle hContext;
+
+ BYTE *pbRecDataBuf;
+ int cbRecDataBuf;
+ int sbRecDataBuf;
+
+ BYTE *pbIoBuffer;
+ int cbIoBuffer;
+ int sbIoBuffer;
+
+ SocketState state;
+};
+
+static void ReportSslError(SECURITY_STATUS scRet, int line, bool showPopup = false)
+{
+ TCHAR szMsgBuf[256];
+ switch (scRet)
+ {
+ case 0:
+ case ERROR_NOT_READY:
+ return;
+
+ case SEC_E_INVALID_TOKEN:
+ _tcscpy(szMsgBuf, TranslateT("Client cannot decode host message. Possible causes: Host does not support SSL or requires not existing security package"));
+ break;
+
+ case CERT_E_CN_NO_MATCH:
+ case SEC_E_WRONG_PRINCIPAL:
+ _tcscpy(szMsgBuf, TranslateT("Host we are connecting to is not the one certificate was issued for"));
+ break;
+
+ default:
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, scRet, LANG_USER_DEFAULT, szMsgBuf, SIZEOF(szMsgBuf), NULL);
+ }
+
+ TCHAR szMsgBuf2[512];
+ mir_sntprintf(szMsgBuf2, SIZEOF(szMsgBuf2), _T("SSL connection failure (%x %u): %s"), scRet, line, szMsgBuf);
+
+ char* szMsg = Utf8EncodeT(szMsgBuf2);
+ NetlibLogf(NULL, szMsg);
+ mir_free(szMsg);
+
+ SetLastError(scRet);
+ PUShowMessageT(szMsgBuf2, SM_WARNING);
+}
+
+static bool AcquireCredentials(void)
+{
+ SCHANNEL_CRED SchannelCred;
+ TimeStamp tsExpiry;
+ SECURITY_STATUS scRet;
+
+ ZeroMemory(&SchannelCred, sizeof(SchannelCred));
+
+ SchannelCred.dwVersion = SCHANNEL_CRED_VERSION;
+ SchannelCred.grbitEnabledProtocols = SP_PROT_SSL3TLS1_CLIENTS /*| 0xA00 TLS1.1 & 1.2*/;
+
+ SchannelCred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS | SCH_CRED_MANUAL_CRED_VALIDATION;
+
+ // Create an SSPI credential.
+ scRet = g_pSSPI->AcquireCredentialsHandleA(
+ NULL, // Name of principal
+ UNISP_NAME_A, // Name of package
+ SECPKG_CRED_OUTBOUND, // Flags indicating use
+ NULL, // Pointer to logon ID
+ &SchannelCred, // Package specific data
+ NULL, // Pointer to GetKey() func
+ NULL, // Value to pass to GetKey()
+ &hCreds, // (out) Cred Handle
+ &tsExpiry); // (out) Lifetime (optional)
+
+ ReportSslError(scRet, __LINE__);
+ return scRet == SEC_E_OK;
+}
+
+static bool SSL_library_init(void)
+{
+ if (bSslInitDone) return true;
+
+ WaitForSingleObject(g_hSslMutex, INFINITE);
+
+ if (!bSslInitDone)
+ {
+ g_hSchannel = LoadLibraryA("schannel.dll");
+ if (g_hSchannel)
+ {
+ INIT_SECURITY_INTERFACE_A pInitSecurityInterface;
+ pInitSecurityInterface = (INIT_SECURITY_INTERFACE_A)GetProcAddress(g_hSchannel, SECURITY_ENTRYPOINT_ANSIA);
+ if (pInitSecurityInterface != NULL)
+ g_pSSPI = pInitSecurityInterface();
+
+ if (g_pSSPI)
+ {
+ HINSTANCE hCrypt = LoadLibraryA("crypt32.dll");
+ if (hCrypt)
+ {
+ fnCertGetCertificateChain = (pfnCertGetCertificateChain)GetProcAddress(hCrypt, "CertGetCertificateChain");
+ fnCertFreeCertificateChain = (pfnCertFreeCertificateChain)GetProcAddress(hCrypt, "CertFreeCertificateChain");
+ fnCertFreeCertificateContext = (pfnCertFreeCertificateContext)GetProcAddress(hCrypt, "CertFreeCertificateContext");
+ fnCertVerifyCertificateChainPolicy = (pfnCertVerifyCertificateChainPolicy)GetProcAddress(hCrypt, "CertVerifyCertificateChainPolicy");
+ }
+
+ MySslEmptyCache = (SSL_EMPTY_CACHE_FN_M)GetProcAddress(g_hSchannel, "SslEmptyCache");
+ AcquireCredentials();
+ bSslInitDone = true;
+ }
+ else
+ {
+ FreeLibrary(g_hSchannel);
+ g_hSchannel = NULL;
+ }
+ }
+ }
+
+ ReleaseMutex(g_hSslMutex);
+ return bSslInitDone;
+}
+
+void NetlibSslFree(SslHandle *ssl)
+{
+ if (ssl == NULL) return;
+
+ g_pSSPI->DeleteSecurityContext(&ssl->hContext);
+
+ mir_free(ssl->pbRecDataBuf);
+ mir_free(ssl->pbIoBuffer);
+ memset(ssl, 0, sizeof(SslHandle));
+ mir_free(ssl);
+}
+
+BOOL NetlibSslPending(SslHandle *ssl)
+{
+ return ssl != NULL && ( ssl->cbRecDataBuf != 0 || ssl->cbIoBuffer != 0 );
+}
+
+static bool VerifyCertificate(SslHandle *ssl, PCSTR pszServerName, DWORD dwCertFlags)
+{
+ if (!fnCertGetCertificateChain)
+ return true;
+
+ static LPSTR rgszUsages[] =
+ {
+ szOID_PKIX_KP_SERVER_AUTH,
+ szOID_SERVER_GATED_CRYPTO,
+ szOID_SGC_NETSCAPE
+ };
+
+ CERT_CHAIN_PARA ChainPara = {0};
+ HTTPSPolicyCallbackData polHttps = {0};
+ CERT_CHAIN_POLICY_PARA PolicyPara = {0};
+ CERT_CHAIN_POLICY_STATUS PolicyStatus = {0};
+ PCCERT_CHAIN_CONTEXT pChainContext = NULL;
+ PCCERT_CONTEXT pServerCert = NULL;
+ DWORD scRet;
+
+ PWSTR pwszServerName = mir_a2u(pszServerName);
+
+ scRet = g_pSSPI->QueryContextAttributesA(&ssl->hContext,
+ SECPKG_ATTR_REMOTE_CERT_CONTEXT, &pServerCert);
+ if (scRet != SEC_E_OK)
+ goto cleanup;
+
+ if (pServerCert == NULL)
+ {
+ scRet = SEC_E_WRONG_PRINCIPAL;
+ goto cleanup;
+ }
+
+ ChainPara.cbSize = sizeof(ChainPara);
+ ChainPara.RequestedUsage.dwType = USAGE_MATCH_TYPE_OR;
+ ChainPara.RequestedUsage.Usage.cUsageIdentifier = SIZEOF(rgszUsages);
+ ChainPara.RequestedUsage.Usage.rgpszUsageIdentifier = rgszUsages;
+
+ if (!fnCertGetCertificateChain(NULL, pServerCert, NULL, pServerCert->hCertStore,
+ &ChainPara, 0, NULL, &pChainContext))
+ {
+ scRet = GetLastError();
+ goto cleanup;
+ }
+
+ polHttps.cbStruct = sizeof(HTTPSPolicyCallbackData);
+ polHttps.dwAuthType = AUTHTYPE_SERVER;
+ polHttps.fdwChecks = dwCertFlags;
+ polHttps.pwszServerName = pwszServerName;
+
+ PolicyPara.cbSize = sizeof(PolicyPara);
+ PolicyPara.pvExtraPolicyPara = &polHttps;
+
+ PolicyStatus.cbSize = sizeof(PolicyStatus);
+
+ if (!fnCertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, pChainContext,
+ &PolicyPara, &PolicyStatus))
+ {
+ scRet = GetLastError();
+ goto cleanup;
+ }
+
+ if (PolicyStatus.dwError)
+ {
+ scRet = PolicyStatus.dwError;
+ goto cleanup;
+ }
+
+ scRet = SEC_E_OK;
+
+cleanup:
+ if (pChainContext)
+ fnCertFreeCertificateChain(pChainContext);
+ if (pServerCert)
+ fnCertFreeCertificateContext(pServerCert);
+ mir_free(pwszServerName);
+
+ ReportSslError(scRet, __LINE__, true);
+ return scRet == SEC_E_OK;
+}
+
+static SECURITY_STATUS ClientHandshakeLoop(SslHandle *ssl, BOOL fDoInitialRead)
+{
+ SecBufferDesc InBuffer;
+ SecBuffer InBuffers[2];
+ SecBufferDesc OutBuffer;
+ SecBuffer OutBuffers[1];
+ DWORD dwSSPIFlags;
+ DWORD dwSSPIOutFlags;
+ TimeStamp tsExpiry;
+ SECURITY_STATUS scRet;
+ DWORD cbData;
+
+ BOOL fDoRead;
+
+ dwSSPIFlags =
+ ISC_REQ_SEQUENCE_DETECT |
+ ISC_REQ_REPLAY_DETECT |
+ ISC_REQ_CONFIDENTIALITY |
+ ISC_REQ_EXTENDED_ERROR |
+ ISC_REQ_ALLOCATE_MEMORY |
+ ISC_REQ_STREAM;
+
+ ssl->cbIoBuffer = 0;
+
+ fDoRead = fDoInitialRead;
+
+ scRet = SEC_I_CONTINUE_NEEDED;
+
+ // Loop until the handshake is finished or an error occurs.
+ while (scRet == SEC_I_CONTINUE_NEEDED || scRet == SEC_E_INCOMPLETE_MESSAGE || scRet == SEC_I_INCOMPLETE_CREDENTIALS)
+ {
+ // Read server data
+ if (0 == ssl->cbIoBuffer || scRet == SEC_E_INCOMPLETE_MESSAGE)
+ {
+ if (fDoRead)
+ {
+ static const TIMEVAL tv = {6, 0};
+ fd_set fd;
+
+ // If buffer not large enough reallocate buffer
+ if (ssl->sbIoBuffer <= ssl->cbIoBuffer)
+ {
+ ssl->sbIoBuffer += 4096;
+ ssl->pbIoBuffer = (PUCHAR)mir_realloc(ssl->pbIoBuffer, ssl->sbIoBuffer);
+ }
+
+ FD_ZERO(&fd);
+ FD_SET(ssl->s, &fd);
+ if (select(1, &fd, NULL, NULL, &tv) != 1)
+ {
+ NetlibLogf(NULL, "SSL Negotiation failure recieving data (timeout) (bytes %u)", ssl->cbIoBuffer);
+ scRet = ERROR_NOT_READY;
+ break;
+ }
+
+ cbData = recv(ssl->s, (char*)ssl->pbIoBuffer + ssl->cbIoBuffer, ssl->sbIoBuffer - ssl->cbIoBuffer, 0);
+ if (cbData == SOCKET_ERROR)
+ {
+ NetlibLogf(NULL, "SSL Negotiation failure recieving data (%d)", WSAGetLastError());
+ scRet = ERROR_NOT_READY;
+ break;
+ }
+ if (cbData == 0)
+ {
+ NetlibLogf(NULL, "SSL Negotiation connection gracefully closed");
+ scRet = ERROR_NOT_READY;
+ break;
+ }
+
+ NetlibDumpData(NULL, ssl->pbIoBuffer + ssl->cbIoBuffer, cbData, 0, MSG_DUMPSSL);
+ ssl->cbIoBuffer += cbData;
+ }
+ else fDoRead = TRUE;
+ }
+
+ // Set up the input buffers. Buffer 0 is used to pass in data
+ // received from the server. Schannel will consume some or all
+ // of this. Leftover data (if any) will be placed in buffer 1 and
+ // given a buffer type of SECBUFFER_EXTRA.
+
+ InBuffers[0].pvBuffer = ssl->pbIoBuffer;
+ InBuffers[0].cbBuffer = ssl->cbIoBuffer;
+ InBuffers[0].BufferType = SECBUFFER_TOKEN;
+
+ InBuffers[1].pvBuffer = NULL;
+ InBuffers[1].cbBuffer = 0;
+ InBuffers[1].BufferType = SECBUFFER_EMPTY;
+
+ InBuffer.cBuffers = 2;
+ InBuffer.pBuffers = InBuffers;
+ InBuffer.ulVersion = SECBUFFER_VERSION;
+
+ // Set up the output buffers. These are initialized to NULL
+ // so as to make it less likely we'll attempt to free random
+ // garbage later.
+
+ OutBuffers[0].pvBuffer = NULL;
+ OutBuffers[0].BufferType= SECBUFFER_TOKEN;
+ OutBuffers[0].cbBuffer = 0;
+
+ OutBuffer.cBuffers = 1;
+ OutBuffer.pBuffers = OutBuffers;
+ OutBuffer.ulVersion = SECBUFFER_VERSION;
+
+ scRet = g_pSSPI->InitializeSecurityContextA(
+ &hCreds,
+ &ssl->hContext,
+ NULL,
+ dwSSPIFlags,
+ 0,
+ SECURITY_NATIVE_DREP,
+ &InBuffer,
+ 0,
+ NULL,
+ &OutBuffer,
+ &dwSSPIOutFlags,
+ &tsExpiry);
+
+ // If success (or if the error was one of the special extended ones),
+ // send the contents of the output buffer to the server.
+ if (scRet == SEC_E_OK ||
+ scRet == SEC_I_CONTINUE_NEEDED ||
+ (FAILED(scRet) && (dwSSPIOutFlags & ISC_RET_EXTENDED_ERROR)))
+ {
+ if (OutBuffers[0].cbBuffer != 0 && OutBuffers[0].pvBuffer != NULL)
+ {
+ NetlibDumpData(NULL, (unsigned char*)(OutBuffers[0].pvBuffer), OutBuffers[0].cbBuffer, 1, MSG_DUMPSSL);
+ cbData = send(ssl->s, (char*)OutBuffers[0].pvBuffer, OutBuffers[0].cbBuffer, 0);
+ if (cbData == SOCKET_ERROR || cbData == 0)
+ {
+ NetlibLogf(NULL, "SSL Negotiation failure sending data (%d)", WSAGetLastError());
+ g_pSSPI->FreeContextBuffer(OutBuffers[0].pvBuffer);
+ return SEC_E_INTERNAL_ERROR;
+ }
+
+ // Free output buffer.
+ g_pSSPI->FreeContextBuffer(OutBuffers[0].pvBuffer);
+ OutBuffers[0].pvBuffer = NULL;
+ }
+ }
+
+ // we need to read more data from the server and try again.
+ if (scRet == SEC_E_INCOMPLETE_MESSAGE) continue;
+
+ // handshake completed successfully.
+ if (scRet == SEC_E_OK)
+ {
+ // Store remaining data for further use
+ if (InBuffers[1].BufferType == SECBUFFER_EXTRA)
+ {
+ memmove(ssl->pbIoBuffer,
+ ssl->pbIoBuffer + (ssl->cbIoBuffer - InBuffers[1].cbBuffer),
+ InBuffers[1].cbBuffer);
+ ssl->cbIoBuffer = InBuffers[1].cbBuffer;
+ }
+ else
+ ssl->cbIoBuffer = 0;
+ break;
+ }
+
+ // Check for fatal error.
+ if (FAILED(scRet)) break;
+
+ // server just requested client authentication.
+ if (scRet == SEC_I_INCOMPLETE_CREDENTIALS)
+ {
+ // Server has requested client authentication and
+ // GetNewClientCredentials(ssl);
+
+ // Go around again.
+ fDoRead = FALSE;
+ scRet = SEC_I_CONTINUE_NEEDED;
+ continue;
+ }
+
+
+ // Copy any leftover data from the buffer, and go around again.
+ if (InBuffers[1].BufferType == SECBUFFER_EXTRA)
+ {
+ memmove(ssl->pbIoBuffer,
+ ssl->pbIoBuffer + (ssl->cbIoBuffer - InBuffers[1].cbBuffer),
+ InBuffers[1].cbBuffer);
+
+ ssl->cbIoBuffer = InBuffers[1].cbBuffer;
+ }
+ else ssl->cbIoBuffer = 0;
+ }
+
+ // Delete the security context in the case of a fatal error.
+ ReportSslError(scRet, __LINE__);
+
+ if (ssl->cbIoBuffer == 0)
+ {
+ mir_free(ssl->pbIoBuffer);
+ ssl->pbIoBuffer = NULL;
+ ssl->sbIoBuffer = 0;
+ }
+
+ return scRet;
+}
+
+static bool ClientConnect(SslHandle *ssl, const char *host)
+{
+ SecBufferDesc OutBuffer;
+ SecBuffer OutBuffers[1];
+ DWORD dwSSPIFlags;
+ DWORD dwSSPIOutFlags;
+ TimeStamp tsExpiry;
+ SECURITY_STATUS scRet;
+ DWORD cbData;
+
+ if (SecIsValidHandle(&ssl->hContext))
+ {
+ g_pSSPI->DeleteSecurityContext(&ssl->hContext);
+ SecInvalidateHandle(&ssl->hContext);
+ }
+
+ if (MySslEmptyCache) MySslEmptyCache();
+
+ dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT |
+ ISC_REQ_REPLAY_DETECT |
+ ISC_REQ_CONFIDENTIALITY |
+ ISC_REQ_EXTENDED_ERROR |
+ ISC_REQ_ALLOCATE_MEMORY |
+ ISC_REQ_STREAM;
+
+ // Initiate a ClientHello message and generate a token.
+
+ OutBuffers[0].pvBuffer = NULL;
+ OutBuffers[0].BufferType = SECBUFFER_TOKEN;
+ OutBuffers[0].cbBuffer = 0;
+
+ OutBuffer.cBuffers = 1;
+ OutBuffer.pBuffers = OutBuffers;
+ OutBuffer.ulVersion = SECBUFFER_VERSION;
+
+ scRet = g_pSSPI->InitializeSecurityContextA(
+ &hCreds,
+ NULL,
+ (SEC_CHAR*)host,
+ dwSSPIFlags,
+ 0,
+ SECURITY_NATIVE_DREP,
+ NULL,
+ 0,
+ &ssl->hContext,
+ &OutBuffer,
+ &dwSSPIOutFlags,
+ &tsExpiry);
+
+ if (scRet != SEC_I_CONTINUE_NEEDED)
+ {
+ ReportSslError(scRet, __LINE__);
+ return 0;
+ }
+
+ // Send response to server if there is one.
+ if (OutBuffers[0].cbBuffer != 0 && OutBuffers[0].pvBuffer != NULL)
+ {
+ NetlibDumpData(NULL, (unsigned char*)(OutBuffers[0].pvBuffer), OutBuffers[0].cbBuffer, 1, MSG_DUMPSSL);
+ cbData = send(ssl->s, (char*)OutBuffers[0].pvBuffer, OutBuffers[0].cbBuffer, 0);
+ if (cbData == SOCKET_ERROR || cbData == 0)
+ {
+ NetlibLogf(NULL, "SSL failure sending connection data (%d %d)", ssl->s, WSAGetLastError());
+ g_pSSPI->FreeContextBuffer(OutBuffers[0].pvBuffer);
+ return 0;
+ }
+
+ // Free output buffer.
+ g_pSSPI->FreeContextBuffer(OutBuffers[0].pvBuffer);
+ OutBuffers[0].pvBuffer = NULL;
+ }
+
+ return ClientHandshakeLoop(ssl, TRUE) == SEC_E_OK;
+}
+
+
+SslHandle *NetlibSslConnect(SOCKET s, const char* host, int verify)
+{
+ SslHandle *ssl = (SslHandle*)mir_calloc(sizeof(SslHandle));
+ ssl->s = s;
+
+ SecInvalidateHandle(&ssl->hContext);
+
+ DWORD dwFlags = 0;
+
+ if (!host || inet_addr(host) != INADDR_NONE)
+ dwFlags |= 0x00001000;
+
+ bool res = SSL_library_init();
+
+ if (res) res = ClientConnect(ssl, host);
+ if (res && verify) res = VerifyCertificate(ssl, host, dwFlags);
+
+ if (!res)
+ {
+ NetlibSslFree(ssl);
+ ssl = NULL;
+ }
+ return ssl;
+}
+
+
+void NetlibSslShutdown(SslHandle *ssl)
+{
+ DWORD dwType;
+
+ SecBufferDesc OutBuffer;
+ SecBuffer OutBuffers[1];
+ DWORD dwSSPIFlags;
+ DWORD dwSSPIOutFlags;
+ TimeStamp tsExpiry;
+ DWORD scRet;
+
+ if (ssl == NULL || !SecIsValidHandle(&ssl->hContext))
+ return;
+
+ dwType = SCHANNEL_SHUTDOWN;
+
+ OutBuffers[0].pvBuffer = &dwType;
+ OutBuffers[0].BufferType = SECBUFFER_TOKEN;
+ OutBuffers[0].cbBuffer = sizeof(dwType);
+
+ OutBuffer.cBuffers = 1;
+ OutBuffer.pBuffers = OutBuffers;
+ OutBuffer.ulVersion = SECBUFFER_VERSION;
+
+ scRet = g_pSSPI->ApplyControlToken(&ssl->hContext, &OutBuffer);
+ if (FAILED(scRet)) return;
+
+ //
+ // Build an SSL close notify message.
+ //
+
+ dwSSPIFlags = ISC_REQ_SEQUENCE_DETECT |
+ ISC_REQ_REPLAY_DETECT |
+ ISC_REQ_CONFIDENTIALITY |
+ ISC_RET_EXTENDED_ERROR |
+ ISC_REQ_ALLOCATE_MEMORY |
+ ISC_REQ_STREAM;
+
+ OutBuffers[0].pvBuffer = NULL;
+ OutBuffers[0].BufferType = SECBUFFER_TOKEN;
+ OutBuffers[0].cbBuffer = 0;
+
+ OutBuffer.cBuffers = 1;
+ OutBuffer.pBuffers = OutBuffers;
+ OutBuffer.ulVersion = SECBUFFER_VERSION;
+
+ scRet = g_pSSPI->InitializeSecurityContextA(
+ &hCreds,
+ &ssl->hContext,
+ NULL,
+ dwSSPIFlags,
+ 0,
+ SECURITY_NATIVE_DREP,
+ NULL,
+ 0,
+ &ssl->hContext,
+ &OutBuffer,
+ &dwSSPIOutFlags,
+ &tsExpiry);
+
+ if (FAILED(scRet)) return;
+
+ // Send the close notify message to the server.
+ if (OutBuffers[0].pvBuffer != NULL && OutBuffers[0].cbBuffer != 0)
+ {
+ NetlibDumpData(NULL, (unsigned char*)(OutBuffers[0].pvBuffer), OutBuffers[0].cbBuffer, 1, MSG_DUMPSSL);
+ send(ssl->s, (char*)OutBuffers[0].pvBuffer, OutBuffers[0].cbBuffer, 0);
+ g_pSSPI->FreeContextBuffer(OutBuffers[0].pvBuffer);
+ }
+}
+
+static int NetlibSslReadSetResult(SslHandle *ssl, char *buf, int num, int peek)
+{
+ if (ssl->cbRecDataBuf == 0)
+ {
+ return (ssl->state == sockClosed ? 0: SOCKET_ERROR);
+ }
+
+ int bytes = min(num, ssl->cbRecDataBuf);
+ int rbytes = ssl->cbRecDataBuf - bytes;
+
+ memcpy(buf, ssl->pbRecDataBuf, bytes);
+ if (!peek)
+ {
+ memmove(ssl->pbRecDataBuf, ssl->pbRecDataBuf + bytes, rbytes);
+ ssl->cbRecDataBuf = rbytes;
+ }
+
+ return bytes;
+}
+
+int NetlibSslRead(SslHandle *ssl, char *buf, int num, int peek)
+{
+ SECURITY_STATUS scRet;
+ DWORD cbData;
+ DWORD resNum = 0;
+ int i;
+
+ SecBufferDesc Message;
+ SecBuffer Buffers[4];
+ SecBuffer * pDataBuffer;
+ SecBuffer * pExtraBuffer;
+
+ if (ssl == NULL) return SOCKET_ERROR;
+
+ if (num <= 0) return 0;
+
+ if (ssl->state != sockOpen || (ssl->cbRecDataBuf != 0 && (!peek || ssl->cbRecDataBuf >= num)))
+ {
+ return NetlibSslReadSetResult(ssl, buf, num, peek);
+ }
+
+ scRet = SEC_E_OK;
+
+ for (;;)
+ {
+ if (0 == ssl->cbIoBuffer || scRet == SEC_E_INCOMPLETE_MESSAGE)
+ {
+ if (ssl->sbIoBuffer <= ssl->cbIoBuffer)
+ {
+ ssl->sbIoBuffer += 2048;
+ ssl->pbIoBuffer = (PUCHAR)mir_realloc(ssl->pbIoBuffer, ssl->sbIoBuffer);
+ }
+
+ if (peek)
+ {
+ static const TIMEVAL tv = {0};
+ fd_set fd;
+ FD_ZERO(&fd);
+ FD_SET(ssl->s, &fd);
+
+ cbData = select(1, &fd, NULL, NULL, &tv);
+ if (cbData == SOCKET_ERROR)
+ {
+ ssl->state = sockError;
+ return NetlibSslReadSetResult(ssl, buf, num, peek);
+ }
+
+ if (cbData == 0 && ssl->cbRecDataBuf)
+ return NetlibSslReadSetResult(ssl, buf, num, peek);
+ }
+
+ cbData = recv(ssl->s, (char*)ssl->pbIoBuffer + ssl->cbIoBuffer, ssl->sbIoBuffer - ssl->cbIoBuffer, 0);
+ if (cbData == SOCKET_ERROR)
+ {
+ NetlibLogf(NULL, "SSL failure recieving data (%d)", WSAGetLastError());
+ ssl->state = sockError;
+ return NetlibSslReadSetResult(ssl, buf, num, peek);
+ }
+
+ if (cbData == 0)
+ {
+ NetlibLogf(NULL, "SSL connection gracefully closed");
+ if (peek && ssl->cbRecDataBuf)
+ {
+ ssl->state = sockClosed;
+ return NetlibSslReadSetResult(ssl, buf, num, peek);
+ }
+
+ // Server disconnected.
+ if (ssl->cbIoBuffer)
+ {
+ ssl->state = sockError;
+ return NetlibSslReadSetResult(ssl, buf, num, peek);
+ }
+
+ return 0;
+ }
+ else
+ {
+ NetlibDumpData(NULL, ssl->pbIoBuffer + ssl->cbIoBuffer, cbData, 0, MSG_DUMPSSL);
+ ssl->cbIoBuffer += cbData;
+ }
+ }
+
+ // Attempt to decrypt the received data.
+ Buffers[0].pvBuffer = ssl->pbIoBuffer;
+ Buffers[0].cbBuffer = ssl->cbIoBuffer;
+ Buffers[0].BufferType = SECBUFFER_DATA;
+
+ Buffers[1].BufferType = SECBUFFER_EMPTY;
+ Buffers[2].BufferType = SECBUFFER_EMPTY;
+ Buffers[3].BufferType = SECBUFFER_EMPTY;
+
+ Message.ulVersion = SECBUFFER_VERSION;
+ Message.cBuffers = 4;
+ Message.pBuffers = Buffers;
+
+ if (g_pSSPI->DecryptMessage != NULL && g_pSSPI->DecryptMessage != PVOID(0x80000000))
+ scRet = g_pSSPI->DecryptMessage(&ssl->hContext, &Message, 0, NULL);
+ else
+ scRet = ((DECRYPT_MESSAGE_FN)g_pSSPI->Reserved4)(&ssl->hContext, &Message, 0, NULL);
+
+ // The input buffer contains only a fragment of an
+ // encrypted record. Loop around and read some more
+ // data.
+ if (scRet == SEC_E_INCOMPLETE_MESSAGE)
+ continue;
+
+ if ( scRet != SEC_E_OK && scRet != SEC_I_RENEGOTIATE && scRet != SEC_I_CONTEXT_EXPIRED)
+ {
+ ReportSslError(scRet, __LINE__);
+ ssl->state = sockError;
+ return NetlibSslReadSetResult(ssl, buf, num, peek);
+ }
+
+ // Locate data and (optional) extra buffers.
+ pDataBuffer = NULL;
+ pExtraBuffer = NULL;
+ for(i = 1; i < 4; i++)
+ {
+ if (pDataBuffer == NULL && Buffers[i].BufferType == SECBUFFER_DATA)
+ pDataBuffer = &Buffers[i];
+
+ if (pExtraBuffer == NULL && Buffers[i].BufferType == SECBUFFER_EXTRA)
+ pExtraBuffer = &Buffers[i];
+ }
+
+ // Return decrypted data.
+ if (pDataBuffer)
+ {
+ DWORD bytes, rbytes;
+
+ bytes = peek ? 0 : min((DWORD)num, pDataBuffer->cbBuffer);
+ rbytes = pDataBuffer->cbBuffer - bytes;
+
+ NetlibDumpData(NULL, (PBYTE)pDataBuffer->pvBuffer, pDataBuffer->cbBuffer, 0, MSG_DUMPSSL);
+
+ if (rbytes > 0)
+ {
+ int nbytes = ssl->cbRecDataBuf + rbytes;
+ if (ssl->sbRecDataBuf < nbytes)
+ {
+ ssl->sbRecDataBuf = nbytes;
+ ssl->pbRecDataBuf = (PUCHAR)mir_realloc(ssl->pbRecDataBuf, nbytes);
+ }
+ memcpy(ssl->pbRecDataBuf + ssl->cbRecDataBuf, (char*)pDataBuffer->pvBuffer + bytes, rbytes);
+ ssl->cbRecDataBuf = nbytes;
+ }
+
+ if (peek)
+ {
+ resNum = bytes = min(num, ssl->cbRecDataBuf);
+ memcpy(buf, ssl->pbRecDataBuf, bytes);
+ }
+ else
+ {
+ resNum = bytes;
+ memcpy(buf, pDataBuffer->pvBuffer, bytes);
+ }
+ }
+
+ // Move any "extra" data to the input buffer.
+ if (pExtraBuffer)
+ {
+ memmove(ssl->pbIoBuffer, pExtraBuffer->pvBuffer, pExtraBuffer->cbBuffer);
+ ssl->cbIoBuffer = pExtraBuffer->cbBuffer;
+ }
+ else ssl->cbIoBuffer = 0;
+
+ if (pDataBuffer && resNum)
+ return resNum;
+
+ // Server signaled end of session
+ if (scRet == SEC_I_CONTEXT_EXPIRED)
+ {
+ NetlibLogf(NULL, "SSL Server signaled SSL Shutdown");
+ ssl->state = sockClosed;
+ return NetlibSslReadSetResult(ssl, buf, num, peek);
+ }
+
+ if (scRet == SEC_I_RENEGOTIATE)
+ {
+ // The server wants to perform another handshake
+ // sequence.
+
+ scRet = ClientHandshakeLoop(ssl, FALSE);
+ if (scRet != SEC_E_OK)
+ {
+ ssl->state = sockError;
+ return NetlibSslReadSetResult(ssl, buf, num, peek);
+ }
+ }
+ }
+}
+
+int NetlibSslWrite(SslHandle *ssl, const char *buf, int num)
+{
+ SecPkgContext_StreamSizes Sizes;
+ SECURITY_STATUS scRet;
+ DWORD cbData;
+
+ SecBufferDesc Message;
+ SecBuffer Buffers[4] = {0};
+
+ PUCHAR pbDataBuffer;
+
+ PUCHAR pbMessage;
+ DWORD cbMessage;
+
+ DWORD sendOff = 0;
+
+ if (ssl == NULL) return SOCKET_ERROR;
+
+ scRet = g_pSSPI->QueryContextAttributesA(&ssl->hContext, SECPKG_ATTR_STREAM_SIZES, &Sizes);
+ if (scRet != SEC_E_OK) return scRet;
+
+ pbDataBuffer = (PUCHAR)mir_calloc(Sizes.cbMaximumMessage + Sizes.cbHeader + Sizes.cbTrailer);
+
+ pbMessage = pbDataBuffer + Sizes.cbHeader;
+
+ while (sendOff < (DWORD)num)
+ {
+ cbMessage = min(Sizes.cbMaximumMessage, (DWORD)num - sendOff);
+ CopyMemory(pbMessage, buf+sendOff, cbMessage);
+
+ Buffers[0].pvBuffer = pbDataBuffer;
+ Buffers[0].cbBuffer = Sizes.cbHeader;
+ Buffers[0].BufferType = SECBUFFER_STREAM_HEADER;
+
+ Buffers[1].pvBuffer = pbMessage;
+ Buffers[1].cbBuffer = cbMessage;
+ Buffers[1].BufferType = SECBUFFER_DATA;
+
+ Buffers[2].pvBuffer = pbMessage + cbMessage;
+ Buffers[2].cbBuffer = Sizes.cbTrailer;
+ Buffers[2].BufferType = SECBUFFER_STREAM_TRAILER;
+
+ Buffers[3].BufferType = SECBUFFER_EMPTY;
+
+ Message.ulVersion = SECBUFFER_VERSION;
+ Message.cBuffers = 4;
+ Message.pBuffers = Buffers;
+
+ if (g_pSSPI->EncryptMessage != NULL)
+ scRet = g_pSSPI->EncryptMessage(&ssl->hContext, 0, &Message, 0);
+ else
+ scRet = ((ENCRYPT_MESSAGE_FN)g_pSSPI->Reserved3)(&ssl->hContext, 0, &Message, 0);
+
+ if (FAILED(scRet)) break;
+
+ // Calculate encrypted packet size
+ cbData = Buffers[0].cbBuffer + Buffers[1].cbBuffer + Buffers[2].cbBuffer;
+
+ // Send the encrypted data to the server.
+ NetlibDumpData(NULL, pbDataBuffer, cbData, 1, MSG_DUMPSSL);
+ cbData = send(ssl->s, (char*)pbDataBuffer, cbData, 0);
+ if (cbData == SOCKET_ERROR || cbData == 0)
+ {
+ NetlibLogf(NULL, "SSL failure sending data (%d)", WSAGetLastError());
+ scRet = SEC_E_INTERNAL_ERROR;
+ break;
+ }
+
+ sendOff += cbMessage;
+ }
+
+ mir_free(pbDataBuffer);
+ return scRet == SEC_E_OK ? num : SOCKET_ERROR;
+}
+
+static INT_PTR GetSslApi(WPARAM, LPARAM lParam)
+{
+ SSL_API* si = (SSL_API*)lParam;
+ if (si == NULL) return FALSE;
+
+ if (si->cbSize != sizeof(SSL_API))
+ return FALSE;
+
+ si->connect = (HSSL (__cdecl *)(SOCKET,const char *,int))NetlibSslConnect;
+ si->pending = (BOOL (__cdecl *)(HSSL))NetlibSslPending;
+ si->read = (int (__cdecl *)(HSSL,char *,int,int))NetlibSslRead;
+ si->write = (int (__cdecl *)(HSSL,const char *,int))NetlibSslWrite;
+ si->shutdown = (void (__cdecl *)(HSSL))NetlibSslShutdown;
+ si->sfree = (void (__cdecl *)(HSSL))NetlibSslFree;
+
+ return TRUE;
+}
+
+int LoadSslModule(void)
+{
+ CreateServiceFunction(MS_SYSTEM_GET_SI, GetSslApi);
+ g_hSslMutex = CreateMutex(NULL, FALSE, NULL);
+ SecInvalidateHandle(&hCreds);
+
+ return 0;
+}
+
+void UnloadSslModule(void)
+{
+ if (g_pSSPI && SecIsValidHandle(&hCreds))
+ g_pSSPI->FreeCredentialsHandle(&hCreds);
+ CloseHandle(g_hSslMutex);
+ if (g_hSchannel) FreeLibrary(g_hSchannel);
+}
diff --git a/src/modules/netlib/netlibupnp.cpp b/src/modules/netlib/netlibupnp.cpp
new file mode 100644
index 0000000000..935801d330
--- /dev/null
+++ b/src/modules/netlib/netlibupnp.cpp
@@ -0,0 +1,885 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2012 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 "netlib.h"
+
+static const char search_request_msg[] =
+ "M-SEARCH * HTTP/1.1\r\n"
+ "HOST: 239.255.255.250:1900\r\n"
+ "MAN: \"ssdp:discover\"\r\n"
+ "MX: 1\r\n"
+ "ST: urn:schemas-upnp-org:service:%s\r\n"
+ "\r\n";
+
+static const char xml_get_hdr[] =
+ "GET %s HTTP/1.1\r\n"
+ "HOST: %s:%u\r\n"
+ "ACCEPT-LANGUAGE: *\r\n\r\n";
+
+static const char soap_post_hdr[] =
+ "POST %s HTTP/1.1\r\n"
+ "HOST: %s:%u\r\n"
+ "CONTENT-LENGTH: %u\r\n"
+ "CONTENT-TYPE: text/xml; charset=\"utf-8\"\r\n"
+ "SOAPACTION: \"%s#%s\"\r\n\r\n"
+ "%s";
+
+static const char soap_post_hdr_m[] =
+ "M-POST %s URL HTTP/1.1\r\n"
+ "HOST: %s:%u\r\n"
+ "CONTENT-LENGTH: %u\r\n"
+ "CONTENT-TYPE: text/xml; charset=\"utf-8\"\r\n"
+ "MAN: \"http://schemas.xmlsoap.org/soap/envelope/\"; ns=01\r\n"
+ "01-SOAPACTION: \"%s#%s\"\r\n\r\n"
+ "%s";
+
+static const char search_device[] =
+ "<serviceType>%s</serviceType>";
+
+static const char soap_action[] =
+ "<?xml version=\"1.0\"?>\r\n"
+ "<s:Envelope\r\n"
+ " xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"\r\n"
+ " s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\r\n"
+ " <s:Body>\r\n"
+ " <u:%s xmlns:u=\"%s\">\r\n"
+ "%s"
+ " </u:%s>\r\n"
+ " </s:Body>\r\n"
+ "</s:Envelope>\r\n";
+
+static const char soap_query[] =
+ "<s:Envelope\r\n"
+ " xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"\r\n"
+ " s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">\r\n"
+ " <s:Body>\r\n"
+ " <u:QueryStateVariable xmlns:u=\"urn:schemas-upnp-org:control-1-0\">\r\n"
+ " <u:varName>%s</u:varName>\r\n"
+ " </u:QueryStateVariable>\r\n"
+ " </s:Body>\r\n"
+ "</s:Envelope>\r\n";
+
+static const char add_port_mapping[] =
+ " <NewRemoteHost></NewRemoteHost>\r\n"
+ " <NewExternalPort>%i</NewExternalPort>\r\n"
+ " <NewProtocol>%s</NewProtocol>\r\n"
+ " <NewInternalPort>%i</NewInternalPort>\r\n"
+ " <NewInternalClient>%s</NewInternalClient>\r\n"
+ " <NewEnabled>1</NewEnabled>\r\n"
+ " <NewPortMappingDescription>Miranda</NewPortMappingDescription>\r\n"
+ " <NewLeaseDuration>0</NewLeaseDuration>\r\n";
+
+static const char delete_port_mapping[] =
+ " <NewRemoteHost></NewRemoteHost>\r\n"
+ " <NewExternalPort>%i</NewExternalPort>\r\n"
+ " <NewProtocol>%s</NewProtocol>\r\n";
+
+static const char get_port_mapping[] =
+ " <NewPortMappingIndex>%i</NewPortMappingIndex>\r\n";
+
+static bool gatewayFound;
+static SOCKADDR_IN locIP;
+static time_t lastDiscTime;
+static int expireTime = 120;
+
+static int retryCount;
+static SOCKET sock = INVALID_SOCKET;
+static char szConnHost[256];
+static unsigned short sConnPort;
+
+static WORD *portList;
+static unsigned numports, numportsAlloc;
+static HANDLE portListMutex;
+
+static char szCtlUrl[256], szDev[256];
+
+typedef enum
+{
+ DeviceGetReq,
+ ControlAction,
+ ControlQuery
+} ReqType;
+
+static bool txtParseParam(char* szData, char* presearch,
+ char* start, char* finish, char* param, size_t size)
+{
+ char *cp, *cp1;
+ size_t len;
+
+ *param = 0;
+
+ if (presearch != NULL) {
+ cp1 = strstr(szData, presearch);
+ if (cp1 == NULL) return false;
+ }
+ else
+ cp1 = szData;
+
+ cp = strstr(cp1, start);
+ if (cp == NULL) return false;
+ cp += strlen(start);
+ while (*cp == ' ') ++cp;
+
+ cp1 = strstr(cp, finish);
+ if (cp1 == NULL) return false;
+ while (*(cp1-1) == ' ' && cp1 > cp) --cp1;
+
+ len = min((size_t)(cp1 - cp), size-1);
+ strncpy(param, cp, len);
+ param[len] = 0;
+
+ return true;
+}
+
+void parseURL(char* szUrl, char* szHost, unsigned short* sPort, char* szPath)
+{
+ char *ppath, *phost, *pport;
+ int sz;
+
+ phost = strstr(szUrl,"://");
+ if (phost == NULL) phost = szUrl;
+ else phost += 3;
+
+ ppath = strchr(phost,'/');
+ if (ppath == NULL) ppath = phost + strlen(phost);
+
+ pport = strchr(phost,':');
+ if (pport == NULL) pport = ppath;
+
+ if (szHost != NULL)
+ {
+ sz = pport - phost + 1;
+ if (sz>256) sz = 256;
+ strncpy(szHost, phost, sz);
+ szHost[sz-1] = 0;
+ }
+
+ if (sPort != NULL)
+ {
+ if (pport < ppath)
+ {
+ long prt = atol(pport+1);
+ *sPort = prt != 0 ? (unsigned short)prt : 80;
+ }
+ else
+ *sPort = 80;
+ }
+
+ if (szPath != NULL)
+ {
+ strncpy(szPath, ppath, 256);
+ szPath[255] = 0;
+ }
+}
+
+
+static void LongLog(char* szData)
+{
+ CallService(MS_NETLIB_LOG, 0, (LPARAM)szData);
+}
+
+static void closeRouterConnection(void)
+{
+ if (sock != INVALID_SOCKET)
+ {
+ closesocket(sock);
+ sock = INVALID_SOCKET;
+ }
+}
+
+static void validateSocket(void)
+{
+ static const TIMEVAL tv = { 0, 0 };
+ fd_set rfd;
+ char buf[4];
+ bool opened;
+
+ if (sock == INVALID_SOCKET)
+ return;
+
+ FD_ZERO(&rfd);
+ FD_SET(sock, &rfd);
+
+ switch (select(1, &rfd, NULL, NULL, &tv))
+ {
+ case SOCKET_ERROR:
+ opened = false;
+ break;
+
+ case 0:
+ opened = true;
+ break;
+
+ case 1:
+ opened = recv(sock, buf, 1, MSG_PEEK) > 0;
+ break;
+ }
+
+ if (!opened)
+ closeRouterConnection();
+}
+
+static int httpTransact(char* szUrl, char* szResult, int resSize, char* szActionName, ReqType reqtype)
+{
+ // Parse URL
+ char szHost[256], szPath[256], szRes[16];
+ int sz = 0, res = 0;
+ unsigned short sPort;
+ bool needClose;
+
+ const char* szPostHdr = soap_post_hdr;
+ char* szData = ( char* )mir_alloc(4096);
+ char* szReq = NULL;
+
+ parseURL(szUrl, szHost, &sPort, szPath);
+
+ if (sPort != sConnPort || _stricmp(szHost, szConnHost))
+ closeRouterConnection();
+ else
+ validateSocket();
+
+ for (;;)
+ {
+ retryCount = 0;
+ switch(reqtype)
+ {
+ case DeviceGetReq:
+ sz = mir_snprintf (szData, 4096, xml_get_hdr, szPath, szHost, sPort);
+ break;
+
+ case ControlAction:
+ {
+ char szData1[1024];
+
+ szReq = mir_strdup(szResult);
+ sz = mir_snprintf (szData1, sizeof(szData1),
+ soap_action, szActionName, szDev, szReq, szActionName);
+
+ sz = mir_snprintf (szData, 4096,
+ szPostHdr, szPath, szHost, sPort,
+ sz, szDev, szActionName, szData1);
+ }
+ break;
+
+ case ControlQuery:
+ {
+ char szData1[1024];
+
+ sz = mir_snprintf (szData1, sizeof(szData1),
+ soap_query, szActionName);
+
+ sz = mir_snprintf (szData, 4096,
+ szPostHdr, szPath, szHost, sPort,
+ sz, "urn:schemas-upnp-org:control-1-0", "QueryStateVariable", szData1);
+ }
+ break;
+ }
+ szResult[0] = 0;
+ {
+ static const TIMEVAL tv = { 6, 0 };
+ static unsigned ttl = 4;
+ static u_long mode = 1;
+ fd_set rfd, wfd, efd;
+ SOCKADDR_IN enetaddr;
+
+retrycon:
+ if (sock == INVALID_SOCKET)
+ {
+ sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+
+ enetaddr.sin_family = AF_INET;
+ enetaddr.sin_port = htons(sPort);
+ enetaddr.sin_addr.s_addr = inet_addr(szHost);
+
+ // Resolve host name if needed
+ if (enetaddr.sin_addr.s_addr == INADDR_NONE)
+ {
+ PHOSTENT he = gethostbyname(szHost);
+ if (he)
+ enetaddr.sin_addr.s_addr = *(unsigned*)he->h_addr_list[0];
+ }
+
+ NetlibLogf(NULL, "UPnP HTTP connection Host: %s Port: %u", szHost, sPort);
+
+ FD_ZERO(&rfd); FD_ZERO(&wfd); FD_ZERO(&efd);
+ FD_SET(sock, &rfd); FD_SET(sock, &wfd); FD_SET(sock, &efd);
+
+ // Limit the scope of the connection (does not work for
+ setsockopt(sock, IPPROTO_IP, IP_TTL, (char *)&ttl, sizeof(unsigned));
+
+ // Put socket into non-blocking mode for timeout on connect
+ ioctlsocket(sock, FIONBIO, &mode);
+
+ // Connect to the remote host
+ if (connect(sock, (SOCKADDR*)&enetaddr, sizeof(enetaddr)) == SOCKET_ERROR)
+ {
+ int err = WSAGetLastError();
+
+ // Socket connection failed
+ if (err != WSAEWOULDBLOCK)
+ {
+ closeRouterConnection();
+ NetlibLogf(NULL, "UPnP connect failed %d", err);
+ break;
+ }
+ // Wait for socket to connect
+ else if (select(1, &rfd, &wfd, &efd, &tv) != 1)
+ {
+ closeRouterConnection();
+ NetlibLogf(NULL, "UPnP connect timeout");
+ break;
+ }
+ else if (!FD_ISSET(sock, &wfd))
+ {
+ closeRouterConnection();
+ NetlibLogf(NULL, "UPnP connect failed");
+ break;
+ }
+ }
+ strcpy(szConnHost, szHost); sConnPort = sPort;
+ }
+
+ if (send(sock, szData, sz, 0) != SOCKET_ERROR)
+ {
+ char *hdrend = NULL;
+ int acksz = 0, pktsz = 0;
+
+ if (szActionName == NULL)
+ {
+ int len = sizeof(locIP);
+ getsockname(sock, (SOCKADDR*)&locIP, &len);
+ if (locIP.sin_addr.S_un.S_addr == 0x0100007f)
+ {
+ struct hostent *he;
+
+ gethostname(szPath, sizeof(szPath));
+ he = gethostbyname(szPath);
+ if (he != NULL)
+ locIP.sin_addr.S_un.S_addr = *(PDWORD)he->h_addr_list[0];
+ }
+ }
+
+ LongLog(szData);
+ sz = 0;
+ for(;;)
+ {
+ int bytesRecv;
+
+ FD_ZERO(&rfd);
+ FD_SET(sock, &rfd);
+
+ // Wait for the next packet
+ if (select(1, &rfd, NULL, NULL, &tv) != 1)
+ {
+ closeRouterConnection();
+ NetlibLogf(NULL, "UPnP recieve timeout");
+ break;
+ }
+
+ //
+ bytesRecv = recv(sock, &szResult[sz], resSize-sz, 0);
+
+ // Connection closed or aborted, all data received
+ if (bytesRecv == 0 || bytesRecv == SOCKET_ERROR)
+ {
+ closeRouterConnection();
+ if ((bytesRecv == SOCKET_ERROR || sz == 0) && retryCount < 2)
+ {
+ ++retryCount;
+ goto retrycon;
+ }
+ break;
+ }
+
+ sz += bytesRecv;
+
+ // Insert null terminator to use string functions
+ if (sz >= (resSize-1))
+ {
+ szResult[resSize-1] = 0;
+ break;
+ }
+ else
+ szResult[sz] = 0;
+
+ // HTTP header found?
+ if (hdrend == NULL)
+ {
+ // Find HTTP header end
+ hdrend = strstr(szResult, "\r\n\r\n");
+ if (hdrend == NULL)
+ {
+ hdrend = strstr(szResult, "\n\n");
+ if (hdrend) hdrend += 2;
+ }
+
+ else
+ hdrend += 4;
+
+ if (hdrend != NULL)
+ {
+ // Get packet size if provided
+ if (txtParseParam(szResult, NULL, "Content-Length:", "\n", szRes, sizeof(szRes)) ||
+ txtParseParam(szResult, NULL, "CONTENT-LENGTH:", "\n", szRes, sizeof(szRes)))
+ {
+ // Add size of HTTP header to the packet size to compute full transmission size
+ pktsz = atol(ltrimp(szRes)) + (hdrend - szResult);
+ }
+ // Get encoding type if provided
+ else if (txtParseParam(szResult, NULL, "Transfer-Encoding:", "\n", szRes, sizeof(szRes)))
+ {
+ if (_stricmp(lrtrimp(szRes), "Chunked") == 0)
+ acksz = hdrend - szResult;
+ }
+ if (txtParseParam(szResult, NULL, "Connection:", "\n", szRes, sizeof(szRes)))
+ {
+ needClose = (_stricmp(lrtrimp(szRes), "close") == 0);
+ }
+ }
+ }
+
+ // Content-Length bytes reached, all data received
+ if (sz >= pktsz && pktsz != 0)
+ {
+ szResult[pktsz] = 0;
+ break;
+ }
+
+ // Chunked encoding processing
+ if (sz > acksz && acksz != 0)
+ {
+retry:
+ // Parse out chunk size
+ char* data = szResult + acksz;
+ char* peol1 = data == hdrend ? data - 1 : strchr(data, '\n');
+ if (peol1 != NULL)
+ {
+ char *peol2 = strchr(++peol1, '\n');
+ if (peol2 != NULL)
+ {
+ // Get chunk size
+ int chunkBytes = strtol(peol1, NULL, 16);
+ acksz += chunkBytes;
+ peol2++;
+
+ memmove(data, peol2, strlen(peol2) + 1);
+ sz -= peol2 - data;
+
+ // Last chunk, all data received
+ if (chunkBytes == 0) break;
+ if (sz > acksz) goto retry;
+ }
+ }
+ }
+ }
+ LongLog(szResult);
+ }
+ else
+ {
+ if (retryCount < 2)
+ {
+ closeRouterConnection();
+ ++retryCount;
+ goto retrycon;
+ }
+ else
+ NetlibLogf(NULL, "UPnP send failed %d", WSAGetLastError());
+ }
+ }
+ txtParseParam(szResult, "HTTP", " ", " ", szRes, sizeof(szRes));
+ res = atol(szRes);
+ if (szActionName != NULL && res == 405 && szPostHdr == soap_post_hdr)
+ szPostHdr = soap_post_hdr_m;
+ else
+ break;
+ }
+
+ if (needClose)
+ closeRouterConnection();
+
+ mir_free(szData);
+ mir_free(szReq);
+ return res;
+}
+
+static unsigned getExtIP(void)
+{
+ char szExtIP[30];
+ char* szData = (char*)mir_alloc(4096); szData[0] = 0;
+
+ unsigned extip = 0;
+ int res = httpTransact(szCtlUrl, szData, 4096, "GetExternalIPAddress", ControlAction);
+ if (res == 200 && txtParseParam(szData, "<NewExternalIPAddress", ">", "<", szExtIP, sizeof(szExtIP)))
+ extip = ntohl(inet_addr(szExtIP));
+
+ mir_free(szData);
+ return extip;
+}
+
+static bool getUPnPURLs(char* szUrl, size_t sizeUrl)
+{
+ char* szData = (char*)mir_alloc(8192);
+
+ gatewayFound = httpTransact(szUrl, szData, 8192, NULL, DeviceGetReq) == 200;
+ if (gatewayFound)
+ {
+ char szTemp[256], *rpth;
+ size_t ctlLen;
+
+ txtParseParam(szData, NULL, "<URLBase>", "</URLBase>", szTemp, sizeof(szTemp));
+ strncpy(szCtlUrl, szTemp[0] ? szTemp : szUrl, sizeof(szCtlUrl));
+ szCtlUrl[sizeof(szCtlUrl)-1] = 0;
+
+ mir_snprintf(szTemp, sizeof(szTemp), search_device, szDev);
+ txtParseParam(szData, szTemp, "<controlURL>", "</controlURL>", szUrl, sizeUrl);
+
+ // URL combining per RFC 2396
+ if ( szUrl[0] != 0 )
+ {
+ if (strstr(szUrl, "://") != NULL) // absolute URI
+ rpth = szCtlUrl;
+ else if (strncmp(szUrl, "//", 2) == 0) // relative URI net_path
+ {
+ rpth = strstr(szCtlUrl, "//");
+ if (rpth == NULL) rpth = szCtlUrl;
+ }
+ else if (szUrl[0] == '/') // relative URI abs_path
+ {
+ rpth = strstr(szCtlUrl, "//");
+ rpth = rpth ? rpth + 2 : szCtlUrl;
+
+ rpth = strchr(rpth, '/');
+ if (rpth == NULL) rpth = szCtlUrl + strlen(szCtlUrl);
+ }
+ else
+ { // relative URI rel_path
+ size_t ctlCLen = strlen(szCtlUrl);
+ rpth = szCtlUrl + ctlCLen;
+ if (ctlCLen != 0 && *(rpth-1) != '/')
+ strncpy(rpth++, "/", sizeof(szCtlUrl) - ctlCLen);
+ }
+
+ ctlLen = sizeof(szCtlUrl) - (rpth - szCtlUrl);
+ strncpy(rpth, szUrl, ctlLen);
+ szCtlUrl[sizeof(szCtlUrl)-1] = 0;
+ }
+ else
+ {
+ szCtlUrl[0] = 0;
+ gatewayFound = false;
+ }
+ }
+ mir_free(szData);
+
+ return gatewayFound;
+}
+
+
+static void discoverUPnP(void)
+{
+ char* buf;
+ int buflen;
+ unsigned i, j, nip = 0;
+ unsigned* ips = NULL;
+
+ static const unsigned any = INADDR_ANY;
+ static const TIMEVAL tv = { 1, 600000 };
+
+ char szUrl[256] = "";
+ char hostname[256];
+ PHOSTENT he;
+ fd_set readfd;
+
+ SOCKET sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+
+ SOCKADDR_IN enetaddr;
+ enetaddr.sin_family = AF_INET;
+ enetaddr.sin_port = htons(1900);
+ enetaddr.sin_addr.s_addr = inet_addr("239.255.255.250");
+
+ gethostname(hostname, sizeof(hostname));
+ he = gethostbyname(hostname);
+
+ if (he)
+ {
+ while(he->h_addr_list[nip]) ++nip;
+
+ ips = ( unsigned* )mir_alloc(nip * sizeof(unsigned));
+
+ for (j = 0; j < nip; ++j)
+ ips[j] = *(unsigned*)he->h_addr_list[j];
+ }
+
+ buf = (char*)mir_alloc(1500);
+
+ for(i = 3; --i && szUrl[0] == 0;)
+ {
+ for (j = 0; j < nip; ++j)
+ {
+ if (ips)
+ setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (char *)&ips[j], sizeof(unsigned));
+
+ buflen = mir_snprintf(buf, 1500, search_request_msg, "WANIPConnection:1");
+ sendto(sock, buf, buflen, 0, (SOCKADDR*)&enetaddr, sizeof(enetaddr));
+ LongLog(buf);
+
+ buflen = mir_snprintf(buf, 1500, search_request_msg, "WANPPPConnection:1");
+ sendto(sock, buf, buflen, 0, (SOCKADDR*)&enetaddr, sizeof(enetaddr));
+ LongLog(buf);
+ }
+
+ if (Miranda_Terminated()) break;
+
+ FD_ZERO(&readfd);
+ FD_SET(sock, &readfd);
+
+ while (select(1, &readfd, NULL, NULL, &tv) >= 1)
+ {
+ buflen = recv(sock, buf, 1500, 0);
+ if (buflen != SOCKET_ERROR)
+ {
+ buf[buflen] = 0;
+ LongLog(buf);
+
+ if (txtParseParam(buf, NULL, "LOCATION:", "\n", szUrl, sizeof(szUrl)) ||
+ txtParseParam(buf, NULL, "Location:", "\n", szUrl, sizeof(szUrl)))
+ {
+ char age[30];
+ char szHostNew[256], szHostExist[256];
+
+ lrtrim(szUrl);
+
+ parseURL(szUrl, szHostNew, NULL, NULL);
+ parseURL(szCtlUrl, szHostExist, NULL, NULL);
+ if (strcmp(szHostNew, szHostExist) == 0)
+ {
+ gatewayFound = true;
+ break;
+ }
+
+ txtParseParam(buf, NULL, "ST:", "\n", szDev, sizeof(szDev));
+ txtParseParam(buf, "max-age", "=", "\n", age, sizeof(age));
+ expireTime = atoi(lrtrimp(age));
+ lrtrim(szDev);
+
+ if (getUPnPURLs(szUrl, sizeof(szUrl)))
+ {
+ gatewayFound = getExtIP() != 0;
+ if (gatewayFound) break;
+ }
+ }
+ }
+ FD_ZERO(&readfd);
+ FD_SET(sock, &readfd);
+ }
+ }
+
+ mir_free(buf);
+ mir_free(ips);
+ setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF, (char *)&any, sizeof(unsigned));
+ closesocket(sock);
+}
+
+
+static bool findUPnPGateway(void)
+{
+ if ((time(NULL) - lastDiscTime) >= expireTime)
+ {
+ WaitForSingleObject(portListMutex, INFINITE);
+
+ time_t curTime = time(NULL);
+
+ if ((curTime - lastDiscTime) >= expireTime)
+ {
+ gatewayFound = false;
+
+ discoverUPnP();
+ lastDiscTime = curTime;
+
+ NetlibLogf(NULL, "UPnP Gateway detected %d, Control URL: %s", gatewayFound, szCtlUrl);
+ }
+
+ ReleaseMutex(portListMutex);
+ }
+
+ return gatewayFound;
+}
+
+bool NetlibUPnPAddPortMapping(WORD intport, char *proto, WORD *extport, DWORD *extip, bool search)
+{
+ int res = 0, i = 5;
+
+ if (findUPnPGateway())
+ {
+ char* szData = (char*)mir_alloc(4096);
+ char szExtIP[30];
+
+ *extport = intport - 1;
+ *extip = ntohl(locIP.sin_addr.S_un.S_addr);
+
+ WaitForSingleObject(portListMutex, INFINITE);
+
+ do
+ {
+ ++*extport;
+ mir_snprintf(szData, 4096, add_port_mapping,
+ *extport, proto, intport, inet_ntoa(locIP.sin_addr));
+ res = httpTransact(szCtlUrl, szData, 4096, "AddPortMapping", ControlAction);
+ txtParseParam(szData, NULL, "<errorCode>", "</errorCode>", szExtIP, sizeof(szExtIP));
+
+ }
+ while (search && res == 500 && atol(szExtIP) == 718 && --i);
+
+ mir_free(szData);
+
+ if (res == 200)
+ {
+ unsigned ip = getExtIP();
+ if (ip) *extip = ip;
+
+ if (numports >= numportsAlloc)
+ mir_realloc(portList, sizeof(WORD)*(numportsAlloc += 10));
+ portList[numports++] = *extport;
+ }
+
+ ReleaseMutex(portListMutex);
+ }
+
+ return res == 200;
+}
+
+void NetlibUPnPDeletePortMapping(WORD extport, char* proto)
+{
+ if (extport == 0)
+ return;
+
+ // findUPnPGateway();
+
+ if (gatewayFound)
+ {
+ unsigned i;
+ char* szData = (char*)mir_alloc(4096);
+
+ WaitForSingleObject(portListMutex, INFINITE);
+ mir_snprintf(szData, 4096, delete_port_mapping, extport, proto);
+ httpTransact(szCtlUrl, szData, 4096, "DeletePortMapping", ControlAction);
+
+ for (i = 0; i < numports; ++i)
+ if (portList[i] == extport && --numports > 0)
+ memmove(&portList[i], &portList[i+1], (numports - i) * sizeof(WORD));
+
+ mir_free(szData);
+ ReleaseMutex(portListMutex);
+ }
+}
+
+void NetlibUPnPCleanup(void*)
+{
+ if (DBGetContactSettingByte(NULL,"Netlib","NLEnableUPnP",1)==0)
+ // upnp is disabled globally, no need for a cleanup
+ return;
+
+ {
+ int i, incoming = 0;
+ EnterCriticalSection(&csNetlibUser);
+ for (i = 0; i < netlibUser.getCount(); ++i)
+ {
+ if (netlibUser[i]->user.flags & NUF_INCOMING)
+ {
+ incoming = 1;
+ break;
+ }
+ }
+ LeaveCriticalSection(&csNetlibUser);
+ if (!incoming) return;
+ }
+
+ if (findUPnPGateway())
+ {
+ char* szData = (char*)alloca(4096);
+ char buf[50], lip[50];
+ unsigned i, j = 0, k, num = 100;
+
+ WORD ports[30];
+
+ strcpy(lip, inet_ntoa(locIP.sin_addr));
+
+ WaitForSingleObject(portListMutex, INFINITE);
+
+ if (httpTransact(szCtlUrl, szData, 4096, "PortMappingNumberOfEntries", ControlQuery) == 200 &&
+ txtParseParam(szData, "QueryStateVariableResponse", "<return>", "<", buf, sizeof(buf)))
+ num = atol(buf);
+
+ for (i=0; i<num && !Miranda_Terminated(); ++i)
+ {
+ mir_snprintf(szData, 4096, get_port_mapping, i);
+
+ ReleaseMutex(portListMutex);
+ WaitForSingleObject(portListMutex, INFINITE);
+
+ if (httpTransact(szCtlUrl, szData, 4096, "GetGenericPortMappingEntry", ControlAction) != 200)
+ break;
+
+ if (!txtParseParam(szData, "<NewPortMappingDescription", ">", "<", buf, sizeof(buf)) || strcmp(buf, "Miranda") != 0)
+ continue;
+
+ if (!txtParseParam(szData, "<NewInternalClient", ">", "<", buf, sizeof(buf)) || strcmp(buf, lip) != 0)
+ continue;
+
+ if (txtParseParam(szData, "<NewExternalPort", ">", "<", buf, sizeof(buf)))
+ {
+ WORD mport = (WORD)atol(buf);
+
+ if (j >= SIZEOF(ports))
+ break;
+
+ for (k=0; k<numports; ++k)
+ if (portList[k] == mport)
+ break;
+
+ if (k >= numports)
+ ports[j++] = mport;
+ }
+ }
+
+ ReleaseMutex(portListMutex);
+
+ for (i=0; i<j && !Miranda_Terminated(); ++i)
+ NetlibUPnPDeletePortMapping(ports[i], "TCP");
+ }
+}
+
+void NetlibUPnPInit(void)
+{
+ numports = 0;
+ numportsAlloc = 10;
+ portList = (WORD*)mir_alloc(sizeof(WORD)*numportsAlloc);
+
+ portListMutex = CreateMutex(NULL, FALSE, NULL);
+}
+
+void NetlibUPnPDestroy(void)
+{
+ mir_free(portList);
+ CloseHandle(portListMutex);
+}
diff --git a/src/modules/options/descbutton.cpp b/src/modules/options/descbutton.cpp
new file mode 100644
index 0000000000..2e5d55c7a4
--- /dev/null
+++ b/src/modules/options/descbutton.cpp
@@ -0,0 +1,332 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2007 Artem Shpynov
+Copyright 2000-2007 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_descbutton.h"
+
+extern HINSTANCE hMirandaInst;
+
+////////////////////////////////////////////////////////////////////////////////////
+// Internals
+
+#define DBC_BORDER_SIZE 7
+#define DBC_VSPACING 15
+#define DBC_HSPACING 10
+
+static LRESULT CALLBACK MDescButtonWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+// structure is used for storing list of tab info
+typedef struct {
+ HWND hwnd;
+ BOOL bSharedIcon;
+ HICON hIcon;
+ TCHAR *lpzTitle;
+ TCHAR *lpzDescription;
+
+ // UI info
+ BOOL bMouseInside;
+ RECT rc;
+ int width, height;
+ HFONT hfntTitle;
+
+ // control colors
+ RGBQUAD rgbBkgTop, rgbBkgBottom;
+ RGBQUAD rgbSelTop, rgbSelBottom;
+ RGBQUAD rgbHotTop, rgbHotBottom;
+ COLORREF clText, clBackground;
+ COLORREF clSelText, clSelBorder;
+ COLORREF clHotText, clHotBorder;
+
+ // fonts
+ HFONT hFont;
+} MDescButtonCtrl;
+
+int LoadDescButtonModule()
+{
+ WNDCLASSEX wc;
+
+ ZeroMemory(&wc, sizeof(wc));
+ wc.cbSize = sizeof(wc);
+ wc.lpszClassName = MIRANDADESCBUTTONCLASS;
+ wc.lpfnWndProc = MDescButtonWndProc;
+ wc.hCursor = LoadCursor(NULL, IDC_HAND);
+ wc.cbWndExtra = sizeof(MDescButtonCtrl *);
+ wc.hbrBackground = 0; //GetStockObject(WHITE_BRUSH);
+ wc.style = CS_GLOBALCLASS|CS_SAVEBITS;
+ RegisterClassEx(&wc);
+ return 0;
+}
+
+static void MDescButton_SetupColors(MDescButtonCtrl *dat)
+{
+ COLORREF cl;
+
+ cl = GetSysColor(COLOR_WINDOW);
+ dat->rgbBkgBottom.rgbRed = (dat->rgbBkgTop.rgbRed = GetRValue(cl)) * .95;
+ dat->rgbBkgBottom.rgbGreen = (dat->rgbBkgTop.rgbGreen = GetGValue(cl)) * .95;
+ dat->rgbBkgBottom.rgbBlue = (dat->rgbBkgTop.rgbBlue = GetBValue(cl)) * .95;
+
+ cl = GetSysColor(COLOR_HIGHLIGHT);
+ dat->rgbSelTop.rgbRed = (dat->rgbSelBottom.rgbRed = GetRValue(cl)) * .75;
+ dat->rgbSelTop.rgbGreen = (dat->rgbSelBottom.rgbGreen = GetGValue(cl)) * .75;
+ dat->rgbSelTop.rgbBlue = (dat->rgbSelBottom.rgbBlue = GetBValue(cl)) * .75;
+
+ dat->rgbHotTop.rgbRed = (dat->rgbSelTop.rgbRed + 255) / 2;
+ dat->rgbHotTop.rgbGreen = (dat->rgbSelTop.rgbGreen + 255) / 2;
+ dat->rgbHotTop.rgbBlue = (dat->rgbSelTop.rgbBlue + 255) / 2;
+
+ dat->rgbHotBottom.rgbRed = (dat->rgbSelBottom.rgbRed + 255) / 2;
+ dat->rgbHotBottom.rgbGreen = (dat->rgbSelBottom.rgbGreen + 255) / 2;
+ dat->rgbHotBottom.rgbBlue = (dat->rgbSelBottom.rgbBlue + 255) / 2;
+
+ dat->clBackground = GetSysColor(COLOR_3DFACE);
+ dat->clText = GetSysColor(COLOR_WINDOWTEXT);
+ dat->clSelText = GetSysColor(COLOR_HIGHLIGHTTEXT);
+ dat->clSelBorder = RGB(dat->rgbSelTop.rgbRed, dat->rgbSelTop.rgbGreen, dat->rgbSelTop.rgbBlue);
+ dat->clHotBorder = RGB(dat->rgbHotTop.rgbRed, dat->rgbHotTop.rgbGreen, dat->rgbHotTop.rgbBlue);
+
+ if (!dat->hFont) dat->hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
+}
+
+static void MDescButton_FillRect(HDC hdc, int x, int y, int width, int height, COLORREF cl)
+{
+ int oldMode = SetBkMode(hdc, OPAQUE);
+ COLORREF oldColor = SetBkColor(hdc, cl);
+
+ RECT rc; SetRect(&rc, x, y, x+width, y+height);
+ ExtTextOutA(hdc, 0, 0, ETO_OPAQUE, &rc, "", 0, 0);
+
+ SetBkMode(hdc, oldMode);
+ SetBkColor(hdc, oldColor);
+}
+
+static void MDescButton_DrawGradient(HDC hdc, int x, int y, int width, int height, RGBQUAD *rgb0, RGBQUAD *rgb1)
+{
+ int oldMode = SetBkMode(hdc, OPAQUE);
+ COLORREF oldColor = SetBkColor(hdc, 0);
+
+ RECT rc; SetRect(&rc, x, 0, x+width, 0);
+ for (int i=y+height; --i >= y; ) {
+ COLORREF color = RGB(
+ ((height-i-1)*rgb0->rgbRed + i*rgb1->rgbRed) / height,
+ ((height-i-1)*rgb0->rgbGreen + i*rgb1->rgbGreen) / height,
+ ((height-i-1)*rgb0->rgbBlue + i*rgb1->rgbBlue) / height);
+ rc.top = rc.bottom = i;
+ ++rc.bottom;
+ SetBkColor(hdc, color);
+ ExtTextOutA(hdc, 0, 0, ETO_OPAQUE, &rc, "", 0, 0);
+ }
+
+ SetBkMode(hdc, oldMode);
+ SetBkColor(hdc, oldColor);
+}
+
+static LRESULT MDescButton_OnPaint(HWND hwndDlg, MDescButtonCtrl *dat, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ PAINTSTRUCT ps;
+ HBITMAP hBmp, hOldBmp;
+ RECT temprc;
+ HFONT hfntSave;
+
+ HDC hdc=BeginPaint(hwndDlg,&ps);
+ HDC tempDC=CreateCompatibleDC(hdc);
+
+ SIZE titleSize = {0};
+
+ hBmp=CreateCompatibleBitmap(hdc,dat->width, dat->height);
+ hOldBmp=(HBITMAP)SelectObject(tempDC,hBmp);
+
+ temprc.left=0;
+ temprc.right=dat->width;
+ temprc.top=0;
+
+ //Draw background
+ if (dat->bMouseInside || (GetFocus() == hwndDlg)) {
+ MDescButton_FillRect(tempDC, 0, 0, dat->width, dat->height, dat->clSelBorder);
+ MDescButton_DrawGradient(tempDC, 1, 1, dat->width-2, dat->height-2, &dat->rgbSelTop, &dat->rgbSelBottom);
+ SetTextColor(tempDC, dat->clSelText);
+ }
+ else {
+ MDescButton_FillRect(tempDC, 0, 0, dat->width, dat->height, dat->clBackground);
+ SetTextColor(tempDC, dat->clText);
+ }
+
+ if (dat->hIcon)
+ DrawIcon(tempDC, DBC_BORDER_SIZE, DBC_BORDER_SIZE, dat->hIcon);
+
+ hfntSave = (HFONT)SelectObject(tempDC, dat->hFont);
+ SetBkMode(tempDC, TRANSPARENT);
+
+ if (dat->lpzTitle) {
+ LOGFONT lf;
+ RECT textRect;
+ HFONT hfntSave;
+
+ GetObject(dat->hFont, sizeof(lf), &lf);
+ lf.lfWeight = FW_BOLD;
+ lf.lfHeight *= 1.5;
+ hfntSave = (HFONT)SelectObject(tempDC, CreateFontIndirect(&lf));
+
+ textRect.left = DBC_BORDER_SIZE + dat->hIcon ? 32 + DBC_VSPACING : 0;
+ textRect.right = dat->width - DBC_BORDER_SIZE;
+ textRect.top = DBC_BORDER_SIZE;
+ textRect.bottom = dat->height - DBC_BORDER_SIZE;
+ DrawText(tempDC, dat->lpzTitle, -1, &textRect, DT_TOP|DT_LEFT|DT_END_ELLIPSIS);
+ GetTextExtentPoint32(tempDC, dat->lpzTitle, lstrlen(dat->lpzTitle), &titleSize);
+
+ DeleteObject(SelectObject(tempDC, hfntSave));
+ }
+
+ if (dat->lpzDescription) {
+ RECT textRect;
+ textRect.left = DBC_BORDER_SIZE + dat->hIcon ? 32 + DBC_VSPACING : 0;
+ textRect.right = dat->width - DBC_BORDER_SIZE;
+ textRect.top = DBC_BORDER_SIZE + titleSize.cy ? titleSize.cy + DBC_HSPACING : 0;
+ textRect.bottom = dat->height - DBC_BORDER_SIZE;
+ DrawText(tempDC, dat->lpzDescription, -1, &textRect, DT_TOP|DT_LEFT|DT_WORDBREAK|DT_END_ELLIPSIS);
+ GetTextExtentPoint32(tempDC, dat->lpzTitle, lstrlen(dat->lpzTitle), &titleSize);
+ }
+
+ SelectObject(tempDC, hfntSave);
+
+ //Copy to output
+ BitBlt(hdc,dat->rc.left,dat->rc.top,dat->width,dat->height,tempDC,0,0,SRCCOPY);
+ SelectObject(tempDC,hOldBmp);
+ DeleteObject(hBmp);
+ DeleteDC(tempDC);
+ EndPaint(hwndDlg,&ps);
+
+ return TRUE;
+}
+
+static LRESULT CALLBACK MDescButtonWndProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ MDescButtonCtrl *dat = (MDescButtonCtrl *)GetWindowLongPtr(hwndDlg, 0);
+ switch(msg) {
+ case WM_NCCREATE:
+ dat = (MDescButtonCtrl*)mir_alloc(sizeof(MDescButtonCtrl));
+ if (dat==NULL)
+ return FALSE;
+
+ memset(dat, 0, sizeof(MDescButtonCtrl));
+ SetWindowLongPtr(hwndDlg, 0, (LONG_PTR)dat);
+ MDescButton_SetupColors(dat);
+ return TRUE;
+
+ case WM_SETFONT:
+ dat->hFont = (HFONT)wParam;
+ break;
+
+ case WM_SIZE:
+ GetClientRect(hwndDlg,&dat->rc);
+ dat->width=dat->rc.right-dat->rc.left;
+ dat->height=dat->rc.bottom-dat->rc.top;
+ return TRUE;
+
+ case WM_THEMECHANGED:
+ case WM_STYLECHANGED:
+ MDescButton_SetupColors(dat);
+ return TRUE;
+
+ case WM_MOUSEMOVE:
+ if (!dat->bMouseInside) {
+ TRACKMOUSEEVENT tme = {0};
+ tme.cbSize = sizeof(tme);
+ tme.dwFlags = TME_LEAVE;
+ tme.hwndTrack = hwndDlg;
+ _TrackMouseEvent(&tme);
+ dat->bMouseInside = TRUE;
+ RedrawWindow(hwndDlg, NULL, NULL, RDW_INVALIDATE);
+ }
+ return 0;
+
+ case WM_MOUSELEAVE:
+ dat->bMouseInside = FALSE;
+ RedrawWindow(hwndDlg, NULL, NULL, RDW_INVALIDATE);
+ return 0;
+
+ case WM_LBUTTONUP:
+ SendMessage(GetParent(hwndDlg), WM_COMMAND, MAKEWPARAM(GetWindowLongPtr(hwndDlg, GWL_ID), 0), 0);
+ return 0;
+
+ case WM_ERASEBKGND:
+ return 1;
+
+ case WM_NCPAINT:
+ InvalidateRect(hwndDlg, NULL, FALSE);
+ break;
+
+ case WM_PAINT:
+ MDescButton_OnPaint(hwndDlg, dat, msg, wParam, lParam);
+ break;
+
+ case DBCM_SETTITLE:
+ if (dat->lpzTitle)
+ mir_free(dat->lpzTitle);
+ if (wParam & MDBCF_UNICODE)
+ dat->lpzTitle = mir_u2t((WCHAR *)lParam);
+ else
+ dat->lpzTitle = mir_a2t((char *)lParam);
+ RedrawWindow(hwndDlg, NULL, NULL, RDW_INVALIDATE);
+ return TRUE;
+
+ case DBCM_SETDESCRIPTION:
+ if (dat->lpzDescription)
+ mir_free(dat->lpzDescription);
+ if (wParam & MDBCF_UNICODE)
+ dat->lpzDescription = mir_u2t((WCHAR *)lParam);
+ else
+ dat->lpzDescription = mir_a2t((char *)lParam);
+ RedrawWindow(hwndDlg, NULL, NULL, RDW_INVALIDATE);
+ return TRUE;
+
+ case DBCM_SETICON:
+ if (dat->hIcon && !dat->bSharedIcon)
+ DestroyIcon(dat->hIcon);
+
+ if (wParam & MDBCF_SHAREDICON) {
+ dat->bSharedIcon = TRUE;
+ dat->hIcon = (HICON)lParam;
+ }
+ else {
+ dat->bSharedIcon = FALSE;
+ dat->hIcon = CopyIcon((HICON)lParam);
+ }
+ RedrawWindow(hwndDlg, NULL, NULL, RDW_INVALIDATE);
+ return TRUE;
+
+ case WM_DESTROY:
+ if (dat->lpzTitle)
+ mir_free(dat->lpzTitle);
+ if (dat->lpzDescription)
+ mir_free(dat->lpzDescription);
+ if (dat->hIcon && !dat->bSharedIcon)
+ DestroyIcon(dat->hIcon);
+ mir_free(dat);
+ return TRUE;
+ }
+
+ return DefWindowProc(hwndDlg, msg, wParam, lParam);
+}
diff --git a/src/modules/options/filter.cpp b/src/modules/options/filter.cpp
new file mode 100644
index 0000000000..116899d44e
--- /dev/null
+++ b/src/modules/options/filter.cpp
@@ -0,0 +1,217 @@
+/*
+
+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 "filter.h"
+
+HANDLE hOptionsInitialize;
+
+int HookFilterEvents()
+{
+ hOptionsInitialize = HookEvent(ME_OPT_INITIALISE, OnOptionsInitialise);
+ return 0;
+}
+
+int UnhookFilterEvents()
+{
+ UnhookEvent(hOptionsInitialize);
+ return 0;
+}
+
+INT_PTR CALLBACK DlgProcOptSearch(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hWnd);
+
+ CheckDlgButton(hWnd, IDC_ENABLE_KEYWORDFILTERING, DBGetContactSettingWord(NULL, "Options", "EnableKeywordFiltering", TRUE) ? BST_CHECKED : BST_UNCHECKED);
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDC_ENABLE_KEYWORDFILTERING:
+ SendMessage(GetParent(hWnd), PSM_CHANGED,0,0);
+ break;
+ }
+ break;
+
+ case WM_SETFOCUS:
+ SetFocus(GetDlgItem(hWnd, IDC_ENABLE_KEYWORDFILTERING));
+ break;
+
+ case WM_NOTIFY:
+ switch(((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_APPLY:
+ DBWriteContactSettingWord(NULL, "Options", "EnableKeywordFiltering", IsDlgButtonChecked(hWnd, IDC_ENABLE_KEYWORDFILTERING));
+ break;
+ }
+ break;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+int OnOptionsInitialise(WPARAM wParam, LPARAM)
+{
+ OPTIONSDIALOGPAGE odp = {0};
+
+ odp.cbSize = sizeof(odp);
+ odp.position = -190000000;
+ odp.hInstance = hMirandaInst;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_KEYWORDFILTER);
+ odp.ptszTitle = TranslateT("Options search");
+ odp.ptszGroup = TranslateT("Customize");
+ odp.groupPosition = 810000000;
+ odp.flags = ODPF_BOLDGROUPS | ODPF_TCHAR;
+ odp.pfnDlgProc = DlgProcOptSearch;
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM)&odp);
+
+ return 0;
+}
+
+CPageList filterStrings(1);
+
+void AddFilterString(const PageHash key, TCHAR *data)
+{
+ if (ContainsFilterString(key, data)) return;
+
+ CPageKeywords * values = filterStrings[key];
+ if ( values == NULL ) {
+ values = new CPageKeywords( key );
+ filterStrings.insert( values );
+ }
+ values->AddKeyWord( data );
+}
+
+void ClearFilterStrings()
+{
+ filterStrings.destroy();
+}
+
+BOOL ContainsFilterString(const PageHash key, TCHAR *data)
+{
+ CPageKeywords* values = filterStrings[key];
+ return (values) ? values->ContainsString( data ) : FALSE;
+}
+
+void AddTreeViewNodes(HWND hWndDlg, PageHash key, HTREEITEM root)
+{
+ if (root) {
+ TCHAR title[2048] = {0};
+
+ TVITEM item = {0};
+ item.mask = TVIF_TEXT;
+ item.hItem = root;
+ item.pszText = title;
+ item.cchTextMax = SIZEOF(title);
+
+ if (TreeView_GetItem(hWndDlg, &item))
+ if (_tcslen(title) > 0)
+ AddFilterString(key, title);
+
+ HTREEITEM child = root;
+ while (child) {
+ child = TreeView_GetNextItem(hWndDlg, child, TVGN_CHILD);
+ AddTreeViewNodes(hWndDlg, key, child);
+ }
+
+ AddTreeViewNodes(hWndDlg, key, TreeView_GetNextSibling(hWndDlg, root));
+ }
+}
+
+void AddDialogString(HWND hWndDlg, const PageHash key)
+{
+ TCHAR title[2048];
+ GetWindowText(hWndDlg, title, SIZEOF( title ));
+ if (_tcslen(title) > 0)
+ AddFilterString(key, title);
+
+ TCHAR szClass[64];
+ GetClassName(hWndDlg,szClass, SIZEOF(szClass));
+
+ if (lstrcmpi(szClass, _T("SysTreeView32")) == 0) {
+ HTREEITEM hItem = TreeView_GetRoot(hWndDlg);
+ AddTreeViewNodes(hWndDlg, key, hItem);
+ }
+ else {
+ if (lstrcmpi(szClass, _T("listbox")) == 0) {
+ if (GetWindowStyle(hWndDlg) & LBS_HASSTRINGS) {
+ int count = ListBox_GetCount(hWndDlg);
+ for (int i = 0; i < count; i++) {
+ title[0] = 0; //safety
+ int res = ListBox_GetText(hWndDlg, i, title);
+ if (res != LB_ERR) {
+ title[SIZEOF(title) - 1] = 0;
+ if (_tcslen(title) > 0)
+ AddFilterString(key, title);
+ } } }
+ }
+ else {
+ if (lstrcmpi(szClass, _T("SysListView32")) == 0) {
+ int count = ListView_GetItemCount(hWndDlg);
+ for (int i = 0; i < count; i++) {
+ title[0] = 0; //safety
+ ListView_GetItemText(hWndDlg, i, 0, title, SIZEOF(title));
+
+ if (_tcslen(title) > 0)
+ AddFilterString(key, title);
+ } }
+
+ if (lstrcmpi(szClass, _T("combobox")) == 0) {
+ if (GetWindowStyle(hWndDlg) & CBS_HASSTRINGS) {
+ int count = ComboBox_GetCount(hWndDlg);
+ for (int i = 0; i < count; i++) {
+ title[0] = 0; //safety
+ int res = ComboBox_GetLBText(hWndDlg, i, title);
+ if (res != CB_ERR) {
+ title[SIZEOF(title) - 1] = 0;
+
+ if (_tcslen(title) > 0)
+ AddFilterString(key, title);
+} } } } } } }
+
+static BOOL CALLBACK GetDialogStringsCallback(HWND hWnd,LPARAM lParam)
+{
+ AddDialogString(hWnd, lParam);
+
+ return TRUE;
+}
+
+void GetDialogStrings(int enableKeywordFiltering, const PageHash key, TCHAR *pluginName, HWND hWnd, TCHAR * group, TCHAR * title, TCHAR * tab, TCHAR * name )
+{
+ AddFilterString(key, pluginName); //add the plugin name as keyword
+ if ( group ) AddFilterString(key, group);
+ if ( title ) AddFilterString(key, title);
+ if ( tab ) AddFilterString(key, tab);
+ if ( name ) AddFilterString(key, name);
+
+ if ((enableKeywordFiltering) && (hWnd != 0)) {
+ AddDialogString(hWnd, key);
+
+ EnumChildWindows(hWnd, GetDialogStringsCallback, (LPARAM) key);
+ }
+}
diff --git a/src/modules/options/filter.h b/src/modules/options/filter.h
new file mode 100644
index 0000000000..3db823fcdf
--- /dev/null
+++ b/src/modules/options/filter.h
@@ -0,0 +1,108 @@
+/*
+
+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.
+*/
+
+#ifndef M_OPTIONS_FILTERING_H
+#define M_OPTIONS_FILTERING_H
+
+extern HANDLE hOptionsInitialize;
+
+int HookFilterEvents();
+int UnhookFilterEvents();
+int OnOptionsInitialise(WPARAM wParam, LPARAM lParam);
+
+typedef DWORD PageHash;
+
+void AddFilterString(const PageHash key, const TCHAR *data);
+BOOL ContainsFilterString(const PageHash key, TCHAR *data);
+void ClearFilterStrings();
+void GetDialogStrings(int enableKeywordFiltering, const PageHash key, TCHAR *pluginName, HWND hWnd, TCHAR * group, TCHAR * title, TCHAR * tab, TCHAR * name );
+
+_inline TCHAR * _tcslwr_locale( TCHAR * buf )
+{
+ LCMapString( LangPackGetDefaultLocale() , LCMAP_LOWERCASE, buf, (int)_tcslen( buf ), buf, (int)_tcslen( buf ) );
+ return buf;
+}
+
+typedef LIST<TCHAR> KeywordList;
+class CPageKeywords
+{
+ PageHash _pageHashKey;
+ KeywordList _pageKeyWords;
+ static int _KeyWordsSortFunc( const TCHAR* p1, const TCHAR* p2 ) { return _tcscmp( p1, p2 ); };
+
+public:
+ CPageKeywords( PageHash pageHashKey ) : _pageHashKey( pageHashKey ), _pageKeyWords( 1, _KeyWordsSortFunc ) {};
+ ~CPageKeywords()
+ {
+ for ( int j = 0; j < _pageKeyWords.getCount(); j++ )
+ {
+ TCHAR * data = _pageKeyWords[j];
+ mir_free( data );
+ }
+ _pageKeyWords.destroy();
+ };
+
+ void AddKeyWord( TCHAR * ptKeyWord )
+ {
+ TCHAR * plwrWord = _tcslwr_locale( mir_tstrdup( ptKeyWord ) );
+ if ( _pageKeyWords.getIndex( plwrWord ) == -1 )
+ _pageKeyWords.insert( plwrWord ) ;
+ else
+ mir_free( plwrWord );
+ };
+
+ BOOL ContainsString( TCHAR * data )
+ {
+ for ( int i = 0; i < _pageKeyWords.getCount(); i++)
+ if (_tcsstr(_pageKeyWords[i], data))
+ return TRUE;
+ return FALSE;
+ }
+ static int PageSortFunc( const CPageKeywords* p1, const CPageKeywords* p2 )
+ {
+ if (p1->_pageHashKey < p2->_pageHashKey) { return -1; }
+ else if (p1->_pageHashKey > p2->_pageHashKey) { return 1; }
+ return 0;
+ }
+};
+
+class CPageList : public OBJLIST<CPageKeywords>
+{
+ CPageList();
+public:
+ CPageList( int aincr, FTSortFunc afunc = CPageKeywords::PageSortFunc ) : OBJLIST<CPageKeywords>( aincr, afunc ) {};
+ CPageKeywords * operator[]( PageHash key )
+ {
+ CPageKeywords keyToSearch( key );
+ return this->find( &keyToSearch );
+ }
+ ~CPageList() {};
+};
+
+
+
+int LangPackGetDefaultLocale();
+
+
+#endif //M_OPTIONS_FILTERING_H
+
diff --git a/src/modules/options/headerbar.cpp b/src/modules/options/headerbar.cpp
new file mode 100644
index 0000000000..a2407d2aab
--- /dev/null
+++ b/src/modules/options/headerbar.cpp
@@ -0,0 +1,372 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2007 Artem Shpynov
+Copyright 2000-2007 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_iconheader.h"
+
+extern HINSTANCE hMirandaInst;
+
+
+static BOOL IsAeroMode()
+{
+ BOOL result;
+ return dwmIsCompositionEnabled && (dwmIsCompositionEnabled(&result) == S_OK) && result;
+}
+
+static BOOL IsVSMode()
+{
+ return isThemeActive && IsWinVerVistaPlus() && isThemeActive();
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+// Internals
+
+static LRESULT CALLBACK MHeaderbarWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+// structure is used for storing list of tab info
+struct MHeaderbarCtrl
+{
+ __inline void* operator new( size_t size )
+ { return mir_calloc( size );
+ }
+ __inline void operator delete( void* p )
+ { mir_free( p );
+ }
+
+ MHeaderbarCtrl() {}
+ ~MHeaderbarCtrl() { mir_free( controlsToRedraw ); }
+
+ HWND hwnd;
+
+ // UI info
+ RECT rc;
+ int width, height;
+ HICON hIcon;
+
+ // control colors
+ RGBQUAD rgbBkgTop, rgbBkgBottom;
+ COLORREF clText;
+
+ int nControlsToRedraw;
+ HWND *controlsToRedraw;
+
+ // fonts
+ HFONT hFont;
+};
+
+int LoadHeaderbarModule()
+{
+ WNDCLASSEX wc;
+
+ ZeroMemory(&wc, sizeof(wc));
+ wc.cbSize = sizeof(wc);
+ wc.lpszClassName = _T("MHeaderbarCtrl"); //MIRANDAHEADERBARCLASS;
+ wc.lpfnWndProc = MHeaderbarWndProc;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.cbWndExtra = sizeof(MHeaderbarCtrl*);
+ wc.hbrBackground = 0; //GetStockObject(WHITE_BRUSH);
+ wc.style = CS_GLOBALCLASS|CS_SAVEBITS;
+ RegisterClassEx(&wc);
+ return 0;
+}
+
+static void MHeaderbar_SetupColors(MHeaderbarCtrl *dat)
+{
+ COLORREF cl;
+
+ cl = GetSysColor(COLOR_WINDOW);
+ dat->rgbBkgBottom.rgbRed = (dat->rgbBkgTop.rgbRed = GetRValue(cl)) * .95;
+ dat->rgbBkgBottom.rgbGreen = (dat->rgbBkgTop.rgbGreen = GetGValue(cl)) * .95;
+ dat->rgbBkgBottom.rgbBlue = (dat->rgbBkgTop.rgbBlue = GetBValue(cl)) * .95;
+
+ dat->clText = GetSysColor(COLOR_WINDOWTEXT);
+
+ if (!dat->hFont) dat->hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
+}
+
+static void MHeaderbar_FillRect(HDC hdc, int x, int y, int width, int height, COLORREF cl)
+{
+ int oldMode = SetBkMode(hdc, OPAQUE);
+ COLORREF oldColor = SetBkColor(hdc, cl);
+
+ RECT rc; SetRect(&rc, x, y, x+width, y+height);
+ ExtTextOutA(hdc, 0, 0, ETO_OPAQUE, &rc, "", 0, 0);
+
+ SetBkMode(hdc, oldMode);
+ SetBkColor(hdc, oldColor);
+}
+
+static void MHeaderbar_DrawGradient(HDC hdc, int x, int y, int width, int height, RGBQUAD *rgb0, RGBQUAD *rgb1)
+{
+ int i;
+
+ int oldMode = SetBkMode(hdc, OPAQUE);
+ COLORREF oldColor = SetBkColor(hdc, 0);
+
+ RECT rc; SetRect(&rc, x, 0, x+width, 0);
+ for (i=y+height; --i >= y; )
+ {
+ COLORREF color = RGB(
+ ((height-i-1)*rgb0->rgbRed + i*rgb1->rgbRed) / height,
+ ((height-i-1)*rgb0->rgbGreen + i*rgb1->rgbGreen) / height,
+ ((height-i-1)*rgb0->rgbBlue + i*rgb1->rgbBlue) / height);
+ rc.top = rc.bottom = i;
+ ++rc.bottom;
+ SetBkColor(hdc, color);
+ ExtTextOutA(hdc, 0, 0, ETO_OPAQUE, &rc, "", 0, 0);
+ }
+
+ SetBkMode(hdc, oldMode);
+ SetBkColor(hdc, oldColor);
+}
+
+static LRESULT MHeaderbar_OnPaint(HWND hwndDlg, MHeaderbarCtrl *mit, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ int iTopSpace = IsAeroMode() ? 0 : 3;
+ PAINTSTRUCT ps;
+ HBITMAP hBmp, hOldBmp;
+
+ int titleLength = GetWindowTextLength(hwndDlg) + 1;
+ TCHAR *szTitle = (TCHAR *)mir_alloc(sizeof(TCHAR) * titleLength);
+ GetWindowText(hwndDlg, szTitle, titleLength);
+
+ TCHAR *szSubTitle = _tcschr(szTitle, _T('\n'));
+ if (szSubTitle) *szSubTitle++ = 0;
+
+ HDC hdc=BeginPaint(hwndDlg,&ps);
+ HDC tempDC=CreateCompatibleDC(hdc);
+
+ BITMAPINFO bmi;
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.bmiHeader.biWidth = mit->width;
+ bmi.bmiHeader.biHeight = -mit->height; // we need this for DrawThemeTextEx
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ hBmp = CreateDIBSection(tempDC, &bmi, DIB_RGB_COLORS, NULL, NULL, 0);
+
+ hOldBmp=(HBITMAP)SelectObject(tempDC,hBmp);
+
+ if (IsAeroMode()) {
+ RECT temprc;
+ temprc.left=0;
+ temprc.right=mit->width;
+ temprc.top=0;
+ temprc.bottom=mit->width;
+ FillRect(tempDC, &temprc, (HBRUSH)GetStockObject(BLACK_BRUSH));
+
+ MARGINS margins = {0,0,mit->height,0};
+ dwmExtendFrameIntoClientArea(GetParent(hwndDlg), &margins);
+
+ WTA_OPTIONS opts;
+ opts.dwFlags = opts.dwMask = WTNCA_NODRAWCAPTION | WTNCA_NODRAWICON;
+ setWindowThemeAttribute(GetParent(hwndDlg), WTA_NONCLIENT, &opts, sizeof(opts));
+ }
+ else {
+ if (IsVSMode())
+ MHeaderbar_FillRect(tempDC, 0, 0, mit->width, mit->height, GetSysColor(COLOR_WINDOW));
+ else
+ MHeaderbar_DrawGradient(tempDC, 0, 0, mit->width, mit->height, &mit->rgbBkgTop, &mit->rgbBkgBottom);
+
+ MHeaderbar_FillRect(tempDC, 0, mit->height-2, mit->width, 1, GetSysColor(COLOR_BTNSHADOW));
+ MHeaderbar_FillRect(tempDC, 0, mit->height-1, mit->width, 1, GetSysColor(COLOR_BTNHIGHLIGHT));
+ }
+
+ HFONT hFont = mit->hFont;
+ SetBkMode(tempDC, TRANSPARENT);
+ SetTextColor(tempDC, mit->clText);
+
+ LOGFONT lf;
+ GetObject(hFont, sizeof(lf), &lf);
+ lf.lfWeight = FW_BOLD;
+ HFONT hFntBold = CreateFontIndirect(&lf);
+
+ if (mit->hIcon)
+ DrawIcon(tempDC, 10, iTopSpace, mit->hIcon);
+ else {
+ HICON hIcon = (HICON)SendMessage(GetParent(hwndDlg), WM_GETICON, ICON_BIG, 0);
+ if (hIcon == NULL)
+ hIcon = (HICON)SendMessage(GetParent(hwndDlg), WM_GETICON, ICON_SMALL, 0);
+ DrawIcon(tempDC, 10, iTopSpace, hIcon);
+ }
+
+ RECT textRect;
+ textRect.left=50;
+ textRect.right=mit->width;
+ textRect.top=2 + iTopSpace;
+ textRect.bottom=GetSystemMetrics(SM_CYICON)-2 + iTopSpace;
+
+ if (IsAeroMode()) {
+ DTTOPTS dto = {0};
+ dto.dwSize = sizeof(dto);
+ dto.dwFlags = DTT_COMPOSITED|DTT_GLOWSIZE;
+ dto.iGlowSize = 10;
+
+ HANDLE hTheme = openThemeData(hwndDlg, L"Window");
+ textRect.left=50;
+ SelectObject(tempDC, hFntBold);
+
+ wchar_t *szTitleW = mir_t2u(szTitle);
+ drawThemeTextEx(hTheme, tempDC, WP_CAPTION, CS_ACTIVE, szTitleW, -1, DT_TOP|DT_LEFT|DT_SINGLELINE|DT_NOPREFIX|DT_NOCLIP|DT_END_ELLIPSIS, &textRect, &dto);
+ mir_free(szTitleW);
+
+ if (szSubTitle) {
+ textRect.left=66;
+ SelectObject(tempDC, hFont);
+
+ wchar_t *szSubTitleW = mir_t2u(szSubTitle);
+ drawThemeTextEx(hTheme, tempDC, WP_CAPTION, CS_ACTIVE, szSubTitleW, -1, DT_BOTTOM|DT_LEFT|DT_SINGLELINE|DT_NOPREFIX|DT_NOCLIP|DT_END_ELLIPSIS, &textRect, &dto);
+ mir_free(szSubTitleW);
+ }
+ closeThemeData(hTheme);
+ }
+ else {
+ textRect.left=50;
+ SelectObject(tempDC, hFntBold);
+ DrawText(tempDC, szTitle, -1, &textRect, DT_TOP|DT_LEFT|DT_SINGLELINE|DT_NOPREFIX|DT_NOCLIP|DT_END_ELLIPSIS);
+
+ if (szSubTitle) {
+ textRect.left=66;
+ SelectObject(tempDC, hFont);
+ DrawText(tempDC, szSubTitle, -1, &textRect, DT_BOTTOM|DT_LEFT|DT_SINGLELINE|DT_NOPREFIX|DT_NOCLIP|DT_END_ELLIPSIS);
+ } }
+
+ DeleteObject(hFntBold);
+
+ mir_free(szTitle);
+
+ //Copy to output
+ if (mit->nControlsToRedraw)
+ {
+ RECT temprc;
+ temprc.left=0;
+ temprc.right=mit->width;
+ temprc.top=0;
+ temprc.bottom=mit->width;
+ HRGN hRgn = CreateRectRgnIndirect(&temprc);
+
+ for (int i = 0; i < mit->nControlsToRedraw; ++i)
+ {
+ GetWindowRect(mit->controlsToRedraw[i], &temprc);
+ MapWindowPoints(NULL, hwndDlg, (LPPOINT)&temprc, 2);
+ HRGN hRgnTmp = CreateRectRgnIndirect(&temprc);
+ CombineRgn(hRgn, hRgn, hRgnTmp, RGN_DIFF);
+ DeleteObject(hRgnTmp);
+ }
+ SelectClipRgn(hdc,hRgn);
+ DeleteObject(hRgn);
+ }
+
+ BitBlt(hdc,mit->rc.left,mit->rc.top,mit->width,mit->height,tempDC,0,0,SRCCOPY);
+
+ SelectClipRgn(hdc,NULL);
+
+ SelectObject(tempDC,hOldBmp);
+ DeleteObject(hBmp);
+ DeleteDC(tempDC);
+
+ EndPaint(hwndDlg,&ps);
+
+ return TRUE;
+}
+
+static LRESULT CALLBACK MHeaderbarWndProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ MHeaderbarCtrl* itc = (MHeaderbarCtrl *)GetWindowLongPtr(hwndDlg, 0);
+ switch(msg) {
+ case WM_NCCREATE:
+ itc = new MHeaderbarCtrl; //(MHeaderbarCtrl*)mir_alloc(sizeof(MHeaderbarCtrl));
+ if (itc==NULL)
+ return FALSE;
+
+ SetWindowLongPtr(hwndDlg, 0, (LONG_PTR)itc);
+ MHeaderbar_SetupColors(itc);
+
+ { HWND hParent = GetParent(hwndDlg);
+ RECT rcWnd; GetWindowRect(hwndDlg, &rcWnd);
+ itc->controlsToRedraw = 0;
+ itc->nControlsToRedraw = 0;
+ for (HWND hChild = FindWindowEx(hParent, NULL, NULL, NULL); hChild; hChild = FindWindowEx(hParent, hChild, NULL, NULL))
+ {
+ if (hChild != hwndDlg)
+ {
+ RECT rcChild; GetWindowRect(hChild, &rcChild);
+ RECT rc;
+ IntersectRect(&rc, &rcChild, &rcWnd);
+ if (!IsRectEmpty(&rc))
+ {
+ ++itc->nControlsToRedraw;
+ itc->controlsToRedraw = (HWND *)mir_realloc(itc->controlsToRedraw, sizeof(HWND) * itc->nControlsToRedraw);
+ itc->controlsToRedraw[itc->nControlsToRedraw - 1] = hChild;
+ }
+ }
+ }
+ }
+
+ break;
+
+ case WM_SETFONT:
+ itc->hFont = (HFONT)wParam;
+ break;
+
+ case WM_SIZE:
+ GetClientRect(hwndDlg,&itc->rc);
+ itc->width=itc->rc.right-itc->rc.left;
+ itc->height=itc->rc.bottom-itc->rc.top;
+ return TRUE;
+
+ case WM_THEMECHANGED:
+ case WM_STYLECHANGED:
+ MHeaderbar_SetupColors(itc);
+ return TRUE;
+
+ case WM_LBUTTONDOWN:
+ SendMessage(GetParent(hwndDlg), WM_SYSCOMMAND, 0xF012, 0);
+ return 0;
+
+ case WM_SETICON:
+ if (wParam < 3) {
+ itc->hIcon = (HICON)lParam;
+ InvalidateRect(hwndDlg, NULL, FALSE);
+ }
+ break;
+
+ case WM_ERASEBKGND:
+ return 1;
+
+ case WM_NCPAINT:
+ InvalidateRect(hwndDlg, NULL, FALSE);
+ break;
+
+ case WM_PAINT:
+ MHeaderbar_OnPaint(hwndDlg, itc, msg, wParam, lParam);
+ break;
+
+ case WM_DESTROY:
+ delete itc;
+ break;
+ }
+ return DefWindowProc(hwndDlg, msg, wParam, lParam);
+}
diff --git a/src/modules/options/iconheader.cpp b/src/modules/options/iconheader.cpp
new file mode 100644
index 0000000000..9ab44b0852
--- /dev/null
+++ b/src/modules/options/iconheader.cpp
@@ -0,0 +1,545 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2007 Artem Shpynov
+Copyright 2000-2007 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_iconheader.h"
+
+
+extern HINSTANCE hMirandaInst;
+
+static BOOL IsAeroMode()
+{
+ BOOL result;
+ return dwmIsCompositionEnabled && (dwmIsCompositionEnabled(&result) == S_OK) && result;
+}
+
+static BOOL IsVSMode()
+{
+ return isThemeActive && IsWinVerVistaPlus() && isThemeActive();
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+// Internals
+
+#define ITC_BORDER_SIZE 3
+
+static LRESULT CALLBACK MIcoTabWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+// structure is used for storing list of tab info
+struct MIcoTabCtrl
+{
+ __inline void* operator new( size_t size )
+ { return mir_calloc( size );
+ }
+ __inline void operator delete( void* p )
+ { mir_free( p );
+ }
+
+ MIcoTabCtrl(): pList(1) {}
+
+ HWND hwnd;
+ int nSelectedIdx, nHotIdx;
+ LIST<MIcoTab> pList;
+
+ // UI info
+ BOOL bMouseInside;
+ RECT rc;
+ int width, height;
+ int itemWidth, itemHeight;
+
+ //background bitmap
+ HBITMAP hBkgBmp;
+ HBITMAP hBkgOldBmp;
+ HDC hBkgDC;
+ SIZE BkgSize;
+
+ // control colors
+ RGBQUAD rgbBkgTop, rgbBkgBottom;
+ RGBQUAD rgbSelTop, rgbSelBottom;
+ RGBQUAD rgbHotTop, rgbHotBottom;
+ COLORREF clText;
+ COLORREF clSelText, clSelBorder;
+ COLORREF clHotText, clHotBorder;
+
+ // fonts
+ HFONT hFont;
+};
+
+typedef void (*ItemDestuctor)(void*);
+
+static void MITListDestructor(void * adr)
+{
+ MIcoTab * mit=(MIcoTab *)adr;
+ mir_free(mit->tcsName);
+ if (mit->hIcon && !(mit->flag&MITCF_SHAREDICON))
+ DestroyIcon(mit->hIcon);
+ mir_free(adr);
+}
+
+void li_ListDestruct(LIST<MIcoTab> &pList, ItemDestuctor pItemDestructor)
+{
+ for (int i=0; i<pList.getCount(); i++) pItemDestructor(pList[i]);
+ pList.destroy();
+}
+
+int LoadIcoTabsModule()
+{
+ WNDCLASSEX wc;
+
+ ZeroMemory(&wc, sizeof(wc));
+ wc.cbSize = sizeof(wc);
+ wc.lpszClassName = MIRANDAICOTABCLASS;
+ wc.lpfnWndProc = MIcoTabWndProc;
+// wc.hCursor = LoadCursor(NULL, IDC_HAND);
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.cbWndExtra = sizeof(MIcoTabCtrl*);
+ wc.hbrBackground = 0; //GetStockObject(WHITE_BRUSH);
+ wc.style = CS_GLOBALCLASS/*|CS_SAVEBITS*/;
+ RegisterClassEx(&wc);
+ return 0;
+}
+
+static void MIcoTab_SetupColors(MIcoTabCtrl *dat)
+{
+ COLORREF cl;
+
+ cl = GetSysColor(COLOR_WINDOW);
+ dat->rgbBkgBottom.rgbRed = (dat->rgbBkgTop.rgbRed = GetRValue(cl)) * .95;
+ dat->rgbBkgBottom.rgbGreen = (dat->rgbBkgTop.rgbGreen = GetGValue(cl)) * .95;
+ dat->rgbBkgBottom.rgbBlue = (dat->rgbBkgTop.rgbBlue = GetBValue(cl)) * .95;
+
+ cl = GetSysColor(COLOR_HIGHLIGHT);
+ dat->rgbSelTop.rgbRed = (dat->rgbSelBottom.rgbRed = GetRValue(cl)) * .75;
+ dat->rgbSelTop.rgbGreen = (dat->rgbSelBottom.rgbGreen = GetGValue(cl)) * .75;
+ dat->rgbSelTop.rgbBlue = (dat->rgbSelBottom.rgbBlue = GetBValue(cl)) * .75;
+
+ dat->rgbHotTop.rgbRed = (dat->rgbSelTop.rgbRed + 255) / 2;
+ dat->rgbHotTop.rgbGreen = (dat->rgbSelTop.rgbGreen + 255) / 2;
+ dat->rgbHotTop.rgbBlue = (dat->rgbSelTop.rgbBlue + 255) / 2;
+
+ dat->rgbHotBottom.rgbRed = (dat->rgbSelBottom.rgbRed + 255) / 2;
+ dat->rgbHotBottom.rgbGreen = (dat->rgbSelBottom.rgbGreen + 255) / 2;
+ dat->rgbHotBottom.rgbBlue = (dat->rgbSelBottom.rgbBlue + 255) / 2;
+
+ dat->clText = GetSysColor(COLOR_WINDOWTEXT);
+ dat->clSelText = GetSysColor(COLOR_HIGHLIGHTTEXT);
+ dat->clSelBorder = RGB(dat->rgbSelTop.rgbRed, dat->rgbSelTop.rgbGreen, dat->rgbSelTop.rgbBlue);
+ dat->clHotBorder = RGB(dat->rgbHotTop.rgbRed, dat->rgbHotTop.rgbGreen, dat->rgbHotTop.rgbBlue);
+
+ if (!dat->hFont) dat->hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
+}
+
+static void MIcoTab_FillRect(HDC hdc, int x, int y, int width, int height, COLORREF cl)
+{
+ int oldMode = SetBkMode(hdc, OPAQUE);
+ COLORREF oldColor = SetBkColor(hdc, cl);
+
+ RECT rc; SetRect(&rc, x, y, x+width, y+height);
+ ExtTextOutA(hdc, 0, 0, ETO_OPAQUE, &rc, "", 0, 0);
+
+ SetBkMode(hdc, oldMode);
+ SetBkColor(hdc, oldColor);
+}
+
+static void MIcoTab_DrawGradient(HDC hdc, int x, int y, int width, int height, RGBQUAD *rgb0, RGBQUAD *rgb1)
+{
+ int oldMode = SetBkMode(hdc, OPAQUE);
+ COLORREF oldColor = SetBkColor(hdc, 0);
+
+ RECT rc; SetRect(&rc, x, 0, x+width, 0);
+ for ( int i=y+height; --i >= y; ) {
+ COLORREF color = RGB(
+ ((height-i-1)*rgb0->rgbRed + i*rgb1->rgbRed) / height,
+ ((height-i-1)*rgb0->rgbGreen + i*rgb1->rgbGreen) / height,
+ ((height-i-1)*rgb0->rgbBlue + i*rgb1->rgbBlue) / height);
+ rc.top = rc.bottom = i;
+ ++rc.bottom;
+ SetBkColor(hdc, color);
+ ExtTextOutA(hdc, 0, 0, ETO_OPAQUE, &rc, "", 0, 0);
+ }
+
+ SetBkMode(hdc, oldMode);
+ SetBkColor(hdc, oldColor);
+}
+
+static void MIcoTab_DrawItem(HWND hwnd, HDC hdc, MIcoTabCtrl *dat, MIcoTab *tab, int i)
+{
+ int iTopSpace = IsAeroMode() ? 0 : ITC_BORDER_SIZE;
+ int itemX = ITC_BORDER_SIZE + dat->itemWidth * i;
+ int iconTop = iTopSpace + 5;
+ int textTop = iconTop + 32 + 3;
+
+ HFONT hFntSave = NULL;
+
+ if (dat->nSelectedIdx == i) {
+ LOGFONT lf;
+ GetObject(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf);
+ lf.lfWeight = FW_BOLD;
+ hFntSave = (HFONT)SelectObject(hdc, CreateFontIndirect(&lf));
+
+ if (IsVSMode()) {
+ RECT rc;
+ rc.left = itemX;
+ rc.top = iTopSpace;
+ rc.right = itemX + dat->itemWidth;
+ rc.bottom = iTopSpace + dat->itemHeight;
+ HANDLE hTheme = openThemeData(hwnd, L"ListView");
+ if (dat->nHotIdx == i || GetFocus() == hwnd)
+ drawThemeBackground(hTheme, hdc, LVP_LISTITEM, LISS_HOTSELECTED, &rc, NULL);
+ else
+ drawThemeBackground(hTheme, hdc, LVP_LISTITEM, LISS_SELECTED, &rc, NULL);
+
+ closeThemeData(hTheme);
+ }
+ else {
+ MIcoTab_FillRect(hdc, itemX, ITC_BORDER_SIZE, dat->itemWidth, dat->itemHeight, dat->clSelBorder);
+ MIcoTab_DrawGradient(hdc, itemX+1, ITC_BORDER_SIZE+1, dat->itemWidth-2, dat->itemHeight-2, &dat->rgbSelTop, &dat->rgbSelBottom);
+ }
+ SetTextColor(hdc, dat->clSelText);
+ }
+ else if (dat->nHotIdx == i) {
+ if (IsVSMode()) {
+ RECT rc;
+ rc.left = itemX;
+ rc.top = iTopSpace;
+ rc.right = itemX + dat->itemWidth;
+ rc.bottom = iTopSpace + dat->itemHeight;
+ setWindowTheme(hwnd, L"explorer", NULL);
+ HANDLE hTheme = openThemeData(hwnd, L"ListView");
+ drawThemeBackground(hTheme, hdc, LVP_LISTITEM, LISS_HOT, &rc, NULL);
+ closeThemeData(hTheme);
+ }
+ else {
+ MIcoTab_FillRect(hdc, itemX, ITC_BORDER_SIZE, dat->itemWidth, dat->itemHeight, dat->clHotBorder);
+ MIcoTab_DrawGradient(hdc, itemX+1, ITC_BORDER_SIZE+1, dat->itemWidth-2, dat->itemHeight-2, &dat->rgbHotTop, &dat->rgbHotBottom);
+ }
+ SetTextColor(hdc, dat->clHotText);
+ }
+ else SetTextColor(hdc, dat->clText);
+
+ RECT textRect;
+ textRect.left=itemX;
+ textRect.right=itemX+dat->itemWidth;
+ textRect.top=textTop;
+ textRect.bottom=iconTop+dat->itemHeight;
+ DrawIcon(hdc,itemX+dat->itemWidth/2-16, iconTop, tab->hIcon);
+
+ if (IsVSMode()) {
+ DTTOPTS dto = {0};
+ dto.dwSize = sizeof(dto);
+ dto.dwFlags = DTT_COMPOSITED|DTT_GLOWSIZE;
+ dto.iGlowSize = 10;
+ HANDLE hTheme = openThemeData(hwnd, L"Window");
+ wchar_t *tcsNameW = mir_t2u(tab->tcsName);
+ drawThemeTextEx(hTheme, hdc, WP_CAPTION, CS_ACTIVE, tcsNameW, -1, DT_VCENTER|DT_CENTER|DT_END_ELLIPSIS, &textRect, &dto);
+ mir_free(tcsNameW);
+ closeThemeData(hTheme);
+ }
+ else DrawText(hdc,tab->tcsName,-1,&textRect, DT_VCENTER|DT_CENTER|DT_END_ELLIPSIS);
+
+ if (hFntSave)
+ DeleteObject(SelectObject(hdc, hFntSave));
+}
+
+static LRESULT MIcoTab_OnPaint(HWND hwndDlg, MIcoTabCtrl *mit, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ PAINTSTRUCT ps;
+ HBITMAP hBmp, hOldBmp;
+ RECT temprc;
+ int i;
+
+ HDC hdc=BeginPaint(hwndDlg,&ps);
+ HDC tempDC=CreateCompatibleDC(hdc);
+
+ HFONT hFont = 0;
+
+ BITMAPINFO bmi;
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.bmiHeader.biWidth = mit->width;
+ bmi.bmiHeader.biHeight = -mit->height; // we need this for DrawThemeTextEx
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ hBmp = CreateDIBSection(tempDC, &bmi, DIB_RGB_COLORS, NULL, NULL, 0);
+
+ hOldBmp=(HBITMAP)SelectObject(tempDC,hBmp);
+
+ if (IsAeroMode()) {
+ temprc.left=0;
+ temprc.right=mit->width;
+ temprc.top=0;
+ temprc.bottom=mit->width;
+ FillRect(tempDC, &temprc, (HBRUSH)GetStockObject(BLACK_BRUSH));
+ }
+ else {
+ if (mit->hBkgBmp)
+ StretchBlt(tempDC,0,0,mit->width,mit->height,mit->hBkgDC,0,0,mit->BkgSize.cx,mit->BkgSize.cy,SRCCOPY);
+ else {
+ if (IsVSMode())
+ MIcoTab_FillRect(tempDC, 0, 0, mit->width, mit->height, GetSysColor(COLOR_WINDOW));
+ else
+ MIcoTab_DrawGradient(tempDC, 0, 0, mit->width, mit->height, &mit->rgbBkgTop, &mit->rgbBkgBottom);
+
+ MIcoTab_FillRect(tempDC, 0, mit->height-2, mit->width, 1, GetSysColor(COLOR_BTNSHADOW));
+ MIcoTab_FillRect(tempDC, 0, mit->height-1, mit->width, 1, GetSysColor(COLOR_BTNHIGHLIGHT));
+ } }
+
+ //Draw Items
+ hFont = mit->hFont;
+ SelectObject(tempDC,hFont);
+ SetBkMode(tempDC,TRANSPARENT);
+
+ for (i=0; i<mit->pList.getCount(); i++) {
+ MIcoTab *tab = (MIcoTab *)mit->pList[i];
+ MIcoTab_DrawItem(hwndDlg, tempDC, mit, tab, i);
+ }
+
+ //Copy to output
+ BitBlt(hdc,mit->rc.left,mit->rc.top,mit->width,mit->height,tempDC,0,0,SRCCOPY);
+ SelectObject(tempDC,hOldBmp);
+ DeleteObject(hBmp);
+ DeleteDC(tempDC);
+
+ EndPaint(hwndDlg,&ps);
+
+ return TRUE;
+}
+
+static LRESULT CALLBACK MIcoTabWndProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ MIcoTabCtrl* itc = (MIcoTabCtrl *)GetWindowLongPtr(hwndDlg, 0);
+ switch(msg) {
+ case WM_NCCREATE:
+ itc = new MIcoTabCtrl; //(MIcoTabCtrl*)mir_alloc(sizeof(MIcoTabCtrl));
+ if (itc==NULL) return FALSE;
+ itc->nSelectedIdx=-1;
+ itc->nHotIdx=-1;
+ itc->bMouseInside = FALSE;
+ SetWindowLongPtr(hwndDlg, 0, (LONG_PTR)itc);
+ MIcoTab_SetupColors(itc);
+
+ if (IsAeroMode()) {
+ RECT rc; GetWindowRect(hwndDlg, &rc);
+ MARGINS margins = {0,0,rc.bottom-rc.top,0};
+ dwmExtendFrameIntoClientArea(GetParent(hwndDlg), &margins);
+ }
+
+ return TRUE;
+
+ case WM_SETFONT:
+ itc->hFont = (HFONT)wParam;
+ break;
+
+ case WM_SIZE:
+ GetClientRect(hwndDlg,&itc->rc);
+ itc->width=itc->rc.right-itc->rc.left;
+ itc->height=itc->rc.bottom-itc->rc.top;
+
+ if (itc->pList.getCount()) {
+ itc->itemWidth=(itc->width-2*ITC_BORDER_SIZE)/itc->pList.getCount();
+ itc->itemHeight=itc->height-2*ITC_BORDER_SIZE-2;
+ }
+ else itc->itemWidth = itc->itemHeight = 0;
+ return TRUE;
+
+ case WM_THEMECHANGED:
+ case WM_STYLECHANGED:
+ MIcoTab_SetupColors(itc);
+ return TRUE;
+
+ case WM_MOUSEMOVE:
+ if (!itc->bMouseInside) {
+ TRACKMOUSEEVENT tme = {0};
+ tme.cbSize = sizeof(tme);
+ tme.dwFlags = TME_LEAVE;
+ tme.hwndTrack = hwndDlg;
+ _TrackMouseEvent(&tme);
+ itc->bMouseInside = TRUE;
+ }
+
+ itc->nHotIdx = (LOWORD(lParam) - ITC_BORDER_SIZE) / itc->itemWidth;
+ if (itc->nHotIdx >= itc->pList.getCount())
+ itc->nHotIdx = -1;
+ RedrawWindow(hwndDlg, NULL, NULL, RDW_INVALIDATE);
+ return 0;
+
+ case WM_MOUSELEAVE:
+ itc->bMouseInside = FALSE;
+ itc->nHotIdx = -1;
+ RedrawWindow(hwndDlg, NULL, NULL, RDW_INVALIDATE);
+ return 0;
+
+ case WM_LBUTTONUP:
+ if ((itc->nHotIdx >= 0) && (itc->nHotIdx != itc->nSelectedIdx))
+ {
+ itc->nSelectedIdx = itc->nHotIdx;
+ SetWindowText(hwndDlg, itc->pList[itc->nSelectedIdx]->tcsName);
+ RedrawWindow(hwndDlg, NULL, NULL, RDW_INVALIDATE);
+ SendMessage(GetParent(hwndDlg), WM_COMMAND,
+ MAKEWPARAM(GetWindowLongPtr(hwndDlg, GWL_ID), ITCN_SELCHANGED),
+ itc->nSelectedIdx);
+ }
+ return 0;
+
+ case WM_SETFOCUS:
+ case WM_KILLFOCUS:
+ RedrawWindow(hwndDlg, NULL, NULL, RDW_INVALIDATE);
+ break;
+
+ case WM_MOUSEACTIVATE:
+ SetFocus(hwndDlg);
+ return MA_ACTIVATE;
+
+ case WM_GETDLGCODE:
+ {
+ if (lParam)
+ {
+ MSG *msg = (MSG *) lParam;
+ if (msg->message == WM_KEYDOWN)
+ {
+ if (msg->wParam == VK_TAB)
+ return 0;
+ if (msg->wParam == VK_ESCAPE)
+ return 0;
+ } else
+ if (msg->message == WM_CHAR)
+ {
+ if (msg->wParam == '\t')
+ return 0;
+ if (msg->wParam == 27)
+ return 0;
+ }
+ }
+ return DLGC_WANTMESSAGE;
+ }
+
+ case WM_KEYDOWN:
+ {
+ int newIdx = itc->nSelectedIdx;
+ switch (wParam)
+ {
+ case VK_NEXT:
+ case VK_RIGHT:
+ newIdx++;
+ break;
+ case VK_PRIOR:
+ case VK_LEFT:
+ newIdx--;
+ break;
+ }
+ if ((newIdx >= 0) && (newIdx < itc->pList.getCount()) && (newIdx != itc->nSelectedIdx))
+ {
+ itc->nSelectedIdx = newIdx;
+ SetWindowText(hwndDlg, itc->pList[itc->nSelectedIdx]->tcsName);
+ RedrawWindow(hwndDlg, NULL, NULL, RDW_INVALIDATE);
+ SendMessage(GetParent(hwndDlg), WM_COMMAND,
+ MAKEWPARAM(GetWindowLongPtr(hwndDlg, GWL_ID), ITCN_SELCHANGEDKBD),
+ itc->nSelectedIdx);
+ }
+ return 0;
+ }
+
+ case WM_ERASEBKGND:
+ return 1;
+
+ case WM_NCPAINT:
+ InvalidateRect(hwndDlg, NULL, FALSE);
+ break;
+
+ case WM_PAINT:
+ MIcoTab_OnPaint(hwndDlg, itc, msg, wParam, lParam);
+ break;
+
+ case ITCM_SETBACKGROUND:
+ itc->hBkgBmp=(HBITMAP)lParam;
+ if (!itc->hBkgDC)
+ itc->hBkgDC = CreateCompatibleDC(NULL);
+ itc->hBkgOldBmp = (HBITMAP)SelectObject(itc->hBkgDC, itc->hBkgBmp);
+ {
+ BITMAPINFO bmp;
+ GetObject(itc->hBkgBmp, sizeof(bmp), &bmp);
+ itc->BkgSize.cx=bmp.bmiHeader.biWidth;
+ itc->BkgSize.cy=bmp.bmiHeader.biHeight;
+ }
+ return TRUE;
+
+ case ITCM_ADDITEM:
+ {
+ MIcoTab* pMit=(MIcoTab *)wParam;
+ if (!pMit)
+ return FALSE;
+
+ MIcoTab* pListMit=(MIcoTab *)mir_calloc(sizeof(MIcoTab));
+ pListMit->flag=pMit->flag;
+ pListMit->data=pMit->data;
+ if (pMit->flag & MITCF_UNICODE)
+ pListMit->tcsName=mir_u2t(pMit->lpwzName);
+ else
+ pListMit->tcsName=mir_a2t(pMit->lpzName);
+ if (pMit->hIcon) {
+ if (pListMit->flag&MITCF_SHAREDICON)
+ pListMit->hIcon=pMit->hIcon;
+ else
+ pListMit->hIcon=CopyIcon(pMit->hIcon);
+ }
+ itc->pList.insert(pListMit);
+
+ itc->itemWidth=(itc->width-2*ITC_BORDER_SIZE)/itc->pList.getCount();
+ itc->itemHeight=itc->height-2*ITC_BORDER_SIZE-2;
+
+ RedrawWindow(hwndDlg, NULL, NULL, RDW_INVALIDATE);
+ return TRUE;
+ }
+
+ case ITCM_SETSEL:
+ if ( wParam >= 0 && (int)wParam < itc->pList.getCount()) {
+ itc->nSelectedIdx = wParam;
+ SetWindowText(hwndDlg, itc->pList[itc->nSelectedIdx]->tcsName);
+ RedrawWindow(hwndDlg, NULL, NULL, RDW_INVALIDATE);
+ SendMessage(GetParent(hwndDlg), WM_COMMAND,
+ MAKEWPARAM(GetWindowLongPtr(hwndDlg, GWL_ID), ITCN_SELCHANGED),
+ itc->nSelectedIdx);
+ }
+ return TRUE;
+
+ case ITCM_GETSEL:
+ return itc->nSelectedIdx;
+
+ case ITCM_GETITEMDATA:
+ if ( wParam >= 0 && (int)wParam < itc->pList.getCount())
+ return ((MIcoTab *)itc->pList[wParam])->data;
+ return 0;
+
+ case WM_DESTROY:
+ if (itc->hBkgDC) {
+ SelectObject(itc->hBkgDC, itc->hBkgOldBmp);
+ DeleteDC(itc->hBkgDC);
+ }
+ li_ListDestruct(itc->pList,MITListDestructor);
+ delete itc;
+ return TRUE;
+ }
+ return DefWindowProc(hwndDlg, msg, wParam, lParam);
+}
diff --git a/src/modules/options/options.cpp b/src/modules/options/options.cpp
new file mode 100644
index 0000000000..0366d99062
--- /dev/null
+++ b/src/modules/options/options.cpp
@@ -0,0 +1,1521 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2010 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 "filter.h"
+
+#define OPENOPTIONSDIALOG_OLD_SIZE 12
+
+#define FILTER_TIMEOUT_TIMER 10012
+
+#define ALL_MODULES_FILTER _T("<all modules>")
+#define CORE_MODULES_FILTER _T("<core modules>")
+
+static HANDLE hOptionsInitEvent;
+static HWND hwndOptions=NULL;
+static HWND hFilterSearchWnd = NULL;
+
+// Thread for search keywords in dialogs
+static BYTE bSearchState = 0; // 0 - not executed; 1 - in progress; 2 - completed;
+static int FilterPage = 0;
+static int FilterLoadProgress = 100;
+static int FilterTimerId = 0;
+
+char * GetPluginNameByInstance( HINSTANCE hInstance );
+
+struct OptionsPageInit
+{
+ int pageCount;
+ OPTIONSDIALOGPAGE *odp;
+};
+
+struct DlgTemplateExBegin
+{
+ WORD dlgVer;
+ WORD signature;
+ DWORD helpID;
+ DWORD exStyle;
+ DWORD style;
+ WORD cDlgItems;
+ short x;
+ short y;
+ short cx;
+ short cy;
+};
+
+struct OptionsPageData
+{
+ DLGTEMPLATE *pTemplate;
+ DLGPROC dlgProc;
+ HINSTANCE hInst;
+ HTREEITEM hTreeItem;
+ HWND hwnd;
+ int changed;
+ int simpleHeight,expertHeight;
+ int simpleWidth,expertWidth;
+ int simpleBottomControlId,simpleRightControlId;
+ int nExpertOnlyControls;
+ UINT *expertOnlyControls;
+ DWORD flags;
+ TCHAR *pszTitle, *pszGroup, *pszTab;
+ BOOL insideTab;
+ LPARAM dwInitParam;
+
+ int offsetX;
+ int offsetY;
+};
+
+struct OptionsDlgData
+{
+ int pageCount;
+ int currentPage;
+ HTREEITEM hCurrentPage;
+ struct OptionsPageData *opd;
+ RECT rcDisplay;
+ RECT rcTab;
+ HFONT hBoldFont;
+ TCHAR szFilterString[1024];
+};
+
+static HTREEITEM FindNamedTreeItemAtRoot(HWND hwndTree, const TCHAR* name)
+{
+ TVITEM tvi;
+ TCHAR str[128];
+
+ tvi.mask = TVIF_TEXT;
+ tvi.pszText = str;
+ tvi.cchTextMax = SIZEOF( str );
+ tvi.hItem = TreeView_GetRoot( hwndTree );
+ while( tvi.hItem != NULL ) {
+ SendMessage( hwndTree, TVM_GETITEM, 0, (LPARAM)&tvi );
+ if( !_tcsicmp( str,name ))
+ return tvi.hItem;
+
+ tvi.hItem = TreeView_GetNextSibling( hwndTree, tvi.hItem );
+ }
+ return NULL;
+}
+
+static HTREEITEM FindNamedTreeItemAtChildren(HWND hwndTree, HTREEITEM hItem, const TCHAR* name)
+{
+ TVITEM tvi;
+ TCHAR str[128];
+
+ tvi.mask = TVIF_TEXT;
+ tvi.pszText = str;
+ tvi.cchTextMax = SIZEOF( str );
+ tvi.hItem = TreeView_GetChild( hwndTree, hItem );
+ while( tvi.hItem != NULL ) {
+ SendMessage( hwndTree, TVM_GETITEM, 0, (LPARAM)&tvi );
+ if( !_tcsicmp( str,name ))
+ return tvi.hItem;
+
+ tvi.hItem = TreeView_GetNextSibling( hwndTree, tvi.hItem );
+ }
+ return NULL;
+}
+
+static BOOL CALLBACK BoldGroupTitlesEnumChildren(HWND hwnd,LPARAM lParam)
+{
+ TCHAR szClass[64];
+
+ GetClassName(hwnd,szClass,SIZEOF(szClass));
+ if(!lstrcmp(szClass,_T("Button")) && (GetWindowLongPtr(hwnd,GWL_STYLE)&0x0F)==BS_GROUPBOX)
+ SendMessage(hwnd,WM_SETFONT,lParam,0);
+ return TRUE;
+}
+
+struct MoveChildParam
+{
+ HWND hDlg;
+ POINT offset;
+};
+static BOOL CALLBACK MoveEnumChildren(HWND hwnd,LPARAM lParam)
+{
+ struct MoveChildParam * param = ( struct MoveChildParam *) lParam;
+
+ RECT rcWnd;
+ GetWindowRect( hwnd, &rcWnd);
+
+ HWND hwndParent = GetParent( hwnd );
+ if ( hwndParent != param->hDlg )
+ return TRUE; // Do not move subchilds
+
+ POINT pt; pt.x = 0; pt.y = 0;
+
+ ClientToScreen( hwndParent, &pt );
+ OffsetRect( &rcWnd, -pt.x, -pt.y );
+
+ SetWindowPos( hwnd, NULL, rcWnd.left + param->offset.x, rcWnd.top + param->offset.y, 0, 0, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE );
+
+ return TRUE;
+}
+
+#define OPTSTATE_PREFIX "s_"
+
+static void SaveOptionsTreeState(HWND hdlg)
+{
+ TVITEMA tvi;
+ char buf[130],str[128];
+ tvi.mask = TVIF_TEXT | TVIF_STATE;
+ tvi.pszText = str;
+ tvi.cchTextMax = SIZEOF(str);
+ tvi.hItem = TreeView_GetRoot( GetDlgItem( hdlg, IDC_PAGETREE ));
+ while ( tvi.hItem != NULL ) {
+ if ( SendMessageA( GetDlgItem(hdlg,IDC_PAGETREE), TVM_GETITEMA, 0, (LPARAM)&tvi )) {
+ mir_snprintf(buf, SIZEOF(buf), "%s%s",OPTSTATE_PREFIX,str);
+ DBWriteContactSettingByte(NULL,"Options",buf,(BYTE)((tvi.state&TVIS_EXPANDED)?1:0));
+ }
+ tvi.hItem = TreeView_GetNextSibling( GetDlgItem( hdlg, IDC_PAGETREE ), tvi.hItem );
+} }
+
+#define DM_FOCUSPAGE (WM_USER+10)
+#define DM_REBUILDPAGETREE (WM_USER+11)
+
+static void ThemeDialogBackground(HWND hwnd, BOOL tabbed)
+{
+ if (enableThemeDialogTexture)
+ enableThemeDialogTexture(hwnd, (tabbed ? ETDT_ENABLE : ETDT_DISABLE) | ETDT_USETABTEXTURE);
+}
+
+static int lstrcmpnull(TCHAR *str1, TCHAR *str2)
+{
+ if ( str1 == NULL && str2 == NULL )
+ return 0;
+ if ( str1 != NULL && str2 == NULL )
+ return 1;
+ if ( str1 == NULL && str2 != NULL )
+ return -1;
+
+ return lstrcmp(str1, str2);
+}
+
+static TCHAR *GetPluginName(HINSTANCE hInstance, TCHAR *buffer, int size)
+{
+ TCHAR tszModuleName[MAX_PATH];
+ GetModuleFileName(hInstance, tszModuleName, SIZEOF(tszModuleName));
+ TCHAR *dllName = _tcsrchr(tszModuleName,'\\');
+ if (!dllName)
+ {
+ dllName = tszModuleName;
+ }
+ else {
+ dllName++;
+ }
+
+ _tcsncpy(buffer, dllName, size);
+
+ return buffer;
+}
+
+PageHash GetPluginPageHash(const OptionsPageData *page)
+{
+ return hashstr(page->pszGroup) + hashstr(page->pszTitle) + hashstr(page->pszTab);
+}
+
+static void FindFilterStrings(int enableKeywordFiltering, int current, HWND hWndParent, const OptionsPageData *page)
+{
+ TCHAR pluginName[MAX_PATH];
+ HWND hWnd = 0;
+ if (enableKeywordFiltering) {
+ if (current)
+ hWnd = page->hwnd;
+ else
+ {
+ hWnd = CreateDialogIndirectParamA(page->hInst, page->pTemplate, hWndParent, page->dlgProc, page->dwInitParam); //create the options dialog page so we can parse it
+ ShowWindow(hWnd, SW_HIDE); //make sure it's hidden
+ } }
+
+ DWORD key = GetPluginPageHash(page); //get the plugin page hash
+
+ TCHAR * PluginFullName = NULL;
+ char * temp = GetPluginNameByInstance( page->hInst );
+ if ( temp ) PluginFullName = mir_a2t( temp );
+ GetDialogStrings(enableKeywordFiltering, key, GetPluginName(page->hInst, pluginName, SIZEOF(pluginName)), hWnd, page->pszGroup, page->pszTitle, page->pszTab, PluginFullName );
+ if ( PluginFullName ) mir_free( PluginFullName ) ;
+
+ if (enableKeywordFiltering && !current)
+ DestroyWindow(hWnd); //destroy the page, we're done with it
+}
+
+static int MatchesFilter(const OptionsPageData *page, TCHAR *szFilterString)
+{
+ DWORD key = GetPluginPageHash(page);
+
+ return ContainsFilterString(key, szFilterString);
+}
+
+static WNDPROC OptionsFilterDefaultProc = NULL;
+
+static LRESULT CALLBACK OptionsFilterSubclassProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ if (message != WM_PAINT && message != WM_PRINT)
+ return CallWindowProc(OptionsFilterDefaultProc, hWnd, message, wParam, lParam );
+
+ if ( GetFocus() == hWnd || GetWindowTextLength( hWnd ) )
+ return CallWindowProc(OptionsFilterDefaultProc, hWnd, message, wParam, lParam );
+
+ RECT rc;
+ GetClientRect( hWnd, &rc);
+ HDC hdc;
+ PAINTSTRUCT paint;
+
+ if (message == WM_PAINT)
+ hdc = BeginPaint( hWnd, &paint);
+ else
+ hdc = (HDC)wParam;
+
+ TCHAR buf[255];
+ if ( bSearchState==1 && FilterLoadProgress < 100 && FilterLoadProgress > 0 )
+ mir_sntprintf( buf, SIZEOF(buf), TranslateT("Loading... %d%%"), FilterLoadProgress );
+ else
+ mir_sntprintf( buf, SIZEOF(buf), TranslateT( "Search" ) );
+
+ BOOL bDrawnByTheme = FALSE;
+
+ int oldMode = SetBkMode( hdc, TRANSPARENT );
+
+ if ( openThemeData ) {
+ HTHEME hTheme = openThemeData( hWnd, L"EDIT");
+ if ( hTheme ) {
+ if ( isThemeBackgroundPartiallyTransparent( hTheme, EP_EDITTEXT, ETS_NORMAL ))
+ drawThemeParentBackground( hWnd, hdc, &rc );
+
+ RECT rc2;
+ getThemeBackgroundContentRect( hTheme, hdc, EP_EDITTEXT, ETS_NORMAL, &rc, &rc2 );
+ rc2.top = 2 * rc.top - rc2.top;
+ rc2.left = 2 * rc.left - rc2.left;
+ rc2.bottom = 2 * rc.bottom - rc2.bottom;
+ rc2.right = 2 * rc.right - rc2.right;
+
+ drawThemeBackground( hTheme, hdc, EP_EDITTEXT, ETS_NORMAL, &rc2, &rc );
+ HFONT hFont = (HFONT) SendMessage(hWnd, WM_GETFONT, 0, 0);
+ HFONT oldFont = (HFONT) SelectObject( hdc, hFont );
+
+ wchar_t *bufW = mir_t2u(buf);
+ drawThemeText( hTheme, hdc, EP_EDITTEXT, ETS_DISABLED, bufW, -1, 0, 0, &rc );
+ mir_free(bufW);
+
+ SelectObject( hdc, oldFont );
+ closeThemeData( hTheme );
+ bDrawnByTheme = TRUE;
+ }
+ }
+
+ SetBkMode( hdc, oldMode );
+
+ if ( !bDrawnByTheme ) {
+ HFONT hFont = (HFONT) SendMessage(hWnd, WM_GETFONT, 0, 0);
+ HFONT oldFont = (HFONT) SelectObject( hdc, hFont );
+ SetTextColor( hdc, GetSysColor(COLOR_GRAYTEXT) );
+ FillRect( hdc, &rc, GetSysColorBrush( COLOR_WINDOW ) );
+ int oldMode = SetBkMode( hdc, TRANSPARENT );
+ DrawText( hdc, buf, -1, &rc, 0 );
+ SetBkMode( hdc, oldMode );
+ SelectObject( hdc, oldFont );
+ }
+
+ if (message == WM_PAINT)
+ EndPaint( hWnd, &paint);
+
+ return 0;
+}
+
+static BOOL CheckPageShow( HWND hdlg, OptionsDlgData * dat, int i )
+{
+ if (dat->szFilterString && dat->szFilterString[0] && !MatchesFilter(&dat->opd[i], dat->szFilterString)) return FALSE;
+ if ((dat->opd[i].flags & ODPF_SIMPLEONLY) && IsDlgButtonChecked( hdlg, IDC_EXPERT)) return FALSE;
+ if ((dat->opd[i].flags & ODPF_EXPERTONLY) && !IsDlgButtonChecked( hdlg, IDC_EXPERT)) return FALSE;
+ return TRUE;
+}
+
+static BOOL IsAeroMode()
+{
+ BOOL result;
+ return dwmIsCompositionEnabled && (dwmIsCompositionEnabled(&result) == S_OK) && result;
+}
+
+static void AeroPaintControl(HWND hwnd, HDC hdc, WNDPROC OldWndProc, UINT msg = WM_PRINT, LPARAM lpFlags = PRF_CLIENT|PRF_NONCLIENT)
+{
+ HBITMAP hBmp, hOldBmp;
+ RECT rc; GetClientRect(hwnd, &rc);
+ BYTE *pBits;
+
+ HDC tempDC = CreateCompatibleDC(hdc);
+
+ BITMAPINFO bmi;
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.bmiHeader.biWidth = rc.right;
+ bmi.bmiHeader.biHeight = -rc.bottom;
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ hBmp = CreateDIBSection(tempDC, &bmi, DIB_RGB_COLORS, (void **)&pBits, NULL, 0);
+
+ hOldBmp = (HBITMAP)SelectObject(tempDC,hBmp);
+
+ //paint
+ SetPropA(hwnd, "Miranda.AeroRender.Active", (HANDLE)TRUE);
+ CallWindowProc(OldWndProc, hwnd, msg, (WPARAM)tempDC, lpFlags);
+ SetPropA(hwnd, "Miranda.AeroRender.Active", (HANDLE)FALSE);
+
+ // Fix alpha channel
+ GdiFlush();
+ for (int i = 0; i < rc.right*rc.bottom; ++i, pBits += 4)
+ if (!pBits[3]) pBits[3] = 255;
+
+ //Copy to output
+ BitBlt(hdc,0,0,rc.right,rc.bottom,tempDC,0,0,SRCCOPY);
+ SelectObject(tempDC,hOldBmp);
+ DeleteObject(hBmp);
+ DeleteDC(tempDC);
+}
+
+static LRESULT CALLBACK AeroPaintSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ WNDPROC OldWndProc = (WNDPROC)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ switch (msg)
+ {
+ case WM_CTLCOLOREDIT:
+ if (!GetPropA((HWND)lParam, "Miranda.AeroRender.Active"))
+ RedrawWindow((HWND)lParam, NULL, NULL, RDW_INVALIDATE);
+ break;
+
+ case WM_ERASEBKGND:
+ return TRUE;
+
+ case WM_PRINT:
+ case WM_PRINTCLIENT:
+ AeroPaintControl(hwnd, (HDC)wParam, OldWndProc, msg, lParam);
+ return TRUE;
+
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ HDC hdc = BeginPaint(hwnd, &ps);
+ AeroPaintControl(hwnd, hdc, OldWndProc);
+ EndPaint(hwnd, &ps);
+ return TRUE;
+ }
+
+ case WM_DESTROY:
+ RemovePropA(hwnd, "Miranda.AeroRender.Active");
+ break;
+ }
+ return CallWindowProc(OldWndProc, hwnd, msg, wParam, lParam);
+}
+
+static void CALLBACK FilterSearchTimerFunc( HWND hwnd, UINT, UINT_PTR, DWORD )
+{
+ struct OptionsDlgData* dat = (struct OptionsDlgData* )GetWindowLongPtr( hwnd, GWLP_USERDATA );
+ if ( !dat )
+ return;
+
+ if ( hFilterSearchWnd == NULL)
+ hFilterSearchWnd = CreateWindowA( "STATIC", "Test", WS_OVERLAPPED|WS_DISABLED, CW_USEDEFAULT,CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, GetModuleHandle(NULL), 0 ); // Fake window to keep option page focused
+
+ if ( FilterPage < dat->pageCount )
+ FindFilterStrings( TRUE, dat->currentPage == FilterPage, hFilterSearchWnd, &( dat->opd[FilterPage]) );
+
+ FilterPage++;
+ FilterLoadProgress = FilterPage*100/( (dat->pageCount) ? dat->pageCount : FilterPage );
+ if ( FilterPage >= dat->pageCount )
+ {
+ KillTimer( hwnd, FilterTimerId );
+ FilterTimerId = 0;
+ bSearchState = 2;
+ FilterLoadProgress = 100;
+ DestroyWindow( hFilterSearchWnd );
+ hFilterSearchWnd = NULL;
+ }
+ RedrawWindow( GetDlgItem(hwnd, IDC_KEYWORD_FILTER ), NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE );
+}
+
+static void ExecuteFindFilterStringsTimer( HWND hdlg )
+{
+ bSearchState = 1;
+ FilterPage = 0;
+ if (FilterTimerId) KillTimer( hdlg, FilterTimerId );
+ FilterTimerId = SetTimer( hdlg, NULL, 1, FilterSearchTimerFunc );
+}
+
+static void FillFilterCombo(int enableKeywordFiltering, HWND hDlg, struct OptionsPageData * opd, int PageCount)
+{
+ int i;
+ int index;
+ HINSTANCE* KnownInstances = ( HINSTANCE* )alloca(sizeof(HINSTANCE)*PageCount);
+ int countKnownInst = 0;
+ SendDlgItemMessage(hDlg, IDC_KEYWORD_FILTER,(UINT) CB_RESETCONTENT, 0,0);
+ index=SendDlgItemMessage(hDlg, IDC_KEYWORD_FILTER,(UINT) CB_ADDSTRING,(WPARAM)0, (LPARAM)TranslateTS(ALL_MODULES_FILTER));
+ SendDlgItemMessage(hDlg, IDC_KEYWORD_FILTER,(UINT) CB_SETITEMDATA,(WPARAM)index, (LPARAM)NULL);
+ index=SendDlgItemMessage(hDlg, IDC_KEYWORD_FILTER,(UINT) CB_ADDSTRING,(WPARAM)0, (LPARAM)TranslateTS(CORE_MODULES_FILTER));
+ SendDlgItemMessage(hDlg, IDC_KEYWORD_FILTER,(UINT) CB_SETITEMDATA,(WPARAM)index, (LPARAM)hMirandaInst);
+ TCHAR* tszModuleName = ( TCHAR* )alloca(MAX_PATH*sizeof(TCHAR));
+ for (i=0; i<PageCount; i++) {
+ TCHAR * dllName = NULL;
+ int j;
+ HINSTANCE inst=opd[i].hInst;
+
+ if ( !enableKeywordFiltering )
+ FindFilterStrings( enableKeywordFiltering, FALSE, hDlg, &opd[i]); // only modules name ( fast enougth )
+
+ if (inst==hMirandaInst) continue;
+ for (j=0; j<countKnownInst; j++)
+ if (KnownInstances[j]==inst) break;
+ if (j!=countKnownInst) continue;
+ KnownInstances[countKnownInst]=inst;
+ countKnownInst++;
+ GetModuleFileName(inst, tszModuleName, MAX_PATH);
+ {
+ char * name = GetPluginNameByInstance( inst );
+ if ( name )
+ dllName = mir_a2t( name );
+ }
+
+ if (!dllName) dllName = mir_tstrdup( _tcsrchr(tszModuleName,_T('\\')) );
+ if (!dllName) dllName = mir_tstrdup( tszModuleName );
+
+ if (dllName) {
+ index=SendDlgItemMessage(hDlg, IDC_KEYWORD_FILTER,(UINT) CB_ADDSTRING,(WPARAM)0, (LPARAM)dllName);
+ SendDlgItemMessage(hDlg, IDC_KEYWORD_FILTER,(UINT) CB_SETITEMDATA,(WPARAM)index, (LPARAM)inst);
+ mir_free( dllName );
+ }
+ }
+
+ FilterLoadProgress = 100;
+ if ( enableKeywordFiltering)
+ ExecuteFindFilterStringsTimer( hDlg );
+}
+
+static BOOL IsInsideTab( HWND hdlg, OptionsDlgData * dat, int i )
+{
+ int pages = 0;
+ if (dat->opd[i].pszTab != NULL)
+ {
+ // Count tabs to calc position
+ for (int j=0; j < dat->pageCount && pages < 2; j++ )
+ {
+ if (!CheckPageShow( hdlg, dat, j ) ) continue;
+ //if (( dat->opd[j].flags & ODPF_SIMPLEONLY ) && IsDlgButtonChecked( hdlg, IDC_EXPERT )) continue;
+ //if (( dat->opd[j].flags & ODPF_EXPERTONLY ) && !IsDlgButtonChecked( hdlg, IDC_EXPERT )) continue;
+ if ( lstrcmp(dat->opd[j].pszTitle, dat->opd[i].pszTitle) || lstrcmpnull(dat->opd[j].pszGroup, dat->opd[i].pszGroup) ) continue;
+ pages++;
+ }
+ }
+ return (pages > 1);
+}
+
+static INT_PTR CALLBACK OptionsDlgProc(HWND hdlg,UINT message,WPARAM wParam,LPARAM lParam)
+{
+ struct OptionsDlgData* dat = (struct OptionsDlgData* )GetWindowLongPtr( hdlg, GWLP_USERDATA );
+ HWND hwndTree = GetDlgItem(hdlg, IDC_PAGETREE);
+
+ switch ( message ) {
+ case WM_CTLCOLORSTATIC:
+ switch ( GetDlgCtrlID(( HWND )lParam ))
+ {
+ case IDC_WHITERECT:
+ case IDC_KEYWORD_FILTER:
+ SetBkColor(( HDC )wParam, GetSysColor( COLOR_WINDOW ));
+ return ( INT_PTR )GetSysColorBrush( COLOR_WINDOW );
+ }
+ break;
+
+ case WM_INITDIALOG:
+ {
+ PROPSHEETHEADER *psh=(PROPSHEETHEADER*)lParam;
+ OPENOPTIONSDIALOG *ood=(OPENOPTIONSDIALOG*)psh->pStartPage;
+ OPTIONSDIALOGPAGE *odp;
+ int i;
+ struct DlgTemplateExBegin *dte;
+ TCHAR *lastPage = NULL, *lastGroup = NULL, *lastTab = NULL;
+ DBVARIANT dbv;
+ TCITEM tie;
+ LOGFONT lf;
+
+ typedef BOOL (STDAPICALLTYPE *pfnGetComboBoxInfo)(HWND, PCOMBOBOXINFO);
+ pfnGetComboBoxInfo getComboBoxInfo = (pfnGetComboBoxInfo)GetProcAddress(GetModuleHandleA("user32"), "GetComboBoxInfo");
+ if (getComboBoxInfo) {
+ COMBOBOXINFO cbi;
+ cbi.cbSize = sizeof(COMBOBOXINFO);
+ getComboBoxInfo(GetDlgItem( hdlg, IDC_KEYWORD_FILTER), &cbi);
+ OptionsFilterDefaultProc = (WNDPROC)SetWindowLongPtr( cbi.hwndItem, GWLP_WNDPROC, (LONG_PTR) OptionsFilterSubclassProc );
+
+ if (IsAeroMode()) {
+ SetWindowLongPtr(cbi.hwndCombo, GWLP_USERDATA, GetWindowLongPtr(cbi.hwndCombo, GWLP_WNDPROC));
+ SetWindowLongPtr(cbi.hwndCombo, GWLP_WNDPROC, (LONG_PTR)AeroPaintSubclassProc);
+ SetWindowLongPtr(cbi.hwndItem, GWLP_USERDATA, GetWindowLongPtr(cbi.hwndItem, GWLP_WNDPROC));
+ SetWindowLongPtr(cbi.hwndItem, GWLP_WNDPROC, (LONG_PTR)AeroPaintSubclassProc);
+ } }
+
+ Utils_RestoreWindowPositionNoSize(hdlg, NULL, "Options", "");
+ TranslateDialogDefault(hdlg);
+ Window_SetIcon_IcoLib(hdlg, SKINICON_OTHER_OPTIONS);
+ CheckDlgButton(hdlg,IDC_EXPERT,DBGetContactSettingByte(NULL,"Options","Expert",SETTING_SHOWEXPERT_DEFAULT)?BST_CHECKED:BST_UNCHECKED);
+ EnableWindow(GetDlgItem(hdlg,IDC_APPLY),FALSE);
+ dat=(struct OptionsDlgData*)mir_alloc(sizeof(struct OptionsDlgData));
+ SetWindowLongPtr(hdlg,GWLP_USERDATA,(LONG_PTR)dat);
+ SetWindowText(hdlg,psh->pszCaption);
+
+ dat->hBoldFont=(HFONT)SendDlgItemMessage(hdlg,IDC_EXPERT,WM_GETFONT,0,0);
+ GetObject(dat->hBoldFont,sizeof(lf),&lf);
+ lf.lfWeight=FW_BOLD;
+ dat->hBoldFont=CreateFontIndirect(&lf);
+
+ dat->pageCount = psh->nPages;
+ dat->opd = ( struct OptionsPageData* )mir_alloc( sizeof(struct OptionsPageData) * dat->pageCount );
+ odp = ( OPTIONSDIALOGPAGE* )psh->ppsp;
+
+ dat->currentPage = -1;
+ if ( ood->pszPage == NULL ) {
+ if ( !DBGetContactSettingTString( NULL, "Options", "LastPage", &dbv )) {
+ lastPage = mir_tstrdup( dbv.ptszVal );
+ DBFreeVariant( &dbv );
+ }
+
+ if ( ood->pszGroup == NULL ) {
+ if ( !DBGetContactSettingTString( NULL, "Options", "LastGroup", &dbv )) {
+ lastGroup = mir_tstrdup( dbv.ptszVal );
+ DBFreeVariant( &dbv );
+ }
+ }
+ else lastGroup = LangPackPcharToTchar( ood->pszGroup );
+ }
+ else
+ {
+ lastPage = LangPackPcharToTchar( ood->pszPage );
+ lastGroup = ( ood->pszGroup == NULL ) ? NULL : LangPackPcharToTchar( ood->pszGroup );
+ }
+
+ if ( ood->pszTab == NULL ) {
+ if ( !DBGetContactSettingTString( NULL, "Options", "LastTab", &dbv )) {
+ lastTab = mir_tstrdup( dbv.ptszVal );
+ DBFreeVariant( &dbv );
+ }
+ }
+ else lastTab = LangPackPcharToTchar( ood->pszTab );
+
+ for ( i=0; i < dat->pageCount; i++, odp++ ) {
+ struct OptionsPageData* opd = &dat->opd[i];
+ HRSRC hrsrc=FindResourceA(odp->hInstance,odp->pszTemplate,MAKEINTRESOURCEA(5));
+ HGLOBAL hglb=LoadResource(odp->hInstance,hrsrc);
+ DWORD resSize=SizeofResource(odp->hInstance,hrsrc);
+ opd->pTemplate = ( DLGTEMPLATE* )mir_alloc(resSize);
+ memcpy(opd->pTemplate,LockResource(hglb),resSize);
+ dte=(struct DlgTemplateExBegin*)opd->pTemplate;
+ if ( dte->signature == 0xFFFF ) {
+ //this feels like an access violation, and is according to boundschecker
+ //...but it works - for now
+ //may well have to remove and sort out the original dialogs
+ dte->style&=~(WS_VISIBLE|WS_CHILD|WS_POPUP|WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|DS_MODALFRAME|DS_CENTER);
+ dte->style|=WS_CHILD;
+ }
+ else {
+ opd->pTemplate->style&=~(WS_VISIBLE|WS_CHILD|WS_POPUP|WS_OVERLAPPED|WS_CAPTION|WS_SYSMENU|DS_MODALFRAME|DS_CENTER);
+ opd->pTemplate->style|=WS_CHILD;
+ }
+ opd->dlgProc=odp->pfnDlgProc;
+ opd->hInst=odp->hInstance;
+ opd->hwnd=NULL;
+ opd->changed=0;
+ opd->simpleHeight=opd->expertHeight=0;
+ opd->simpleBottomControlId=odp->nIDBottomSimpleControl;
+ opd->simpleWidth=opd->expertWidth=0;
+ opd->simpleRightControlId=odp->nIDRightSimpleControl;
+ opd->nExpertOnlyControls=odp->nExpertOnlyControls;
+ opd->expertOnlyControls=odp->expertOnlyControls;
+ opd->flags=odp->flags;
+ opd->dwInitParam=odp->dwInitParam;
+ if ( odp->pszTitle == NULL )
+ opd->pszTitle = NULL;
+ else if ( odp->flags & ODPF_UNICODE ) {
+ #if defined ( _UNICODE )
+ opd->pszTitle = ( TCHAR* )mir_wstrdup( odp->ptszTitle );
+ #else
+ opd->pszTitle = mir_u2a(( WCHAR* )odp->ptszTitle );
+ #endif
+ }
+ else opd->pszTitle = ( TCHAR* )mir_strdup( odp->pszTitle );
+
+ if ( odp->pszGroup == NULL )
+ opd->pszGroup = NULL;
+ else if ( odp->flags & ODPF_UNICODE ) {
+ #if defined ( _UNICODE )
+ opd->pszGroup = ( TCHAR* )mir_wstrdup( odp->ptszGroup );
+ #else
+ opd->pszGroup = mir_u2a(( WCHAR* )odp->ptszGroup );
+ #endif
+ }
+ else opd->pszGroup = ( TCHAR* )mir_strdup( odp->pszGroup );
+
+ if ( odp->pszTab == NULL )
+ opd->pszTab = NULL;
+ else if ( odp->flags & ODPF_UNICODE ) {
+ #if defined ( _UNICODE )
+ opd->pszTab = ( TCHAR* )mir_wstrdup( odp->ptszTab );
+ #else
+ opd->pszTab = mir_u2a(( WCHAR* )odp->ptszTab );
+ #endif
+ }
+ else opd->pszTab = ( TCHAR* )mir_strdup( odp->pszTab );
+
+ if ( !lstrcmp( lastPage, odp->ptszTitle ) &&
+ !lstrcmpnull( lastGroup, odp->ptszGroup ) &&
+ (( ood->pszTab == NULL && dat->currentPage == -1 ) || !lstrcmpnull( lastTab, odp->ptszTab )))
+ dat->currentPage = i;
+ }
+ mir_free( lastGroup );
+ mir_free( lastPage );
+ mir_free( lastTab );
+
+ GetWindowRect(GetDlgItem(hdlg,IDC_STNOPAGE),&dat->rcDisplay);
+ MapWindowPoints(NULL, hdlg, (LPPOINT)&dat->rcDisplay, 2);
+
+ // Add an item to count in height
+ tie.mask = TCIF_TEXT | TCIF_IMAGE;
+ tie.iImage = -1;
+ tie.pszText = _T("X");
+ TabCtrl_InsertItem(GetDlgItem(hdlg,IDC_TAB), 0, &tie);
+
+ GetWindowRect(GetDlgItem(hdlg,IDC_TAB), &dat->rcTab);
+ MapWindowPoints(NULL, hdlg, (LPPOINT)&dat->rcTab, 2);
+ TabCtrl_AdjustRect(GetDlgItem(hdlg,IDC_TAB), FALSE, &dat->rcTab);
+
+ //!!!!!!!!!! int enableKeywordFiltering = DBGetContactSettingWord(NULL, "Options", "EnableKeywordFiltering", TRUE);
+ FillFilterCombo( 0, //!!!!!!!!!! enableKeywordFiltering,
+ hdlg, dat->opd, dat->pageCount);
+ SendMessage(hdlg,DM_REBUILDPAGETREE,0,0);
+
+ return TRUE;
+ }
+ case DM_REBUILDPAGETREE:
+ {
+ int i;
+ TVINSERTSTRUCT tvis;
+ TVITEMA tvi;
+ BOOL bRemoveFocusFromFilter = FALSE;
+ char str[128],buf[130];
+
+ HINSTANCE FilterInst=NULL;
+
+ LPARAM oldSel = SendDlgItemMessage(hdlg, IDC_KEYWORD_FILTER, CB_GETEDITSEL, 0, 0);
+
+ GetDlgItemText(hdlg, IDC_KEYWORD_FILTER, dat->szFilterString, SIZEOF(dat->szFilterString));
+
+ //if filter string is set to all modules then make the filter string empty (this will return all modules)
+ if (_tcscmp(dat->szFilterString, TranslateTS( ALL_MODULES_FILTER ) ) == 0) {
+ dat->szFilterString[0] = 0;
+ bRemoveFocusFromFilter = TRUE;
+ }
+ //if filter string is set to core modules replace it with the name of the executable (this will return all core modules)
+ else if (_tcscmp(dat->szFilterString, TranslateTS( CORE_MODULES_FILTER) ) == 0) {
+ //replace string with process name - that will show core settings
+ TCHAR szFileName[300];
+ GetModuleFileName(NULL, szFileName, SIZEOF(szFileName));
+ TCHAR *pos = _tcsrchr(szFileName, _T('\\'));
+ if (pos)
+ pos++;
+ else
+ pos = szFileName;
+
+ _tcsncpy(dat->szFilterString, pos, SIZEOF(dat->szFilterString));
+ }
+ else {
+ int sel = SendMessage( GetDlgItem(hdlg, IDC_KEYWORD_FILTER ), (UINT) CB_GETCURSEL, 0,0 );
+ if (sel != -1) {
+ HINSTANCE hinst = (HINSTANCE)SendMessage( GetDlgItem(hdlg, IDC_KEYWORD_FILTER ), (UINT) CB_GETITEMDATA, sel ,0 );
+ TCHAR szFileName[300];
+ GetModuleFileName(hinst, szFileName, SIZEOF(szFileName));
+ TCHAR *pos = _tcsrchr(szFileName, _T('\\'));
+ if (pos) pos++;
+ else pos = szFileName;
+ _tcsncpy(dat->szFilterString, pos, SIZEOF(dat->szFilterString));
+ } }
+
+ _tcslwr_locale(dat->szFilterString); //all strings are stored as lowercase ... make sure filter string is lowercase too
+
+ ShowWindow(hwndTree, SW_HIDE); //deleteall is annoyingly visible
+
+ HWND oldWnd = NULL;
+ HWND oldTab = NULL;
+ if ( dat->currentPage != (-1)) {
+ oldWnd = dat->opd[dat->currentPage].hwnd;
+ if ( dat->opd[dat->currentPage].insideTab )
+ oldTab = GetDlgItem( hdlg,IDC_TAB );
+ }
+
+ dat->hCurrentPage = NULL;
+
+ TreeView_SelectItem(hwndTree, NULL);
+
+ TreeView_DeleteAllItems(hwndTree);
+
+ tvis.hParent = NULL;
+ tvis.hInsertAfter = TVI_SORT;
+ tvis.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM;
+ tvis.item.state = tvis.item.stateMask = TVIS_EXPANDED;
+ for ( i=0; i < dat->pageCount; i++ ) {
+ static TCHAR *fullTitle=NULL;
+ TCHAR * useTitle;
+ if (fullTitle) mir_free(fullTitle);
+ fullTitle=NULL;
+ if (! CheckPageShow( hdlg, dat, i ) ) continue;
+ tvis.hParent = NULL;
+ if ( FilterInst!=NULL ) {
+ size_t sz=dat->opd[i].pszGroup?_tcslen(dat->opd[i].pszGroup)+1:0;
+ if (sz) sz+=3;
+ sz+=dat->opd[i].pszTitle?_tcslen(dat->opd[i].pszTitle)+1:0;
+ fullTitle = ( TCHAR* )mir_alloc(sz*sizeof(TCHAR));
+ mir_sntprintf(fullTitle,sz,(dat->opd[i].pszGroup && dat->opd[i].pszTitle)?_T("%s - %s"):_T("%s%s"),dat->opd[i].pszGroup?dat->opd[i].pszGroup:_T(""),dat->opd[i].pszTitle?dat->opd[i].pszTitle:_T("") );
+ }
+ useTitle=fullTitle?fullTitle:dat->opd[i].pszTitle;
+ if(dat->opd[i].pszGroup != NULL && FilterInst==NULL) {
+ tvis.hParent = FindNamedTreeItemAtRoot(hwndTree, dat->opd[i].pszGroup);
+ if(tvis.hParent == NULL) {
+ tvis.item.lParam = -1;
+ tvis.item.pszText = dat->opd[i].pszGroup;
+ tvis.hParent = TreeView_InsertItem(hwndTree, &tvis);
+ }
+ }
+ else {
+ TVITEM tvi;
+ tvi.hItem = FindNamedTreeItemAtRoot(hwndTree,useTitle);
+ if( tvi.hItem != NULL ) {
+ if ( i == dat->currentPage ) dat->hCurrentPage=tvi.hItem;
+ tvi.mask = TVIF_PARAM;
+ TreeView_GetItem(hwndTree,&tvi);
+ if ( tvi.lParam == -1 ) {
+ tvi.lParam = i;
+ TreeView_SetItem(hwndTree,&tvi);
+ continue;
+ } } }
+
+ if ( dat->opd[i].pszTab != NULL ) {
+ HTREEITEM hItem;
+ if (tvis.hParent == NULL)
+ hItem = FindNamedTreeItemAtRoot(hwndTree,useTitle);
+ else
+ hItem = FindNamedTreeItemAtChildren(hwndTree,tvis.hParent,useTitle);
+ if( hItem != NULL ) {
+ if ( i == dat->currentPage ) {
+ TVITEM tvi;
+ tvi.hItem=hItem;
+ tvi.mask=TVIF_PARAM;
+ tvi.lParam=dat->currentPage;
+ TreeView_SetItem(hwndTree,&tvi);
+ dat->hCurrentPage=hItem;
+ }
+ continue;
+ }
+ }
+
+ tvis.item.pszText = useTitle;
+ tvis.item.lParam = i;
+ dat->opd[i].hTreeItem = TreeView_InsertItem(hwndTree, &tvis);
+ if ( i == dat->currentPage )
+ dat->hCurrentPage = dat->opd[i].hTreeItem;
+
+ if (fullTitle) mir_free(fullTitle);
+ fullTitle=NULL;
+ }
+ tvi.mask = TVIF_TEXT | TVIF_STATE;
+ tvi.pszText = str;
+ tvi.cchTextMax = SIZEOF(str);
+ tvi.hItem = TreeView_GetRoot(hwndTree);
+ while ( tvi.hItem != NULL ) {
+ if ( SendMessageA( hwndTree, TVM_GETITEMA, 0, (LPARAM)&tvi )) {
+ mir_snprintf(buf, SIZEOF(buf), "%s%s",OPTSTATE_PREFIX,str);
+ if ( !DBGetContactSettingByte( NULL, "Options", buf, 1 ))
+ TreeView_Expand( hwndTree, tvi.hItem, TVE_COLLAPSE );
+ }
+ tvi.hItem = TreeView_GetNextSibling( hwndTree, tvi.hItem );
+ }
+ if(dat->hCurrentPage==NULL) {
+ dat->hCurrentPage=TreeView_GetRoot(hwndTree);
+ dat->currentPage=-1;
+ }
+ TreeView_SelectItem(hwndTree,dat->hCurrentPage);
+
+ if ( oldWnd ) {
+ if ( dat->currentPage == (-1) || oldWnd != dat->opd[dat->currentPage].hwnd ) {
+ ShowWindow( oldWnd, SW_HIDE);
+ if ( oldTab && ( dat->currentPage ==-1 || !dat->opd[dat->currentPage].insideTab ) )
+ ShowWindow( oldTab, SW_HIDE );
+ }
+ }
+
+ if ( dat->szFilterString[0] == 0 ) // Clear the keyword combo box
+ SetWindowText( GetDlgItem(hdlg, IDC_KEYWORD_FILTER), _T("") );
+ if ( !bRemoveFocusFromFilter )
+ SetFocus(GetDlgItem(hdlg, IDC_KEYWORD_FILTER)); //set the focus back to the combo box
+
+ SendDlgItemMessage(hdlg, IDC_KEYWORD_FILTER, CB_SETEDITSEL, 0, oldSel ); //but don't select any of the text
+
+ ShowWindow(hwndTree,SW_SHOW);
+ }
+ break;
+
+ case PSM_CHANGED:
+ EnableWindow(GetDlgItem(hdlg,IDC_APPLY),TRUE);
+ if(dat->currentPage != (-1)) dat->opd[dat->currentPage].changed=1;
+ return TRUE;
+
+ case PSM_ISEXPERT:
+ SetWindowLongPtr(hdlg,DWLP_MSGRESULT,IsDlgButtonChecked(hdlg,IDC_EXPERT));
+ return TRUE;
+
+ case PSM_GETBOLDFONT:
+ SetWindowLongPtr(hdlg,DWLP_MSGRESULT,(LONG_PTR)dat->hBoldFont);
+ return TRUE;
+
+ case WM_NOTIFY:
+ switch(wParam) {
+ case IDC_TAB:
+ case IDC_PAGETREE:
+ switch(((LPNMHDR)lParam)->code) {
+ case TVN_ITEMEXPANDING:
+ SetWindowLongPtr(hdlg,DWLP_MSGRESULT,FALSE);
+ return TRUE;
+ case TCN_SELCHANGING:
+ case TVN_SELCHANGING:
+ { PSHNOTIFY pshn;
+ if(dat->currentPage==-1 || dat->opd[dat->currentPage].hwnd==NULL) break;
+ pshn.hdr.code=PSN_KILLACTIVE;
+ pshn.hdr.hwndFrom=dat->opd[dat->currentPage].hwnd;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=0;
+ if(SendMessage(dat->opd[dat->currentPage].hwnd,WM_NOTIFY,0,(LPARAM)&pshn)) {
+ SetWindowLongPtr(hdlg,DWLP_MSGRESULT,TRUE);
+ return TRUE;
+ }
+ break;
+ }
+ case TCN_SELCHANGE:
+ case TVN_SELCHANGED:
+ { BOOL tabChange = (wParam == IDC_TAB);
+ ShowWindow(GetDlgItem(hdlg,IDC_STNOPAGE),SW_HIDE);
+ if(dat->currentPage!=-1 && dat->opd[dat->currentPage].hwnd!=NULL) ShowWindow(dat->opd[dat->currentPage].hwnd,SW_HIDE);
+ if (!tabChange) {
+ TVITEM tvi;
+ tvi.hItem=dat->hCurrentPage=TreeView_GetSelection(hwndTree);
+ if(tvi.hItem==NULL) break;
+ tvi.mask=TVIF_HANDLE|TVIF_PARAM;
+ TreeView_GetItem(hwndTree,&tvi);
+ dat->currentPage=tvi.lParam;
+ ShowWindow(GetDlgItem(hdlg,IDC_TAB),SW_HIDE);
+ }
+ else {
+ TCITEM tie;
+ TVITEM tvi;
+
+ tie.mask = TCIF_PARAM;
+ TabCtrl_GetItem(GetDlgItem(hdlg,IDC_TAB),TabCtrl_GetCurSel(GetDlgItem(hdlg,IDC_TAB)),&tie);
+ dat->currentPage=tie.lParam;
+
+ tvi.hItem=dat->hCurrentPage;
+ tvi.mask=TVIF_PARAM;
+ tvi.lParam=dat->currentPage;
+ TreeView_SetItem(hwndTree,&tvi);
+ }
+ if ( dat->currentPage != -1 ) {
+ if ( dat->opd[dat->currentPage].hwnd == NULL ) {
+ RECT rcPage;
+ RECT rcControl,rc;
+ int w,h;
+
+ dat->opd[dat->currentPage].hwnd=CreateDialogIndirectParamA(dat->opd[dat->currentPage].hInst,dat->opd[dat->currentPage].pTemplate,hdlg,dat->opd[dat->currentPage].dlgProc,dat->opd[dat->currentPage].dwInitParam);
+ if(dat->opd[dat->currentPage].flags&ODPF_BOLDGROUPS)
+ EnumChildWindows(dat->opd[dat->currentPage].hwnd,BoldGroupTitlesEnumChildren,(LPARAM)dat->hBoldFont);
+ GetClientRect(dat->opd[dat->currentPage].hwnd,&rcPage);
+ dat->opd[dat->currentPage].expertWidth=rcPage.right;
+ dat->opd[dat->currentPage].expertHeight=rcPage.bottom;
+ GetWindowRect(dat->opd[dat->currentPage].hwnd,&rc);
+
+ if(dat->opd[dat->currentPage].simpleBottomControlId) {
+ GetWindowRect(GetDlgItem(dat->opd[dat->currentPage].hwnd,dat->opd[dat->currentPage].simpleBottomControlId),&rcControl);
+ dat->opd[dat->currentPage].simpleHeight=rcControl.bottom-rc.top;
+ }
+ else dat->opd[dat->currentPage].simpleHeight=dat->opd[dat->currentPage].expertHeight;
+
+ if(dat->opd[dat->currentPage].simpleRightControlId) {
+ GetWindowRect(GetDlgItem(dat->opd[dat->currentPage].hwnd,dat->opd[dat->currentPage].simpleRightControlId),&rcControl);
+ dat->opd[dat->currentPage].simpleWidth=rcControl.right-rc.left;
+ }
+ else dat->opd[dat->currentPage].simpleWidth=dat->opd[dat->currentPage].expertWidth;
+
+ if(IsDlgButtonChecked(hdlg,IDC_EXPERT)) {
+ w=dat->opd[dat->currentPage].expertWidth;
+ h=dat->opd[dat->currentPage].expertHeight;
+ }
+ else {
+ int i;
+ for(i=0;i<dat->opd[dat->currentPage].nExpertOnlyControls;i++)
+ ShowWindow(GetDlgItem(dat->opd[dat->currentPage].hwnd,dat->opd[dat->currentPage].expertOnlyControls[i]),SW_HIDE);
+ w=dat->opd[dat->currentPage].simpleWidth;
+ h=dat->opd[dat->currentPage].simpleHeight;
+ }
+
+ dat->opd[dat->currentPage].offsetX = 0;
+ dat->opd[dat->currentPage].offsetY = 0;
+
+ dat->opd[dat->currentPage].insideTab = IsInsideTab( hdlg, dat, dat->currentPage );
+ if (dat->opd[dat->currentPage].insideTab) {
+ SetWindowPos(dat->opd[dat->currentPage].hwnd,HWND_TOP,(dat->rcTab.left+dat->rcTab.right-w)>>1,dat->rcTab.top,w,h,0);
+ ThemeDialogBackground(dat->opd[dat->currentPage].hwnd,TRUE);
+ } else {
+ SetWindowPos(dat->opd[dat->currentPage].hwnd,HWND_TOP,(dat->rcDisplay.left+dat->rcDisplay.right-w)>>1,(dat->rcDisplay.top+dat->rcDisplay.bottom-h)>>1,w,h,0);
+ ThemeDialogBackground(dat->opd[dat->currentPage].hwnd,FALSE);
+ }
+ }
+ if ( !tabChange )
+ {
+ dat->opd[ dat->currentPage].insideTab = IsInsideTab( hdlg, dat, dat->currentPage );
+ if ( dat->opd[dat->currentPage].insideTab ) {
+ // Make tabbed pane
+ int i,pages=0,sel=0;
+ TCITEM tie;
+ HWND hwndTab = GetDlgItem(hdlg,IDC_TAB);
+
+ TabCtrl_DeleteAllItems(hwndTab);
+ tie.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_PARAM;
+ tie.iImage = -1;
+ for ( i=0; i < dat->pageCount; i++ ) {
+ if (!CheckPageShow( hdlg, dat, i ) ) continue;
+ //if (( dat->opd[i].flags & ODPF_SIMPLEONLY ) && IsDlgButtonChecked( hdlg, IDC_EXPERT )) continue;
+ //if (( dat->opd[i].flags & ODPF_EXPERTONLY ) && !IsDlgButtonChecked( hdlg, IDC_EXPERT )) continue;
+ if ( lstrcmp(dat->opd[i].pszTitle, dat->opd[dat->currentPage].pszTitle) || lstrcmpnull(dat->opd[i].pszGroup, dat->opd[dat->currentPage].pszGroup) ) continue;
+
+ tie.pszText = dat->opd[i].pszTab;
+ tie.lParam = i;
+ TabCtrl_InsertItem(hwndTab, pages, &tie);
+ if ( !lstrcmp(dat->opd[i].pszTab,dat->opd[dat->currentPage].pszTab) )
+ sel = pages;
+ pages++;
+ }
+ TabCtrl_SetCurSel(hwndTab,sel);
+ ShowWindow(hwndTab, dat->opd[dat->currentPage].insideTab ? SW_SHOW : SW_HIDE );
+ }
+
+ if (dat->opd[dat->currentPage].insideTab)
+ ThemeDialogBackground(dat->opd[dat->currentPage].hwnd,TRUE);
+ else
+ ThemeDialogBackground(dat->opd[dat->currentPage].hwnd,FALSE);
+ }
+
+ // Resizing
+ if (!dat->opd[dat->currentPage].simpleBottomControlId)
+ {
+ int pageWidth, pageHeight;
+
+ if(IsDlgButtonChecked(hdlg,IDC_EXPERT)) {
+ pageWidth=dat->opd[dat->currentPage].expertWidth;
+ pageHeight=dat->opd[dat->currentPage].expertHeight;
+ }
+ else {
+ pageWidth=dat->opd[dat->currentPage].simpleWidth;
+ pageHeight=dat->opd[dat->currentPage].simpleHeight;
+ }
+
+ RECT * parentPageRect = &dat->rcDisplay;
+
+ if ( dat->opd[dat->currentPage].insideTab )
+ parentPageRect = &dat->rcTab;
+
+ pageHeight = min( pageHeight, parentPageRect->bottom - parentPageRect->top );
+ pageWidth = min( pageWidth, parentPageRect->right - parentPageRect->left );
+
+ int newOffsetX = ( parentPageRect->right - parentPageRect->left - pageWidth ) >> 1;
+ int newOffsetY = dat->opd[dat->currentPage].insideTab ? 0 : ( parentPageRect->bottom - parentPageRect->top - pageHeight ) >> 1;
+
+ struct MoveChildParam mcp;
+ mcp.hDlg = dat->opd[dat->currentPage].hwnd;
+ mcp.offset.x = newOffsetX - dat->opd[dat->currentPage].offsetX;
+ mcp.offset.y = newOffsetY - dat->opd[dat->currentPage].offsetY;
+
+
+ if ( mcp.offset.x || mcp.offset.y )
+ {
+ EnumChildWindows(dat->opd[dat->currentPage].hwnd,MoveEnumChildren,(LPARAM)(&mcp));
+
+ SetWindowPos( dat->opd[dat->currentPage].hwnd, NULL,
+ parentPageRect->left, parentPageRect->top,
+ parentPageRect->right - parentPageRect->left,
+ parentPageRect->bottom - parentPageRect->top,
+ SWP_NOZORDER | SWP_NOACTIVATE );
+ dat->opd[dat->currentPage].offsetX = newOffsetX;
+ dat->opd[dat->currentPage].offsetY = newOffsetY;
+ }
+
+ }
+
+ ShowWindow(dat->opd[dat->currentPage].hwnd,SW_SHOW);
+ if(((LPNMTREEVIEW)lParam)->action==TVC_BYMOUSE) PostMessage(hdlg,DM_FOCUSPAGE,0,0);
+ else SetFocus(hwndTree);
+ }
+ else ShowWindow(GetDlgItem(hdlg,IDC_STNOPAGE),SW_SHOW);
+ break;
+ } } }
+ break;
+
+ case DM_FOCUSPAGE:
+ if (dat->currentPage != -1)
+ SetFocus(dat->opd[dat->currentPage].hwnd);
+ break;
+
+ case WM_TIMER:
+ if (wParam == FILTER_TIMEOUT_TIMER) {
+ SaveOptionsTreeState(hdlg);
+ SendMessage(hdlg,DM_REBUILDPAGETREE,0,0);
+
+ KillTimer(hdlg, FILTER_TIMEOUT_TIMER);
+ }
+ break;
+
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDC_KEYWORD_FILTER:
+ //add a timer - when the timer elapses filter the option pages
+ if ( (HIWORD(wParam)==CBN_SELCHANGE) || (HIWORD(wParam) == CBN_EDITCHANGE))
+ if (!SetTimer(hdlg, FILTER_TIMEOUT_TIMER, 400, NULL))
+ MessageBeep(MB_ICONSTOP);
+
+ break;
+
+ case IDC_EXPERT:
+ {
+ int expert=IsDlgButtonChecked(hdlg,IDC_EXPERT);
+ int i,j;
+ PSHNOTIFY pshn;
+ RECT rcPage;
+ int neww,newh;
+
+ DBWriteContactSettingByte(NULL,"Options","Expert",(BYTE)expert);
+ pshn.hdr.idFrom=0;
+ pshn.lParam=expert;
+ pshn.hdr.code=PSN_EXPERTCHANGED;
+ for(i=0;i<dat->pageCount;i++) {
+ if(dat->opd[i].hwnd==NULL) continue;
+ if (!CheckPageShow( hdlg, dat, i ) ) continue;
+ //if (( dat->opd[i].flags & ODPF_SIMPLEONLY ) && expert) continue;
+ //if (( dat->opd[i].flags & ODPF_EXPERTONLY ) && !expert) continue;
+ pshn.hdr.hwndFrom=dat->opd[i].hwnd;
+ SendMessage(dat->opd[i].hwnd,WM_NOTIFY,0,(LPARAM)&pshn);
+
+ for(j=0;j<dat->opd[i].nExpertOnlyControls;j++)
+ ShowWindow(GetDlgItem(dat->opd[i].hwnd,dat->opd[i].expertOnlyControls[j]),expert?SW_SHOW:SW_HIDE);
+
+ dat->opd[i].insideTab = IsInsideTab( hdlg, dat, i );
+
+ GetWindowRect(dat->opd[i].hwnd,&rcPage);
+ if(dat->opd[i].simpleBottomControlId) newh=expert?dat->opd[i].expertHeight:dat->opd[i].simpleHeight;
+ else newh=rcPage.bottom-rcPage.top;
+ if(dat->opd[i].simpleRightControlId) neww=expert?dat->opd[i].expertWidth:dat->opd[i].simpleWidth;
+ else neww=rcPage.right-rcPage.left;
+ if(i==dat->currentPage) {
+ POINT ptStart,ptEnd,ptNow;
+ DWORD thisTick,startTick;
+ RECT rc;
+
+ ptNow.x=ptNow.y=0;
+ ClientToScreen(hdlg,&ptNow);
+ GetWindowRect(dat->opd[i].hwnd,&rc);
+ ptStart.x=rc.left-ptNow.x;
+ ptStart.y=rc.top-ptNow.y;
+ if (dat->opd[i].insideTab) {
+ ptEnd.x=(dat->rcTab.left+dat->rcTab.right-neww)>>1;
+ ptEnd.y=dat->rcTab.top;
+ } else {
+ ptEnd.x=(dat->rcDisplay.left+dat->rcDisplay.right-neww)>>1;
+ ptEnd.y=(dat->rcDisplay.top+dat->rcDisplay.bottom-newh)>>1;
+ }
+ if(abs(ptEnd.x-ptStart.x)>5 || abs(ptEnd.y-ptStart.y)>5) {
+ startTick=GetTickCount();
+ SetWindowPos(dat->opd[i].hwnd,HWND_TOP,0,0,min(neww,rcPage.right),min(newh,rcPage.bottom),SWP_NOMOVE);
+ UpdateWindow(dat->opd[i].hwnd);
+ for(;;) {
+ thisTick=GetTickCount();
+ if(thisTick>startTick+100) break;
+ ptNow.x=ptStart.x+(ptEnd.x-ptStart.x)*(int)(thisTick-startTick)/100;
+ ptNow.y=ptStart.y+(ptEnd.y-ptStart.y)*(int)(thisTick-startTick)/100;
+ SetWindowPos(dat->opd[i].hwnd,0,ptNow.x,ptNow.y,0,0,SWP_NOZORDER|SWP_NOSIZE);
+ }
+ }
+ if (dat->opd[i].insideTab)
+ ShowWindow(GetDlgItem(hdlg,IDC_TAB),SW_SHOW);
+ else
+ ShowWindow(GetDlgItem(hdlg,IDC_TAB),SW_HIDE);
+ }
+
+ if (dat->opd[i].insideTab) {
+ SetWindowPos(dat->opd[i].hwnd,HWND_TOP,(dat->rcTab.left+dat->rcTab.right-neww)>>1,dat->rcTab.top,neww,newh,0);
+ ThemeDialogBackground(dat->opd[i].hwnd,TRUE);
+ } else {
+ SetWindowPos(dat->opd[i].hwnd,HWND_TOP,(dat->rcDisplay.left+dat->rcDisplay.right-neww)>>1,(dat->rcDisplay.top+dat->rcDisplay.bottom-newh)>>1,neww,newh,0);
+ ThemeDialogBackground(dat->opd[i].hwnd,FALSE);
+ }
+ }
+ SaveOptionsTreeState(hdlg);
+ SendMessage(hdlg,DM_REBUILDPAGETREE,0,0);
+ break;
+ }
+ case IDCANCEL:
+ { int i;
+ PSHNOTIFY pshn;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=0;
+ pshn.hdr.code=PSN_RESET;
+ for(i=0;i<dat->pageCount;i++) {
+ if(dat->opd[i].hwnd==NULL || !dat->opd[i].changed) continue;
+ pshn.hdr.hwndFrom=dat->opd[i].hwnd;
+ SendMessage(dat->opd[i].hwnd,WM_NOTIFY,0,(LPARAM)&pshn);
+ }
+ DestroyWindow(hdlg);
+ break;
+ }
+ case IDOK:
+ case IDC_APPLY:
+ {
+ int i;
+ PSHNOTIFY pshn;
+
+ if (LOWORD(wParam) == IDOK && GetParent(GetFocus()) == GetDlgItem(hdlg, IDC_KEYWORD_FILTER))
+ return TRUE;
+
+ EnableWindow(GetDlgItem(hdlg,IDC_APPLY),FALSE);
+ SetFocus(hwndTree);
+ if(dat->currentPage!=(-1)) {
+ pshn.hdr.idFrom=0;
+ pshn.lParam=0;
+ pshn.hdr.code=PSN_KILLACTIVE;
+ pshn.hdr.hwndFrom=dat->opd[dat->currentPage].hwnd;
+ if(SendMessage(dat->opd[dat->currentPage].hwnd,WM_NOTIFY,0,(LPARAM)&pshn))
+ break;
+ }
+
+ pshn.hdr.code=PSN_APPLY;
+ for(i=0;i<dat->pageCount;i++) {
+ if(dat->opd[i].hwnd==NULL || !dat->opd[i].changed) continue;
+ dat->opd[i].changed=0;
+ pshn.hdr.hwndFrom=dat->opd[i].hwnd;
+ if(SendMessage(dat->opd[i].hwnd,WM_NOTIFY,0,(LPARAM)&pshn)==PSNRET_INVALID_NOCHANGEPAGE) {
+ dat->hCurrentPage=dat->opd[i].hTreeItem;
+ TreeView_SelectItem(hwndTree,dat->hCurrentPage);
+ if(dat->currentPage!=(-1)) ShowWindow(dat->opd[dat->currentPage].hwnd,SW_HIDE);
+ dat->currentPage=i;
+ if (dat->currentPage != (-1)) ShowWindow(dat->opd[dat->currentPage].hwnd,SW_SHOW);
+ return 0;
+ } }
+
+ if ( LOWORD( wParam ) == IDOK )
+ DestroyWindow(hdlg);
+ break;
+ } }
+ break;
+
+ case WM_DESTROY:
+ if ( FilterTimerId ) KillTimer ( hdlg, FilterTimerId );
+ DestroyWindow ( hFilterSearchWnd );
+ ClearFilterStrings();
+ dat->szFilterString[0]=0;
+
+ SaveOptionsTreeState( hdlg );
+ Window_FreeIcon_IcoLib( hdlg );
+
+ if ( dat->currentPage != -1 ) {
+ if ( dat->opd[dat->currentPage].pszTab )
+ DBWriteContactSettingTString( NULL, "Options", "LastTab", dat->opd[dat->currentPage].pszTab );
+ else DBDeleteContactSetting( NULL, "Options", "LastTab" );
+ if ( dat->opd[dat->currentPage].pszGroup )
+ DBWriteContactSettingTString( NULL, "Options", "LastGroup", dat->opd[dat->currentPage].pszGroup );
+ else DBDeleteContactSetting( NULL, "Options", "LastGroup" );
+ DBWriteContactSettingTString( NULL, "Options", "LastPage", dat->opd[dat->currentPage].pszTitle );
+ }
+ else {
+ DBDeleteContactSetting(NULL,"Options","LastTab");
+ DBDeleteContactSetting(NULL,"Options","LastGroup");
+ DBDeleteContactSetting(NULL,"Options","LastPage");
+ }
+ Utils_SaveWindowPosition(hdlg, NULL, "Options", "");
+ {
+ int i;
+ for ( i=0; i < dat->pageCount; i++ ) {
+ if ( dat->opd[i].hwnd != NULL )
+ DestroyWindow(dat->opd[i].hwnd);
+ mir_free(dat->opd[i].pszGroup);
+ mir_free(dat->opd[i].pszTab);
+ mir_free(dat->opd[i].pszTitle);
+ mir_free(dat->opd[i].pTemplate);
+ } }
+ mir_free( dat->opd );
+ DeleteObject( dat->hBoldFont );
+ mir_free( dat );
+ hwndOptions = NULL;
+
+ CallService(MS_MODERNOPT_RESTORE, 0, 0);
+ break;
+ }
+ return FALSE;
+}
+
+static void FreeOptionsData( struct OptionsPageInit* popi )
+{
+ int i;
+ for ( i=0; i < popi->pageCount; i++ ) {
+ mir_free(( char* )popi->odp[i].pszTitle );
+ mir_free( popi->odp[i].pszGroup );
+ mir_free( popi->odp[i].pszTab );
+ if (( DWORD_PTR )popi->odp[i].pszTemplate & 0xFFFF0000 )
+ mir_free((char*)popi->odp[i].pszTemplate);
+ }
+ mir_free(popi->odp);
+}
+
+void OpenAccountOptions( PROTOACCOUNT* pa )
+{
+ struct OptionsPageInit opi = { 0 };
+ if ( pa->ppro == NULL )
+ return;
+
+ pa->ppro->OnEvent( EV_PROTO_ONOPTIONS, ( WPARAM )&opi, 0 );
+ if ( opi.pageCount > 0 ) {
+ TCHAR tszTitle[ 100 ];
+ OPENOPTIONSDIALOG ood = { 0 };
+ PROPSHEETHEADER psh = { 0 };
+
+ mir_sntprintf( tszTitle, SIZEOF(tszTitle), TranslateT("%s options"), pa->tszAccountName );
+
+ ood.cbSize = sizeof(ood);
+ ood.pszGroup = LPGEN("Network");
+ ood.pszPage = mir_t2a( pa->tszAccountName );
+
+ psh.dwSize = sizeof(psh);
+ psh.dwFlags = PSH_PROPSHEETPAGE|PSH_NOAPPLYNOW;
+ psh.hwndParent = NULL;
+ psh.nPages = opi.pageCount;
+ psh.pStartPage = (LPCTSTR)&ood;
+ psh.pszCaption = tszTitle;
+ psh.ppsp = (PROPSHEETPAGE*)opi.odp;
+ hwndOptions = CreateDialogParam(hMirandaInst,MAKEINTRESOURCE(IDD_OPTIONSPAGE),NULL,OptionsDlgProc,(LPARAM)&psh);
+ mir_free(( void* )ood.pszPage );
+ FreeOptionsData( &opi );
+} }
+
+static void OpenOptionsNow(const char *pszGroup,const char *pszPage,const char *pszTab, bool bSinglePage=false)
+{
+ if ( IsWindow( hwndOptions )) {
+ ShowWindow( hwndOptions, SW_RESTORE );
+ SetForegroundWindow( hwndOptions );
+ if ( pszPage != NULL) {
+ TCHAR *ptszPage = LangPackPcharToTchar(pszPage);
+ HTREEITEM hItem = NULL;
+ if (pszGroup != NULL) {
+ TCHAR *ptszGroup = LangPackPcharToTchar(pszGroup);
+ hItem = FindNamedTreeItemAtRoot(GetDlgItem(hwndOptions,IDC_PAGETREE),ptszGroup);
+ if (hItem != NULL) {
+ hItem = FindNamedTreeItemAtChildren(GetDlgItem(hwndOptions,IDC_PAGETREE),hItem,ptszPage);
+ }
+ mir_free(ptszGroup);
+ } else {
+ hItem = FindNamedTreeItemAtRoot(GetDlgItem(hwndOptions,IDC_PAGETREE),ptszPage);
+ }
+ if (hItem != NULL) {
+ TreeView_SelectItem(GetDlgItem(hwndOptions,IDC_PAGETREE),hItem);
+ }
+ mir_free(ptszPage);
+ }
+ } else {
+ struct OptionsPageInit opi = { 0 };
+ NotifyEventHooks( hOptionsInitEvent, ( WPARAM )&opi, 0 );
+ if ( opi.pageCount > 0 ) {
+ OPENOPTIONSDIALOG ood = { 0 };
+ PROPSHEETHEADER psh = { 0 };
+ psh.dwSize = sizeof(psh);
+ psh.dwFlags = PSH_PROPSHEETPAGE | PSH_NOAPPLYNOW;
+ psh.nPages = opi.pageCount;
+ ood.pszGroup = pszGroup;
+ ood.pszPage = pszPage;
+ ood.pszTab = pszTab;
+ psh.pStartPage = (LPCTSTR)&ood; //more structure misuse
+ psh.pszCaption = TranslateT("Miranda IM Options");
+ psh.ppsp = (PROPSHEETPAGE*)opi.odp; //blatent misuse of the structure, but what the hell
+
+ hwndOptions = CreateDialogParam(hMirandaInst,
+ MAKEINTRESOURCE(bSinglePage ? IDD_OPTIONSPAGE : IDD_OPTIONS),
+ NULL, OptionsDlgProc, (LPARAM)&psh);
+
+ FreeOptionsData( &opi );
+} } }
+
+static INT_PTR OpenOptions(WPARAM, LPARAM lParam)
+{
+ OPENOPTIONSDIALOG *ood=(OPENOPTIONSDIALOG*)lParam;
+ if ( ood == NULL )
+ return 1;
+
+ if ( ood->cbSize == OPENOPTIONSDIALOG_OLD_SIZE )
+ OpenOptionsNow( ood->pszGroup, ood->pszPage, NULL );
+ else if (ood->cbSize == sizeof(OPENOPTIONSDIALOG))
+ OpenOptionsNow( ood->pszGroup, ood->pszPage, ood->pszTab );
+ else
+ return 1;
+
+ return 0;
+}
+
+static INT_PTR OpenOptionsPage(WPARAM, LPARAM lParam)
+{
+ OPENOPTIONSDIALOG *ood=(OPENOPTIONSDIALOG*)lParam;
+ if ( ood == NULL )
+ return 1;
+
+ if ( ood->cbSize == OPENOPTIONSDIALOG_OLD_SIZE )
+ OpenOptionsNow( ood->pszGroup, ood->pszPage, NULL, true );
+ else if (ood->cbSize == sizeof(OPENOPTIONSDIALOG))
+ OpenOptionsNow( ood->pszGroup, ood->pszPage, ood->pszTab, true );
+ else
+ return 1;
+
+ return (INT_PTR)hwndOptions;
+}
+
+static INT_PTR OpenOptionsDialog(WPARAM, LPARAM)
+{
+ if (hwndOptions || GetAsyncKeyState(VK_CONTROL) || !ServiceExists(MS_MODERNOPT_SHOW))
+ OpenOptionsNow(NULL,NULL,NULL);
+ else
+ CallService(MS_MODERNOPT_SHOW, 0, 0);
+ return 0;
+}
+
+static INT_PTR AddOptionsPage(WPARAM wParam,LPARAM lParam)
+{ OPTIONSDIALOGPAGE *odp=(OPTIONSDIALOGPAGE*)lParam, *dst;
+ struct OptionsPageInit *opi=(struct OptionsPageInit*)wParam;
+
+ if(odp==NULL||opi==NULL) return 1;
+ if(odp->cbSize!=sizeof(OPTIONSDIALOGPAGE)
+ && odp->cbSize != OPTIONPAGE_OLD_SIZE
+ && odp->cbSize != OPTIONPAGE_OLD_SIZE2
+ && odp->cbSize != OPTIONPAGE_OLD_SIZE3)
+ return 1;
+
+ opi->odp=(OPTIONSDIALOGPAGE*)mir_realloc(opi->odp,sizeof(OPTIONSDIALOGPAGE)*(opi->pageCount+1));
+ dst = opi->odp + opi->pageCount;
+ memset( dst, 0, sizeof( OPTIONSDIALOGPAGE ));
+ memcpy( dst, odp, odp->cbSize );
+
+ if ( odp->ptszTitle != NULL ) {
+ if ( odp->flags & ODPF_DONTTRANSLATE ) {
+ #if defined( _UNICODE )
+ if ( odp->flags & ODPF_UNICODE )
+ dst->ptszTitle = mir_wstrdup( odp->ptszTitle );
+ else {
+ dst->ptszTitle = mir_a2u( odp->pszTitle );
+ dst->flags |= ODPF_UNICODE;
+ }
+ #else
+ dst->pszTitle = mir_strdup( odp->pszTitle );
+ #endif
+ }
+ else {
+ #if defined( _UNICODE )
+ if ( odp->flags & ODPF_UNICODE )
+ dst->ptszTitle = mir_wstrdup( TranslateW( odp->ptszTitle ));
+ else {
+ dst->ptszTitle = LangPackPcharToTchar( odp->pszTitle );
+ dst->flags |= ODPF_UNICODE;
+ }
+ #else
+ dst->pszTitle = mir_strdup( Translate( odp->pszTitle ));
+ #endif
+ }
+ }
+
+ if ( odp->ptszGroup != NULL ) {
+ #if defined( _UNICODE )
+ if ( odp->flags & ODPF_UNICODE )
+ dst->ptszGroup = mir_wstrdup( TranslateW( odp->ptszGroup ));
+ else {
+ dst->ptszGroup = LangPackPcharToTchar( odp->pszGroup );
+ dst->flags |= ODPF_UNICODE;
+ }
+ #else
+ dst->pszGroup = mir_strdup( Translate( odp->pszGroup ));
+ #endif
+ }
+
+ if ( odp->cbSize > OPTIONPAGE_OLD_SIZE2 && odp->ptszTab != NULL ) {
+ #if defined( _UNICODE )
+ if ( odp->flags & ODPF_UNICODE )
+ dst->ptszTab = mir_wstrdup( TranslateW( odp->ptszTab ));
+ else {
+ dst->ptszTab = LangPackPcharToTchar( odp->pszTab );
+ dst->flags |= ODPF_UNICODE;
+ }
+ #else
+ dst->pszTab = mir_strdup( Translate( odp->pszTab ));
+ #endif
+ }
+
+ if (( DWORD_PTR )odp->pszTemplate & 0xFFFF0000 )
+ dst->pszTemplate = mir_strdup( odp->pszTemplate );
+
+ opi->pageCount++;
+ return 0;
+}
+
+static int OptModulesLoaded(WPARAM, LPARAM)
+{
+ CLISTMENUITEM mi = { 0 };
+ mi.cbSize = sizeof(mi);
+ mi.flags = CMIF_ICONFROMICOLIB;
+ mi.icolibItem = GetSkinIconHandle( SKINICON_OTHER_OPTIONS );
+ mi.position = 1900000000;
+ mi.pszName = LPGEN("&Options...");
+ mi.pszService = "Options/OptionsCommand";
+ CallService( MS_CLIST_ADDMAINMENUITEM, 0, ( LPARAM )&mi );
+ return 0;
+}
+
+int ShutdownOptionsModule(WPARAM, LPARAM)
+{
+ if (IsWindow(hwndOptions)) DestroyWindow(hwndOptions);
+ hwndOptions=NULL;
+
+ //!!!!!!!!!! UnhookFilterEvents();
+
+ return 0;
+}
+
+int LoadOptionsModule(void)
+{
+ hwndOptions=NULL;
+ hOptionsInitEvent=CreateHookableEvent(ME_OPT_INITIALISE);
+ CreateServiceFunction(MS_OPT_ADDPAGE,AddOptionsPage);
+ CreateServiceFunction(MS_OPT_OPENOPTIONS,OpenOptions);
+ CreateServiceFunction(MS_OPT_OPENOPTIONSPAGE,OpenOptionsPage);
+ CreateServiceFunction("Options/OptionsCommand",OpenOptionsDialog);
+ HookEvent(ME_SYSTEM_MODULESLOADED,OptModulesLoaded);
+ HookEvent(ME_SYSTEM_PRESHUTDOWN,ShutdownOptionsModule);
+
+ //!!!!!!!!!! HookFilterEvents();
+ return 0;
+}
diff --git a/src/modules/plugins/newplugins.cpp b/src/modules/plugins/newplugins.cpp
new file mode 100644
index 0000000000..80dddc00dd
--- /dev/null
+++ b/src/modules/plugins/newplugins.cpp
@@ -0,0 +1,1204 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2010 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"
+
+// block these plugins
+#define DEFMOD_REMOVED_UIPLUGINOPTS 21
+#define DEFMOD_REMOVED_PROTOCOLNETLIB 22
+
+// basic export prototypes
+typedef int (__cdecl * Miranda_Plugin_Load) ( PLUGINLINK * );
+typedef int (__cdecl * Miranda_Plugin_Unload) ( void );
+// version control
+typedef PLUGININFO * (__cdecl * Miranda_Plugin_Info) ( DWORD mirandaVersion );
+typedef PLUGININFOEX * (__cdecl * Miranda_Plugin_InfoEx) ( DWORD mirandaVersion );
+// prototype for databases
+typedef DATABASELINK * (__cdecl * Database_Plugin_Info) ( void * reserved );
+// prototype for clists
+typedef int (__cdecl * CList_Initialise) ( PLUGINLINK * );
+// Interface support
+typedef MUUID * (__cdecl * Miranda_Plugin_Interfaces) ( void );
+
+typedef struct { // can all be NULL
+ HINSTANCE hInst;
+ Miranda_Plugin_Load Load;
+ Miranda_Plugin_Unload Unload;
+ Miranda_Plugin_Info Info;
+ Miranda_Plugin_InfoEx InfoEx;
+ Miranda_Plugin_Interfaces Interfaces;
+ Database_Plugin_Info DbInfo;
+ CList_Initialise clistlink;
+ PLUGININFOEX * pluginInfo; // must be freed if hInst==NULL then its a copy
+ DATABASELINK * dblink; // only valid during module being in memory
+} BASIC_PLUGIN_INFO;
+
+#define PCLASS_FAILED 0x1 // not a valid plugin, or API is invalid, pluginname is valid
+#define PCLASS_BASICAPI 0x2 // has Load, Unload, MirandaPluginInfo() -> PLUGININFO seems valid, this dll is in memory.
+#define PCLASS_DB 0x4 // has DatabasePluginInfo() and is valid as can be, and PCLASS_BASICAPI has to be set too
+#define PCLASS_LAST 0x8 // this plugin should be unloaded after everything else
+#define PCLASS_OK 0x10 // plugin should be loaded, if DB means nothing
+#define PCLASS_LOADED 0x20 // Load() has been called, Unload() should be called.
+#define PCLASS_STOPPED 0x40 // wasn't loaded cos plugin name not on white list
+#define PCLASS_CLIST 0x80 // a CList implementation
+#define PCLASS_SERVICE 0x100 // has Service Mode implementation
+
+typedef struct pluginEntry {
+ TCHAR pluginname[64];
+ unsigned int pclass; // PCLASS_*
+ BASIC_PLUGIN_INFO bpi;
+ struct pluginEntry * nextclass;
+} pluginEntry;
+
+static int sttComparePlugins( const pluginEntry* p1, const pluginEntry* p2 )
+{ return ( int )( p1->bpi.hInst - p2->bpi.hInst );
+}
+
+static int sttComparePluginsByName( const pluginEntry* p1, const pluginEntry* p2 )
+{ return lstrcmp( p1->pluginname, p2->pluginname );
+}
+
+LIST<pluginEntry> pluginList( 10, sttComparePluginsByName ), pluginListAddr( 10, sttComparePlugins );
+
+/////////////////////////////////////////////////////////////////////////////////
+
+#define MAX_MIR_VER ULONG_MAX
+
+struct PluginUUIDList {
+ MUUID uuid;
+ DWORD maxVersion;
+}
+static const pluginBannedList[] =
+{
+ {{0x7f65393b, 0x7771, 0x4f3f, { 0xa9, 0xeb, 0x5d, 0xba, 0xf2, 0xb3, 0x61, 0xf1 }}, MAX_MIR_VER}, // png2dib
+ {{0xe00f1643, 0x263c, 0x4599, { 0xb8, 0x4b, 0x5, 0x3e, 0x5c, 0x51, 0x1d, 0x28 }}, MAX_MIR_VER}, // loadavatars (unicode)
+ {{0xc9e01eb0, 0xa119, 0x42d2, { 0xb3, 0x40, 0xe8, 0x67, 0x8f, 0x5f, 0xea, 0xd9 }}, MAX_MIR_VER}, // loadavatars (ansi)
+ {{0xb4ef58c4, 0x4458, 0x4e47, { 0xa7, 0x67, 0x5c, 0xae, 0xe5, 0xe7, 0xc, 0x81 }}, MAX_MIR_VER}, // 0.7.x AIM Protocol
+ {{0xb529402b, 0x53ba, 0x4c81, { 0x9e, 0x27, 0xd4, 0x31, 0xeb, 0xe8, 0xec, 0x36 }}, MAX_MIR_VER}, // 0.7.x IRC Protocol
+ {{0x847bb03c, 0x408c, 0x4f9b, { 0xaa, 0x5a, 0xf5, 0xc0, 0xb7, 0xb5, 0x60, 0x1e }}, MAX_MIR_VER}, // 0.7.x ICQ Protocol
+ {{0x1ee5af12, 0x26b0, 0x4290, { 0x8f, 0x97, 0x16, 0x77, 0xcb, 0xe, 0xfd, 0x2b }}, MAX_MIR_VER}, // 0.7.x Jabber Protocol (Unicode)
+ {{0xf7f5861d, 0x988d, 0x479d, { 0xa5, 0xbb, 0x80, 0xc7, 0xfa, 0x8a, 0xd0, 0xef }}, MAX_MIR_VER}, // 0.7.x Jabber Protocol (Ansi)
+ {{0xdc39da8a, 0x8385, 0x4cd9, { 0xb2, 0x98, 0x80, 0x67, 0x7b, 0x8f, 0xe6, 0xe4 }}, MAX_MIR_VER}, // 0.7.x MSN Protocol (Unicode)
+ {{0x29aa3a80, 0x3368, 0x4b78, { 0x82, 0xc1, 0xdf, 0xc7, 0x29, 0x6a, 0x58, 0x99 }}, MAX_MIR_VER}, // 0.7.x MSN Protocol (Ansi)
+ {{0xa6648b6c, 0x6fb8, 0x4551, { 0xb4, 0xe7, 0x1, 0x36, 0xf9, 0x16, 0xd4, 0x85 }}, MAX_MIR_VER}, // 0.7.x Yahoo Protocol
+ {{0x6ca5f042, 0x7a7f, 0x47cc, { 0xa7, 0x15, 0xfc, 0x8c, 0x46, 0xfb, 0xf4, 0x34 }}, PLUGIN_MAKE_VERSION(3, 0, 4, 0)}, // 0.8.x TabSRMM (Unicode)
+ {{0x5889a3ef, 0x7c95, 0x4249, { 0x98, 0xbb, 0x34, 0xe9, 0x5, 0x3a, 0x6e, 0xa0 }}, PLUGIN_MAKE_VERSION(3, 0, 4, 0)}, // 0.8.x TabSRMM (ANSI)
+ {{0x84636f78, 0x2057, 0x4302, { 0x8a, 0x65, 0x23, 0xa1, 0x6d, 0x46, 0x84, 0x4c }}, PLUGIN_MAKE_VERSION(2, 9, 0, 4)}, // 0.8.x Scriver (Unicode)
+ {{0x1e91b6c9, 0xe040, 0x4a6f, { 0xab, 0x56, 0xdf, 0x76, 0x98, 0xfa, 0xcb, 0xf1 }}, PLUGIN_MAKE_VERSION(2, 9, 0, 4)}, // 0.8.x Scriver (ANSI)
+ {{0x240a91dc, 0x9464, 0x457a, { 0x97, 0x87, 0xff, 0x1e, 0xa8, 0x8e, 0x77, 0xe3 }}, PLUGIN_MAKE_VERSION(0, 9, 0, 0)}, // 0.8.x CList Classic (Unicode)
+ {{0x552cf71a, 0x249f, 0x4650, { 0xbb, 0x2b, 0x7c, 0xdb, 0x1f, 0xe7, 0xd1, 0x78 }}, PLUGIN_MAKE_VERSION(0, 9, 0, 0)}, // 0.8.x CList Classic (ANSI)
+ {{0x8f79b4ee, 0xeb48, 0x4a03, { 0x87, 0x3e, 0x27, 0xbe, 0x6b, 0x7e, 0x9a, 0x25 }}, PLUGIN_MAKE_VERSION(0, 9, 1, 0)}, // 0.8.x Clist Nicer (Unicode)
+ {{0x5a070cec, 0xb2ab, 0x4bbe, { 0x8e, 0x48, 0x9c, 0x8d, 0xcd, 0xda, 0x14, 0xc3 }}, PLUGIN_MAKE_VERSION(0, 9, 1, 0)}, // 0.8.x Clist Nicer (ANSI)
+ {{0x43909b6, 0xaad8, 0x4d82, { 0x8e, 0xb5, 0x9f, 0x64, 0xcf, 0xe8, 0x67, 0xcd }}, PLUGIN_MAKE_VERSION(0, 9, 0, 8)}, // 0.8.x Clist Modern (Unicode)
+ {{0xf6588c56, 0x15dc, 0x4cd7, { 0x8c, 0xf9, 0x48, 0xab, 0x6c, 0x5f, 0xd2, 0xf }}, PLUGIN_MAKE_VERSION(0, 9, 0, 8)}, // 0.8.x Clist Modern (ANSI)
+ {{0x2a417ab9, 0x16f2, 0x472d, { 0x9a, 0xe3, 0x41, 0x51, 0x3, 0xc7, 0x8a, 0x64 }}, PLUGIN_MAKE_VERSION(0, 9, 0, 0)}, // 0.8.x Clist MW (Unicode)
+ {{0x7ab05d31, 0x9972, 0x4406, { 0x82, 0x3e, 0xe, 0xd7, 0x45, 0xef, 0x7c, 0x56 }}, PLUGIN_MAKE_VERSION(0, 9, 0, 0)} // 0.8.x Clist MW (ANSI)
+};
+const int pluginBannedListCount = SIZEOF(pluginBannedList);
+
+static BOOL bModuleInitialized = FALSE;
+
+PLUGINLINK pluginCoreLink;
+TCHAR mirandabootini[MAX_PATH];
+static DWORD mirandaVersion;
+static int serviceModeIdx = -1;
+static pluginEntry * pluginListSM;
+static pluginEntry * pluginListDb;
+static pluginEntry * pluginListUI;
+static pluginEntry * pluginList_freeimg;
+static pluginEntry * pluginList_crshdmp;
+static HANDLE hPluginListHeap = NULL;
+static pluginEntry * pluginDefModList[DEFMOD_HIGHEST+1]; // do not free this memory
+static int askAboutIgnoredPlugins;
+
+int InitIni(void);
+void UninitIni(void);
+
+#define PLUGINDISABLELIST "PluginDisable"
+
+int CallHookSubscribers( HANDLE hEvent, WPARAM wParam, LPARAM lParam );
+
+int LoadDatabaseModule(void);
+
+char * GetPluginNameByInstance( HINSTANCE hInstance )
+{
+ int i = 0;
+ if ( pluginList.getCount() == 0) return NULL;
+ for (i = 0; i < pluginList.getCount(); i++)
+ {
+ pluginEntry* pe = pluginList[i];
+ if (pe->bpi.pluginInfo && pe->bpi.hInst == hInstance)
+ return pe->bpi.pluginInfo->shortName;
+ }
+ return NULL;
+}
+
+HINSTANCE GetInstByAddress( void* codePtr )
+{
+ int idx;
+ HINSTANCE result;
+ pluginEntry p; p.bpi.hInst = ( HINSTANCE )codePtr;
+
+ if ( pluginListAddr.getCount() == 0 )
+ return NULL;
+
+ List_GetIndex(( SortedList* )&pluginListAddr, &p, &idx );
+ if ( idx > 0 )
+ idx--;
+
+ result = pluginListAddr[idx]->bpi.hInst;
+
+ if (result < hMirandaInst && codePtr > hMirandaInst)
+ result = hMirandaInst;
+ else if ( idx == 0 && codePtr < ( void* )result )
+ result = NULL;
+
+ return result;
+}
+
+static int uuidToString(const MUUID uuid, char *szStr, int cbLen)
+{
+ if (cbLen<1||!szStr) return 0;
+ mir_snprintf(szStr, cbLen, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
+ uuid.a, uuid.b, uuid.c, uuid.d[0], uuid.d[1], uuid.d[2], uuid.d[3], uuid.d[4], uuid.d[5], uuid.d[6], uuid.d[7]);
+ return 1;
+}
+
+static int equalUUID(MUUID u1, MUUID u2)
+{
+ return memcmp(&u1, &u2, sizeof(MUUID))?0:1;
+}
+
+static MUUID miid_last = MIID_LAST;
+static MUUID miid_servicemode = MIID_SERVICEMODE;
+
+static int validInterfaceList(Miranda_Plugin_Interfaces ifaceProc)
+{
+ MUUID *piface = ( ifaceProc ) ? ifaceProc() : NULL;
+ int i = 0/*, j*/;
+
+ if (!piface)
+ return 0;
+ if (equalUUID(miid_last, piface[0]))
+ return 0;
+ /*while (!equalUUID(miid_last, piface[i]) ) {
+ for (j=0; j<interfaceBannedListCount; j++) {
+ if (equalUUID(interfaceBannedList[j].uuid, piface[i]))
+ return 0;
+ i++;
+ }
+ break;
+ }*/
+ return 1;
+}
+
+static int isPluginBanned(MUUID u1, DWORD dwVersion) {
+ int i;
+
+ for (i=0; i<pluginBannedListCount; i++) {
+ if (equalUUID(pluginBannedList[i].uuid, u1)) {
+ if (dwVersion<pluginBannedList[i].maxVersion)
+ return 1;
+ return 0;
+ }
+ }
+ return 0;
+}
+
+// returns true if the API exports were good, otherwise, passed in data is returned
+#define CHECKAPI_NONE 0
+#define CHECKAPI_DB 1
+#define CHECKAPI_CLIST 2
+
+/*
+ * historyeditor added by nightwish - plugin is problematic and can ruin database as it does not understand UTF-8 message
+ * storage
+ */
+
+static const TCHAR* modulesToSkip[] =
+{
+ _T("autoloadavatars.dll"), _T("multiwindow.dll"), _T("fontservice.dll"),
+ _T("icolib.dll"), _T("historyeditor.dll")
+};
+
+// The following plugins will be checked for a valid MUUID or they will not be loaded
+static const TCHAR* expiredModulesToSkip[] =
+{
+ _T("scriver.dll"), _T("nconvers.dll"), _T("tabsrmm.dll"), _T("nhistory.dll"),
+ _T("historypp.dll"), _T("help.dll"), _T("loadavatars.dll"), _T("tabsrmm_unicode.dll"),
+ _T("clist_nicer_plus.dll"), _T("changeinfo.dll"), _T("png2dib.dll"), _T("dbx_mmap.dll"),
+ _T("dbx_3x.dll"), _T("sramm.dll"), _T("srmm_mod.dll"), _T("srmm_mod (no Unicode).dll"),
+ _T("singlemodeSRMM.dll"), _T("msg_export.dll"), _T("clist_modern.dll"),
+ _T("clist_nicer.dll")
+};
+
+static int checkPI( BASIC_PLUGIN_INFO* bpi, PLUGININFOEX* pi )
+{
+ int bHasValidInfo = FALSE;
+
+ if ( pi == NULL )
+ return FALSE;
+
+ if ( bpi->InfoEx ) {
+ if ( pi->cbSize == sizeof(PLUGININFOEX))
+ if ( !validInterfaceList(bpi->Interfaces) || isPluginBanned( pi->uuid, pi->version ))
+ return FALSE;
+
+ bHasValidInfo = TRUE;
+ }
+
+ if ( !bHasValidInfo )
+ if ( bpi->Info && pi->cbSize != sizeof(PLUGININFO))
+ return FALSE;
+
+ if ( pi->shortName == NULL || pi->description == NULL || pi->author == NULL ||
+ pi->authorEmail == NULL || pi->copyright == NULL || pi->homepage == NULL )
+ return FALSE;
+
+ if ( pi->replacesDefaultModule > DEFMOD_HIGHEST ||
+ pi->replacesDefaultModule == DEFMOD_REMOVED_UIPLUGINOPTS ||
+ pi->replacesDefaultModule == DEFMOD_REMOVED_PROTOCOLNETLIB )
+ return FALSE;
+
+ return TRUE;
+}
+
+static int checkAPI(TCHAR* plugin, BASIC_PLUGIN_INFO* bpi, DWORD mirandaVersion, int checkTypeAPI, int* exports)
+{
+ HINSTANCE h = NULL;
+ // this is evil but these plugins are buggy/old and people are blaming Miranda
+ // fontservice plugin is built into the core now
+ {
+ TCHAR * p = _tcsrchr(plugin, '\\');
+ if ( p != NULL && ++p ) {
+ int i;
+ for ( i = 0; i < SIZEOF(modulesToSkip); i++ )
+ if ( lstrcmpi( p, modulesToSkip[i] ) == 0 )
+ return 0;
+ } }
+
+ h = LoadLibrary(plugin);
+ if ( h == NULL ) return 0;
+ // loaded, check for exports
+ bpi->Load = (Miranda_Plugin_Load) GetProcAddress(h, "Load");
+ bpi->Unload = (Miranda_Plugin_Unload) GetProcAddress(h, "Unload");
+ bpi->Info = (Miranda_Plugin_Info) GetProcAddress(h, "MirandaPluginInfo");
+ bpi->InfoEx = (Miranda_Plugin_InfoEx) GetProcAddress(h, "MirandaPluginInfoEx");
+ bpi->Interfaces = (Miranda_Plugin_Interfaces) GetProcAddress(h, "MirandaPluginInterfaces");
+
+ // if they were present
+ if ( bpi->Load && bpi->Unload && ( bpi->Info || ( bpi->InfoEx && bpi->Interfaces ))) {
+ PLUGININFOEX* pi = 0;
+ if (bpi->InfoEx)
+ pi = bpi->InfoEx(mirandaVersion);
+ else
+ pi = (PLUGININFOEX*)bpi->Info(mirandaVersion);
+ {
+ // similar to the above hack but these plugins are checked for a valid interface first (in case there are updates to the plugin later)
+ TCHAR* p = _tcsrchr(plugin, '\\');
+ if ( pi != NULL && p != NULL && ++p ) {
+ if ( !bpi->InfoEx || pi->cbSize != sizeof(PLUGININFOEX)) {
+ int i;
+ for ( i = 0; i < SIZEOF(expiredModulesToSkip); i++ ) {
+ if ( lstrcmpi( p, expiredModulesToSkip[i] ) == 0 ) {
+ FreeLibrary(h);
+ return 0;
+ } } } } }
+
+ if ( checkPI( bpi, pi )) {
+ bpi->pluginInfo = pi;
+ // basic API is present
+ if ( checkTypeAPI == CHECKAPI_NONE ) {
+ bpi->hInst=h;
+ return 1;
+ }
+ // check for DB?
+ if ( checkTypeAPI == CHECKAPI_DB ) {
+ bpi->DbInfo = (Database_Plugin_Info) GetProcAddress(h, "DatabasePluginInfo");
+ if ( bpi->DbInfo ) {
+ // fetch internal database function pointers
+ bpi->dblink = bpi->DbInfo(NULL);
+ // validate returned link structure
+ if ( bpi->dblink && bpi->dblink->cbSize==sizeof(DATABASELINK) ) {
+ bpi->hInst=h;
+ return 1;
+ }
+ // had DB exports
+ if ( exports != NULL ) *exports=1;
+ } //if
+ } //if
+
+ // check clist ?
+ if ( checkTypeAPI == CHECKAPI_CLIST ) {
+ bpi->clistlink = (CList_Initialise) GetProcAddress(h, "CListInitialise");
+ #if defined( _UNICODE )
+ if ( pi->flags & UNICODE_AWARE )
+ #endif
+ if ( bpi->clistlink ) {
+ // nothing more can be done here, this export is a load function
+ bpi->hInst=h;
+ if ( exports != NULL ) *exports=1;
+ return 1;
+ }
+ }
+
+ } // if
+ if ( exports != NULL ) *exports=1;
+ } //if
+ // not found, unload
+ FreeLibrary(h);
+ return 0;
+}
+
+// returns true if the given file is <anything>.dll exactly
+static int valid_library_name(TCHAR *name)
+{
+ TCHAR * dot = _tcsrchr(name, '.');
+ if ( dot != NULL && lstrcmpi(dot + 1, _T("dll")) == 0)
+ if (dot[4] == 0)
+ return 1;
+
+ return 0;
+}
+
+// returns true if the given file matches dbx_*.dll, which is used to LoadLibrary()
+static int validguess_db_name(TCHAR * name)
+{
+ int rc = 0;
+ // this is ONLY SAFE because name -> ffd.cFileName == MAX_PATH
+ TCHAR x = name[4];
+ name[4]=0;
+ rc = lstrcmpi(name, _T("dbx_")) == 0 || lstrcmpi(name, _T("dbrw")) == 0;
+ name[4] = x;
+ return rc;
+}
+
+// returns true if the given file matches clist_*.dll
+static int validguess_clist_name(TCHAR * name)
+{
+ int rc=0;
+ // argh evil
+ TCHAR x = name[6];
+ name[6] = 0;
+ rc = lstrcmpi(name, _T("clist_")) == 0;
+ name[6] = x;
+ return rc;
+}
+
+// returns true if the given file matches svc_*.dll
+static int validguess_servicemode_name(TCHAR * name)
+{
+ int rc = 0;
+ // argh evil
+ TCHAR x = name[4];
+ name[4]=0;
+ rc = lstrcmpi(name, _T("svc_")) == 0;
+ name[4] = x;
+ return rc;
+}
+
+// perform any API related tasks to freeing
+static void Plugin_Uninit(pluginEntry * p)
+{
+ // if it was an installed database plugin, call its unload
+ if ( p->pclass & PCLASS_DB )
+ p->bpi.dblink->Unload( p->pclass & PCLASS_OK );
+
+ // if the basic API check had passed, call Unload if Load() was ever called
+ if ( p->pclass & PCLASS_LOADED )
+ p->bpi.Unload();
+
+ // release the library
+ if ( p->bpi.hInst != NULL ) {
+ // we need to kill all resources which belong to that DLL before calling FreeLibrary
+ KillModuleEventHooks( p->bpi.hInst );
+ KillModuleServices( p->bpi.hInst );
+
+ FreeLibrary( p->bpi.hInst );
+ ZeroMemory( &p->bpi, sizeof( p->bpi ));
+ }
+ pluginList.remove( p );
+ pluginListAddr.remove( p );
+}
+
+typedef BOOL (*SCAN_PLUGINS_CALLBACK) ( WIN32_FIND_DATA * fd, TCHAR * path, WPARAM wParam, LPARAM lParam );
+
+static void enumPlugins(SCAN_PLUGINS_CALLBACK cb, WPARAM wParam, LPARAM lParam)
+{
+ TCHAR exe[MAX_PATH];
+ TCHAR search[MAX_PATH];
+ TCHAR * p = 0;
+ // get miranda's exe path
+ GetModuleFileName(NULL, exe, SIZEOF(exe));
+ // find the last \ and null it out, this leaves no trailing slash
+ p = _tcsrchr(exe, '\\'); if (p) *p = 0;
+ // create the search filter
+ mir_sntprintf(search, SIZEOF(search), _T("%s\\Plugins\\*.dll"), exe);
+ {
+ // FFFN will return filenames for things like dot dll+ or dot dllx
+ HANDLE hFind=INVALID_HANDLE_VALUE;
+ WIN32_FIND_DATA ffd;
+ hFind = FindFirstFile(search, &ffd);
+ if (hFind != INVALID_HANDLE_VALUE)
+ {
+ do {
+ if (!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && valid_library_name(ffd.cFileName))
+ {
+ cb(&ffd, exe, wParam, lParam);
+ } //if
+ } while (FindNextFile(hFind, &ffd));
+ FindClose(hFind);
+ } //if
+ }
+}
+
+// this is called by the db module to return all DBs plugins, then when it finds the one it likes the others are unloaded
+static INT_PTR PluginsEnum(WPARAM, LPARAM lParam)
+{
+ PLUGIN_DB_ENUM * de = (PLUGIN_DB_ENUM *) lParam;
+ pluginEntry * x = pluginListDb;
+ if ( de == NULL || de->cbSize != sizeof(PLUGIN_DB_ENUM) || de->pfnEnumCallback == NULL ) return 1;
+ while ( x != NULL )
+ {
+ int rc = de->pfnEnumCallback(StrConvA(x->pluginname), x->bpi.dblink, de->lParam);
+ if (rc == DBPE_DONE)
+ {
+ // this db has been picked, get rid of all the others
+ pluginEntry * y = pluginListDb, * n;
+ while ( y != NULL )
+ {
+ n = y->nextclass;
+ if ( x != y )
+ Plugin_Uninit(y);
+ y = n;
+ } // while
+ x->pclass |= PCLASS_LOADED | PCLASS_OK | PCLASS_LAST;
+ return 0;
+ }
+ else if ( rc == DBPE_HALT ) return 1;
+ x = x->nextclass;
+ } // while
+ return pluginListDb != NULL ? 1 : -1;
+}
+
+static INT_PTR PluginsGetDefaultArray(WPARAM, LPARAM)
+{
+ return (INT_PTR)&pluginDefModList;
+}
+
+// called in the first pass to create pluginEntry* structures and validate database plugins
+static BOOL scanPluginsDir (WIN32_FIND_DATA * fd, TCHAR * path, WPARAM, LPARAM)
+{
+ int isdb = validguess_db_name(fd->cFileName);
+ BASIC_PLUGIN_INFO bpi;
+ pluginEntry* p = (pluginEntry*)HeapAlloc(hPluginListHeap, HEAP_NO_SERIALIZE | HEAP_ZERO_MEMORY, sizeof(pluginEntry));
+ _tcsncpy(p->pluginname, fd->cFileName, SIZEOF(p->pluginname));
+ // plugin name suggests its a db module, load it right now
+ if ( isdb )
+ {
+ TCHAR buf[MAX_PATH];
+ mir_sntprintf(buf, SIZEOF(buf), _T("%s\\Plugins\\%s"), path, fd->cFileName);
+ if (checkAPI(buf, &bpi, mirandaVersion, CHECKAPI_DB, NULL))
+ {
+ // db plugin is valid
+ p->pclass |= (PCLASS_DB | PCLASS_BASICAPI);
+ // copy the dblink stuff
+ p->bpi=bpi;
+ // keep a faster list.
+ if ( pluginListDb != NULL ) p->nextclass = pluginListDb;
+ pluginListDb=p;
+ }
+ else
+ // didn't have basic APIs or DB exports - failed.
+ p->pclass |= PCLASS_FAILED;
+ }
+ else if (validguess_clist_name(fd->cFileName))
+ {
+ // keep a note of this plugin for later
+ if ( pluginListUI != NULL ) p->nextclass=pluginListUI;
+ pluginListUI=p;
+ p->pclass |= PCLASS_CLIST;
+ }
+ else if (validguess_servicemode_name(fd->cFileName))
+ {
+ TCHAR buf[MAX_PATH];
+ mir_sntprintf(buf, SIZEOF(buf), _T("%s\\Plugins\\%s"), path, fd->cFileName);
+ if (checkAPI(buf, &bpi, mirandaVersion, CHECKAPI_NONE, NULL))
+ {
+ p->pclass |= (PCLASS_OK | PCLASS_BASICAPI);
+ p->bpi = bpi;
+ if (bpi.Interfaces)
+ {
+ int i = 0;
+ MUUID *piface = bpi.Interfaces();
+ while (!equalUUID(miid_last, piface[i]))
+ {
+ if (!equalUUID(miid_servicemode, piface[i++]))
+ continue;
+ p->pclass |= (PCLASS_SERVICE);
+ if ( pluginListSM != NULL ) p->nextclass = pluginListSM;
+ pluginListSM=p;
+ if (pluginList_crshdmp == NULL && lstrcmpi(fd->cFileName, _T("svc_crshdmp.dll")) == 0)
+ {
+ pluginList_crshdmp = p;
+ p->pclass |= PCLASS_LAST;
+ }
+ break;
+ }
+ }
+ }
+ else
+ // didn't have basic APIs or DB exports - failed.
+ p->pclass |= PCLASS_FAILED;
+ }
+ else if (pluginList_freeimg == NULL && lstrcmpi(fd->cFileName, _T("advaimg.dll")) == 0)
+ pluginList_freeimg = p;
+
+ // add it to the list
+ pluginList.insert( p );
+ return TRUE;
+}
+
+static void SetPluginOnWhiteList(TCHAR * pluginname, int allow)
+{
+ DBWriteContactSettingByte(NULL, PLUGINDISABLELIST, StrConvA(pluginname), allow == 0);
+}
+
+// returns 1 if the plugin should be enabled within this profile, filename is always lower case
+static int isPluginOnWhiteList(TCHAR * pluginname)
+{
+ char* pluginnameA = _strlwr(mir_t2a(pluginname));
+ int rc = DBGetContactSettingByte(NULL, PLUGINDISABLELIST, pluginnameA, 0);
+ mir_free(pluginnameA);
+ if ( rc != 0 && askAboutIgnoredPlugins )
+ {
+ TCHAR buf[256];
+ mir_sntprintf(buf, SIZEOF(buf), TranslateT("'%s' is disabled, re-enable?"), pluginname);
+ if (MessageBox(NULL, buf, TranslateT("Re-enable Miranda plugin?"), MB_YESNO | MB_ICONQUESTION) == IDYES)
+ {
+ SetPluginOnWhiteList(pluginname, 1);
+ rc = 0;
+ }
+ }
+
+ return rc == 0;
+}
+
+static pluginEntry* getCListModule(TCHAR * exe, TCHAR * slice, int useWhiteList)
+{
+ pluginEntry * p = pluginListUI;
+ BASIC_PLUGIN_INFO bpi;
+ while ( p != NULL )
+ {
+ mir_sntprintf(slice, &exe[MAX_PATH] - slice, _T("\\Plugins\\%s"), p->pluginname);
+ CharLower(p->pluginname);
+ if ( useWhiteList ? isPluginOnWhiteList(p->pluginname) : 1 ) {
+ if ( checkAPI(exe, &bpi, mirandaVersion, CHECKAPI_CLIST, NULL) ) {
+ p->bpi = bpi;
+ p->pclass |= PCLASS_LAST | PCLASS_OK | PCLASS_BASICAPI;
+ pluginListAddr.insert( p );
+ if ( bpi.clistlink(&pluginCoreLink) == 0 ) {
+ p->bpi = bpi;
+ p->pclass |= PCLASS_LOADED;
+ return p;
+ }
+ else Plugin_Uninit( p );
+ } //if
+ } //if
+ p = p->nextclass;
+ }
+ return NULL;
+}
+
+int UnloadPlugin(TCHAR* buf, int bufLen)
+{
+ int i;
+ for ( i = pluginList.getCount()-1; i >= 0; i-- )
+ {
+ pluginEntry* p = pluginList[i];
+ if (!_tcsicmp( p->pluginname, buf))
+ {
+ GetModuleFileName( p->bpi.hInst, buf, bufLen);
+ Plugin_Uninit( p );
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+//
+// Service plugins functions
+
+char **GetSeviceModePluginsList(void)
+{
+ int i = 0;
+ char **list = NULL;
+ pluginEntry * p = pluginListSM;
+ while ( p != NULL ) {
+ i++;
+ p = p->nextclass;
+ }
+ if ( i ) {
+ list = (char**)mir_calloc( (i + 1) * sizeof(char*) );
+ p = pluginListSM;
+ i = 0;
+ while ( p != NULL ) {
+ list[i++] = p->bpi.pluginInfo->shortName;
+ p = p->nextclass;
+ }
+ }
+ return list;
+}
+
+void SetServiceModePlugin( int idx )
+{
+ serviceModeIdx = idx;
+}
+
+int LoadServiceModePlugin(void)
+{
+ int i = 0;
+ pluginEntry * p = pluginListSM;
+
+ if ( serviceModeIdx < 0 )
+ return 0;
+
+ while ( p != NULL ) {
+ if ( serviceModeIdx == i++ ) {
+ if ( p->bpi.Load(&pluginCoreLink) == 0 ) {
+ p->pclass |= PCLASS_LOADED;
+ if ( CallService( MS_SERVICEMODE_LAUNCH, 0, 0 ) != CALLSERVICE_NOTFOUND )
+ return 1;
+ else {
+ MessageBox(NULL, TranslateT("Unable to load plugin in Service Mode!"), p->pluginname, 0);
+ return -1;
+ }
+ }
+ Plugin_Uninit( p );
+ return -1;
+ }
+ p = p->nextclass;
+ }
+ return -1;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+//
+// Event hook to unload all non-core plugins
+// hooked very late, after all the internal plugins, blah
+
+void UnloadNewPlugins(void)
+{
+ int i;
+
+ // unload everything but the special db/clist plugins
+ for ( i = pluginList.getCount()-1; i >= 0; i-- ) {
+ pluginEntry* p = pluginList[i];
+ if ( !(p->pclass & PCLASS_LAST) && (p->pclass & PCLASS_OK))
+ Plugin_Uninit( p );
+} }
+
+/////////////////////////////////////////////////////////////////////////////////////////
+//
+// Plugins options page dialog
+
+typedef struct
+{
+ int flags;
+ char* author;
+ char* authorEmail;
+ char* description;
+ char* copyright;
+ char* homepage;
+ MUUID uuid;
+}
+ PluginListItemData;
+
+static BOOL dialogListPlugins(WIN32_FIND_DATA * fd, TCHAR * path, WPARAM, LPARAM lParam)
+{
+ LVITEM it;
+ int iRow;
+ HWND hwndList=(HWND)lParam;
+ BASIC_PLUGIN_INFO pi;
+ int exports=0;
+ TCHAR buf[MAX_PATH];
+ int isdb = 0;
+ HINSTANCE gModule;
+ PluginListItemData* dat;
+
+ mir_sntprintf(buf, SIZEOF(buf), _T("%s\\Plugins\\%s"), path, fd->cFileName);
+ CharLower(fd->cFileName);
+ gModule = GetModuleHandle(buf);
+ if ( checkAPI(buf, &pi, mirandaVersion, CHECKAPI_NONE, &exports) == 0 ) {
+ // failed to load anything, but if exports were good, show some info.
+ return TRUE;
+ }
+ isdb = pi.pluginInfo->replacesDefaultModule == DEFMOD_DB;
+ ZeroMemory(&it, sizeof(it));
+ it.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
+ it.pszText = fd->cFileName;
+ it.iImage = ( pi.pluginInfo->flags & 1 ) ? 0 : 1;
+ it.lParam = (LPARAM)( dat = (PluginListItemData*)mir_alloc( sizeof( PluginListItemData )));
+ iRow=SendMessage( hwndList, LVM_INSERTITEM, 0, (LPARAM)&it );
+ if ( isPluginOnWhiteList(fd->cFileName) )
+ ListView_SetItemState(hwndList, iRow, !isdb ? 0x2000 : 0x3000, LVIS_STATEIMAGEMASK);
+ if ( iRow != -1 ) {
+ dat->flags = pi.pluginInfo->replacesDefaultModule;
+ dat->author = mir_strdup( pi.pluginInfo->author );
+ dat->authorEmail = mir_strdup( pi.pluginInfo->authorEmail );
+ dat->copyright = mir_strdup( pi.pluginInfo->copyright );
+ dat->description = mir_strdup( pi.pluginInfo->description );
+ dat->homepage = mir_strdup( pi.pluginInfo->homepage );
+ if ( pi.pluginInfo->cbSize == sizeof( PLUGININFOEX ))
+ dat->uuid = pi.pluginInfo->uuid;
+ else
+ memset( &dat->uuid, 0, sizeof(dat->uuid));
+
+ TCHAR *shortNameT = mir_a2t(pi.pluginInfo->shortName);
+ ListView_SetItemText(hwndList, iRow, 1, shortNameT);
+ mir_free(shortNameT);
+
+ mir_sntprintf(buf, SIZEOF(buf), _T("%d.%d.%d.%d"), HIBYTE(HIWORD(pi.pluginInfo->version)),
+ LOBYTE(HIWORD(pi.pluginInfo->version)), HIBYTE(LOWORD(pi.pluginInfo->version)),
+ LOBYTE(LOWORD(pi.pluginInfo->version)));
+ ListView_SetItemText(hwndList, iRow, 2, buf);
+
+ it.mask = LVIF_IMAGE;
+ it.iItem = iRow;
+ it.iSubItem = 3;
+ it.iImage = ( gModule != NULL ) ? 2 : 3;
+ ListView_SetItem( hwndList, &it );
+ }
+ else mir_free( dat );
+ FreeLibrary(pi.hInst);
+ return TRUE;
+}
+
+static void RemoveAllItems( HWND hwnd )
+{
+ LVITEM lvi;
+ lvi.mask = LVIF_PARAM;
+ lvi.iItem = 0;
+ while ( ListView_GetItem( hwnd, &lvi )) {
+ PluginListItemData* dat = ( PluginListItemData* )lvi.lParam;
+ mir_free( dat->author );
+ mir_free( dat->authorEmail );
+ mir_free( dat->copyright );
+ mir_free( dat->description );
+ mir_free( dat->homepage );
+ mir_free( dat );
+ lvi.iItem ++;
+} }
+
+INT_PTR CALLBACK DlgPluginOpt(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ {
+ HWND hwndList=GetDlgItem(hwndDlg,IDC_PLUGLIST);
+ LVCOLUMN col;
+ HIMAGELIST hIml = ImageList_Create(16, 16, ILC_MASK | (IsWinVerXPPlus()? ILC_COLOR32 : ILC_COLOR16), 4, 0);
+ ImageList_AddIcon_IconLibLoaded( hIml, SKINICON_OTHER_UNICODE );
+ ImageList_AddIcon_IconLibLoaded( hIml, SKINICON_OTHER_ANSI );
+ ImageList_AddIcon_IconLibLoaded( hIml, SKINICON_OTHER_LOADED );
+ ImageList_AddIcon_IconLibLoaded( hIml, SKINICON_OTHER_NOTLOADED );
+ ListView_SetImageList( hwndList, hIml, LVSIL_SMALL );
+
+ TranslateDialogDefault(hwndDlg);
+
+ col.mask = LVCF_TEXT | LVCF_WIDTH;
+ col.pszText = TranslateT("Plugin");
+ col.cx = 70;//max = 140;
+ ListView_InsertColumn(hwndList,0,&col);
+
+ col.pszText=TranslateT("Name");
+ col.cx = 70;//max = 220;
+ ListView_InsertColumn(hwndList,1,&col);
+
+ col.pszText=TranslateT("Version");
+ col.cx=55;
+ ListView_InsertColumn(hwndList,2,&col);
+
+ col.pszText=_T("");
+ col.cx=20;
+ ListView_InsertColumn(hwndList,3,&col);
+ //ListView_InsertColumn(hwndList,4,&col);
+
+ // XXX: Won't work on windows 95 without IE3+ or 4.70
+ ListView_SetExtendedListViewStyleEx( hwndList, 0, LVS_EX_SUBITEMIMAGES | LVS_EX_CHECKBOXES | LVS_EX_LABELTIP | LVS_EX_FULLROWSELECT );
+ // scan the plugin dir for plugins, cos
+ enumPlugins( dialogListPlugins, ( WPARAM )hwndDlg, ( LPARAM )hwndList );
+ // sort out the headers
+ {
+ int w, max;
+
+ ListView_SetColumnWidth( hwndList, 0, LVSCW_AUTOSIZE ); // dll name
+ w = ListView_GetColumnWidth( hwndList, 0 );
+ if (w>140) {
+ ListView_SetColumnWidth( hwndList, 0, 140 );
+ w = 140;
+ }
+ max = w<140? 220+140-w:220;
+ ListView_SetColumnWidth( hwndList, 1, LVSCW_AUTOSIZE ); // short name
+ w = ListView_GetColumnWidth( hwndList, 1 );
+ if (w>max)
+ ListView_SetColumnWidth( hwndList, 1, max );
+ }
+ return TRUE;
+ }
+ case WM_NOTIFY:
+ {
+ NMLISTVIEW * hdr = (NMLISTVIEW *) lParam;
+ if ( hdr && hdr->hdr.code == LVN_ITEMCHANGED && hdr->uOldState != 0
+ && (hdr->uNewState == 0x1000 || hdr->uNewState == 0x2000 ) && IsWindowVisible(hdr->hdr.hwndFrom) ) {
+ HWND hwndList = GetDlgItem(hwndDlg,IDC_PLUGLIST);
+ PluginListItemData* dat;
+ int iRow;
+ LVITEM it;
+ it.mask=LVIF_PARAM | LVIF_STATE;
+ it.iItem = hdr->iItem;
+ if ( !ListView_GetItem( hwndList, &it ))
+ break;
+
+ dat = ( PluginListItemData* )it.lParam;
+ if ( dat->flags == DEFMOD_DB ) {
+ ListView_SetItemState(hwndList, hdr->iItem, 0x3000, LVIS_STATEIMAGEMASK);
+ return FALSE;
+ }
+ // if enabling and replaces, find all other replaces and toggle off
+ if ( hdr->uNewState & 0x2000 && dat->flags != 0 ) {
+ for ( iRow=0; iRow != -1; ) {
+ if ( iRow != hdr->iItem ) {
+ LVITEM dt;
+ dt.mask = LVIF_PARAM;
+ dt.iItem = iRow;
+ if ( ListView_GetItem( hwndList, &dt )) {
+ PluginListItemData* dat2 = ( PluginListItemData* )dt.lParam;
+ if ( dat2->flags == dat->flags ) {
+ // the lParam is unset, so when the check is unset the clist block doesnt trigger
+ int lParam = dat2->flags;
+ dat2->flags = 0;
+ ListView_SetItemState(hwndList, iRow, 0x1000, LVIS_STATEIMAGEMASK );
+ dat2->flags = lParam;
+ } } }
+
+ iRow = ListView_GetNextItem( hwndList, iRow, LVNI_ALL );
+ } }
+
+ ShowWindow( GetDlgItem(hwndDlg, IDC_RESTART ), TRUE );
+ SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 );
+ break;
+ }
+
+ if ( hdr && hdr->hdr.code == LVN_ITEMCHANGED && IsWindowVisible(hdr->hdr.hwndFrom) && hdr->iItem != -1 ) {
+ TCHAR buf[1024];
+ int sel = hdr->uNewState & LVIS_SELECTED;
+ HWND hwndList = GetDlgItem(hwndDlg, IDC_PLUGLIST);
+ LVITEM lvi = { 0 };
+ lvi.mask = LVIF_PARAM;
+ lvi.iItem = hdr->iItem;
+ if ( ListView_GetItem( hwndList, &lvi )) {
+ PluginListItemData* dat = ( PluginListItemData* )lvi.lParam;
+
+ ListView_GetItemText(hwndList, hdr->iItem, 1, buf, SIZEOF(buf));
+ SetWindowText(GetDlgItem(hwndDlg,IDC_PLUGININFOFRAME),sel ? buf : _T(""));
+
+ SetWindowTextA(GetDlgItem(hwndDlg,IDC_PLUGINAUTHOR), sel ? dat->author : "" );
+ SetWindowTextA(GetDlgItem(hwndDlg,IDC_PLUGINEMAIL), sel ? dat->authorEmail : "" );
+ {
+ TCHAR* p = LangPackPcharToTchar( dat->description );
+ SetWindowText(GetDlgItem(hwndDlg,IDC_PLUGINLONGINFO), sel ? p : _T(""));
+ mir_free( p );
+ }
+ SetWindowTextA(GetDlgItem(hwndDlg,IDC_PLUGINCPYR), sel ? dat->copyright : "" );
+ SetWindowTextA(GetDlgItem(hwndDlg,IDC_PLUGINURL), sel ? dat->homepage : "" );
+ if(equalUUID(miid_last, dat->uuid))
+ SetWindowText(GetDlgItem(hwndDlg,IDC_PLUGINPID), sel ? TranslateT("<none>") : _T(""));
+ else
+ {
+ char szUID[128];
+ uuidToString( dat->uuid, szUID, sizeof(szUID));
+ SetWindowTextA(GetDlgItem(hwndDlg,IDC_PLUGINPID), sel ? szUID : "" );
+ }
+ } }
+
+ if ( hdr && hdr->hdr.code == PSN_APPLY ) {
+ HWND hwndList=GetDlgItem(hwndDlg,IDC_PLUGLIST);
+ int iRow;
+ int iState;
+ TCHAR buf[1024];
+ for (iRow=0 ; iRow != (-1) ; ) {
+ ListView_GetItemText(hwndList, iRow, 0, buf, SIZEOF(buf));
+ iState=ListView_GetItemState(hwndList, iRow, LVIS_STATEIMAGEMASK);
+ SetPluginOnWhiteList(buf, iState&0x2000 ? 1 : 0);
+ iRow=ListView_GetNextItem(hwndList, iRow, LVNI_ALL);
+ } }
+ break;
+ }
+
+ case WM_COMMAND:
+ if ( HIWORD(wParam) == STN_CLICKED ) {
+ switch (LOWORD(wParam)) {
+ case IDC_PLUGINEMAIL:
+ case IDC_PLUGINURL:
+ {
+ char buf[512];
+ char * p = &buf[7];
+ lstrcpyA(buf,"mailto:");
+ if ( GetWindowTextA(GetDlgItem(hwndDlg, LOWORD(wParam)), p, SIZEOF(buf) - 7) ) {
+ CallService(MS_UTILS_OPENURL,0,(LPARAM) (LOWORD(wParam)==IDC_PLUGINEMAIL ? buf : p) );
+ }
+ break;
+ }
+ case IDC_GETMOREPLUGINS:
+ {
+ CallService(MS_UTILS_OPENURL,0,(LPARAM) "http://addons.miranda-im.org/index.php?action=display&id=1" );
+ break;
+ }
+ } }
+ break;
+
+ case WM_DESTROY:
+ RemoveAllItems( GetDlgItem( hwndDlg, IDC_PLUGLIST ));
+ break;
+ }
+ return FALSE;
+}
+
+static int PluginOptionsInit(WPARAM wParam, LPARAM)
+{
+ OPTIONSDIALOGPAGE odp = { 0 };
+ odp.cbSize = sizeof(odp);
+ odp.hInstance = hMirandaInst;
+ odp.pfnDlgProc = DlgPluginOpt;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_PLUGINS);
+ odp.position = 1300000000;
+ odp.pszTitle = LPGEN("Plugins");
+ odp.flags = ODPF_BOLDGROUPS;
+ CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+//
+// Loads all plugins
+
+int LoadNewPluginsModule(void)
+{
+ TCHAR exe[MAX_PATH];
+ TCHAR* slice;
+ pluginEntry* p;
+ pluginEntry* clist = NULL;
+ int useWhiteList, i;
+ bool msgModule = false;
+
+ // make full path to the plugin
+ GetModuleFileName(NULL, exe, SIZEOF(exe));
+ slice = _tcsrchr(exe, '\\');
+ if (slice) *slice = 0;
+
+ // remember some useful options
+ askAboutIgnoredPlugins=(UINT) GetPrivateProfileInt( _T("PluginLoader"), _T("AskAboutIgnoredPlugins"), 0, mirandabootini);
+
+ // if Crash Dumper is present, load it to provide Crash Reports
+ if (pluginList_crshdmp != NULL && isPluginOnWhiteList(pluginList_crshdmp->pluginname))
+ {
+ if ( pluginList_crshdmp->bpi.Load(&pluginCoreLink) == 0 )
+ pluginList_crshdmp->pclass |= PCLASS_LOADED | PCLASS_LAST;
+ else
+ Plugin_Uninit( pluginList_crshdmp );
+ }
+
+ // if freeimage is present, load it to provide the basic core functions
+ if ( pluginList_freeimg != NULL ) {
+ BASIC_PLUGIN_INFO bpi;
+ mir_sntprintf(slice, &exe[SIZEOF(exe)] - slice, _T("\\Plugins\\%s"), pluginList_freeimg->pluginname);
+ if ( checkAPI(exe, &bpi, mirandaVersion, CHECKAPI_NONE, NULL) ) {
+ pluginList_freeimg->bpi = bpi;
+ pluginList_freeimg->pclass |= PCLASS_OK | PCLASS_BASICAPI;
+ if ( bpi.Load(&pluginCoreLink) == 0 )
+ pluginList_freeimg->pclass |= PCLASS_LOADED;
+ else
+ Plugin_Uninit( pluginList_freeimg );
+ } }
+
+ // first load the clist cos alot of plugins need that to be present at Load()
+ for ( useWhiteList = 1; useWhiteList >= 0 && clist == NULL; useWhiteList-- )
+ clist=getCListModule(exe, slice, useWhiteList);
+ /* the loop above will try and get one clist DLL to work, if all fail then just bail now */
+ if ( clist == NULL ) {
+ // result = 0, no clist_* can be found
+ if ( pluginListUI )
+ MessageBox(NULL, TranslateT("Unable to start any of the installed contact list plugins, I even ignored your preferences for which contact list couldn't load any."), _T("Miranda IM"), MB_OK | MB_ICONINFORMATION);
+ else
+ MessageBox(NULL, TranslateT("Can't find a contact list plugin! you need clist_classic or any other clist plugin.") , _T("Miranda IM"), MB_OK | MB_ICONINFORMATION);
+ return 1;
+ }
+
+ /* enable and disable as needed */
+ p = pluginListUI;
+ while ( p != NULL ) {
+ SetPluginOnWhiteList(p->pluginname, clist != p ? 0 : 1 );
+ p = p->nextclass;
+ }
+ /* now loop thru and load all the other plugins, do this in one pass */
+
+ for ( i=0; i < pluginList.getCount(); i++ ) {
+ p = pluginList[i];
+ CharLower(p->pluginname);
+ if (!(p->pclass & (PCLASS_LOADED | PCLASS_DB | PCLASS_CLIST)))
+ {
+ if (isPluginOnWhiteList(p->pluginname))
+ {
+ BASIC_PLUGIN_INFO bpi;
+ mir_sntprintf(slice, &exe[SIZEOF(exe)] - slice, _T("\\Plugins\\%s"), p->pluginname);
+ if ( checkAPI(exe, &bpi, mirandaVersion, CHECKAPI_NONE, NULL) ) {
+ int rm = bpi.pluginInfo->replacesDefaultModule;
+ p->bpi = bpi;
+ p->pclass |= PCLASS_OK | PCLASS_BASICAPI;
+
+ if ( pluginDefModList[rm] == NULL ) {
+ pluginListAddr.insert( p );
+ if ( bpi.Load(&pluginCoreLink) == 0 ) {
+ p->pclass |= PCLASS_LOADED;
+ msgModule |= (bpi.pluginInfo->replacesDefaultModule == DEFMOD_SRMESSAGE);
+ }
+ else {
+ Plugin_Uninit( p );
+ i--;
+ }
+ if ( rm ) pluginDefModList[rm]=p;
+ } //if
+ else {
+ SetPluginOnWhiteList( p->pluginname, 0 );
+ Plugin_Uninit( p );
+ i--;
+ }
+ }
+ else p->pclass |= PCLASS_FAILED;
+ }
+ else {
+ Plugin_Uninit( p );
+ i--;
+ }
+ }
+ else if ( p->bpi.hInst != NULL )
+ {
+ pluginListAddr.insert( p );
+ p->pclass |= PCLASS_LOADED;
+ }
+ }
+ if (!msgModule)
+ MessageBox(NULL, TranslateT("No messaging plugins loaded. Please install/enable one of the messaging plugins, for instance, \"srmm.dll\""), _T("Miranda IM"), MB_OK | MB_ICONINFORMATION);
+
+ HookEvent(ME_OPT_INITIALISE, PluginOptionsInit);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+//
+// Plugins module initialization
+// called before anything real is loaded, incl. database
+
+int LoadNewPluginsModuleInfos(void)
+{
+ bModuleInitialized = TRUE;
+
+ hPluginListHeap=HeapCreate(HEAP_NO_SERIALIZE, 0, 0);
+ mirandaVersion = (DWORD)CallService(MS_SYSTEM_GETVERSION, 0, 0);
+ //
+ CreateServiceFunction(MS_PLUGINS_ENUMDBPLUGINS, PluginsEnum);
+ CreateServiceFunction(MS_PLUGINS_GETDISABLEDEFAULTARRAY, PluginsGetDefaultArray);
+ // make sure plugins can get internal core APIs
+ pluginCoreLink.CallService = CallService;
+ pluginCoreLink.ServiceExists = ServiceExists;
+ pluginCoreLink.CreateServiceFunction = CreateServiceFunction;
+ pluginCoreLink.CreateServiceFunctionParam = CreateServiceFunctionParam;
+ pluginCoreLink.CreateServiceFunctionObj = CreateServiceFunctionObj;
+ pluginCoreLink.CreateServiceFunctionObjParam = CreateServiceFunctionObjParam;
+ pluginCoreLink.CreateTransientServiceFunction = CreateServiceFunction;
+ pluginCoreLink.DestroyServiceFunction = DestroyServiceFunction;
+ pluginCoreLink.CreateHookableEvent = CreateHookableEvent;
+ pluginCoreLink.DestroyHookableEvent = DestroyHookableEvent;
+ pluginCoreLink.HookEvent = HookEvent;
+ pluginCoreLink.HookEventParam = HookEventParam;
+ pluginCoreLink.HookEventObj = HookEventObj;
+ pluginCoreLink.HookEventObjParam = HookEventObjParam;
+ pluginCoreLink.HookEventMessage = HookEventMessage;
+ pluginCoreLink.UnhookEvent = UnhookEvent;
+ pluginCoreLink.NotifyEventHooks = NotifyEventHooks;
+ pluginCoreLink.SetHookDefaultForHookableEvent = SetHookDefaultForHookableEvent;
+ pluginCoreLink.CallServiceSync = CallServiceSync;
+ pluginCoreLink.CallFunctionAsync = CallFunctionAsync;
+ pluginCoreLink.NotifyEventHooksDirect = CallHookSubscribers;
+ pluginCoreLink.CallProtoService = CallProtoService;
+ pluginCoreLink.CallContactService = CallContactService;
+ pluginCoreLink.KillObjectServices = KillObjectServices;
+ pluginCoreLink.KillObjectEventHooks = KillObjectEventHooks;
+
+ // remember where the mirandaboot.ini goes
+ pathToAbsoluteT(_T("mirandaboot.ini"), mirandabootini, NULL);
+ // look for all *.dll's
+ enumPlugins(scanPluginsDir, 0, 0);
+ // the database will select which db plugin to use, or fail if no profile is selected
+ if (LoadDatabaseModule()) return 1;
+ InitIni();
+ // could validate the plugin entries here but internal modules arent loaded so can't call Load() in one pass
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+//
+// Plugins module unloading
+// called at the end of module chain unloading, just modular engine left at this point
+
+void UnloadNewPluginsModule(void)
+{
+ int i;
+
+ if ( !bModuleInitialized ) return;
+
+ // unload everything but the DB
+ for ( i = pluginList.getCount()-1; i >= 0; i-- ) {
+ pluginEntry* p = pluginList[i];
+ if ( !(p->pclass & PCLASS_DB) && p != pluginList_crshdmp )
+ Plugin_Uninit( p );
+ }
+
+ if ( pluginList_crshdmp )
+ Plugin_Uninit( pluginList_crshdmp );
+
+ // unload the DB
+ for ( i = pluginList.getCount()-1; i >= 0; i-- ) {
+ pluginEntry* p = pluginList[i];
+ Plugin_Uninit( p );
+ }
+
+ if ( hPluginListHeap ) HeapDestroy(hPluginListHeap);
+ hPluginListHeap=0;
+
+ pluginList.destroy();
+ pluginListAddr.destroy();
+ UninitIni();
+}
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;
+}
diff --git a/src/modules/skin/hotkeys.cpp b/src/modules/skin/hotkeys.cpp
new file mode 100644
index 0000000000..cd87fda1a7
--- /dev/null
+++ b/src/modules/skin/hotkeys.cpp
@@ -0,0 +1,1465 @@
+/*
+
+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_hotkeys.h>
+
+#define DBMODULENAME "SkinHotKeys"
+#define WM_HOTKEYUNREGISTERED (WM_USER+721)
+
+typedef enum { HKT_GLOBAL, HKT_LOCAL, HKT_MANUAL, HKT_COUNT } THotkeyType;
+
+typedef struct _THotkeyItem THotkeyItem;
+struct _THotkeyItem
+{
+ THotkeyType type;
+ char *pszService, *pszName; // pszName is valid _only_ for "root" hotkeys
+ TCHAR *ptszSection, *ptszDescription;
+ TCHAR *ptszSection_tr, *ptszDescription_tr;
+ LPARAM lParam;
+ WORD DefHotkey, Hotkey;
+ bool Enabled;
+ ATOM idHotkey;
+
+ THotkeyItem *rootHotkey;
+ int nSubHotkeys;
+ bool allowSubHotkeys;
+
+ bool OptChanged, OptDeleted, OptNew;
+ WORD OptHotkey;
+ THotkeyType OptType;
+ bool OptEnabled;
+
+ bool UnregisterHotkey; // valid only during WM_APP message in options UI, used to remove unregistered hotkeys from options
+};
+
+static int sttCompareHotkeys(const THotkeyItem *p1, const THotkeyItem *p2)
+{
+ int res;
+ if ( res = lstrcmp( p1->ptszSection_tr, p2->ptszSection_tr ))
+ return res;
+ if ( res = lstrcmp( p1->ptszDescription_tr, p2->ptszDescription_tr ))
+ return res;
+ if (!p1->rootHotkey && p2->rootHotkey)
+ return -1;
+ if (p1->rootHotkey && !p2->rootHotkey)
+ return 1;
+ return 0;
+}
+
+static LIST<THotkeyItem> hotkeys( 10, sttCompareHotkeys );
+
+static void sttFreeHotkey(THotkeyItem *item);
+
+static BOOL bModuleInitialized = FALSE;
+static HWND g_hwndHotkeyHost = NULL;
+static HWND g_hwndOptions = NULL;
+static DWORD g_pid = 0;
+static int g_hotkeyCount = 0;
+static HANDLE hEvChanged = 0;
+
+static LRESULT CALLBACK sttHotkeyHostWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+static TCHAR *sttHokeyVkToName(WORD vkKey);
+static void sttHotkeyEditCreate(HWND hwnd);
+static void sttHotkeyEditDestroy(HWND hwnd);
+static LRESULT CALLBACK sttHotkeyEditProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+static void sttRegisterHotkeys();
+static void sttUnregisterHotkeys();
+
+static INT_PTR svcHotkeySubclass(WPARAM wParam, LPARAM lParam);
+static INT_PTR svcHotkeyUnsubclass(WPARAM wParam, LPARAM lParam);
+static INT_PTR svcHotkeyRegister(WPARAM wParam, LPARAM lParam);
+static INT_PTR svcHotkeyUnregister(WPARAM wParam, LPARAM lParam);
+static INT_PTR svcHotkeyCheck(WPARAM wParam, LPARAM lParam);
+
+HHOOK hhkKeyboard = NULL;
+static LRESULT CALLBACK sttKeyboardProc(int code, WPARAM wParam, LPARAM lParam);
+
+static void sttWordToModAndVk(WORD w, BYTE *mod, BYTE *vk)
+{
+ *mod = 0;
+ if (HIBYTE(w) & HOTKEYF_CONTROL) *mod |= MOD_CONTROL;
+ if (HIBYTE(w) & HOTKEYF_SHIFT) *mod |= MOD_SHIFT;
+ if (HIBYTE(w) & HOTKEYF_ALT) *mod |= MOD_ALT;
+ if (HIBYTE(w) & HOTKEYF_EXT) *mod |= MOD_WIN;
+ *vk = LOBYTE(w);
+}
+
+static LRESULT CALLBACK sttHotkeyHostWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ if (msg == WM_HOTKEY ) {
+ int i;
+ for (i = 0; i < hotkeys.getCount(); i++) {
+ THotkeyItem *item = hotkeys[i];
+ if (item->type != HKT_GLOBAL) continue;
+ if (!item->Enabled) continue;
+ if (item->pszService && (wParam == item->idHotkey)) {
+ CallService(item->pszService, 0, item->lParam);
+ break;
+ } }
+
+ return FALSE;
+ }
+
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+}
+
+static LRESULT CALLBACK sttKeyboardProc(int code, WPARAM wParam, LPARAM lParam)
+{
+ if (code == HC_ACTION && !(HIWORD(lParam) & KF_UP)) {
+ int i;
+ BYTE mod=0, vk=wParam;
+
+ if ( vk ) {
+ if (GetAsyncKeyState(VK_CONTROL)) mod |= MOD_CONTROL;
+ if (GetAsyncKeyState(VK_MENU)) mod |= MOD_ALT;
+ if (GetAsyncKeyState(VK_SHIFT)) mod |= MOD_SHIFT;
+ if (GetAsyncKeyState(VK_LWIN) || GetAsyncKeyState(VK_RWIN)) mod |= MOD_WIN;
+
+ for ( i = 0; i < hotkeys.getCount(); i++ ) {
+ THotkeyItem *item = hotkeys[i];
+ BYTE hkMod, hkVk;
+ if (item->type != HKT_LOCAL) continue;
+ sttWordToModAndVk(item->Hotkey, &hkMod, &hkVk);
+ if (!hkVk) continue;
+ if (!item->Enabled) continue;
+ if (item->pszService && (vk == hkVk) && (mod == hkMod)) {
+ CallService(item->pszService, 0, item->lParam);
+ return TRUE;
+ } } } }
+
+ return CallNextHookEx(hhkKeyboard, code, wParam, lParam);
+}
+
+static INT_PTR svcHotkeySubclass(WPARAM wParam, LPARAM)
+{
+ sttHotkeyEditCreate((HWND)wParam);
+ return 0;
+}
+
+static INT_PTR svcHotkeyUnsubclass(WPARAM wParam, LPARAM)
+{
+ sttHotkeyEditDestroy((HWND)wParam);
+ return 0;
+}
+
+static INT_PTR svcHotkeyRegister(WPARAM wParam, LPARAM lParam)
+{
+ HOTKEYDESC *desc = (HOTKEYDESC *)lParam;
+ if ( desc->cbSize != sizeof(HOTKEYDESC) && desc->cbSize != HOTKEYDESC_SIZE_V1 )
+ return 0;
+
+ THotkeyItem *item = ( THotkeyItem* )mir_alloc(sizeof(THotkeyItem));
+ #if defined( _UNICODE )
+ DWORD dwFlags = ( desc->cbSize >= sizeof(HOTKEYDESC)) ? desc->dwFlags : 0;
+ if ( dwFlags & HKD_UNICODE ) {
+ item->ptszSection = mir_tstrdup( desc->ptszSection );
+ item->ptszDescription = mir_tstrdup( desc->ptszDescription );
+ }
+ else {
+ item->ptszSection = mir_a2u( desc->pszSection );
+ item->ptszDescription = mir_a2u( desc->pszDescription );
+ }
+ #else
+ item->ptszSection = mir_tstrdup( desc->pszSection );
+ item->ptszDescription = mir_tstrdup( desc->pszDescription );
+ #endif
+ item->ptszSection_tr = TranslateTS(item->ptszSection);
+ item->ptszDescription_tr = TranslateTS(item->ptszDescription);
+ item->allowSubHotkeys = TRUE;
+ item->rootHotkey = NULL;
+ item->nSubHotkeys = 0;
+
+ if ( item->rootHotkey = hotkeys.find( item )) {
+ if (item->rootHotkey->allowSubHotkeys) {
+ char nameBuf[MAXMODULELABELLENGTH];
+ mir_snprintf(nameBuf, SIZEOF(nameBuf), "%s$%d", item->rootHotkey->pszName, item->rootHotkey->nSubHotkeys);
+ item->pszName = mir_strdup(nameBuf);
+ item->Enabled = TRUE;
+
+ item->rootHotkey->nSubHotkeys++;
+ }
+ else {
+ mir_free(item->ptszSection);
+ mir_free(item->ptszDescription);
+ mir_free(item);
+ return 0;
+ }
+ }
+ else {
+ item->pszName = mir_strdup(desc->pszName);
+ item->Enabled = !DBGetContactSettingByte(NULL, DBMODULENAME "Off", item->pszName, 0);
+ }
+
+ item->pszService = desc->pszService ? mir_strdup(desc->pszService) : 0;
+ item->DefHotkey = desc->DefHotKey & ~HKF_MIRANDA_LOCAL;
+ item->Hotkey = DBGetContactSettingWord(NULL, DBMODULENAME, item->pszName, item->DefHotkey);
+ item->type = item->pszService ?
+ ( THotkeyType )DBGetContactSettingByte(NULL, DBMODULENAME "Types", item->pszName,
+ (desc->DefHotKey & HKF_MIRANDA_LOCAL) ? HKT_LOCAL : HKT_GLOBAL) : HKT_MANUAL;
+ item->lParam = desc->lParam;
+
+ char buf[256];
+ mir_snprintf(buf, SIZEOF(buf), "mir_hotkey_%d_%d", g_pid, g_hotkeyCount++);
+ item->idHotkey = GlobalAddAtomA(buf);
+ if (item->type == HKT_GLOBAL) {
+ if (item->Enabled) {
+ BYTE mod, vk;
+ sttWordToModAndVk(item->Hotkey, &mod, &vk);
+ if (vk) RegisterHotKey(g_hwndHotkeyHost, item->idHotkey, mod, vk);
+ } }
+
+ hotkeys.insert( item );
+
+ if ( !item->rootHotkey ) {
+ /* try to load alternatives from db */
+ int count, i;
+ mir_snprintf(buf, SIZEOF(buf), "%s$count", item->pszName);
+ count = (int)DBGetContactSettingDword(NULL, DBMODULENAME, buf, -1);
+ for (i = 0; i < count; i++) {
+ mir_snprintf(buf, SIZEOF(buf), "%s$%d", item->pszName, i);
+ if (!DBGetContactSettingWord(NULL, DBMODULENAME, buf, 0))
+ continue;
+
+ svcHotkeyRegister(wParam, lParam);
+ }
+ item->allowSubHotkeys = count < 0;
+ }
+ else {
+ mir_free( item->pszName );
+ item->pszName = NULL;
+ }
+
+ return item->idHotkey;
+}
+
+static INT_PTR svcHotkeyUnregister(WPARAM, LPARAM lParam)
+{
+ int i;
+ char *pszName = (char *)lParam;
+ char pszNamePrefix[MAXMODULELABELLENGTH];
+ size_t cbNamePrefix;
+ mir_snprintf(pszNamePrefix, SIZEOF(pszNamePrefix), "%s$", pszName);
+ cbNamePrefix = strlen(pszNamePrefix);
+
+ for (i = 0; i < hotkeys.getCount(); ++i)
+ {
+ char *pszCurrentName = hotkeys[i]->rootHotkey ?
+ hotkeys[i]->rootHotkey->pszName :
+ hotkeys[i]->pszName;
+ if (!pszCurrentName) continue;
+
+ hotkeys[i]->UnregisterHotkey =
+ !lstrcmpA(pszCurrentName, pszName) ||
+ !strncmp(pszCurrentName, pszNamePrefix, cbNamePrefix);
+ }
+
+ if (g_hwndOptions)
+ SendMessage(g_hwndOptions, WM_HOTKEYUNREGISTERED, 0, 0);
+
+ for (i = 0; i < hotkeys.getCount(); ++i)
+ if (hotkeys[i]->UnregisterHotkey) {
+ sttFreeHotkey(hotkeys[i]);
+ List_Remove((SortedList *)&hotkeys, i);
+ --i;
+ }
+
+ return 0;
+}
+
+static INT_PTR svcHotkeyCheck(WPARAM wParam, LPARAM lParam)
+{
+ MSG *msg = (MSG *)wParam;
+ TCHAR *pszSection = mir_a2t((char *)lParam);
+
+ if ((msg->message == WM_KEYDOWN) || (msg->message == WM_SYSKEYDOWN)) {
+ int i;
+ BYTE mod=0, vk=msg->wParam;
+
+ if (vk) {
+ if (GetAsyncKeyState(VK_CONTROL)) mod |= MOD_CONTROL;
+ if (GetAsyncKeyState(VK_MENU)) mod |= MOD_ALT;
+ if (GetAsyncKeyState(VK_SHIFT)) mod |= MOD_SHIFT;
+ if (GetAsyncKeyState(VK_LWIN) || GetAsyncKeyState(VK_RWIN)) mod |= MOD_WIN;
+
+ for ( i = 0; i < hotkeys.getCount(); i++ ) {
+ THotkeyItem *item = hotkeys[i];
+ BYTE hkMod, hkVk;
+ if ((item->type != HKT_MANUAL) || lstrcmp(pszSection, item->ptszSection)) continue;
+ sttWordToModAndVk(item->Hotkey, &hkMod, &hkVk);
+ if (!hkVk) continue;
+ if (!item->Enabled) continue;
+ if ((vk == hkVk) && (mod == hkMod)) {
+ mir_free(pszSection);
+ return item->lParam;
+ } } } }
+
+ mir_free(pszSection);
+ return 0;
+}
+
+static void sttFreeHotkey(THotkeyItem *item)
+{
+ if ( item->type == HKT_GLOBAL && item->Enabled )
+ UnregisterHotKey(g_hwndHotkeyHost, item->idHotkey);
+ GlobalDeleteAtom(item->idHotkey);
+ mir_free(item->pszName);
+ mir_free(item->pszService);
+ mir_free(item->ptszDescription);
+ mir_free(item->ptszSection);
+ mir_free(item);
+}
+
+static void sttRegisterHotkeys()
+{
+ int i;
+ for ( i = 0; i < hotkeys.getCount(); i++ ) {
+ THotkeyItem *item = hotkeys[i];
+ UnregisterHotKey(g_hwndHotkeyHost, item->idHotkey);
+ if (item->type != HKT_GLOBAL) continue;
+ if (item->Enabled) {
+ BYTE mod, vk;
+ sttWordToModAndVk(item->Hotkey, &mod, &vk);
+ if (vk) RegisterHotKey(g_hwndHotkeyHost, item->idHotkey, mod, vk);
+} } }
+
+static void sttUnregisterHotkeys()
+{
+ int i;
+ for (i = 0; i < hotkeys.getCount(); i++) {
+ THotkeyItem *item = hotkeys[i];
+ if ( item->type == HKT_GLOBAL && item->Enabled )
+ UnregisterHotKey(g_hwndHotkeyHost, item->idHotkey);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Hotkey control
+typedef struct
+{
+ WNDPROC oldWndProc;
+ BYTE shift;
+ BYTE key;
+}
+ THotkeyBoxData;
+
+static TCHAR *sttHokeyVkToName(WORD vkKey)
+{
+ static TCHAR buf[256] = {0};
+ DWORD code = MapVirtualKey(vkKey, 0) << 16;
+
+ switch (vkKey)
+ {
+ case 0:
+ case VK_CONTROL:
+ case VK_SHIFT:
+ case VK_MENU:
+ case VK_LWIN:
+ case VK_RWIN:
+ case VK_PAUSE:
+ case VK_CANCEL:
+ case VK_NUMLOCK:
+ case VK_CAPITAL:
+ case VK_SCROLL:
+ return _T("");
+
+ case VK_DIVIDE:
+ case VK_INSERT:
+ case VK_HOME:
+ case VK_PRIOR:
+ case VK_DELETE:
+ case VK_END:
+ case VK_NEXT:
+ case VK_LEFT:
+ case VK_RIGHT:
+ case VK_UP:
+ case VK_DOWN:
+ code |= (1UL << 24);
+ }
+
+ GetKeyNameText(code, buf, 256);
+ return buf;
+}
+
+void HotkeyToName(TCHAR *buf, int size, BYTE shift, BYTE key)
+{
+ mir_sntprintf(buf, size, _T("%s%s%s%s%s"),
+ (shift & HOTKEYF_CONTROL) ? _T("Ctrl + ") : _T(""),
+ (shift & HOTKEYF_ALT) ? _T("Alt + ") : _T(""),
+ (shift & HOTKEYF_SHIFT) ? _T("Shift + ") : _T(""),
+ (shift & HOTKEYF_EXT) ? _T("Win + ") : _T(""),
+ sttHokeyVkToName(key));
+}
+
+WORD GetHotkeyValue(INT_PTR idHotkey)
+{
+ for (int i = 0; i < hotkeys.getCount(); i++)
+ if (hotkeys[i]->idHotkey == idHotkey)
+ return hotkeys[i]->Enabled ? hotkeys[i]->Hotkey : 0;
+
+ return 0;
+}
+
+static LRESULT CALLBACK sttHotkeyEditProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ THotkeyBoxData *data = (THotkeyBoxData *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ BOOL bKeyDown = FALSE;
+ if (!data) return 0;
+
+ switch (msg) {
+ case HKM_GETHOTKEY:
+ return data->key ? MAKEWORD(data->key, data->shift) : 0;
+
+ case HKM_SETHOTKEY:
+ {
+ TCHAR buf[256] = {0};
+ data->key = (BYTE)LOWORD(wParam);
+ data->shift = (BYTE)HIWORD(wParam);
+ HotkeyToName(buf, SIZEOF(buf), data->shift, data->key);
+ SetWindowText(hwnd, buf);
+ return 0;
+ }
+
+ case WM_GETDLGCODE:
+ return DLGC_WANTALLKEYS;
+
+ case WM_KILLFOCUS:
+ break;
+
+ case WM_CHAR:
+ case WM_SYSCHAR:
+ case WM_PASTE:
+ case WM_CONTEXTMENU:
+ return TRUE;
+
+ case WM_KEYDOWN:
+ case WM_SYSKEYDOWN:
+ bKeyDown = TRUE;
+
+ case WM_KEYUP:
+ case WM_SYSKEYUP:
+ {
+ TCHAR buf[256] = {0};
+
+ BYTE shift = 0;
+ BYTE key = wParam;
+ TCHAR *name = sttHokeyVkToName(key);
+ if (!*name || !bKeyDown) key = 0;
+
+ if (GetAsyncKeyState(VK_CONTROL)) shift |= HOTKEYF_CONTROL;
+ if (GetAsyncKeyState(VK_MENU)) shift |= HOTKEYF_ALT;
+ if (GetAsyncKeyState(VK_SHIFT)) shift |= HOTKEYF_SHIFT;
+ if (GetAsyncKeyState(VK_LWIN) || GetAsyncKeyState(VK_RWIN)) shift |= HOTKEYF_EXT;
+
+ if (bKeyDown || !data->key) {
+ data->shift = shift;
+ data->key = key;
+ }
+
+ HotkeyToName(buf, SIZEOF(buf), data->shift, data->key);
+ SetWindowText(hwnd, buf);
+
+ if (bKeyDown && data->key)
+ SendMessage(GetParent(hwnd), WM_COMMAND, MAKELONG(GetWindowLongPtr(hwnd, GWL_ID), 0), (LPARAM)hwnd);
+ return TRUE;
+ }
+
+ case WM_DESTROY:
+ {
+ WNDPROC saveOldWndProc = data->oldWndProc;
+ SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)data->oldWndProc);
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, 0);
+ mir_free(data);
+ return CallWindowProc(saveOldWndProc, hwnd, msg, wParam, lParam);
+ } }
+
+ return CallWindowProc(data->oldWndProc, hwnd, msg, wParam, lParam);
+}
+
+static void sttHotkeyEditCreate(HWND hwnd)
+{
+ THotkeyBoxData *data = (THotkeyBoxData *)mir_alloc(sizeof(THotkeyBoxData));
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, (ULONG_PTR)data);
+ data->oldWndProc = (WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (ULONG_PTR)sttHotkeyEditProc);
+}
+
+static void sttHotkeyEditDestroy(HWND hwnd)
+{
+ THotkeyBoxData *data = (THotkeyBoxData *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+ SetWindowLongPtr(hwnd, GWLP_WNDPROC, (ULONG_PTR)data->oldWndProc);
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, 0);
+ mir_free(data);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Options
+
+enum { COL_NAME, COL_TYPE, COL_KEY, COL_RESET, COL_ADDREMOVE };
+
+static void sttOptionsSetupItem(HWND hwndList, int idx, THotkeyItem *item)
+{
+ TCHAR buf[256];
+ LVITEM lvi = {0};
+ lvi.iItem = idx;
+
+ if ( !item->rootHotkey ) {
+ lvi.mask = LVIF_TEXT|LVIF_IMAGE;
+ lvi.iSubItem = COL_NAME;
+ lvi.pszText = item->ptszDescription_tr;
+ lvi.iImage = item->OptType;
+ ListView_SetItem(hwndList, &lvi);
+
+ ListView_SetCheckState(hwndList, lvi.iItem, item->Enabled);
+ }
+
+ lvi.mask = LVIF_TEXT;
+ lvi.iSubItem = COL_KEY;
+ HotkeyToName(buf, SIZEOF(buf), HIBYTE(item->OptHotkey), LOBYTE(item->OptHotkey));
+ lvi.pszText = buf;
+ ListView_SetItem(hwndList, &lvi);
+
+ if ( item->rootHotkey ) {
+ lvi.mask = LVIF_IMAGE;
+ lvi.iSubItem = COL_TYPE;
+ lvi.iImage = item->OptType;
+ ListView_SetItem(hwndList, &lvi);
+ }
+
+ lvi.mask = LVIF_IMAGE;
+ lvi.iSubItem = COL_RESET;
+ lvi.iImage = (item->Hotkey != item->OptHotkey) ? 5 : -1;
+ ListView_SetItem(hwndList, &lvi);
+
+ lvi.mask = LVIF_IMAGE|LVIF_TEXT;
+ lvi.iSubItem = COL_ADDREMOVE;
+ if (item->rootHotkey) {
+ lvi.iImage = 4;
+ lvi.pszText = TranslateT("Remove shortcut");
+ }
+ else {
+ lvi.iImage = 3;
+ lvi.pszText = TranslateT("Add another shortcut");
+ }
+ ListView_SetItem(hwndList, &lvi);
+}
+
+static void sttOptionsDeleteHotkey(HWND hwndList, int idx, THotkeyItem *item)
+{
+ item->OptDeleted = TRUE;
+ ListView_DeleteItem(hwndList, idx);
+ if (item->rootHotkey)
+ item->rootHotkey->OptChanged = TRUE;
+}
+
+static int CALLBACK sttOptionsSortList(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
+{
+ TCHAR title1[256] = {0}, title2[256] = {0};
+ THotkeyItem *item1 = NULL, *item2 = NULL;
+ LVITEM lvi = {0};
+ int res;
+
+ lvi.mask = LVIF_TEXT|LVIF_PARAM;
+ lvi.iItem = lParam1;
+ lvi.pszText = title1;
+ lvi.cchTextMax = SIZEOF(title1);
+ if (ListView_GetItem((HWND)lParamSort, &lvi))
+ item1 = (THotkeyItem *)lvi.lParam;
+
+ lvi.mask = LVIF_TEXT|LVIF_PARAM;
+ lvi.iItem = lParam2;
+ lvi.pszText = title2;
+ lvi.cchTextMax = SIZEOF(title2);
+ if (ListView_GetItem((HWND)lParamSort, &lvi))
+ item2 = (THotkeyItem *)lvi.lParam;
+
+ if (!item1 && !item2)
+ return lstrcmp(title1, title2);
+
+ if (!item1) {
+ if (res = lstrcmp(title1, item2->ptszSection_tr))
+ return res;
+ return -1;
+ }
+
+ if (!item2) {
+ if (res = lstrcmp(item1->ptszSection_tr, title2))
+ return res;
+ return 1;
+ }
+ return sttCompareHotkeys(item1, item2);
+}
+
+static void sttOptionsAddHotkey(HWND hwndList, THotkeyItem *item)
+{
+ char buf[256];
+ LVITEM lvi = {0};
+
+ THotkeyItem *newItem = (THotkeyItem *)mir_alloc(sizeof(THotkeyItem));
+ newItem->pszName = NULL;
+ newItem->pszService = item->pszService ? mir_strdup(item->pszService) : NULL;
+ newItem->ptszSection = mir_tstrdup(item->ptszSection);
+ newItem->ptszDescription = mir_tstrdup(item->ptszDescription);
+ newItem->ptszSection_tr = item->ptszSection_tr;
+ newItem->ptszDescription_tr = item->ptszDescription_tr;
+ newItem->lParam = item->lParam;
+ mir_snprintf(buf, SIZEOF(buf), "mir_hotkey_%d_%d", g_pid, g_hotkeyCount++);
+ newItem->idHotkey = GlobalAddAtomA(buf);
+ newItem->rootHotkey = item;
+ newItem->Hotkey = newItem->DefHotkey = newItem->OptHotkey = 0;
+ newItem->type = newItem->OptType = item->OptType;
+ newItem->Enabled = newItem->OptEnabled = TRUE;
+ newItem->OptChanged = newItem->OptDeleted = FALSE;
+ newItem->OptNew = TRUE;
+
+ hotkeys.insert( newItem );
+
+ SendMessage(hwndList, WM_SETREDRAW, FALSE, 0);
+
+ lvi.mask |= LVIF_PARAM;
+ lvi.lParam = (LPARAM)newItem;
+ sttOptionsSetupItem(hwndList, ListView_InsertItem(hwndList, &lvi), newItem);
+ ListView_SortItemsEx(hwndList, sttOptionsSortList, (LPARAM)hwndList);
+
+ SendMessage(hwndList, WM_SETREDRAW, TRUE, 0);
+ RedrawWindow(hwndList, NULL, NULL, RDW_INVALIDATE);
+
+ item->OptChanged = TRUE;
+}
+
+static void sttOptionsSetChanged(THotkeyItem *item)
+{
+ item->OptChanged = TRUE;
+ if (item->rootHotkey)
+ item->rootHotkey->OptChanged = TRUE;
+}
+
+static void sttOptionsSaveItem(THotkeyItem *item)
+{
+ int i;
+ char buf[MAXMODULELABELLENGTH];
+
+ if (item->rootHotkey) return;
+ if (!item->OptChanged) return;
+
+ item->Hotkey = item->OptHotkey;
+ item->type = item->OptType;
+ item->Enabled = item->OptEnabled;
+
+ DBWriteContactSettingWord(NULL, DBMODULENAME, item->pszName, item->Hotkey);
+ DBWriteContactSettingByte(NULL, DBMODULENAME "Off", item->pszName, (BYTE)!item->Enabled);
+ if (item->type != HKT_MANUAL)
+ DBWriteContactSettingByte(NULL, DBMODULENAME "Types", item->pszName, (BYTE)item->type);
+
+ item->nSubHotkeys = 0;
+ for (i = 0; i < hotkeys.getCount(); i++) {
+ THotkeyItem *subItem = hotkeys[i];
+ if (subItem->rootHotkey == item) {
+ subItem->Hotkey = subItem->OptHotkey;
+ subItem->type = subItem->OptType;
+
+ mir_snprintf(buf, SIZEOF(buf), "%s$%d", item->pszName, item->nSubHotkeys);
+ DBWriteContactSettingWord(NULL, DBMODULENAME, buf, subItem->Hotkey);
+ if (subItem->type != HKT_MANUAL)
+ DBWriteContactSettingByte(NULL, DBMODULENAME "Types", buf, (BYTE)subItem->type);
+
+ ++item->nSubHotkeys;
+ } }
+
+ mir_snprintf(buf, SIZEOF(buf), "%s$count", item->pszName);
+ DBWriteContactSettingDword(NULL, DBMODULENAME, buf, item->nSubHotkeys);
+}
+
+static void sttBuildHotkeyList(HWND hwndList, TCHAR *section)
+{
+ int i, nItems=0;
+ ListView_DeleteAllItems(hwndList);
+
+ for (i = 0; i < hotkeys.getCount(); i++) {
+ LVITEM lvi = {0};
+ THotkeyItem *item = hotkeys[i];
+
+ if (item->OptDeleted) continue;
+ if (section && lstrcmp(section, item->ptszSection)) continue;
+
+ if ( !section && (!i || lstrcmp(item->ptszSection, ((THotkeyItem *)hotkeys[i-1])->ptszSection ))) {
+ lvi.mask = LVIF_TEXT|LVIF_PARAM;
+ lvi.iItem = nItems++;
+ lvi.iSubItem = 0;
+ lvi.lParam = 0;
+ lvi.pszText = item->ptszSection_tr;
+ ListView_InsertItem(hwndList, &lvi);
+ ListView_SetCheckState(hwndList, lvi.iItem, TRUE);
+
+ lvi.mask = LVIF_TEXT;
+ lvi.iSubItem = 1;
+ lvi.pszText = item->ptszSection;
+ ListView_SetItem(hwndList, &lvi);
+
+ lvi.iSubItem = 0;
+ }
+
+ lvi.mask = LVIF_PARAM;
+ if (!section) {
+ lvi.mask |= LVIF_INDENT;
+ lvi.iIndent = 1;
+ }
+ lvi.iItem = nItems++;
+ lvi.lParam = (LPARAM)item;
+ ListView_InsertItem(hwndList, &lvi);
+ sttOptionsSetupItem(hwndList, nItems-1, item);
+ }
+}
+
+static void sttOptionsStartEdit(HWND hwndDlg, HWND hwndHotkey)
+{
+ LVITEM lvi;
+ THotkeyItem *item;
+ int iItem = ListView_GetNextItem(hwndHotkey, -1, LVNI_SELECTED);
+ if (iItem < 0) return;
+
+ lvi.mask = LVIF_PARAM;
+ lvi.iItem = iItem;
+ ListView_GetItem(hwndHotkey, &lvi);
+
+ if (item = (THotkeyItem *)lvi.lParam) {
+ RECT rc;
+ ListView_GetSubItemRect(hwndHotkey, iItem, COL_KEY, LVIR_BOUNDS, &rc);
+ MapWindowPoints(hwndHotkey, hwndDlg, (LPPOINT)&rc, 2);
+ SendDlgItemMessage(hwndDlg, IDC_HOTKEY, HKM_SETHOTKEY, MAKELONG(LOBYTE(item->OptHotkey), HIBYTE(item->OptHotkey)), 0);
+
+ SetWindowPos(hwndHotkey, HWND_BOTTOM, 0, 0, 0, 0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE);
+ SetWindowPos(GetDlgItem(hwndDlg, IDC_HOTKEY), HWND_TOP, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, SWP_SHOWWINDOW);
+ RedrawWindow(GetDlgItem(hwndDlg, IDC_HOTKEY), NULL, NULL, RDW_INVALIDATE);
+
+ SetFocus(GetDlgItem(hwndDlg, IDC_HOTKEY));
+ RedrawWindow(GetDlgItem(hwndDlg, IDC_HOTKEY), NULL, NULL, RDW_INVALIDATE);
+ }
+}
+
+static void sttOptionsDrawTextChunk(HDC hdc, TCHAR *text, RECT *rc)
+{
+ SIZE sz;
+ DrawText(hdc, text, lstrlen(text), rc, DT_LEFT|DT_NOPREFIX|DT_SINGLELINE|DT_VCENTER|DT_WORD_ELLIPSIS);
+ GetTextExtentPoint32(hdc, text, lstrlen(text), &sz);
+ rc->left += sz.cx;
+}
+
+static INT_PTR CALLBACK sttOptionsDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static BOOL initialized = FALSE;
+ static int colWidth = 0;
+ static WORD currentLanguage = 0;
+
+ HWND hwndHotkey = GetDlgItem(hwndDlg, IDC_LV_HOTKEYS);
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ {
+ int i;
+ LVCOLUMN lvc;
+ RECT rc;
+ HIMAGELIST hIml;
+
+ initialized = FALSE;
+
+ TranslateDialogDefault(hwndDlg);
+
+ sttHotkeyEditCreate(GetDlgItem(hwndDlg, IDC_HOTKEY));
+
+ hIml = ImageList_Create(16, 16, ILC_MASK + (IsWinVerXPPlus() ? ILC_COLOR32 : ILC_COLOR16), 3, 1);
+ ImageList_AddIcon_IconLibLoaded(hIml, SKINICON_OTHER_WINDOWS);
+ ImageList_AddIcon_IconLibLoaded(hIml, SKINICON_OTHER_MIRANDA);
+ ImageList_AddIcon_IconLibLoaded(hIml, SKINICON_OTHER_WINDOW);
+ ImageList_AddIcon_IconLibLoaded(hIml, SKINICON_OTHER_ADDCONTACT);
+ ImageList_AddIcon_IconLibLoaded(hIml, SKINICON_OTHER_DELETE);
+ ImageList_AddIcon_IconLibLoaded(hIml, SKINICON_OTHER_UNDO);
+
+ // This is added to use for drawing operation only
+ ImageList_AddIcon_IconLibLoaded(hIml, SKINICON_OTHER_GROUPOPEN);
+ ImageList_AddIcon_IconLibLoaded(hIml, SKINICON_OTHER_GROUPSHUT);
+
+ ListView_SetImageList(hwndHotkey, hIml, LVSIL_SMALL);
+
+ ListView_SetExtendedListViewStyle(hwndHotkey, LVS_EX_CHECKBOXES|LVS_EX_SUBITEMIMAGES|LVS_EX_FULLROWSELECT|LVS_EX_DOUBLEBUFFER|LVS_EX_INFOTIP);
+
+ GetClientRect(hwndHotkey, &rc);
+ colWidth = rc.right - GetSystemMetrics(SM_CXHTHUMB) - 3*GetSystemMetrics(SM_CXSMICON) - 5;
+
+ lvc.mask = LVCF_WIDTH;
+ lvc.cx = colWidth * 2 / 3;
+ ListView_InsertColumn(hwndHotkey, COL_NAME, &lvc);
+ lvc.cx = GetSystemMetrics(SM_CXSMICON);
+ ListView_InsertColumn(hwndHotkey, COL_TYPE, &lvc);
+ lvc.cx = colWidth / 3;
+ ListView_InsertColumn(hwndHotkey, COL_KEY, &lvc);
+ lvc.cx = GetSystemMetrics(SM_CXSMICON);
+ ListView_InsertColumn(hwndHotkey, COL_RESET, &lvc);
+ lvc.cx = GetSystemMetrics(SM_CXSMICON);
+ ListView_InsertColumn(hwndHotkey, COL_ADDREMOVE, &lvc);
+
+ for (i = 0; i < hotkeys.getCount(); i++) {
+ THotkeyItem *item = hotkeys[i];
+
+ item->OptChanged = FALSE;
+ item->OptDeleted = item->OptNew = FALSE;
+ item->OptEnabled = item->Enabled;
+ item->OptHotkey = item->Hotkey;
+ item->OptType = item->type;
+ }
+
+ currentLanguage = LOWORD(GetKeyboardLayout(0));
+ sttBuildHotkeyList(hwndHotkey, NULL);
+ SetTimer(hwndDlg, 1024, 1000, NULL);
+
+ initialized = TRUE;
+
+ { /* load group states */
+ int count = ListView_GetItemCount(hwndHotkey);
+ TCHAR buf[128];
+ LVITEM lvi = {0};
+ lvi.pszText = buf;
+ lvi.cchTextMax = SIZEOF(buf);
+ for (lvi.iItem = 0; lvi.iItem < count; ++lvi.iItem) {
+ char *szSetting;
+
+ lvi.mask = LVIF_PARAM;
+ lvi.iSubItem = 0;
+ ListView_GetItem(hwndHotkey, &lvi);
+ if (lvi.lParam) continue;
+
+ lvi.mask = LVIF_TEXT;
+ lvi.iSubItem = 1;
+ ListView_GetItem(hwndHotkey, &lvi);
+
+ szSetting = mir_t2a(lvi.pszText);
+
+ ListView_SetCheckState(hwndHotkey, lvi.iItem,
+ DBGetContactSettingByte(NULL, DBMODULENAME "UI", szSetting, TRUE));
+
+ mir_free(szSetting);
+ }
+ }
+
+ g_hwndOptions = hwndDlg;
+
+ break;
+ }
+
+ case WM_DESTROY:
+ {
+ int count = ListView_GetItemCount(hwndHotkey);
+ TCHAR buf[128];
+ LVITEM lvi = {0};
+
+ g_hwndOptions = NULL;
+
+ KillTimer(hwndDlg, 1024);
+
+ lvi.pszText = buf;
+ lvi.cchTextMax = SIZEOF(buf);
+ for (lvi.iItem = 0; lvi.iItem < count; ++lvi.iItem) {
+ char *szSetting;
+
+ lvi.mask = LVIF_PARAM;
+ lvi.iSubItem = 0;
+ ListView_GetItem(hwndHotkey, &lvi);
+ if (lvi.lParam) continue;
+
+ lvi.mask = LVIF_TEXT;
+ lvi.iSubItem = 1;
+ ListView_GetItem(hwndHotkey, &lvi);
+
+ szSetting = mir_t2a(lvi.pszText);
+
+ DBWriteContactSettingByte(NULL, DBMODULENAME "UI", szSetting,
+ (BYTE) ListView_GetCheckState(hwndHotkey, lvi.iItem));
+
+ mir_free(szSetting);
+ }
+ break;
+ }
+
+ case WM_TIMER:
+ {
+ WORD newLanguage;
+ int count;
+ LVITEM lvi = {0};
+
+ if (!initialized) break;
+
+ newLanguage = LOWORD(GetKeyboardLayout(0));
+ if (newLanguage == currentLanguage) break;
+
+ count = ListView_GetItemCount(hwndHotkey);
+ lvi.mask = LVIF_PARAM;
+ for (lvi.iItem = 0; lvi.iItem < count; ++lvi.iItem) {
+ ListView_GetItem(hwndHotkey, &lvi);
+ if (!lvi.lParam) continue;
+
+ sttOptionsSetupItem(hwndHotkey, lvi.iItem, (THotkeyItem *)lvi.lParam);
+ }
+
+ currentLanguage = newLanguage;
+ break;
+ }
+
+ case WM_HOTKEYUNREGISTERED:
+ {
+ int count;
+ LVITEM lvi = {0};
+
+ count = ListView_GetItemCount(hwndHotkey);
+ lvi.mask = LVIF_PARAM;
+ for (lvi.iItem = 0; lvi.iItem < count; ++lvi.iItem) {
+ ListView_GetItem(hwndHotkey, &lvi);
+ if (!lvi.lParam) continue;
+
+ if (((THotkeyItem *)lvi.lParam)->UnregisterHotkey) {
+ ListView_DeleteItem(hwndHotkey, lvi.iItem);
+ --lvi.iItem;
+ --count;
+ }
+ }
+ break;
+ }
+
+ case WM_DRAWITEM:
+ {
+ LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam;
+ RECT rc = lpdis->rcItem;
+ int prefix = 65;
+ int width = (lpdis->rcItem.right - lpdis->rcItem.left - prefix) / 3;
+ rc.left += 5;
+
+ HIMAGELIST hIml = ListView_GetImageList(hwndHotkey, LVSIL_SMALL);
+
+ if (lpdis->CtlID == IDC_CANVAS2) {
+ sttOptionsDrawTextChunk(lpdis->hDC, TranslateT("Scope:"), &rc);
+
+ rc.left = prefix + width * 0;
+ ImageList_Draw(hIml, 0, lpdis->hDC, rc.left, (rc.top+rc.bottom-16)/2, ILD_TRANSPARENT);
+ rc.left += 20;
+ sttOptionsDrawTextChunk(lpdis->hDC, TranslateT("System"), &rc);
+
+ rc.left = prefix + width * 1;
+ ImageList_Draw(hIml, 1, lpdis->hDC, rc.left, (rc.top+rc.bottom-16)/2, ILD_TRANSPARENT);
+ rc.left += 20;
+ sttOptionsDrawTextChunk(lpdis->hDC, TranslateT("Miranda"), &rc);
+
+ rc.left = prefix + width * 2;
+ ImageList_Draw(hIml, 2, lpdis->hDC, rc.left, (rc.top+rc.bottom-16)/2, ILD_TRANSPARENT);
+ rc.left += 20;
+ sttOptionsDrawTextChunk(lpdis->hDC, TranslateT("Window"), &rc);
+
+ return TRUE;
+ }
+
+ if (lpdis->CtlID == IDC_CANVAS) {
+ sttOptionsDrawTextChunk(lpdis->hDC, TranslateT("Actions:"), &rc);
+ rc.left += 10;
+
+ rc.left = prefix + width * 0;
+ ImageList_Draw(hIml, 5, lpdis->hDC, rc.left, (rc.top+rc.bottom-16)/2, ILD_TRANSPARENT);
+ rc.left += 20;
+ sttOptionsDrawTextChunk(lpdis->hDC, TranslateT("Undo"), &rc);
+
+ rc.left = prefix + width * 1;
+ ImageList_Draw(hIml, 3, lpdis->hDC, rc.left, (rc.top+rc.bottom-16)/2, ILD_TRANSPARENT);
+ rc.left += 20;
+ sttOptionsDrawTextChunk(lpdis->hDC, TranslateT("Add binding"), &rc);
+
+ rc.left = prefix + width * 2;
+ ImageList_Draw(hIml, 4, lpdis->hDC, rc.left, (rc.top+rc.bottom-16)/2, ILD_TRANSPARENT);
+ rc.left += 20;
+ sttOptionsDrawTextChunk(lpdis->hDC, TranslateT("Remove"), &rc);
+
+ return TRUE;
+ }
+
+ break;
+ }
+
+ case WM_COMMAND:
+ if (( LOWORD( wParam ) == IDC_HOTKEY) && (( HIWORD( wParam ) == EN_KILLFOCUS) || (HIWORD(wParam) == 0 ))) {
+ LVITEM lvi;
+ THotkeyItem *item;
+ WORD wHotkey = (WORD)SendDlgItemMessage(hwndDlg, IDC_HOTKEY, HKM_GETHOTKEY, 0, 0);
+
+ ShowWindow(GetDlgItem(hwndDlg, IDC_HOTKEY), SW_HIDE);
+ SetFocus(hwndHotkey);
+ if ( !wHotkey || (wHotkey == VK_ESCAPE) || (HIWORD(wParam) != 0 ))
+ break;
+
+ lvi.mask = LVIF_PARAM;
+ lvi.iItem = ListView_GetNextItem(hwndHotkey, -1, LVNI_SELECTED);
+ if (lvi.iItem >= 0) {
+ ListView_GetItem(hwndHotkey, &lvi);
+ if (item = (THotkeyItem *)lvi.lParam) {
+ item->OptHotkey = wHotkey;
+
+ sttOptionsSetupItem(hwndHotkey, lvi.iItem, item);
+ sttOptionsSetChanged(item);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ } } }
+ break;
+
+ case WM_CONTEXTMENU:
+ if (GetWindowLongPtr((HWND)wParam, GWL_ID) == IDC_LV_HOTKEYS)
+ {
+ HWND hwndList = (HWND)wParam;
+ POINT pt = { (signed short)LOWORD( lParam ), (signed short)HIWORD( lParam ) };
+ LVITEM lvi = {0};
+ THotkeyItem *item = NULL;
+
+ lvi.iItem = ListView_GetNextItem(hwndHotkey, -1, LVNI_SELECTED);
+ if (lvi.iItem < 0) return FALSE;
+
+ lvi.mask = LVIF_PARAM;
+ ListView_GetItem(hwndList, &lvi);
+ if (!(item = (THotkeyItem *)lvi.lParam)) return FALSE;
+
+ if (( pt.x == -1 ) && ( pt.y == -1 )) {
+ RECT rc;
+ ListView_GetItemRect(hwndList, lvi.iItem, &rc, LVIR_LABEL);
+ pt.x = rc.left;
+ pt.y = rc.bottom;
+ ClientToScreen(hwndList, &pt);
+ }
+
+ {
+ enum { MI_CANCEL, MI_CHANGE, MI_SYSTEM, MI_LOCAL, MI_ADD, MI_REMOVE, MI_REVERT };
+
+ MENUITEMINFO mii = {0};
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_STATE;
+ mii.fState = MFS_DEFAULT;
+
+ HMENU hMenu = CreatePopupMenu();
+ AppendMenu(hMenu, MF_STRING, (UINT_PTR)MI_CHANGE, TranslateT("Modify"));
+ SetMenuItemInfo(hMenu, (UINT_PTR)MI_CHANGE, FALSE, &mii);
+ if (item->type != HKT_MANUAL) {
+ AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
+ AppendMenu(hMenu, MF_STRING|
+ ((item->OptType == HKT_GLOBAL) ? MF_CHECKED : 0),
+ (UINT_PTR)MI_SYSTEM, TranslateT("System scope"));
+ AppendMenu(hMenu, MF_STRING|
+ ((item->OptType == HKT_LOCAL) ? MF_CHECKED : 0),
+ (UINT_PTR)MI_LOCAL, TranslateT("Miranda scope"));
+ }
+ AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
+ if (!item->rootHotkey)
+ AppendMenu(hMenu, MF_STRING, (UINT_PTR)MI_ADD, TranslateT("Add binding"));
+ else
+ AppendMenu(hMenu, MF_STRING, (UINT_PTR)MI_REMOVE, TranslateT("Remove"));
+ if (item->Hotkey != item->OptHotkey) {
+ AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
+ AppendMenu(hMenu, MF_STRING, (UINT_PTR)MI_REVERT, TranslateT("Undo"));
+ }
+
+ switch (TrackPopupMenu(hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hwndDlg, NULL)) {
+ case MI_CHANGE:
+ sttOptionsStartEdit(hwndDlg, hwndHotkey);
+ break;
+ case MI_SYSTEM:
+ item->OptType = HKT_GLOBAL;
+ sttOptionsSetupItem(hwndList, lvi.iItem, item);
+ sttOptionsSetChanged(item);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case MI_LOCAL:
+ item->OptType = HKT_LOCAL;
+ sttOptionsSetupItem(hwndList, lvi.iItem, item);
+ sttOptionsSetChanged(item);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case MI_ADD:
+ initialized = FALSE;
+ sttOptionsAddHotkey(hwndList, item);
+ initialized = FALSE;
+ break;
+ case MI_REMOVE:
+ sttOptionsDeleteHotkey(hwndList, lvi.iItem, item);
+ break;
+ case MI_REVERT:
+ item->OptHotkey = item->Hotkey;
+ sttOptionsSetupItem(hwndList, lvi.iItem, item);
+ break;
+ }
+ DestroyMenu( hMenu );
+ }
+
+ break;
+ }
+ break;
+
+ case WM_NOTIFY:
+ {
+ LPNMHDR lpnmhdr = (LPNMHDR)lParam;
+ switch (lpnmhdr->idFrom) {
+ case 0:
+ {
+ int i;
+
+ if (( lpnmhdr->code != PSN_APPLY) && (lpnmhdr->code != PSN_RESET ))
+ break;
+
+ sttUnregisterHotkeys();
+
+ for (i = 0; i < hotkeys.getCount(); i++) {
+ THotkeyItem *item = hotkeys[i];
+ if (item->OptNew && item->OptDeleted ||
+ item->rootHotkey && !item->OptHotkey ||
+ (lpnmhdr->code == PSN_APPLY) && item->OptDeleted ||
+ (lpnmhdr->code == PSN_RESET) && item->OptNew)
+ {
+ sttFreeHotkey(item);
+ hotkeys.remove( i-- );
+ }
+ }
+
+ if (lpnmhdr->code == PSN_APPLY) {
+ LVITEM lvi = {0};
+ int count = ListView_GetItemCount(hwndHotkey);
+
+ for (i = 0; i < hotkeys.getCount(); i++)
+ sttOptionsSaveItem(hotkeys[i]);
+
+ lvi.mask = LVIF_IMAGE;
+ lvi.iSubItem = COL_RESET;
+ lvi.iImage = -1;
+ for (lvi.iItem = 0; lvi.iItem < count; ++lvi.iItem)
+ ListView_SetItem(hwndHotkey, &lvi);
+ }
+
+ sttRegisterHotkeys();
+
+ NotifyEventHooks( hEvChanged, 0, 0 );
+ break;
+ }
+ case IDC_LV_HOTKEYS:
+ switch (lpnmhdr->code) {
+ case NM_CLICK:
+ {
+ THotkeyItem *item = NULL;
+ LPNMITEMACTIVATE lpnmia = (LPNMITEMACTIVATE)lParam;
+ LVHITTESTINFO lvhti = {0};
+ LVITEM lvi = {0};
+
+ lvi.mask = LVIF_PARAM|LVIF_IMAGE;
+ lvi.iItem = lpnmia->iItem;
+ ListView_GetItem(lpnmia->hdr.hwndFrom, &lvi);
+ item = (THotkeyItem *)lvi.lParam;
+
+ lvhti.pt = lpnmia->ptAction;
+ lvhti.iItem = lpnmia->iItem;
+ lvhti.iSubItem = lpnmia->iSubItem;
+ ListView_HitTest(lpnmia->hdr.hwndFrom, &lvhti);
+
+ if (item &&
+ (!item->rootHotkey && (lpnmia->iSubItem == COL_NAME) && ((lvhti.flags & LVHT_ONITEM) == LVHT_ONITEMICON) ||
+ item->rootHotkey && (lpnmia->iSubItem == COL_TYPE)) &&
+ ((item->OptType == HKT_GLOBAL) || (item->OptType == HKT_LOCAL)))
+ {
+ item->OptType = (item->OptType == HKT_GLOBAL) ? HKT_LOCAL : HKT_GLOBAL;
+ sttOptionsSetupItem(lpnmia->hdr.hwndFrom, lpnmia->iItem, item);
+ sttOptionsSetChanged(item);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ else if (item && (lpnmia->iSubItem == COL_RESET)) {
+ item->OptHotkey = item->Hotkey;
+ sttOptionsSetupItem(lpnmia->hdr.hwndFrom, lpnmia->iItem, item);
+ }
+ else if (item && (lpnmia->iSubItem == COL_ADDREMOVE)) {
+ if (item->rootHotkey)
+ sttOptionsDeleteHotkey(lpnmia->hdr.hwndFrom, lpnmia->iItem, item);
+ else {
+ initialized = FALSE;
+ sttOptionsAddHotkey(lpnmia->hdr.hwndFrom, item);
+ initialized = TRUE;
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ break;
+ }
+ case LVN_KEYDOWN:
+ {
+ LPNMLVKEYDOWN param = (LPNMLVKEYDOWN)lParam;
+ if ((param->wVKey == VK_SUBTRACT) || (param->wVKey == VK_LEFT) ||
+ (param->wVKey == VK_ADD) || (param->wVKey == VK_RIGHT))
+ {
+ LVITEM lvi = {0};
+ lvi.mask = LVIF_PARAM;
+ lvi.iItem = ListView_GetNextItem(lpnmhdr->hwndFrom, -1, LVNI_SELECTED);
+ if (lvi.iItem < 0) break;
+ ListView_GetItem(lpnmhdr->hwndFrom, &lvi);
+ if (lvi.lParam) break;
+
+ if ((param->wVKey == VK_ADD) || (param->wVKey == VK_RIGHT))
+ {
+ ListView_SetCheckState(lpnmhdr->hwndFrom, lvi.iItem, TRUE);
+ } else
+ // if ((param->wVKey == VK_SUBTRACT) || (param->wVKey == VK_LEFT))
+ {
+ ListView_SetCheckState(lpnmhdr->hwndFrom, lvi.iItem, FALSE);
+ }
+ }
+ else if (param->wVKey == VK_F2)
+ sttOptionsStartEdit(hwndDlg, hwndHotkey);
+
+ break;
+ }
+ case LVN_ITEMACTIVATE:
+ {
+ LVITEM lvi = {0};
+ lvi.mask = LVIF_PARAM;
+ lvi.iItem = ListView_GetNextItem(lpnmhdr->hwndFrom, -1, LVNI_SELECTED);
+ if (lvi.iItem < 0) break;
+ ListView_GetItem(lpnmhdr->hwndFrom, &lvi);
+
+ if (lvi.lParam)
+ sttOptionsStartEdit(hwndDlg, hwndHotkey);
+ else
+ ListView_SetCheckState(lpnmhdr->hwndFrom, lvi.iItem, !ListView_GetCheckState(lpnmhdr->hwndFrom, lvi.iItem));
+ break;
+ }
+ case LVN_ITEMCHANGED:
+ {
+ LPNMLISTVIEW param = (LPNMLISTVIEW)lParam;
+ THotkeyItem *item = (THotkeyItem *)param->lParam;
+ if (!initialized || (param->uNewState>>12 == param->uOldState>>12))
+ break;
+
+ if (item && !item->rootHotkey) {
+ item->OptEnabled = ListView_GetCheckState(lpnmhdr->hwndFrom, param->iItem) ? 1 : 0;
+ sttOptionsSetChanged(item);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ else if (!item) {
+ TCHAR buf[256];
+ LVITEM lvi = {0};
+ lvi.mask = LVIF_TEXT;
+ lvi.iItem = param->iItem;
+ lvi.pszText = buf;
+ lvi.cchTextMax = SIZEOF(buf);
+ ListView_GetItem(lpnmhdr->hwndFrom, &lvi);
+
+ if (param->uNewState>>12 == 1) {
+ int count = ListView_GetItemCount(lpnmhdr->hwndFrom);
+ LVITEM lvi = {0};
+ lvi.mask = LVIF_PARAM;
+ for (lvi.iItem = 0; lvi.iItem < count; ++lvi.iItem) {
+ THotkeyItem *item;
+ ListView_GetItem(lpnmhdr->hwndFrom, &lvi);
+ item = (THotkeyItem *)lvi.lParam;
+ if (!item) continue;
+ if (!lstrcmp(item->ptszSection_tr, buf)) {
+ ListView_DeleteItem(lpnmhdr->hwndFrom, lvi.iItem);
+ --lvi.iItem;
+ --count;
+ } }
+ }
+ else if (param->uNewState>>12 == 2) {
+ int i, nItems = ListView_GetItemCount(lpnmhdr->hwndFrom);
+ initialized = FALSE;
+ for (i = 0; i < hotkeys.getCount(); ++i) {
+ LVITEM lvi = {0};
+ THotkeyItem *item = hotkeys[i];
+
+ if (item->OptDeleted) continue;
+ if (lstrcmp(buf, item->ptszSection_tr)) continue;
+
+ lvi.mask = LVIF_PARAM|LVIF_INDENT;
+ lvi.iIndent = 1;
+ lvi.iItem = nItems++;
+ lvi.lParam = (LPARAM)item;
+ ListView_InsertItem(lpnmhdr->hwndFrom, &lvi);
+ sttOptionsSetupItem(lpnmhdr->hwndFrom, nItems-1, item);
+ }
+ ListView_SortItemsEx(lpnmhdr->hwndFrom, sttOptionsSortList, (LPARAM)lpnmhdr->hwndFrom);
+ initialized = TRUE;
+ }
+ }
+ break;
+ }
+ case NM_CUSTOMDRAW:
+ {
+ NMLVCUSTOMDRAW *param = (NMLVCUSTOMDRAW *) lParam;
+ switch (param->nmcd.dwDrawStage) {
+ case CDDS_PREPAINT:
+ case CDDS_ITEMPREPAINT:
+ SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, CDRF_NOTIFYSUBITEMDRAW );
+ return TRUE;
+
+ case CDDS_SUBITEM|CDDS_ITEMPREPAINT:
+ {
+ THotkeyItem *item;
+ TCHAR buf[256];
+ LVITEM lvi = {0};
+ lvi.mask = LVIF_TEXT|LVIF_PARAM;
+ lvi.iItem = param->nmcd.dwItemSpec;
+ lvi.pszText = buf;
+ lvi.cchTextMax = SIZEOF(buf);
+ ListView_GetItem(lpnmhdr->hwndFrom, &lvi);
+ item = (THotkeyItem *)lvi.lParam;
+
+ if (!item) {
+ RECT rc;
+ HFONT hfnt;
+
+ ListView_GetSubItemRect(lpnmhdr->hwndFrom, param->nmcd.dwItemSpec, param->iSubItem, LVIR_BOUNDS, &rc);
+ FillRect(param->nmcd.hdc, &rc, GetSysColorBrush(param->nmcd.uItemState&CDIS_SELECTED ? COLOR_HIGHLIGHT : COLOR_WINDOW));
+ SetTextColor(param->nmcd.hdc, GetSysColor(param->nmcd.uItemState&CDIS_SELECTED ? COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT));
+
+ if (param->iSubItem == 0) {
+ rc.left += 3;
+ HIMAGELIST hIml = ListView_GetImageList(hwndHotkey, LVSIL_SMALL);
+ ImageList_Draw(hIml,
+ ListView_GetCheckState(hwndHotkey, lvi.iItem) ? 6 : 7,
+ param->nmcd.hdc, rc.left, (rc.top+rc.bottom-16)/2, ILD_TRANSPARENT);
+ rc.left += 18;
+ hfnt = ( HFONT )SelectObject(param->nmcd.hdc, (HFONT)SendMessage(GetParent(hwndDlg), PSM_GETBOLDFONT, 0, 0));
+ DrawText(param->nmcd.hdc, buf, -1, &rc, DT_LEFT|DT_NOPREFIX|DT_SINGLELINE|DT_VCENTER);
+ SelectObject(param->nmcd.hdc, hfnt);
+ }
+
+ SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, CDRF_SKIPDEFAULT );
+ return TRUE;
+ }
+
+ if (item->rootHotkey && (param->iSubItem == 0)) {
+ RECT rc;
+ ListView_GetSubItemRect(lpnmhdr->hwndFrom, param->nmcd.dwItemSpec, param->iSubItem, LVIR_BOUNDS, &rc);
+ FillRect(param->nmcd.hdc, &rc, GetSysColorBrush(COLOR_WINDOW));
+ SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, CDRF_SKIPDEFAULT );
+ return TRUE;
+ }
+ break;
+ } }
+ break;
+ }
+ break;
+ } }
+ break;
+ } /* case WM_NOTIFY */
+ } /* switch */
+
+ return FALSE;
+}
+
+static int sttOptionsInit(WPARAM wParam, LPARAM)
+{
+ OPTIONSDIALOGPAGE odp = {0};
+ odp.cbSize = sizeof(odp);
+ odp.hInstance = hMirandaInst;
+ odp.flags = ODPF_BOLDGROUPS | ODPF_TCHAR;
+ odp.position = -180000000;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_HOTKEYS);
+ odp.ptszTitle = TranslateT("Hotkeys");
+ odp.ptszGroup = TranslateT("Customize");
+ odp.pfnDlgProc = sttOptionsDlgProc;
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM)&odp);
+ return 0;
+}
+
+static int sttModulesLoaded(WPARAM, LPARAM)
+{
+ HookEvent(ME_OPT_INITIALISE, sttOptionsInit);
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Hotkey manager
+
+static const char* oldSettings[] = { "ShowHide", "ReadMsg", "NetSearch", "ShowOptions" };
+static const char* newSettings[] = { "ShowHide", "ReadMessage", "SearchInWeb", "ShowOptions" };
+
+int LoadSkinHotkeys(void)
+{
+ WNDCLASSEX wcl = {0};
+
+ bModuleInitialized = TRUE;
+
+ wcl.cbSize = sizeof(wcl);
+ wcl.lpfnWndProc = sttHotkeyHostWndProc;
+ wcl.style = 0;
+ wcl.cbClsExtra = 0;
+ wcl.cbWndExtra = 0;
+ wcl.hInstance = hMirandaInst;
+ wcl.hIcon = NULL;
+ wcl.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wcl.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
+ wcl.lpszMenuName = NULL;
+ wcl.lpszClassName = _T("MirandaHotkeyHostWnd");
+ wcl.hIconSm = NULL;
+ RegisterClassEx(&wcl);
+
+ g_pid = GetCurrentProcessId();
+
+ g_hwndHotkeyHost = CreateWindow(_T("MirandaHotkeyHostWnd"), NULL, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, HWND_DESKTOP, NULL, hMirandaInst, NULL);
+ SetWindowPos(g_hwndHotkeyHost, 0, 0, 0, 0, 0, SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|SWP_DEFERERASE|SWP_NOSENDCHANGING|SWP_HIDEWINDOW);
+
+ hhkKeyboard = SetWindowsHookEx(WH_KEYBOARD, sttKeyboardProc, NULL, GetCurrentThreadId());
+
+ hEvChanged = CreateHookableEvent(ME_HOTKEYS_CHANGED);
+
+ CreateServiceFunction(MS_HOTKEY_SUBCLASS, svcHotkeySubclass);
+ CreateServiceFunction(MS_HOTKEY_UNSUBCLASS, svcHotkeyUnsubclass);
+ CreateServiceFunction(MS_HOTKEY_REGISTER, svcHotkeyRegister);
+ CreateServiceFunction(MS_HOTKEY_UNREGISTER, svcHotkeyUnregister);
+ CreateServiceFunction(MS_HOTKEY_CHECK, svcHotkeyCheck);
+
+ HookEvent(ME_SYSTEM_MODULESLOADED, sttModulesLoaded);
+ {
+ WORD key;
+ int i;
+ for ( i = 0; i < SIZEOF( oldSettings ); i++ ) {
+ char szSetting[ 100 ];
+ mir_snprintf( szSetting, SIZEOF(szSetting), "HK%s", oldSettings[i] );
+ if (( key = DBGetContactSettingWord( NULL, "Clist", szSetting, 0 ))) {
+ DBDeleteContactSetting( NULL, "Clist", szSetting );
+ DBWriteContactSettingWord( NULL, DBMODULENAME, newSettings[i], key );
+ }
+
+ mir_snprintf( szSetting, SIZEOF(szSetting), "HKEn%s", oldSettings[i] );
+ if (( key = DBGetContactSettingByte( NULL, "Clist", szSetting, 0 ))) {
+ DBDeleteContactSetting( NULL, "Clist", szSetting );
+ DBWriteContactSettingByte( NULL, DBMODULENAME "Off", newSettings[i], (BYTE)(key == 0) );
+ } } }
+
+ return 0;
+}
+
+void UnloadSkinHotkeys(void)
+{
+ int i;
+
+ if ( !bModuleInitialized ) return;
+
+ DestroyHookableEvent(hEvChanged);
+ UnhookWindowsHookEx(hhkKeyboard);
+ sttUnregisterHotkeys();
+ DestroyWindow(g_hwndHotkeyHost);
+ for ( i = 0; i < hotkeys.getCount(); i++ )
+ sttFreeHotkey(hotkeys[i]);
+ hotkeys.destroy();
+}
diff --git a/src/modules/skin/skinicons.cpp b/src/modules/skin/skinicons.cpp
new file mode 100644
index 0000000000..9bfb0cf655
--- /dev/null
+++ b/src/modules/skin/skinicons.cpp
@@ -0,0 +1,489 @@
+/*
+
+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 <io.h>
+
+struct StandardIconDescription
+{
+ int id;
+ const char* description;
+ int resource_id;
+ int pf2;
+ const char* section;
+};
+
+static const struct StandardIconDescription mainIcons[] =
+{
+ { SKINICON_OTHER_MIRANDA, LPGEN("Miranda IM"), -IDI_MIRANDA },
+ { SKINICON_EVENT_MESSAGE, LPGEN("Message"), -IDI_RECVMSG },
+ { SKINICON_EVENT_URL, LPGEN("URL"), -IDI_URL },
+ { SKINICON_EVENT_FILE, LPGEN("File"), -IDI_FILE },
+ { SKINICON_OTHER_USERONLINE, LPGEN("User Online"), -IDI_USERONLINE },
+ { SKINICON_OTHER_GROUPOPEN, LPGEN("Group (Open)"), -IDI_GROUPOPEN },
+ { SKINICON_OTHER_GROUPSHUT, LPGEN("Group (Closed)"), -IDI_GROUPSHUT },
+ { SKINICON_OTHER_CONNECTING, LPGEN("Connecting"), -IDI_LOAD },
+ { SKINICON_OTHER_ADDCONTACT, LPGEN("Add Contact"), -IDI_ADDCONTACT },
+ { SKINICON_OTHER_USERDETAILS, LPGEN("User Details"), -IDI_USERDETAILS },
+ { SKINICON_OTHER_HISTORY, LPGEN("History"), -IDI_HISTORY },
+ { SKINICON_OTHER_DOWNARROW, LPGEN("Down Arrow"), -IDI_DOWNARROW },
+ { SKINICON_OTHER_FINDUSER, LPGEN("Find User"), -IDI_FINDUSER },
+ { SKINICON_OTHER_OPTIONS, LPGEN("Options"), -IDI_OPTIONS },
+ { SKINICON_OTHER_SENDEMAIL, LPGEN("Send E-mail"), -IDI_SENDEMAIL },
+ { SKINICON_OTHER_DELETE, LPGEN("Delete"), -IDI_DELETE },
+ { SKINICON_OTHER_RENAME, LPGEN("Rename"), -IDI_RENAME },
+ { SKINICON_OTHER_SMS, LPGEN("SMS"), -IDI_SMS },
+ { SKINICON_OTHER_SEARCHALL, LPGEN("Search All"), -IDI_SEARCHALL },
+ { SKINICON_OTHER_TICK, LPGEN("Tick"), -IDI_TICK },
+ { SKINICON_OTHER_NOTICK, LPGEN("No Tick"), -IDI_NOTICK },
+ { SKINICON_OTHER_HELP, LPGEN("Help"), -IDI_HELP },
+ { SKINICON_OTHER_MIRANDAWEB, LPGEN("Miranda Website"), -IDI_MIRANDAWEBSITE },
+ { SKINICON_OTHER_TYPING, LPGEN("Typing"), -IDI_TYPING },
+ { SKINICON_OTHER_SMALLDOT, LPGEN("Small Dot"), -IDI_SMALLDOT },
+ { SKINICON_OTHER_FILLEDBLOB, LPGEN("Filled Blob"), -IDI_FILLEDBLOB },
+ { SKINICON_OTHER_EMPTYBLOB, LPGEN("Empty Blob"), -IDI_EMPTYBLOB },
+ { SKINICON_OTHER_UNICODE, LPGEN("Unicode plugin"), -IDI_UNICODE },
+ { SKINICON_OTHER_ANSI, LPGEN("ANSI plugin"), -IDI_ANSI },
+ { SKINICON_OTHER_LOADED, LPGEN("Running plugin"), -IDI_LOADED },
+ { SKINICON_OTHER_NOTLOADED, LPGEN("Unloaded plugin"), -IDI_NOTLOADED },
+ { SKINICON_OTHER_UNDO, LPGEN("Undo"), -IDI_UNDO },
+ { SKINICON_OTHER_WINDOW, LPGEN("Window"), -IDI_WINDOW },
+ { SKINICON_OTHER_WINDOWS, LPGEN("System"), -IDI_WINDOWS },
+ { SKINICON_OTHER_ACCMGR, LPGEN("Accounts"), -IDI_ACCMGR },
+ { SKINICON_OTHER_SHOWHIDE, LPGEN("ShowHide"), -IDI_SHOWHIDE },
+ { SKINICON_OTHER_EXIT, LPGEN("Exit"), -IDI_EXIT },
+ { SKINICON_OTHER_MAINMENU, LPGEN("Main Menu"), -IDI_MIRANDA },
+ { SKINICON_OTHER_STATUS, LPGEN("Status"), -IDI_ONLINE },
+ { SKINICON_CHAT_JOIN, LPGEN("Join chat"), -IDI_JOINCHAT },
+ { SKINICON_CHAT_LEAVE, LPGEN("Leave chat"), -IDI_LEAVECHAT },
+ { SKINICON_OTHER_GROUP, LPGEN("Move to Group"), -IDI_MOVETOGROUP },
+ { SKINICON_OTHER_ON, LPGEN("On"), -IDI_ON },
+ { SKINICON_OTHER_OFF, LPGEN("Off"), -IDI_OFF },
+ { SKINICON_OTHER_STATUS_LOCKED, LPGEN("Locked status"), -IDI_STATUS_LOCKED, 0, "Status Icons" },
+};
+
+HANDLE hMainIcons[SIZEOF(mainIcons)];
+
+static const struct StandardIconDescription statusIcons[] =
+{
+ { ID_STATUS_OFFLINE, LPGEN("Offline"), -IDI_OFFLINE, 0xFFFFFFFF },
+ { ID_STATUS_ONLINE, LPGEN("Online"), -IDI_ONLINE, PF2_ONLINE },
+ { ID_STATUS_AWAY, LPGEN("Away"), -IDI_AWAY, PF2_SHORTAWAY },
+ { ID_STATUS_NA, LPGEN("NA"), -IDI_NA, PF2_LONGAWAY },
+ { ID_STATUS_OCCUPIED, LPGEN("Occupied"), -IDI_OCCUPIED, PF2_LIGHTDND },
+ { ID_STATUS_DND, LPGEN("DND"), -IDI_DND, PF2_HEAVYDND },
+ { ID_STATUS_FREECHAT, LPGEN("Free for chat"), -IDI_FREE4CHAT, PF2_FREECHAT },
+ { ID_STATUS_INVISIBLE, LPGEN("Invisible"), -IDI_INVISIBLE, PF2_INVISIBLE },
+ { ID_STATUS_ONTHEPHONE, LPGEN("On the phone"), -IDI_ONTHEPHONE, PF2_ONTHEPHONE },
+ { ID_STATUS_OUTTOLUNCH, LPGEN("Out to lunch"), -IDI_OUTTOLUNCH, PF2_OUTTOLUNCH }
+};
+
+HANDLE hStatusIcons[SIZEOF(statusIcons)];
+
+const char* mainIconsFmt = "core_main_";
+const char* statusIconsFmt = "core_status_";
+const char* protoIconsFmt = LPGEN("%s Icons");
+
+#define PROTOCOLS_PREFIX "Status Icons/"
+#define GLOBAL_PROTO_NAME "*"
+
+
+
+
+// load small icon (shared) it's not need to be destroyed
+
+static HICON LoadSmallIconShared(HINSTANCE hInstance, LPCTSTR lpIconName)
+{
+ int cx = GetSystemMetrics(SM_CXSMICON);
+ return ( HICON )LoadImage( hInstance, lpIconName, IMAGE_ICON,cx, cx, LR_DEFAULTCOLOR | LR_SHARED );
+}
+
+// load small icon (not shared) it IS NEED to be destroyed
+static HICON LoadSmallIcon(HINSTANCE hInstance, LPCTSTR lpIconName)
+{
+ HICON hIcon = NULL; // icon handle
+ int index = -( int )lpIconName;
+ TCHAR filename[MAX_PATH] = {0};
+ GetModuleFileName( hInstance, filename, MAX_PATH );
+ ExtractIconEx( filename, index, NULL, &hIcon, 1 );
+ return hIcon;
+}
+
+// load small icon from hInstance
+HICON LoadIconEx(HINSTANCE hInstance, LPCTSTR lpIconName, BOOL bShared)
+{
+ HICON hResIcon = bShared ? LoadSmallIcon(hInstance,lpIconName) : LoadSmallIconShared(hInstance,lpIconName);
+ if ( !hResIcon ) { //Icon not found in hInstance lets try to load it from core
+ HINSTANCE hCoreInstance=hMirandaInst;
+ if ( hCoreInstance != hInstance )
+ hResIcon = bShared ? LoadSmallIcon(hCoreInstance,lpIconName) : LoadSmallIconShared(hCoreInstance,lpIconName);
+ }
+ return hResIcon;
+}
+
+int ImageList_AddIcon_NotShared(HIMAGELIST hIml, LPCTSTR szResource)
+{
+ HICON hTempIcon=LoadIconEx( hMirandaInst, szResource, 0);
+ int res = ImageList_AddIcon(hIml, hTempIcon);
+ Safe_DestroyIcon(hTempIcon);
+ return res;
+}
+
+int ImageList_AddIcon_IconLibLoaded(HIMAGELIST hIml, int iconId)
+{
+ HICON hIcon = LoadSkinIcon( iconId );
+ int res = ImageList_AddIcon(hIml, hIcon);
+ IconLib_ReleaseIcon(hIcon,0);
+ return res;
+}
+
+int ImageList_AddIcon_ProtoIconLibLoaded(HIMAGELIST hIml, const char* szProto, int iconId)
+{
+ HICON hIcon = LoadSkinProtoIcon( szProto, iconId );
+ int res = ImageList_AddIcon(hIml, hIcon);
+ IconLib_ReleaseIcon(hIcon,0);
+ return res;
+}
+
+int ImageList_ReplaceIcon_NotShared(HIMAGELIST hIml, int iIndex, HINSTANCE hInstance, LPCTSTR szResource)
+{
+ HICON hTempIcon = LoadIconEx(hInstance, szResource, 0);
+ int res = ImageList_ReplaceIcon(hIml, iIndex, hTempIcon);
+ Safe_DestroyIcon(hTempIcon);
+ return res;
+}
+
+int ImageList_ReplaceIcon_IconLibLoaded(HIMAGELIST hIml, int nIndex, HICON hIcon)
+{
+ int res = ImageList_ReplaceIcon(hIml,nIndex, hIcon);
+ IconLib_ReleaseIcon(hIcon,0);
+ return res;
+}
+
+void Window_SetIcon_IcoLib(HWND hWnd, int iconId)
+{
+ SendMessage(hWnd, WM_SETICON, ICON_BIG, ( LPARAM )LoadSkinIcon( iconId, true ));
+ SendMessage(hWnd, WM_SETICON, ICON_SMALL, ( LPARAM )LoadSkinIcon( iconId ));
+}
+
+void Window_SetProtoIcon_IcoLib(HWND hWnd, const char* szProto, int iconId)
+{
+ SendMessage(hWnd, WM_SETICON, ICON_BIG, ( LPARAM )LoadSkinProtoIcon( szProto, iconId, true ));
+ SendMessage(hWnd, WM_SETICON, ICON_SMALL, ( LPARAM )LoadSkinProtoIcon( szProto, iconId ));
+}
+
+void Window_FreeIcon_IcoLib(HWND hWnd)
+{
+ IconLib_ReleaseIcon(( HICON )SendMessage(hWnd, WM_SETICON, ICON_BIG, 0), NULL);
+ IconLib_ReleaseIcon(( HICON )SendMessage(hWnd, WM_SETICON, ICON_SMALL, 0), NULL);
+}
+
+void Button_SetIcon_IcoLib(HWND hwndDlg, int itemId, int iconId, const char* tooltip)
+{
+ HWND hWnd = GetDlgItem( hwndDlg, itemId );
+ SendMessage( hWnd, BM_SETIMAGE, IMAGE_ICON, ( LPARAM )LoadSkinIcon( iconId ));
+ SendMessage( hWnd, BUTTONSETASFLATBTN, 0, 0 );
+ SendMessage( hWnd, BUTTONADDTOOLTIP, (WPARAM)tooltip, 0);
+}
+
+void Button_FreeIcon_IcoLib(HWND hwndDlg, int itemId)
+{
+ HICON hIcon = ( HICON )SendDlgItemMessage(hwndDlg, itemId, BM_SETIMAGE, IMAGE_ICON, 0 );
+ IconLib_ReleaseIcon(hIcon,0);
+}
+
+//
+// wParam = szProto
+// lParam = status
+//
+HICON LoadSkinProtoIcon( const char* szProto, int status, bool big )
+{
+ int i, statusIndx = -1;
+ char iconName[MAX_PATH];
+ HICON hIcon;
+ DWORD caps2 = ( szProto == NULL ) ? ( DWORD )-1 : CallProtoService(szProto,PS_GETCAPS,PFLAGNUM_2,0);
+
+ if ( status >= ID_STATUS_CONNECTING && status < ID_STATUS_CONNECTING+MAX_CONNECT_RETRIES ) {
+ mir_snprintf( iconName, SIZEOF(iconName), "%s%d", mainIconsFmt, 7 );
+ return IcoLib_GetIcon( iconName, big );
+ }
+
+ for ( i = 0; i < SIZEOF(statusIcons); i++ ) {
+ if ( statusIcons[i].id == status ) {
+ statusIndx = i;
+ break;
+ } }
+
+ if ( statusIndx == -1 )
+ return NULL;
+
+ if ( !szProto ) {
+ // Only return a protocol specific icon if there is only one protocol
+ // Otherwise return the global icon. This affects the global status menu mainly.
+ if ( accounts.getCount() == 1 ) {
+ HICON hIcon;
+
+ // format: core_status_%proto%statusindex
+ mir_snprintf(iconName, SIZEOF(iconName), "%s%s%d", statusIconsFmt, szProto, statusIndx);
+
+ hIcon = IcoLib_GetIcon( iconName, big );
+ if ( hIcon )
+ return hIcon;
+ }
+
+ // format: core_status_%s%d
+ mir_snprintf(iconName, SIZEOF(iconName), "%s%s%d", statusIconsFmt, GLOBAL_PROTO_NAME, statusIndx);
+ return IcoLib_GetIcon( iconName, big );
+ }
+
+ // format: core_status_%s%d
+ mir_snprintf(iconName, SIZEOF(iconName), "%s%s%d", statusIconsFmt, szProto, statusIndx);
+ hIcon = IcoLib_GetIcon( iconName, big );
+ if ( hIcon == NULL && ( caps2 == 0 || ( caps2 & statusIcons[statusIndx].pf2 ))) {
+ PROTOACCOUNT* pa = Proto_GetAccount( szProto );
+ if ( pa ) {
+ TCHAR szPath[MAX_PATH], szFullPath[MAX_PATH], *str;
+ SKINICONDESC sid = { 0 };
+
+ //
+ // Queried protocol isn't in list, adding
+ //
+ TCHAR tszSection[MAX_PATH];
+ mir_sntprintf( tszSection, SIZEOF(tszSection), _T("%s%s"), _T(PROTOCOLS_PREFIX), pa->tszAccountName );
+ sid.ptszSection = tszSection;
+
+ sid.cbSize = sizeof(sid);
+ sid.flags = SIDF_ALL_TCHAR;
+
+ GetModuleFileName( hMirandaInst, szPath, MAX_PATH );
+ str = _tcsrchr( szPath, '\\' );
+ if ( str != NULL )
+ *str = 0;
+ mir_sntprintf( szFullPath, SIZEOF(szFullPath), _T("%s\\Icons\\proto_") _T(TCHAR_STR_PARAM) _T(".dll"), szPath, pa->szProtoName );
+ if ( GetFileAttributes( szFullPath ) != INVALID_FILE_ATTRIBUTES )
+ sid.ptszDefaultFile = szFullPath;
+ else {
+ mir_sntprintf( szFullPath, SIZEOF(szFullPath), _T("%s\\Plugins\\") _T(TCHAR_STR_PARAM) _T(".dll"), szPath, szProto );
+ if (( int )ExtractIconEx( szFullPath, statusIcons[i].resource_id, NULL, &hIcon, 1 ) > 0 ) {
+ DestroyIcon( hIcon );
+ sid.ptszDefaultFile = szFullPath;
+ hIcon = NULL;
+ }
+
+ if ( sid.pszDefaultFile == NULL ) {
+ if ( str != NULL )
+ *str = '\\';
+ sid.ptszDefaultFile = szPath;
+ } }
+
+ //
+ // Add global icons to list
+ //
+ {
+ int lowidx, highidx;
+ if ( caps2 == 0 )
+ lowidx = statusIndx, highidx = statusIndx+1;
+ else
+ lowidx = 0, highidx = SIZEOF(statusIcons);
+
+ for ( i = lowidx; i < highidx; i++ ) {
+ if ( caps2 == 0 || ( caps2 & statusIcons[i].pf2 )) {
+ // format: core_%s%d
+ mir_snprintf( iconName, SIZEOF(iconName), "%s%s%d", statusIconsFmt, szProto, i );
+ sid.pszName = iconName;
+ sid.ptszDescription = cli.pfnGetStatusModeDescription( statusIcons[i].id, 0 );
+ sid.iDefaultIndex = statusIcons[i].resource_id;
+ IcoLib_AddNewIcon( &sid );
+ } } } }
+
+ // format: core_status_%s%d
+ mir_snprintf( iconName, SIZEOF(iconName), "%s%s%d", statusIconsFmt, szProto, statusIndx );
+ hIcon = IcoLib_GetIcon( iconName, big );
+ if ( hIcon )
+ return hIcon;
+ }
+
+ if ( hIcon == NULL ) {
+ mir_snprintf( iconName, SIZEOF(iconName), "%s%s%d", statusIconsFmt, GLOBAL_PROTO_NAME, statusIndx );
+ hIcon = IcoLib_GetIcon( iconName, big );
+ }
+
+ return hIcon;
+}
+
+HANDLE GetSkinIconHandle( int idx )
+{
+ int i;
+ for ( i = 0; i < SIZEOF(mainIcons); i++ )
+ if ( idx == mainIcons[i].id )
+ return hMainIcons[i];
+
+ return NULL;
+}
+
+HICON LoadSkinIcon( int idx, bool big )
+{
+ //
+ // Query for global status icons
+ //
+ if ( idx < SKINICON_EVENT_MESSAGE ) {
+ if ( idx >= SIZEOF( statusIcons ))
+ return NULL;
+
+ return LoadSkinProtoIcon( NULL, statusIcons[ idx ].id, big );
+ }
+
+ return IcoLib_GetIconByHandle( GetSkinIconHandle( idx ), big );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Initializes the icon skin module
+
+static void convertOneProtocol( char* moduleName, char* iconName )
+{
+ char* pm = moduleName + strlen( moduleName );
+ char* pi = iconName + strlen( iconName );
+ DBVARIANT dbv;
+ int i;
+
+ for ( i = 0; i < SIZEOF(statusIcons); i++ ) {
+ _itoa( statusIcons[i].id, pm, 10 );
+
+ if ( !DBGetContactSettingTString( NULL, "Icons", moduleName, &dbv ) ) {
+ _itoa( i, pi, 10 );
+
+ DBWriteContactSettingTString( NULL, "SkinIcons", iconName, dbv.ptszVal );
+ DBFreeVariant( &dbv );
+
+ DBDeleteContactSetting( NULL, "Icons", moduleName );
+} } }
+
+static INT_PTR sttLoadSkinIcon( WPARAM wParam, LPARAM lParam )
+{
+ switch (lParam)
+ {
+ case 0:
+ return (INT_PTR)LoadSkinIcon( wParam );
+
+ case 1:
+ return (INT_PTR)GetSkinIconHandle( wParam );
+
+ case 2:
+ return (INT_PTR)LoadSkinIcon( wParam, true );
+ }
+
+ return 0;
+}
+
+static INT_PTR sttLoadSkinProtoIcon( WPARAM wParam, LPARAM lParam )
+{
+ return (INT_PTR)LoadSkinProtoIcon( (char*)wParam, (int)lParam, false );
+}
+
+static INT_PTR sttLoadSkinProtoIconBig( WPARAM wParam, LPARAM lParam )
+{
+ return (INT_PTR)LoadSkinProtoIcon( (char*)wParam, (int)lParam, true );
+}
+
+int LoadSkinIcons(void)
+{
+ SKINICONDESC sid;
+ int i, j = 0;
+ char iconName[MAX_PATH], moduleName[MAX_PATH];
+ TCHAR modulePath[MAX_PATH];
+ DBVARIANT dbv;
+
+ //
+ // Perform "1st-time running import"
+
+ for ( i = 0; i < SIZEOF(mainIcons); i++ ) {
+ _itoa( mainIcons[i].id, moduleName, 10 );
+ if ( DBGetContactSettingTString( NULL, "Icons", moduleName, &dbv ))
+ break;
+
+ mir_snprintf( iconName, SIZEOF(iconName), "%s%d", mainIconsFmt, i );
+
+ DBWriteContactSettingTString( NULL, "SkinIcons", iconName, dbv.ptszVal );
+ DBFreeVariant( &dbv );
+
+ DBDeleteContactSetting( NULL, "Icons", moduleName );
+ }
+
+ for ( ;; ) {
+ // get the next protocol name
+ moduleName[0] = 'p';
+ moduleName[1] = 0;
+ _itoa( j++, moduleName+1, 100 );
+ if ( DBGetContactSettingTString( NULL, "Icons", moduleName, &dbv ))
+ break;
+
+ DBDeleteContactSetting( NULL, "Icons", moduleName );
+
+ // make old skinicons' prefix
+ mir_snprintf( moduleName, SIZEOF(moduleName), TCHAR_STR_PARAM, dbv.ptszVal );
+ // make IcoLib's prefix
+ mir_snprintf( iconName, SIZEOF(iconName), "%s" TCHAR_STR_PARAM, statusIconsFmt, dbv.ptszVal );
+
+ convertOneProtocol( moduleName, iconName );
+ DBFreeVariant( &dbv );
+ }
+ moduleName[0] = 0;
+ strcpy(iconName, "core_status_" GLOBAL_PROTO_NAME);
+ convertOneProtocol( moduleName, iconName );
+
+ CreateServiceFunction( MS_SKIN_LOADICON, sttLoadSkinIcon );
+ CreateServiceFunction( MS_SKIN_LOADPROTOICON, sttLoadSkinProtoIcon );
+ CreateServiceFunction( MS_SKIN_LOADPROTOICONBIG, sttLoadSkinProtoIconBig );
+
+ ZeroMemory( &sid, sizeof(sid) );
+ sid.cbSize = sizeof(sid);
+ GetModuleFileName(NULL, modulePath, SIZEOF(modulePath));
+ sid.ptszDefaultFile = modulePath;
+ sid.flags = SIDF_PATH_TCHAR;
+ sid.pszName = iconName;
+
+ //
+ // Add main icons to list
+ //
+ for ( i = 0; i < SIZEOF(mainIcons); i++ ) {
+ mir_snprintf( iconName, SIZEOF(iconName), "%s%d", mainIconsFmt, i );
+ sid.pszSection = mainIcons[i].section == NULL ? "Main Icons" : (char*)mainIcons[i].section;
+ sid.pszDescription = (char*)mainIcons[i].description;
+ sid.iDefaultIndex = mainIcons[i].resource_id;
+ hMainIcons[i] = IcoLib_AddNewIcon( &sid );
+ }
+ //
+ // Add global icons to list
+ //
+ sid.pszSection = PROTOCOLS_PREFIX "Global";
+ //
+ // Asterisk is used, to avoid conflict with proto-plugins
+ // 'coz users can't rename it to name with '*'
+ for ( i = 0; i < SIZEOF(statusIcons); i++ ) {
+ mir_snprintf( iconName, SIZEOF(iconName), "%s%s%d", statusIconsFmt, GLOBAL_PROTO_NAME, i );
+ sid.pszName = iconName;
+ sid.pszDescription = (char*)statusIcons[i].description;
+ sid.iDefaultIndex = statusIcons[i].resource_id;
+ hStatusIcons[i] = IcoLib_AddNewIcon( &sid );
+ }
+ return 0;
+}
diff --git a/src/modules/skin/sounds.cpp b/src/modules/skin/sounds.cpp
new file mode 100644
index 0000000000..734c319ac9
--- /dev/null
+++ b/src/modules/skin/sounds.cpp
@@ -0,0 +1,469 @@
+/*
+
+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"
+
+struct SoundItem {
+ char* name;
+ TCHAR* section;
+ TCHAR* description;
+ char* tempFile;
+};
+
+static BOOL bModuleInitialized = FALSE;
+static struct SoundItem *soundList = NULL;
+static int soundCount;
+static HANDLE hPlayEvent = NULL;
+
+static INT_PTR ServiceSkinAddNewSound(WPARAM, LPARAM lParam)
+{
+ SKINSOUNDDESCEX *ssd = ( SKINSOUNDDESCEX* )lParam;
+ switch( ssd->cbSize ) {
+ case sizeof( SKINSOUNDDESCEX ):
+ case SKINSOUNDDESC_SIZE_V1:
+ case SKINSOUNDDESC_SIZE_V2:
+ break;
+
+ default:
+ return 1;
+ }
+
+ if ( ssd->pszName == NULL || ssd->pszDescription == NULL)
+ return 1;
+
+ DBVARIANT dbv;
+ DWORD dwFlags = ( ssd->cbSize == sizeof(SKINSOUNDDESCEX)) ? ssd->dwFlags : 0;
+
+ soundList=(struct SoundItem*)mir_realloc(soundList,sizeof(struct SoundItem)*(soundCount+1));
+ SoundItem* item = &soundList[soundCount++];
+ item->name = mir_strdup( ssd->pszName );
+ item->tempFile = NULL;
+ #if defined( _UNICODE )
+ TCHAR* ptszDefaultFile;
+ if ( dwFlags & SSDF_UNICODE ) {
+ item->description = mir_tstrdup( TranslateTS( ssd->ptszDescription ));
+ item->section = mir_tstrdup( TranslateTS( ssd->cbSize != SKINSOUNDDESC_SIZE_V1 && ssd->pszSection != NULL ? ssd->ptszSection : _T("Other")));
+ ptszDefaultFile = mir_tstrdup( ssd->ptszDefaultFile );
+ }
+ else {
+ item->description = LangPackPcharToTchar( ssd->pszDescription );
+ item->section = LangPackPcharToTchar( ssd->cbSize != SKINSOUNDDESC_SIZE_V1 && ssd->pszSection != NULL ? ssd->pszSection : "Other" );
+ ptszDefaultFile = mir_a2t( ssd->pszDefaultFile );
+ }
+
+ if ( ptszDefaultFile ) {
+ if ( DBGetContactSettingString(NULL, "SkinSounds", item->name, &dbv))
+ DBWriteContactSettingTString(NULL, "SkinSounds", item->name, ptszDefaultFile);
+ else
+ DBFreeVariant(&dbv);
+ mir_free( ptszDefaultFile );
+ }
+ #else
+ item->description = mir_tstrdup( TranslateTS( ssd->pszDescription ));
+ item->section = mir_tstrdup( TranslateTS( ssd->cbSize != SKINSOUNDDESC_SIZE_V1 && ssd->pszSection != NULL ? ssd->pszSection : "Other" ));
+ if ( ssd->pszDefaultFile ) {
+ if ( DBGetContactSettingString(NULL, "SkinSounds", item->name, &dbv))
+ DBWriteContactSettingString(NULL, "SkinSounds", item->name, ssd->pszDefaultFile);
+ else
+ DBFreeVariant(&dbv);
+ }
+ #endif
+ return 0;
+}
+
+static int SkinPlaySoundDefault(WPARAM wParam, LPARAM lParam)
+{
+ char * pszFile = (char *) lParam;
+ if ( pszFile && (DBGetContactSettingByte(NULL,"Skin","UseSound",0) || (int)wParam==1))
+ PlaySoundA(pszFile, NULL, SND_ASYNC | SND_FILENAME | SND_NOWAIT);
+
+ return 0;
+}
+
+static INT_PTR ServiceSkinPlaySound(WPARAM, LPARAM lParam)
+{
+ char* pszSoundName = ( char* )lParam;
+ int j;
+
+ for (j=0; j<soundCount; j++) {
+ if ( pszSoundName && strcmp( soundList[j].name, pszSoundName ) == 0) {
+ if (DBGetContactSettingByte(NULL, "SkinSoundsOff", pszSoundName, 0)==0) {
+ DBVARIANT dbv;
+
+ if (DBGetContactSettingString(NULL, "SkinSounds", pszSoundName, &dbv)==0) {
+ char szFull[MAX_PATH];
+
+ pathToAbsolute(dbv.pszVal, szFull, NULL);
+ NotifyEventHooks(hPlayEvent, 0, (LPARAM)szFull);
+ DBFreeVariant(&dbv);
+ }
+ }
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static HTREEITEM FindNamedTreeItemAtRoot(HWND hwndTree, const TCHAR* name)
+{
+ TVITEM tvi;
+ TCHAR str[128];
+
+ tvi.mask = TVIF_TEXT;
+ tvi.pszText = str;
+ tvi.cchTextMax = SIZEOF(str);
+ tvi.hItem = TreeView_GetRoot(hwndTree);
+ while( tvi.hItem != NULL ) {
+ TreeView_GetItem( hwndTree, &tvi );
+ if ( !_tcsicmp( str, name ))
+ return tvi.hItem;
+
+ tvi.hItem = TreeView_GetNextSibling( hwndTree, tvi.hItem );
+ }
+ return NULL;
+}
+
+#define DM_REBUILD_STREE (WM_USER+1)
+#define DM_HIDEPANE (WM_USER+2)
+#define DM_SHOWPANE (WM_USER+3)
+#define DM_CHECKENABLED (WM_USER+4)
+INT_PTR CALLBACK DlgProcSoundOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static HWND hwndTree = NULL;
+ switch (msg) {
+ case WM_DESTROY:
+ ImageList_Destroy(TreeView_GetImageList(hwndTree, TVSIL_STATE));
+ break;
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ hwndTree = GetDlgItem(hwndDlg, IDC_SOUNDTREE);
+ SetWindowLongPtr(hwndTree,GWL_STYLE,GetWindowLongPtr(hwndTree,GWL_STYLE)|TVS_NOHSCROLL|TVS_CHECKBOXES);
+ SendMessage(hwndDlg, DM_HIDEPANE, 0, 0);
+ SendMessage(hwndDlg, DM_REBUILD_STREE, 0, 0);
+ TreeView_SetItemState(hwndTree, 0, TVIS_SELECTED, TVIS_SELECTED);
+ CheckDlgButton(hwndDlg, IDC_ENABLESOUNDS, DBGetContactSettingByte(NULL, "Skin", "UseSound", 0));
+ SendMessage(hwndDlg, DM_CHECKENABLED, 0, 0);
+ return TRUE;
+
+ case DM_REBUILD_STREE:
+ TreeView_SelectItem(hwndTree, NULL);
+ ShowWindow(hwndTree, SW_HIDE);
+ TreeView_DeleteAllItems(hwndTree);
+ {
+ TVINSERTSTRUCT tvis;
+ int i;
+ tvis.hParent = NULL;
+ tvis.hInsertAfter = TVI_SORT;
+ tvis.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM;
+ tvis.item.state = tvis.item.stateMask = TVIS_EXPANDED;
+ for( i=0; i < soundCount; i++ ) {
+ tvis.item.stateMask = TVIS_EXPANDED;
+ tvis.item.state = TVIS_EXPANDED;
+ tvis.hParent = FindNamedTreeItemAtRoot( hwndTree, soundList[i].section );
+ if ( tvis.hParent == NULL ) {
+ tvis.item.lParam = -1;
+ tvis.item.pszText = soundList[i].section;
+ tvis.hParent = tvis.item.hItem = TreeView_InsertItem( hwndTree, &tvis );
+ tvis.item.stateMask = TVIS_STATEIMAGEMASK;
+ tvis.item.state = INDEXTOSTATEIMAGEMASK(0);
+ TreeView_SetItem( hwndTree, &tvis.item );
+ }
+ tvis.item.stateMask = TVIS_STATEIMAGEMASK;
+ tvis.item.state = INDEXTOSTATEIMAGEMASK(!DBGetContactSettingByte(NULL,"SkinSoundsOff",soundList[i].name,0)?2:1);
+ tvis.item.lParam = i;
+ tvis.item.pszText = soundList[i].description;
+ TreeView_InsertItem( hwndTree, &tvis );
+ } }
+ { TVITEM tvi;
+ tvi.hItem = TreeView_GetRoot(hwndTree);
+ while ( tvi.hItem != NULL ) {
+ tvi.mask = TVIF_PARAM | TVIF_HANDLE | TVIF_STATE;
+ TreeView_GetItem(hwndTree, &tvi);
+ if ( tvi.lParam == -1 )
+ TreeView_SetItemState(hwndTree, tvi.hItem, INDEXTOSTATEIMAGEMASK(0), TVIS_STATEIMAGEMASK);
+
+ tvi.hItem=TreeView_GetNextSibling(hwndTree,tvi.hItem);
+ } }
+
+ ShowWindow(hwndTree, SW_SHOW);
+ break;
+
+ case DM_HIDEPANE:
+ ShowWindow(GetDlgItem(hwndDlg, IDC_SGROUP), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_NAME), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_NAMEVAL), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_SLOC), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_LOCATION), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_CHANGE), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_PREVIEW), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_GETMORE), SW_HIDE);
+ break;
+
+ case DM_SHOWPANE:
+ ShowWindow(GetDlgItem(hwndDlg, IDC_SGROUP), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_NAME), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_NAMEVAL), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_SLOC), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_LOCATION), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_CHANGE), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_PREVIEW), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_GETMORE), SW_SHOW);
+ break;
+
+ case DM_CHECKENABLED:
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SOUNDTREE), IsDlgButtonChecked(hwndDlg, IDC_ENABLESOUNDS));
+ if (!IsDlgButtonChecked(hwndDlg, IDC_ENABLESOUNDS))
+ SendMessage(hwndDlg, DM_HIDEPANE, 0, 0);
+ else if (TreeView_GetSelection(hwndTree)&&TreeView_GetParent(hwndTree, TreeView_GetSelection(hwndTree)))
+ SendMessage(hwndDlg, DM_SHOWPANE, 0, 0);
+ break;
+
+ case WM_COMMAND:
+ if ( LOWORD(wParam) == IDC_ENABLESOUNDS )
+ SendMessage(hwndDlg, DM_CHECKENABLED, 0, 0);
+
+ if ( LOWORD(wParam) == IDC_PREVIEW ) {
+ TVITEM tvi;
+ HTREEITEM hti;
+
+ ZeroMemory(&tvi,sizeof(tvi));
+ ZeroMemory(&hti,sizeof(hti));
+ hti=TreeView_GetSelection(hwndTree);
+ if (hti==NULL) break;
+ tvi.mask=TVIF_HANDLE|TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_PARAM|TVIF_TEXT;
+ tvi.hItem = hti;
+ if (TreeView_GetItem(hwndTree, &tvi)==FALSE) break;
+ if (tvi.lParam==-1) break;
+ if (soundList[tvi.lParam].tempFile)
+ NotifyEventHooks(hPlayEvent, 1, (LPARAM)soundList[tvi.lParam].tempFile);
+ else {
+ DBVARIANT dbv;
+ if(!DBGetContactSettingString(NULL,"SkinSounds",soundList[tvi.lParam].name,&dbv)) {
+ char szPathFull[MAX_PATH];
+
+ pathToAbsolute(dbv.pszVal, szPathFull, NULL);
+ NotifyEventHooks(hPlayEvent, 1, (LPARAM)szPathFull);
+ DBFreeVariant(&dbv);
+ } }
+ break;
+ }
+ if ( LOWORD( wParam ) == IDC_CHANGE ) {
+ char str[MAX_PATH] = "", strFull[MAX_PATH], strdir[MAX_PATH]="", filter[MAX_PATH];
+ OPENFILENAMEA ofn;
+ TVITEM tvi;
+ HTREEITEM hti;
+
+ ZeroMemory(&tvi,sizeof(tvi));
+ ZeroMemory(&hti,sizeof(hti));
+ hti=TreeView_GetSelection(hwndTree);
+ if (hti==NULL) break;
+ tvi.mask=TVIF_HANDLE|TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_PARAM|TVIF_TEXT;
+ tvi.hItem = hti;
+ if (TreeView_GetItem(hwndTree, &tvi)==FALSE) break;
+ if (tvi.lParam==-1) break;
+ if (soundList[tvi.lParam].tempFile)
+ mir_snprintf(strFull, SIZEOF(strFull), "%s", soundList[tvi.lParam].tempFile);
+ else {
+ if (DBGetContactSettingByte(NULL, "SkinSoundsOff", soundList[tvi.lParam].name, 0)==0) {
+ DBVARIANT dbv;
+
+ if (DBGetContactSettingString(NULL, "SkinSounds", soundList[tvi.lParam].name, &dbv)==0) {
+ pathToAbsolute(dbv.pszVal, strdir, NULL);
+ DBFreeVariant(&dbv);
+ } } }
+
+ mir_snprintf(strFull, SIZEOF(strFull), "%s", soundList[tvi.lParam].tempFile?soundList[tvi.lParam].tempFile:"");
+ pathToAbsolute(strFull, strdir, NULL);
+ ZeroMemory(&ofn, sizeof(ofn));
+ mir_snprintf(filter, SIZEOF(filter), "%s (*.wav; *.mp3; *.ogg; *.flac)%c*.WAV; *.MP3; *.OGG; *.FLAC%c%s (*)%c*%c", Translate("Sound Files"), 0, 0, Translate("All Files"), 0, 0);
+ ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
+ ofn.hwndOwner = GetParent(hwndDlg);
+ ofn.hInstance = NULL;
+ ofn.lpstrFilter = filter;
+ { char* slash = strrchr(strdir, '\\');
+ if (slash) {
+ *slash = 0;
+ ofn.lpstrInitialDir = strdir;
+ }
+ }
+ ofn.lpstrFile = str;
+ ofn.Flags = OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_EXPLORER|OFN_LONGNAMES|OFN_NOCHANGEDIR;
+ ofn.nMaxFile = SIZEOF(str);
+ ofn.nMaxFileTitle = MAX_PATH;
+ ofn.lpstrDefExt = "wav";
+ if(!GetOpenFileNameA(&ofn)) break;
+ CallService(MS_UTILS_PATHTORELATIVE, (WPARAM)str, (LPARAM)strFull);
+ soundList[tvi.lParam].tempFile = mir_strdup(strFull);
+ SetDlgItemTextA(hwndDlg, IDC_LOCATION, strFull);
+ }
+ if(LOWORD(wParam)==IDC_GETMORE) {
+ CallService(MS_UTILS_OPENURL,1,(LPARAM)"http://addons.miranda-im.org/index.php?action=display&id=5");
+ break;
+ }
+ if(LOWORD(wParam)==IDC_LOCATION) {
+ break;
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case WM_NOTIFY:
+ switch(((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ if (((LPNMHDR)lParam)->code == PSN_APPLY)
+ {
+ int i;
+
+ DBWriteContactSettingByte(NULL, "Skin", "UseSound", (BYTE) IsDlgButtonChecked(hwndDlg, IDC_ENABLESOUNDS));
+ for ( i=0; i < soundCount; i++ )
+ if ( soundList[i].tempFile )
+ DBWriteContactSettingString(NULL,"SkinSounds",soundList[i].name,soundList[i].tempFile);
+ {
+ TVITEM tvi,tvic;
+ tvi.hItem = TreeView_GetRoot(hwndTree);
+ while ( tvi.hItem != NULL ) {
+ tvi.mask = TVIF_PARAM | TVIF_HANDLE | TVIF_STATE;
+ TreeView_GetItem(hwndTree, &tvi);
+ if ( tvi.lParam == -1 ) {
+ tvic.hItem = TreeView_GetChild(hwndTree, tvi.hItem);
+ while ( tvic.hItem != NULL ) {
+ tvic.mask = TVIF_PARAM | TVIF_HANDLE | TVIF_STATE;
+ TreeView_GetItem(hwndTree, &tvic);
+ if ((( tvic.state & TVIS_STATEIMAGEMASK ) >> 12 == 2 )) {
+ DBCONTACTGETSETTING cgs;
+ cgs.szModule = "SkinSoundsOff";
+ cgs.szSetting = soundList[tvic.lParam].name;
+ CallService(MS_DB_CONTACT_DELETESETTING,(WPARAM)(HANDLE)NULL,(LPARAM)&cgs);
+ }
+ else DBWriteContactSettingByte(NULL,"SkinSoundsOff",soundList[tvic.lParam].name,1);
+ tvic.hItem=TreeView_GetNextSibling(hwndTree,tvic.hItem);
+ } }
+
+ tvi.hItem=TreeView_GetNextSibling(hwndTree,tvi.hItem);
+ } }
+ return TRUE;
+ }
+ break;
+ case IDC_SOUNDTREE:
+ switch(((NMHDR*)lParam)->code) {
+ case TVN_SELCHANGEDA:
+ {
+ NMTREEVIEW *pnmtv = (NMTREEVIEW*)lParam;
+ TVITEM tvi = pnmtv->itemNew;
+
+ if (tvi.lParam==-1) {
+ SendMessage(hwndDlg, DM_HIDEPANE, 0, 0);
+ }
+ else {
+ TCHAR buf[256];
+ DBVARIANT dbv;
+
+ mir_sntprintf(buf, SIZEOF(buf), _T("%s: %s"), soundList[tvi.lParam].section, soundList[tvi.lParam].description);
+ SetDlgItemText(hwndDlg, IDC_NAMEVAL, buf);
+ if (soundList[tvi.lParam].tempFile)
+ SetDlgItemTextA(hwndDlg, IDC_LOCATION, soundList[tvi.lParam].tempFile);
+ else if(!DBGetContactSettingString(NULL,"SkinSounds",soundList[tvi.lParam].name,&dbv)) {
+ SetDlgItemTextA(hwndDlg, IDC_LOCATION, dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ else SetDlgItemText(hwndDlg, IDC_LOCATION, TranslateT("<not specified>"));
+ SendMessage(hwndDlg, DM_SHOWPANE, 0, 0);
+ }
+ }
+ break;
+ case TVN_KEYDOWN:
+ {
+ NMTVKEYDOWN* ptkd = (NMTVKEYDOWN*)lParam;
+
+ if (ptkd&&ptkd->wVKey==VK_SPACE&&TreeView_GetSelection(ptkd->hdr.hwndFrom))
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ break;
+ case NM_CLICK:
+ {
+ TVHITTESTINFO hti;
+ hti.pt.x=(short)LOWORD(GetMessagePos());
+ hti.pt.y=(short)HIWORD(GetMessagePos());
+ ScreenToClient(((LPNMHDR)lParam)->hwndFrom,&hti.pt);
+ if(TreeView_HitTest(((LPNMHDR)lParam)->hwndFrom,&hti))
+ if (hti.flags&TVHT_ONITEM)
+ if(hti.flags&TVHT_ONITEMSTATEICON)
+ if (TreeView_GetParent(hwndTree, hti.hItem)!=NULL)
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ } }
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static UINT iconsExpertOnlyControls[]={IDC_IMPORT};
+
+static int SkinOptionsInit(WPARAM wParam, LPARAM)
+{
+ OPTIONSDIALOGPAGE odp = { 0 };
+ odp.cbSize = sizeof(odp);
+ odp.position = -200000000;
+ odp.hInstance = hMirandaInst;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_SOUND);
+ odp.pszGroup = LPGEN("Customize");
+ odp.pszTitle = LPGEN("Sounds");
+ odp.pfnDlgProc = DlgProcSoundOpts;
+ odp.flags = ODPF_BOLDGROUPS;
+ CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
+ return 0;
+}
+
+static int SkinSystemModulesLoaded(WPARAM, LPARAM)
+{
+ HookEvent(ME_OPT_INITIALISE,SkinOptionsInit);
+ return 0;
+}
+
+int LoadSkinSounds(void)
+{
+ bModuleInitialized = TRUE;
+
+ soundList=NULL;
+ soundCount=0;
+ CreateServiceFunction(MS_SKIN_ADDNEWSOUND,ServiceSkinAddNewSound);
+ CreateServiceFunction(MS_SKIN_PLAYSOUND,ServiceSkinPlaySound);
+ HookEvent(ME_SYSTEM_MODULESLOADED,SkinSystemModulesLoaded);
+ hPlayEvent=CreateHookableEvent(ME_SKIN_PLAYINGSOUND);
+ SetHookDefaultForHookableEvent(hPlayEvent, SkinPlaySoundDefault);
+ return 0;
+}
+
+void UnloadSkinSounds(void)
+{
+ int i;
+
+ if ( !bModuleInitialized ) return;
+
+ for(i=0;i<soundCount;i++) {
+ mir_free(soundList[i].name);
+ mir_free(soundList[i].section);
+ mir_free(soundList[i].description);
+ if (soundList[i].tempFile) mir_free(soundList[i].tempFile);
+ }
+ if(soundCount) mir_free(soundList);
+}
diff --git a/src/modules/srauth/auth.cpp b/src/modules/srauth/auth.cpp
new file mode 100644
index 0000000000..d62c4af4f4
--- /dev/null
+++ b/src/modules/srauth/auth.cpp
@@ -0,0 +1,129 @@
+/*
+
+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 MS_AUTH_SHOWREQUEST "Auth/ShowRequest"
+#define MS_AUTH_SHOWADDED "Auth/ShowAdded"
+
+INT_PTR CALLBACK DlgProcAuthReq(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+INT_PTR CALLBACK DlgProcAdded(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+INT_PTR ShowReqWindow(WPARAM, LPARAM lParam)
+{
+ CreateDialogParam(hMirandaInst, MAKEINTRESOURCE(IDD_AUTHREQ), NULL, DlgProcAuthReq,
+ (LPARAM)((CLISTEVENT *)lParam)->hDbEvent);
+ return 0;
+}
+
+INT_PTR ShowAddedWindow(WPARAM, LPARAM lParam)
+{
+ CreateDialogParam(hMirandaInst, MAKEINTRESOURCE(IDD_ADDED), NULL, DlgProcAdded,
+ (LPARAM)((CLISTEVENT *)lParam)->hDbEvent);
+ return 0;
+}
+
+static int AuthEventAdded(WPARAM, LPARAM lParam)
+{
+ TCHAR szUid[128] = _T("");
+ TCHAR szTooltip[256];
+ const HANDLE hDbEvent = (HANDLE)lParam;
+
+ DBEVENTINFO dbei = {0};
+ dbei.cbSize = sizeof(dbei);
+ CallService(MS_DB_EVENT_GET,(WPARAM)lParam,(LPARAM)&dbei);
+ if (dbei.flags & (DBEF_SENT | DBEF_READ) ||
+ (dbei.eventType != EVENTTYPE_AUTHREQUEST && dbei.eventType != EVENTTYPE_ADDED))
+ return 0;
+
+ dbei.cbBlob = CallService(MS_DB_EVENT_GETBLOBSIZE, lParam, 0);
+ dbei.pBlob = (PBYTE)alloca(dbei.cbBlob);
+ CallService(MS_DB_EVENT_GET, lParam, (LPARAM)&dbei);
+
+ HANDLE hContact = *(PHANDLE)(dbei.pBlob + sizeof(DWORD));
+
+ CLISTEVENT cli ={0};
+ cli.cbSize = sizeof(cli);
+ cli.hContact = hContact;
+ cli.ptszTooltip = szTooltip;
+ cli.flags = CLEF_TCHAR;
+ cli.lParam = lParam;
+ cli.hDbEvent = hDbEvent;
+
+ CONTACTINFO ci = {0};
+ ci.cbSize = sizeof(ci);
+ ci.hContact = hContact;
+ ci.szProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ ci.dwFlag = CNF_UNIQUEID | CNF_TCHAR;
+ if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM)&ci))
+ {
+ switch (ci.type)
+ {
+ case CNFT_ASCIIZ:
+ mir_sntprintf(szUid, SIZEOF(szUid), _T("%s"), ci.pszVal);
+ mir_free(ci.pszVal);
+ break;
+
+ case CNFT_DWORD:
+ mir_sntprintf(szUid, SIZEOF(szUid), _T("%u"), ci.dVal);
+ break;
+ }
+ }
+
+ if (dbei.eventType == EVENTTYPE_AUTHREQUEST)
+ {
+ SkinPlaySound("AuthRequest");
+ if (szUid[0])
+ mir_sntprintf(szTooltip, SIZEOF(szTooltip), TranslateT("%s requests authorization"), szUid);
+ else
+ mir_sntprintf(szTooltip, SIZEOF(szTooltip), TranslateT("%u requests authorization"), *((PDWORD)dbei.pBlob));
+
+ cli.hIcon = LoadSkinIcon(SKINICON_OTHER_MIRANDA);
+ cli.pszService = MS_AUTH_SHOWREQUEST;
+ CallService(MS_CLIST_ADDEVENT, 0, (LPARAM)&cli);
+ }
+ else if (dbei.eventType == EVENTTYPE_ADDED)
+ {
+ SkinPlaySound("AddedEvent");
+ if (szUid[0])
+ mir_sntprintf(szTooltip, SIZEOF(szTooltip), TranslateT("%s added you to their contact list"), szUid);
+ else
+ mir_sntprintf(szTooltip, SIZEOF(szTooltip), TranslateT("%u added you to their contact list"), *((PDWORD)dbei.pBlob));
+
+ cli.hIcon = LoadSkinIcon(SKINICON_OTHER_MIRANDA);
+ cli.pszService = MS_AUTH_SHOWADDED;
+ CallService(MS_CLIST_ADDEVENT, 0, (LPARAM)&cli);
+ }
+ return 0;
+}
+
+int LoadSendRecvAuthModule(void)
+{
+ CreateServiceFunction(MS_AUTH_SHOWREQUEST, ShowReqWindow);
+ CreateServiceFunction(MS_AUTH_SHOWADDED, ShowAddedWindow);
+ HookEvent(ME_DB_EVENT_ADDED, AuthEventAdded);
+
+ SkinAddNewSoundEx("AuthRequest", "Alerts", "Authorization request");
+ SkinAddNewSoundEx("AddedEvent", "Alerts", "Added event");
+
+ return 0;
+}
diff --git a/src/modules/srauth/authdialogs.cpp b/src/modules/srauth/authdialogs.cpp
new file mode 100644
index 0000000000..07651da4ce
--- /dev/null
+++ b/src/modules/srauth/authdialogs.cpp
@@ -0,0 +1,312 @@
+/*
+
+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_PTR CALLBACK DlgProcAdded(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ HANDLE hDbEvent = (HANDLE)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ TranslateDialogDefault(hwndDlg);
+ Button_SetIcon_IcoLib(hwndDlg, IDC_DETAILS, SKINICON_OTHER_USERDETAILS, LPGEN("View User's Details"));
+ Button_SetIcon_IcoLib(hwndDlg, IDC_ADD, SKINICON_OTHER_ADDCONTACT, LPGEN("Add Contact Permanently to List"));
+
+ hDbEvent = (HANDLE)lParam;
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
+
+ //blob is: uin(DWORD), hcontact(HANDLE), nick(ASCIIZ), first(ASCIIZ), last(ASCIIZ), email(ASCIIZ)
+ DBEVENTINFO dbei = {0};
+ dbei.cbSize = sizeof(dbei);
+ dbei.cbBlob = CallService(MS_DB_EVENT_GETBLOBSIZE,(WPARAM)hDbEvent,0);
+ dbei.pBlob = (PBYTE)alloca(dbei.cbBlob);
+ CallService(MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM)&dbei);
+
+ DWORD uin = *(PDWORD)dbei.pBlob;
+ HANDLE hContact = *(HANDLE*)(dbei.pBlob + sizeof(DWORD));
+ char* nick = (char *)(dbei.pBlob + sizeof(DWORD) + sizeof(HANDLE));
+ char* first = nick + strlen(nick) + 1;
+ char* last = first + strlen(first) + 1;
+ char* email = last + strlen(last) + 1;
+
+ SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, CallProtoService(dbei.szModule, PS_LOADICON, PLI_PROTOCOL | PLIF_SMALL, 0));
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, CallProtoService(dbei.szModule, PS_LOADICON, PLI_PROTOCOL | PLIF_LARGE, 0));
+
+ PROTOACCOUNT* acc = Proto_GetAccount(dbei.szModule);
+
+ TCHAR* lastT = dbei.flags & DBEF_UTF ? Utf8DecodeT(last) : mir_a2t(last);
+ TCHAR* firstT = dbei.flags & DBEF_UTF ? Utf8DecodeT(first) : mir_a2t(first);
+ TCHAR* nickT = dbei.flags & DBEF_UTF ? Utf8DecodeT(nick) : mir_a2t(nick);
+ TCHAR* emailT = dbei.flags & DBEF_UTF ? Utf8DecodeT(email) : mir_a2t(email);
+
+ TCHAR name[128] = _T("");
+ int off = 0;
+ if (firstT[0] && lastT[0])
+ off = mir_sntprintf(name, SIZEOF(name), _T("%s %s"), firstT, lastT);
+ else if (firstT[0])
+ off = mir_sntprintf(name, SIZEOF(name), _T("%s"), firstT);
+ else if (lastT[0])
+ off = mir_sntprintf(name, SIZEOF(name), _T("%s"), lastT);
+ if (nickT[0])
+ {
+ if (off)
+ mir_sntprintf(name + off, SIZEOF(name) - off, _T(" (%s)"), nickT);
+ else
+ mir_sntprintf(name, SIZEOF(name), _T("%s"), nickT);
+ }
+ if (!name[0])
+ _tcscpy(name, TranslateT("<Unknown>"));
+
+ TCHAR hdr[256];
+ if (uin && emailT[0])
+ mir_sntprintf(hdr, SIZEOF(hdr), TranslateT("%s added you to the contact list\n%u (%s) on %s"), name, uin, emailT, acc->tszAccountName);
+ else if (uin)
+ mir_sntprintf(hdr, SIZEOF(hdr), TranslateT("%s added you to the contact list\n%u on %s"), name, uin, acc->tszAccountName);
+ else
+ mir_sntprintf(hdr, SIZEOF(hdr), TranslateT("%s added you to the contact list\n%s on %s"), name, emailT[0] ? emailT : TranslateT("(Unknown)"), acc->tszAccountName);
+
+ SetDlgItemText(hwndDlg, IDC_HEADERBAR, hdr);
+
+ mir_free(lastT);
+ mir_free(firstT);
+ mir_free(nickT);
+ mir_free(emailT);
+
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_DETAILS), GWLP_USERDATA, (LONG_PTR)hContact);
+
+ if (hContact == INVALID_HANDLE_VALUE || !DBGetContactSettingByte(hContact, "CList", "NotOnList", 0))
+ ShowWindow(GetDlgItem(hwndDlg, IDC_ADD), FALSE);
+ }
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDC_ADD:
+ {
+ ADDCONTACTSTRUCT acs = {0};
+ acs.handle = hDbEvent;
+ acs.handleType = HANDLE_EVENT;
+ acs.szProto = "";
+ CallService(MS_ADDCONTACT_SHOW, (WPARAM)hwndDlg, (LPARAM)&acs);
+
+ HANDLE hContact = (HANDLE)GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_DETAILS), GWLP_USERDATA);
+ if ((hContact == INVALID_HANDLE_VALUE) || !DBGetContactSettingByte(hContact, "CList", "NotOnList", 0))
+ ShowWindow(GetDlgItem(hwndDlg,IDC_ADD),FALSE);
+ break;
+ }
+ case IDC_DETAILS:
+ {
+ HANDLE hContact = (HANDLE)GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_DETAILS), GWLP_USERDATA);
+ CallService(MS_USERINFO_SHOWDIALOG, (WPARAM)hContact, 0);
+ break;
+ }
+
+ case IDOK:
+ {
+ ADDCONTACTSTRUCT acs = {0};
+ acs.handle = hDbEvent;
+ acs.handleType = HANDLE_EVENT;
+ acs.szProto = "";
+ CallService(MS_ADDCONTACT_SHOW, (WPARAM)hwndDlg, (LPARAM)&acs);
+ }
+ //fall through
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ break;
+ }
+ break;
+
+ case WM_DESTROY:
+ Button_FreeIcon_IcoLib(hwndDlg,IDC_ADD);
+ Button_FreeIcon_IcoLib(hwndDlg,IDC_DETAILS);
+ DestroyIcon((HICON)SendMessage(hwndDlg, WM_SETICON, ICON_BIG, 0));
+ DestroyIcon((HICON)SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, 0));
+ break;
+ }
+ return FALSE;
+}
+
+INT_PTR CALLBACK DlgProcAuthReq(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ HANDLE hDbEvent = (HANDLE)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ Button_SetIcon_IcoLib(hwndDlg, IDC_DETAILS, SKINICON_OTHER_USERDETAILS, LPGEN("View User Details"));
+ Button_SetIcon_IcoLib(hwndDlg, IDC_ADD, SKINICON_OTHER_ADDCONTACT, LPGEN("Add Contact Permanently to List"));
+
+ {
+ DBEVENTINFO dbei = {0};
+ DWORD uin;
+ char *nick,*first,*last,*email,*reason;
+ HANDLE hContact;
+
+ hDbEvent = (HANDLE)lParam;
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
+
+ //blob is: uin(DWORD),hcontact(HANDLE),nick(ASCIIZ),first(ASCIIZ),last(ASCIIZ),email(ASCIIZ),reason(ASCIIZ)
+ dbei.cbSize = sizeof(dbei);
+ dbei.cbBlob = CallService(MS_DB_EVENT_GETBLOBSIZE, (WPARAM)hDbEvent, 0);
+ dbei.pBlob = (PBYTE)alloca(dbei.cbBlob);
+ CallService(MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM)&dbei);
+
+ uin = *(PDWORD)dbei.pBlob;
+ hContact = *(HANDLE*)(dbei.pBlob + sizeof(DWORD));
+ nick = (char *)(dbei.pBlob + sizeof(DWORD) + sizeof(HANDLE));
+ first = nick + strlen(nick) + 1;
+ last = first + strlen(first) + 1;
+ email = last + strlen(last) + 1;
+ reason = email + strlen(email) + 1;
+
+ SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, CallProtoService(dbei.szModule, PS_LOADICON, PLI_PROTOCOL | PLIF_SMALL, 0));
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, CallProtoService(dbei.szModule, PS_LOADICON, PLI_PROTOCOL | PLIF_LARGE, 0));
+
+ PROTOACCOUNT* acc = Proto_GetAccount(dbei.szModule);
+
+ TCHAR* lastT = dbei.flags & DBEF_UTF ? Utf8DecodeT(last) : mir_a2t(last);
+ TCHAR* firstT = dbei.flags & DBEF_UTF ? Utf8DecodeT(first) : mir_a2t(first);
+ TCHAR* nickT = dbei.flags & DBEF_UTF ? Utf8DecodeT(nick) : mir_a2t(nick);
+ TCHAR* emailT = dbei.flags & DBEF_UTF ? Utf8DecodeT(email) : mir_a2t(email);
+ TCHAR* reasonT = dbei.flags & DBEF_UTF ? Utf8DecodeT(reason) : mir_a2t(reason);
+
+ TCHAR name[128] =_T("");
+ int off = 0;
+ if (firstT[0] && lastT[0])
+ off = mir_sntprintf(name, SIZEOF(name), _T("%s %s"), firstT, lastT);
+ else if (firstT[0])
+ off = mir_sntprintf(name, SIZEOF(name), _T("%s"), firstT);
+ else if (lastT[0])
+ off = mir_sntprintf(name, SIZEOF(name), _T("%s"), lastT);
+ if (nickT[0])
+ {
+ if (off)
+ mir_sntprintf(name + off, SIZEOF(name) - off, _T(" (%s)"), nickT);
+ else
+ mir_sntprintf(name, SIZEOF(name), _T("%s"), nickT);
+ }
+ if (!name[0])
+ _tcscpy(name, TranslateT("<Unknown>"));
+
+ TCHAR hdr[256];
+ if (uin && emailT[0])
+ mir_sntprintf(hdr, SIZEOF(hdr), TranslateT("%s requested authorization\n%u (%s) on %s"), name, uin, emailT, acc->tszAccountName);
+ else if (uin)
+ mir_sntprintf(hdr, SIZEOF(hdr), TranslateT("%s requested authorization\n%u on %s"), name, uin, acc->tszAccountName);
+ else
+ mir_sntprintf(hdr, SIZEOF(hdr), TranslateT("%s requested authorization\n%s on %s"), name, emailT[0] ? emailT : TranslateT("(Unknown)"), acc->tszAccountName);
+
+ SetDlgItemText(hwndDlg, IDC_HEADERBAR, hdr);
+ SetDlgItemText(hwndDlg, IDC_REASON, reasonT);
+
+ mir_free(lastT);
+ mir_free(firstT);
+ mir_free(nickT);
+ mir_free(emailT);
+ mir_free(reasonT);
+
+ if (hContact == INVALID_HANDLE_VALUE || !DBGetContactSettingByte(hContact, "CList", "NotOnList", 0))
+ ShowWindow(GetDlgItem(hwndDlg, IDC_ADD), FALSE);
+
+ SendDlgItemMessage(hwndDlg, IDC_DENYREASON, EM_LIMITTEXT, 255, 0);
+ if (CallProtoService(dbei.szModule, PS_GETCAPS,PFLAGNUM_4, 0) & PF4_NOAUTHDENYREASON)
+ {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_DENYREASON), FALSE);
+ SetDlgItemText(hwndDlg, IDC_DENYREASON, TranslateT("Feature is not supported by protocol"));
+ }
+ if (!DBGetContactSettingByte(hContact, "CList", "NotOnList", 0))
+ {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_ADDCHECK), FALSE);
+ CheckDlgButton(hwndDlg, IDC_ADDCHECK, BST_UNCHECKED);
+ }
+ else
+ CheckDlgButton(hwndDlg, IDC_ADDCHECK, BST_CHECKED);
+
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_DETAILS), GWLP_USERDATA, (LONG_PTR)hContact);
+ }
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDC_DETAILS:
+ CallService(MS_USERINFO_SHOWDIALOG, GetWindowLongPtr((HWND)lParam, GWLP_USERDATA), 0);
+ break;
+
+ case IDC_DECIDELATER:
+ DestroyWindow(hwndDlg);
+ break;
+
+ case IDOK:
+ {
+ DBEVENTINFO dbei = {0};
+ dbei.cbSize = sizeof(dbei);
+ CallService(MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM)&dbei);
+ CallProtoService(dbei.szModule, PS_AUTHALLOW, (WPARAM)hDbEvent,0);
+
+ if (IsDlgButtonChecked(hwndDlg, IDC_ADDCHECK))
+ {
+ ADDCONTACTSTRUCT acs = {0};
+ acs.handle = hDbEvent;
+ acs.handleType = HANDLE_EVENT;
+ acs.szProto = "";
+ CallService(MS_ADDCONTACT_SHOW, (WPARAM)hwndDlg, (LPARAM)&acs);
+ }
+ }
+ DestroyWindow(hwndDlg);
+ break;
+
+ case IDCANCEL:
+ {
+ DBEVENTINFO dbei = {0};
+ dbei.cbSize = sizeof(dbei);
+ CallService(MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM)&dbei);
+
+ if (IsWindowEnabled(GetDlgItem(hwndDlg, IDC_DENYREASON)))
+ {
+ TCHAR szReason[256];
+ GetDlgItemText(hwndDlg, IDC_DENYREASON, szReason, SIZEOF(szReason));
+ CallProtoService(dbei.szModule, PS_AUTHDENYT, (WPARAM)hDbEvent, (LPARAM)szReason);
+ }
+ else
+ CallProtoService(dbei.szModule, PS_AUTHDENYT, (WPARAM)hDbEvent, 0);
+ }
+ DestroyWindow(hwndDlg);
+ break;;
+ }
+ break;
+
+ case WM_DESTROY:
+ Button_FreeIcon_IcoLib(hwndDlg,IDC_ADD);
+ Button_FreeIcon_IcoLib(hwndDlg,IDC_DETAILS);
+ DestroyIcon((HICON)SendMessage(hwndDlg, WM_SETICON, ICON_BIG, 0));
+ DestroyIcon((HICON)SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, 0));
+ break;
+ }
+ return FALSE;
+}
diff --git a/src/modules/srawaymsg/awaymsg.cpp b/src/modules/srawaymsg/awaymsg.cpp
new file mode 100644
index 0000000000..39383e5367
--- /dev/null
+++ b/src/modules/srawaymsg/awaymsg.cpp
@@ -0,0 +1,194 @@
+/*
+
+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 LoadAwayMessageSending(void);
+
+static HANDLE hAwayMsgMenuItem;
+static HANDLE hWindowList;
+
+struct AwayMsgDlgData {
+ HANDLE hContact;
+ HANDLE hSeq;
+ HANDLE hAwayMsgEvent;
+};
+#define HM_AWAYMSG (WM_USER+10)
+static INT_PTR CALLBACK ReadAwayMsgDlgProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ AwayMsgDlgData *dat = (AwayMsgDlgData*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+
+ switch(message)
+ {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ dat = (AwayMsgDlgData*)mir_alloc(sizeof(AwayMsgDlgData));
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)dat);
+
+ dat->hContact = (HANDLE)lParam;
+ dat->hAwayMsgEvent = HookEventMessage(ME_PROTO_ACK, hwndDlg, HM_AWAYMSG);
+ dat->hSeq = (HANDLE)CallContactService(dat->hContact, PSS_GETAWAYMSG, 0, 0);
+ WindowList_Add(hWindowList, hwndDlg, dat->hContact);
+
+ {
+ TCHAR str[256], format[128];
+ TCHAR* contactName = cli.pfnGetContactDisplayName(dat->hContact, 0);
+ char* szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)dat->hContact, 0);
+ WORD dwStatus = DBGetContactSettingWord(dat->hContact, szProto, "Status", ID_STATUS_OFFLINE);
+ TCHAR* status = cli.pfnGetStatusModeDescription(dwStatus, 0);
+
+ GetWindowText(hwndDlg, format, SIZEOF(format));
+ mir_sntprintf(str, SIZEOF(str), format, status, contactName);
+ SetWindowText(hwndDlg, str);
+
+ GetDlgItemText(hwndDlg, IDC_RETRIEVING, format, SIZEOF(format));
+ mir_sntprintf(str, SIZEOF(str), format, status);
+ SetDlgItemText(hwndDlg, IDC_RETRIEVING, str);
+
+ Window_SetProtoIcon_IcoLib(hwndDlg, szProto, dwStatus);
+ }
+ if (dat->hSeq == NULL)
+ {
+ ACKDATA ack = {0};
+ ack.cbSize = sizeof(ack);
+ ack.hContact = dat->hContact;
+ ack.type = ACKTYPE_AWAYMSG;
+ ack.result = ACKRESULT_SUCCESS;
+ SendMessage(hwndDlg, HM_AWAYMSG, 0, (LPARAM)&ack);
+ }
+ Utils_RestoreWindowPosition(hwndDlg, (HANDLE)lParam, "SRAway", "AwayMsgDlg");
+ return TRUE;
+
+ case HM_AWAYMSG:
+ {
+ ACKDATA *ack = (ACKDATA*)lParam;
+ if (ack->hContact != dat->hContact || ack->type != ACKTYPE_AWAYMSG) break;
+ if (ack->result != ACKRESULT_SUCCESS) break;
+ if (dat->hAwayMsgEvent && ack->hProcess == dat->hSeq) { UnhookEvent(dat->hAwayMsgEvent); dat->hAwayMsgEvent = NULL; }
+
+#ifdef _UNICODE
+ DBVARIANT dbv;
+ bool unicode = !DBGetContactSetting(dat->hContact, "CList", "StatusMsg", &dbv) &&
+ (dbv.type == DBVT_UTF8 || dbv.type == DBVT_WCHAR);
+ DBFreeVariant(&dbv);
+ if (unicode)
+ {
+ DBGetContactSettingWString(dat->hContact, "CList", "StatusMsg", &dbv);
+ SetDlgItemText(hwndDlg, IDC_MSG, dbv.pwszVal);
+ }
+ else
+#endif
+ SetDlgItemTextA(hwndDlg, IDC_MSG, (const char*)ack->lParam);
+
+ ShowWindow(GetDlgItem(hwndDlg,IDC_RETRIEVING), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg,IDC_MSG), SW_SHOW);
+ SetDlgItemText(hwndDlg, IDOK, TranslateT("&Close"));
+ break;
+ }
+
+ case WM_COMMAND:
+ switch(LOWORD(wParam))
+ {
+ case IDCANCEL:
+ case IDOK:
+ DestroyWindow(hwndDlg);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ DestroyWindow(hwndDlg);
+ break;
+
+ case WM_DESTROY:
+ if (dat->hAwayMsgEvent) UnhookEvent(dat->hAwayMsgEvent);
+ Utils_SaveWindowPosition(hwndDlg,dat->hContact,"SRAway","AwayMsgDlg");
+ WindowList_Remove(hWindowList,hwndDlg);
+ Window_FreeIcon_IcoLib(hwndDlg);
+ mir_free(dat);
+ break;
+ }
+ return FALSE;
+}
+
+static INT_PTR GetMessageCommand(WPARAM wParam, LPARAM)
+{
+ HWND hwnd;
+ if(hwnd=WindowList_Find(hWindowList,(HANDLE)wParam)) {
+ SetForegroundWindow(hwnd);
+ SetFocus(hwnd);
+ }
+ else CreateDialogParam(hMirandaInst,MAKEINTRESOURCE(IDD_READAWAYMSG),NULL,ReadAwayMsgDlgProc,wParam);
+ return 0;
+}
+
+static int AwayMsgPreBuildMenu(WPARAM wParam, LPARAM)
+{
+ CLISTMENUITEM clmi;
+ TCHAR str[128];
+ char *szProto;
+
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,wParam,0);
+ ZeroMemory(&clmi,sizeof(clmi));
+ clmi.cbSize = sizeof(clmi);
+ clmi.flags = CMIM_FLAGS | CMIF_NOTOFFLINE | CMIF_HIDDEN | CMIF_TCHAR;
+
+ if ( szProto != NULL ) {
+ int chatRoom = szProto ? DBGetContactSettingByte((HANDLE)wParam, szProto, "ChatRoom", 0) : 0;
+ if ( !chatRoom ) {
+ int status = DBGetContactSettingWord((HANDLE)wParam,szProto,"Status",ID_STATUS_OFFLINE);
+ mir_sntprintf( str, SIZEOF(str), TranslateT("Re&ad %s Message"), cli.pfnGetStatusModeDescription( status, 0 ));
+ clmi.ptszName = str;
+ if ( CallProtoService( szProto, PS_GETCAPS, PFLAGNUM_1, 0 ) & PF1_MODEMSGRECV ) {
+ if ( CallProtoService( szProto, PS_GETCAPS, PFLAGNUM_3, 0 ) & Proto_Status2Flag( status )) {
+ clmi.flags = CMIM_FLAGS | CMIM_NAME | CMIF_NOTOFFLINE | CMIM_ICON | CMIF_TCHAR;
+ clmi.hIcon = LoadSkinProtoIcon(szProto, status);
+ } } } }
+
+ CallService( MS_CLIST_MODIFYMENUITEM, ( WPARAM )hAwayMsgMenuItem, ( LPARAM )&clmi );
+ IconLib_ReleaseIcon(clmi.hIcon,0);
+ return 0;
+}
+
+static int AwayMsgPreShutdown(WPARAM, LPARAM)
+{
+ if (hWindowList) WindowList_BroadcastAsync(hWindowList,WM_CLOSE,0,0);
+ return 0;
+}
+
+int LoadAwayMsgModule(void)
+{
+ CLISTMENUITEM mi = { 0 };
+
+ hWindowList = (HANDLE)CallService(MS_UTILS_ALLOCWINDOWLIST,0,0);
+ CreateServiceFunction(MS_AWAYMSG_SHOWAWAYMSG,GetMessageCommand);
+
+ mi.cbSize = sizeof(mi);
+ mi.position = -2000005000;
+ mi.flags = CMIF_NOTOFFLINE;
+ mi.pszName = LPGEN("Re&ad Status Message");
+ mi.pszService = MS_AWAYMSG_SHOWAWAYMSG;
+ hAwayMsgMenuItem = ( HANDLE )CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&mi);
+ HookEvent(ME_CLIST_PREBUILDCONTACTMENU,AwayMsgPreBuildMenu);
+ HookEvent(ME_SYSTEM_PRESHUTDOWN,AwayMsgPreShutdown);
+ return LoadAwayMessageSending();
+}
diff --git a/src/modules/srawaymsg/sendmsg.cpp b/src/modules/srawaymsg/sendmsg.cpp
new file mode 100644
index 0000000000..09cfcc77ad
--- /dev/null
+++ b/src/modules/srawaymsg/sendmsg.cpp
@@ -0,0 +1,637 @@
+/*
+
+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"
+
+extern bool prochotkey;
+
+static DWORD protoModeMsgFlags;
+static HWND hwndStatusMsg;
+
+static const TCHAR *GetDefaultMessage(int status)
+{
+ switch(status) {
+ case ID_STATUS_AWAY: return TranslateT("I've been away since %time%.");
+ case ID_STATUS_NA: return TranslateT("Give it up, I'm not in!");
+ case ID_STATUS_OCCUPIED: return TranslateT("Not right now.");
+ case ID_STATUS_DND: return TranslateT("Give a guy some peace, would ya?");
+ case ID_STATUS_FREECHAT: return TranslateT("I'm a chatbot!");
+ case ID_STATUS_ONLINE: return TranslateT("Yep, I'm here.");
+ case ID_STATUS_OFFLINE: return TranslateT("Nope, not here.");
+ case ID_STATUS_INVISIBLE: return TranslateT("I'm hiding from the mafia.");
+ case ID_STATUS_ONTHEPHONE: return TranslateT("That'll be the phone.");
+ case ID_STATUS_OUTTOLUNCH: return TranslateT("Mmm...food.");
+ case ID_STATUS_IDLE: return TranslateT("idleeeeeeee");
+ }
+ return NULL;
+}
+
+static const char *StatusModeToDbSetting(int status, const char *suffix)
+{
+ const char *prefix;
+ static char str[64];
+
+ switch(status)
+ {
+ case ID_STATUS_AWAY: prefix = "Away"; break;
+ case ID_STATUS_NA: prefix = "Na"; break;
+ case ID_STATUS_DND: prefix = "Dnd"; break;
+ case ID_STATUS_OCCUPIED: prefix = "Occupied"; break;
+ case ID_STATUS_FREECHAT: prefix = "FreeChat"; break;
+ case ID_STATUS_ONLINE: prefix = "On"; break;
+ case ID_STATUS_OFFLINE: prefix = "Off"; break;
+ case ID_STATUS_INVISIBLE: prefix = "Inv"; break;
+ case ID_STATUS_ONTHEPHONE: prefix = "Otp"; break;
+ case ID_STATUS_OUTTOLUNCH: prefix = "Otl"; break;
+ case ID_STATUS_IDLE: prefix = "Idl"; break;
+ default: return NULL;
+ }
+ mir_snprintf(str, SIZEOF(str), "%s%s", prefix, suffix);
+ return str;
+}
+
+static TCHAR* GetAwayMessage(int statusMode, char *szProto)
+{
+ DBVARIANT dbv;
+
+ if (szProto && !(CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_3, 0) & Proto_Status2Flag(statusMode)))
+ return NULL;
+
+ if (DBGetContactSettingByte(NULL, "SRAway", StatusModeToDbSetting(statusMode, "Ignore"), 0))
+ return NULL;
+
+ if (DBGetContactSettingByte(NULL, "SRAway", StatusModeToDbSetting(statusMode, "UsePrev"),0))
+ {
+ if (DBGetContactSettingTString(NULL, "SRAway", StatusModeToDbSetting(statusMode, "Msg"), &dbv))
+ dbv.ptszVal = mir_tstrdup(GetDefaultMessage(statusMode));
+ }
+ else {
+ int i;
+ TCHAR substituteStr[128];
+ if (DBGetContactSettingTString(NULL, "SRAway", StatusModeToDbSetting(statusMode,"Default"), &dbv))
+ dbv.ptszVal = mir_tstrdup(GetDefaultMessage(statusMode));
+
+ for (i=0; dbv.ptszVal[i]; i++)
+ {
+ if (dbv.ptszVal[i] != '%') continue;
+ if (!_tcsnicmp(dbv.ptszVal + i, _T("%time%"), 6))
+ {
+ MIRANDA_IDLE_INFO mii = {0};
+ mii.cbSize = sizeof(mii);
+ CallService(MS_IDLE_GETIDLEINFO, 0, (LPARAM)&mii);
+
+ if (mii.idleType == 1)
+ {
+ int mm;
+ SYSTEMTIME t;
+ GetLocalTime(&t);
+ mm = t.wMinute + t.wHour * 60 - mii.idleTime;
+ if (mm < 0) mm += 60 * 24;
+ t.wMinute = mm % 60;
+ t.wHour = mm / 60;
+ GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &t, NULL, substituteStr, SIZEOF(substituteStr));
+ }
+ else GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, NULL, NULL, substituteStr, SIZEOF(substituteStr));
+ }
+ else if (!_tcsnicmp(dbv.ptszVal + i, _T("%date%"), 6))
+ GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, NULL, NULL, substituteStr, SIZEOF(substituteStr));
+ else continue;
+ if (lstrlen(substituteStr) > 6)
+ dbv.ptszVal = (TCHAR*)mir_realloc(dbv.ptszVal, (lstrlen(dbv.ptszVal) + 1 + lstrlen(substituteStr) - 6) * sizeof(TCHAR));
+ MoveMemory(dbv.ptszVal + i + lstrlen(substituteStr), dbv.ptszVal + i + 6, (lstrlen(dbv.ptszVal) - i - 5) * sizeof(TCHAR));
+ CopyMemory(dbv.ptszVal+i, substituteStr, lstrlen(substituteStr) * sizeof(TCHAR));
+ }
+ }
+ return dbv.ptszVal;
+}
+
+static WNDPROC OldMessageEditProc;
+
+static LRESULT CALLBACK MessageEditSubclassProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
+{
+ switch(msg)
+ {
+ case WM_CHAR:
+ if(wParam == '\n' && GetKeyState(VK_CONTROL) & 0x8000)
+ {
+ PostMessage(GetParent(hwnd), WM_COMMAND, IDOK, 0);
+ return 0;
+ }
+ if (wParam == 1 && GetKeyState(VK_CONTROL) & 0x8000) //ctrl-a
+ {
+ SendMessage(hwnd, EM_SETSEL, 0, -1);
+ return 0;
+ }
+ if (wParam == 23 && GetKeyState(VK_CONTROL) & 0x8000) // ctrl-w
+ {
+ SendMessage(GetParent(hwnd), WM_CLOSE, 0, 0);
+ return 0;
+ }
+ if (wParam == 127 && GetKeyState(VK_CONTROL) & 0x8000) //ctrl-backspace
+ {
+ DWORD start, end;
+ TCHAR *text;
+ int textLen;
+ SendMessage(hwnd, EM_GETSEL, (WPARAM)&end, 0);
+ SendMessage(hwnd, WM_KEYDOWN, VK_LEFT, 0);
+ SendMessage(hwnd, EM_GETSEL, (WPARAM)&start, 0);
+ textLen = GetWindowTextLength(hwnd);
+ text = (TCHAR *)alloca(sizeof(TCHAR) * (textLen + 1));
+ GetWindowText(hwnd, text, textLen + 1);
+ memmove(text + start, text + end, sizeof(TCHAR) * (textLen + 1 - end));
+ SetWindowText(hwnd, text);
+ SendMessage(hwnd, EM_SETSEL, start, start);
+ SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hwnd), EN_CHANGE), (LPARAM)hwnd);
+ return 0;
+ }
+ break;
+ }
+ return CallWindowProc(OldMessageEditProc, hwnd, msg, wParam, lParam);
+}
+
+void ChangeAllProtoMessages(char *szProto, int statusMode, TCHAR *msg)
+{
+ if (szProto == NULL)
+ {
+ for (int i=0; i < accounts.getCount(); i++)
+ {
+ PROTOACCOUNT* pa = accounts[i];
+ if (!Proto_IsAccountEnabled(pa)) continue;
+ if ((CallProtoService(pa->szModuleName, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_MODEMSGSEND) &&
+ !Proto_IsAccountLocked(pa))
+ CallProtoService(pa->szModuleName, PS_SETAWAYMSGT, statusMode, (LPARAM)msg);
+ }
+ }
+ else
+ CallProtoService(szProto, PS_SETAWAYMSGT, statusMode,(LPARAM)msg);
+}
+
+struct SetAwayMsgData
+{
+ int statusMode;
+ int countdown;
+ TCHAR okButtonFormat[64];
+ char *szProto;
+ HANDLE hPreshutdown;
+};
+struct SetAwasMsgNewData
+{
+ char *szProto;
+ int statusMode;
+};
+
+#define DM_SRAWAY_SHUTDOWN WM_USER+10
+
+static INT_PTR CALLBACK SetAwayMsgDlgProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ SetAwayMsgData* dat = (SetAwayMsgData*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+
+ switch(message)
+ {
+ case WM_INITDIALOG:
+ {
+ SetAwasMsgNewData *newdat = (SetAwasMsgNewData*)lParam;
+ TranslateDialogDefault(hwndDlg);
+ dat = (SetAwayMsgData*)mir_alloc(sizeof(SetAwayMsgData));
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)dat);
+ dat->statusMode = newdat->statusMode;
+ dat->szProto = newdat->szProto;
+ mir_free(newdat);
+ SendDlgItemMessage(hwndDlg, IDC_MSG, EM_LIMITTEXT, 1024, 0);
+ OldMessageEditProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_MSG), GWLP_WNDPROC, (LONG_PTR)MessageEditSubclassProc);
+ {
+ TCHAR str[256], format[128];
+ GetWindowText(hwndDlg, format, SIZEOF(format));
+ mir_sntprintf(str, SIZEOF(str), format, cli.pfnGetStatusModeDescription(dat->statusMode, 0));
+ SetWindowText(hwndDlg, str );
+ }
+ GetDlgItemText(hwndDlg, IDOK, dat->okButtonFormat, SIZEOF(dat->okButtonFormat));
+ {
+ TCHAR *msg = GetAwayMessage(dat->statusMode, dat->szProto);
+ SetDlgItemText(hwndDlg, IDC_MSG, msg);
+ mir_free(msg);
+ }
+ dat->countdown = 6;
+ SendMessage(hwndDlg, WM_TIMER, 0, 0);
+ Window_SetProtoIcon_IcoLib(hwndDlg, dat->szProto, dat->statusMode);
+ Utils_RestoreWindowPosition(hwndDlg,NULL,"SRAway","AwayMsgDlg");
+ SetTimer(hwndDlg, 1, 1000, 0);
+ dat->hPreshutdown = HookEventMessage(ME_SYSTEM_PRESHUTDOWN, hwndDlg, DM_SRAWAY_SHUTDOWN);
+ }
+ return TRUE;
+
+ case WM_TIMER:
+ if (--dat->countdown >= 0)
+ {
+ TCHAR str[64];
+ mir_sntprintf(str, SIZEOF(str), dat->okButtonFormat, dat->countdown);
+ SetDlgItemText(hwndDlg, IDOK, str);
+ }
+ else
+ {
+ KillTimer(hwndDlg, 1);
+ PostMessage(hwndDlg, WM_CLOSE, 0, 0);
+ }
+ break;
+
+ case WM_CLOSE:
+ {
+ TCHAR *msg = GetAwayMessage(dat->statusMode, dat->szProto);
+ ChangeAllProtoMessages(dat->szProto, dat->statusMode, msg);
+ mir_free(msg);
+ }
+ DestroyWindow(hwndDlg);
+ break;
+
+ case WM_COMMAND:
+ switch(LOWORD(wParam))
+ {
+ case IDOK:
+ if (dat->countdown < 0)
+ {
+ TCHAR str[1024];
+ GetDlgItemText(hwndDlg, IDC_MSG, str, SIZEOF(str));
+ ChangeAllProtoMessages(dat->szProto, dat->statusMode, str);
+ DBWriteContactSettingTString(NULL, "SRAway", StatusModeToDbSetting(dat->statusMode, "Msg"), str);
+ DestroyWindow(hwndDlg);
+ }
+ else
+ PostMessage(hwndDlg, WM_CLOSE, 0, 0);
+ break;
+
+ case IDC_MSG:
+ if (dat->countdown >= 0)
+ {
+ KillTimer(hwndDlg, 1);
+ SetDlgItemText(hwndDlg, IDOK, TranslateT("OK"));
+ dat->countdown = -1;
+ }
+ break;
+ }
+ break;
+
+ case DM_SRAWAY_SHUTDOWN:
+ DestroyWindow(hwndDlg);
+ break;
+
+ case WM_DESTROY:
+ Utils_SaveWindowPosition(hwndDlg,NULL,"SRAway","AwayMsgDlg");
+ KillTimer(hwndDlg, 1);
+ UnhookEvent(dat->hPreshutdown);
+ Window_FreeIcon_IcoLib(hwndDlg);
+ SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_MSG), GWLP_WNDPROC, (LONG_PTR)OldMessageEditProc);
+ mir_free(dat);
+ hwndStatusMsg = NULL;
+ break;
+ }
+ return FALSE;
+}
+
+static int StatusModeChange(WPARAM wParam, LPARAM lParam)
+{
+ BOOL bScreenSaverRunning = FALSE;
+ int statusMode = (int)wParam;
+ char *szProto = (char*)lParam;
+
+ if (protoModeMsgFlags == 0) return 0;
+
+ // If its a global change check the complete PFLAGNUM_3 flags to see if a popup might be needed
+ if (!szProto)
+ {
+ if (!(protoModeMsgFlags & Proto_Status2Flag(statusMode)))
+ return 0;
+ }
+ else
+ {
+ // If its a single protocol check the PFLAGNUM_3 for the single protocol
+ if (!(CallProtoService(szProto, PS_GETCAPS,PFLAGNUM_1, 0) & PF1_MODEMSGSEND) ||
+ !(CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_3, 0) & Proto_Status2Flag(statusMode)))
+ return 0;
+ }
+
+ SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &bScreenSaverRunning, FALSE);
+ if (DBGetContactSettingByte(NULL, "SRAway", StatusModeToDbSetting(statusMode, "Ignore"), 0))
+ {
+ ChangeAllProtoMessages(szProto, statusMode, NULL);
+ }
+ else if (bScreenSaverRunning || ((!GetAsyncKeyState(VK_CONTROL) || prochotkey) &&
+ DBGetContactSettingByte(NULL, "SRAway", StatusModeToDbSetting(statusMode, "NoDlg"), 0)))
+ {
+ TCHAR *msg = GetAwayMessage(statusMode, szProto);
+ ChangeAllProtoMessages(szProto, statusMode, msg);
+ mir_free(msg);
+ }
+ else {
+ SetAwasMsgNewData *newdat = (SetAwasMsgNewData*)mir_alloc(sizeof(SetAwasMsgNewData));
+ newdat->szProto = szProto;
+ newdat->statusMode = statusMode;
+ if (hwndStatusMsg)
+ DestroyWindow(hwndStatusMsg);
+ hwndStatusMsg = CreateDialogParam(hMirandaInst, MAKEINTRESOURCE(IDD_SETAWAYMSG),
+ NULL, SetAwayMsgDlgProc, (LPARAM)newdat);
+ }
+ return 0;
+}
+
+static const int statusModes[] =
+{
+ ID_STATUS_OFFLINE, ID_STATUS_ONLINE, ID_STATUS_AWAY, ID_STATUS_NA, ID_STATUS_OCCUPIED, ID_STATUS_DND,
+ ID_STATUS_FREECHAT,ID_STATUS_INVISIBLE,ID_STATUS_OUTTOLUNCH,ID_STATUS_ONTHEPHONE, ID_STATUS_IDLE
+};
+
+struct AwayMsgInfo
+{
+ int ignore;
+ int noDialog;
+ int usePrevious;
+ TCHAR msg[1024];
+};
+struct AwayMsgDlgData
+{
+ struct AwayMsgInfo info[ SIZEOF(statusModes) ];
+ int oldPage;
+};
+
+static INT_PTR CALLBACK DlgProcAwayMsgOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct AwayMsgDlgData *dat;
+
+ HWND hLst = GetDlgItem(hwndDlg, IDC_LST_STATUS);
+
+ dat=(struct AwayMsgDlgData*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA);
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ TranslateDialogDefault(hwndDlg);
+ dat = (AwayMsgDlgData*)mir_alloc(sizeof(AwayMsgDlgData));
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)dat);
+ dat->oldPage = -1;
+ for (int i = 0; i < SIZEOF(statusModes); i++)
+ {
+ int j;
+ if (!(protoModeMsgFlags & Proto_Status2Flag(statusModes[i])))
+ continue;
+
+ if (hLst)
+ {
+ j = SendDlgItemMessage(hwndDlg, IDC_LST_STATUS, LB_ADDSTRING, 0, (LPARAM)cli.pfnGetStatusModeDescription(statusModes[i], 0));
+ SendDlgItemMessage(hwndDlg, IDC_LST_STATUS, LB_SETITEMDATA, j, statusModes[i]);
+ }
+ else
+ {
+ j = SendDlgItemMessage(hwndDlg, IDC_STATUS, CB_ADDSTRING, 0, (LPARAM)cli.pfnGetStatusModeDescription(statusModes[i], 0));
+ SendDlgItemMessage(hwndDlg, IDC_STATUS, CB_SETITEMDATA, j, statusModes[i]);
+ }
+
+ dat->info[j].ignore = DBGetContactSettingByte(NULL, "SRAway",
+ StatusModeToDbSetting(statusModes[i], "Ignore"), 0);
+ dat->info[j].noDialog = DBGetContactSettingByte(NULL, "SRAway",
+ StatusModeToDbSetting(statusModes[i], "NoDlg"), 0);
+ dat->info[j].usePrevious = DBGetContactSettingByte(NULL, "SRAway",
+ StatusModeToDbSetting(statusModes[i], "UsePrev"), 0);
+
+ DBVARIANT dbv;
+ if (DBGetContactSettingTString(NULL, "SRAway", StatusModeToDbSetting(statusModes[i], "Default"), &dbv))
+ if (DBGetContactSettingTString(NULL, "SRAway", StatusModeToDbSetting(statusModes[i], "Msg"), &dbv))
+ dbv.ptszVal = mir_tstrdup(GetDefaultMessage(statusModes[i]));
+ lstrcpy(dat->info[j].msg, dbv.ptszVal);
+ mir_free(dbv.ptszVal);
+ }
+ if (hLst)
+ SendDlgItemMessage(hwndDlg, IDC_LST_STATUS, LB_SETCURSEL, 0, 0);
+ else
+ SendDlgItemMessage(hwndDlg, IDC_STATUS, CB_SETCURSEL, 0, 0);
+ SendMessage(hwndDlg, WM_COMMAND, hLst ? MAKEWPARAM(IDC_LST_STATUS, LBN_SELCHANGE) : MAKEWPARAM(IDC_STATUS, CBN_SELCHANGE), 0);
+ return TRUE;
+ }
+ case WM_MEASUREITEM:
+ {
+ LPMEASUREITEMSTRUCT mis = (LPMEASUREITEMSTRUCT)lParam;
+ if (mis->CtlID == IDC_LST_STATUS)
+ mis->itemHeight = 20;
+ break;
+ }
+ case WM_DRAWITEM:
+ {
+ LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT)lParam;
+ if (dis->CtlID != IDC_LST_STATUS) break;
+ if (dis->itemID < 0) break;
+
+ TCHAR buf[128];
+ SendDlgItemMessage(hwndDlg, IDC_LST_STATUS, LB_GETTEXT, dis->itemID, (LPARAM)buf);
+
+ if (dis->itemState & (ODS_SELECTED|ODS_FOCUS))
+ {
+ FillRect(dis->hDC, &dis->rcItem, GetSysColorBrush(COLOR_HIGHLIGHT));
+ SetTextColor(dis->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
+ }
+ else
+ {
+ FillRect(dis->hDC, &dis->rcItem, GetSysColorBrush(COLOR_WINDOW));
+ SetTextColor(dis->hDC, GetSysColor(COLOR_WINDOWTEXT));
+ }
+
+ RECT rc = dis->rcItem;
+ DrawIconEx(dis->hDC, 3, (rc.top + rc.bottom - 16) / 2, LoadSkinnedProtoIcon(NULL, dis->itemData), 16, 16, 0, NULL, DI_NORMAL);
+ rc.left += 25;
+ SetBkMode(dis->hDC, TRANSPARENT);
+ DrawText(dis->hDC, buf, -1, &rc, DT_LEFT | DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX);
+ break;
+ }
+ case WM_COMMAND:
+ switch(LOWORD(wParam))
+ {
+ case IDC_LST_STATUS:
+ case IDC_STATUS:
+ if ((HIWORD(wParam) == CBN_SELCHANGE) || (HIWORD(wParam) == LBN_SELCHANGE))
+ {
+ int i = hLst ?
+ SendDlgItemMessage(hwndDlg, IDC_LST_STATUS, LB_GETCURSEL, 0, 0) :
+ SendDlgItemMessage(hwndDlg, IDC_STATUS, CB_GETCURSEL, 0, 0);
+ if (dat->oldPage != -1)
+ {
+ dat->info[dat->oldPage].ignore = IsDlgButtonChecked(hwndDlg, IDC_DONTREPLY);
+ dat->info[dat->oldPage].noDialog = IsDlgButtonChecked(hwndDlg, IDC_NODIALOG);
+ dat->info[dat->oldPage].usePrevious = IsDlgButtonChecked(hwndDlg, IDC_USEPREVIOUS);
+ GetDlgItemText(hwndDlg, IDC_MSG, dat->info[dat->oldPage].msg, SIZEOF(dat->info[dat->oldPage].msg));
+ }
+ CheckDlgButton(hwndDlg, IDC_DONTREPLY, i < 0 ? 0 : dat->info[i].ignore);
+ CheckDlgButton(hwndDlg, IDC_NODIALOG, i < 0 ? 0 : dat->info[i].noDialog);
+ CheckDlgButton(hwndDlg, IDC_USEPREVIOUS, i < 0 ? 0 : dat->info[i].usePrevious);
+ CheckDlgButton(hwndDlg, IDC_USESPECIFIC, i < 0 ? 0 : !dat->info[i].usePrevious);
+
+ SetDlgItemText(hwndDlg,IDC_MSG, i < 0 ? _T("") : dat->info[i].msg);
+
+ EnableWindow(GetDlgItem(hwndDlg, IDC_NODIALOG), i < 0 ? 0 : !dat->info[i].ignore);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_USEPREVIOUS), i < 0 ? 0 : !dat->info[i].ignore);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_USESPECIFIC), i < 0 ? 0 : !dat->info[i].ignore);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_MSG), i < 0 ? 0 : !(dat->info[i].ignore || dat->info[i].usePrevious));
+ dat->oldPage = i;
+ }
+ return 0;
+
+ case IDC_DONTREPLY:
+ case IDC_USEPREVIOUS:
+ case IDC_USESPECIFIC:
+ SendMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_STATUS,CBN_SELCHANGE),0);
+ break;
+
+ case IDC_MSG:
+ if (HIWORD(wParam) != EN_CHANGE || (HWND)lParam != GetFocus()) return 0;
+ break;
+ }
+ 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, status;
+ SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_STATUS,CBN_SELCHANGE), 0);
+ i = hLst ?
+ (SendDlgItemMessage(hwndDlg, IDC_LST_STATUS, LB_GETCOUNT, 0, 0) - 1) :
+ (SendDlgItemMessage(hwndDlg, IDC_STATUS, CB_GETCOUNT, 0, 0) - 1);
+ for (; i>=0; i--)
+ {
+ status = hLst ?
+ SendDlgItemMessage(hwndDlg, IDC_LST_STATUS, LB_GETITEMDATA, i, 0):
+ SendDlgItemMessage(hwndDlg, IDC_STATUS, CB_GETITEMDATA, i, 0);
+ DBWriteContactSettingByte(NULL, "SRAway", StatusModeToDbSetting(status,"Ignore"), (BYTE)dat->info[i].ignore);
+ DBWriteContactSettingByte(NULL, "SRAway", StatusModeToDbSetting(status,"NoDlg"), (BYTE)dat->info[i].noDialog);
+ DBWriteContactSettingByte(NULL, "SRAway", StatusModeToDbSetting(status,"UsePrev"),(BYTE)dat->info[i].usePrevious);
+ DBWriteContactSettingTString(NULL, "SRAway", StatusModeToDbSetting(status,"Default"), dat->info[i].msg);
+ }
+ return TRUE;
+ }
+ }
+ break;
+ }
+ break;
+
+ case WM_DESTROY:
+ mir_free(dat);
+ break;
+ }
+ return FALSE;
+}
+
+static int AwayMsgOptInitialise(WPARAM wParam, LPARAM)
+{
+ if (protoModeMsgFlags == 0)
+ return 0;
+
+ OPTIONSDIALOGPAGE odp = { 0 };
+ odp.cbSize = sizeof(odp);
+ odp.position = 870000000;
+ odp.hInstance = hMirandaInst;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_AWAYMSG);
+ odp.pszTitle = LPGEN("Status Messages");
+ odp.pszGroup = LPGEN("Status");
+ odp.pfnDlgProc = DlgProcAwayMsgOpts;
+ odp.flags = ODPF_BOLDGROUPS;
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM)&odp);
+ return 0;
+}
+
+static int AwayMsgSendModernOptInit(WPARAM wParam, LPARAM)
+{
+ if (protoModeMsgFlags == 0)
+ return 0;
+
+ static const int iBoldControls[] =
+ {
+ IDC_TXT_TITLE1, IDC_TXT_TITLE2, IDC_TXT_TITLE3,
+ MODERNOPT_CTRL_LAST
+ };
+
+ MODERNOPTOBJECT obj = {0};
+ obj.cbSize = sizeof(obj);
+ obj.hInstance = hMirandaInst;
+ obj.dwFlags = MODEROPT_FLG_TCHAR | MODEROPT_FLG_NORESIZE;
+ obj.iSection = MODERNOPT_PAGE_STATUS;
+ obj.iType = MODERNOPT_TYPE_SECTIONPAGE;
+ obj.iBoldControls = (int*)iBoldControls;
+ obj.lpzTemplate = MAKEINTRESOURCEA(IDD_MODERNOPT_STATUS);
+ obj.pfnDlgProc = DlgProcAwayMsgOpts;
+// obj.lpzClassicGroup = "Status";
+// obj.lpzClassicPage = "Messages";
+ obj.lpzHelpUrl = "http://wiki.miranda-im.org/";
+ CallService(MS_MODERNOPT_ADDOBJECT, wParam, (LPARAM)&obj);
+ return 0;
+}
+
+static int AwayMsgSendAccountsChanged(WPARAM, LPARAM)
+{
+ protoModeMsgFlags = 0;
+ for (int i=0; i < accounts.getCount(); i++)
+ {
+ if (!Proto_IsAccountEnabled(accounts[i])) continue;
+ protoModeMsgFlags |= CallProtoService(accounts[i]->szModuleName, PS_GETCAPS, PFLAGNUM_3, 0);
+ }
+
+ return 0;
+}
+
+static int AwayMsgSendModulesLoaded(WPARAM, LPARAM)
+{
+ AwayMsgSendAccountsChanged(0, 0);
+
+ HookEvent(ME_CLIST_STATUSMODECHANGE, StatusModeChange);
+ HookEvent(ME_MODERNOPT_INITIALIZE, AwayMsgSendModernOptInit);
+ HookEvent(ME_OPT_INITIALISE, AwayMsgOptInitialise);
+ return 0;
+}
+
+//remember to mir_free() the return value
+static INT_PTR sttGetAwayMessageT(WPARAM wParam, LPARAM lParam)
+{
+ return (INT_PTR)GetAwayMessage((int)wParam, (char*)lParam);
+}
+
+#ifdef UNICODE
+static INT_PTR sttGetAwayMessage(WPARAM wParam, LPARAM lParam)
+{
+ TCHAR* msg = GetAwayMessage((int)wParam, (char*)lParam);
+ char* res = mir_t2a(msg);
+ mir_free(msg);
+ return (INT_PTR)res;
+}
+#endif
+
+int LoadAwayMessageSending(void)
+{
+ HookEvent(ME_SYSTEM_MODULESLOADED,AwayMsgSendModulesLoaded);
+ HookEvent(ME_PROTO_ACCLISTCHANGED, AwayMsgSendAccountsChanged);
+
+#ifdef UNICODE
+ CreateServiceFunction(MS_AWAYMSG_GETSTATUSMSG, sttGetAwayMessage);
+ CreateServiceFunction(MS_AWAYMSG_GETSTATUSMSGW, sttGetAwayMessageT);
+#else
+ CreateServiceFunction(MS_AWAYMSG_GETSTATUSMSG, sttGetAwayMessageT);
+#endif
+ return 0;
+}
diff --git a/src/modules/sremail/email.cpp b/src/modules/sremail/email.cpp
new file mode 100644
index 0000000000..251963a406
--- /dev/null
+++ b/src/modules/sremail/email.cpp
@@ -0,0 +1,89 @@
+/*
+
+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"
+
+static HANDLE hEMailMenuItem;
+
+void SendEmailThread(void *szUrl)
+{
+ ShellExecuteA(NULL,"open",( char* )szUrl,"","",SW_SHOW);
+ mir_free(szUrl);
+ return;
+}
+
+static INT_PTR SendEMailCommand(WPARAM wParam,LPARAM lParam)
+{
+ DBVARIANT dbv;
+ char *szUrl;
+ char *szProto;
+
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,wParam,0);
+ if(szProto==NULL || DBGetContactSettingString((HANDLE)wParam,szProto,"e-mail",&dbv)) {
+ if(DBGetContactSettingString((HANDLE)wParam,"UserInfo","Mye-mail0",&dbv)) {
+ MessageBox((HWND)lParam,TranslateT("User has not registered an e-mail address"),TranslateT("Send e-mail"),MB_OK);
+ return 1;
+ }
+ }
+ szUrl=(char*)mir_alloc(lstrlenA(dbv.pszVal)+8);
+ lstrcpyA(szUrl,"mailto:");
+ lstrcatA(szUrl,dbv.pszVal);
+ mir_free(dbv.pszVal);
+ forkthread(SendEmailThread,0,szUrl);
+ return 0;
+}
+
+static int EMailPreBuildMenu(WPARAM wParam, LPARAM)
+{
+ CLISTMENUITEM mi;
+ DBVARIANT dbv = { 0 };
+ char *szProto;
+
+ ZeroMemory(&mi,sizeof(mi));
+ mi.cbSize = sizeof(mi);
+ mi.flags = CMIM_FLAGS;
+
+ szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ if (szProto == NULL || DBGetContactSettingString((HANDLE)wParam, szProto, "e-mail",& dbv))
+ if (DBGetContactSettingString((HANDLE)wParam, "UserInfo", "Mye-mail0", &dbv))
+ mi.flags = CMIM_FLAGS | CMIF_HIDDEN;
+
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hEMailMenuItem, (LPARAM)&mi);
+ if (dbv.pszVal) DBFreeVariant(&dbv);
+ return 0;
+}
+
+int LoadSendRecvEMailModule(void)
+{
+ CLISTMENUITEM mi = { 0 };
+ mi.cbSize = sizeof(mi);
+ mi.position = -2000010000;
+ mi.flags = CMIF_ICONFROMICOLIB;
+ mi.icolibItem = GetSkinIconHandle( SKINICON_OTHER_SENDEMAIL );
+ mi.pszName = LPGEN("&E-mail");
+ mi.pszService = MS_EMAIL_SENDEMAIL;
+ hEMailMenuItem = (HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM)&mi);
+
+ CreateServiceFunction(MS_EMAIL_SENDEMAIL, SendEMailCommand);
+ HookEvent(ME_CLIST_PREBUILDCONTACTMENU, EMailPreBuildMenu);
+ return 0;
+}
diff --git a/src/modules/srfile/file.cpp b/src/modules/srfile/file.cpp
new file mode 100644
index 0000000000..85eb99a7bc
--- /dev/null
+++ b/src/modules/srfile/file.cpp
@@ -0,0 +1,392 @@
+/*
+
+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 "file.h"
+
+TCHAR* PFTS_StringToTchar( int flags, const PROTOCHAR* s );
+int PFTS_CompareWithTchar( PROTOFILETRANSFERSTATUS* ft, const PROTOCHAR* s, TCHAR* r );
+
+static HANDLE hSRFileMenuItem;
+
+static INT_PTR SendFileCommand(WPARAM wParam, LPARAM)
+{
+ struct FileSendData fsd;
+ fsd.hContact=(HANDLE)wParam;
+ fsd.ppFiles=NULL;
+ CreateDialogParam(hMirandaInst,MAKEINTRESOURCE(IDD_FILESEND),NULL,DlgProcSendFile,(LPARAM)&fsd);
+ return 0;
+}
+
+static INT_PTR SendSpecificFiles(WPARAM wParam,LPARAM lParam)
+{
+ FileSendData fsd;
+ fsd.hContact=(HANDLE)wParam;
+ #if defined( _UNICODE )
+ char** ppFiles = ( char** )lParam;
+ int count = 0;
+ while ( ppFiles[count] != NULL )
+ count++;
+
+ fsd.ppFiles = (const TCHAR**)alloca(( count+1 ) * sizeof( void* ));
+ for ( int i=0; i < count; i++ )
+ fsd.ppFiles[i] = ( const TCHAR* )mir_a2t( ppFiles[i] );
+ fsd.ppFiles[ count ] = NULL;
+ #else
+ fsd.ppFiles=(const char**)lParam;
+ #endif
+ CreateDialogParam(hMirandaInst,MAKEINTRESOURCE(IDD_FILESEND),NULL,DlgProcSendFile,(LPARAM)&fsd);
+ #if defined( _UNICODE )
+ for ( int j=0; j < count; j++ )
+ mir_free(( void* )fsd.ppFiles[j] );
+ #endif
+ return 0;
+}
+
+static INT_PTR SendSpecificFilesT(WPARAM wParam,LPARAM lParam)
+{
+ FileSendData fsd;
+ fsd.hContact=(HANDLE)wParam;
+ fsd.ppFiles=(const TCHAR**)lParam;
+ CreateDialogParam(hMirandaInst,MAKEINTRESOURCE(IDD_FILESEND),NULL,DlgProcSendFile,(LPARAM)&fsd);
+ return 0;
+}
+
+static INT_PTR GetReceivedFilesFolder(WPARAM wParam,LPARAM lParam)
+{
+ TCHAR buf[MAX_PATH];
+ GetContactReceivedFilesDir((HANDLE)wParam,buf,MAX_PATH,TRUE);
+ char* dir = mir_t2a(buf);
+ lstrcpynA((char*)lParam,dir,MAX_PATH);
+ mir_free(dir);
+ return 0;
+}
+
+static INT_PTR RecvFileCommand(WPARAM, LPARAM lParam)
+{
+ CreateDialogParam(hMirandaInst,MAKEINTRESOURCE(IDD_FILERECV),NULL,DlgProcRecvFile,lParam);
+ return 0;
+}
+
+void PushFileEvent( HANDLE hContact, HANDLE hdbe, LPARAM lParam )
+{
+ CLISTEVENT cle={0};
+ cle.cbSize = sizeof(cle);
+ cle.hContact = hContact;
+ cle.hDbEvent = hdbe;
+ cle.lParam = lParam;
+ if ( DBGetContactSettingByte(NULL,"SRFile","AutoAccept",0) && !DBGetContactSettingByte(hContact,"CList","NotOnList",0)) {
+ CreateDialogParam(hMirandaInst,MAKEINTRESOURCE(IDD_FILERECV),NULL,DlgProcRecvFile,(LPARAM)&cle);
+ }
+ else {
+ SkinPlaySound("RecvFile");
+
+ TCHAR szTooltip[256];
+ mir_sntprintf(szTooltip,SIZEOF(szTooltip),TranslateT("File from %s"), cli.pfnGetContactDisplayName( hContact, 0 ));
+ cle.ptszTooltip = szTooltip;
+
+ cle.flags |= CLEF_TCHAR;
+ cle.hIcon = LoadSkinIcon( SKINICON_EVENT_FILE );
+ cle.pszService = "SRFile/RecvFile";
+ CallService(MS_CLIST_ADDEVENT,0,(LPARAM)&cle);
+} }
+
+static int FileEventAdded(WPARAM wParam,LPARAM lParam)
+{
+ DWORD dwSignature;
+
+ DBEVENTINFO dbei={0};
+ dbei.cbSize = sizeof(dbei);
+ dbei.cbBlob = sizeof( DWORD );
+ dbei.pBlob = ( PBYTE )&dwSignature;
+ CallService( MS_DB_EVENT_GET, lParam, ( LPARAM )&dbei );
+ if ( dbei.flags&(DBEF_SENT|DBEF_READ) || dbei.eventType != EVENTTYPE_FILE || dwSignature == 0 )
+ return 0;
+
+ PushFileEvent(( HANDLE )wParam, ( HANDLE )lParam, 0 );
+ return 0;
+}
+
+int SRFile_GetRegValue(HKEY hKeyBase,const TCHAR *szSubKey,const TCHAR *szValue,TCHAR *szOutput,int cbOutput)
+{
+ HKEY hKey;
+ DWORD cbOut=cbOutput;
+
+ if ( RegOpenKeyEx( hKeyBase,szSubKey,0,KEY_QUERY_VALUE,&hKey ) != ERROR_SUCCESS)
+ return 0;
+
+ if ( RegQueryValueEx( hKey,szValue,NULL,NULL,(PBYTE)szOutput, &cbOut ) != ERROR_SUCCESS ) {
+ RegCloseKey(hKey);
+ return 0;
+ }
+
+ RegCloseKey(hKey);
+ return 1;
+}
+
+void GetSensiblyFormattedSize(__int64 size,TCHAR *szOut,int cchOut,int unitsOverride,int appendUnits,int *unitsUsed)
+{
+ if(!unitsOverride) {
+ if(size<1000) unitsOverride=UNITS_BYTES;
+ else if(size<100*1024) unitsOverride=UNITS_KBPOINT1;
+ else if(size<1024*1024) unitsOverride=UNITS_KBPOINT0;
+ else if(size<1024*1024*1024) unitsOverride=UNITS_MBPOINT2;
+ else unitsOverride=UNITS_GBPOINT3;
+ }
+ if(unitsUsed) *unitsUsed=unitsOverride;
+ switch(unitsOverride) {
+ case UNITS_BYTES: mir_sntprintf(szOut,cchOut,_T("%u%s%s"),(int)size,appendUnits?_T(" "):_T(""),appendUnits?TranslateT("bytes"):_T("")); break;
+ case UNITS_KBPOINT1: mir_sntprintf(szOut,cchOut,_T("%.1lf%s"),size/1024.0,appendUnits?_T(" KB"):_T("")); break;
+ case UNITS_KBPOINT0: mir_sntprintf(szOut,cchOut,_T("%u%s"),(int)(size/1024),appendUnits?_T(" KB"):_T("")); break;
+ case UNITS_GBPOINT3: mir_sntprintf(szOut,cchOut,_T("%.3f%s"),(size >> 20)/1024.0,appendUnits?_T(" GB"):_T("")); break;
+ default: mir_sntprintf(szOut,cchOut,_T("%.2lf%s"),size/1048576.0,appendUnits?_T(" MB"):_T("")); break;
+ }
+}
+
+// Tripple redirection sucks but is needed to nullify the array pointer
+void FreeFilesMatrix(TCHAR ***files)
+{
+ if (*files == NULL)
+ return;
+
+ // Free each filename in the pointer array
+ TCHAR **pFile = *files;
+ while (*pFile != NULL)
+ {
+ mir_free(*pFile);
+ *pFile = NULL;
+ pFile++;
+ }
+
+ // Free the array itself
+ mir_free(*files);
+ *files = NULL;
+}
+
+void FreeProtoFileTransferStatus(PROTOFILETRANSFERSTATUS *fts)
+{
+ mir_free(fts->tszCurrentFile);
+ if(fts->ptszFiles) {
+ for( int i=0;i<fts->totalFiles;i++) mir_free(fts->ptszFiles[i]);
+ mir_free(fts->ptszFiles);
+ }
+ mir_free(fts->tszWorkingDir);
+}
+
+void CopyProtoFileTransferStatus(PROTOFILETRANSFERSTATUS *dest, PROTOFILETRANSFERSTATUS *src)
+{
+ *dest=*src;
+ if ( src->tszCurrentFile ) dest->tszCurrentFile = PFTS_StringToTchar(src->flags, src->tszCurrentFile);
+ if ( src->ptszFiles ) {
+ dest->ptszFiles = (TCHAR**)mir_alloc(sizeof(TCHAR*)*src->totalFiles);
+ for( int i=0; i < src->totalFiles; i++ )
+ dest->ptszFiles[i] = PFTS_StringToTchar(src->flags, src->ptszFiles[i] );
+ }
+ if ( src->tszWorkingDir ) dest->tszWorkingDir = PFTS_StringToTchar(src->flags, src->tszWorkingDir );
+ dest->flags &= ~PFTS_UTF;
+ dest->flags |= PFTS_TCHAR;
+}
+
+void UpdateProtoFileTransferStatus(PROTOFILETRANSFERSTATUS *dest, PROTOFILETRANSFERSTATUS *src)
+{
+ if (src->cbSize == sizeof(PROTOFILETRANSFERSTATUS_V1))
+ {
+ PROTOFILETRANSFERSTATUS_V1 *src1 = (PROTOFILETRANSFERSTATUS_V1*)src;
+ src = (PROTOFILETRANSFERSTATUS*)alloca(sizeof(PROTOFILETRANSFERSTATUS));
+
+ src->cbSize = sizeof(PROTOFILETRANSFERSTATUS);
+ src->hContact = src1->hContact;
+ src->flags = src1->sending ? PFTS_SENDING : 0;
+ src->pszFiles = src1->files;
+ src->totalFiles = src1->totalFiles;
+ src->currentFileNumber = src1->currentFileNumber;
+ src->totalBytes = src1->totalBytes;
+ src->totalProgress = src1->totalProgress;
+ src->szWorkingDir = src1->workingDir;
+ src->szCurrentFile = src1->currentFile;
+ src->currentFileSize = src1->currentFileSize;
+ src->currentFileProgress = src1->currentFileProgress;
+ src->currentFileTime = src1->currentFileTime;
+ }
+
+ dest->hContact = src->hContact;
+ dest->flags = src->flags;
+ if ( dest->totalFiles != src->totalFiles ) {
+ for( int i=0;i<dest->totalFiles;i++) mir_free(dest->ptszFiles[i]);
+ mir_free(dest->ptszFiles);
+ dest->ptszFiles = NULL;
+ dest->totalFiles = src->totalFiles;
+ }
+ if ( src->ptszFiles ) {
+ if ( !dest->ptszFiles )
+ dest->ptszFiles = ( TCHAR** )mir_calloc( sizeof(TCHAR*)*src->totalFiles);
+ for ( int i=0; i < src->totalFiles; i++ )
+ if ( !dest->ptszFiles[i] || !src->ptszFiles[i] || PFTS_CompareWithTchar( src, src->ptszFiles[i], dest->ptszFiles[i] )) {
+ mir_free( dest->ptszFiles[i] );
+ if ( src->ptszFiles[i] )
+ dest->ptszFiles[i] = PFTS_StringToTchar( src->flags, src->ptszFiles[i] );
+ else
+ dest->ptszFiles[i] = NULL;
+ }
+ }
+ else if (dest->ptszFiles) {
+ for( int i=0; i < dest->totalFiles; i++ )
+ mir_free(dest->ptszFiles[i]);
+ mir_free( dest->ptszFiles );
+ dest->ptszFiles = NULL;
+ }
+
+ dest->currentFileNumber = src->currentFileNumber;
+ dest->totalBytes = src->totalBytes;
+ dest->totalProgress = src->totalProgress;
+ if (src->tszWorkingDir && (!dest->tszWorkingDir || PFTS_CompareWithTchar( src, src->tszWorkingDir, dest->tszWorkingDir))) {
+ mir_free( dest->tszWorkingDir );
+ if ( src->tszWorkingDir )
+ dest->tszWorkingDir = PFTS_StringToTchar( src->flags, src->tszWorkingDir );
+ else
+ dest->tszWorkingDir = NULL;
+ }
+
+ if ( !dest->tszCurrentFile || !src->tszCurrentFile || PFTS_CompareWithTchar( src, src->tszCurrentFile, dest->tszCurrentFile )) {
+ mir_free( dest->tszCurrentFile );
+ if ( src->tszCurrentFile )
+ dest->tszCurrentFile = PFTS_StringToTchar( src->flags, src->tszCurrentFile );
+ else
+ dest->tszCurrentFile = NULL;
+ }
+ dest->currentFileSize = src->currentFileSize;
+ dest->currentFileProgress = src->currentFileProgress;
+ dest->currentFileTime = src->currentFileTime;
+ dest->flags &= ~PFTS_UTF;
+ dest->flags |= PFTS_TCHAR;
+}
+
+static void RemoveUnreadFileEvents(void)
+{
+ DBEVENTINFO dbei={0};
+ HANDLE hDbEvent,hContact;
+
+ dbei.cbSize=sizeof(dbei);
+ hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDFIRST,0,0);
+ while(hContact) {
+ hDbEvent=(HANDLE)CallService(MS_DB_EVENT_FINDFIRSTUNREAD,(WPARAM)hContact,0);
+ while(hDbEvent) {
+ dbei.cbBlob=0;
+ CallService(MS_DB_EVENT_GET,(WPARAM)hDbEvent,(LPARAM)&dbei);
+ if(!(dbei.flags&(DBEF_SENT|DBEF_READ)) && dbei.eventType==EVENTTYPE_FILE)
+ CallService(MS_DB_EVENT_MARKREAD,(WPARAM)hContact,(LPARAM)hDbEvent);
+ hDbEvent=(HANDLE)CallService(MS_DB_EVENT_FINDNEXT,(WPARAM)hDbEvent,0);
+ }
+ hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)hContact,0);
+ }
+}
+
+static int SRFilePreBuildMenu(WPARAM wParam, LPARAM)
+{
+ CLISTMENUITEM mi = { 0 };
+ mi.cbSize = sizeof(mi);
+ mi.flags = CMIM_FLAGS | CMIF_HIDDEN;
+
+ char *szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ if (szProto != NULL) {
+ if ( CallProtoService(szProto, PS_GETCAPS,PFLAGNUM_1, 0 ) & PF1_FILESEND) {
+ if ( CallProtoService(szProto, PS_GETCAPS,PFLAGNUM_4, 0 ) & PF4_OFFLINEFILES )
+ mi.flags = CMIM_FLAGS;
+ else if ( DBGetContactSettingWord(( HANDLE )wParam, szProto, "Status", ID_STATUS_OFFLINE ) != ID_STATUS_OFFLINE )
+ mi.flags = CMIM_FLAGS;
+ } }
+
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hSRFileMenuItem, (LPARAM)&mi);
+ return 0;
+}
+
+static int SRFileModulesLoaded(WPARAM, LPARAM)
+{
+ CLISTMENUITEM mi = { 0 };
+ mi.cbSize = sizeof(mi);
+ mi.position = -2000020000;
+ mi.icolibItem = GetSkinIconHandle( SKINICON_EVENT_FILE );
+ mi.pszName = LPGEN("&File");
+ mi.pszService = MS_FILE_SENDFILE;
+ mi.flags = CMIF_ICONFROMICOLIB;
+ hSRFileMenuItem = ( HANDLE )CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&mi);
+
+ RemoveUnreadFileEvents();
+ return 0;
+}
+
+INT_PTR FtMgrShowCommand(WPARAM, LPARAM)
+{
+ FtMgr_Show(true, true);
+ return 0;
+}
+
+INT_PTR openContRecDir(WPARAM wparam, LPARAM)
+{
+ TCHAR szContRecDir[MAX_PATH];
+ HANDLE hContact = (HANDLE)wparam;
+ GetContactReceivedFilesDir(hContact, szContRecDir, SIZEOF(szContRecDir),TRUE);
+ ShellExecute(0, _T("open"), szContRecDir, 0, 0, SW_SHOW);
+ return 0;
+}
+
+INT_PTR openRecDir(WPARAM, LPARAM)
+{
+ TCHAR szContRecDir[MAX_PATH];
+ GetReceivedFilesDir(szContRecDir, SIZEOF(szContRecDir));
+ ShellExecute(0, _T("open"), szContRecDir, 0, 0, SW_SHOW);
+ return 0;
+}
+
+int LoadSendRecvFileModule(void)
+{
+ CreateServiceFunction("FtMgr/Show", FtMgrShowCommand);
+
+ CLISTMENUITEM mi = { 0 };
+ mi.cbSize = sizeof(mi);
+ mi.flags = CMIF_ICONFROMICOLIB;
+ mi.icolibItem = GetSkinIconHandle( SKINICON_EVENT_FILE );
+ mi.position = 1900000000;
+ mi.pszName = LPGEN("File &Transfers...");
+ mi.pszService = "FtMgr/Show"; //MS_PROTO_SHOWFTMGR;
+ CallService( MS_CLIST_ADDMAINMENUITEM, 0, ( LPARAM )&mi );
+
+ HookEvent(ME_SYSTEM_MODULESLOADED,SRFileModulesLoaded);
+ HookEvent(ME_DB_EVENT_ADDED,FileEventAdded);
+ HookEvent(ME_OPT_INITIALISE,FileOptInitialise);
+ HookEvent(ME_CLIST_PREBUILDCONTACTMENU, SRFilePreBuildMenu);
+
+ CreateServiceFunction(MS_FILE_SENDFILE,SendFileCommand);
+ CreateServiceFunction(MS_FILE_SENDSPECIFICFILES,SendSpecificFiles);
+ CreateServiceFunction(MS_FILE_SENDSPECIFICFILEST,SendSpecificFilesT);
+ CreateServiceFunction(MS_FILE_GETRECEIVEDFILESFOLDER,GetReceivedFilesFolder);
+ CreateServiceFunction("SRFile/RecvFile",RecvFileCommand);
+
+ CreateServiceFunction("SRFile/OpenContRecDir",openContRecDir);
+ CreateServiceFunction("SRFile/OpenRecDir",openRecDir);
+
+ SkinAddNewSoundEx("RecvFile", "File", "Incoming");
+ SkinAddNewSoundEx("FileDone", "File", "Complete");
+ SkinAddNewSoundEx("FileFailed", "File", "Error");
+ SkinAddNewSoundEx("FileDenied", "File", "Denied");
+ return 0;
+}
diff --git a/src/modules/srfile/file.h b/src/modules/srfile/file.h
new file mode 100644
index 0000000000..8ee9048eb9
--- /dev/null
+++ b/src/modules/srfile/file.h
@@ -0,0 +1,115 @@
+/*
+
+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.
+*/
+
+#define VIRUSSCAN_DISABLE 0
+#define VIRUSSCAN_AFTERDL 1
+#define VIRUSSCAN_DURINGDL 2
+
+#define FILERESUME_ASK 0
+//1,2,3,4: resume, overwrite, rename, skip: from proto library
+#define FILERESUMEF_ALL 0x80
+#define FILERESUME_RESUMEALL (FILERESUME_RESUME|FILERESUMEF_ALL)
+#define FILERESUME_OVERWRITEALL (FILERESUME_OVERWRITE|FILERESUMEF_ALL)
+#define FILERESUME_RENAMEALL (FILERESUME_RENAME|FILERESUMEF_ALL)
+#define FILERESUME_CANCEL 0xFFFFFFFF
+
+#define M_FILEEXISTSDLGREPLY (WM_USER+200)
+#define M_PRESHUTDOWN (WM_USER+201)
+
+struct FileSendData {
+ HANDLE hContact;
+ const TCHAR **ppFiles;
+};
+
+#define BYTESRECVEDHISTORYCOUNT 10 //the number of bytes recved is sampled once a second and the last 10 are used to get the transfer speed
+struct FileDlgData {
+ HWND hwndTransfer;
+ HANDLE fs;
+ HANDLE hContact;
+ HANDLE hDbEvent;
+ HANDLE hNotifyEvent;
+ TCHAR **files;
+ int send;
+ int closeIfFileChooseCancelled;
+ int resumeBehaviour;
+ int bytesRecvedHistory[BYTESRECVEDHISTORYCOUNT];
+ int bytesRecvedHistorySize;
+ int waitingForAcceptance;
+ PROTOFILETRANSFERSTATUS transferStatus;
+ int *fileVirusScanned;
+ HANDLE hPreshutdownEvent;
+ DWORD dwTicks;
+
+ TCHAR szSavePath[MAX_PATH];
+ TCHAR szMsg[450], szFilenames[1024];
+ HICON hIcon, hIconFolder;
+};
+
+//file.c
+#define UNITS_BYTES 1 // 0<=size<1000: "%d bytes"
+#define UNITS_KBPOINT1 2 // 1000<=size<100*1024: "%.1f KB"
+#define UNITS_KBPOINT0 3 // 100*1024<=size<1024*1024: "%d KB"
+#define UNITS_MBPOINT2 4 // 1024*1024<=size: "%.2f MB"
+#define UNITS_GBPOINT3 5 // 1024*1024*1024<=size: "%.3f GB"
+
+void GetSensiblyFormattedSize(__int64 size,TCHAR *szOut,int cchOut,int unitsOverride,int appendUnits,int *unitsUsed);
+void FreeFilesMatrix(TCHAR ***files); //loving that triple indirection
+void FreeProtoFileTransferStatus(PROTOFILETRANSFERSTATUS *fts);
+void CopyProtoFileTransferStatus(PROTOFILETRANSFERSTATUS *dest,PROTOFILETRANSFERSTATUS *src);
+void UpdateProtoFileTransferStatus(PROTOFILETRANSFERSTATUS *dest,PROTOFILETRANSFERSTATUS *src);
+int SRFile_GetRegValue(HKEY hKeyBase,const TCHAR *szSubKey,const TCHAR *szValue,TCHAR *szOutput,int cbOutput);
+//filesenddlg.c
+INT_PTR CALLBACK DlgProcSendFile(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+//filerecv.c
+INT_PTR CALLBACK DlgProcRecvFile(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+void RemoveInvalidFilenameChars(TCHAR *tszString);
+void RemoveInvalidPathChars(TCHAR *tszString);
+void GetContactReceivedFilesDir(HANDLE hContact,TCHAR *szDir,int cchDir,BOOL substVars);
+void GetReceivedFilesDir(TCHAR *szDir,int cchDir);
+int BrowseForFolder(HWND hwnd,TCHAR *szPath);
+//fileexistsdlg.c
+struct TDlgProcFileExistsParam
+{
+ HWND hwndParent;
+ PROTOFILETRANSFERSTATUS *fts;
+};
+INT_PTR CALLBACK DlgProcFileExists(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+//filexferdlg.c
+INT_PTR CALLBACK DlgProcFileTransfer(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+//fileopts.c
+int FileOptInitialise(WPARAM wParam,LPARAM lParam);
+//ftmanager.c
+#define WM_FT_ADD (WM_USER+701)
+#define WM_FT_RESIZE (WM_USER+702)
+#define WM_FT_REMOVE (WM_USER+703)
+#define WM_FT_SELECTPAGE (WM_USER+704)
+#define WM_FT_CLEANUP (WM_USER+705)
+#define WM_FT_COMPLETED (WM_USER+706)
+
+HWND FtMgr_Show(bool bForceActivate, bool bFromMenu);
+void FtMgr_Destroy();
+HWND FtMgr_AddTransfer(struct FileDlgData *dat);
+
+void FreeFileDlgData( FileDlgData* dat );
+
+TCHAR *GetContactID(HANDLE hContact);
diff --git a/src/modules/srfile/fileexistsdlg.cpp b/src/modules/srfile/fileexistsdlg.cpp
new file mode 100644
index 0000000000..d97d6d8da2
--- /dev/null
+++ b/src/modules/srfile/fileexistsdlg.cpp
@@ -0,0 +1,354 @@
+/*
+
+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 <shlobj.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "file.h"
+
+static void SetControlToUnixTime(HWND hwndDlg, UINT idCtrl, time_t unixTime)
+{
+ LARGE_INTEGER liFiletime;
+ FILETIME filetime;
+ SYSTEMTIME st;
+ char szTime[64],szDate[64],szOutput[128];
+
+ liFiletime.QuadPart=(BIGI(11644473600)+(__int64)unixTime)*10000000;
+ filetime.dwHighDateTime=liFiletime.HighPart;
+ filetime.dwLowDateTime=liFiletime.LowPart;
+ FileTimeToSystemTime(&filetime,&st);
+ GetTimeFormatA(LOCALE_USER_DEFAULT,0,&st,NULL,szTime,SIZEOF(szTime));
+ GetDateFormatA(LOCALE_USER_DEFAULT,DATE_SHORTDATE,&st,NULL,szDate,SIZEOF(szDate));
+ mir_snprintf(szOutput, SIZEOF(szOutput), "%s %s",szDate,szTime);
+ SetDlgItemTextA(hwndDlg,idCtrl,szOutput);
+}
+
+#define C_CONTEXTMENU 0
+#define C_PROPERTIES 1
+// not defined in VC++ 6.0 SE
+#ifndef CMF_EXTENDEDVERBS
+#define CMF_EXTENDEDVERBS 0x00000100
+#endif
+static void DoAnnoyingShellCommand(HWND hwnd,const TCHAR *szFilename,int cmd,POINT *ptCursor)
+{
+ IShellFolder *pDesktopFolder;
+ if(SHGetDesktopFolder(&pDesktopFolder)==NOERROR) {
+ ITEMIDLIST *pCurrentIdl;
+ #if defined( _UNICODE )
+ WCHAR* wszFilename = ( LPWSTR )szFilename;
+ #else
+ WCHAR wszFilename[MAX_PATH];
+ MultiByteToWideChar(CP_ACP,0,szFilename,-1,wszFilename,SIZEOF(wszFilename));
+ #endif
+ if(pDesktopFolder->ParseDisplayName(NULL,NULL,wszFilename,NULL,&pCurrentIdl,NULL)==NOERROR) {
+ if(pCurrentIdl->mkid.cb) {
+ ITEMIDLIST *pidl,*pidlNext,*pidlFilename;
+ IShellFolder *pFileFolder;
+
+ for(pidl=pCurrentIdl;;) {
+ pidlNext=(ITEMIDLIST*)((PBYTE)pidl+pidl->mkid.cb);
+ if(pidlNext->mkid.cb==0) {
+ pidlFilename = (ITEMIDLIST*)CoTaskMemAlloc(pidl->mkid.cb+sizeof(pidl->mkid.cb));
+ CopyMemory(pidlFilename,pidl,pidl->mkid.cb+sizeof(pidl->mkid.cb));
+ pidl->mkid.cb=0;
+ break;
+ }
+ pidl=pidlNext;
+ }
+ if(pDesktopFolder->BindToObject(pCurrentIdl,NULL,IID_IShellFolder,(void**)&pFileFolder)==NOERROR) {
+ IContextMenu *pContextMenu;
+ if(pFileFolder->GetUIObjectOf(NULL,1,(LPCITEMIDLIST*)&pidlFilename,IID_IContextMenu,NULL,(void**)&pContextMenu)==NOERROR) {
+ switch(cmd) {
+ case C_PROPERTIES:
+ { CMINVOKECOMMANDINFO ici={0};
+ ici.cbSize=sizeof(ici);
+ ici.hwnd=hwnd;
+ ici.lpVerb="properties";
+ ici.nShow=SW_SHOW;
+ pContextMenu->InvokeCommand(&ici);
+ break;
+ }
+ case C_CONTEXTMENU:
+ { HMENU hMenu;
+ hMenu=CreatePopupMenu();
+ if(SUCCEEDED(pContextMenu->QueryContextMenu(hMenu,0,1000,65535,(GetKeyState(VK_SHIFT)&0x8000?CMF_EXTENDEDVERBS:0)|CMF_NORMAL))) {
+ int cmd;
+ cmd=TrackPopupMenu(hMenu,TPM_RETURNCMD,ptCursor->x,ptCursor->y,0,hwnd,NULL);
+ if(cmd) {
+ CMINVOKECOMMANDINFO ici={0};
+ ici.cbSize=sizeof(ici);
+ ici.hwnd=hwnd;
+ ici.lpVerb=MAKEINTRESOURCEA(cmd-1000);
+ ici.nShow=SW_SHOW;
+ pContextMenu->InvokeCommand(&ici);
+ }
+ }
+ DestroyMenu(hMenu);
+ break;
+ }
+ }
+ pContextMenu->Release();
+ }
+ pFileFolder->Release();
+ }
+ CoTaskMemFree(pidlFilename);
+ }
+ CoTaskMemFree(pCurrentIdl);
+ }
+ pDesktopFolder->Release();
+ }
+}
+
+static WNDPROC pfnIconWindowProc;
+static LRESULT CALLBACK IconCtrlSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ PROTOFILETRANSFERSTATUS* pft = (PROTOFILETRANSFERSTATUS*)GetWindowLongPtr(GetParent(hwnd),GWLP_USERDATA);
+
+ switch(msg) {
+ case WM_LBUTTONDBLCLK:
+ ShellExecute(hwnd,NULL,pft->tszCurrentFile,NULL,NULL,SW_SHOW);
+ break;
+ case WM_RBUTTONUP:
+ { POINT pt;
+ pt.x=(short)LOWORD(lParam); pt.y=(short)HIWORD(lParam);
+ ClientToScreen( hwnd, &pt );
+ DoAnnoyingShellCommand( hwnd, pft->tszCurrentFile, C_CONTEXTMENU, &pt );
+ return 0;
+ }
+ }
+ return CallWindowProc(pfnIconWindowProc,hwnd,msg,wParam,lParam);
+}
+
+struct loadiconsstartinfo {
+ HWND hwndDlg;
+ TCHAR *szFilename;
+};
+void __cdecl LoadIconsAndTypesThread(void* param)
+{
+ loadiconsstartinfo *info = ( loadiconsstartinfo* )param;
+ SHFILEINFO fileInfo;
+
+ if ( SHGetFileInfo( info->szFilename, 0, &fileInfo, sizeof(fileInfo),SHGFI_TYPENAME|SHGFI_ICON|SHGFI_LARGEICON)) {
+ TCHAR *pszExtension,*pszFilename;
+ TCHAR szExtension[64];
+ TCHAR szIconFile[MAX_PATH];
+
+ pszFilename = _tcsrchr(info->szFilename,'\\');
+ if ( pszFilename == NULL )
+ pszFilename = info->szFilename;
+
+ pszExtension = _tcsrchr( pszFilename, '.' );
+ if ( pszExtension )
+ lstrcpyn( szExtension, pszExtension+1, SIZEOF( szExtension ));
+ else {
+ pszExtension = _T(".");
+ szExtension[0]='\0';
+ }
+ CharUpper(szExtension);
+ if ( fileInfo.szTypeName[0]=='\0' )
+ mir_sntprintf( fileInfo.szTypeName, SIZEOF(fileInfo.szTypeName), TranslateT("%s File"),szExtension);
+ SetDlgItemText(info->hwndDlg,IDC_EXISTINGTYPE,fileInfo.szTypeName);
+ SetDlgItemText(info->hwndDlg,IDC_NEWTYPE,fileInfo.szTypeName);
+ SendDlgItemMessage(info->hwndDlg,IDC_EXISTINGICON,STM_SETICON,(WPARAM)fileInfo.hIcon,0);
+ szIconFile[0]='\0';
+ if ( !lstrcmp( szExtension, _T("EXE"))) {
+ SRFile_GetRegValue(HKEY_LOCAL_MACHINE,_T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Icons"),_T("2"),szIconFile,SIZEOF(szIconFile));
+ }
+ else {
+ TCHAR szTypeName[MAX_PATH];
+ if(SRFile_GetRegValue(HKEY_CLASSES_ROOT,pszExtension,NULL,szTypeName,SIZEOF(szTypeName))) {
+ lstrcat(szTypeName,_T("\\DefaultIcon"));
+ if(SRFile_GetRegValue(HKEY_CLASSES_ROOT,szTypeName,NULL,szIconFile,SIZEOF(szIconFile))) {
+ if ( _tcsstr( szIconFile, _T("%1")))
+ SRFile_GetRegValue(HKEY_LOCAL_MACHINE,_T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Icons"),_T("0"),szIconFile,SIZEOF(szIconFile));
+ else szIconFile[0]='\0';
+ } } }
+
+ if ( szIconFile[0]) {
+ int iconIndex;
+ HICON hIcon;
+ TCHAR *pszComma = _tcsrchr(szIconFile,',');
+ if ( pszComma == NULL )
+ iconIndex=0;
+ else {
+ iconIndex = _ttoi(pszComma+1); *pszComma='\0';
+ }
+ hIcon = ExtractIcon( hMirandaInst, szIconFile, iconIndex );
+ if ( hIcon )
+ fileInfo.hIcon = hIcon;
+ }
+ SendDlgItemMessage(info->hwndDlg,IDC_NEWICON,STM_SETICON,(WPARAM)fileInfo.hIcon,0);
+ }
+ mir_free(info->szFilename);
+ mir_free(info);
+}
+
+INT_PTR CALLBACK DlgProcFileExists(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ PROTOFILETRANSFERSTATUS *fts;
+
+ fts=(PROTOFILETRANSFERSTATUS*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA);
+ switch(msg) {
+ case WM_INITDIALOG:
+ {
+ TCHAR szSize[64];
+ struct _stati64 statbuf;
+ HWND hwndFocus;
+ struct TDlgProcFileExistsParam *dat = (struct TDlgProcFileExistsParam *)lParam;
+
+ SetPropA(hwndDlg,"Miranda.Preshutdown",HookEventMessage(ME_SYSTEM_PRESHUTDOWN,hwndDlg,M_PRESHUTDOWN));
+ SetPropA(hwndDlg,"Miranda.ParentWnd",dat->hwndParent);
+
+ TranslateDialogDefault(hwndDlg);
+ fts=(PROTOFILETRANSFERSTATUS*)mir_alloc(sizeof(PROTOFILETRANSFERSTATUS));
+ CopyProtoFileTransferStatus(fts,dat->fts);
+ SetWindowLongPtr(hwndDlg,GWLP_USERDATA,(LONG_PTR)fts);
+ SetDlgItemText(hwndDlg,IDC_FILENAME,fts->tszCurrentFile);
+ SetControlToUnixTime(hwndDlg,IDC_NEWDATE,fts->currentFileTime);
+ GetSensiblyFormattedSize(fts->currentFileSize,szSize,SIZEOF(szSize),0,1,NULL);
+ SetDlgItemText(hwndDlg,IDC_NEWSIZE,szSize);
+
+ pfnIconWindowProc=(WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_EXISTINGICON),GWLP_WNDPROC,(LONG_PTR)IconCtrlSubclassProc);
+
+ hwndFocus=GetDlgItem(hwndDlg,IDC_RESUME);
+ if ( _tstati64(fts->tszCurrentFile,&statbuf)==0) {
+ SetControlToUnixTime(hwndDlg,IDC_EXISTINGDATE,statbuf.st_mtime);
+ GetSensiblyFormattedSize(statbuf.st_size,szSize,SIZEOF(szSize),0,1,NULL);
+ SetDlgItemText(hwndDlg,IDC_EXISTINGSIZE,szSize);
+ if(statbuf.st_size>(int)fts->currentFileSize) {
+ EnableWindow(GetDlgItem(hwndDlg,IDC_RESUME),FALSE);
+ hwndFocus=GetDlgItem(hwndDlg,IDC_OVERWRITE);
+ } }
+
+ loadiconsstartinfo *lisi = ( loadiconsstartinfo* )mir_alloc(sizeof(loadiconsstartinfo));
+ lisi->hwndDlg=hwndDlg;
+ lisi->szFilename = mir_tstrdup(fts->tszCurrentFile);
+ //can be a little slow, so why not?
+ forkthread(LoadIconsAndTypesThread,0,lisi);
+ SetFocus(hwndFocus);
+ SetWindowLongPtr(hwndFocus,GWL_STYLE,GetWindowLongPtr(hwndFocus,GWL_STYLE)|BS_DEFPUSHBUTTON);
+ return FALSE;
+ }
+ case WM_COMMAND:
+ {
+ PROTOFILERESUME pfr={0};
+ switch(LOWORD(wParam)) {
+ case IDC_OPENFILE:
+ ShellExecute( hwndDlg, NULL, fts->tszCurrentFile, NULL, NULL, SW_SHOW );
+ return FALSE;
+
+ case IDC_OPENFOLDER:
+ {
+ TCHAR szFile[MAX_PATH];
+ lstrcpyn( szFile, fts->tszCurrentFile, SIZEOF(szFile));
+ TCHAR* pszLastBackslash = _tcsrchr( szFile, '\\' );
+ if ( pszLastBackslash )
+ *pszLastBackslash = '\0';
+ ShellExecute(hwndDlg,NULL,szFile,NULL,NULL,SW_SHOW);
+ return FALSE;
+ }
+ case IDC_PROPERTIES:
+ DoAnnoyingShellCommand(hwndDlg,fts->tszCurrentFile,C_PROPERTIES,NULL);
+ return FALSE;
+ case IDC_RESUME:
+ pfr.action=FILERESUME_RESUME;
+ break;
+ case IDC_RESUMEALL:
+ pfr.action=FILERESUME_RESUMEALL;
+ break;
+ case IDC_OVERWRITE:
+ pfr.action=FILERESUME_OVERWRITE;
+ break;
+ case IDC_OVERWRITEALL:
+ pfr.action=FILERESUME_OVERWRITEALL;
+ break;
+
+ case IDC_AUTORENAME:
+ pfr.action = FILERESUME_RENAMEALL;
+ break;
+
+ case IDC_SAVEAS:
+ {
+ OPENFILENAME ofn={0};
+ TCHAR filter[512],*pfilter;
+ TCHAR str[MAX_PATH];
+
+ lstrcpyn( str, fts->tszCurrentFile, SIZEOF(str));
+ ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
+ ofn.hwndOwner = hwndDlg;
+ ofn.Flags = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY;
+ _tcscpy( filter, TranslateT("All Files"));
+ _tcscat( filter, _T(" (*)"));
+ pfilter = filter + _tcslen(filter) + 1;
+ _tcscpy( pfilter, _T("*"));
+ pfilter = pfilter + _tcslen(pfilter) + 1;
+ *pfilter='\0';
+ ofn.lpstrFilter = filter;
+ ofn.lpstrFile = str;
+ ofn.nMaxFile = SIZEOF(str);
+ ofn.nMaxFileTitle = MAX_PATH;
+ if(!GetSaveFileName(&ofn))
+ return FALSE;
+
+ pfr.szFilename = mir_tstrdup(str);
+ pfr.action = FILERESUME_RENAME;
+ break;
+ }
+ case IDC_SKIP:
+ pfr.action=FILERESUME_SKIP;
+ break;
+ case IDCANCEL:
+ pfr.action=FILERESUME_CANCEL;
+ break;
+ default:
+ return FALSE;
+ }
+ { PROTOFILERESUME *pfrCopy;
+ pfrCopy=(PROTOFILERESUME*)mir_alloc(sizeof(pfr));
+ CopyMemory(pfrCopy,&pfr,sizeof(pfr));
+ PostMessage((HWND)GetPropA(hwndDlg,"Miranda.ParentWnd"),M_FILEEXISTSDLGREPLY,(WPARAM)mir_tstrdup(fts->tszCurrentFile),(LPARAM)pfrCopy);
+ DestroyWindow(hwndDlg);
+ }
+ break;
+ }
+
+ case WM_CLOSE:
+ PostMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDCANCEL,BN_CLICKED),(LPARAM)GetDlgItem(hwndDlg,IDCANCEL));
+ break;
+
+ case M_PRESHUTDOWN:
+ PostMessage(hwndDlg,WM_CLOSE,0,0);
+ break;
+
+ case WM_DESTROY:
+ UnhookEvent(GetPropA(hwndDlg,"Miranda.Preshutdown")); // GetProp() will return NULL if it couldnt find anything
+ RemovePropA(hwndDlg,"Miranda.Preshutdown");
+ RemovePropA(hwndDlg,"Miranda.ParentWnd");
+ DestroyIcon((HICON)SendDlgItemMessage(hwndDlg,IDC_EXISTINGICON,STM_GETICON,0,0));
+ DestroyIcon((HICON)SendDlgItemMessage(hwndDlg,IDC_NEWICON,STM_GETICON,0,0));
+ FreeProtoFileTransferStatus(fts);
+ mir_free(fts);
+ break;
+ }
+ return FALSE;
+}
diff --git a/src/modules/srfile/fileopts.cpp b/src/modules/srfile/fileopts.cpp
new file mode 100644
index 0000000000..3107f109a3
--- /dev/null
+++ b/src/modules/srfile/fileopts.cpp
@@ -0,0 +1,247 @@
+/*
+
+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 "file.h"
+
+#define VSCAN_MCAFEE 1
+#define VSCAN_DRSOLOMON 2
+#define VSCAN_NORTON 3
+#define VSCAN_CA 4
+
+struct virusscannerinfo {
+ const TCHAR *szProductName;
+ const TCHAR *szExeRegPath;
+ const TCHAR *szExeRegValue;
+ const TCHAR *szCommandLine;
+};
+
+static const struct virusscannerinfo virusScanners[]={
+ {_T("Network Associates/McAfee VirusScan"),_T("SOFTWARE\\McAfee\\VirusScan"),_T("Scan32EXE"),_T("\"%s\" %%f /nosplash /comp /autoscan /autoexit /noboot")},
+ {_T("Dr Solomon's VirusScan (Network Associates)"),_T("SOFTWARE\\Network Associates\\TVD\\VirusScan\\AVConsol\\General"),_T("szScannerExe"),_T("\"%s\" %%f /uinone /noboot /comp /prompt /autoexit")},
+ {_T("Norton AntiVirus"),_T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\Navw32.exe"),NULL,_T("\"%s\" %%f /b- /m- /s+ /noresults")},
+ {_T("Computer Associates/Inoculate IT"),_T("Software\\Antivirus"),_T("ImageFilename"),_T("\"%s\" %%f /display=progress /exit")},
+ {_T("Computer Associates eTrust"),_T("SOFTWARE\\ComputerAssociates\\Anti-Virus\\Resident"),_T("VetPath"),_T("\"%s\" %%f /display=progress /exit")},
+ {_T("Kaspersky Anti-Virus"),_T("SOFTWARE\\KasperskyLab\\Components\\101"),_T("EXEName"),_T("\"%s\" /S /Q %%f")},
+ {_T("Kaspersky Anti-Virus"),_T("SOFTWARE\\KasperskyLab\\SetupFolders"),_T("KAV8"),_T("\"%savp.exe\" SCAN %%f")},
+ {_T("Kaspersky Anti-Virus"),_T("SOFTWARE\\KasperskyLab\\SetupFolders"),_T("KAV9"),_T("\"%savp.exe\" SCAN %%f")},
+ {_T("AntiVir PersonalEdition Classic"),_T("SOFTWARE\\Avira\\AntiVir PersonalEdition Classic"),_T("Path"),_T("\"%savscan.exe\" /GUIMODE=2 /PATH=\"%%f\"")},
+ {_T("ESET NOD32 Antivirus"),_T("SOFTWARE\\ESET\\ESET Security\\CurrentVersion\\Info"),_T("InstallDir"),_T("\"%secls.exe\" /log-all /aind /no-boots /adware /sfx /unsafe /unwanted /heur /adv-heur /action=clean \"%%f\"")},
+};
+
+#define M_UPDATEENABLING (WM_USER+100)
+#define M_SCANCMDLINESELCHANGE (WM_USER+101)
+
+#ifndef SHACF_FILESYS_DIRS
+ #define SHACF_FILESYS_DIRS 0x00000020
+#endif
+
+static INT_PTR CALLBACK DlgProcFileOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG:
+ {
+ TranslateDialogDefault(hwndDlg);
+
+ if (shAutoComplete)
+ shAutoComplete(GetDlgItem(hwndDlg, IDC_FILEDIR), SHACF_FILESYS_DIRS);
+
+ {
+ TCHAR str[MAX_PATH];
+ GetContactReceivedFilesDir(NULL,str,SIZEOF(str),FALSE);
+ SetDlgItemText(hwndDlg,IDC_FILEDIR,str);
+ }
+
+ CheckDlgButton(hwndDlg, IDC_AUTOACCEPT, DBGetContactSettingByte(NULL,"SRFile","AutoAccept",0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_AUTOMIN, DBGetContactSettingByte(NULL,"SRFile","AutoMin",0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_AUTOCLOSE, DBGetContactSettingByte(NULL,"SRFile","AutoClose",0) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_AUTOCLEAR, DBGetContactSettingByte(NULL,"SRFile","AutoClear",1) ? BST_CHECKED : BST_UNCHECKED);
+ switch(DBGetContactSettingByte(NULL,"SRFile","UseScanner",VIRUSSCAN_DISABLE)) {
+ case VIRUSSCAN_AFTERDL: CheckDlgButton(hwndDlg, IDC_SCANAFTERDL, BST_CHECKED); break;
+ case VIRUSSCAN_DURINGDL: CheckDlgButton(hwndDlg, IDC_SCANDURINGDL, BST_CHECKED); break;
+ default: CheckDlgButton(hwndDlg, IDC_NOSCANNER, BST_CHECKED); break;
+ }
+ CheckDlgButton(hwndDlg, IDC_WARNBEFOREOPENING, DBGetContactSettingByte(NULL,"SRFile","WarnBeforeOpening",1) ? BST_CHECKED : BST_UNCHECKED);
+
+ { TCHAR szScanExe[MAX_PATH];
+ int i,iItem;
+ for( i=0; i < SIZEOF(virusScanners); i++ ) {
+ if(SRFile_GetRegValue(HKEY_LOCAL_MACHINE,virusScanners[i].szExeRegPath,virusScanners[i].szExeRegValue,szScanExe,SIZEOF(szScanExe))) {
+ iItem=SendDlgItemMessage(hwndDlg,IDC_SCANCMDLINE,CB_ADDSTRING,0,(LPARAM)virusScanners[i].szProductName);
+ SendDlgItemMessage(hwndDlg,IDC_SCANCMDLINE,CB_SETITEMDATA,iItem,i);
+ }
+ }
+ if ( SendDlgItemMessageA(hwndDlg,IDC_SCANCMDLINE,CB_GETCOUNT,0,0) == 0 )
+ {
+ iItem = SendDlgItemMessage(hwndDlg,IDC_SCANCMDLINE,CB_ADDSTRING,0,(LPARAM)_T("") );
+ SendDlgItemMessage(hwndDlg,IDC_SCANCMDLINE,CB_SETITEMDATA,iItem, (LPARAM)-1);
+ }
+ }
+
+ DBVARIANT dbv;
+ if(DBGetContactSettingTString(NULL,"SRFile","ScanCmdLine",&dbv)==0) {
+ SetDlgItemText(hwndDlg,IDC_SCANCMDLINE,dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ }
+ else {
+ if(SendDlgItemMessage(hwndDlg,IDC_SCANCMDLINE,CB_GETCOUNT,0,0)) {
+ SendDlgItemMessage(hwndDlg,IDC_SCANCMDLINE,CB_SETCURSEL,0,0);
+ PostMessage(hwndDlg,M_SCANCMDLINESELCHANGE,0,0);
+ }
+ }
+ switch(DBGetContactSettingByte(NULL,"SRFile","IfExists",FILERESUME_ASK)) {
+ case FILERESUME_RESUMEALL: CheckDlgButton(hwndDlg, IDC_RESUME, BST_CHECKED); break;
+ case FILERESUME_OVERWRITEALL: CheckDlgButton(hwndDlg, IDC_OVERWRITE, BST_CHECKED); break;
+ case FILERESUME_RENAMEALL: CheckDlgButton(hwndDlg, IDC_RENAME, BST_CHECKED); break;
+ default: CheckDlgButton(hwndDlg, IDC_ASK, BST_CHECKED); break;
+ }
+ SendMessage(hwndDlg,M_UPDATEENABLING,0,0);
+ return TRUE;
+ }
+ case M_UPDATEENABLING:
+ { int on=!IsDlgButtonChecked(hwndDlg,IDC_NOSCANNER);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_ST_CMDLINE),on);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_SCANCMDLINE),on);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_SCANCMDLINEBROWSE),on);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_ST_CMDLINEHELP),on);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_AUTOMIN),IsDlgButtonChecked(hwndDlg,IDC_AUTOACCEPT));
+ break;
+ }
+ case M_SCANCMDLINESELCHANGE:
+ { TCHAR str[512];
+ TCHAR szScanExe[MAX_PATH];
+ int iScanner=SendDlgItemMessage(hwndDlg,IDC_SCANCMDLINE,CB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_SCANCMDLINE,CB_GETCURSEL,0,0),0);
+ if(iScanner >= SIZEOF(virusScanners) || iScanner<0) break;
+ str[0]='\0';
+ if(SRFile_GetRegValue(HKEY_LOCAL_MACHINE,virusScanners[iScanner].szExeRegPath,virusScanners[iScanner].szExeRegValue,szScanExe,SIZEOF(szScanExe)))
+ mir_sntprintf(str, SIZEOF(str), virusScanners[iScanner].szCommandLine,szScanExe);
+ SetDlgItemText(hwndDlg,IDC_SCANCMDLINE,str);
+ break;
+ }
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDC_FILEDIR:
+ if((HIWORD(wParam)!=EN_CHANGE || (HWND)lParam!=GetFocus())) return 0;
+ break;
+ case IDC_FILEDIRBROWSE:
+ { TCHAR str[MAX_PATH];
+ GetDlgItemText(hwndDlg,IDC_FILEDIR,str,SIZEOF(str));
+ if(BrowseForFolder(hwndDlg,str))
+ SetDlgItemText(hwndDlg,IDC_FILEDIR,str);
+ break;
+ }
+ case IDC_AUTOACCEPT:
+ case IDC_NOSCANNER:
+ case IDC_SCANAFTERDL:
+ case IDC_SCANDURINGDL:
+ SendMessage(hwndDlg,M_UPDATEENABLING,0,0);
+ break;
+ case IDC_SCANCMDLINE:
+ if(HIWORD(wParam)==CBN_SELCHANGE) PostMessage(hwndDlg,M_SCANCMDLINESELCHANGE,0,0);
+ else if(HIWORD(wParam)!=CBN_EDITCHANGE) return 0;
+ break;
+ case IDC_SCANCMDLINEBROWSE:
+ { TCHAR str[MAX_PATH+2];
+ OPENFILENAME ofn = {0};
+ TCHAR filter[512], *pfilter;
+
+ GetDlgItemText(hwndDlg, IDC_SCANCMDLINE, str, SIZEOF(str));
+ ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
+ ofn.hwndOwner = hwndDlg;
+ ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_DONTADDTORECENT;
+ _tcscpy(filter,TranslateT("Executable Files"));
+ _tcscat(filter, _T(" (*.exe)"));
+ pfilter = filter + _tcslen(filter) + 1;
+ _tcscpy(pfilter, _T("*.exe"));
+ pfilter = pfilter + _tcslen(pfilter)+1;
+ _tcscpy(pfilter, TranslateT("All Files"));
+ _tcscat(pfilter, _T(" (*)"));
+ pfilter = pfilter + _tcslen(pfilter) + 1;
+ _tcscpy(pfilter, _T("*"));
+ pfilter = pfilter + _tcslen(pfilter) + 1;
+ *pfilter = 0;
+ ofn.lpstrFilter = filter;
+ ofn.lpstrFile = str;
+ ofn.nMaxFile = SIZEOF(str)-2;
+ if(str[0]=='"') {
+ TCHAR *pszQuote = _tcschr(str + 1, '"');
+ if (pszQuote) *pszQuote = 0;
+ MoveMemory(str, str + 1, _tcslen(str) * sizeof(TCHAR));
+ }
+ else {
+ TCHAR *pszSpace = _tcschr(str, ' ');
+ if (pszSpace) *pszSpace = 0;
+ }
+ ofn.nMaxFileTitle = MAX_PATH;
+ if (!GetOpenFileName(&ofn)) break;
+ if (_tcschr(str, ' ') != NULL) {
+ MoveMemory(str+1, str, SIZEOF(str) - 2 * sizeof(TCHAR));
+ str[0] = '"';
+ _tcscat(str, _T("\""));
+ }
+ SetDlgItemText(hwndDlg, IDC_SCANCMDLINE, str);
+ break;
+ }
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case PSN_APPLY:
+ { TCHAR str[512];
+ GetDlgItemText(hwndDlg, IDC_FILEDIR, str, SIZEOF(str));
+ RemoveInvalidPathChars(str);
+ DBWriteContactSettingTString(NULL,"SRFile","RecvFilesDirAdv",str);
+ DBWriteContactSettingByte(NULL,"SRFile","AutoAccept",(BYTE)IsDlgButtonChecked(hwndDlg,IDC_AUTOACCEPT));
+ DBWriteContactSettingByte(NULL,"SRFile","AutoMin",(BYTE)IsDlgButtonChecked(hwndDlg,IDC_AUTOMIN));
+ DBWriteContactSettingByte(NULL,"SRFile","AutoClose",(BYTE)IsDlgButtonChecked(hwndDlg,IDC_AUTOCLOSE));
+ DBWriteContactSettingByte(NULL,"SRFile","AutoClear",(BYTE)IsDlgButtonChecked(hwndDlg,IDC_AUTOCLEAR));
+ DBWriteContactSettingByte(NULL,"SRFile","UseScanner",(BYTE)(IsDlgButtonChecked(hwndDlg,IDC_SCANAFTERDL)?VIRUSSCAN_AFTERDL:(IsDlgButtonChecked(hwndDlg,IDC_SCANDURINGDL)?VIRUSSCAN_DURINGDL:VIRUSSCAN_DISABLE)));
+ GetDlgItemText(hwndDlg, IDC_SCANCMDLINE, str, SIZEOF(str));
+ DBWriteContactSettingTString(NULL,"SRFile","ScanCmdLine",str);
+ DBWriteContactSettingByte(NULL,"SRFile","WarnBeforeOpening",(BYTE)IsDlgButtonChecked(hwndDlg,IDC_WARNBEFOREOPENING));
+ DBWriteContactSettingByte(NULL,"SRFile","IfExists",(BYTE)(IsDlgButtonChecked(hwndDlg,IDC_ASK)?FILERESUME_ASK:(IsDlgButtonChecked(hwndDlg,IDC_RESUME)?FILERESUME_RESUMEALL:(IsDlgButtonChecked(hwndDlg,IDC_OVERWRITE)?FILERESUME_OVERWRITEALL:FILERESUME_RENAMEALL))));
+ return TRUE;
+ }
+ }
+ break;
+ }
+ return FALSE;
+}
+
+int FileOptInitialise(WPARAM wParam, LPARAM)
+{
+ OPTIONSDIALOGPAGE odp={0};
+ odp.cbSize = sizeof(odp);
+ odp.position = 900000000;
+ odp.hInstance = hMirandaInst;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_FILETRANSFER);
+ odp.pszTitle = LPGEN("File Transfers");
+ odp.pszGroup = LPGEN("Events");
+ odp.pfnDlgProc = DlgProcFileOpts;
+ odp.flags = ODPF_BOLDGROUPS;
+ odp.nIDBottomSimpleControl = IDC_VIRUSSCANNERGROUP;
+ CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
+ return 0;
+}
+
diff --git a/src/modules/srfile/filerecvdlg.cpp b/src/modules/srfile/filerecvdlg.cpp
new file mode 100644
index 0000000000..451a27e8bc
--- /dev/null
+++ b/src/modules/srfile/filerecvdlg.cpp
@@ -0,0 +1,446 @@
+/*
+
+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 "file.h"
+
+#define MAX_MRU_DIRS 5
+
+static BOOL CALLBACK ClipSiblingsChildEnumProc(HWND hwnd, LPARAM)
+{
+ SetWindowLongPtr(hwnd,GWL_STYLE,GetWindowLongPtr(hwnd,GWL_STYLE)|WS_CLIPSIBLINGS);
+ return TRUE;
+}
+
+static void GetLowestExistingDirName(const TCHAR *szTestDir,TCHAR *szExistingDir,int cchExistingDir)
+{
+ DWORD dwAttributes;
+ TCHAR *pszLastBackslash;
+
+ lstrcpyn(szExistingDir,szTestDir,cchExistingDir);
+ while((dwAttributes=GetFileAttributes(szExistingDir))!=INVALID_FILE_ATTRIBUTES && !(dwAttributes&FILE_ATTRIBUTE_DIRECTORY)) {
+ pszLastBackslash=_tcsrchr(szExistingDir,'\\');
+ if(pszLastBackslash==NULL) {*szExistingDir='\0'; break;}
+ *pszLastBackslash='\0';
+ }
+ if(szExistingDir[0]=='\0') GetCurrentDirectory(cchExistingDir,szExistingDir);
+}
+
+static const TCHAR InvalidFilenameChars[] = _T("\\/:*?\"<>|");
+void RemoveInvalidFilenameChars(TCHAR *tszString)
+{
+ size_t i;
+ if (tszString) {
+ for(i=_tcscspn(tszString,InvalidFilenameChars); tszString[i]; i+=_tcscspn(tszString+i+1,InvalidFilenameChars)+1)
+ if(tszString[i] >= 0)
+ tszString[i] = _T('_');
+ }
+}
+
+static const TCHAR InvalidPathChars[] = _T("*?\"<>|"); // "\/:" are excluded as they are allowed in file path
+void RemoveInvalidPathChars(TCHAR *tszString)
+{
+ size_t i;
+ if (tszString) {
+ for(i=_tcscspn(tszString,InvalidPathChars); tszString[i]; i+=_tcscspn(tszString+i+1,InvalidPathChars)+1)
+ if(tszString[i] >= 0)
+ tszString[i] = _T('_');
+ }
+}
+
+static INT CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM pData)
+{
+ TCHAR szDir[MAX_PATH];
+ switch(uMsg) {
+ case BFFM_INITIALIZED:
+ SendMessage(hwnd, BFFM_SETSELECTION, TRUE, pData);
+ break;
+ case BFFM_SELCHANGED:
+ if (SHGetPathFromIDList((LPITEMIDLIST) lp ,szDir))
+ SendMessage(hwnd,BFFM_SETSTATUSTEXT,0,(LPARAM)szDir);
+ break;
+ }
+ return 0;
+}
+
+int BrowseForFolder(HWND hwnd,TCHAR *szPath)
+{
+ BROWSEINFO bi={0};
+ LPITEMIDLIST pidlResult;
+
+ bi.hwndOwner=hwnd;
+ bi.pszDisplayName=szPath;
+ bi.lpszTitle=TranslateT("Select Folder");
+ bi.ulFlags=BIF_NEWDIALOGSTYLE|BIF_EDITBOX|BIF_RETURNONLYFSDIRS; // Use this combo instead of BIF_USENEWUI
+ bi.lpfn=BrowseCallbackProc;
+ bi.lParam=(LPARAM)szPath;
+
+ pidlResult=SHBrowseForFolder(&bi);
+ if(pidlResult) {
+ SHGetPathFromIDList(pidlResult,szPath);
+ lstrcat(szPath,_T("\\"));
+ CoTaskMemFree(pidlResult);
+ }
+ return pidlResult != NULL;
+}
+
+static REPLACEVARSARRAY sttVarsToReplace[] =
+{
+ { ( TCHAR* )"///", ( TCHAR* )"//" },
+ { ( TCHAR* )"//", ( TCHAR* )"/" },
+ { ( TCHAR* )"()", ( TCHAR* )"" },
+ { NULL, NULL }
+};
+
+static void patchDir( TCHAR* str, size_t strSize )
+{
+ REPLACEVARSDATA dat = { 0 };
+ dat.cbSize = sizeof( dat );
+ dat.dwFlags = RVF_TCHAR;
+ dat.variables = sttVarsToReplace;
+
+ TCHAR* result = ( TCHAR* )CallService( MS_UTILS_REPLACEVARS, (WPARAM)str, (LPARAM)&dat );
+ if ( result ) {
+ _tcsncpy( str, result, strSize );
+ mir_free( result );
+ }
+
+ size_t len = lstrlen( str );
+ if ( len+1 < strSize && str[len-1] != '\\' )
+ lstrcpy( str+len, _T("\\") );
+}
+
+void GetContactReceivedFilesDir(HANDLE hContact, TCHAR *szDir, int cchDir, BOOL patchVars)
+{
+ DBVARIANT dbv;
+ TCHAR szTemp[MAX_PATH];
+ szTemp[0] = 0;
+
+ if ( !DBGetContactSettingTString( NULL, "SRFile", "RecvFilesDirAdv", &dbv)) {
+ if ( lstrlen( dbv.ptszVal ) > 0 )
+ lstrcpyn( szTemp, dbv.ptszVal, SIZEOF( szTemp ));
+ DBFreeVariant( &dbv );
+ }
+
+ if ( !szTemp[0] )
+#ifdef _UNICODE
+ mir_sntprintf( szTemp, SIZEOF(szTemp), _T("%%mydocuments%%\\%s\\%%userid%%"), TranslateT("My Received Files"));
+#else
+ mir_sntprintf( szTemp, SIZEOF(szTemp), _T("%%mydocuments%%\\%s\\%%userid%%"), "My Received Files");
+#endif
+
+ if ( hContact ) {
+ REPLACEVARSDATA dat = { 0 };
+ REPLACEVARSARRAY rvaVarsToReplace[4];
+ rvaVarsToReplace[0].lptzKey = _T("nick");
+ rvaVarsToReplace[0].lptzValue = mir_tstrdup((TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR));
+ rvaVarsToReplace[1].lptzKey = _T("userid");
+ rvaVarsToReplace[1].lptzValue = GetContactID(hContact);
+ rvaVarsToReplace[2].lptzKey = _T("proto");
+ rvaVarsToReplace[2].lptzValue = mir_a2t((char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact,0));
+ rvaVarsToReplace[3].lptzKey = NULL;
+ rvaVarsToReplace[3].lptzValue = NULL;
+ for (int i=0; i < (SIZEOF(rvaVarsToReplace)-1);i++)
+ RemoveInvalidFilenameChars(rvaVarsToReplace[i].lptzValue);
+
+ dat.cbSize = sizeof( dat );
+ dat.dwFlags = RVF_TCHAR;
+ dat.variables = rvaVarsToReplace;
+ dat.hContact = hContact;
+ TCHAR* result = ( TCHAR* )CallService( MS_UTILS_REPLACEVARS, (WPARAM)szTemp, (LPARAM)&dat );
+ if ( result ) {
+ _tcsncpy( szTemp, result, SIZEOF(szTemp));
+ mir_free( result );
+ for (int i=0; i < (SIZEOF(rvaVarsToReplace)-1);i++)
+ mir_free(rvaVarsToReplace[i].lptzValue);
+ } }
+
+ if (patchVars)
+ patchDir( szTemp, SIZEOF(szTemp));
+ RemoveInvalidPathChars(szTemp);
+ lstrcpyn( szDir, szTemp, cchDir );
+}
+
+void GetReceivedFilesDir(TCHAR *szDir, int cchDir)
+{
+ DBVARIANT dbv;
+ TCHAR szTemp[MAX_PATH];
+ szTemp[0] = 0;
+
+ if ( !DBGetContactSettingTString( NULL, "SRFile", "RecvFilesDirAdv", &dbv )) {
+ if ( lstrlen( dbv.ptszVal ) > 0 )
+ lstrcpyn( szTemp, dbv.ptszVal, SIZEOF( szTemp ));
+ DBFreeVariant(&dbv);
+ }
+
+ if ( !szTemp[0] )
+#ifdef _UNICODE
+ mir_sntprintf( szTemp, SIZEOF(szTemp), _T("%%mydocuments%%\\%s"), TranslateT("My Received Files"));
+#else
+ mir_sntprintf( szTemp, SIZEOF(szTemp), _T("%%mydocuments%%\\%s"), "My Received Files");
+#endif
+
+ patchDir( szTemp, SIZEOF(szTemp));
+ RemoveInvalidPathChars(szTemp);
+ lstrcpyn( szDir, szTemp, cchDir );
+}
+
+INT_PTR CALLBACK DlgProcRecvFile(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct FileDlgData *dat;
+
+ dat=(struct FileDlgData*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA);
+ switch (msg) {
+ case WM_INITDIALOG: {
+ TCHAR *contactName;
+ TCHAR szPath[450];
+ CLISTEVENT* cle = (CLISTEVENT*)lParam;
+
+ TranslateDialogDefault(hwndDlg);
+
+ dat=(struct FileDlgData*)mir_calloc(sizeof(struct FileDlgData));
+ SetWindowLongPtr(hwndDlg,GWLP_USERDATA,(LONG_PTR)dat);
+ dat->hContact = cle->hContact;
+ dat->hDbEvent = cle->hDbEvent;
+ dat->hPreshutdownEvent = HookEventMessage(ME_SYSTEM_PRESHUTDOWN,hwndDlg,M_PRESHUTDOWN);
+ dat->dwTicks = GetTickCount();
+
+ EnumChildWindows(hwndDlg,ClipSiblingsChildEnumProc,0);
+
+ Window_SetIcon_IcoLib(hwndDlg, SKINICON_EVENT_FILE);
+ Button_SetIcon_IcoLib(hwndDlg, IDC_ADD, SKINICON_OTHER_ADDCONTACT, LPGEN("Add Contact Permanently to List"));
+ Button_SetIcon_IcoLib(hwndDlg, IDC_DETAILS, SKINICON_OTHER_USERDETAILS, LPGEN("View User's Details"));
+ Button_SetIcon_IcoLib(hwndDlg, IDC_HISTORY, SKINICON_OTHER_HISTORY, LPGEN("View User's History"));
+ Button_SetIcon_IcoLib(hwndDlg, IDC_USERMENU, SKINICON_OTHER_DOWNARROW, LPGEN("User Menu"));
+
+ contactName = cli.pfnGetContactDisplayName( dat->hContact, 0 );
+ SetDlgItemText(hwndDlg,IDC_FROM,contactName);
+ GetContactReceivedFilesDir(dat->hContact,szPath,SIZEOF(szPath),TRUE);
+ SetDlgItemText(hwndDlg,IDC_FILEDIR,szPath);
+ {
+ int i;
+ char idstr[32];
+ DBVARIANT dbv;
+
+ if (shAutoComplete)
+ shAutoComplete(GetWindow(GetDlgItem(hwndDlg,IDC_FILEDIR),GW_CHILD),1);
+
+ for(i=0;i<MAX_MRU_DIRS;i++) {
+ mir_snprintf(idstr, SIZEOF(idstr), "MruDir%d",i);
+ if(DBGetContactSettingTString(NULL,"SRFile",idstr,&dbv)) break;
+ SendDlgItemMessage(hwndDlg,IDC_FILEDIR,CB_ADDSTRING,0,(LPARAM)dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ }
+ }
+
+ CallService(MS_DB_EVENT_MARKREAD,(WPARAM)dat->hContact,(LPARAM)dat->hDbEvent);
+ {
+ DBEVENTINFO dbei={0};
+ TCHAR datetimestr[64];
+ char buf[540];
+
+ dbei.cbSize=sizeof(dbei);
+ dbei.cbBlob=CallService(MS_DB_EVENT_GETBLOBSIZE,(WPARAM)dat->hDbEvent,0);
+ dbei.pBlob=(PBYTE)mir_alloc(dbei.cbBlob);
+ CallService(MS_DB_EVENT_GET,(WPARAM)dat->hDbEvent,(LPARAM)&dbei);
+ dat->fs = cle->lParam ? (HANDLE)cle->lParam : (HANDLE)*(PDWORD)dbei.pBlob;
+ lstrcpynA(buf, (char*)dbei.pBlob+4, min(dbei.cbBlob+1,SIZEOF(buf)));
+ TCHAR* ptszFileName = DbGetEventStringT( &dbei, buf );
+ SetDlgItemText(hwndDlg,IDC_FILENAMES,ptszFileName);
+ mir_free(ptszFileName);
+ lstrcpynA(buf, (char*)dbei.pBlob+4+strlen((char*)dbei.pBlob+4)+1, min((int)(dbei.cbBlob-4-strlen((char*)dbei.pBlob+4)),SIZEOF(buf)));
+ TCHAR* ptszDescription = DbGetEventStringT( &dbei, buf );
+ SetDlgItemText(hwndDlg,IDC_MSG,ptszDescription);
+ mir_free(ptszDescription);
+ mir_free(dbei.pBlob);
+
+ tmi.printTimeStamp(NULL, dbei.timestamp, _T("t d"), datetimestr, SIZEOF(datetimestr), 0);
+ SetDlgItemText(hwndDlg, IDC_DATE, datetimestr);
+ }
+ {
+ char* szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)dat->hContact, 0);
+ if (szProto) {
+ CONTACTINFO ci;
+ int hasName = 0;
+ char buf[128];
+ ZeroMemory(&ci,sizeof(ci));
+
+ ci.cbSize = sizeof(ci);
+ ci.hContact = dat->hContact;
+ ci.szProto = szProto;
+ ci.dwFlag = CNF_UNIQUEID;
+ if (!CallService(MS_CONTACT_GETCONTACTINFO,0,(LPARAM)&ci)) {
+ switch(ci.type) {
+ case CNFT_ASCIIZ:
+ hasName = 1;
+ mir_snprintf(buf, SIZEOF(buf), "%s", ci.pszVal);
+ mir_free(ci.pszVal);
+ break;
+ case CNFT_DWORD:
+ hasName = 1;
+ mir_snprintf(buf, SIZEOF(buf),"%u",ci.dVal);
+ break;
+ } }
+ if (hasName)
+ SetDlgItemTextA(hwndDlg, IDC_NAME, buf );
+ else
+ SetDlgItemText(hwndDlg, IDC_NAME, contactName);
+ } }
+
+ if(DBGetContactSettingByte(dat->hContact,"CList","NotOnList",0)) {
+ RECT rcBtn1,rcBtn2,rcDateCtrl;
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_ADD),&rcBtn1);
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_USERMENU),&rcBtn2);
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_DATE),&rcDateCtrl);
+ SetWindowPos(GetDlgItem(hwndDlg,IDC_DATE),0,0,0,rcDateCtrl.right-rcDateCtrl.left-(rcBtn2.left-rcBtn1.left),rcDateCtrl.bottom-rcDateCtrl.top,SWP_NOZORDER|SWP_NOMOVE);
+ }
+ else if(DBGetContactSettingByte(NULL,"SRFile","AutoAccept",0)) {
+ //don't check auto-min here to fix BUG#647620
+ PostMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDOK,BN_CLICKED),(LPARAM)GetDlgItem(hwndDlg,IDOK));
+ }
+ if(!DBGetContactSettingByte(dat->hContact,"CList","NotOnList",0))
+ ShowWindow(GetDlgItem(hwndDlg, IDC_ADD),SW_HIDE);
+ return TRUE;
+ }
+
+ case WM_MEASUREITEM:
+ return CallService(MS_CLIST_MENUMEASUREITEM,wParam,lParam);
+
+ case WM_DRAWITEM:
+ { LPDRAWITEMSTRUCT dis=(LPDRAWITEMSTRUCT)lParam;
+ if(dis->hwndItem==GetDlgItem(hwndDlg, IDC_PROTOCOL)) {
+ char *szProto;
+
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)dat->hContact,0);
+ if (szProto) {
+ HICON hIcon;
+
+ hIcon=(HICON)CallProtoService(szProto,PS_LOADICON,PLI_PROTOCOL|PLIF_SMALL,0);
+ if (hIcon) {
+ DrawIconEx(dis->hDC,dis->rcItem.left,dis->rcItem.top,hIcon,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0,NULL,DI_NORMAL);
+ DestroyIcon(hIcon);
+ } } } }
+ return CallService(MS_CLIST_MENUDRAWITEM,wParam,lParam);
+
+ case WM_COMMAND:
+ if ( CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(wParam),MPCF_CONTACTMENU), (LPARAM)dat->hContact ))
+ break;
+
+ switch ( LOWORD( wParam )) {
+ case IDC_FILEDIRBROWSE:
+ {
+ TCHAR szDirName[MAX_PATH],szExistingDirName[MAX_PATH];
+
+ GetDlgItemText(hwndDlg,IDC_FILEDIR,szDirName,SIZEOF(szDirName));
+ GetLowestExistingDirName(szDirName,szExistingDirName,SIZEOF(szExistingDirName));
+ if(BrowseForFolder(hwndDlg,szExistingDirName))
+ SetDlgItemText(hwndDlg,IDC_FILEDIR,szExistingDirName);
+ }
+ break;
+
+ case IDOK:
+ { //most recently used directories
+ TCHAR szRecvDir[MAX_PATH],szDefaultRecvDir[MAX_PATH];
+ GetDlgItemText(hwndDlg,IDC_FILEDIR,szRecvDir,SIZEOF(szRecvDir));
+ RemoveInvalidPathChars(szRecvDir);
+ GetContactReceivedFilesDir(NULL,szDefaultRecvDir,SIZEOF(szDefaultRecvDir),TRUE);
+ if(_tcsnicmp(szRecvDir,szDefaultRecvDir,lstrlen(szDefaultRecvDir))) {
+ char idstr[32];
+ int i;
+ DBVARIANT dbv;
+ for(i=MAX_MRU_DIRS-2;i>=0;i--) {
+ mir_snprintf(idstr, SIZEOF(idstr), "MruDir%d",i);
+ if(DBGetContactSettingTString(NULL,"SRFile",idstr,&dbv)) continue;
+ mir_snprintf(idstr, SIZEOF(idstr), "MruDir%d",i+1);
+ DBWriteContactSettingTString(NULL,"SRFile",idstr,dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ }
+ DBWriteContactSettingTString(NULL,"SRFile",idstr,szRecvDir);
+ }
+ }
+ EnableWindow(GetDlgItem(hwndDlg,IDC_FILENAMES),FALSE);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_MSG),FALSE);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_FILEDIR),FALSE);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_FILEDIRBROWSE),FALSE);
+
+ GetDlgItemText(hwndDlg,IDC_FILEDIR,dat->szSavePath,SIZEOF(dat->szSavePath));
+ GetDlgItemText(hwndDlg,IDC_FILE,dat->szFilenames,SIZEOF(dat->szFilenames));
+ GetDlgItemText(hwndDlg,IDC_MSG,dat->szMsg,SIZEOF(dat->szMsg));
+ dat->hwndTransfer = FtMgr_AddTransfer(dat);
+ SetWindowLongPtr( hwndDlg, GWLP_USERDATA, 0);
+ //check for auto-minimize here to fix BUG#647620
+ if(DBGetContactSettingByte(NULL,"SRFile","AutoAccept",0) && DBGetContactSettingByte(NULL,"SRFile","AutoMin",0)) {
+ ShowWindow(hwndDlg,SW_HIDE);
+ ShowWindow(hwndDlg,SW_SHOWMINNOACTIVE);
+ }
+ DestroyWindow(hwndDlg);
+ break;
+
+ case IDCANCEL:
+ if (dat->fs) CallContactService(dat->hContact,PSS_FILEDENYT,(WPARAM)dat->fs,(LPARAM)TranslateT("Cancelled"));
+ dat->fs=NULL; /* the protocol will free the handle */
+ DestroyWindow(hwndDlg);
+ break;
+
+ case IDC_ADD:
+ { ADDCONTACTSTRUCT acs={0};
+
+ acs.handle=dat->hContact;
+ acs.handleType=HANDLE_CONTACT;
+ acs.szProto="";
+ CallService(MS_ADDCONTACT_SHOW,(WPARAM)hwndDlg,(LPARAM)&acs);
+ if(!DBGetContactSettingByte(dat->hContact,"CList","NotOnList",0))
+ ShowWindow(GetDlgItem(hwndDlg,IDC_ADD), SW_HIDE);
+ }
+ break;
+
+ case IDC_USERMENU:
+ { RECT rc;
+ HMENU hMenu=(HMENU)CallService(MS_CLIST_MENUBUILDCONTACT,(WPARAM)dat->hContact,0);
+ GetWindowRect((HWND)lParam,&rc);
+ TrackPopupMenu(hMenu,0,rc.left,rc.bottom,0,hwndDlg,NULL);
+ DestroyMenu(hMenu);
+ }
+ break;
+
+ case IDC_DETAILS:
+ CallService(MS_USERINFO_SHOWDIALOG,(WPARAM)dat->hContact,0);
+ break;
+
+ case IDC_HISTORY:
+ CallService(MS_HISTORY_SHOWCONTACTHISTORY,(WPARAM)dat->hContact,0);
+ break;
+ }
+ break;
+
+ case WM_DESTROY:
+ Window_FreeIcon_IcoLib(hwndDlg);
+ Button_FreeIcon_IcoLib(hwndDlg,IDC_ADD);
+ Button_FreeIcon_IcoLib(hwndDlg,IDC_DETAILS);
+ Button_FreeIcon_IcoLib(hwndDlg,IDC_HISTORY);
+ Button_FreeIcon_IcoLib(hwndDlg,IDC_USERMENU);
+
+ if ( dat ) FreeFileDlgData( dat );
+ break;
+ }
+ return FALSE;
+}
diff --git a/src/modules/srfile/filesenddlg.cpp b/src/modules/srfile/filesenddlg.cpp
new file mode 100644
index 0000000000..94c24a2479
--- /dev/null
+++ b/src/modules/srfile/filesenddlg.cpp
@@ -0,0 +1,363 @@
+/*
+
+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 <sys/types.h>
+#include <sys/stat.h>
+#include "file.h"
+
+static void SetFileListAndSizeControls(HWND hwndDlg,struct FileDlgData *dat)
+{
+ int fileCount=0,dirCount=0,totalSize=0,i;
+ struct _stat statbuf;
+ TCHAR str[64];
+
+ for ( i=0; dat->files[i]; i++ ) {
+ if ( _tstat( dat->files[i], &statbuf ) == 0 ) {
+ if ( statbuf.st_mode & _S_IFDIR)
+ dirCount++;
+ else
+ fileCount++;
+ totalSize += statbuf.st_size;
+ } }
+
+ GetSensiblyFormattedSize(totalSize,str,SIZEOF(str),0,1,NULL);
+ SetDlgItemText(hwndDlg,IDC_TOTALSIZE,str);
+ if(i>1) {
+ TCHAR szFormat[32];
+ if(fileCount && dirCount) {
+ mir_sntprintf(szFormat,SIZEOF(szFormat),_T("%s, %s"),TranslateTS(fileCount==1?_T("%d file"):_T("%d files")),TranslateTS(dirCount==1?_T("%d directory"):_T("%d directories")));
+ mir_sntprintf(str,SIZEOF(str),szFormat,fileCount,dirCount);
+ }
+ else if(fileCount) {
+ lstrcpy(szFormat,TranslateT("%d files"));
+ mir_sntprintf(str,SIZEOF(str),szFormat,fileCount);
+ }
+ else {
+ lstrcpy(szFormat,TranslateT("%d directories"));
+ mir_sntprintf(str,SIZEOF(str),szFormat,dirCount);
+ }
+ SetDlgItemText(hwndDlg,IDC_FILE,str);
+ }
+ else SetDlgItemText(hwndDlg,IDC_FILE,dat->files[0]);
+
+ EnableWindow(GetDlgItem(hwndDlg, IDOK), fileCount || dirCount);
+}
+
+static void FilenameToFileList(HWND hwndDlg, struct FileDlgData* dat, const TCHAR* buf)
+{
+ DWORD dwFileAttributes;
+
+ // Make sure that the file matrix is empty (the user may select files several times)
+ FreeFilesMatrix(&dat->files);
+
+ // Get the file attributes of selection
+ dwFileAttributes = GetFileAttributes( buf );
+ if (dwFileAttributes == INVALID_FILE_ATTRIBUTES)
+ return;
+
+ // Check if the selection is a directory or a file
+ if ( GetFileAttributes( buf ) & FILE_ATTRIBUTE_DIRECTORY ) {
+ const TCHAR* pBuf;
+ int nNumberOfFiles = 0;
+ int nTemp;
+ int fileOffset;
+
+ // :NOTE: The first string in the buffer is the directory, followed by a
+ // NULL separated list of all files
+
+ // fileOffset is the offset to the first file.
+ fileOffset = lstrlen(buf) + 1;
+
+ // Count number of files
+ pBuf = buf + fileOffset;
+ while ( *pBuf ) {
+ pBuf += lstrlen(pBuf) + 1;
+ nNumberOfFiles++;
+ }
+
+ // Allocate memory for a pointer array
+ if (( dat->files = ( TCHAR* *)mir_alloc((nNumberOfFiles + 1) * sizeof(TCHAR*))) == NULL )
+ return;
+
+ // Fill the array
+ pBuf = buf + fileOffset;
+ nTemp = 0;
+ while(*pBuf)
+ {
+ // Allocate space for path+filename
+ int cbFileNameLen = lstrlen( pBuf );
+ dat->files[nTemp] = ( TCHAR* )mir_alloc( sizeof(TCHAR)*(fileOffset + cbFileNameLen + 1));
+
+ // Add path to filename and copy into array
+ #if defined( _UNICODE )
+ CopyMemory(dat->files[nTemp], buf, (fileOffset-1)*sizeof( TCHAR ));
+ dat->files[nTemp][fileOffset-1] = '\\';
+ _tcscpy(dat->files[nTemp] + fileOffset - (buf[fileOffset-2]=='\\'?1:0), pBuf);
+ #else
+ CopyMemory(dat->files[nTemp], buf, fileOffset-1 );
+ dat->files[nTemp][fileOffset-1] = '\\';
+ strcpy(dat->files[nTemp] + fileOffset - (buf[fileOffset-2]=='\\'?1:0), pBuf);
+ #endif
+ // Move pointers to next file...
+ pBuf += cbFileNameLen + 1;
+ nTemp++;
+ }
+ // Terminate array
+ dat->files[nNumberOfFiles] = NULL;
+ }
+ // ...the selection is a single file
+ else
+ {
+ if (( dat->files = ( TCHAR **)mir_alloc(2 * sizeof( TCHAR*))) == NULL ) // Leaks when aborted
+ return;
+
+ dat->files[0] = mir_tstrdup(buf);
+ dat->files[1] = NULL;
+ }
+
+ // Update dialog text with new file selection
+ SetFileListAndSizeControls(hwndDlg, dat);
+}
+
+#define M_FILECHOOSEDONE (WM_USER+100)
+void __cdecl ChooseFilesThread(void* param)
+{
+ HWND hwndDlg = ( HWND )param;
+ TCHAR filter[128], *pfilter;
+ TCHAR* buf = ( TCHAR* )mir_alloc( sizeof(TCHAR)*32767 );
+ if ( buf == NULL )
+ PostMessage( hwndDlg, M_FILECHOOSEDONE, 0, ( LPARAM )( TCHAR* )NULL );
+ else {
+ OPENFILENAME ofn = {0};
+ ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400;
+ ofn.hwndOwner = hwndDlg;
+ lstrcpy( filter, TranslateT( "All Files" ));
+ lstrcat( filter, _T(" (*)" ));
+ pfilter = filter + lstrlen( filter )+1;
+ lstrcpy( pfilter, _T( "*" ));
+ pfilter = filter + lstrlen( filter )+1;
+ pfilter[ 0 ] = '\0';
+ ofn.lpstrFilter = filter;
+ ofn.lpstrFile = buf; *buf = 0;
+ ofn.nMaxFile = 32767;
+ ofn.Flags = OFN_NOCHANGEDIR | OFN_FILEMUSTEXIST | OFN_ALLOWMULTISELECT | OFN_EXPLORER | OFN_HIDEREADONLY | OFN_DONTADDTORECENT;
+ if ( GetOpenFileName( &ofn ))
+ PostMessage( hwndDlg, M_FILECHOOSEDONE, 0, ( LPARAM )buf );
+ else {
+ mir_free( buf );
+ PostMessage( hwndDlg, M_FILECHOOSEDONE, 0, ( LPARAM )( TCHAR* )NULL );
+} } }
+
+static BOOL CALLBACK ClipSiblingsChildEnumProc(HWND hwnd,LPARAM)
+{
+ SetWindowLongPtr(hwnd,GWL_STYLE,GetWindowLongPtr(hwnd,GWL_STYLE)|WS_CLIPSIBLINGS);
+ return TRUE;
+}
+
+static WNDPROC OldSendEditProc;
+static LRESULT CALLBACK SendEditSubclassProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
+{
+ switch(msg) {
+ case WM_CHAR:
+ if(wParam=='\n' && GetKeyState(VK_CONTROL)&0x8000) {
+ PostMessage(GetParent(hwnd),WM_COMMAND,IDOK,0);
+ return 0;
+ }
+ break;
+ case WM_SYSCHAR:
+ if((wParam=='s' || wParam=='S') && GetKeyState(VK_MENU)&0x8000) {
+ PostMessage(GetParent(hwnd),WM_COMMAND,IDOK,0);
+ return 0;
+ }
+ break;
+ }
+ return CallWindowProc(OldSendEditProc,hwnd,msg,wParam,lParam);
+}
+
+INT_PTR CALLBACK DlgProcSendFile(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct FileDlgData *dat;
+
+ dat=(struct FileDlgData*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA);
+ switch (msg) {
+ case WM_INITDIALOG:
+ {
+ struct FileSendData *fsd=(struct FileSendData*)lParam;
+
+ dat=(struct FileDlgData*)mir_calloc(sizeof(struct FileDlgData));
+ SetWindowLongPtr(hwndDlg,GWLP_USERDATA,(LONG_PTR)dat);
+ dat->hContact=fsd->hContact;
+ dat->send=1;
+ dat->hPreshutdownEvent=HookEventMessage(ME_SYSTEM_PRESHUTDOWN,hwndDlg,M_PRESHUTDOWN);
+ dat->fs=NULL;
+ dat->dwTicks=GetTickCount();
+
+ TranslateDialogDefault(hwndDlg);
+ EnumChildWindows(hwndDlg,ClipSiblingsChildEnumProc,0);
+ OldSendEditProc=(WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_MSG),GWLP_WNDPROC,(LONG_PTR)SendEditSubclassProc);
+
+ Window_SetIcon_IcoLib(hwndDlg, SKINICON_EVENT_FILE);
+ Button_SetIcon_IcoLib(hwndDlg, IDC_DETAILS, SKINICON_OTHER_USERDETAILS, LPGEN("View User's Details"));
+ Button_SetIcon_IcoLib(hwndDlg, IDC_HISTORY, SKINICON_OTHER_HISTORY, LPGEN("View User's History"));
+ Button_SetIcon_IcoLib(hwndDlg, IDC_USERMENU, SKINICON_OTHER_DOWNARROW, LPGEN("User Menu"));
+
+ EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
+
+ if(fsd->ppFiles!=NULL && fsd->ppFiles[0]!=NULL) {
+ int totalCount,i;
+ for(totalCount=0;fsd->ppFiles[totalCount];totalCount++);
+ dat->files = ( TCHAR** )mir_alloc( sizeof(TCHAR*)*(totalCount+1)); // Leaks
+ for(i=0;i<totalCount;i++)
+ dat->files[i] = mir_tstrdup( fsd->ppFiles[i] );
+ dat->files[totalCount]=NULL;
+ SetFileListAndSizeControls(hwndDlg,dat);
+ }
+ {
+ char *szProto;
+ TCHAR* contactName = cli.pfnGetContactDisplayName( dat->hContact, 0 );
+ SetDlgItemText(hwndDlg,IDC_TO,contactName);
+
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)dat->hContact,0);
+ if (szProto) {
+ CONTACTINFO ci;
+ int hasName = 0;
+ char buf[128];
+ ZeroMemory(&ci,sizeof(ci));
+
+ ci.cbSize = sizeof(ci);
+ ci.hContact = dat->hContact;
+ ci.szProto = szProto;
+ ci.dwFlag = CNF_UNIQUEID;
+ if (!CallService(MS_CONTACT_GETCONTACTINFO,0,(LPARAM)&ci)) {
+ switch(ci.type) {
+ case CNFT_ASCIIZ:
+ hasName = 1;
+ mir_snprintf(buf, SIZEOF(buf), "%s", ci.pszVal);
+ mir_free(ci.pszVal);
+ break;
+ case CNFT_DWORD:
+ hasName = 1;
+ mir_snprintf(buf, SIZEOF(buf),"%u",ci.dVal);
+ break;
+ } }
+
+ if ( hasName )
+ SetDlgItemTextA(hwndDlg,IDC_NAME,buf);
+ else
+ SetDlgItemText(hwndDlg,IDC_NAME,contactName);
+ } }
+
+ if ( fsd->ppFiles == NULL ) {
+ EnableWindow(hwndDlg, FALSE);
+ dat->closeIfFileChooseCancelled=1;
+ PostMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_CHOOSE,BN_CLICKED),(LPARAM)GetDlgItem(hwndDlg,IDC_CHOOSE));
+ }
+ return TRUE;
+ }
+
+ case WM_MEASUREITEM:
+ return CallService(MS_CLIST_MENUMEASUREITEM,wParam,lParam);
+
+ case WM_DRAWITEM:
+ {
+ LPDRAWITEMSTRUCT dis=(LPDRAWITEMSTRUCT)lParam;
+ if(dis->hwndItem==GetDlgItem(hwndDlg, IDC_PROTOCOL)) {
+ char *szProto;
+
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)dat->hContact,0);
+ if (szProto) {
+ HICON hIcon = (HICON)CallProtoService(szProto,PS_LOADICON,PLI_PROTOCOL|PLIF_SMALL,0);
+ if (hIcon) {
+ DrawIconEx(dis->hDC,dis->rcItem.left,dis->rcItem.top,hIcon,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0,NULL,DI_NORMAL);
+ DestroyIcon(hIcon);
+ } } } }
+ return CallService(MS_CLIST_MENUDRAWITEM,wParam,lParam);
+
+ case M_FILECHOOSEDONE:
+ if( lParam != 0 ) {
+ FilenameToFileList( hwndDlg, dat, ( TCHAR* )lParam );
+ mir_free(( TCHAR* )lParam );
+ dat->closeIfFileChooseCancelled = 0;
+ }
+ else if(dat->closeIfFileChooseCancelled) DestroyWindow(hwndDlg);
+ EnableWindow(hwndDlg,TRUE);
+ break;
+
+ case WM_COMMAND:
+ if(CallService(MS_CLIST_MENUPROCESSCOMMAND,MAKEWPARAM(LOWORD(wParam),MPCF_CONTACTMENU),(LPARAM)dat->hContact))
+ break;
+ switch (LOWORD(wParam))
+ {
+ case IDC_CHOOSE:
+ EnableWindow(hwndDlg,FALSE);
+ //GetOpenFileName() creates its own message queue which prevents any incoming events being processed
+ forkthread(ChooseFilesThread,0,hwndDlg);
+ break;
+ case IDOK:
+ EnableWindow(GetDlgItem(hwndDlg,IDC_FILENAME),FALSE);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_MSG),FALSE);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_CHOOSE),FALSE);
+
+ GetDlgItemText(hwndDlg,IDC_FILEDIR,dat->szSavePath,SIZEOF(dat->szSavePath));
+ GetDlgItemText(hwndDlg,IDC_FILE,dat->szFilenames,SIZEOF(dat->szFilenames));
+ GetDlgItemText(hwndDlg,IDC_MSG,dat->szMsg,SIZEOF(dat->szMsg));
+ dat->hwndTransfer = FtMgr_AddTransfer(dat);
+ SetWindowLongPtr( hwndDlg, GWLP_USERDATA, 0);
+ DestroyWindow(hwndDlg);
+ return TRUE;
+
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ return TRUE;
+
+ case IDC_USERMENU:
+ { RECT rc;
+ HMENU hMenu=(HMENU)CallService(MS_CLIST_MENUBUILDCONTACT,(WPARAM)dat->hContact,0);
+ GetWindowRect((HWND)lParam,&rc);
+ TrackPopupMenu(hMenu,0,rc.left,rc.bottom,0,hwndDlg,NULL);
+ DestroyMenu(hMenu);
+ break;
+ }
+ case IDC_DETAILS:
+ CallService(MS_USERINFO_SHOWDIALOG,(WPARAM)dat->hContact,0);
+ return TRUE;
+ case IDC_HISTORY:
+ CallService(MS_HISTORY_SHOWCONTACTHISTORY,(WPARAM)dat->hContact,0);
+ return TRUE;
+ }
+ break;
+
+ case WM_DESTROY:
+ Window_FreeIcon_IcoLib(hwndDlg);
+ Button_FreeIcon_IcoLib(hwndDlg,IDC_DETAILS);
+ Button_FreeIcon_IcoLib(hwndDlg,IDC_HISTORY);
+ Button_FreeIcon_IcoLib(hwndDlg,IDC_USERMENU);
+
+ if ( dat )
+ FreeFileDlgData( dat );
+
+ SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_MSG),GWLP_WNDPROC,(LONG_PTR)OldSendEditProc);
+ return TRUE;
+ }
+ return FALSE;
+}
diff --git a/src/modules/srfile/filexferdlg.cpp b/src/modules/srfile/filexferdlg.cpp
new file mode 100644
index 0000000000..0a6246dea0
--- /dev/null
+++ b/src/modules/srfile/filexferdlg.cpp
@@ -0,0 +1,799 @@
+/*
+
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2000-2010 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 <io.h>
+#include "file.h"
+
+#define HM_RECVEVENT (WM_USER+10)
+
+static int CheckVirusScanned(HWND hwnd,struct FileDlgData *dat,int i)
+{
+ if(dat->send) return 1;
+ if(dat->fileVirusScanned == NULL) return 0;
+ if(dat->fileVirusScanned[i]) return 1;
+ if(DBGetContactSettingByte(NULL,"SRFile","WarnBeforeOpening",1)==0) return 1;
+ return IDYES==MessageBox(hwnd,TranslateT("This file has not yet been scanned for viruses. Are you certain you want to open it?"),TranslateT("File Received"),MB_YESNO|MB_DEFBUTTON2);
+}
+
+#define M_VIRUSSCANDONE (WM_USER+100)
+struct virusscanthreadstartinfo {
+ TCHAR *szFile;
+ int returnCode;
+ HWND hwndReply;
+};
+
+TCHAR* PFTS_StringToTchar( int flags, const PROTOCHAR* s )
+{
+#ifdef _UNICODE
+ if ( flags & PFTS_UTF )
+ return Utf8DecodeUcs2(( char* )s );
+ else if ( flags & PFTS_UNICODE )
+ return mir_tstrdup( s );
+ else
+ return mir_a2t(( char* )s );
+#else
+ if ( flags & PFTS_UTF ) {
+ char *szAnsi = mir_strdup(( char* )s );
+ return Utf8Decode(szAnsi, NULL);
+ }
+ else
+ return mir_strdup( s );
+#endif
+}
+
+int PFTS_CompareWithTchar( PROTOFILETRANSFERSTATUS* ft, const PROTOCHAR* s, TCHAR* r )
+{
+#ifdef _UNICODE
+ if ( ft->flags & PFTS_UTF ) {
+ TCHAR* ts = Utf8DecodeUcs2(( char* )s );
+ int res = _tcscmp( ts, r );
+ mir_free( ts );
+ return res;
+ }
+ else if ( ft->flags & PFTS_UNICODE )
+ return _tcscmp( s, r );
+ else {
+ TCHAR* ts = mir_a2t(( char* )s );
+ int res = _tcscmp( ts, r );
+ mir_free( ts );
+ return res;
+ }
+#else
+ if ( ft->flags & PFTS_UTF ) {
+ char *ts = NEWSTR_ALLOCA(( char* )s );
+ return _tcscmp( Utf8Decode(( char* )ts, NULL), r );
+ }
+ else
+ return _tcscmp( s, r );
+#endif
+}
+
+static void SetOpenFileButtonStyle(HWND hwndButton,int enabled)
+{
+ EnableWindow(hwndButton,enabled);
+}
+
+void FillSendData( FileDlgData* dat, DBEVENTINFO& dbei )
+{
+ dbei.cbSize = sizeof(dbei);
+ dbei.szModule = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)dat->hContact,0);
+ dbei.eventType = EVENTTYPE_FILE;
+ dbei.flags = DBEF_SENT;
+ dbei.timestamp = time(NULL);
+ #if defined( _UNICODE )
+ char *szFileNames = Utf8EncodeT(dat->szFilenames), *szMsg = Utf8EncodeT(dat->szMsg);
+ dbei.flags |= DBEF_UTF;
+ #else
+ char *szFileNames = dat->szFilenames, *szMsg = dat->szMsg;
+ #endif
+
+ dbei.cbBlob = sizeof(DWORD) + lstrlenA(szFileNames)+lstrlenA(szMsg)+2;
+ dbei.pBlob=(PBYTE)mir_alloc(dbei.cbBlob);
+ *(PDWORD)dbei.pBlob=0;
+ lstrcpyA((char*)dbei.pBlob+sizeof(DWORD),szFileNames);
+ lstrcpyA((char*)dbei.pBlob+sizeof(DWORD)+lstrlenA(szFileNames)+1,szMsg);
+
+ #if defined( _UNICODE )
+ mir_free( szFileNames ), mir_free( szMsg );
+ #endif
+}
+
+static void __cdecl RunVirusScannerThread(struct virusscanthreadstartinfo *info)
+{
+ PROCESS_INFORMATION pi;
+ STARTUPINFO si={0};
+ DBVARIANT dbv;
+ TCHAR szCmdLine[768];
+
+ if (!DBGetContactSettingTString(NULL,"SRFile", "ScanCmdLine", &dbv))
+ {
+ if(dbv.ptszVal[0])
+ {
+ TCHAR *pszReplace;
+ si.cb=sizeof(si);
+ pszReplace = _tcsstr(dbv.ptszVal, _T("%f"));
+ if (pszReplace)
+ {
+ if ( info->szFile[_tcslen(info->szFile) - 1] == '\\')
+ info->szFile[_tcslen(info->szFile) - 1] = '\0';
+ *pszReplace = 0;
+ mir_sntprintf(szCmdLine, SIZEOF(szCmdLine), _T("%s\"%s\"%s"), dbv.ptszVal, info->szFile, pszReplace+2);
+ }
+ else lstrcpyn(szCmdLine, dbv.ptszVal, SIZEOF(szCmdLine));
+ if(CreateProcess(NULL,szCmdLine,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi)) {
+ if(WaitForSingleObject(pi.hProcess,3600*1000)==WAIT_OBJECT_0)
+ PostMessage(info->hwndReply,M_VIRUSSCANDONE,info->returnCode,0);
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ }
+ }
+ DBFreeVariant(&dbv);
+ }
+ mir_free(info->szFile);
+ mir_free(info);
+}
+
+static void SetFilenameControls(HWND hwndDlg, struct FileDlgData *dat, PROTOFILETRANSFERSTATUS *fts)
+{
+ TCHAR msg[MAX_PATH];
+ TCHAR *fnbuf = NULL, *fn = NULL;
+ SHFILEINFO shfi = {0};
+
+ if ( fts->tszCurrentFile ) {
+ fnbuf = mir_tstrdup( fts->tszCurrentFile );
+ if (( fn = _tcsrchr( fnbuf, '\\' )) == NULL )
+ fn = fnbuf;
+ else fn++;
+ }
+
+ if (dat->hIcon) DestroyIcon(dat->hIcon); dat->hIcon = NULL;
+
+ if (fn && (fts->totalFiles > 1)) {
+ mir_sntprintf(msg, SIZEOF(msg), _T("%s: %s (%d %s %d)"),
+ cli.pfnGetContactDisplayName( fts->hContact, 0 ),
+ fn, fts->currentFileNumber+1, TranslateT("of"), fts->totalFiles);
+
+ SHGetFileInfo(fn, FILE_ATTRIBUTE_DIRECTORY, &shfi, sizeof(shfi), SHGFI_USEFILEATTRIBUTES|SHGFI_ICON|SHGFI_SMALLICON);
+ dat->hIcon = shfi.hIcon;
+ }
+ else if (fn) {
+ mir_sntprintf(msg, SIZEOF(msg), _T("%s: %s"), cli.pfnGetContactDisplayName( fts->hContact, 0 ), fn);
+
+ SHGetFileInfo(fn, FILE_ATTRIBUTE_NORMAL, &shfi, sizeof(shfi), SHGFI_USEFILEATTRIBUTES|SHGFI_ICON|SHGFI_SMALLICON);
+ dat->hIcon = shfi.hIcon;
+ }
+ else {
+ lstrcpyn(msg, cli.pfnGetContactDisplayName( fts->hContact, 0 ), SIZEOF(msg));
+ HICON hIcon = LoadSkinIcon(SKINICON_OTHER_DOWNARROW);
+ dat->hIcon = CopyIcon(hIcon);
+ IconLib_ReleaseIcon(hIcon, NULL);
+ }
+
+ mir_free( fnbuf );
+
+ SendDlgItemMessage(hwndDlg, IDC_FILEICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)dat->hIcon);
+ SetDlgItemText(hwndDlg, IDC_CONTACTNAME, msg);
+}
+
+enum { FTS_TEXT, FTS_PROGRESS, FTS_OPEN };
+static void SetFtStatus(HWND hwndDlg, TCHAR *text, int mode)
+{
+ SetDlgItemText(hwndDlg,IDC_STATUS,TranslateTS(text));
+ SetDlgItemText(hwndDlg,IDC_TRANSFERCOMPLETED,TranslateTS(text));
+
+ ShowWindow(GetDlgItem(hwndDlg,IDC_STATUS), (mode == FTS_TEXT)?SW_SHOW:SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg,IDC_ALLFILESPROGRESS), (mode == FTS_PROGRESS)?SW_SHOW:SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg,IDC_TRANSFERCOMPLETED), (mode == FTS_OPEN)?SW_SHOW:SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg,IDC_FILEICON), (mode == FTS_OPEN)?SW_SHOW:SW_HIDE);
+}
+
+static void HideProgressControls(HWND hwndDlg)
+{
+ RECT rc;
+ char buf[64];
+
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_ALLPRECENTS), &rc);
+ MapWindowPoints(NULL, hwndDlg, (LPPOINT)&rc, 2);
+ SetWindowPos(hwndDlg, NULL, 0, 0, 100, rc.bottom+3, SWP_NOMOVE|SWP_NOZORDER);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_ALLTRANSFERRED), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_ALLSPEED), SW_HIDE);
+
+ _strtime(buf);
+ SetDlgItemTextA(hwndDlg, IDC_ALLPRECENTS, buf);
+
+ PostMessage(GetParent(hwndDlg), WM_FT_RESIZE, 0, (LPARAM)hwndDlg);
+}
+
+static int FileTransferDlgResizer(HWND, LPARAM, UTILRESIZECONTROL *urc)
+{
+ switch(urc->wId) {
+ case IDC_CONTACTNAME:
+ case IDC_STATUS:
+ case IDC_ALLFILESPROGRESS:
+ case IDC_TRANSFERCOMPLETED:
+ return RD_ANCHORX_WIDTH|RD_ANCHORY_TOP;
+ case IDC_FRAME:
+ return RD_ANCHORX_WIDTH|RD_ANCHORY_BOTTOM;
+ case IDC_ALLPRECENTS:
+ case IDCANCEL:
+ case IDC_OPENFILE:
+ case IDC_OPENFOLDER:
+ return RD_ANCHORX_RIGHT|RD_ANCHORY_TOP;
+
+ case IDC_ALLTRANSFERRED:
+ urc->rcItem.right = urc->rcItem.left + (urc->rcItem.right - urc->rcItem.left - urc->dlgOriginalSize.cx + urc->dlgNewSize.cx) / 3;
+ return RD_ANCHORX_CUSTOM|RD_ANCHORY_CUSTOM;
+
+ case IDC_ALLSPEED:
+ urc->rcItem.right = urc->rcItem.right - urc->dlgOriginalSize.cx + urc->dlgNewSize.cx;
+ urc->rcItem.left = urc->rcItem.left + (urc->rcItem.right - urc->rcItem.left) / 3;
+ return RD_ANCHORX_CUSTOM|RD_ANCHORY_CUSTOM;
+ }
+ return RD_ANCHORX_LEFT|RD_ANCHORY_TOP;
+}
+
+INT_PTR CALLBACK DlgProcFileTransfer(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ FileDlgData *dat = (FileDlgData*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ dat = (FileDlgData*)lParam;
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)dat);
+ dat->hNotifyEvent=HookEventMessage(ME_PROTO_ACK,hwndDlg,HM_RECVEVENT);
+ dat->transferStatus.currentFileNumber = -1;
+ if(dat->send) {
+ dat->fs=(HANDLE)CallContactService(dat->hContact,PSS_FILET,(WPARAM)dat->szMsg,(LPARAM)dat->files);
+ SetFtStatus(hwndDlg, LPGENT("Request sent, waiting for acceptance..."), FTS_TEXT);
+ SetOpenFileButtonStyle(GetDlgItem(hwndDlg,IDC_OPENFILE),1);
+ dat->waitingForAcceptance=1;
+ // hide "open" button since it may cause potential access violations...
+ ShowWindow(GetDlgItem(hwndDlg, IDC_OPENFILE), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_OPENFOLDER), SW_HIDE);
+ }
+ else { //recv
+ CreateDirectoryTreeT(dat->szSavePath);
+ dat->fs=(HANDLE)CallContactService(dat->hContact,PSS_FILEALLOWT,(WPARAM)dat->fs,(LPARAM)dat->szSavePath);
+ dat->transferStatus.tszWorkingDir = mir_tstrdup(dat->szSavePath);
+ if(DBGetContactSettingByte(dat->hContact,"CList","NotOnList",0)) dat->resumeBehaviour=FILERESUME_ASK;
+ else dat->resumeBehaviour=DBGetContactSettingByte(NULL,"SRFile","IfExists",FILERESUME_ASK);
+ SetFtStatus(hwndDlg, LPGENT("Waiting for connection..."), FTS_TEXT);
+ }
+ {
+ /* check we actually got an fs handle back from the protocol */
+ if (!dat->fs) {
+ SetFtStatus(hwndDlg, LPGENT("Unable to initiate transfer."), FTS_TEXT);
+ dat->waitingForAcceptance=0;
+ }
+ }
+ { LOGFONT lf;
+ HFONT hFont;
+ hFont=(HFONT)SendDlgItemMessage(hwndDlg,IDC_CONTACTNAME,WM_GETFONT,0,0);
+ GetObject(hFont,sizeof(lf),&lf);
+ lf.lfWeight=FW_BOLD;
+ hFont=CreateFontIndirect(&lf);
+ SendDlgItemMessage(hwndDlg,IDC_CONTACTNAME,WM_SETFONT,(WPARAM)hFont,0);
+ }
+
+ { SHFILEINFO shfi = {0};
+ SHGetFileInfo(_T(""), FILE_ATTRIBUTE_DIRECTORY, &shfi, sizeof(shfi), SHGFI_USEFILEATTRIBUTES|SHGFI_ICON|SHGFI_SMALLICON);
+ dat->hIconFolder = shfi.hIcon;
+ }
+
+ dat->hIcon = NULL;
+
+ SendDlgItemMessage(hwndDlg, IDC_CONTACT, BM_SETIMAGE, IMAGE_ICON,
+ (LPARAM)LoadSkinnedProtoIcon((char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)dat->hContact, 0), ID_STATUS_ONLINE));
+ SendDlgItemMessage(hwndDlg, IDC_CONTACT, BUTTONADDTOOLTIP, (WPARAM)LPGEN("Contact menu"), 0);
+ SendDlgItemMessage(hwndDlg, IDC_CONTACT, BUTTONSETASFLATBTN, 0, 0);
+
+ Button_SetIcon_IcoLib(hwndDlg, IDC_OPENFILE, SKINICON_OTHER_DOWNARROW, LPGEN("Open..."));
+ SendDlgItemMessage(hwndDlg, IDC_OPENFILE, BUTTONSETASPUSHBTN, 0, 0);
+
+ SendDlgItemMessage(hwndDlg, IDC_OPENFOLDER, BM_SETIMAGE, IMAGE_ICON, (LPARAM)dat->hIconFolder);
+ SendDlgItemMessage(hwndDlg, IDC_OPENFOLDER, BUTTONADDTOOLTIP, (WPARAM)LPGEN("Open folder"), 0);
+ SendDlgItemMessage(hwndDlg, IDC_OPENFOLDER, BUTTONSETASFLATBTN, 0, 0);
+
+ Button_SetIcon_IcoLib(hwndDlg, IDCANCEL, SKINICON_OTHER_DELETE, LPGEN("Cancel"));
+
+ SetDlgItemText(hwndDlg, IDC_CONTACTNAME, cli.pfnGetContactDisplayName( dat->hContact, 0 ));
+
+ if(!dat->waitingForAcceptance) SetTimer(hwndDlg,1,1000,NULL);
+ return TRUE;
+ case WM_TIMER:
+ MoveMemory(dat->bytesRecvedHistory+1,dat->bytesRecvedHistory,sizeof(dat->bytesRecvedHistory)-sizeof(dat->bytesRecvedHistory[0]));
+ dat->bytesRecvedHistory[0]=dat->transferStatus.totalProgress;
+ if ( dat->bytesRecvedHistorySize < SIZEOF(dat->bytesRecvedHistory))
+ dat->bytesRecvedHistorySize++;
+
+ { TCHAR szSpeed[32], szTime[32], szDisplay[96];
+ SYSTEMTIME st;
+ ULARGE_INTEGER li;
+ FILETIME ft;
+
+ GetSensiblyFormattedSize((dat->bytesRecvedHistory[0]-dat->bytesRecvedHistory[dat->bytesRecvedHistorySize-1])/dat->bytesRecvedHistorySize,szSpeed,SIZEOF(szSpeed),0,1,NULL);
+ if(dat->bytesRecvedHistory[0]==dat->bytesRecvedHistory[dat->bytesRecvedHistorySize-1])
+ lstrcpy(szTime,_T("??:??:??"));
+ else {
+ li.QuadPart=BIGI(10000000)*(dat->transferStatus.currentFileSize-dat->transferStatus.currentFileProgress)*dat->bytesRecvedHistorySize/(dat->bytesRecvedHistory[0]-dat->bytesRecvedHistory[dat->bytesRecvedHistorySize-1]);
+ ft.dwHighDateTime=li.HighPart; ft.dwLowDateTime=li.LowPart;
+ FileTimeToSystemTime(&ft,&st);
+ GetTimeFormat(LOCALE_USER_DEFAULT,TIME_FORCE24HOURFORMAT|TIME_NOTIMEMARKER,&st,NULL,szTime,SIZEOF(szTime));
+ }
+ if(dat->bytesRecvedHistory[0]!=dat->bytesRecvedHistory[dat->bytesRecvedHistorySize-1]) {
+ li.QuadPart=BIGI(10000000)*(dat->transferStatus.totalBytes-dat->transferStatus.totalProgress)*dat->bytesRecvedHistorySize/(dat->bytesRecvedHistory[0]-dat->bytesRecvedHistory[dat->bytesRecvedHistorySize-1]);
+ ft.dwHighDateTime=li.HighPart; ft.dwLowDateTime=li.LowPart;
+ FileTimeToSystemTime(&ft,&st);
+ GetTimeFormat(LOCALE_USER_DEFAULT,TIME_FORCE24HOURFORMAT|TIME_NOTIMEMARKER,&st,NULL,szTime,SIZEOF(szTime));
+ }
+
+ mir_sntprintf(szDisplay,SIZEOF(szDisplay),_T("%s/%s (%s %s)"),szSpeed,TranslateT("sec"),szTime,TranslateT("remaining"));
+ SetDlgItemText(hwndDlg,IDC_ALLSPEED,szDisplay);
+ }
+ break;
+
+ case WM_MEASUREITEM:
+ return CallService(MS_CLIST_MENUMEASUREITEM,wParam,lParam);
+
+ case WM_DRAWITEM:
+ return CallService(MS_CLIST_MENUDRAWITEM,wParam,lParam);
+
+ case WM_FT_CLEANUP:
+ if (!dat->fs)
+ {
+ PostMessage(GetParent(hwndDlg), WM_FT_REMOVE, 0, (LPARAM)hwndDlg);
+ DestroyWindow(hwndDlg);
+ }
+ break;
+
+ case WM_COMMAND:
+ if ( CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(wParam),MPCF_CONTACTMENU), (LPARAM)dat->hContact ))
+ break;
+
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ case IDCANCEL:
+ PostMessage(GetParent(hwndDlg), WM_FT_REMOVE, 0, (LPARAM)hwndDlg);
+ DestroyWindow(hwndDlg);
+ break;
+
+ case IDC_CONTACT:
+ { RECT rc;
+ HMENU hMenu=(HMENU)CallService(MS_CLIST_MENUBUILDCONTACT,(WPARAM)dat->hContact,0);
+ GetWindowRect((HWND)lParam,&rc);
+ TrackPopupMenu(hMenu,0,rc.left,rc.bottom,0,hwndDlg,NULL);
+ DestroyMenu(hMenu);
+ break;
+ }
+
+ case IDC_TRANSFERCOMPLETED:
+ if (dat->transferStatus.currentFileNumber <= 1 && CheckVirusScanned(hwndDlg, dat, 0))
+ {
+ ShellExecute(NULL, NULL, dat->files[0], NULL, NULL, SW_SHOW);
+ break;
+ }
+
+ case IDC_OPENFOLDER:
+ if ( dat )
+ {
+ TCHAR* path = dat->transferStatus.tszWorkingDir;
+ if (!path || !path[0])
+ {
+ path = NEWTSTR_ALLOCA(dat->transferStatus.tszCurrentFile);
+ TCHAR* p = _tcsrchr(path, '\\'); if (p) *p = 0;
+ }
+
+ if (path) ShellExecute(NULL, _T("open"), path, NULL, NULL, SW_SHOW);
+ }
+ break;
+
+ case IDC_OPENFILE:
+ {
+ TCHAR **files;
+ HMENU hMenu;
+ RECT rc;
+ int ret;
+
+ if (dat->send)
+ if (dat->files == NULL)
+ files = dat->transferStatus.ptszFiles;
+ else
+ files = dat->files;
+ else
+ files=dat->files;
+
+ hMenu = CreatePopupMenu();
+ AppendMenu(hMenu, MF_STRING, 1, TranslateT("Open folder"));
+ AppendMenu(hMenu, MF_SEPARATOR, 0, 0);
+
+ if (files && *files)
+ {
+ int i, limit;
+ TCHAR *pszFilename,*pszNewFileName;
+
+ if (dat->send)
+ limit = dat->transferStatus.totalFiles;
+ else
+ limit = dat->transferStatus.currentFileNumber;
+
+ // Loop over all transfered files and add them to the menu
+ for (i = 0; i < limit; i++) {
+ pszFilename = _tcsrchr(files[i], '\\');
+ if (pszFilename == NULL)
+ pszFilename = files[i];
+ else
+ pszFilename++;
+ {
+ if (pszFilename) {
+ size_t cbFileNameLen = _tcslen(pszFilename);
+
+ pszNewFileName = (TCHAR*)mir_alloc( cbFileNameLen*2*sizeof( TCHAR ));
+ TCHAR *p = pszNewFileName;
+ for (size_t pszlen=0; pszlen < cbFileNameLen; pszlen++) {
+ *p++ = pszFilename[pszlen];
+ if (pszFilename[pszlen]=='&')
+ *p++ = '&';
+ }
+ *p = '\0';
+ AppendMenu(hMenu, MF_STRING, i+10, pszNewFileName);
+ mir_free(pszNewFileName);
+ }
+ }
+ }
+ }
+
+ GetWindowRect((HWND)lParam, &rc);
+ CheckDlgButton(hwndDlg, IDC_OPENFILE, BST_CHECKED);
+ ret = TrackPopupMenu(hMenu, TPM_RETURNCMD|TPM_RIGHTALIGN, rc.right, rc.bottom, 0, hwndDlg, NULL);
+ CheckDlgButton(hwndDlg, IDC_OPENFILE, BST_UNCHECKED);
+ DestroyMenu(hMenu);
+
+ if (ret == 1)
+ {
+ TCHAR* path = dat->transferStatus.tszWorkingDir;
+ if (!path || !path[0])
+ {
+ path = NEWTSTR_ALLOCA(dat->transferStatus.tszCurrentFile);
+ TCHAR* p = _tcsrchr(path, '\\'); if (p) *p = 0;
+ }
+
+ if (path) ShellExecute(NULL, _T("open"), path, NULL, NULL, SW_SHOW);
+ }
+ else if (ret && CheckVirusScanned(hwndDlg, dat, ret))
+ ShellExecute(NULL, NULL, files[ret-10], NULL, NULL, SW_SHOW);
+
+ break;
+ }
+ }
+ break;
+ case M_FILEEXISTSDLGREPLY:
+ { PROTOFILERESUME *pfr=(PROTOFILERESUME*)lParam;
+ TCHAR *szOriginalFilename=(TCHAR*)wParam;
+ char *szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)dat->hContact,0);
+
+ EnableWindow(hwndDlg,TRUE);
+ switch(pfr->action) {
+ case FILERESUME_CANCEL:
+ if (dat->fs) CallContactService(dat->hContact,PSS_FILECANCEL,(WPARAM)dat->fs,0);
+ dat->fs=NULL;
+ mir_free(szOriginalFilename);
+ if(pfr->szFilename) mir_free((char*)pfr->szFilename);
+ mir_free(pfr);
+ return 0;
+ case FILERESUME_RESUMEALL:
+ case FILERESUME_OVERWRITEALL:
+ dat->resumeBehaviour=pfr->action;
+ pfr->action&=~FILERESUMEF_ALL;
+ break;
+ case FILERESUME_RENAMEALL:
+ pfr->action=FILERESUME_RENAME;
+ { TCHAR *pszExtension,*pszFilename;
+ int i;
+ if((pszFilename = _tcsrchr(szOriginalFilename,'\\'))==NULL) pszFilename=szOriginalFilename;
+ if((pszExtension = _tcsrchr(pszFilename+1,'.'))==NULL) pszExtension=pszFilename+lstrlen(pszFilename);
+ if(pfr->szFilename) mir_free((TCHAR*)pfr->szFilename);
+ pfr->szFilename = (TCHAR*)mir_alloc(sizeof(TCHAR)*((pszExtension-szOriginalFilename)+21+lstrlen(pszExtension)));
+ for(i=1;;i++) {
+ _stprintf((TCHAR*)pfr->szFilename,_T("%.*s (%u)%s"),pszExtension-szOriginalFilename,szOriginalFilename,i,pszExtension);
+ if(_taccess(pfr->szFilename,0)!=0)
+ break;
+ }
+ }
+ break;
+ }
+ mir_free(szOriginalFilename);
+ CallProtoService(szProto,PS_FILERESUMET,(WPARAM)dat->fs,(LPARAM)pfr);
+ if(pfr->szFilename) mir_free((char*)pfr->szFilename);
+ mir_free(pfr);
+ break;
+ }
+ case HM_RECVEVENT:
+ { ACKDATA *ack=(ACKDATA*)lParam;
+ if (ack->hProcess!=dat->fs) break; /* icq abuses this sometimes */
+ if(ack->hContact!=dat->hContact) break;
+ if(ack->type!=ACKTYPE_FILE) break;
+
+ if(dat->waitingForAcceptance) {
+ SetTimer(hwndDlg,1,1000,NULL);
+ dat->waitingForAcceptance=0;
+ }
+ switch(ack->result) {
+ case ACKRESULT_SENTREQUEST: SetFtStatus(hwndDlg, LPGENT("Decision sent"), FTS_TEXT); break;
+ case ACKRESULT_CONNECTING: SetFtStatus(hwndDlg, LPGENT("Connecting..."), FTS_TEXT); break;
+ case ACKRESULT_CONNECTPROXY: SetFtStatus(hwndDlg, LPGENT("Connecting to proxy..."), FTS_TEXT); break;
+ case ACKRESULT_CONNECTED: SetFtStatus(hwndDlg, LPGENT("Connected"), FTS_TEXT); break;
+ case ACKRESULT_LISTENING: SetFtStatus(hwndDlg, LPGENT("Waiting for connection..."), FTS_TEXT); break;
+ case ACKRESULT_INITIALISING: SetFtStatus(hwndDlg, LPGENT("Initialising..."), FTS_TEXT); break;
+ case ACKRESULT_NEXTFILE:
+ SetFtStatus(hwndDlg, LPGENT("Moving to next file..."), FTS_TEXT);
+ SetDlgItemTextA(hwndDlg,IDC_FILENAME,"");
+ if(dat->transferStatus.currentFileNumber==1 && dat->transferStatus.totalFiles>1 && !dat->send)
+ SetOpenFileButtonStyle(GetDlgItem(hwndDlg,IDC_OPENFILE),1);
+ if(dat->transferStatus.currentFileNumber!=-1 && dat->files && !dat->send && DBGetContactSettingByte(NULL,"SRFile","UseScanner",VIRUSSCAN_DISABLE)==VIRUSSCAN_DURINGDL) {
+ if(GetFileAttributes(dat->files[dat->transferStatus.currentFileNumber])&FILE_ATTRIBUTE_DIRECTORY)
+ PostMessage(hwndDlg,M_VIRUSSCANDONE,dat->transferStatus.currentFileNumber,0);
+ else {
+ virusscanthreadstartinfo *vstsi;
+ vstsi=(struct virusscanthreadstartinfo*)mir_alloc(sizeof(struct virusscanthreadstartinfo));
+ vstsi->hwndReply = hwndDlg;
+ vstsi->szFile = mir_tstrdup(dat->files[dat->transferStatus.currentFileNumber]);
+ vstsi->returnCode = dat->transferStatus.currentFileNumber;
+ forkthread((void (*)(void*))RunVirusScannerThread,0,vstsi);
+ }
+ }
+ break;
+ case ACKRESULT_FILERESUME:
+ {
+ UpdateProtoFileTransferStatus(&dat->transferStatus, (PROTOFILETRANSFERSTATUS*)ack->lParam);
+ PROTOFILETRANSFERSTATUS *fts = &dat->transferStatus;
+
+ SetFilenameControls( hwndDlg, dat, fts );
+ int res = _taccess( fts->tszCurrentFile, 0 );
+ if ( res )
+ break;
+
+ SetFtStatus(hwndDlg, LPGENT("File already exists"), FTS_TEXT);
+ if(dat->resumeBehaviour==FILERESUME_ASK) {
+ TDlgProcFileExistsParam param = { hwndDlg, fts };
+ ShowWindow(hwndDlg,SW_SHOWNORMAL);
+ CreateDialogParam(hMirandaInst,MAKEINTRESOURCE(IDD_FILEEXISTS),hwndDlg,DlgProcFileExists,(LPARAM)&param);
+ EnableWindow(hwndDlg,FALSE);
+ }
+ else {
+ PROTOFILERESUME *pfr;
+ pfr=(PROTOFILERESUME*)mir_alloc(sizeof(PROTOFILERESUME));
+ pfr->action = dat->resumeBehaviour;
+ pfr->szFilename = NULL;
+ PostMessage(hwndDlg,M_FILEEXISTSDLGREPLY,(WPARAM)mir_tstrdup(fts->tszCurrentFile),(LPARAM)pfr);
+ }
+ SetWindowLongPtr(hwndDlg,DWLP_MSGRESULT,1);
+ return TRUE;
+ }
+ case ACKRESULT_DATA:
+ {
+ PROTOFILETRANSFERSTATUS *fts=(PROTOFILETRANSFERSTATUS*)ack->lParam;
+ TCHAR str[64], str2[64], szSizeDone[32], szSizeTotal[32];//,*contactName;
+ int units;
+
+ if ( dat->fileVirusScanned==NULL )
+ dat->fileVirusScanned=(int*)mir_calloc(sizeof(int) * fts->totalFiles);
+
+ // This needs to be here - otherwise we get holes in the files array
+ if (!dat->send)
+ {
+ if (dat->files == NULL)
+ dat->files = (TCHAR**)mir_calloc((fts->totalFiles + 1) * sizeof(TCHAR*));
+ if (fts->currentFileNumber < fts->totalFiles && dat->files[fts->currentFileNumber] == NULL)
+ {
+ if (fts->cbSize == sizeof(PROTOFILETRANSFERSTATUS_V1))
+ {
+ PROTOFILETRANSFERSTATUS_V1 *fts1 = (PROTOFILETRANSFERSTATUS_V1*)fts;
+ dat->files[fts->currentFileNumber] = PFTS_StringToTchar(0, (PROTOCHAR*)fts1->currentFile);
+ }
+ else
+ dat->files[fts->currentFileNumber] = PFTS_StringToTchar(fts->flags, fts->tszCurrentFile);
+ }
+ }
+
+ /* HACK: for 0.3.3, limit updates to around 1.1 ack per second */
+ if (fts->totalProgress != fts->totalBytes && GetTickCount() < (dat->dwTicks + 650)) break; // the last update was less than a second ago!
+ dat->dwTicks = GetTickCount();
+
+ // Update local transfer status with data from protocol
+ UpdateProtoFileTransferStatus(&dat->transferStatus, fts);
+ fts = &dat->transferStatus;
+
+ bool firstTime = false;
+ if ((GetWindowLong(GetDlgItem(hwndDlg, IDC_ALLFILESPROGRESS), GWL_STYLE) & WS_VISIBLE) == 0)
+ {
+ SetFtStatus(hwndDlg, ( fts->flags & PFTS_SENDING ) ? LPGENT("Sending...") : LPGENT("Receiving..."), FTS_PROGRESS);
+ SetFilenameControls(hwndDlg, dat, fts);
+ firstTime = true;
+ }
+
+ const unsigned long lastPos = SendDlgItemMessage(hwndDlg, IDC_ALLFILESPROGRESS, PBM_GETPOS, 0, 0);
+ const unsigned long nextPos = fts->totalBytes ? (BIGI(100) * fts->totalProgress / fts->totalBytes) : 0;
+ if (lastPos != nextPos || firstTime)
+ {
+ SendDlgItemMessage(hwndDlg, IDC_ALLFILESPROGRESS, PBM_SETPOS, nextPos, 0);
+ mir_sntprintf(str, SIZEOF(str), _T("%u%%"), nextPos);
+ SetDlgItemText(hwndDlg, IDC_ALLPRECENTS, str);
+ }
+
+ GetSensiblyFormattedSize(fts->totalBytes, szSizeTotal, SIZEOF(szSizeTotal), 0, 1, &units);
+ GetSensiblyFormattedSize(fts->totalProgress, szSizeDone, SIZEOF(szSizeDone), units, 0, NULL);
+ mir_sntprintf(str, SIZEOF(str), _T("%s/%s"), szSizeDone, szSizeTotal);
+ str2[0] = 0;
+ GetDlgItemText(hwndDlg, IDC_ALLTRANSFERRED, str2, SIZEOF(str2));
+ if (_tcscmp(str, str2)) SetDlgItemText(hwndDlg, IDC_ALLTRANSFERRED, str);
+ break;
+ }
+
+ case ACKRESULT_SUCCESS:
+ case ACKRESULT_FAILED:
+ case ACKRESULT_DENIED:
+ {
+
+ HideProgressControls(hwndDlg);
+ KillTimer(hwndDlg,1);
+ if (!dat->send)
+ SetOpenFileButtonStyle(GetDlgItem(hwndDlg,IDC_OPENFILE),1);
+ SetDlgItemText(hwndDlg,IDCANCEL,TranslateT("Close"));
+ if (dat->hNotifyEvent)
+ UnhookEvent(dat->hNotifyEvent);
+ dat->hNotifyEvent=NULL;
+
+ if (ack->result == ACKRESULT_DENIED)
+ {
+ dat->fs=NULL; /* protocol will free structure */
+ SkinPlaySound("FileDenied");
+ SetFtStatus(hwndDlg, LPGENT("File transfer denied"), FTS_TEXT);
+ } else if (ack->result == ACKRESULT_FAILED)
+ {
+ dat->fs=NULL; /* protocol will free structure */
+ SkinPlaySound("FileFailed");
+ SetFtStatus(hwndDlg, LPGENT("File transfer failed"), FTS_TEXT);
+ } else {
+ SkinPlaySound("FileDone");
+ if (dat->send)
+ {
+ dat->fs=NULL; /* protocol will free structure */
+ SetFtStatus(hwndDlg, LPGENT("Transfer completed."), FTS_TEXT);
+
+ DBEVENTINFO dbei={0};
+ FillSendData( dat, dbei );
+ CallService(MS_DB_EVENT_ADD,(WPARAM)dat->hContact,(LPARAM)&dbei);
+ if (dbei.pBlob)
+ mir_free(dbei.pBlob);
+ dat->files=NULL; //protocol library frees this
+
+ } else {
+ SetFtStatus(hwndDlg,
+ (dat->transferStatus.totalFiles == 1) ?
+ LPGENT("Transfer completed, open file.") :
+ LPGENT("Transfer completed, open folder."),
+ FTS_OPEN);
+
+ int useScanner=DBGetContactSettingByte(NULL,"SRFile","UseScanner",VIRUSSCAN_DISABLE);
+ if (useScanner!=VIRUSSCAN_DISABLE) {
+ struct virusscanthreadstartinfo *vstsi;
+ vstsi=(struct virusscanthreadstartinfo*)mir_alloc(sizeof(struct virusscanthreadstartinfo));
+ vstsi->hwndReply=hwndDlg;
+ if(useScanner==VIRUSSCAN_DURINGDL) {
+ vstsi->returnCode=dat->transferStatus.currentFileNumber;
+ if ( GetFileAttributes(dat->files[dat->transferStatus.currentFileNumber])&FILE_ATTRIBUTE_DIRECTORY) {
+ PostMessage(hwndDlg,M_VIRUSSCANDONE,vstsi->returnCode,0);
+ mir_free(vstsi);
+ vstsi=NULL;
+ }
+ else vstsi->szFile = mir_tstrdup(dat->files[dat->transferStatus.currentFileNumber]);
+ }
+ else {
+ vstsi->szFile = mir_tstrdup(dat->transferStatus.tszWorkingDir);
+ vstsi->returnCode = -1;
+ }
+ SetFtStatus(hwndDlg, LPGENT("Scanning for viruses..."), FTS_TEXT);
+ if(vstsi) forkthread((void (*)(void*))RunVirusScannerThread,0,vstsi);
+ } else {
+ dat->fs=NULL; /* protocol will free structure */
+ }
+ dat->transferStatus.currentFileNumber=dat->transferStatus.totalFiles;
+ } // else dat->send
+
+ } // else ack->result
+
+ PostMessage(GetParent(hwndDlg), WM_FT_COMPLETED, ack->result, (LPARAM)hwndDlg);
+ break;
+ }
+ break;
+ } // switch ack->result
+ } break; // case HM_RECVEVENT
+ case M_VIRUSSCANDONE:
+ { int done=1,i;
+ if((int)wParam==-1) {
+ for(i=0;i<dat->transferStatus.totalFiles;i++) dat->fileVirusScanned[i]=1;
+ }
+ else {
+ dat->fileVirusScanned[wParam]=1;
+ for(i=0;i<dat->transferStatus.totalFiles;i++) if(!dat->fileVirusScanned[i]) {done=0; break;}
+ }
+ if (done)
+ {
+ dat->fs=NULL; /* protocol will free structure */
+ SetFtStatus(hwndDlg, LPGENT("Transfer and virus scan complete"), FTS_TEXT);
+ }
+ break;
+ }
+ case WM_SIZE:
+ {
+ UTILRESIZEDIALOG urd={0};
+ urd.cbSize=sizeof(urd);
+ urd.hwndDlg=hwndDlg;
+ urd.hInstance=hMirandaInst;
+ urd.lpTemplate=MAKEINTRESOURCEA(IDD_FILETRANSFERINFO);
+ urd.pfnResizer=FileTransferDlgResizer;
+ CallService(MS_UTILS_RESIZEDIALOG,0,(LPARAM)&urd);
+
+ RedrawWindow(GetDlgItem(hwndDlg, IDC_ALLTRANSFERRED), NULL, NULL, RDW_INVALIDATE|RDW_NOERASE);
+ RedrawWindow(GetDlgItem(hwndDlg, IDC_ALLSPEED), NULL, NULL, RDW_INVALIDATE|RDW_NOERASE);
+ RedrawWindow(GetDlgItem(hwndDlg, IDC_CONTACTNAME), NULL, NULL, RDW_INVALIDATE|RDW_NOERASE);
+ RedrawWindow(GetDlgItem(hwndDlg, IDC_STATUS), NULL, NULL, RDW_INVALIDATE|RDW_NOERASE);
+ break;
+ }
+ case WM_DESTROY:
+ KillTimer(hwndDlg, 1);
+
+ HFONT hFont = (HFONT)SendDlgItemMessage(hwndDlg,IDC_CONTACTNAME,WM_GETFONT,0,0);
+ DeleteObject(hFont);
+
+ Button_FreeIcon_IcoLib(hwndDlg, IDC_CONTACT);
+ Button_FreeIcon_IcoLib(hwndDlg, IDC_OPENFILE);
+ Button_FreeIcon_IcoLib(hwndDlg, IDCANCEL);
+
+ FreeFileDlgData(dat);
+ break;
+ }
+ return FALSE;
+}
+
+void FreeFileDlgData( FileDlgData* dat )
+{
+ if(dat->fs)
+ CallContactService(dat->hContact,PSS_FILECANCEL,(WPARAM)dat->fs,0);
+ dat->fs = NULL;
+
+ if (dat->hPreshutdownEvent) UnhookEvent(dat->hPreshutdownEvent);
+ if (dat->hNotifyEvent) UnhookEvent(dat->hNotifyEvent);
+ dat->hNotifyEvent = NULL;
+
+ FreeProtoFileTransferStatus(&dat->transferStatus);
+ FreeFilesMatrix(&dat->files);
+
+ mir_free(dat->fileVirusScanned);
+ Safe_DestroyIcon(dat->hIcon);
+ Safe_DestroyIcon(dat->hIconFolder);
+ mir_free(dat);
+}
diff --git a/src/modules/srfile/ftmanager.cpp b/src/modules/srfile/ftmanager.cpp
new file mode 100644
index 0000000000..a219d2188a
--- /dev/null
+++ b/src/modules/srfile/ftmanager.cpp
@@ -0,0 +1,592 @@
+/*
+
+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 "file.h"
+
+static HWND hwndFtMgr = NULL;
+
+struct TFtMgrData
+{
+ HWND hwndIncoming;
+ HWND hwndOutgoing;
+
+ HANDLE hhkPreshutdown;
+ TBPFLAG errorState;
+};
+
+
+#define M_CALCPROGRESS (WM_USER + 200)
+struct TFtProgressData
+{
+ unsigned int init, run, scan;
+ unsigned __int64 totalBytes, totalProgress;
+};
+
+struct TLayoutWindowInfo
+{
+ HWND hwnd;
+ RECT rc;
+};
+
+struct TLayoutWindowList
+{
+ struct TLayoutWindowInfo **items;
+ int realCount, limit, increment;
+ FSortFunc sortFunc;
+};
+
+struct TFtPageData
+{
+ struct TLayoutWindowList *wnds;
+ int runningCount;
+ int height, dataHeight, scrollPos;
+};
+
+static void LayoutTransfers(HWND hwnd, struct TFtPageData *dat)
+{
+ int top = 0;
+ RECT rc;
+ GetClientRect(hwnd, &rc);
+
+ dat->scrollPos = GetScrollPos(hwnd, SB_VERT);
+ dat->height = rc.bottom - rc.top;
+
+ if (dat->wnds->realCount)
+ {
+ int i;
+ HDWP hdwp;
+
+ hdwp = BeginDeferWindowPos(dat->wnds->realCount);
+ top -= dat->scrollPos;
+ for (i = 0; i < dat->wnds->realCount; ++i)
+ {
+ int height = dat->wnds->items[i]->rc.bottom - dat->wnds->items[i]->rc.top;
+ hdwp = DeferWindowPos(hdwp, dat->wnds->items[i]->hwnd, NULL, 0, top, rc.right, height, SWP_NOZORDER);
+ top += height;
+ }
+ top += dat->scrollPos;
+ EndDeferWindowPos(hdwp);
+ }
+
+ dat->dataHeight = top;
+
+ {
+ SCROLLINFO si = {0};
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_DISABLENOSCROLL|SIF_PAGE|SIF_RANGE;
+ si.nPage = dat->height;
+ si.nMin = 0;
+ si.nMax = dat->dataHeight;
+ SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
+ }
+}
+
+static INT_PTR CALLBACK FtMgrPageDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct TFtPageData *dat = (struct TFtPageData *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ // Force scrollbar visibility
+ SCROLLINFO si = {0};
+ si.cbSize = sizeof(si);
+ si.fMask = SIF_DISABLENOSCROLL;
+ SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
+
+ dat = (struct TFtPageData *)mir_alloc(sizeof(struct TFtPageData));
+ dat->wnds = (struct TLayoutWindowList *)List_Create(0, 1);
+ dat->scrollPos = 0;
+ dat->runningCount = 0;
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)dat);
+ break;
+ }
+
+ case WM_FT_ADD:
+ {
+ struct TLayoutWindowInfo *wnd = (struct TLayoutWindowInfo *)mir_alloc(sizeof(struct TLayoutWindowInfo));
+ wnd->hwnd = (HWND)lParam;
+ GetWindowRect(wnd->hwnd, &wnd->rc);
+ List_Insert((SortedList *)dat->wnds, wnd, dat->wnds->realCount);
+ LayoutTransfers(hwnd, dat);
+ dat->runningCount++;
+ PostMessage(GetParent(hwnd), WM_TIMER, 1, NULL);
+ break;
+ }
+
+ case WM_FT_RESIZE:
+ {
+ int i;
+ for (i = 0; i < dat->wnds->realCount; ++i)
+ if (dat->wnds->items[i]->hwnd == (HWND)lParam)
+ {
+ GetWindowRect(dat->wnds->items[i]->hwnd, &dat->wnds->items[i]->rc);
+ break;
+ }
+ LayoutTransfers(hwnd, dat);
+ break;
+ }
+
+ case WM_FT_REMOVE:
+ {
+ int i;
+ for (i = 0; i < dat->wnds->realCount; ++i)
+ if (dat->wnds->items[i]->hwnd == (HWND)lParam)
+ {
+ mir_free(dat->wnds->items[i]);
+ List_Remove((SortedList *)dat->wnds, i);
+ break;
+ }
+ LayoutTransfers(hwnd, dat);
+ break;
+ }
+
+ case WM_FT_COMPLETED:
+ { //wParam: { ACKRESULT_SUCCESS | ACKRESULT_FAILED | ACKRESULT_DENIED }
+ dat->runningCount--;
+ int i = 0;
+ while (i < dat->wnds->realCount)
+ {
+ // no error when canceling (WM_FT_REMOVE is send first, check if hwnd is still registered)
+ if (dat->wnds->items[i]->hwnd == (HWND)lParam)
+ {
+ SendMessage(GetParent(hwnd), WM_TIMER, 1, (LPARAM)wParam);
+ break;
+ }
+ ++i;
+ }
+ if (i == dat->wnds->realCount)
+ PostMessage(GetParent(hwnd), WM_TIMER, 1, NULL);
+
+ if(dat->runningCount == 0 && (int)wParam == ACKRESULT_SUCCESS && DBGetContactSettingByte(NULL,"SRFile","AutoClose",0))
+ ShowWindow(hwndFtMgr, SW_HIDE);
+ break;
+ }
+
+ case WM_FT_CLEANUP:
+ {
+ int i;
+ for (i = 0; i < dat->wnds->realCount; ++i)
+ SendMessage(dat->wnds->items[i]->hwnd, WM_FT_CLEANUP, wParam, lParam);
+ break;
+ }
+
+ case WM_SIZE:
+ {
+ LayoutTransfers(hwnd, dat);
+ break;
+ }
+
+ case WM_MOUSEWHEEL:
+ {
+ int zDelta = GET_WHEEL_DELTA_WPARAM(wParam);
+ if (zDelta)
+ {
+ int i, nScrollLines = 0;
+ SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, (void*)&nScrollLines, 0);
+ for (i = 0; i < (nScrollLines + 1) / 2; i++ )
+ SendMessage(hwnd, WM_VSCROLL, (zDelta < 0) ? SB_LINEDOWN : SB_LINEUP, 0);
+ }
+
+ SetWindowLongPtr(hwnd, DWLP_MSGRESULT, 0);
+ return TRUE;
+ }
+
+ case WM_VSCROLL:
+ {
+ int pos = dat->scrollPos;
+ switch (LOWORD(wParam))
+ {
+ case SB_LINEDOWN:
+ pos += 15;
+ break;
+ case SB_LINEUP:
+ pos -= 15;
+ break;
+ case SB_PAGEDOWN:
+ pos += dat->height - 10;
+ break;
+ case SB_PAGEUP:
+ pos -= dat->height - 10;
+ break;
+ case SB_THUMBTRACK:
+ pos = HIWORD(wParam);
+ break;
+ }
+
+ if (pos > dat->dataHeight - dat->height) pos = dat->dataHeight - dat->height;
+ if (pos < 0) pos = 0;
+
+ if (dat->scrollPos != pos)
+ {
+ ScrollWindow(hwnd, 0, dat->scrollPos - pos, NULL, NULL);
+ SetScrollPos(hwnd, SB_VERT, pos, TRUE);
+ dat->scrollPos = pos;
+ }
+ break;
+ }
+
+ case M_PRESHUTDOWN:
+ {
+ int i;
+ for (i = 0; i < dat->wnds->realCount; ++i)
+ PostMessage(dat->wnds->items[i]->hwnd, WM_COMMAND, MAKEWPARAM(IDCANCEL, BN_CLICKED), 0);
+ break;
+ }
+
+ case WM_DESTROY:
+ {
+ int i;
+ for (i = 0; i < dat->wnds->realCount; ++i)
+ mir_free(dat->wnds->items[i]);
+ List_Destroy((SortedList *)dat->wnds);
+ mir_free(dat->wnds);
+ mir_free(dat);
+ break;
+ }
+
+ case M_CALCPROGRESS:
+ {
+ int i;
+ TFtProgressData * prg = (TFtProgressData *)wParam;
+ for (i = 0; i < dat->wnds->realCount; ++i)
+ {
+ struct FileDlgData *trdat = (struct FileDlgData *)GetWindowLongPtr(dat->wnds->items[i]->hwnd, GWLP_USERDATA);
+ if (trdat->transferStatus.totalBytes && trdat->fs && !trdat->send && (trdat->transferStatus.totalBytes == trdat->transferStatus.totalProgress))
+ {
+ prg->scan++;
+ } else if (trdat->transferStatus.totalBytes && trdat->fs)
+ { // in progress
+ prg->run++;
+ prg->totalBytes += trdat->transferStatus.totalBytes;
+ prg->totalProgress += trdat->transferStatus.totalProgress;
+ } else if (trdat->fs)
+ { // starting
+ prg->init++;
+ }
+
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+static INT_PTR CALLBACK FtMgrDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct TFtMgrData *dat = (struct TFtMgrData *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ TCITEM tci = {0};
+ HWND hwndTab = GetDlgItem(hwnd, IDC_TABS);
+
+ TranslateDialogDefault(hwnd);
+ Window_SetIcon_IcoLib(hwnd, SKINICON_EVENT_FILE);
+
+ dat = (struct TFtMgrData *)mir_calloc(sizeof(struct TFtMgrData));
+
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)dat);
+
+ dat->hhkPreshutdown = HookEventMessage(ME_SYSTEM_PRESHUTDOWN, hwnd, M_PRESHUTDOWN);
+
+ dat->hwndIncoming = CreateDialog(hMirandaInst, MAKEINTRESOURCE(IDD_FTPAGE), hwnd, FtMgrPageDlgProc);
+ dat->hwndOutgoing = CreateDialog(hMirandaInst, MAKEINTRESOURCE(IDD_FTPAGE), hwnd, FtMgrPageDlgProc);
+ ShowWindow(dat->hwndIncoming, SW_SHOW);
+
+ tci.mask = TCIF_PARAM|TCIF_TEXT;
+ tci.pszText = TranslateT("Incoming");
+ tci.lParam = (LPARAM)dat->hwndIncoming;
+ TabCtrl_InsertItem(hwndTab, 0, &tci);
+ tci.pszText = TranslateT("Outgoing");
+ tci.lParam = (LPARAM)dat->hwndOutgoing;
+ TabCtrl_InsertItem(hwndTab, 1, &tci);
+
+ // Utils_RestoreWindowPosition(hwnd, NULL, "SRFile", "FtMgrDlg_");
+ SAVEWINDOWPOS swp;
+ swp.hwnd=hwnd; swp.hContact=NULL; swp.szModule="SRFile"; swp.szNamePrefix="FtMgrDlg_";
+ CallService(MS_UTILS_RESTOREWINDOWPOSITION, RWPF_NOACTIVATE, (LPARAM)&swp);
+
+ // Fall through to setup initial placement
+ }
+ case WM_SIZE:
+ {
+ RECT rc, rcButton;
+ HDWP hdwp;
+ HWND hwndTab = GetDlgItem(hwnd, IDC_TABS);
+
+ GetWindowRect(GetDlgItem(hwnd, IDCANCEL), &rcButton);
+ OffsetRect(&rcButton, -rcButton.left, -rcButton.top);
+
+ GetClientRect(hwnd, &rc);
+ InflateRect(&rc, -6, -6);
+
+ hdwp = BeginDeferWindowPos(3);
+
+ hdwp = DeferWindowPos(hdwp, GetDlgItem(hwnd, IDC_CLEAR), NULL, rc.left, rc.bottom-rcButton.bottom, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
+ hdwp = DeferWindowPos(hdwp, GetDlgItem(hwnd, IDCANCEL), NULL, rc.right-rcButton.right, rc.bottom-rcButton.bottom, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
+
+ rc.bottom -= rcButton.bottom + 5;
+
+ hdwp = DeferWindowPos(hdwp, hwndTab, NULL, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, SWP_NOZORDER);
+
+ EndDeferWindowPos(hdwp);
+
+ GetWindowRect(hwndTab, &rc);
+ MapWindowPoints(NULL, hwnd, (LPPOINT)&rc, 2);
+ TabCtrl_AdjustRect(hwndTab, FALSE, &rc);
+ InflateRect(&rc, -5, -5);
+
+ hdwp = BeginDeferWindowPos(2);
+
+ hdwp = DeferWindowPos(hdwp, dat->hwndIncoming, HWND_TOP, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, 0);
+ hdwp = DeferWindowPos(hdwp, dat->hwndOutgoing, HWND_TOP, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, 0);
+
+ EndDeferWindowPos(hdwp);
+
+ break;
+ }
+
+ case WM_MOUSEWHEEL:
+ {
+ if (IsWindowVisible(dat->hwndIncoming)) SendMessage(dat->hwndIncoming, msg, wParam, lParam);
+ if (IsWindowVisible(dat->hwndOutgoing)) SendMessage(dat->hwndOutgoing, msg, wParam, lParam);
+ break;
+ }
+
+ case WM_FT_SELECTPAGE:
+ {
+ TCITEM tci = {0};
+ HWND hwndTab = GetDlgItem(hwnd, IDC_TABS);
+
+ if (TabCtrl_GetCurSel(hwndTab) == (int)wParam) break;
+
+ tci.mask = TCIF_PARAM;
+
+ TabCtrl_GetItem(hwndTab, TabCtrl_GetCurSel(hwndTab), &tci);
+ ShowWindow((HWND)tci.lParam, SW_HIDE);
+
+ TabCtrl_SetCurSel(hwndTab, wParam);
+
+ TabCtrl_GetItem(hwndTab, TabCtrl_GetCurSel(hwndTab), &tci);
+ ShowWindow((HWND)tci.lParam, SW_SHOW);
+
+ break;
+ }
+
+ case WM_GETMINMAXINFO:
+ {
+ LPMINMAXINFO lpmmi = (LPMINMAXINFO)lParam;
+ lpmmi->ptMinTrackSize.x = 300;
+ lpmmi->ptMinTrackSize.y = 400;
+ return 0;
+ }
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDCANCEL:
+ PostMessage(hwnd, WM_CLOSE , 0, 0);
+ break;
+
+ case IDC_CLEAR:
+ PostMessage(dat->hwndIncoming, WM_FT_CLEANUP, 0, 0);
+ PostMessage(dat->hwndOutgoing, WM_FT_CLEANUP, 0, 0);
+ break;
+ }
+ break;
+
+ case WM_NOTIFY:
+ {
+ switch (((LPNMHDR)lParam)->idFrom)
+ {
+ case IDC_TABS:
+ {
+ HWND hwndTab = GetDlgItem(hwnd, IDC_TABS);
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case TCN_SELCHANGING:
+ {
+ TCITEM tci = {0};
+ tci.mask = TCIF_PARAM;
+ TabCtrl_GetItem(hwndTab, TabCtrl_GetCurSel(hwndTab), &tci);
+ ShowWindow((HWND)tci.lParam, SW_HIDE);
+ break;
+ }
+
+ case TCN_SELCHANGE:
+ {
+ TCITEM tci = {0};
+ tci.mask = TCIF_PARAM;
+ TabCtrl_GetItem(hwndTab, TabCtrl_GetCurSel(hwndTab), &tci);
+ ShowWindow((HWND)tci.lParam, SW_SHOW);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+
+ case M_PRESHUTDOWN:
+ SendMessage(dat->hwndIncoming, M_PRESHUTDOWN, 0, 0);
+ SendMessage(dat->hwndOutgoing, M_PRESHUTDOWN, 0, 0);
+ DestroyWindow(hwnd);
+ break;
+
+ case WM_CLOSE:
+ ShowWindow(hwnd, SW_HIDE);
+ if (DBGetContactSettingByte(NULL, "SRFile", "AutoClear", 1)) {
+ PostMessage(dat->hwndIncoming, WM_FT_CLEANUP, 0, 0);
+ PostMessage(dat->hwndOutgoing, WM_FT_CLEANUP, 0, 0);
+ }
+ return TRUE; /* Disable default IDCANCEL notification */
+
+ case WM_DESTROY:
+ UnhookEvent(dat->hhkPreshutdown);
+ Window_FreeIcon_IcoLib(hwnd);
+ DestroyWindow(dat->hwndIncoming);
+ DestroyWindow(dat->hwndOutgoing);
+ mir_free(dat);
+ SetWindowLongPtr(hwnd, GWLP_USERDATA, 0);
+ Utils_SaveWindowPosition(hwnd, NULL, "SRFile", "FtMgrDlg_");
+ break;
+
+ case WM_ACTIVATE:
+ {
+ dat->errorState = TBPF_NOPROGRESS;
+ wParam = 1;
+ } break;
+ case WM_SHOWWINDOW:
+ {
+ if (!wParam) // hiding
+ {
+ KillTimer(hwnd, 1);
+ break;
+ }
+ lParam = 0;
+ }
+ case WM_TIMER:
+ {
+ if (pTaskbarInterface)
+ {
+ SetTimer(hwnd, 1, 400, NULL);
+ if ((lParam == ACKRESULT_FAILED) || (lParam == ACKRESULT_DENIED))
+ dat->errorState = TBPF_ERROR;
+
+ TFtProgressData prg = {0};
+ SendMessage(dat->hwndIncoming, M_CALCPROGRESS, (WPARAM)&prg, 0);
+ SendMessage(dat->hwndOutgoing, M_CALCPROGRESS, (WPARAM)&prg, 0);
+ if (dat->errorState)
+ {
+ pTaskbarInterface->SetProgressState(hwnd, dat->errorState);
+ if (!prg.run)
+ pTaskbarInterface->SetProgressValue(hwnd, 1, 1);
+ } else if (prg.run)
+ {
+ pTaskbarInterface->SetProgressState(hwnd, TBPF_NORMAL);
+ } else if (prg.init || prg.scan)
+ {
+ pTaskbarInterface->SetProgressState(hwnd, TBPF_INDETERMINATE);
+ } else {
+ pTaskbarInterface->SetProgressState(hwnd, TBPF_NOPROGRESS);
+ KillTimer(hwnd, 1);
+ }
+
+ if (prg.run)
+ {
+ pTaskbarInterface->SetProgressValue(hwnd, prg.totalProgress, prg.totalBytes);
+ }
+
+ }
+ } break;
+
+ }
+
+ return FALSE;
+}
+
+HWND FtMgr_Show(bool bForceActivate, bool bFromMenu)
+{
+ bool bAutoMin = DBGetContactSettingByte(NULL,"SRFile","AutoMin",0) != 0; /* lqbe */
+
+ bool bJustCreated = (hwndFtMgr == NULL);
+ if (bJustCreated)
+ {
+ hwndFtMgr = CreateDialog(hMirandaInst, MAKEINTRESOURCE(IDD_FTMGR), NULL, FtMgrDlgProc);
+ }
+ if (bFromMenu) /* lqbe */
+ {
+ ShowWindow(hwndFtMgr, SW_RESTORE);
+ ShowWindow(hwndFtMgr, SW_SHOW);
+ SetForegroundWindow(hwndFtMgr);
+ return hwndFtMgr;
+ }
+ else if (bAutoMin && bJustCreated) /* lqbe */
+ {
+ ShowWindow(hwndFtMgr, SW_HIDE);
+ ShowWindow(hwndFtMgr, SW_MINIMIZE);
+ return hwndFtMgr;
+ }
+ else if (bForceActivate) /* lqbe */
+ {
+ ShowWindow(hwndFtMgr, SW_RESTORE);
+ ShowWindow(hwndFtMgr, SW_SHOWNOACTIVATE);
+ SetForegroundWindow(hwndFtMgr);
+ return hwndFtMgr;
+ }
+ if (!bJustCreated && IsWindowVisible(hwndFtMgr))
+ return hwndFtMgr;
+
+ ShowWindow(hwndFtMgr, bAutoMin ? SW_SHOWMINNOACTIVE : SW_SHOWNOACTIVATE);
+ return hwndFtMgr;
+ }
+
+void FtMgr_Destroy()
+{
+ if (hwndFtMgr)
+ DestroyWindow(hwndFtMgr);
+}
+
+void FtMgr_ShowPage(int page)
+{
+ if (hwndFtMgr)
+ SendMessage(hwndFtMgr, WM_FT_SELECTPAGE, page, 0);
+}
+
+HWND FtMgr_AddTransfer(FileDlgData *fdd)
+{
+ bool bForceActivate = fdd->send || !DBGetContactSettingByte(NULL, "SRFile", "AutoAccept", 0);
+ TFtMgrData *dat = (TFtMgrData*)GetWindowLongPtr(FtMgr_Show(bForceActivate, false), GWLP_USERDATA);
+ if (dat == NULL) return NULL;
+ HWND hwndBox = fdd->send ? dat->hwndOutgoing : dat->hwndIncoming;
+ HWND hwndFt = CreateDialogParam(hMirandaInst, MAKEINTRESOURCE(IDD_FILETRANSFERINFO), hwndBox, DlgProcFileTransfer, (LPARAM)fdd);
+ ShowWindow(hwndFt, SW_SHOWNA);
+ SendMessage(hwndBox, WM_FT_ADD, 0, (LPARAM)hwndFt);
+ FtMgr_ShowPage(fdd->send ? 1 : 0);
+ return hwndFt;
+} \ No newline at end of file
diff --git a/src/modules/srurl/url.cpp b/src/modules/srurl/url.cpp
new file mode 100644
index 0000000000..a6dfb9141f
--- /dev/null
+++ b/src/modules/srurl/url.cpp
@@ -0,0 +1,182 @@
+/*
+
+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_url.h>
+#include "url.h"
+
+HANDLE hUrlWindowList = NULL;
+static HANDLE hEventContactSettingChange = NULL;
+static HANDLE hContactDeleted = NULL;
+static HANDLE hSRUrlMenuItem = NULL;
+
+INT_PTR CALLBACK DlgProcUrlSend(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+INT_PTR CALLBACK DlgProcUrlRecv(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+static INT_PTR ReadUrlCommand(WPARAM, LPARAM lParam)
+{
+ CreateDialogParam(hMirandaInst,MAKEINTRESOURCE(IDD_URLRECV),NULL,DlgProcUrlRecv,lParam);
+ return 0;
+}
+
+static int UrlEventAdded(WPARAM wParam,LPARAM lParam)
+{
+ CLISTEVENT cle;
+ DBEVENTINFO dbei;
+ TCHAR szTooltip[256];
+
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.cbBlob=0;
+ CallService(MS_DB_EVENT_GET,lParam,(LPARAM)&dbei);
+ if(dbei.flags&(DBEF_SENT|DBEF_READ) || dbei.eventType!=EVENTTYPE_URL) return 0;
+
+ SkinPlaySound("RecvUrl");
+ ZeroMemory(&cle,sizeof(cle));
+ cle.cbSize=sizeof(cle);
+ cle.flags = CLEF_TCHAR;
+ cle.hContact=(HANDLE)wParam;
+ cle.hDbEvent=(HANDLE)lParam;
+ cle.hIcon = LoadSkinIcon( SKINICON_EVENT_URL );
+ cle.pszService="SRUrl/ReadUrl";
+ mir_sntprintf(szTooltip,SIZEOF(szTooltip),TranslateT("URL from %s"), cli.pfnGetContactDisplayName(( HANDLE )wParam, 0 ));
+ cle.ptszTooltip=szTooltip;
+ CallService(MS_CLIST_ADDEVENT,0,(LPARAM)&cle);
+ return 0;
+}
+
+static INT_PTR SendUrlCommand(WPARAM wParam, LPARAM)
+{
+ CreateDialogParam(hMirandaInst,MAKEINTRESOURCE(IDD_URLSEND),NULL,DlgProcUrlSend,wParam);
+ return 0;
+}
+
+static void RestoreUnreadUrlAlerts(void)
+{
+ CLISTEVENT cle={0};
+ DBEVENTINFO dbei={0};
+ TCHAR toolTip[256];
+ HANDLE hDbEvent,hContact;
+
+ dbei.cbSize=sizeof(dbei);
+ cle.cbSize=sizeof(cle);
+ cle.hIcon = LoadSkinIcon( SKINICON_EVENT_URL );
+ cle.pszService="SRUrl/ReadUrl";
+
+ hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDFIRST,0,0);
+ while(hContact) {
+ hDbEvent=(HANDLE)CallService(MS_DB_EVENT_FINDFIRSTUNREAD,(WPARAM)hContact,0);
+ while(hDbEvent) {
+ dbei.cbBlob=0;
+ CallService(MS_DB_EVENT_GET,(WPARAM)hDbEvent,(LPARAM)&dbei);
+ if(!(dbei.flags&(DBEF_SENT|DBEF_READ)) && dbei.eventType==EVENTTYPE_URL) {
+ cle.hContact=hContact;
+ cle.hDbEvent=hDbEvent;
+ cle.flags = CLEF_TCHAR;
+ mir_sntprintf(toolTip,SIZEOF(toolTip),TranslateT("URL from %s"), cli.pfnGetContactDisplayName( hContact, 0 ));
+ cle.ptszTooltip=toolTip;
+ CallService(MS_CLIST_ADDEVENT,0,(LPARAM)&cle);
+ }
+ hDbEvent=(HANDLE)CallService(MS_DB_EVENT_FINDNEXT,(WPARAM)hDbEvent,0);
+ }
+ hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)hContact,0);
+ }
+}
+
+static int ContactSettingChanged(WPARAM wParam, LPARAM lParam)
+{
+ DBCONTACTWRITESETTING *cws=(DBCONTACTWRITESETTING*)lParam;
+ char *szProto;
+
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,wParam,0);
+ if(lstrcmpA(cws->szModule,"CList") && (szProto==NULL || lstrcmpA(cws->szModule,szProto))) return 0;
+ WindowList_Broadcast(hUrlWindowList,DM_UPDATETITLE,0,0);
+ return 0;
+}
+
+static int SRUrlPreBuildMenu(WPARAM wParam, LPARAM)
+{
+ CLISTMENUITEM mi = { 0 };
+ mi.cbSize = sizeof(mi);
+ mi.flags = CMIM_FLAGS | CMIF_HIDDEN;
+
+ char *szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ if ( szProto != NULL )
+ if ( CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_URLSEND )
+ mi.flags = CMIM_FLAGS;
+
+ CallService( MS_CLIST_MODIFYMENUITEM, (WPARAM)hSRUrlMenuItem, (LPARAM)&mi );
+ return 0;
+}
+
+static int SRUrlModulesLoaded(WPARAM, LPARAM)
+{
+ CLISTMENUITEM mi = { 0 };
+ mi.cbSize = sizeof(mi);
+ mi.position = -2000040000;
+ mi.flags = CMIF_ICONFROMICOLIB;
+ mi.icolibItem = GetSkinIconHandle( SKINICON_EVENT_URL );
+ mi.pszName = LPGEN("Web Page Address (&URL)");
+ mi.pszService = MS_URL_SENDURL;
+ hSRUrlMenuItem = (HANDLE)CallService( MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM)&mi );
+
+ RestoreUnreadUrlAlerts();
+ return 0;
+}
+
+static int SRUrlShutdown(WPARAM, LPARAM)
+{
+ if ( hEventContactSettingChange )
+ UnhookEvent( hEventContactSettingChange );
+
+ if ( hContactDeleted )
+ UnhookEvent( hContactDeleted );
+
+ if ( hUrlWindowList )
+ WindowList_BroadcastAsync( hUrlWindowList, WM_CLOSE, 0, 0 );
+
+ return 0;
+}
+
+int UrlContactDeleted(WPARAM wParam, LPARAM)
+{
+ HWND h = WindowList_Find(hUrlWindowList,(HANDLE)wParam);
+ if ( h )
+ SendMessage(h,WM_CLOSE,0,0);
+
+ return 0;
+}
+
+int LoadSendRecvUrlModule(void)
+{
+ hUrlWindowList=(HANDLE)CallService(MS_UTILS_ALLOCWINDOWLIST,0,0);
+ HookEvent(ME_SYSTEM_MODULESLOADED,SRUrlModulesLoaded);
+ HookEvent(ME_DB_EVENT_ADDED,UrlEventAdded);
+ HookEvent(ME_CLIST_PREBUILDCONTACTMENU,SRUrlPreBuildMenu);
+ hEventContactSettingChange = HookEvent(ME_DB_CONTACT_SETTINGCHANGED, ContactSettingChanged);
+ hContactDeleted = HookEvent(ME_DB_CONTACT_DELETED, UrlContactDeleted);
+ HookEvent(ME_SYSTEM_PRESHUTDOWN,SRUrlShutdown);
+ CreateServiceFunction(MS_URL_SENDURL,SendUrlCommand);
+ CreateServiceFunction("SRUrl/ReadUrl",ReadUrlCommand);
+ SkinAddNewSoundEx("RecvUrl","URL","Incoming");
+ return 0;
+}
diff --git a/src/modules/srurl/url.h b/src/modules/srurl/url.h
new file mode 100644
index 0000000000..98c5566f53
--- /dev/null
+++ b/src/modules/srurl/url.h
@@ -0,0 +1,41 @@
+/*
+
+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.
+*/
+
+#define TIMEOUT_URLSEND 9000
+#define HM_EVENTSENT (WM_USER+10)
+#define DM_UPDATETITLE (WM_USER+11)
+
+#define DDEMESSAGETIMEOUT 1000
+
+
+struct UrlRcvData {
+ HANDLE hContact;
+ HANDLE hDbEvent;
+};
+
+struct UrlSendData {
+ HANDLE hContact;
+ HANDLE hSendId;
+ HANDLE hAckEvent;
+ char *sendBuffer;
+};
diff --git a/src/modules/srurl/urldialogs.cpp b/src/modules/srurl/urldialogs.cpp
new file mode 100644
index 0000000000..294e3be4da
--- /dev/null
+++ b/src/modules/srurl/urldialogs.cpp
@@ -0,0 +1,664 @@
+/*
+
+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 "url.h"
+
+INT_PTR CALLBACK DlgProcUrlSend(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+extern HANDLE hUrlWindowList;
+
+static void sttUpdateTitle( HWND hwndDlg, HANDLE hContact )
+{
+ TCHAR newtitle[256],oldtitle[256];
+ TCHAR *szStatus, *contactName, *pszNewTitleStart = TranslateT("Send URL to");
+ char *szProto;
+
+ if ( hContact ) {
+ szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hContact,0);
+ if ( szProto ) {
+ CONTACTINFO ci;
+ int hasName = 0;
+ char buf[128];
+ ZeroMemory(&ci,sizeof(ci));
+
+ ci.cbSize = sizeof(ci);
+ ci.hContact = hContact;
+ ci.szProto = szProto;
+ ci.dwFlag = CNF_UNIQUEID;
+ if (!CallService(MS_CONTACT_GETCONTACTINFO,0,(LPARAM)&ci)) {
+ switch(ci.type) {
+ case CNFT_ASCIIZ:
+ hasName = 1;
+ mir_snprintf(buf, SIZEOF(buf), "%s", ci.pszVal);
+ mir_free(ci.pszVal);
+ break;
+ case CNFT_DWORD:
+ hasName = 1;
+ mir_snprintf(buf, SIZEOF(buf),"%u",ci.dVal);
+ break;
+ } }
+
+ contactName = cli.pfnGetContactDisplayName( hContact, 0 );
+ if ( hasName )
+ SetDlgItemTextA( hwndDlg, IDC_NAME, buf );
+ else
+ SetDlgItemText( hwndDlg, IDC_NAME, contactName );
+
+ szStatus = cli.pfnGetStatusModeDescription( szProto == NULL ? ID_STATUS_OFFLINE : DBGetContactSettingWord( hContact, szProto, "Status", ID_STATUS_OFFLINE ), 0 );
+ mir_sntprintf( newtitle, SIZEOF(newtitle), _T("%s %s (%s)"), pszNewTitleStart, contactName, szStatus);
+ }
+ }
+ else lstrcpyn( newtitle, pszNewTitleStart, SIZEOF(newtitle));
+
+ GetWindowText( hwndDlg, oldtitle, SIZEOF(oldtitle));
+
+ if ( lstrcmp( newtitle, oldtitle )) //swt() flickers even if the title hasn't actually changed
+ SetWindowText( hwndDlg, newtitle );
+}
+
+INT_PTR CALLBACK DlgProcUrlRecv(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct UrlRcvData *dat = (struct UrlRcvData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ Window_SetIcon_IcoLib(hwndDlg, SKINICON_EVENT_URL);
+ Button_SetIcon_IcoLib(hwndDlg, IDC_ADD, SKINICON_OTHER_ADDCONTACT, LPGEN("Add Contact Permanently to List"));
+ Button_SetIcon_IcoLib(hwndDlg, IDC_DETAILS, SKINICON_OTHER_USERDETAILS, LPGEN("View User's Details"));
+ Button_SetIcon_IcoLib(hwndDlg, IDC_HISTORY, SKINICON_OTHER_HISTORY, LPGEN("View User's History"));
+ Button_SetIcon_IcoLib(hwndDlg, IDC_USERMENU, SKINICON_OTHER_DOWNARROW, LPGEN("User Menu"));
+
+ dat=(struct UrlRcvData*)mir_alloc(sizeof(struct UrlRcvData));
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)dat);
+
+ dat->hContact = ((CLISTEVENT*)lParam)->hContact;
+ dat->hDbEvent = ((CLISTEVENT*)lParam)->hDbEvent;
+
+ WindowList_Add(hUrlWindowList, hwndDlg, dat->hContact);
+ {
+ DBEVENTINFO dbei;
+ TCHAR* contactName;
+ TCHAR msg[128];
+
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.cbBlob=CallService(MS_DB_EVENT_GETBLOBSIZE,(WPARAM)dat->hDbEvent,0);
+ dbei.pBlob=(PBYTE)mir_alloc(dbei.cbBlob);
+ CallService(MS_DB_EVENT_GET,(WPARAM)dat->hDbEvent,(LPARAM)&dbei);
+ SetDlgItemTextA(hwndDlg,IDC_URL,(char*)dbei.pBlob);
+ SetDlgItemTextA(hwndDlg,IDC_MSG,(char*)dbei.pBlob+lstrlenA((char*)dbei.pBlob)+1);
+ mir_free(dbei.pBlob);
+
+ CallService(MS_DB_EVENT_MARKREAD,(WPARAM)dat->hContact,(LPARAM)dat->hDbEvent);
+
+ contactName = cli.pfnGetContactDisplayName( dat->hContact, 0 );
+ mir_sntprintf(msg,SIZEOF(msg),TranslateT("URL from %s"),contactName);
+ SetWindowText(hwndDlg,msg);
+ SetDlgItemText(hwndDlg,IDC_FROM,contactName);
+ SendDlgItemMessage(hwndDlg,IDOK,BUTTONSETARROW,1,0);
+ { TCHAR str[128];
+ tmi.printTimeStamp(NULL, dbei.timestamp, _T("t d"), str, SIZEOF(str), 0);
+ SetDlgItemText(hwndDlg, IDC_DATE, str);
+ } }
+
+ // From message dlg
+ if (!DBGetContactSettingByte(dat->hContact, "CList", "NotOnList", 0))
+ ShowWindow(GetDlgItem(hwndDlg, IDC_ADD), SW_HIDE);
+
+ SendMessage(hwndDlg,DM_UPDATETITLE,0,0);
+ // From message dlg end
+
+ Utils_RestoreWindowPositionNoSize(hwndDlg,NULL,"SRUrl","recv");
+ return TRUE;
+
+ case WM_MEASUREITEM:
+ return CallService(MS_CLIST_MENUMEASUREITEM,wParam,lParam);
+
+ case WM_DRAWITEM:
+ {
+ LPDRAWITEMSTRUCT dis=(LPDRAWITEMSTRUCT)lParam;
+ if(dis->hwndItem==GetDlgItem(hwndDlg, IDC_PROTOCOL)) {
+ char *szProto;
+
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)dat->hContact,0);
+ if (szProto) {
+ HICON hIcon;
+
+ hIcon = ( HICON )CallProtoService(szProto,PS_LOADICON,PLI_PROTOCOL|PLIF_SMALL,0);
+ if (hIcon) {
+ DrawIconEx(dis->hDC,dis->rcItem.left,dis->rcItem.top,hIcon,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0,NULL,DI_NORMAL);
+ DestroyIcon( hIcon );
+ } } } }
+ return CallService(MS_CLIST_MENUDRAWITEM,wParam,lParam);
+
+ case DM_UPDATETITLE:
+ sttUpdateTitle( hwndDlg, dat->hContact );
+ break;
+
+ case WM_COMMAND:
+ if (dat)
+ if(CallService(MS_CLIST_MENUPROCESSCOMMAND,MAKEWPARAM(LOWORD(wParam),MPCF_CONTACTMENU),(LPARAM)dat->hContact))
+ break;
+ switch(LOWORD(wParam)) {
+ case IDOK:
+ { HMENU hMenu,hSubMenu;
+ RECT rc;
+ char url[256];
+
+ hMenu=LoadMenu(hMirandaInst,MAKEINTRESOURCE(IDR_CONTEXT));
+ hSubMenu=GetSubMenu(hMenu,6);
+ CallService(MS_LANGPACK_TRANSLATEMENU,(WPARAM)hSubMenu,0);
+ GetWindowRect((HWND)lParam, &rc);
+ GetDlgItemTextA(hwndDlg, IDC_URL, url, SIZEOF(url));
+ switch(TrackPopupMenu(hSubMenu,TPM_RETURNCMD,rc.left,rc.bottom,0,hwndDlg,NULL)) {
+ case IDM_OPENNEW:
+ CallService(MS_UTILS_OPENURL,1,(LPARAM)url);
+ break;
+ case IDM_OPENEXISTING:
+ CallService(MS_UTILS_OPENURL,0,(LPARAM)url);
+ break;
+ case IDM_COPYLINK:
+ { HGLOBAL hData;
+ if(!OpenClipboard(hwndDlg)) break;
+ EmptyClipboard();
+ hData=GlobalAlloc(GMEM_MOVEABLE,lstrlenA(url)+1);
+ lstrcpyA((char*)GlobalLock(hData),url);
+ GlobalUnlock(hData);
+ SetClipboardData(CF_TEXT,hData);
+ CloseClipboard();
+ break;
+ }
+ }
+ DestroyMenu(hMenu);
+ }
+ return TRUE;
+
+ case IDC_USERMENU:
+ {
+ RECT rc;
+ HMENU hMenu=(HMENU)CallService(MS_CLIST_MENUBUILDCONTACT,(WPARAM)dat->hContact,0);
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_USERMENU),&rc);
+ TrackPopupMenu(hMenu,0,rc.left,rc.bottom,0,hwndDlg,NULL);
+ DestroyMenu(hMenu);
+ }
+ break;
+
+ case IDC_HISTORY:
+ CallService(MS_HISTORY_SHOWCONTACTHISTORY,(WPARAM)dat->hContact,0);
+ break;
+
+ case IDC_DETAILS:
+ CallService(MS_USERINFO_SHOWDIALOG,(WPARAM)dat->hContact,0);
+ break;
+
+ case IDC_ADD:
+ {
+ ADDCONTACTSTRUCT acs={0};
+
+ acs.handle=dat->hContact;
+ acs.handleType=HANDLE_CONTACT;
+ acs.szProto=0;
+ CallService(MS_ADDCONTACT_SHOW,(WPARAM)hwndDlg,(LPARAM)&acs);
+ }
+ if (!DBGetContactSettingByte(dat->hContact,"CList","NotOnList",0)) {
+ ShowWindow(GetDlgItem(hwndDlg,IDC_ADD),FALSE);
+ }
+ break;
+
+ case IDC_REPLY:
+ CallService(MS_MSG_SENDMESSAGE,(WPARAM)dat->hContact,0);
+ //fall through
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ return TRUE;
+ }
+ break;
+
+ case WM_DESTROY:
+ Window_FreeIcon_IcoLib(hwndDlg);
+ Button_FreeIcon_IcoLib(hwndDlg,IDC_ADD);
+ Button_FreeIcon_IcoLib(hwndDlg,IDC_DETAILS);
+ Button_FreeIcon_IcoLib(hwndDlg,IDC_HISTORY);
+ Button_FreeIcon_IcoLib(hwndDlg,IDC_USERMENU);
+
+ WindowList_Remove(hUrlWindowList, hwndDlg);
+ mir_free(dat);
+ Utils_SaveWindowPosition(hwndDlg,NULL,"SRUrl","recv");
+ break;
+ }
+ return FALSE;
+}
+
+static int ddeAcked,ddeData;
+static ATOM hSzDdeData;
+static HWND hwndDde;
+static HGLOBAL hGlobalDdeData;
+static LRESULT DdeMessage(HWND hwndDlg,UINT msg,WPARAM wParam,LPARAM lParam)
+{
+ UINT_PTR hSzItem;
+
+ switch(msg) {
+ case WM_DDE_ACK:
+ ddeAcked=1;
+ hwndDde=(HWND)wParam;
+ break;
+
+ case WM_DDE_DATA:
+ UnpackDDElParam(msg,lParam,(PUINT_PTR)&hGlobalDdeData,(PUINT_PTR)&hSzItem);
+ ddeData = 1;
+ if( hGlobalDdeData ) {
+ DDEDATA* data = ( DDEDATA* )GlobalLock( hGlobalDdeData );
+ if ( data->fAckReq ) {
+ DDEACK ack = {0};
+ PostMessage(( HWND )wParam, WM_DDE_ACK, ( WPARAM )hwndDlg, PackDDElParam( WM_DDE_ACK, *(PUINT)&ack, hSzItem ));
+ }
+ else GlobalDeleteAtom(( ATOM )hSzItem );
+ GlobalUnlock( hGlobalDdeData );
+ }
+ else GlobalDeleteAtom(( ATOM )hSzItem );
+ break;
+ }
+ return 0;
+}
+
+static HGLOBAL DoDdeRequest(const char *szItemName,HWND hwndDlg)
+{
+ ATOM hSzItemName;
+ DWORD timeoutTick,thisTick;
+ MSG msg;
+
+ hSzItemName=GlobalAddAtomA(szItemName);
+ if(!PostMessage(hwndDde,WM_DDE_REQUEST,(WPARAM)hwndDlg,MAKELPARAM(CF_TEXT,hSzItemName))) {
+ GlobalDeleteAtom(hSzItemName);
+ return NULL;
+ }
+ timeoutTick=GetTickCount()+5000;
+ ddeData=0; ddeAcked=0;
+ do {
+ if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ if(ddeData || ddeAcked) break;
+ thisTick=GetTickCount();
+ if(thisTick>timeoutTick) break;
+ }
+ while(MsgWaitForMultipleObjects(0,NULL,FALSE,timeoutTick-thisTick,QS_ALLINPUT)==WAIT_OBJECT_0);
+
+ if(!ddeData) {
+ GlobalDeleteAtom(hSzItemName);
+ return NULL;
+ }
+
+ return hGlobalDdeData;
+}
+
+static void FreeDdeRequestData(HGLOBAL hData)
+{
+ DDEDATA *data;
+ data=(DDEDATA*)GlobalLock(hData);
+ if(data->fRelease) {
+ GlobalUnlock(hData);
+ GlobalFree(hData);
+ }
+ else GlobalUnlock(hData);
+}
+
+static void AddBrowserPageToCombo(char *url,HWND hwndCombo)
+{
+ char *title,*frame,*end;
+
+ if(url[0]!='"') return;
+ url++;
+ title=strchr(url,'"');
+ if(title==NULL) return;
+ *title='\0'; title++;
+ if(*title) {
+ title+=2;
+ frame=strchr(title,'"');
+ if(frame==NULL) return;
+ *frame='\0'; frame++;
+ if(*frame) {
+ frame+=2;
+ end=strchr(frame,'"');
+ if(end==NULL) return;
+ *end='\0';
+ }
+ else frame=NULL;
+ }
+ else title=frame=NULL;
+ if(frame==NULL || *frame==0) {
+ char *szItemData;
+ int i;
+ char szExistingUrl[1024];
+
+ for(i=SendMessage(hwndCombo,CB_GETCOUNT,0,0)-1;i>=0;i--) {
+ if(SendMessage(hwndCombo,CB_GETLBTEXTLEN,i,0) >= SIZEOF(szExistingUrl))
+ continue;
+ SendMessageA(hwndCombo,CB_GETLBTEXT,i,(LPARAM)szExistingUrl);
+ if(!lstrcmpA(szExistingUrl,url)) return;
+ }
+ i=SendMessageA(hwndCombo,CB_ADDSTRING,0,(LPARAM)url);
+ szItemData=mir_strdup(title);
+ SendMessage(hwndCombo,CB_SETITEMDATA,i,(LPARAM)szItemData);
+ }
+}
+
+//see Q160957 and http://developer.netscape.com/docs/manuals/communicator/DDE/index.htm
+static void GetOpenBrowserUrlsForBrowser(const char *szBrowser,HWND hwndDlg,HWND hwndCombo)
+{
+ ATOM hSzBrowser,hSzTopic;
+ int windowCount,i;
+ DWORD *windowId;
+ DWORD dwResult;
+ HGLOBAL hData;
+ DDEDATA *data;
+ int dataLength;
+
+ hSzBrowser=GlobalAddAtomA(szBrowser);
+
+ hSzTopic=GlobalAddAtomA("WWW_ListWindows");
+ ddeAcked=0;
+ if(!SendMessageTimeout(HWND_BROADCAST,WM_DDE_INITIATE,(WPARAM)hwndDlg,MAKELPARAM(hSzBrowser,hSzTopic),SMTO_ABORTIFHUNG|SMTO_NORMAL,DDEMESSAGETIMEOUT,(PDWORD_PTR)&dwResult)
+ || !ddeAcked) {
+ GlobalDeleteAtom(hSzTopic);
+ GlobalDeleteAtom(hSzBrowser);
+ return;
+ }
+ hData=DoDdeRequest("WWW_ListWindows",hwndDlg);
+ if(hData==NULL) {
+ GlobalDeleteAtom(hSzTopic);
+ GlobalDeleteAtom(hSzBrowser);
+ return;
+ }
+ dataLength=GlobalSize(hData)-offsetof(DDEDATA,Value);
+ data=(DDEDATA*)GlobalLock(hData);
+ windowCount=dataLength/sizeof(DWORD);
+ windowId=(PDWORD)mir_alloc(sizeof(DWORD)*windowCount);
+ memcpy(windowId,data->Value,windowCount*sizeof(DWORD));
+ GlobalUnlock(hData);
+ FreeDdeRequestData(hData);
+ PostMessage(hwndDde,WM_DDE_TERMINATE,(WPARAM)hwndDlg,0);
+ GlobalDeleteAtom(hSzTopic);
+
+ hSzTopic=GlobalAddAtomA("WWW_GetWindowInfo");
+ ddeAcked=0;
+ if(!SendMessageTimeout(HWND_BROADCAST,WM_DDE_INITIATE,(WPARAM)hwndDlg,MAKELPARAM(hSzBrowser,hSzTopic),SMTO_ABORTIFHUNG|SMTO_NORMAL,DDEMESSAGETIMEOUT,(PDWORD_PTR)&dwResult)
+ || !ddeAcked) {
+ GlobalDeleteAtom(hSzTopic);
+ GlobalDeleteAtom(hSzBrowser);
+ mir_free(windowId);
+ return;
+ }
+ for(i=0;i<windowCount;i++) {
+ if(windowId[i]==0) break;
+ { char str[16];
+ mir_snprintf(str, SIZEOF(str), "%d",windowId[i]);
+ hData=DoDdeRequest(str,hwndDlg);
+ }
+ if(hData!=NULL) {
+ dataLength=GlobalSize(hData)-offsetof(DDEDATA,Value);
+ data=(DDEDATA*)GlobalLock(hData);
+ AddBrowserPageToCombo((char*)data->Value,hwndCombo);
+ GlobalUnlock(hData);
+ FreeDdeRequestData(hData);
+ }
+ }
+ PostMessage(hwndDde,WM_DDE_TERMINATE,(WPARAM)hwndDlg,0);
+ GlobalDeleteAtom(hSzTopic);
+ GlobalDeleteAtom(hSzBrowser);
+ mir_free(windowId);
+}
+
+static void GetOpenBrowserUrls(HWND hwndDlg,HWND hwndCombo)
+{
+ GetOpenBrowserUrlsForBrowser("opera",hwndDlg,hwndCombo);
+ GetOpenBrowserUrlsForBrowser("netscape",hwndDlg,hwndCombo);
+ GetOpenBrowserUrlsForBrowser("iexplore",hwndDlg,hwndCombo);
+}
+
+static WNDPROC OldSendEditProc;
+static LRESULT CALLBACK SendEditSubclassProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
+{
+ switch(msg) {
+ case WM_CHAR:
+ if(wParam=='\n' && GetKeyState(VK_CONTROL)&0x8000) {
+ PostMessage(GetParent(hwnd),WM_COMMAND,IDOK,0);
+ return 0;
+ }
+ break;
+ case WM_SYSCHAR:
+ if((wParam=='s' || wParam=='S') && GetKeyState(VK_MENU)&0x8000) {
+ PostMessage(GetParent(hwnd),WM_COMMAND,IDOK,0);
+ return 0;
+ }
+ break;
+ }
+ return CallWindowProc(OldSendEditProc,hwnd,msg,wParam,lParam);
+}
+
+INT_PTR CALLBACK DlgProcUrlSend(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct UrlSendData* dat = (struct UrlSendData*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA);
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ Window_SetIcon_IcoLib(hwndDlg, SKINICON_EVENT_URL);
+ Button_SetIcon_IcoLib(hwndDlg, IDC_ADD, SKINICON_OTHER_ADDCONTACT, LPGEN("Add Contact Permanently to List"));
+ Button_SetIcon_IcoLib(hwndDlg, IDC_DETAILS, SKINICON_OTHER_USERDETAILS, LPGEN("View User's Details"));
+ Button_SetIcon_IcoLib(hwndDlg, IDC_HISTORY, SKINICON_OTHER_HISTORY, LPGEN("View User's History"));
+ Button_SetIcon_IcoLib(hwndDlg, IDC_USERMENU, SKINICON_OTHER_DOWNARROW, LPGEN("User Menu"));
+
+ SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_LIMITTEXT, 450, 0);
+ dat=(struct UrlSendData*)mir_alloc(sizeof(struct UrlSendData));
+ SetWindowLongPtr(hwndDlg,GWLP_USERDATA,(LONG_PTR)dat);
+ dat->hContact=(HANDLE)lParam;
+ dat->hAckEvent=NULL;
+ dat->hSendId=NULL;
+ dat->sendBuffer=NULL;
+
+ WindowList_Add(hUrlWindowList, hwndDlg, dat->hContact);
+ {
+ TCHAR *str = cli.pfnGetContactDisplayName( dat->hContact, 0 );
+ SetDlgItemText(hwndDlg,IDC_NAME,str);
+ }
+
+ GetOpenBrowserUrls(hwndDlg,GetDlgItem(hwndDlg,IDC_URLS));
+ SendDlgItemMessage(hwndDlg, IDC_URLS, CB_SETCURSEL, 0, 0);
+ if (SendDlgItemMessage(hwndDlg,IDC_URLS,CB_GETCOUNT,0,0))SendMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_URLS,CBN_SELCHANGE),0);
+ EnableWindow(GetDlgItem(hwndDlg, IDOK), (SendDlgItemMessage(hwndDlg, IDC_URLS, CB_GETCURSEL, 0, 0) == CB_ERR)?FALSE:TRUE);
+ Utils_RestoreWindowPositionNoSize(hwndDlg,NULL,"SRUrl","send");
+ OldSendEditProc=(WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_MESSAGE),GWLP_WNDPROC,(LONG_PTR)SendEditSubclassProc);
+ OldSendEditProc=(WNDPROC)SetWindowLongPtr(GetWindow(GetDlgItem(hwndDlg,IDC_URLS),GW_CHILD),GWLP_WNDPROC,(LONG_PTR)SendEditSubclassProc);
+
+ // From message dlg
+ if (!DBGetContactSettingByte(dat->hContact, "CList", "NotOnList", 0))
+ ShowWindow(GetDlgItem(hwndDlg, IDC_ADD), SW_HIDE);
+
+ SendMessage(hwndDlg,DM_UPDATETITLE,0,0);
+ // From message dlg end
+ return TRUE;
+
+ case WM_DDE_DATA:
+ case WM_DDE_ACK:
+ return DdeMessage(hwndDlg,msg,wParam,lParam);
+
+ case WM_TIMER:
+ if ( wParam == 0 ) {
+ //ICQ sendurl timed out
+ KillTimer(hwndDlg,0);
+ MessageBox(hwndDlg,TranslateT("Send timed out"),_T(""),MB_OK);
+ EnableWindow(GetDlgItem(hwndDlg,IDOK),TRUE);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_URLS),TRUE);
+ SendDlgItemMessage(hwndDlg,IDC_MESSAGE,EM_SETREADONLY,FALSE,0);
+ }
+ break;
+
+ case WM_MEASUREITEM:
+ return CallService(MS_CLIST_MENUMEASUREITEM,wParam,lParam);
+
+ case WM_DRAWITEM:
+ {
+ LPDRAWITEMSTRUCT dis = ( LPDRAWITEMSTRUCT )lParam;
+ if ( dis->hwndItem == GetDlgItem(hwndDlg, IDC_PROTOCOL)) {
+ char *szProto = ( char* )CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)dat->hContact,0);
+ if (szProto) {
+ HICON hIcon = (HICON)CallProtoService(szProto,PS_LOADICON,PLI_PROTOCOL|PLIF_SMALL,0);
+ if ( hIcon ) {
+ DrawIconEx(dis->hDC,dis->rcItem.left,dis->rcItem.top,hIcon,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0,NULL,DI_NORMAL);
+ DestroyIcon(hIcon);
+ } } } }
+ return CallService(MS_CLIST_MENUDRAWITEM,wParam,lParam);
+
+ case DM_UPDATETITLE:
+ sttUpdateTitle( hwndDlg, dat->hContact );
+ break;
+
+ case WM_COMMAND:
+ if(CallService(MS_CLIST_MENUPROCESSCOMMAND,MAKEWPARAM(LOWORD(wParam),MPCF_CONTACTMENU),(LPARAM)dat->hContact))
+ break;
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ {
+ char *body,*url;
+ int bodySize,urlSize;
+
+ urlSize=GetWindowTextLength(GetDlgItem(hwndDlg,IDC_URLS))+1;
+ url=(char*)mir_alloc(urlSize);
+ GetDlgItemTextA(hwndDlg,IDC_URLS,url,urlSize);
+ if (url[0] == 0) {
+ mir_free(url);
+ break;
+ }
+ bodySize=GetWindowTextLength(GetDlgItem(hwndDlg,IDC_MESSAGE))+1;
+ body=(char*)mir_alloc(bodySize);
+ GetDlgItemTextA(hwndDlg,IDC_MESSAGE,body,bodySize);
+
+ dat->sendBuffer=(char*)mir_realloc(dat->sendBuffer,lstrlenA(url)+lstrlenA(body)+2);
+ lstrcpyA(dat->sendBuffer,url);
+ lstrcpyA(dat->sendBuffer+lstrlenA(url)+1,body);
+ dat->hAckEvent=HookEventMessage(ME_PROTO_ACK,hwndDlg,HM_EVENTSENT);
+ dat->hSendId=(HANDLE)CallContactService(dat->hContact,PSS_URL,0,(LPARAM)dat->sendBuffer);
+ mir_free(url);
+ mir_free(body);
+
+ //create a timeout timer
+ SetTimer(hwndDlg,0,TIMEOUT_URLSEND,NULL);
+ EnableWindow(GetDlgItem(hwndDlg,IDOK),FALSE);
+ EnableWindow(GetDlgItem(hwndDlg,IDC_URLS),FALSE);
+ SendDlgItemMessage(hwndDlg,IDC_MESSAGE,EM_SETREADONLY,TRUE,0);
+
+ return TRUE;
+ }
+
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ return TRUE;
+ case IDC_URLS:
+ if(HIWORD(wParam)==CBN_SELCHANGE) {
+ int i, urlSize;
+ char *title;
+ i=SendDlgItemMessage(hwndDlg,IDC_URLS,CB_GETCURSEL,0,0);
+ title=(char*)SendDlgItemMessage(hwndDlg,IDC_URLS,CB_GETITEMDATA,(WPARAM)i,0);
+ SetDlgItemTextA(hwndDlg,IDC_MESSAGE,title);
+ urlSize=SendDlgItemMessage(hwndDlg,IDC_URLS,CB_GETLBTEXTLEN,(WPARAM)i,0);
+ EnableWindow(GetDlgItem(hwndDlg,IDOK), (urlSize>0));
+ }
+ else if(HIWORD(wParam)==CBN_EDITCHANGE) {
+ int urlSize = GetWindowTextLength(GetDlgItem(hwndDlg,IDC_URLS));
+ EnableWindow(GetDlgItem(hwndDlg,IDOK), (urlSize>0));
+ }
+ break;
+ case IDC_USERMENU:
+ { RECT rc;
+ HMENU hMenu=(HMENU)CallService(MS_CLIST_MENUBUILDCONTACT,(WPARAM)dat->hContact,0);
+ GetWindowRect(GetDlgItem(hwndDlg,IDC_USERMENU),&rc);
+ TrackPopupMenu(hMenu,0,rc.left,rc.bottom,0,hwndDlg,NULL);
+ DestroyMenu(hMenu);
+ }
+ break;
+ case IDC_HISTORY:
+ CallService(MS_HISTORY_SHOWCONTACTHISTORY,(WPARAM)dat->hContact,0);
+ break;
+ case IDC_DETAILS:
+ CallService(MS_USERINFO_SHOWDIALOG,(WPARAM)dat->hContact,0);
+ break;
+ case IDC_ADD:
+ { ADDCONTACTSTRUCT acs={0};
+
+ acs.handle=dat->hContact;
+ acs.handleType=HANDLE_CONTACT;
+ acs.szProto=0;
+ CallService(MS_ADDCONTACT_SHOW,(WPARAM)hwndDlg,(LPARAM)&acs);
+ }
+ if (!DBGetContactSettingByte(dat->hContact,"CList","NotOnList",0)) {
+ ShowWindow(GetDlgItem(hwndDlg,IDC_ADD),FALSE);
+ }
+ break;
+ }
+ break;
+ case HM_EVENTSENT:
+ { ACKDATA *ack=(ACKDATA*)lParam;
+ DBEVENTINFO dbei;
+ if(ack->hProcess!=dat->hSendId) break;
+ if(ack->hContact!=dat->hContact) break;
+ if(ack->type!=ACKTYPE_URL || ack->result!=ACKRESULT_SUCCESS) break;
+
+ ZeroMemory(&dbei,sizeof(dbei));
+ dbei.cbSize=sizeof(dbei);
+ dbei.eventType=EVENTTYPE_URL;
+ dbei.flags=DBEF_SENT;
+ dbei.szModule=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)dat->hContact,0);
+ dbei.timestamp=time(NULL);
+ dbei.cbBlob=(DWORD)(strlen(dat->sendBuffer)+strlen(dat->sendBuffer+strlen(dat->sendBuffer)+1)+2);
+ dbei.pBlob=(PBYTE)dat->sendBuffer;
+ CallService(MS_DB_EVENT_ADD,(WPARAM)dat->hContact,(LPARAM)&dbei);
+ KillTimer(hwndDlg,0);
+ DestroyWindow(hwndDlg);
+ break;
+ }
+ case WM_DESTROY:
+ Window_FreeIcon_IcoLib(hwndDlg);
+ Button_FreeIcon_IcoLib(hwndDlg,IDC_ADD);
+ Button_FreeIcon_IcoLib(hwndDlg,IDC_DETAILS);
+ Button_FreeIcon_IcoLib(hwndDlg,IDC_HISTORY);
+ Button_FreeIcon_IcoLib(hwndDlg,IDC_USERMENU);
+
+ WindowList_Remove(hUrlWindowList, hwndDlg);
+ SetWindowLongPtr(GetWindow(GetDlgItem(hwndDlg,IDC_URLS),GW_CHILD),GWLP_WNDPROC,(LONG_PTR)OldSendEditProc);
+ SetWindowLongPtr(GetDlgItem(hwndDlg,IDC_MESSAGE),GWLP_WNDPROC,(LONG_PTR)OldSendEditProc);
+ if(dat->hAckEvent) UnhookEvent(dat->hAckEvent);
+ if(dat->sendBuffer!=NULL) mir_free(dat->sendBuffer);
+ mir_free(dat);
+ Utils_SaveWindowPosition(hwndDlg,NULL,"SRUrl","send");
+ { int i;
+ for(i=SendDlgItemMessage(hwndDlg,IDC_URLS,CB_GETCOUNT,0,0)-1;i>=0;i--)
+ mir_free((char*)SendDlgItemMessage(hwndDlg,IDC_URLS,CB_GETITEMDATA,i,0));
+ }
+ break;
+ }
+
+ return FALSE;
+}
diff --git a/src/modules/updatenotify/updatenotify.cpp b/src/modules/updatenotify/updatenotify.cpp
new file mode 100644
index 0000000000..ef955ba3c5
--- /dev/null
+++ b/src/modules/updatenotify/updatenotify.cpp
@@ -0,0 +1,680 @@
+/*
+
+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 UN_MOD "UpdateNotify"
+#define UN_ENABLE "UpdateNotifyEnable"
+#define UN_ENABLE_DEF 1
+#define UN_LASTCHECK "UpdateNotifyLastCheck"
+#define UN_SERVERPERIOD "UpdateNotifyPingDelayPeriod"
+#define UN_CURRENTVERSION "UpdateNotifyCurrentVersion"
+#define UN_CURRENTVERSIONFND "UpdateNotifyCurrentVersionFound"
+#define UN_NOTIFYTYPE "UpdateNotifyType"
+#define UN_NOTIFYTYPE_STABLE 1
+#define UN_NOTIFYTYPE_BETA 2
+#define UN_NOTIFYTYPE_ALPHA 3
+#define UN_NOTIFYTYPE_DEF UN_NOTIFYTYPE_STABLE
+#define UN_CUSTOMXMLURL "UpdateNotifyCustomXMLURL"
+#define UN_URLXML "http://update.miranda-im.org/update.xml"
+#define UN_MINCHECKTIME 60*60 /* Check no more than once an hour */
+#define UN_DEFAULTCHECKTIME 60*48*60 /* Default to check once every 48 hours */
+#define UN_FIRSTCHECK 15 /* First check 15 seconds after startup */
+#define UN_REPEATNOTIFYDLY 24*60*60 /* 24 hours before showing release notification again */
+
+typedef struct {
+ int isNew;
+ int isManual;
+ char version[64];
+ char versionReal[16];
+ char notesUrl[256];
+ char downloadUrl[256];
+ DWORD reqTime;
+} UpdateNotifyData;
+
+typedef struct {
+ DWORD dwVersion;
+ char *szVersionPublic;
+ char *szVersion;
+ char *szDownload;
+ char *szNotes;
+} UpdateNotifyReleaseData;
+
+static BOOL bModuleInitialized = FALSE;
+static HANDLE hNetlibUser = 0, hHookModules, hHookPreShutdown;
+static UINT_PTR updateTimerId;
+static HANDLE dwUpdateThreadID = 0;
+static HWND hwndUpdateDlg = 0, hwndManualUpdateDlg = 0;
+static XML_API xun;
+
+static int UpdateNotifyOptInit(WPARAM wParam, LPARAM lParam);
+static INT_PTR UpdateNotifyMenuCommand(WPARAM wParam, LPARAM lParam);
+static VOID CALLBACK UpdateNotifyTimerCheck(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);
+static int UpdateNotifyMakeRequest(UpdateNotifyData *und);
+static void UpdateNotifyPerform(void *m);
+static INT_PTR CALLBACK UpdateNotifyProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+static INT_PTR CALLBACK UpdateNotifyOptsProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+static int UpdateNotifyModulesLoaded(WPARAM, LPARAM) {
+ NETLIBUSER nlu;
+
+ ZeroMemory(&nlu, sizeof(nlu));
+ nlu.cbSize = sizeof(nlu);
+ nlu.flags = NUF_OUTGOING|NUF_HTTPCONNS;
+ nlu.szSettingsModule = UN_MOD;
+ nlu.szDescriptiveName = Translate("Update notification");
+ hNetlibUser = (HANDLE)CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu);
+ return 0;
+}
+
+static int UpdateNotifyPreShutdown(WPARAM, LPARAM) {
+ if (IsWindow(hwndUpdateDlg)) {
+ SendMessage(hwndUpdateDlg, WM_COMMAND, MAKELONG(IDOK, 0), 0);
+ }
+ if (IsWindow(hwndManualUpdateDlg)) {
+ SendMessage(hwndManualUpdateDlg, WM_COMMAND, MAKELONG(IDOK, 0), 0);
+ }
+ return 0;
+}
+
+int LoadUpdateNotifyModule(void) {
+ CLISTMENUITEM mi = { 0 };
+
+ bModuleInitialized = TRUE;
+
+ // Upgrade Routine
+ if (DBGetContactSettingByte(NULL, UN_MOD, "UpdateNotifyNotifyAlpha", 0)) {
+ DBDeleteContactSetting(NULL, UN_MOD, "UpdateNotifyNotifyAlpha");
+ DBWriteContactSettingByte(NULL, UN_MOD, UN_NOTIFYTYPE, UN_NOTIFYTYPE_ALPHA);
+ }
+ // Ene Upgrade Routine
+
+ CreateServiceFunction("UpdateNotify/UpdateCommand", UpdateNotifyMenuCommand);
+ mi.cbSize = sizeof(mi);
+ mi.flags = CMIF_ICONFROMICOLIB;
+ mi.icolibItem = GetSkinIconHandle(SKINICON_OTHER_EMPTYBLOB);
+ mi.pszPopupName = LPGEN("&Help");
+ mi.position = 2000030000;
+ mi.pszName = LPGEN("Check for Update");
+ mi.pszService = "UpdateNotify/UpdateCommand";
+ CallService(MS_CLIST_ADDMAINMENUITEM,0,(LPARAM)&mi);
+
+ hHookModules = HookEvent(ME_SYSTEM_MODULESLOADED, UpdateNotifyModulesLoaded);
+ hHookPreShutdown = HookEvent(ME_SYSTEM_PRESHUTDOWN, UpdateNotifyPreShutdown);
+ HookEvent(ME_OPT_INITIALISE, UpdateNotifyOptInit);
+ updateTimerId = SetTimer(NULL, 0, 1000*UN_FIRSTCHECK, UpdateNotifyTimerCheck);
+ mir_getXI(&xun);
+ return 0;
+}
+
+void UnloadUpdateNotifyModule()
+{
+ if (!bModuleInitialized) return;
+ UnhookEvent(hHookModules);
+ UnhookEvent(hHookPreShutdown);
+}
+
+static int UpdateNotifyOptInit(WPARAM wParam, LPARAM) {
+ OPTIONSDIALOGPAGE odp;
+
+ ZeroMemory(&odp, sizeof(odp));
+ odp.cbSize = sizeof(odp);
+ odp.position = 100000000;
+ odp.hInstance = hMirandaInst;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_UPDATENOTIFY);
+ odp.pszGroup = LPGEN("Events");
+ odp.pszTitle = LPGEN("Update Notify");
+ odp.pfnDlgProc = UpdateNotifyOptsProc;
+ odp.flags = ODPF_BOLDGROUPS;
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM)&odp);
+ return 0;
+}
+
+static INT_PTR UpdateNotifyMenuCommand(WPARAM, LPARAM) {
+ UpdateNotifyData und;
+
+ if (IsWindow(hwndManualUpdateDlg)) {
+ SetForegroundWindow(hwndManualUpdateDlg);
+ return 0;
+ }
+ ZeroMemory(&und, sizeof(und));
+ UpdateNotifyMakeRequest(&und);
+ if (und.isNew) {
+ DBWriteContactSettingString(NULL, UN_MOD, UN_CURRENTVERSION, und.versionReal);
+ DBWriteContactSettingDword(NULL, UN_MOD, UN_CURRENTVERSIONFND, und.reqTime);
+ }
+ und.isManual = 1;
+ DialogBoxParam(hMirandaInst, MAKEINTRESOURCE(IDD_UPDATE_NOTIFY), 0, UpdateNotifyProc,(LPARAM)&und);
+ hwndManualUpdateDlg = 0;
+ return 0;
+}
+
+static VOID CALLBACK UpdateNotifyTimerCheck(HWND, UINT, UINT_PTR, DWORD)
+{
+ KillTimer(NULL, updateTimerId);
+ if (!DBGetContactSettingByte(NULL, UN_MOD, UN_ENABLE, UN_ENABLE_DEF))
+ return;
+ if (dwUpdateThreadID!=0) {
+ Netlib_Logf(hNetlibUser, "Update notification already running, ignoring attempt");
+ return;
+ }
+ {
+ DWORD lastCheck = 0;
+
+ if (!hNetlibUser)
+ return;
+ lastCheck = DBGetContactSettingDword(NULL, UN_MOD, UN_LASTCHECK, 0);
+ if (!lastCheck) { // never checked for update before
+ Netlib_Logf(hNetlibUser, "Running update notify check for the first time.");
+ dwUpdateThreadID = mir_forkthread(UpdateNotifyPerform, 0);
+ }
+ else {
+ DWORD dwNow = time(NULL), dwTimeDiff;
+ DWORD dwServerPing = DBGetContactSettingDword(NULL, UN_MOD, UN_SERVERPERIOD, UN_DEFAULTCHECKTIME);
+
+ if (lastCheck>dwNow) {
+ // time for last check is after the current date so reset lastcheck and quit
+ DBWriteContactSettingDword(NULL, UN_MOD, UN_LASTCHECK, dwNow);
+ return;
+ }
+ dwTimeDiff = dwNow - lastCheck;
+ if (dwServerPing<UN_MINCHECKTIME)
+ dwServerPing = UN_MINCHECKTIME;
+ if (dwTimeDiff>dwServerPing)
+ dwUpdateThreadID = mir_forkthread(UpdateNotifyPerform, 0);
+ }
+ updateTimerId = SetTimer(NULL, 0, 1000*UN_MINCHECKTIME, UpdateNotifyTimerCheck);
+ }
+}
+
+static DWORD UpdateNotifyMakeVersion(char *str) {
+ DWORD a1,a2,a3,a4;
+ if (!str)
+ return 0;
+ sscanf(str, "%u.%u.%u.%u", &a1, &a2, &a3, &a4);
+ return PLUGIN_MAKE_VERSION(a1, a2, a3, a4);
+}
+
+static int UpdateNotifyIsNewer(DWORD dwCurrent, DWORD dwTest) {
+ if (dwTest>dwCurrent)
+ return 1;
+ return 0;
+}
+
+static int UpdateNotifyReleaseDataValid(UpdateNotifyReleaseData *d) {
+ if (d&&d->szVersionPublic&&d->szVersion&&d->szDownload&&d->szNotes)
+ return 1;
+ return 0;
+}
+
+static void UpdateNotifyFreeReleaseData(UpdateNotifyReleaseData *d) {
+ if (!d)
+ return;
+ if (d->szVersionPublic) mir_free(d->szVersionPublic);
+ if (d->szVersion) mir_free(d->szVersion);
+ if (d->szDownload) mir_free(d->szDownload);
+ if (d->szNotes) mir_free(d->szNotes);
+}
+
+static void UpdateNotifyReleaseLogUpdate(UpdateNotifyReleaseData *d) {
+ if (!UpdateNotifyReleaseDataValid(d))
+ return;
+ #ifdef _WIN64
+ Netlib_Logf(hNetlibUser, "Update server version: %s [%s] [64-bit]", d->szVersionPublic, d->szVersion);
+ #elif defined(_UNICODE)
+ Netlib_Logf(hNetlibUser, "Update server version: %s [%s] [Unicode]", d->szVersionPublic, d->szVersion);
+ #else
+ Netlib_Logf(hNetlibUser, "Update server version: %s [%s] [ANSI]", d->szVersionPublic, d->szVersion);
+ #endif
+
+}
+
+static void UpdateNotifyReleaseCopyData(UpdateNotifyReleaseData *d, UpdateNotifyData *und) {
+ if (!UpdateNotifyReleaseDataValid(d)||!und)
+ return;
+ mir_snprintf(und->version, sizeof(und->version), "%s", d->szVersionPublic);
+ mir_snprintf(und->versionReal, sizeof(und->versionReal), "%s", d->szVersion);
+ mir_snprintf(und->notesUrl, sizeof(und->notesUrl), "%s", d->szNotes);
+ mir_snprintf(und->downloadUrl, sizeof(und->downloadUrl), "%s", d->szDownload);
+}
+
+static int UpdateNotifyMakeRequest(UpdateNotifyData *und) {
+ NETLIBHTTPREQUEST req;
+ NETLIBHTTPREQUEST *resp;
+ NETLIBHTTPHEADER headers[1];
+ DWORD dwVersion;
+ char szVersion[32], szUrl[256], szVersionText[128], szUserAgent[64];
+ int isUnicode, isAlphaCheck, isBetaCheck;
+ DBVARIANT dbv;
+
+ if (!und)
+ return 0;
+ und->version[0] = 0;
+ und->versionReal[0] = 0;
+ und->notesUrl[0] = 0;
+ und->downloadUrl[0] = 0;
+ und->reqTime = time(NULL);
+
+ DBWriteContactSettingDword(NULL, UN_MOD, UN_LASTCHECK, und->reqTime);
+ CallService(MS_SYSTEM_GETVERSIONTEXT, sizeof(szVersionText), (LPARAM)szVersionText);
+ isUnicode = strstr(szVersionText, "Unicode") != NULL ? 1 : 0;
+ isBetaCheck = DBGetContactSettingByte(NULL, UN_MOD, UN_NOTIFYTYPE, UN_NOTIFYTYPE_DEF)==UN_NOTIFYTYPE_BETA?1:0;
+ isAlphaCheck = DBGetContactSettingByte(NULL, UN_MOD, UN_NOTIFYTYPE, UN_NOTIFYTYPE_DEF)==UN_NOTIFYTYPE_ALPHA?1:0;
+ dwVersion = CallService(MS_SYSTEM_GETVERSION, 0, 0);
+ mir_snprintf(szVersion, sizeof(szVersion), "%d.%d.%d.%d",
+ HIBYTE(HIWORD(dwVersion)), LOBYTE(HIWORD(dwVersion)),
+ HIBYTE(LOWORD(dwVersion)), LOBYTE(LOWORD(dwVersion)));
+ if (!DBGetContactSettingString(NULL, UN_MOD, UN_CUSTOMXMLURL, &dbv)) {
+ mir_snprintf(szUrl, sizeof(szUrl), "%s", dbv.pszVal?dbv.pszVal:UN_URLXML);
+ DBFreeVariant(&dbv);
+ }
+ else mir_snprintf(szUrl, sizeof(szUrl), "%s", UN_URLXML);
+ ZeroMemory(&req, sizeof(req));
+ req.cbSize = sizeof(req);
+ req.requestType = REQUEST_GET;
+ req.szUrl = szUrl;
+ req.flags = 0;
+ headers[0].szName = "User-Agent";
+ headers[0].szValue = szUserAgent;
+ #ifdef _WIN64
+ mir_snprintf(szUserAgent, sizeof(szUserAgent), "Miranda/%s (x64)", szVersion);
+ #elif defined(_UNICODE)
+ mir_snprintf(szUserAgent, sizeof(szUserAgent), "Miranda/%s (Unicode)", szVersion);
+ #else
+ mir_snprintf(szUserAgent, sizeof(szUserAgent), "Miranda/%s (ANSI)", szVersion);
+ #endif
+ req.headersCount = 1;
+ req.headers = headers;
+ resp = (NETLIBHTTPREQUEST *)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)hNetlibUser, (LPARAM)&req);
+ if (resp) {
+ if (resp->resultCode == 200 && resp->dataLength > 0) {
+ //int i;
+ int resUpdate = 0;
+ TCHAR *tXml;
+ char *tmp;
+ HXML nodeDoc, n;
+
+ tXml = mir_a2t(resp->pData);
+ nodeDoc = xun.parseString(tXml, 0, _T("miranda"));
+ if (nodeDoc) {
+ int rdStableValid = 0, rdBetaValid = 0, rdAlphaValid = 0;
+ // stable release
+ UpdateNotifyReleaseData rdStable;
+ ZeroMemory(&rdStable, sizeof(rdStable));
+ if ((n = xun.getChildByPath(nodeDoc, _T("releases/releasestable/versionpublic"), 0)) != NULL && xun.getText(n)) {
+ rdStable.szVersionPublic = mir_t2a(xun.getText(n));
+ }
+ if ((n = xun.getChildByPath(nodeDoc, _T("releases/releasestable/versionreal"), 0)) != NULL && xun.getText(n)) {
+ rdStable.szVersion = mir_t2a(xun.getText(n));
+ if (rdStable.szVersion)
+ rdStable.dwVersion = UpdateNotifyMakeVersion(rdStable.szVersion);
+ }
+ #ifdef _WIN64
+ if ((n = xun.getChildByPath(nodeDoc, _T("releases/releasestable/downloadx64exe"), 0)) != NULL && xun.getText(n)) {
+ rdStable.szDownload = mir_t2a(xun.getText(n));
+ }
+ #elif defined(_UNICODE)
+ if ((n = xun.getChildByPath(nodeDoc, _T("releases/releasestable/downloadunicodeexe"), 0)) != NULL && xun.getText(n)) {
+ rdStable.szDownload = mir_t2a(xun.getText(n));
+ }
+ #else
+ if ((n = xun.getChildByPath(nodeDoc, _T("releases/releasestable/downloadansiexe"), 0)) != NULL && xun.getText(n)) {
+ rdStable.szDownload = mir_t2a(xun.getText(n));
+ }
+ #endif
+ if ((n = xun.getChildByPath(nodeDoc, _T("releases/releasestable/notesurl"), 0)) != NULL && xun.getText(n)) {
+ rdStable.szNotes = mir_t2a(xun.getText(n));
+ }
+ rdStableValid = UpdateNotifyReleaseDataValid(&rdStable);
+
+ // beta release
+ UpdateNotifyReleaseData rdBeta;
+ ZeroMemory(&rdBeta, sizeof(rdBeta));
+ if ((n = xun.getChildByPath(nodeDoc, _T("releases/releasebeta/versionpublic"), 0)) != NULL && xun.getText(n)) {
+ rdBeta.szVersionPublic = mir_t2a(xun.getText(n));
+ }
+ if ((n = xun.getChildByPath(nodeDoc, _T("releases/releasebeta/versionreal"), 0)) != NULL && xun.getText(n)) {
+ rdBeta.szVersion = mir_t2a(xun.getText(n));
+ if (rdBeta.szVersion)
+ rdBeta.dwVersion = UpdateNotifyMakeVersion(rdBeta.szVersion);
+ }
+ #ifdef _WIN64
+ if ((n = xun.getChildByPath(nodeDoc, _T("releases/releasebeta/downloadx64zip"), 0)) != NULL && xun.getText(n)) {
+ rdBeta.szDownload = mir_t2a(xun.getText(n));
+ }
+ #elif defined(_UNICODE)
+ if ((n = xun.getChildByPath(nodeDoc, _T("releases/releasebeta/downloadunicodeexe"), 0)) != NULL && xun.getText(n)) {
+ rdBeta.szDownload = mir_t2a(xun.getText(n));
+ }
+ #else
+ if ((n = xun.getChildByPath(nodeDoc, _T("releases/releasebeta/downloadansiexe"), 0)) != NULL && xun.getText(n)) {
+ rdBeta.szDownload = mir_t2a(xun.getText(n));
+ }
+ #endif
+ if ((n = xun.getChildByPath(nodeDoc, _T("releases/releasebeta/notesurl"), 0)) != NULL && xun.getText(n)) {
+ rdBeta.szNotes = mir_t2a(xun.getText(n));
+ }
+ rdBetaValid = UpdateNotifyReleaseDataValid(&rdBeta);
+
+ // alpha release
+ UpdateNotifyReleaseData rdAlpha;
+ ZeroMemory(&rdAlpha, sizeof(rdAlpha));
+ if ((n = xun.getChildByPath(nodeDoc, _T("releases/releasealpha/versionpublic"), 0)) != NULL && xun.getText(n)) {
+ rdAlpha.szVersionPublic = mir_t2a(xun.getText(n));
+ }
+ if ((n = xun.getChildByPath(nodeDoc, _T("releases/releasealpha/versionreal"), 0)) != NULL && xun.getText(n)) {
+ rdAlpha.szVersion = mir_t2a(xun.getText(n));
+ if (rdAlpha.szVersion)
+ rdAlpha.dwVersion = UpdateNotifyMakeVersion(rdAlpha.szVersion);
+ }
+ #ifdef _WIN64
+ if ((n = xun.getChildByPath(nodeDoc, _T("releases/releasealpha/downloadx64zip"), 0)) != NULL && xun.getText(n)) {
+ rdAlpha.szDownload = mir_t2a(xun.getText(n));
+ }
+ #elif defined(_UNICODE)
+ if ((n = xun.getChildByPath(nodeDoc, _T("releases/releasealpha/downloadunicodezip"), 0)) != NULL && xun.getText(n)) {
+ rdAlpha.szDownload = mir_t2a(xun.getText(n));
+ }
+ #else
+ if ((n = xun.getChildByPath(nodeDoc, _T("releases/releasealpha/downloadansizip"), 0)) != NULL && xun.getText(n)) {
+ rdAlpha.szDownload = mir_t2a(xun.getText(n));
+ }
+ #endif
+ if ((n = xun.getChildByPath(nodeDoc, _T("releases/releasealpha/notesurl"), 0)) != NULL && xun.getText(n)) {
+ rdAlpha.szNotes = mir_t2a(xun.getText(n));
+ }
+ rdAlphaValid = UpdateNotifyReleaseDataValid(&rdAlpha);
+
+ if (isBetaCheck) {
+ if (!rdBetaValid&&rdStableValid) {
+ UpdateNotifyReleaseLogUpdate(&rdStable);
+ if (UpdateNotifyIsNewer(dwVersion, rdStable.dwVersion))
+ resUpdate = 1;
+ UpdateNotifyReleaseCopyData(&rdStable, und);
+ }
+ else if (rdBetaValid&&rdStableValid&&UpdateNotifyIsNewer(rdBeta.dwVersion, rdStable.dwVersion)) {
+ UpdateNotifyReleaseLogUpdate(&rdStable);
+ if (UpdateNotifyIsNewer(dwVersion, UpdateNotifyMakeVersion(rdStable.szVersion)))
+ resUpdate = 1;
+ UpdateNotifyReleaseCopyData(&rdStable, und);
+ }
+ else if (rdBetaValid) {
+ UpdateNotifyReleaseLogUpdate(&rdBeta);
+ if (UpdateNotifyIsNewer(dwVersion, rdBeta.dwVersion))
+ resUpdate = 1;
+ UpdateNotifyReleaseCopyData(&rdBeta, und);
+ }
+ }
+ else if (isAlphaCheck) {
+ if (!rdAlphaValid&&rdStableValid) {
+ if (UpdateNotifyIsNewer(rdStable.dwVersion, rdAlpha.dwVersion)) {
+ UpdateNotifyReleaseLogUpdate(&rdAlpha);
+ if (UpdateNotifyIsNewer(dwVersion, rdAlpha.dwVersion))
+ resUpdate = 1;
+ UpdateNotifyReleaseCopyData(&rdAlpha, und);
+ }
+ else {
+ UpdateNotifyReleaseLogUpdate(&rdStable);
+ if (UpdateNotifyIsNewer(dwVersion, rdStable.dwVersion))
+ resUpdate = 1;
+ UpdateNotifyReleaseCopyData(&rdStable, und);
+ }
+ }
+ else if (rdAlphaValid&&rdStableValid&&UpdateNotifyIsNewer(rdAlpha.dwVersion, rdStable.dwVersion)) {
+ UpdateNotifyReleaseLogUpdate(&rdStable);
+ if (UpdateNotifyIsNewer(dwVersion, rdStable.dwVersion))
+ resUpdate = 1;
+ UpdateNotifyReleaseCopyData(&rdStable, und);
+ }
+ else if (!rdAlphaValid&&rdBetaValid&&rdStableValid) {
+ if (UpdateNotifyIsNewer(rdStable.dwVersion, rdBeta.dwVersion)) {
+ UpdateNotifyReleaseLogUpdate(&rdBeta);
+ if (UpdateNotifyIsNewer(dwVersion, rdBeta.dwVersion))
+ resUpdate = 1;
+ UpdateNotifyReleaseCopyData(&rdBeta, und);
+ }
+ else {
+ UpdateNotifyReleaseLogUpdate(&rdStable);
+ if (UpdateNotifyIsNewer(dwVersion, rdStable.dwVersion))
+ resUpdate = 1;
+ UpdateNotifyReleaseCopyData(&rdStable, und);
+ }
+ }
+ else if (rdAlphaValid) {
+ UpdateNotifyReleaseLogUpdate(&rdAlpha);
+ if (UpdateNotifyIsNewer(dwVersion, rdAlpha.dwVersion))
+ resUpdate = 1;
+ UpdateNotifyReleaseCopyData(&rdAlpha, und);
+ }
+ }
+ else {
+ if (rdStableValid) {
+ UpdateNotifyReleaseLogUpdate(&rdStable);
+ if (UpdateNotifyIsNewer(dwVersion, rdStable.dwVersion))
+ resUpdate = 1;
+ UpdateNotifyReleaseCopyData(&rdStable, und);
+ }
+ }
+
+ UpdateNotifyFreeReleaseData(&rdStable);
+ UpdateNotifyFreeReleaseData(&rdBeta);
+ UpdateNotifyFreeReleaseData(&rdAlpha);
+ // settings
+ if ((n = xun.getChildByPath(nodeDoc, _T("settings/ping"), 0)) != NULL && xun.getText(n)) {
+ tmp = mir_t2a(xun.getText(n));
+ if (tmp) {
+ int pingval = atoi(tmp);
+ if ((pingval*60*60)>UN_MINCHECKTIME) {
+ Netlib_Logf(hNetlibUser, "Next update check in %d hours", pingval);
+ DBWriteContactSettingDword(NULL, UN_MOD, UN_SERVERPERIOD, pingval*60*60);
+ }
+ mir_free(tmp);
+ }
+ }
+ if ((n = xun.getChildByPath(nodeDoc, _T("settings/updateurl"), 0)) != NULL && xun.getText(n)) {
+ tmp = mir_t2a(xun.getText(n));
+ if (tmp) {
+ Netlib_Logf(hNetlibUser, "Update URL has changed (%s)", tmp);
+ DBWriteContactSettingString(NULL, UN_MOD, UN_CUSTOMXMLURL, tmp);
+ mir_free(tmp);
+ }
+ }
+ if (resUpdate&&und->version&&und->versionReal&&und->notesUrl&&und->downloadUrl) {
+ Netlib_Logf(hNetlibUser, "A new version of Miranda IM is available: %s", und->version);
+ und->isNew = 1;
+ }
+ xun.destroyNode(nodeDoc);
+ }
+ mir_free(tXml);
+ }
+ else Netlib_Logf(hNetlibUser, "Invalid response code from HTTP request");
+ CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)resp);
+ }
+ else Netlib_Logf(hNetlibUser, "No response from HTTP request");
+ return und->isNew;
+}
+
+static void UpdateNotifyPerform(void *)
+{
+ UpdateNotifyData und;
+ DBVARIANT dbv;
+
+ ZeroMemory(&und, sizeof(und));
+ UpdateNotifyMakeRequest(&und);
+ if (und.isNew) {
+ int notify = 1;
+
+ if (!DBGetContactSettingString(NULL, UN_MOD, UN_CURRENTVERSION, &dbv)) {
+ if (!strcmp(dbv.pszVal, und.versionReal)) { // already notified of this version
+
+ DWORD dwNotifyLast = DBGetContactSettingDword(NULL, UN_MOD, UN_CURRENTVERSIONFND, 0);
+
+ if (dwNotifyLast>und.reqTime) { // fix last check date if time has changed
+ DBWriteContactSettingDword(NULL, UN_MOD, UN_CURRENTVERSIONFND, und.reqTime);
+ notify = 0;
+ }
+ else if (und.reqTime-dwNotifyLast<UN_REPEATNOTIFYDLY) {
+ notify = 0;
+ }
+ DBFreeVariant(&dbv);
+ }
+ }
+ if (notify) {
+ DBWriteContactSettingString(NULL, UN_MOD, UN_CURRENTVERSION, und.versionReal);
+ DBWriteContactSettingDword(NULL, UN_MOD, UN_CURRENTVERSIONFND, und.reqTime);
+ DialogBoxParam(hMirandaInst, MAKEINTRESOURCE(IDD_UPDATE_NOTIFY), 0, UpdateNotifyProc,(LPARAM)&und);
+ hwndUpdateDlg = 0;
+ }
+ }
+ dwUpdateThreadID = 0;
+}
+
+static INT_PTR CALLBACK UpdateNotifyProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch ( msg ) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ Window_SetIcon_IcoLib(hwndDlg, SKINICON_OTHER_MIRANDA);
+ {
+ UpdateNotifyData *und = (UpdateNotifyData*)lParam;
+ char szVersion[128], szVersionTmp[128], *p;
+ TCHAR szTmp[128];
+
+ if (und->isManual)
+ hwndManualUpdateDlg = hwndDlg;
+ else hwndUpdateDlg = hwndDlg;
+ if (und->isNew) {
+ TCHAR* ptszVer = mir_a2t( und->version );
+ mir_sntprintf(szTmp, SIZEOF(szTmp), TranslateT("Miranda IM %s Now Available"), ptszVer);
+ mir_free(ptszVer);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_UPDATE), SW_HIDE);
+ }
+ else {
+ mir_sntprintf(szTmp, SIZEOF(szTmp), TranslateT("No Update Available"));
+ SetDlgItemText(hwndDlg, IDC_MESSAGE, TranslateT("You are running the latest version of Miranda IM. No update is available at this time."));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_DOWNLOAD), FALSE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_VERSION), SW_HIDE);
+ }
+ SetWindowText(hwndDlg, szTmp);
+ CallService(MS_SYSTEM_GETVERSIONTEXT, sizeof(szVersion), (LPARAM)szVersion);
+ p = strstr(szVersion, "x64 Unicode");
+ if (p)
+ *p = '\0';
+ p = strstr(szVersion, " Unicode");
+ if (p)
+ *p = '\0';
+ SetDlgItemTextA(hwndDlg, IDC_CURRENTVERSION, szVersion);
+ mir_snprintf(szVersionTmp, SIZEOF(szVersionTmp), "%s", und->version?und->version:szVersion);
+ SetDlgItemTextA(hwndDlg, und->isNew?IDC_VERSION:IDC_UPDATE, szVersionTmp);
+ if (und->isNew) {
+ HFONT hFont;
+ LOGFONT lf;
+
+ hFont = (HFONT)SendDlgItemMessage(hwndDlg, IDC_VERSION, WM_GETFONT, 0, 0);
+ GetObject(hFont, sizeof(lf), &lf);
+ lf.lfWeight = FW_BOLD;
+ hFont = CreateFontIndirect(&lf);
+ SendDlgItemMessage(hwndDlg, IDC_VERSION, WM_SETFONT, (WPARAM)hFont, 0);
+ hFont = (HFONT)SendDlgItemMessage(hwndDlg, IDC_NEWVERSIONLABEL, WM_GETFONT, 0, 0);
+ GetObject(hFont, sizeof(lf), &lf);
+ lf.lfWeight = FW_BOLD;
+ hFont = CreateFontIndirect(&lf);
+ SendDlgItemMessage(hwndDlg, IDC_NEWVERSIONLABEL, WM_SETFONT, (WPARAM)hFont, 0);
+ }
+ SetFocus(GetDlgItem(hwndDlg, IDOK));
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDC_VERSION:
+ {
+ UpdateNotifyData *und = (UpdateNotifyData*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ if (und&&und->notesUrl)
+ CallService(MS_UTILS_OPENURL, 1, (LPARAM)und->notesUrl);
+ break;
+ }
+ case IDC_DOWNLOAD:
+ {
+ UpdateNotifyData *und = (UpdateNotifyData*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ if (und&&und->downloadUrl) {
+ CallService(MS_UTILS_OPENURL, 1, (LPARAM)und->downloadUrl);
+ DestroyWindow(hwndDlg);
+ }
+ break;
+ }
+ case IDOK:
+ case IDCANCEL:
+ DestroyWindow(hwndDlg);
+ return TRUE;
+ }
+ break;
+
+ case WM_DESTROY:
+ Window_FreeIcon_IcoLib( hwndDlg );
+ break;
+ }
+ return FALSE;
+}
+
+static INT_PTR CALLBACK UpdateNotifyOptsProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ CheckDlgButton(hwndDlg, IDC_ENABLEUPDATES, DBGetContactSettingByte(NULL, UN_MOD, UN_ENABLE, UN_ENABLE_DEF) ? BST_CHECKED : BST_UNCHECKED);
+ switch (DBGetContactSettingByte(NULL, UN_MOD, UN_NOTIFYTYPE, UN_NOTIFYTYPE_STABLE)) {
+ case UN_NOTIFYTYPE_BETA: CheckDlgButton(hwndDlg, IDC_ENABLEBETA, BST_CHECKED); break;
+ case UN_NOTIFYTYPE_ALPHA: CheckDlgButton(hwndDlg, IDC_ENABLEALPHA, BST_CHECKED); break;
+ default: CheckDlgButton(hwndDlg, IDC_ENABLESTABLE, BST_CHECKED); break;
+ }
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDC_ENABLEUPDATES:
+ case IDC_ENABLEALPHA:
+ case IDC_ENABLEBETA:
+ case IDC_ENABLESTABLE:
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+ break;
+
+ case WM_NOTIFY:
+ {
+ NMHDR *hdr = (NMHDR *)lParam;
+ if (hdr&&hdr->code==PSN_APPLY) {
+ DBWriteContactSettingByte(NULL, UN_MOD, UN_ENABLE, (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_ENABLEUPDATES)));
+ if (IsDlgButtonChecked(hwndDlg, IDC_ENABLESTABLE))
+ DBWriteContactSettingByte(NULL, UN_MOD, UN_NOTIFYTYPE, UN_NOTIFYTYPE_STABLE);
+ if (IsDlgButtonChecked(hwndDlg, IDC_ENABLEBETA))
+ DBWriteContactSettingByte(NULL, UN_MOD, UN_NOTIFYTYPE, UN_NOTIFYTYPE_BETA);
+ if (IsDlgButtonChecked(hwndDlg, IDC_ENABLEALPHA))
+ DBWriteContactSettingByte(NULL, UN_MOD, UN_NOTIFYTYPE, UN_NOTIFYTYPE_ALPHA);
+ }
+ break;
+ }
+ }
+ return FALSE;
+}
diff --git a/src/modules/userinfo/contactinfo.cpp b/src/modules/userinfo/contactinfo.cpp
new file mode 100644
index 0000000000..dc66067bbf
--- /dev/null
+++ b/src/modules/userinfo/contactinfo.cpp
@@ -0,0 +1,515 @@
+/*
+
+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"
+
+static HFONT hEmailFont=NULL;
+static HCURSOR hHandCursor=NULL;
+
+static INT_PTR CALLBACK EditUserEmailDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG:
+ SetWindowLongPtr(hwndDlg,GWLP_USERDATA,(LONG_PTR)lParam);
+ if(*(char*)lParam) SetWindowText(hwndDlg,TranslateT("Edit E-Mail Address"));
+ TranslateDialogDefault(hwndDlg);
+ SetDlgItemTextA(hwndDlg,IDC_EMAIL,(char*)lParam);
+ EnableWindow(GetDlgItem(hwndDlg,IDOK),*(char*)lParam);
+ return TRUE;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDOK:
+ GetDlgItemTextA(hwndDlg,IDC_EMAIL,(char*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA),256);
+ //fall through
+ case IDCANCEL:
+ EndDialog(hwndDlg,wParam);
+ case IDC_EMAIL:
+ if(HIWORD(wParam)==EN_CHANGE)
+ EnableWindow(GetDlgItem(hwndDlg,IDOK),GetWindowTextLength(GetDlgItem(hwndDlg,IDC_EMAIL)));
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static INT_PTR CALLBACK EditUserPhoneDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static int noRecursion=0;
+
+ switch(msg) {
+ case WM_INITDIALOG:
+ { char *szText=(char*)lParam;
+ int i,item,countryCount;
+ struct CountryListEntry *countries;
+ SetWindowLongPtr(hwndDlg,GWLP_USERDATA,(LONG_PTR)lParam);
+ if(szText[0]) SetWindowText(hwndDlg,TranslateT("Edit Phone Number"));
+ TranslateDialogDefault(hwndDlg);
+ if(lstrlenA(szText)>4 && !lstrcmpA(szText+lstrlenA(szText)-4," SMS")) {
+ CheckDlgButton(hwndDlg,IDC_SMS,BST_CHECKED);
+ szText[lstrlenA(szText)-4]='\0';
+ }
+ EnableWindow(GetDlgItem(hwndDlg,IDOK),szText[0]);
+ SendDlgItemMessage(hwndDlg,IDC_AREA,EM_LIMITTEXT,31,0);
+ SendDlgItemMessage(hwndDlg,IDC_NUMBER,EM_LIMITTEXT,63,0);
+ CallService(MS_UTILS_GETCOUNTRYLIST,(WPARAM)&countryCount,(LPARAM)&countries);
+ for(i=0;i<countryCount;i++) {
+ if(countries[i].id==0 || countries[i].id==0xFFFF) continue;
+ item=SendDlgItemMessageA(hwndDlg,IDC_COUNTRY,CB_ADDSTRING,0,(LPARAM)Translate(countries[i].szName));
+ SendDlgItemMessage(hwndDlg,IDC_COUNTRY,CB_SETITEMDATA,item,countries[i].id);
+ }
+ SetDlgItemTextA(hwndDlg,IDC_PHONE,szText);
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDOK:
+ { char *szText=(char*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA);
+ int isValid=1;
+ GetDlgItemTextA(hwndDlg,IDC_PHONE,szText,252);
+ if(lstrlenA(szText)<7 || szText[0]!='+') isValid=0;
+ if(isValid) isValid=(lstrlenA(szText+1)==(int)strspn(szText+1,"0123456789 ()-"));
+ if(!isValid) {
+ MessageBox(hwndDlg,TranslateT("The phone number should start with a + and consist of numbers, spaces, brackets and hyphens only."),TranslateT("Invalid Phone Number"),MB_OK);
+ break;
+ }
+ if(IsDlgButtonChecked(hwndDlg,IDC_SMS)) lstrcatA(szText," SMS");
+ }
+ //fall through
+ case IDCANCEL:
+ EndDialog(hwndDlg,wParam);
+ case IDC_COUNTRY:
+ if(HIWORD(wParam)!=CBN_SELCHANGE) break;
+ case IDC_AREA:
+ case IDC_NUMBER:
+ if(LOWORD(wParam)!=IDC_COUNTRY && HIWORD(wParam)!=EN_CHANGE) break;
+ if(noRecursion) break;
+ EnableWindow(GetDlgItem(hwndDlg,IDOK),TRUE);
+ { char szPhone[96],szArea[32],szNumber[64];
+ GetDlgItemTextA(hwndDlg,IDC_AREA,szArea,SIZEOF(szArea));
+ GetDlgItemTextA(hwndDlg,IDC_NUMBER,szNumber,SIZEOF(szNumber));
+ mir_snprintf(szPhone,SIZEOF(szPhone),"+%u (%s) %s",SendDlgItemMessage(hwndDlg,IDC_COUNTRY,CB_GETITEMDATA,SendDlgItemMessage(hwndDlg,IDC_COUNTRY,CB_GETCURSEL,0,0),0),szArea,szNumber);
+ noRecursion=1;
+ SetDlgItemTextA(hwndDlg,IDC_PHONE,szPhone);
+ noRecursion=0;
+ }
+ break;
+ case IDC_PHONE:
+ if(HIWORD(wParam)!=EN_UPDATE) break;
+ if(noRecursion) break;
+ noRecursion=1;
+ {
+ char szText[256],*pText=NULL,*pArea,*pNumber;
+ int isValid=1;
+ GetDlgItemTextA(hwndDlg,IDC_PHONE,szText,SIZEOF(szText));
+ if (szText[0] != '+')
+ isValid=0;
+
+ if ( isValid ) {
+ int i, country = strtol( szText+1, &pText, 10 );
+ if ( pText - szText > 4 )
+ isValid = 0;
+ else {
+ for ( i = SendDlgItemMessage( hwndDlg, IDC_COUNTRY, CB_GETCOUNT, 0, 0 )-1; i >= 0; i-- )
+ if ( country == SendDlgItemMessage(hwndDlg,IDC_COUNTRY,CB_GETITEMDATA,i,0)) {
+ SendDlgItemMessage(hwndDlg,IDC_COUNTRY,CB_SETCURSEL,i,0);
+ break;
+ }
+ if ( i < 0 )
+ isValid = 0;
+ }
+ }
+ if ( isValid ) {
+ pArea = pText+strcspn(pText,"0123456789");
+ pText = pArea+strspn(pArea,"0123456789");
+ if(*pText) {
+ *pText='\0';
+ pNumber = pText+1+strcspn(pText+1,"0123456789");
+ SetDlgItemTextA(hwndDlg,IDC_NUMBER,pNumber);
+ }
+ SetDlgItemTextA(hwndDlg,IDC_AREA,pArea);
+ }
+ if ( !isValid ) {
+ SendDlgItemMessage(hwndDlg,IDC_COUNTRY,CB_SETCURSEL,-1,0);
+ SetDlgItemTextA(hwndDlg,IDC_AREA,"");
+ SetDlgItemTextA(hwndDlg,IDC_NUMBER,"");
+ }
+ }
+ noRecursion=0;
+ EnableWindow(GetDlgItem(hwndDlg,IDOK),GetWindowTextLength(GetDlgItem(hwndDlg,IDC_PHONE)));
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static int IsOverEmail(HWND hwndDlg,TCHAR* szEmail,int cchEmail)
+{
+ RECT rc;
+ HWND hwndEmails;
+ TCHAR szText[256];
+ HDC hdc;
+ SIZE textSize;
+ LVHITTESTINFO hti;
+
+ hwndEmails=GetDlgItem(hwndDlg,IDC_EMAILS);
+ GetCursorPos(&hti.pt);
+ ScreenToClient(hwndEmails,&hti.pt);
+ GetClientRect(hwndEmails,&rc);
+ if(!PtInRect(&rc,hti.pt)) return 0;
+ if(ListView_SubItemHitTest(hwndEmails,&hti)==-1) return 0;
+ if(hti.iSubItem!=1) return 0;
+ if(!(hti.flags&LVHT_ONITEMLABEL)) return 0;
+ ListView_GetSubItemRect(hwndEmails,hti.iItem,1,LVIR_LABEL,&rc);
+ szText[0] = 0;
+ ListView_GetItemText(hwndEmails,hti.iItem,1,szText,SIZEOF(szText));
+ hdc=GetDC(hwndEmails);
+ SelectObject(hdc,hEmailFont);
+ GetTextExtentPoint32(hdc,szText,lstrlen(szText),&textSize);
+ ReleaseDC(hwndEmails,hdc);
+ if(hti.pt.x<rc.left+textSize.cx) {
+ if(szEmail && cchEmail) lstrcpyn(szEmail,szText,cchEmail);
+ return 1;
+ }
+ return 0;
+}
+
+#define M_REMAKELISTS (WM_USER+1)
+INT_PTR CALLBACK ContactDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG:
+ SetWindowLongPtr(hwndDlg,GWLP_USERDATA,(LONG_PTR)lParam);
+ if(hEmailFont) DeleteObject(hEmailFont);
+ { LOGFONT lf;
+ hEmailFont=(HFONT)SendDlgItemMessage(hwndDlg,IDC_EMAILS,WM_GETFONT,0,0);
+ GetObject(hEmailFont,sizeof(lf),&lf);
+ lf.lfUnderline=1;
+ hEmailFont=CreateFontIndirect(&lf);
+ }
+ if(hHandCursor==NULL) {
+ if(IsWinVer2000Plus()) hHandCursor=LoadCursor(NULL,IDC_HAND);
+ else hHandCursor=LoadCursor(hMirandaInst,MAKEINTRESOURCE(IDC_HYPERLINKHAND));
+ }
+ TranslateDialogDefault(hwndDlg);
+ { LVCOLUMN lvc;
+ RECT rc;
+ GetClientRect(GetDlgItem(hwndDlg,IDC_EMAILS),&rc);
+ rc.right-=GetSystemMetrics(SM_CXVSCROLL);
+ lvc.mask=LVCF_WIDTH;
+ ListView_SetExtendedListViewStyleEx(GetDlgItem(hwndDlg,IDC_EMAILS), LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP, LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP);
+ ListView_SetExtendedListViewStyleEx(GetDlgItem(hwndDlg,IDC_PHONES), LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP, LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP);
+ lvc.cx=rc.right/4;
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_EMAILS),0,&lvc);
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_PHONES),0,&lvc);
+ lvc.cx=rc.right-rc.right/4-40;
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_EMAILS),1,&lvc);
+ lvc.cx=rc.right-rc.right/4-90;
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_PHONES),1,&lvc);
+ lvc.cx=50;
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_PHONES),2,&lvc);
+ lvc.cx=20;
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_EMAILS),2,&lvc);
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_EMAILS),3,&lvc);
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_PHONES),3,&lvc);
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_PHONES),4,&lvc);
+ }
+ break;
+ case M_REMAKELISTS:
+ { char *szProto;
+ LVITEM lvi;
+ int i;
+ char idstr[33];
+ TCHAR idstr2[33];
+ DBVARIANT dbv;
+ HANDLE hContact=(HANDLE)GetWindowLongPtr(hwndDlg,GWLP_USERDATA);
+
+ if (hContact != NULL) {
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hContact,0);
+ if (szProto==NULL) break;
+ //e-mails
+ ListView_DeleteAllItems(GetDlgItem(hwndDlg,IDC_EMAILS));
+ lvi.mask=LVIF_TEXT|LVIF_PARAM;
+ lvi.lParam=(LPARAM)(-1);
+ lvi.iSubItem=0;
+ lvi.iItem=0;
+ for(i=-1;;i++) {
+ if(i==-1) {
+ if(DBGetContactSettingTString(hContact,szProto,"e-mail",&dbv))
+ continue;
+ lvi.pszText=TranslateT("Primary");
+ }
+ else {
+ mir_snprintf(idstr, SIZEOF(idstr), "e-mail%d", i );
+ if(DBGetContactSettingTString(hContact,szProto,idstr,&dbv))
+ break;
+ lvi.pszText=idstr2;
+ mir_sntprintf(idstr2, SIZEOF(idstr2), _T("%d"),i+2);
+ }
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_EMAILS),&lvi);
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_EMAILS),lvi.iItem,1,dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ lvi.iItem++;
+ }
+ lvi.iSubItem=0;
+ for(i=0;;i++) {
+ lvi.lParam=i;
+ mir_snprintf(idstr, SIZEOF(idstr), "Mye-mail%d",i);
+ if(DBGetContactSettingTString(hContact,"UserInfo",idstr,&dbv))
+ break;
+ lvi.pszText=idstr2;
+ mir_sntprintf(idstr2, SIZEOF(idstr2), TranslateT("Custom %d"),i+1);
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_EMAILS),&lvi);
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_EMAILS),lvi.iItem,1,dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ lvi.iItem++;
+ }
+ lvi.mask=LVIF_PARAM;
+ lvi.lParam=(LPARAM)(-2);
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_EMAILS),&lvi);
+ //phones
+ ListView_DeleteAllItems(GetDlgItem(hwndDlg,IDC_PHONES));
+ lvi.mask=LVIF_TEXT|LVIF_PARAM;
+ lvi.lParam=(LPARAM)(-1);
+ lvi.iSubItem=0;
+ lvi.iItem=0;
+ if(!DBGetContactSettingTString(hContact,szProto,"Phone",&dbv)) {
+ lvi.pszText=TranslateT("Primary");
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_PHONES),&lvi);
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_PHONES),lvi.iItem,1,dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ lvi.iItem++;
+ }
+ if(!DBGetContactSettingTString(hContact,szProto,"Fax",&dbv)) {
+ lvi.pszText=TranslateT("Fax");
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_PHONES),&lvi);
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_PHONES),lvi.iItem,1,dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ lvi.iItem++;
+ }
+ if(!DBGetContactSettingTString(hContact,szProto,"Cellular",&dbv)) {
+ lvi.pszText=TranslateT("Mobile");
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_PHONES),&lvi);
+ if(lstrlenA(dbv.pszVal)>4 && !lstrcmpA(dbv.pszVal+lstrlenA(dbv.pszVal)-4," SMS")) {
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_PHONES),lvi.iItem,2,_T("y"));
+ dbv.ptszVal[lstrlen(dbv.ptszVal)-4]='\0';
+ }
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_PHONES),lvi.iItem,1,dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ lvi.iItem++;
+ }
+ if(!DBGetContactSettingTString(hContact,szProto,"CompanyPhone",&dbv)) {
+ lvi.pszText=TranslateT("Work Phone");
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_PHONES),&lvi);
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_PHONES),lvi.iItem,1,dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ lvi.iItem++;
+ }
+ if(!DBGetContactSettingTString(hContact,szProto,"CompanyFax",&dbv)) {
+ lvi.pszText=TranslateT("Work Fax");
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_PHONES),&lvi);
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_PHONES),lvi.iItem,1,dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ lvi.iItem++;
+ }
+ lvi.iSubItem=0;
+ for(i=0;;i++) {
+ lvi.lParam=i;
+ mir_snprintf(idstr, SIZEOF(idstr), "MyPhone%d",i);
+ if(DBGetContactSettingTString(hContact,"UserInfo",idstr,&dbv))
+ break;
+ lvi.pszText=idstr2;
+ mir_sntprintf(idstr2, SIZEOF(idstr2), TranslateT("Custom %d"),i+1);
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_PHONES),&lvi);
+ if(lstrlen(dbv.ptszVal)>4 && !lstrcmp(dbv.ptszVal+lstrlen(dbv.ptszVal)-4,_T(" SMS"))) {
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_PHONES),lvi.iItem,2,_T("y"));
+ dbv.ptszVal[lstrlen(dbv.ptszVal)-4]='\0';
+ }
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_PHONES),lvi.iItem,1,dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ lvi.iItem++;
+ }
+ lvi.mask=LVIF_PARAM;
+ lvi.lParam=(LPARAM)(-2);
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_PHONES),&lvi);
+ }
+ break;
+ }
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_INFOCHANGED:
+ SendMessage(hwndDlg,M_REMAKELISTS,0,0);
+ break;
+ }
+ break;
+ case IDC_EMAILS:
+ case IDC_PHONES:
+ switch (((LPNMHDR)lParam)->code) {
+ case NM_CUSTOMDRAW:
+ { NMLVCUSTOMDRAW *nm=(NMLVCUSTOMDRAW*)lParam;
+ switch(nm->nmcd.dwDrawStage) {
+ case CDDS_PREPAINT:
+ case CDDS_ITEMPREPAINT:
+ SetWindowLongPtr(hwndDlg,DWLP_MSGRESULT,CDRF_NOTIFYSUBITEMDRAW);
+ return TRUE;
+ case CDDS_SUBITEM|CDDS_ITEMPREPAINT:
+ {
+ RECT rc;
+ ListView_GetSubItemRect(nm->nmcd.hdr.hwndFrom,nm->nmcd.dwItemSpec,nm->iSubItem,LVIR_LABEL,&rc);
+ if(nm->iSubItem==1 && nm->nmcd.hdr.idFrom==IDC_EMAILS) {
+ HFONT hoFont;
+ TCHAR szText[256] = {0};
+ ListView_GetItemText(nm->nmcd.hdr.hwndFrom,nm->nmcd.dwItemSpec,nm->iSubItem,szText,SIZEOF(szText));
+ hoFont=(HFONT)SelectObject(nm->nmcd.hdc,hEmailFont);
+ SetTextColor(nm->nmcd.hdc,RGB(0,0,255));
+ DrawText(nm->nmcd.hdc,szText,-1,&rc,DT_END_ELLIPSIS|DT_LEFT|DT_NOPREFIX|DT_SINGLELINE|DT_TOP);
+ SelectObject(nm->nmcd.hdc,hoFont);
+ SetWindowLongPtr(hwndDlg,DWLP_MSGRESULT,CDRF_SKIPDEFAULT);
+ return TRUE;
+ }
+
+ HICON hIcon = NULL;
+ if(nm->nmcd.lItemlParam==(LPARAM)(-2) && nm->iSubItem-3==(nm->nmcd.hdr.idFrom==IDC_PHONES))
+ hIcon = LoadSkinIcon( SKINICON_OTHER_ADDCONTACT );
+ else if(nm->iSubItem>1 && nm->nmcd.lItemlParam!=(LPARAM)(-1) && nm->nmcd.lItemlParam!=(LPARAM)(-2)) {
+ static int iconResources[3]={SKINICON_OTHER_RENAME,SKINICON_OTHER_DELETE};
+ if(nm->iSubItem==2 && nm->nmcd.hdr.idFrom==IDC_PHONES) {
+ TCHAR szText[2];
+ ListView_GetItemText(nm->nmcd.hdr.hwndFrom,nm->nmcd.dwItemSpec,nm->iSubItem,szText,SIZEOF(szText));
+ if(szText[0]) hIcon = LoadSkinIcon( SKINICON_OTHER_SMS );
+ }
+ else hIcon = LoadSkinIcon( iconResources[nm->iSubItem-3+(nm->nmcd.hdr.idFrom==IDC_EMAILS)] );
+ }
+ else break;
+ DrawIconEx(nm->nmcd.hdc,(rc.left+rc.right-GetSystemMetrics(SM_CXSMICON))/2,(rc.top+rc.bottom-GetSystemMetrics(SM_CYSMICON))/2,hIcon,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0,NULL,DI_NORMAL);
+ IconLib_ReleaseIcon(hIcon, 0);
+ SetWindowLongPtr(hwndDlg,DWLP_MSGRESULT,CDRF_SKIPDEFAULT);
+ return TRUE;
+ }
+ }
+ break;
+ }
+ case NM_CLICK:
+ { NMLISTVIEW *nm=(NMLISTVIEW*)lParam;
+ LVITEM lvi;
+ TCHAR szEmail[256];
+ HANDLE hContact=(HANDLE)GetWindowLongPtr(hwndDlg,GWLP_USERDATA);
+ char *szIdTemplate=nm->hdr.idFrom==IDC_PHONES?"MyPhone%d":"Mye-mail%d";
+ LVHITTESTINFO hti;
+
+ if(IsOverEmail(hwndDlg,szEmail,SIZEOF(szEmail))) {
+ TCHAR szExec[264];
+ mir_sntprintf(szExec, SIZEOF(szExec), _T("mailto:%s"), szEmail);
+ ShellExecute(hwndDlg,_T("open"),szExec,NULL,NULL,SW_SHOW);
+ break;
+ }
+ if(nm->iSubItem<2) break;
+ hti.pt.x=(short)LOWORD(GetMessagePos());
+ hti.pt.y=(short)HIWORD(GetMessagePos());
+ ScreenToClient(nm->hdr.hwndFrom,&hti.pt);
+ if(ListView_SubItemHitTest(nm->hdr.hwndFrom,&hti)==-1) break;
+ lvi.mask=LVIF_PARAM;
+ lvi.iItem=hti.iItem;
+ lvi.iSubItem=0;
+ ListView_GetItem(nm->hdr.hwndFrom,&lvi);
+ if(lvi.lParam==(LPARAM)(-1)) break;
+ if(lvi.lParam==(LPARAM)(-2)) {
+ if(hti.iSubItem-3==(nm->hdr.idFrom==IDC_PHONES)) {
+ //add
+ char szNewData[256]="",idstr[33];
+ int i;
+ DBVARIANT dbv;
+ if(IDOK!=DialogBoxParam(hMirandaInst,MAKEINTRESOURCE(nm->hdr.idFrom==IDC_PHONES?IDD_ADDPHONE:IDD_ADDEMAIL),hwndDlg,nm->hdr.idFrom==IDC_PHONES?EditUserPhoneDlgProc:EditUserEmailDlgProc,(LPARAM)szNewData))
+ break;
+ for(i=0;;i++) {
+ mir_snprintf(idstr, SIZEOF(idstr), szIdTemplate,i);
+ if(DBGetContactSettingString(hContact,"UserInfo",idstr,&dbv)) break;
+ DBFreeVariant(&dbv);
+ }
+ DBWriteContactSettingString(hContact,"UserInfo",idstr,szNewData);
+ SendMessage(hwndDlg,M_REMAKELISTS,0,0);
+ }
+ }
+ else {
+ if(hti.iSubItem-3==(nm->hdr.idFrom==IDC_PHONES)) {
+ //delete
+ int i;
+ char idstr[33];
+ DBVARIANT dbv;
+ for(i=lvi.lParam;;i++) {
+ mir_snprintf(idstr, SIZEOF(idstr), szIdTemplate,i+1);
+ if(DBGetContactSettingString(hContact,"UserInfo",idstr,&dbv)) break;
+ mir_snprintf(idstr, SIZEOF(idstr), szIdTemplate,i);
+ DBWriteContactSettingString(hContact,"UserInfo",idstr,dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ mir_snprintf(idstr, SIZEOF(idstr), szIdTemplate,i);
+ DBDeleteContactSetting(hContact,"UserInfo",idstr);
+ SendMessage(hwndDlg,M_REMAKELISTS,0,0);
+ }
+ else if(hti.iSubItem-2==(nm->hdr.idFrom==IDC_PHONES)) {
+ //edit
+ char szText[256],idstr[33];
+ DBVARIANT dbv;
+ mir_snprintf(idstr, SIZEOF(idstr), szIdTemplate,lvi.lParam);
+ if(DBGetContactSettingString(hContact,"UserInfo",idstr,&dbv)) break;
+ lstrcpynA(szText,dbv.pszVal,SIZEOF(szText));
+ DBFreeVariant(&dbv);
+ if(IDOK!=DialogBoxParam(hMirandaInst,MAKEINTRESOURCE(nm->hdr.idFrom==IDC_PHONES?IDD_ADDPHONE:IDD_ADDEMAIL),hwndDlg,nm->hdr.idFrom==IDC_PHONES?EditUserPhoneDlgProc:EditUserEmailDlgProc,(LPARAM)szText))
+ break;
+ DBWriteContactSettingString(hContact,"UserInfo",idstr,szText);
+ SendMessage(hwndDlg,M_REMAKELISTS,0,0);
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ break;
+ case WM_SETCURSOR:
+ if(LOWORD(lParam)!=HTCLIENT) break;
+ if(GetForegroundWindow()==GetParent(hwndDlg)) {
+ POINT pt;
+ GetCursorPos(&pt);
+ ScreenToClient(hwndDlg,&pt);
+// SetFocus(ChildWindowFromPoint(hwndDlg,pt)); //ugly hack because listviews ignore their first click
+ }
+ if(IsOverEmail(hwndDlg,NULL,0)) {
+ SetCursor(hHandCursor);
+ SetWindowLongPtr(hwndDlg,DWLP_MSGRESULT,TRUE);
+ return TRUE;
+ }
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDCANCEL:
+ SendMessage(GetParent(hwndDlg),msg,wParam,lParam);
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
diff --git a/src/modules/userinfo/stdinfo.cpp b/src/modules/userinfo/stdinfo.cpp
new file mode 100644
index 0000000000..89f6ab0f45
--- /dev/null
+++ b/src/modules/userinfo/stdinfo.cpp
@@ -0,0 +1,613 @@
+/*
+
+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_PTR CALLBACK ContactDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+#define SVS_NORMAL 0
+#define SVS_GENDER 1
+#define SVS_ZEROISUNSPEC 2
+#define SVS_IP 3
+#define SVS_COUNTRY 4
+#define SVS_MONTH 5
+#define SVS_SIGNED 6
+#define SVS_TIMEZONE 7
+
+static int Proto_GetContactInfoSetting(HANDLE hContact,const char *szProto,const char *szModule,const char *szSetting,DBVARIANT *dbv, const int nType)
+{
+ DBCONTACTGETSETTING cgs={szModule,szSetting,dbv};
+ dbv->type=(BYTE)nType;
+
+ return CallProtoService(szProto,PS_GETINFOSETTING,(WPARAM)hContact,(LPARAM)&cgs);
+}
+
+static void Proto_FreeInfoVariant(DBVARIANT *dbv)
+{
+ switch ( dbv->type ) {
+ case DBVT_ASCIIZ:
+ case DBVT_UTF8:
+ case DBVT_WCHAR:
+ {
+ mir_free(dbv->pszVal);
+ dbv->pszVal=0;
+ break;
+ }
+ case DBVT_BLOB:
+ {
+ mir_free(dbv->pbVal);
+ dbv->pbVal=0;
+ break;
+ }
+ }
+ dbv->type=0;
+}
+
+static void SetValue(HWND hwndDlg,int idCtrl,HANDLE hContact,char *szModule,char *szSetting,int special)
+{
+ DBVARIANT dbv = { 0 };
+ char str[80],*pstr = NULL;
+ TCHAR* ptstr = NULL;
+ int unspecified=0;
+ char* szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ bool proto_service = szProto && (CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_4, 0) & PF4_INFOSETTINGSVC);
+
+ dbv.type=DBVT_DELETED;
+ if(szModule==NULL) unspecified=1;
+ else if (proto_service) unspecified=Proto_GetContactInfoSetting(hContact,szProto,szModule,szSetting,&dbv,0);
+ else unspecified=DBGetContactSettingW(hContact,szModule,szSetting,&dbv);
+ if(!unspecified) {
+ switch(dbv.type) {
+ case DBVT_BYTE:
+ if(special==SVS_GENDER) {
+ if(dbv.cVal=='M') ptstr=TranslateT("Male");
+ else if(dbv.cVal=='F') ptstr=TranslateT("Female");
+ else unspecified=1;
+ }
+ else if(special==SVS_MONTH) {
+ if(dbv.bVal>0 && dbv.bVal<=12) {
+ pstr=str;
+ GetLocaleInfoA(LOCALE_USER_DEFAULT,LOCALE_SABBREVMONTHNAME1-1+dbv.bVal,str,SIZEOF(str));
+ }
+ else unspecified=1;
+ }
+ else if(special==SVS_TIMEZONE) {
+ if(dbv.cVal==-100) unspecified=1;
+ else {
+ pstr=str;
+ mir_snprintf(str, SIZEOF(str), dbv.cVal?"UTC%+d:%02d":"UTC",-dbv.cVal/2,(dbv.cVal&1)*30);
+ }
+ }
+ else {
+ unspecified=(special==SVS_ZEROISUNSPEC && dbv.bVal==0);
+ pstr=_itoa(special==SVS_SIGNED?dbv.cVal:dbv.bVal,str,10);
+ }
+ break;
+ case DBVT_WORD:
+ if(special==SVS_COUNTRY) {
+ WORD wSave = dbv.wVal;
+ if (wSave == ( WORD )-1) {
+ char szSettingName[100];
+ mir_snprintf( szSettingName, SIZEOF(szSettingName), "%sName", szSetting );
+ if ( !DBGetContactSettingTString(hContact,szModule,szSettingName,&dbv)) {
+ ptstr = dbv.ptszVal;
+ unspecified = false;
+ break;
+ }
+ }
+
+ pstr = Translate((char*)CallService(MS_UTILS_GETCOUNTRYBYNUMBER,wSave,0));
+ unspecified=pstr==NULL;
+ }
+ else {
+ unspecified=(special==SVS_ZEROISUNSPEC && dbv.wVal==0);
+ pstr=_itoa(special==SVS_SIGNED?dbv.sVal:dbv.wVal,str,10);
+ }
+ break;
+ case DBVT_DWORD:
+ unspecified=(special==SVS_ZEROISUNSPEC && dbv.dVal==0);
+ if(special==SVS_IP) {
+ struct in_addr ia;
+ ia.S_un.S_addr=htonl(dbv.dVal);
+ pstr=inet_ntoa(ia);
+ if(dbv.dVal==0) unspecified=1;
+ }
+ else pstr=_itoa(special==SVS_SIGNED?dbv.lVal:dbv.dVal,str,10);
+ break;
+ case DBVT_ASCIIZ:
+ unspecified=(special==SVS_ZEROISUNSPEC && dbv.pszVal[0]=='\0');
+ pstr=dbv.pszVal;
+ break;
+ case DBVT_UTF8:
+ unspecified=(special==SVS_ZEROISUNSPEC && dbv.pszVal[0]=='\0');
+ #if defined( _UNICODE )
+ if ( !unspecified )
+ { WCHAR* wszStr;
+ Utf8Decode( dbv.pszVal, &wszStr );
+ SetDlgItemTextW( hwndDlg, idCtrl, TranslateTS(wszStr));
+ mir_free( wszStr );
+ goto LBL_Exit;
+ }
+ #endif
+ pstr=dbv.pszVal;
+ Utf8Decode( dbv.pszVal, NULL );
+ break;
+ default: pstr=str; lstrcpyA(str,"???"); break;
+ } }
+
+ if (unspecified)
+ SetDlgItemText(hwndDlg, idCtrl, TranslateT("<not specified>"));
+ else if ( ptstr != NULL )
+ SetDlgItemText(hwndDlg, idCtrl, ptstr);
+ else
+ SetDlgItemTextA(hwndDlg, idCtrl, pstr);
+
+#if defined( _UNICODE )
+LBL_Exit:
+#endif
+ EnableWindow(GetDlgItem(hwndDlg, idCtrl), !unspecified);
+ if (proto_service)
+ Proto_FreeInfoVariant(&dbv);
+ else
+ DBFreeVariant(&dbv);
+}
+
+static INT_PTR CALLBACK SummaryDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ break;
+
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ if (((LPNMHDR)lParam)->code == PSN_INFOCHANGED )
+ { char *szProto;
+ HANDLE hContact=(HANDLE)((LPPSHNOTIFY)lParam)->lParam;
+ if (hContact != NULL) {
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hContact,0);
+ if (szProto==NULL) break;
+ SetValue(hwndDlg,IDC_NICK,hContact,szProto,"Nick",0);
+ SetValue(hwndDlg,IDC_FIRSTNAME,hContact,szProto,"FirstName",0);
+ SetValue(hwndDlg,IDC_LASTNAME,hContact,szProto,"LastName",0);
+ SetValue(hwndDlg,IDC_EMAIL,hContact,szProto,"e-mail",0);
+ SetValue(hwndDlg,IDC_AGE,hContact,szProto,"Age",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_GENDER,hContact,szProto,"Gender",SVS_GENDER);
+ SetValue(hwndDlg,IDC_DOBDAY,hContact,szProto,"BirthDay",0);
+ SetValue(hwndDlg,IDC_DOBMONTH,hContact,szProto,"BirthMonth",SVS_MONTH);
+ SetValue(hwndDlg,IDC_DOBYEAR,hContact,szProto,"BirthYear",0);
+ SetValue(hwndDlg,IDC_MARITAL,hContact,szProto,"MaritalStatus",0);
+ } }
+ break;
+ }
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDCANCEL:
+ SendMessage(GetParent(hwndDlg),msg,wParam,lParam);
+ break;
+ case IDC_EMAIL:
+ if(IsWindowEnabled(GetDlgItem(hwndDlg,IDC_EMAIL))) {
+ TCHAR szExec[264], szEmail[256];
+ GetDlgItemText(hwndDlg, IDC_EMAIL, szEmail, SIZEOF(szEmail));
+ mir_sntprintf(szExec, SIZEOF(szExec), _T("mailto:%s"), szEmail);
+ ShellExecute(hwndDlg, _T("open"), szExec, NULL, NULL, SW_SHOW);
+ }
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static INT_PTR CALLBACK LocationDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG:
+
+ SetWindowLongPtr(hwndDlg,GWLP_USERDATA,lParam);
+ TranslateDialogDefault(hwndDlg);
+ SetTimer(hwndDlg,1,1000,NULL);
+
+ tmi.prepareList((HANDLE)lParam, GetDlgItem(hwndDlg, IDC_TIMEZONESELECT), TZF_PLF_CB);
+ SendMessage(hwndDlg,WM_TIMER,0,0);
+ break;
+
+ case WM_TIMER:
+ {
+ HANDLE hContact = (HANDLE)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+
+ if (hContact != NULL)
+ {
+ TCHAR szTime[80];
+
+ if (tmi.printDateTimeByContact(hContact, _T("s"), szTime, SIZEOF(szTime), TZF_KNOWNONLY))
+ {
+ EnableWindow(GetDlgItem(hwndDlg,IDC_LOCALTIME),FALSE);
+ SetDlgItemText(hwndDlg, IDC_LOCALTIME, TranslateT("<not specified>"));
+ }
+ else
+ {
+ EnableWindow(GetDlgItem(hwndDlg,IDC_LOCALTIME), TRUE);
+ SetDlgItemText(hwndDlg, IDC_LOCALTIME, szTime);
+ }
+ }
+ break;
+ }
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ if (((LPNMHDR)lParam)->code == PSN_INFOCHANGED )
+ { char *szProto;
+ HANDLE hContact=(HANDLE)((LPPSHNOTIFY)lParam)->lParam;
+ if (hContact != NULL) {
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hContact,0);
+ if (szProto==NULL) break;
+ SetValue(hwndDlg,IDC_STREET,hContact,szProto,"Street",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_CITY,hContact,szProto,"City",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_STATE,hContact,szProto,"State",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_ZIP,hContact,szProto,"ZIP",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_COUNTRY,hContact,szProto,"Country",SVS_COUNTRY);
+ SetValue(hwndDlg,IDC_LANGUAGE1,hContact,szProto,"Language1",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_LANGUAGE2,hContact,szProto,"Language2",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_LANGUAGE3,hContact,szProto,"Language3",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_TIMEZONE,hContact,szProto,"Timezone",SVS_TIMEZONE);
+ }
+ }
+ break;
+ }
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDCANCEL:
+ SendMessage(GetParent(hwndDlg),msg,wParam,lParam);
+ break;
+ case IDC_TIMEZONESELECT:
+ if(HIWORD(wParam) == CBN_SELCHANGE) {
+ HANDLE hContact = (HANDLE)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+
+ SendMessage(GetParent(hwndDlg),PSM_CHANGED, 0,0);
+ tmi.storeListResults(hContact, GetDlgItem(hwndDlg, IDC_TIMEZONESELECT), TZF_PLF_CB);
+ }
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static INT_PTR CALLBACK WorkDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ break;
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ if (((LPNMHDR)lParam)->code == PSN_INFOCHANGED)
+ { char *szProto;
+ HANDLE hContact=(HANDLE)((LPPSHNOTIFY)lParam)->lParam;
+ if (hContact != NULL) {
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hContact,0);
+ if (szProto==NULL) break;
+ SetValue(hwndDlg,IDC_COMPANY,hContact,szProto,"Company",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_DEPARTMENT,hContact,szProto,"CompanyDepartment",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_POSITION,hContact,szProto,"CompanyPosition",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_STREET,hContact,szProto,"CompanyStreet",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_CITY,hContact,szProto,"CompanyCity",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_STATE,hContact,szProto,"CompanyState",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_ZIP,hContact,szProto,"CompanyZIP",SVS_ZEROISUNSPEC);
+ SetValue(hwndDlg,IDC_COUNTRY,hContact,szProto,"CompanyCountry",SVS_COUNTRY);
+ SetValue(hwndDlg,IDC_WEBPAGE,hContact,szProto,"CompanyHomepage",SVS_ZEROISUNSPEC);
+ } }
+ break;
+ }
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDCANCEL:
+ SendMessage(GetParent(hwndDlg),msg,wParam,lParam);
+ break;
+ case IDC_WEBPAGE:
+ if(IsWindowEnabled(GetDlgItem(hwndDlg,IDC_WEBPAGE))) {
+ char szPage[256];
+ GetDlgItemTextA(hwndDlg,IDC_WEBPAGE,szPage,SIZEOF(szPage));
+ CallService(MS_UTILS_OPENURL,1,(LPARAM)szPage);
+ }
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+// Resizes all columns in a listview (report style)
+// to make all text visible
+void ResizeColumns(HWND hwndLV)
+{
+ int nCol = 0; LVCOLUMN lvCol;
+ lvCol.mask = LVCF_WIDTH;
+ while(ListView_GetColumn(hwndLV, nCol++, &lvCol))
+ ListView_SetColumnWidth(hwndLV, nCol-1, LVSCW_AUTOSIZE);
+}
+
+static INT_PTR CALLBACK BackgroundDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ { LVCOLUMN lvc;
+ RECT rc;
+ GetClientRect(GetDlgItem(hwndDlg,IDC_PAST),&rc);
+ rc.right-=GetSystemMetrics(SM_CXVSCROLL);
+ lvc.mask=LVCF_WIDTH;
+ lvc.cx=rc.right/3;
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_PAST),0,&lvc);
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_INTERESTS),0,&lvc);
+ lvc.cx=rc.right-rc.right/3;
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_PAST),1,&lvc);
+ ListView_InsertColumn(GetDlgItem(hwndDlg,IDC_INTERESTS),1,&lvc);
+ }
+ ListView_SetExtendedListViewStyleEx(GetDlgItem(hwndDlg,IDC_PAST),LVS_EX_LABELTIP,LVS_EX_LABELTIP);
+ ListView_SetExtendedListViewStyleEx(GetDlgItem(hwndDlg,IDC_INTERESTS),LVS_EX_LABELTIP,LVS_EX_LABELTIP);
+ break;
+
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ if (((LPNMHDR)lParam)->code == PSN_INFOCHANGED)
+ { LVITEM lvi;
+ int i;
+ char idstr[33];
+ DBVARIANT dbv,dbvText;
+ HANDLE hContact=(HANDLE)((LPPSHNOTIFY)lParam)->lParam;
+
+ if (hContact != NULL) {
+ char *szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hContact,0);
+ if (szProto==NULL) break;
+ bool proto_service = (CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_4, 0) & PF4_INFOSETTINGSVC) == PF4_INFOSETTINGSVC;
+ SetValue(hwndDlg,IDC_WEBPAGE,hContact,szProto,"Homepage",SVS_ZEROISUNSPEC);
+
+ //past
+ ListView_DeleteAllItems(GetDlgItem(hwndDlg,IDC_PAST));
+ lvi.mask=LVIF_TEXT;
+ lvi.iSubItem=0;
+ lvi.iItem=0;
+ for(i=0;;i++) {
+ mir_snprintf(idstr, SIZEOF(idstr), "Past%d",i);
+ if((proto_service && Proto_GetContactInfoSetting(hContact,szProto,szProto,idstr,&dbv,DBVT_TCHAR)) ||
+ (!proto_service && DBGetContactSettingTString(hContact,szProto,idstr,&dbv)))
+ break;
+ mir_snprintf(idstr, SIZEOF(idstr), "Past%dText",i);
+ if(DBGetContactSettingTString(hContact,szProto,idstr,&dbvText))
+ {if(proto_service) Proto_FreeInfoVariant(&dbv); else DBFreeVariant(&dbv); break;}
+ lvi.pszText=dbv.ptszVal;
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_PAST),&lvi);
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_PAST),lvi.iItem,1,dbvText.ptszVal);
+ DBFreeVariant(&dbvText);
+ if(proto_service)
+ Proto_FreeInfoVariant(&dbv);
+ else
+ DBFreeVariant(&dbv);
+ lvi.iItem++;
+ }
+
+ for(i=0;;i++) {
+ mir_snprintf(idstr, SIZEOF(idstr), "Affiliation%d", i);
+ if((proto_service && Proto_GetContactInfoSetting(hContact,szProto,szProto,idstr,&dbv,DBVT_TCHAR)) ||
+ (!proto_service && DBGetContactSettingTString(hContact,szProto,idstr,&dbv)))
+ break;
+ mir_snprintf(idstr, SIZEOF(idstr), "Affiliation%dText",i);
+ if(DBGetContactSettingTString(hContact,szProto,idstr,&dbvText))
+ {if(proto_service) Proto_FreeInfoVariant(&dbv); else DBFreeVariant(&dbv); break;}
+ lvi.pszText=dbv.ptszVal;
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_PAST),&lvi);
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_PAST),lvi.iItem,1,dbvText.ptszVal);
+ DBFreeVariant(&dbvText);
+ if(proto_service)
+ Proto_FreeInfoVariant(&dbv);
+ else
+ DBFreeVariant(&dbv);
+ lvi.iItem++;
+ }
+
+ ResizeColumns(GetDlgItem(hwndDlg,IDC_PAST));
+
+ //interests
+ ListView_DeleteAllItems(GetDlgItem(hwndDlg,IDC_INTERESTS));
+ lvi.mask=LVIF_TEXT;
+ lvi.iSubItem=0;
+ lvi.iItem=0;
+ for(i=0;;i++) {
+ mir_snprintf(idstr, SIZEOF(idstr), "Interest%dCat", i);
+ if((proto_service && Proto_GetContactInfoSetting(hContact,szProto,szProto,idstr,&dbv,DBVT_TCHAR)) ||
+ (!proto_service && DBGetContactSettingTString(hContact,szProto,idstr,&dbv)))
+ break;
+ mir_snprintf(idstr, SIZEOF(idstr), "Interest%dText", i);
+ if(DBGetContactSettingTString(hContact,szProto,idstr,&dbvText))
+ {if(proto_service) Proto_FreeInfoVariant(&dbv); else DBFreeVariant(&dbv); break;}
+ lvi.pszText=dbv.ptszVal;
+ ListView_InsertItem(GetDlgItem(hwndDlg,IDC_INTERESTS),&lvi);
+ ListView_SetItemText(GetDlgItem(hwndDlg,IDC_INTERESTS),lvi.iItem,1,dbvText.ptszVal);
+ DBFreeVariant(&dbvText);
+ if(proto_service)
+ Proto_FreeInfoVariant(&dbv);
+ else
+ DBFreeVariant(&dbv);
+ lvi.iItem++;
+ }
+ ResizeColumns(GetDlgItem(hwndDlg,IDC_INTERESTS));
+ } }
+ break;
+ }
+ break;
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDCANCEL:
+ SendMessage(GetParent(hwndDlg),msg,wParam,lParam);
+ break;
+ case IDC_WEBPAGE:
+ if(IsWindowEnabled(GetDlgItem(hwndDlg,IDC_WEBPAGE))) {
+ char szPage[256];
+ GetDlgItemTextA(hwndDlg,IDC_WEBPAGE,szPage,SIZEOF(szPage));
+ CallService(MS_UTILS_OPENURL,1,(LPARAM)szPage);
+ }
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static INT_PTR CALLBACK NotesDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch(msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ { DBVARIANT dbv;
+ HFONT hFont;
+ LOGFONT lf;
+ HDC hDC = GetDC(hwndDlg);
+ lf.lfHeight = -MulDiv(10, GetDeviceCaps(hDC, LOGPIXELSY), 72);
+ ReleaseDC(hwndDlg, hDC);
+ lf.lfWidth = 0;
+ lf.lfEscapement = 0;
+ lf.lfOrientation = 0;
+ lf.lfWeight = FW_NORMAL;
+ lf.lfItalic = 0;
+ lf.lfUnderline = 0;
+ lf.lfStrikeOut = 0;
+ lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
+ lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ lf.lfQuality = DEFAULT_QUALITY;
+ lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
+ lstrcpy(lf.lfFaceName, _T("Courier New"));
+ lf.lfCharSet = DEFAULT_CHARSET;
+// hFont = (HFONT) GetStockObject(ANSI_FIXED_FONT);
+ hFont = CreateFontIndirect(&lf);
+ SendDlgItemMessage(hwndDlg, IDC_ABOUT, WM_SETFONT, (WPARAM) hFont, MAKELPARAM(TRUE, 0));
+
+ if(!DBGetContactSettingString((HANDLE)lParam,"UserInfo","MyNotes",&dbv)) {
+ SetDlgItemTextA(hwndDlg,IDC_MYNOTES,dbv.pszVal);
+ DBFreeVariant(&dbv);
+ }
+ }
+ SendDlgItemMessage(hwndDlg,IDC_MYNOTES,EM_LIMITTEXT,2048,0);
+ break;
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_INFOCHANGED:
+ { char *szProto;
+ HANDLE hContact=(HANDLE)((LPPSHNOTIFY)lParam)->lParam;
+ if (hContact != NULL) {
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hContact,0);
+ if (szProto==NULL) break;
+ SetValue(hwndDlg,IDC_ABOUT,hContact,szProto,"About",0);
+ }
+ break;
+ }
+ case PSN_APPLY:
+ { HANDLE hContact=(HANDLE)((LPPSHNOTIFY)lParam)->lParam;
+ if(GetWindowTextLength(GetDlgItem(hwndDlg,IDC_MYNOTES))) {
+ char text[2048];
+ GetDlgItemTextA(hwndDlg,IDC_MYNOTES,text,SIZEOF(text));
+ DBWriteContactSettingString(hContact,"UserInfo","MyNotes",text);
+ }
+ else DBDeleteContactSetting(hContact,"UserInfo","MyNotes");
+ break;
+ }
+ }
+ break;
+ }
+ break;
+ case WM_COMMAND:
+ if(wParam==MAKEWPARAM(IDC_MYNOTES,EN_CHANGE))
+ SendMessage(GetParent(hwndDlg),PSM_CHANGED,0,0);
+ else if(LOWORD(wParam)==IDCANCEL)
+ SendMessage(GetParent(hwndDlg),msg,wParam,lParam);
+ break;
+ case WM_DESTROY:
+ {
+ HFONT hFont = (HFONT)SendDlgItemMessage(hwndDlg, IDC_ABOUT, WM_GETFONT, 0, 0);
+ DeleteObject(hFont);
+ }
+ break;
+ }
+ return FALSE;
+}
+
+int DetailsInit(WPARAM wParam,LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE odp;
+
+ if ((HANDLE)lParam == NULL)
+ return 0;
+
+ if ( CallService(MS_PROTO_GETCONTACTBASEPROTO, lParam, 0) == 0 )
+ return 0;
+
+ odp.cbSize = sizeof(odp);
+ odp.hIcon = NULL;
+ odp.hInstance = hMirandaInst;
+ odp.flags = 0;
+
+ odp.pfnDlgProc = SummaryDlgProc;
+ odp.position = -2100000000;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_INFO_SUMMARY);
+ odp.pszTitle = LPGEN("Summary");
+ CallService(MS_USERINFO_ADDPAGE, wParam, ( LPARAM )&odp);
+
+ odp.pfnDlgProc = ContactDlgProc;
+ odp.position = -1800000000;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_INFO_CONTACT);
+ odp.pszTitle = LPGEN("Contact");
+ CallService(MS_USERINFO_ADDPAGE, wParam, ( LPARAM )&odp );
+
+ odp.pfnDlgProc = LocationDlgProc;
+ odp.position = -1500000000;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_INFO_LOCATION);
+ odp.pszTitle = LPGEN("Location");
+ CallService(MS_USERINFO_ADDPAGE, wParam, ( LPARAM )&odp);
+
+ odp.pfnDlgProc = WorkDlgProc;
+ odp.position = -1200000000;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_INFO_WORK);
+ odp.pszTitle = LPGEN("Work");
+ CallService(MS_USERINFO_ADDPAGE, wParam, ( LPARAM )&odp);
+
+ odp.pfnDlgProc = BackgroundDlgProc;
+ odp.position = -900000000;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_INFO_BACKGROUND);
+ odp.pszTitle = LPGEN("Background info");
+ CallService(MS_USERINFO_ADDPAGE, wParam, ( LPARAM )&odp );
+
+ odp.pfnDlgProc = NotesDlgProc;
+ odp.position = 0;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_INFO_NOTES);
+ odp.pszTitle = LPGEN("Notes");
+ CallService(MS_USERINFO_ADDPAGE, wParam, ( LPARAM )&odp);
+ return 0;
+}
diff --git a/src/modules/userinfo/userinfo.cpp b/src/modules/userinfo/userinfo.cpp
new file mode 100644
index 0000000000..a17b2d4c71
--- /dev/null
+++ b/src/modules/userinfo/userinfo.cpp
@@ -0,0 +1,636 @@
+/*
+
+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 UPDATEANIMFRAMES 20
+
+int DetailsInit(WPARAM wParam,LPARAM lParam);
+static INT_PTR CALLBACK DlgProcDetails(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+static HANDLE hWindowList=NULL;
+static HANDLE hDetailsInitEvent;
+
+struct DetailsPageInit {
+ int pageCount;
+ OPTIONSDIALOGPAGE *odp;
+};
+
+struct DetailsPageData {
+ DLGTEMPLATE *pTemplate;
+ HINSTANCE hInst;
+ DLGPROC dlgProc;
+ LPARAM dlgParam;
+ HWND hwnd;
+ HTREEITEM hItem;
+ int changed;
+ TCHAR *ptszTitle, *ptszTab;
+};
+
+struct DetailsData {
+ HANDLE hContact;
+ HANDLE hProtoAckEvent;
+ HINSTANCE hInstIcmp;
+ HFONT hBoldFont;
+ int pageCount;
+ int currentPage;
+ struct DetailsPageData *opd;
+ RECT rcDisplay, rcDisplayTab;
+ int updateAnimFrame;
+ TCHAR szUpdating[64];
+ int *infosUpdated;
+};
+
+static int PageSortProc(OPTIONSDIALOGPAGE *item1,OPTIONSDIALOGPAGE *item2)
+{
+ int res;
+ if (!lstrcmp(item1->ptszTitle, TranslateT("Summary"))) return -1;
+ if (!lstrcmp(item2->ptszTitle, TranslateT("Summary"))) return 1;
+ if (res = lstrcmp(item1->ptszTitle, item2->ptszTitle)) return res;
+ if (item1->ptszTab && !item2->ptszTab) return -1;
+ if (!item1->ptszTab && item2->ptszTab) return 1;
+ if (!item1->ptszTab && !item2->ptszTab) return 0;
+ if (item1->ptszTab && !lstrcmp(item1->ptszTab, TranslateT("General"))) return -1;
+ if (item2->ptszTab && !lstrcmp(item2->ptszTab, TranslateT("General"))) return 1;
+ return lstrcmp(item1->ptszTab, item2->ptszTab);
+}
+
+static INT_PTR ShowDetailsDialogCommand(WPARAM wParam,LPARAM)
+{
+ HWND hwnd;
+ PROPSHEETHEADER psh;
+ struct DetailsPageInit opi;
+ int i;
+
+ if(hwnd=WindowList_Find(hWindowList,(HANDLE)wParam)) {
+ SetForegroundWindow(hwnd);
+ SetFocus(hwnd);
+ return 0;
+ }
+
+ opi.pageCount=0;
+ opi.odp=NULL;
+ NotifyEventHooks(hDetailsInitEvent,(WPARAM)&opi,wParam);
+ if(opi.pageCount==0) return 0;
+ qsort(opi.odp,opi.pageCount,sizeof(OPTIONSDIALOGPAGE),(int (*)(const void*,const void*))PageSortProc);
+
+ ZeroMemory(&psh,sizeof(psh));
+ psh.dwSize = sizeof(psh);
+ psh.dwFlags = PSH_PROPSHEETPAGE|PSH_NOAPPLYNOW;
+ psh.hwndParent = NULL;
+ psh.nPages = opi.pageCount;
+ psh.pStartPage = 0;
+ psh.pszCaption = (TCHAR*)wParam; //more abuses of structure: this is hContact
+ psh.ppsp = (PROPSHEETPAGE*)opi.odp; //blatent misuse of the structure, but what the hell
+
+ CreateDialogParam(hMirandaInst,MAKEINTRESOURCE(IDD_DETAILS), NULL, DlgProcDetails, (LPARAM)&psh);
+ for(i=0;i<opi.pageCount;i++) {
+ //cleanup moved to WM_DESTROY
+ //mir_free((char*)opi.odp[i].pszTitle);
+ //mir_free((char*)opi.odp[i].pszTab);
+ if(opi.odp[i].pszGroup!=NULL) mir_free(opi.odp[i].pszGroup);
+ if((DWORD_PTR)opi.odp[i].pszTemplate&0xFFFF0000) mir_free((char*)opi.odp[i].pszTemplate);
+ }
+ mir_free(opi.odp);
+ return 0;
+}
+
+static INT_PTR AddDetailsPage(WPARAM wParam,LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE *odp=(OPTIONSDIALOGPAGE*)lParam, *dst;
+ struct DetailsPageInit *opi=(struct DetailsPageInit*)wParam;
+
+ if(odp==NULL||opi==NULL) return 1;
+ if(odp->cbSize!=sizeof(OPTIONSDIALOGPAGE)
+ && odp->cbSize != OPTIONPAGE_OLD_SIZE2
+ && odp->cbSize != OPTIONPAGE_OLD_SIZE3)
+ return 1;
+
+ opi->odp=(OPTIONSDIALOGPAGE*)mir_realloc(opi->odp,sizeof(OPTIONSDIALOGPAGE)*(opi->pageCount+1));
+ dst = opi->odp + opi->pageCount;
+ dst->cbSize = sizeof(OPTIONSDIALOGPAGE);
+ dst->hInstance = odp->hInstance;
+ dst->pfnDlgProc = odp->pfnDlgProc;
+ dst->position = odp->position;
+ if((DWORD_PTR)odp->pszTemplate&0xFFFF0000) dst->pszTemplate = mir_strdup(odp->pszTemplate);
+ else dst->pszTemplate = odp->pszTemplate;
+
+ #if defined(_UNICODE)
+ if ( odp->flags & ODPF_UNICODE )
+ {
+ dst->ptszTitle = (odp->ptszTitle==0) ? NULL : mir_wstrdup(odp->ptszTitle);
+ dst->ptszTab = (!(odp->flags & ODPF_USERINFOTAB) || !odp->ptszTab) ? NULL : mir_wstrdup(odp->ptszTab);
+ }
+ else
+ #endif
+ {
+ if ( odp->flags & ODPF_DONTTRANSLATE )
+ dst->ptszTitle = (odp->pszTitle==0) ? NULL : mir_a2t(odp->pszTitle);
+ else
+ dst->ptszTitle = (odp->pszTitle==0) ? NULL : LangPackPcharToTchar(odp->pszTitle);
+ dst->ptszTab = (!(odp->flags & ODPF_USERINFOTAB) || !odp->pszTab) ? NULL : LangPackPcharToTchar(odp->pszTab);
+ }
+
+ dst->pszGroup = NULL;
+ dst->groupPosition = odp->groupPosition;
+ dst->hGroupIcon = odp->hGroupIcon;
+ dst->hIcon = odp->hIcon;
+ if ( odp->cbSize == sizeof(OPTIONSDIALOGPAGE))
+ dst->dwInitParam = odp->dwInitParam;
+ opi->pageCount++;
+ return 0;
+}
+
+static void ThemeDialogBackground(HWND hwnd)
+{
+ if (enableThemeDialogTexture)
+ enableThemeDialogTexture(hwnd, ETDT_ENABLETAB);
+}
+
+static void CreateDetailsTabs( HWND hwndDlg, struct DetailsData* dat, struct DetailsPageData* ppg )
+{
+ HWND hwndTab = GetDlgItem(hwndDlg, IDC_TABS);
+ int i, sel=0, pages=0;
+ TCITEM tie;
+ tie.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_PARAM;
+ tie.iImage = -1;
+ TabCtrl_DeleteAllItems(hwndTab);
+ for ( i=0; i < dat->pageCount; i++ ) {
+ if (!dat->opd[i].ptszTab || lstrcmp(dat->opd[i].ptszTitle, ppg->ptszTitle)) continue;
+
+ tie.pszText = TranslateTS(dat->opd[i].ptszTab);
+ tie.lParam = i;
+ TabCtrl_InsertItem(hwndTab, pages, &tie);
+ if (!lstrcmp(dat->opd[i].ptszTab,ppg->ptszTab))
+ sel = pages;
+ pages++;
+ }
+ TabCtrl_SetCurSel(hwndTab,sel);
+
+ LONG style = GetWindowLong(hwndTab, GWL_STYLE);
+ SetWindowLong(hwndTab, GWL_STYLE, pages > 1 ? style | WS_TABSTOP : style & ~WS_TABSTOP);
+}
+
+static void CreateDetailsPageWindow( HWND hwndDlg, struct DetailsData* dat, struct DetailsPageData* ppg )
+{
+ RECT *rc = ppg->ptszTab ? &dat->rcDisplayTab : &dat->rcDisplay;
+ ppg->hwnd=CreateDialogIndirectParam(ppg->hInst,ppg->pTemplate,hwndDlg,ppg->dlgProc,(LPARAM)dat->hContact);
+ ThemeDialogBackground(ppg->hwnd);
+ SetWindowPos(ppg->hwnd, HWND_TOP, rc->left, rc->top, rc->right - rc->left, rc->bottom - rc->top, 0);
+ SetWindowPos(ppg->hwnd, HWND_TOP, rc->left, rc->top, rc->right - rc->left, rc->bottom - rc->top, 0);
+ {
+ PSHNOTIFY pshn;
+ pshn.hdr.code = PSN_PARAMCHANGED;
+ pshn.hdr.hwndFrom = ppg->hwnd;
+ pshn.hdr.idFrom = 0;
+ pshn.lParam = (LPARAM)ppg->dlgParam;
+ SendMessage(ppg->hwnd,WM_NOTIFY,0,(LPARAM)&pshn);
+
+ pshn.hdr.code=PSN_INFOCHANGED;
+ pshn.hdr.hwndFrom=ppg->hwnd;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=(LPARAM)dat->hContact;
+ SendMessage(ppg->hwnd,WM_NOTIFY,0,(LPARAM)&pshn);
+ }
+}
+
+static int UserInfoContactDelete(WPARAM wParam,LPARAM)
+{
+ HWND hwnd;
+ hwnd=WindowList_Find(hWindowList,(HANDLE)wParam);
+ if(hwnd!=NULL) DestroyWindow(hwnd);
+ return 0;
+}
+
+#define HM_PROTOACK (WM_USER+10)
+#define M_CHECKONLINE (WM_USER+11)
+static INT_PTR CALLBACK DlgProcDetails(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ struct DetailsData *dat =(struct DetailsData*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA);
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ Window_SetIcon_IcoLib(hwndDlg, SKINICON_OTHER_USERDETAILS);
+ {
+ PROPSHEETHEADER *psh = (PROPSHEETHEADER*)lParam;
+ dat = (DetailsData*)mir_calloc(sizeof(DetailsData));
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)dat);
+ dat->hContact = (HANDLE)psh->pszCaption;
+ dat->hProtoAckEvent = HookEventMessage(ME_PROTO_ACK,hwndDlg,HM_PROTOACK);
+ WindowList_Add(hWindowList,hwndDlg,dat->hContact);
+ {
+ TCHAR *name, oldTitle[256], newTitle[256];
+ if (dat->hContact == NULL)
+ name = TranslateT("Owner");
+ else
+ name = cli.pfnGetContactDisplayName( dat->hContact, 0 );
+
+ GetWindowText( hwndDlg, oldTitle, SIZEOF( oldTitle ));
+ mir_sntprintf( newTitle, SIZEOF(newTitle), oldTitle, name );
+ SetWindowText( hwndDlg, newTitle );
+
+ GetDlgItemText( hwndDlg, IDC_HEADERBAR, oldTitle, SIZEOF( oldTitle ));
+ mir_sntprintf( newTitle, SIZEOF(newTitle), oldTitle, name );
+ SetDlgItemText( hwndDlg, IDC_HEADERBAR, newTitle );
+ }
+ { LOGFONT lf;
+ HFONT hNormalFont=(HFONT)SendDlgItemMessage(hwndDlg,IDC_NAME,WM_GETFONT,0,0);
+ GetObject(hNormalFont,sizeof(lf),&lf);
+ lf.lfWeight=FW_BOLD;
+ dat->hBoldFont=CreateFontIndirect(&lf);
+ SendDlgItemMessage(hwndDlg,IDC_NAME,WM_SETFONT,(WPARAM)dat->hBoldFont,0);
+ }
+ { OPTIONSDIALOGPAGE *odp;
+ int i;
+ TVINSERTSTRUCT tvis;
+ DBVARIANT dbv;
+
+ HWND hwndTree = GetDlgItem(hwndDlg, IDC_PAGETREE);
+
+ dat->currentPage = 0;
+ if ( DBGetContactSettingTString( NULL, "UserInfo", "LastTab", &dbv ))
+ dbv.type = DBVT_DELETED;
+ dat->pageCount = psh->nPages;
+ dat->opd = (DetailsPageData*)mir_calloc(sizeof(DetailsPageData) * dat->pageCount);
+ odp = (OPTIONSDIALOGPAGE*)psh->ppsp;
+
+ for ( i=0; i < dat->pageCount; i++ ) {
+ dat->opd[i].pTemplate = (LPDLGTEMPLATE)LockResource(LoadResource(odp[i].hInstance,
+ FindResourceA(odp[i].hInstance, odp[i].pszTemplate, MAKEINTRESOURCEA(5))));
+ dat->opd[i].dlgProc = odp[i].pfnDlgProc;
+ dat->opd[i].dlgParam = odp[i].dwInitParam;
+ dat->opd[i].hInst = odp[i].hInstance;
+
+ dat->opd[i].ptszTitle = odp[i].ptszTitle;
+ dat->opd[i].ptszTab = odp[i].ptszTab;
+
+ if (i && dat->opd[i].ptszTab && !lstrcmp(dat->opd[i-1].ptszTitle, dat->opd[i].ptszTitle)) {
+ dat->opd[i].hItem = dat->opd[i-1].hItem;
+ continue;
+ }
+
+ tvis.hParent = NULL;
+ tvis.hInsertAfter = TVI_LAST;
+ tvis.item.mask = TVIF_TEXT | TVIF_PARAM;
+ tvis.item.lParam = (LPARAM) i;
+ if (odp[i].flags & ODPF_DONTTRANSLATE)
+ tvis.item.pszText = mir_tstrdup(odp[i].ptszTitle);
+ else
+ tvis.item.pszText = TranslateTS(odp[i].ptszTitle);
+ if ( dbv.type != DBVT_DELETED && !lstrcmp( tvis.item.pszText, dbv.ptszVal ))
+ dat->currentPage = i;
+ dat->opd[i].hItem = TreeView_InsertItem(hwndTree, &tvis);
+ }
+ DBFreeVariant(&dbv);
+ }
+
+ {
+ HWND hwndTab = GetDlgItem(hwndDlg, IDC_TABS);
+
+ TCITEM tci;
+ tci.mask = TCIF_TEXT | TCIF_IMAGE;
+ tci.iImage = -1;
+ tci.pszText = _T("X");
+ TabCtrl_InsertItem(hwndTab,0,&tci);
+
+ GetWindowRect(hwndTab, &dat->rcDisplayTab);
+ TabCtrl_AdjustRect(hwndTab, FALSE, &dat->rcDisplayTab);
+ { POINT pt={0,0};
+ ClientToScreen(hwndDlg, &pt);
+ OffsetRect(&dat->rcDisplayTab, -pt.x, -pt.y);
+ }
+
+ TabCtrl_DeleteAllItems(hwndTab);
+
+ GetWindowRect(hwndTab, &dat->rcDisplay);
+ TabCtrl_AdjustRect(hwndTab, FALSE, &dat->rcDisplay);
+ { POINT pt={0,0};
+ ClientToScreen(hwndDlg, &pt);
+ OffsetRect(&dat->rcDisplay, -pt.x, -pt.y);
+ } }
+
+ TreeView_SelectItem(GetDlgItem(hwndDlg, IDC_PAGETREE), dat->opd[dat->currentPage].hItem);
+
+ dat->updateAnimFrame = 0;
+ GetDlgItemText(hwndDlg,IDC_UPDATING,dat->szUpdating,SIZEOF(dat->szUpdating));
+ SendMessage(hwndDlg,M_CHECKONLINE,0,0);
+ if (!CallContactService(dat->hContact,PSS_GETINFO,SGIF_ONOPEN,0)) {
+ EnableWindow(GetDlgItem(hwndDlg,IDC_UPDATE),FALSE);
+ SetTimer(hwndDlg,1,100,NULL);
+ } else
+ ShowWindow(GetDlgItem(hwndDlg,IDC_UPDATING),SW_HIDE);
+
+ SetFocus(GetDlgItem(hwndDlg, IDC_PAGETREE));
+
+ return TRUE;
+ }
+ case WM_TIMER:
+ {
+ TCHAR str[128];
+ mir_sntprintf(str,SIZEOF(str), _T("%.*s%s%.*s"),dat->updateAnimFrame%10,_T("........."),dat->szUpdating,dat->updateAnimFrame%10,_T("........."));
+ SetDlgItemText(hwndDlg,IDC_UPDATING,str);
+ if(++dat->updateAnimFrame==UPDATEANIMFRAMES) dat->updateAnimFrame=0;
+ break;
+ }
+ case WM_CTLCOLORSTATIC:
+ switch (GetDlgCtrlID((HWND)lParam)) {
+ case IDC_WHITERECT:
+ SetBkColor((HDC)wParam, GetSysColor(COLOR_WINDOW));
+ return (INT_PTR)GetSysColorBrush(COLOR_WINDOW);
+ case IDC_UPDATING:
+ {
+ COLORREF textCol,bgCol,newCol;
+ int ratio;
+ textCol=GetSysColor(COLOR_BTNTEXT);
+ bgCol=GetSysColor(COLOR_3DFACE);
+ ratio=abs(UPDATEANIMFRAMES/2-dat->updateAnimFrame)*510/UPDATEANIMFRAMES;
+ newCol=RGB(GetRValue(bgCol)+(GetRValue(textCol)-GetRValue(bgCol))*ratio/256,
+ GetGValue(bgCol)+(GetGValue(textCol)-GetGValue(bgCol))*ratio/256,
+ GetBValue(bgCol)+(GetBValue(textCol)-GetBValue(bgCol))*ratio/256);
+ SetTextColor((HDC)wParam,newCol);
+ SetBkColor((HDC)wParam,GetSysColor(COLOR_3DFACE));
+ return (INT_PTR)GetSysColorBrush(COLOR_3DFACE);
+ }
+ default:
+ SetBkMode((HDC)wParam,TRANSPARENT);
+ return (INT_PTR)GetStockObject(NULL_BRUSH);
+ }
+ break;
+
+ case PSM_CHANGED:
+ dat->opd[dat->currentPage].changed=1;
+ return TRUE;
+
+ case PSM_FORCECHANGED:
+ {
+ int i;
+ PSHNOTIFY pshn;
+ pshn.hdr.code=PSN_INFOCHANGED;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=(LPARAM)dat->hContact;
+ for(i=0;i<dat->pageCount;i++) {
+ pshn.hdr.hwndFrom=dat->opd[i].hwnd;
+ if(dat->opd[i].hwnd!=NULL)
+ SendMessage(dat->opd[i].hwnd,WM_NOTIFY,0,(LPARAM)&pshn);
+ }
+ break;
+ }
+ case M_CHECKONLINE:
+ {
+ char *szProto;
+ if (dat->hContact != NULL) {
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)dat->hContact,0);
+ if(szProto==NULL) {EnableWindow(GetDlgItem(hwndDlg,IDC_UPDATE),FALSE); break;}
+ if(CallProtoService(szProto,PS_GETSTATUS,0,0)<ID_STATUS_ONLINE) EnableWindow(GetDlgItem(hwndDlg,IDC_UPDATE),FALSE);
+ else EnableWindow(GetDlgItem(hwndDlg,IDC_UPDATE),!IsWindowVisible(GetDlgItem(hwndDlg,IDC_UPDATING)));
+ }
+ break;
+ }
+ case HM_PROTOACK:
+ {
+ ACKDATA *ack=(ACKDATA*)lParam;
+ int i;
+
+ if(ack->hContact==NULL && ack->type==ACKTYPE_STATUS) {
+ SendMessage(hwndDlg,M_CHECKONLINE,0,0);
+ break;
+ }
+ if(ack->hContact!=dat->hContact) break;
+ if(ack->type!=ACKTYPE_GETINFO) break;
+ SendMessage(hwndDlg,PSM_FORCECHANGED,0,0);
+ /* if they're not gonna send any more ACK's don't let that mean we should crash */
+ if (!ack->hProcess && !ack->lParam) {
+ ShowWindow(GetDlgItem(hwndDlg,IDC_UPDATING),SW_HIDE);
+ KillTimer(hwndDlg,1);
+ SendMessage(hwndDlg,M_CHECKONLINE,0,0);
+ break;
+ } //if
+ if(dat->infosUpdated==NULL) dat->infosUpdated=(int*)mir_calloc(sizeof(int)*(INT_PTR)ack->hProcess);
+ if(ack->result==ACKRESULT_SUCCESS || ack->result==ACKRESULT_FAILED) dat->infosUpdated[ack->lParam]=1;
+ for(i=0;i<(int)ack->hProcess;i++)
+ if(dat->infosUpdated[i]==0) break;
+ if(i==(int)ack->hProcess) {
+ ShowWindow(GetDlgItem(hwndDlg,IDC_UPDATING),SW_HIDE);
+ KillTimer(hwndDlg,1);
+ SendMessage(hwndDlg,M_CHECKONLINE,0,0);
+ } }
+ break;
+
+ case WM_NOTIFY:
+ switch(wParam) {
+ case IDC_TABS:
+ case IDC_PAGETREE:
+ switch(((LPNMHDR)lParam)->code)
+ {
+ case TCN_SELCHANGING:
+ case TVN_SELCHANGING:
+ if (dat->currentPage != -1 && dat->opd[dat->currentPage].hwnd != NULL)
+ {
+ PSHNOTIFY pshn;
+ pshn.hdr.code = PSN_KILLACTIVE;
+ pshn.hdr.hwndFrom = dat->opd[dat->currentPage].hwnd;
+ pshn.hdr.idFrom = 0;
+ pshn.lParam = (LPARAM)dat->hContact;
+ if (SendMessage(dat->opd[dat->currentPage].hwnd, WM_NOTIFY, 0, (LPARAM)&pshn))
+ {
+ SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE);
+ return TRUE;
+ }
+ }
+ break;
+
+ case TCN_SELCHANGE:
+ if (dat->currentPage != -1 && dat->opd[dat->currentPage].hwnd != NULL)
+ {
+ HWND hwndTab = GetDlgItem(hwndDlg, IDC_TABS);
+ ShowWindow(dat->opd[dat->currentPage].hwnd, SW_HIDE);
+
+ TCITEM tie;
+ TVITEM tvi;
+
+ tie.mask = TCIF_PARAM;
+ TabCtrl_GetItem(hwndTab, TabCtrl_GetCurSel(hwndTab), &tie);
+ dat->currentPage = tie.lParam;
+
+ tvi.hItem = TreeView_GetNextItem(GetDlgItem(hwndDlg,IDC_PAGETREE), NULL, TVGN_CARET);
+ tvi.mask = TVIF_PARAM;
+ tvi.lParam = dat->currentPage;
+ TreeView_SetItem(GetDlgItem(hwndDlg,IDC_PAGETREE), &tvi);
+
+ if (dat->currentPage != -1)
+ {
+ if (dat->opd[dat->currentPage].hwnd == NULL)
+ CreateDetailsPageWindow(hwndDlg, dat, &dat->opd[dat->currentPage]);
+ ShowWindow(dat->opd[dat->currentPage].hwnd, SW_SHOWNA);
+ }
+ }
+ break;
+
+ case TVN_SELCHANGED:
+ if (dat->currentPage != -1 && dat->opd[dat->currentPage].hwnd != NULL)
+ ShowWindow(dat->opd[dat->currentPage].hwnd, SW_HIDE);
+
+ {
+ LPNMTREEVIEW pnmtv = (LPNMTREEVIEW) lParam;
+ TVITEM tvi = pnmtv->itemNew;
+ dat->currentPage = tvi.lParam;
+
+ if(dat->currentPage != -1)
+ {
+ CreateDetailsTabs(hwndDlg, dat, &dat->opd[dat->currentPage]);
+ if (dat->opd[dat->currentPage].hwnd == NULL)
+ CreateDetailsPageWindow(hwndDlg, dat, &dat->opd[dat->currentPage]);
+ ShowWindow(dat->opd[dat->currentPage].hwnd, SW_SHOWNA);
+
+ }
+ }
+ break;
+ }
+ break;
+ }
+ break;
+
+ case WM_COMMAND:
+ switch(LOWORD(wParam)) {
+ case IDCANCEL:
+ {
+ int i;
+ PSHNOTIFY pshn;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=(LPARAM)dat->hContact;
+ pshn.hdr.code=PSN_RESET;
+ for(i=0;i<dat->pageCount;i++) {
+ if(dat->opd[i].hwnd==NULL || !dat->opd[i].changed) continue;
+ pshn.hdr.hwndFrom=dat->opd[i].hwnd;
+ SendMessage(dat->opd[i].hwnd,WM_NOTIFY,0,(LPARAM)&pshn);
+ }
+ DestroyWindow(hwndDlg);
+ break;
+ }
+ case IDOK:
+ {
+ int i;
+ PSHNOTIFY pshn;
+ pshn.hdr.idFrom=0;
+ pshn.lParam=(LPARAM)dat->hContact;
+ if(dat->currentPage!=-1) {
+ pshn.hdr.code=PSN_KILLACTIVE;
+ pshn.hdr.hwndFrom=dat->opd[dat->currentPage].hwnd;
+ if(SendMessage(dat->opd[dat->currentPage].hwnd,WM_NOTIFY,0,(LPARAM)&pshn))
+ break;
+ }
+
+ pshn.hdr.code=PSN_APPLY;
+ for(i=0;i<dat->pageCount;i++) {
+ if(dat->opd[i].hwnd==NULL || !dat->opd[i].changed) continue;
+ pshn.hdr.hwndFrom=dat->opd[i].hwnd;
+ if(SendMessage(dat->opd[i].hwnd,WM_NOTIFY,0,(LPARAM)&pshn)==PSNRET_INVALID_NOCHANGEPAGE) {
+ TreeView_Select(GetDlgItem(hwndDlg,IDC_PAGETREE), dat->opd[i].hItem, TVGN_CARET);
+ if(dat->currentPage!=-1) ShowWindow(dat->opd[dat->currentPage].hwnd,SW_HIDE);
+ dat->currentPage=i;
+ ShowWindow(dat->opd[dat->currentPage].hwnd,SW_SHOW);
+ return 0;
+ }
+ }
+ DestroyWindow(hwndDlg);
+ break;
+ }
+ case IDC_UPDATE:
+ if(dat->infosUpdated!=NULL) {mir_free(dat->infosUpdated); dat->infosUpdated=NULL;}
+ if(dat->hContact != NULL) {
+ if (!CallContactService(dat->hContact,PSS_GETINFO,0,0)) {
+ EnableWindow(GetDlgItem(hwndDlg,IDC_UPDATE),FALSE);
+ ShowWindow(GetDlgItem(hwndDlg,IDC_UPDATING),SW_SHOW);
+ SetTimer(hwndDlg,1,100,NULL);
+ }
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ SendMessage(hwndDlg,WM_COMMAND,MAKEWPARAM(IDOK,BN_CLICKED),(LPARAM)GetDlgItem(hwndDlg,IDOK));
+ break;
+
+ case WM_DESTROY:
+ {
+ TCHAR name[128];
+ TVITEM tvi;
+ tvi.mask = TVIF_TEXT;
+ tvi.hItem = dat->opd[dat->currentPage].hItem;
+ tvi.pszText=name;
+ tvi.cchTextMax=SIZEOF(name);
+ TreeView_GetItem(GetDlgItem(hwndDlg, IDC_PAGETREE), &tvi);
+ DBWriteContactSettingTString(NULL,"UserInfo","LastTab", name);
+ }
+ Window_FreeIcon_IcoLib(hwndDlg);
+ SendDlgItemMessage(hwndDlg,IDC_NAME,WM_SETFONT,SendDlgItemMessage(hwndDlg,IDC_WHITERECT,WM_GETFONT,0,0),0);
+ DeleteObject(dat->hBoldFont);
+ WindowList_Remove(hWindowList,hwndDlg);
+ UnhookEvent(dat->hProtoAckEvent);
+ { int i;
+ for(i=0;i<dat->pageCount;i++)
+ {
+ if(dat->opd[i].hwnd!=NULL) DestroyWindow(dat->opd[i].hwnd);
+ mir_free(dat->opd[i].ptszTitle);
+ mir_free(dat->opd[i].ptszTab);
+ }
+ }
+ mir_free(dat->infosUpdated);
+ mir_free(dat->opd);
+ mir_free(dat);
+ break;
+ }
+ return FALSE;
+}
+
+int ShutdownUserInfo(WPARAM, LPARAM)
+{
+ WindowList_BroadcastAsync(hWindowList,WM_DESTROY,0,0);
+ return 0;
+}
+
+int LoadUserInfoModule(void)
+{
+ CLISTMENUITEM mi = { 0 };
+
+ CreateServiceFunction(MS_USERINFO_SHOWDIALOG,ShowDetailsDialogCommand);
+ hDetailsInitEvent=CreateHookableEvent(ME_USERINFO_INITIALISE);
+ HookEvent(ME_USERINFO_INITIALISE,DetailsInit);
+ HookEvent(ME_DB_CONTACT_DELETED,UserInfoContactDelete);
+ HookEvent(ME_SYSTEM_PRESHUTDOWN,ShutdownUserInfo);
+ CreateServiceFunction(MS_USERINFO_ADDPAGE,AddDetailsPage);
+
+ mi.cbSize = sizeof(mi);
+ mi.flags = CMIF_ICONFROMICOLIB;
+ mi.position = 1000050000;
+ mi.icolibItem = GetSkinIconHandle( SKINICON_OTHER_USERDETAILS );
+ mi.pszName = LPGEN("User &Details");
+ mi.pszService = MS_USERINFO_SHOWDIALOG;
+ CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&mi);
+
+ mi.position = 500050000;
+ mi.pszName = LPGEN("View/Change My &Details...");
+ CallService(MS_CLIST_ADDMAINMENUITEM,0,(LPARAM)&mi);
+
+ hWindowList = (HANDLE)CallService(MS_UTILS_ALLOCWINDOWLIST,0,0);
+ return 0;
+}
diff --git a/src/modules/useronline/useronline.cpp b/src/modules/useronline/useronline.cpp
new file mode 100644
index 0000000000..23371de267
--- /dev/null
+++ b/src/modules/useronline/useronline.cpp
@@ -0,0 +1,117 @@
+/*
+
+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"
+
+static int uniqueEventId=0;
+
+static int UserOnlineSettingChanged(WPARAM wParam,LPARAM lParam)
+{
+ DBCONTACTWRITESETTING *cws=(DBCONTACTWRITESETTING*)lParam;
+ int newStatus,oldStatus;
+
+ if((HANDLE)wParam==NULL || strcmp(cws->szSetting,"Status")) return 0;
+ newStatus=cws->value.wVal;
+ oldStatus=DBGetContactSettingWord((HANDLE)wParam,"UserOnline","OldStatus",ID_STATUS_OFFLINE);
+ DBWriteContactSettingWord((HANDLE)wParam,"UserOnline","OldStatus",(WORD)newStatus);
+ if(CallService(MS_IGNORE_ISIGNORED,wParam,IGNOREEVENT_USERONLINE)) return 0;
+ if(DBGetContactSettingByte((HANDLE)wParam,"CList","Hidden",0)) return 0;
+ if(newStatus==ID_STATUS_OFFLINE&&oldStatus!=ID_STATUS_OFFLINE) {
+ // Remove the event from the queue if it exists since they are now offline
+ int lastEvent = (int)DBGetContactSettingDword((HANDLE)wParam,"UserOnline","LastEvent",0);
+
+ if (lastEvent) {
+ CallService(MS_CLIST_REMOVEEVENT,wParam,(LPARAM)lastEvent);
+ DBWriteContactSettingDword((HANDLE)wParam,"UserOnline", "LastEvent", 0);
+ }
+ }
+ if((newStatus==ID_STATUS_ONLINE || newStatus==ID_STATUS_FREECHAT) &&
+ oldStatus!=ID_STATUS_ONLINE && oldStatus!=ID_STATUS_FREECHAT) {
+ {
+ DWORD ticked = db_dword_get(NULL, "UserOnline", cws->szModule, GetTickCount());
+ // only play the sound (or show event) if this event happens at least 10 secs after the proto went from offline
+ if ( GetTickCount() - ticked > (1000*10) ) {
+ CLISTEVENT cle;
+ TCHAR tooltip[256];
+
+ ZeroMemory(&cle,sizeof(cle));
+ cle.cbSize=sizeof(cle);
+ cle.flags=CLEF_ONLYAFEW | CLEF_TCHAR;
+ cle.hContact=(HANDLE)wParam;
+ cle.hDbEvent=(HANDLE)(uniqueEventId++);
+ cle.hIcon = LoadSkinIcon( SKINICON_OTHER_USERONLINE, false );
+ cle.pszService="UserOnline/Description";
+ mir_sntprintf(tooltip,SIZEOF(tooltip),TranslateT("%s is Online"), cli.pfnGetContactDisplayName(( HANDLE )wParam, 0 ));
+ cle.ptszTooltip=tooltip;
+ CallService(MS_CLIST_ADDEVENT,0,(LPARAM)&cle);
+ IconLib_ReleaseIcon( cle.hIcon, 0 );
+ DBWriteContactSettingDword(cle.hContact,"UserOnline", "LastEvent", (DWORD)cle.hDbEvent);
+ SkinPlaySound("UserOnline");
+ }
+ }
+ }
+ return 0;
+}
+
+static int UserOnlineAck(WPARAM, LPARAM lParam)
+{
+ ACKDATA * ack = (ACKDATA*) lParam;
+ if ( ack != 0 && ack->szModule && ack->type == ACKTYPE_STATUS && ack->result == ACKRESULT_SUCCESS && ack->hProcess == (HANDLE)ID_STATUS_OFFLINE) {
+ // if going from offline to any other mode, remember when it happened.
+ db_dword_set(NULL, "UserOnline", ack->szModule, GetTickCount());
+ }
+ return 0;
+}
+
+static int UserOnlineModulesLoaded(WPARAM, LPARAM)
+{
+ // reset the counter
+ for ( int j = 0; j < accounts.getCount(); j++ )
+ if ( Proto_IsAccountEnabled( accounts[j] )) db_dword_set( NULL, "UserOnline", accounts[j]->szModuleName, GetTickCount());
+
+ return 0;
+}
+
+static int UserOnlineAccountsChanged( WPARAM eventCode, LPARAM lParam )
+{
+ PROTOACCOUNT* pa = (PROTOACCOUNT*)lParam;
+
+ switch( eventCode ) {
+ case PRAC_ADDED:
+ case PRAC_CHECKED:
+ // reset the counter
+ if ( Proto_IsAccountEnabled( pa ))
+ db_dword_set( NULL, "UserOnline", pa->szModuleName, GetTickCount());
+ break;
+ }
+ return 0;
+}
+
+int LoadUserOnlineModule(void)
+{
+ HookEvent(ME_DB_CONTACT_SETTINGCHANGED,UserOnlineSettingChanged);
+ HookEvent(ME_PROTO_ACK, UserOnlineAck);
+ HookEvent(ME_SYSTEM_MODULESLOADED, UserOnlineModulesLoaded);
+ HookEvent(ME_PROTO_ACCLISTCHANGED, UserOnlineAccountsChanged);
+ SkinAddNewSoundEx("UserOnline","Alerts","Online");
+ return 0;
+}
diff --git a/src/modules/utils/bmpfilter.cpp b/src/modules/utils/bmpfilter.cpp
new file mode 100644
index 0000000000..6f92eba126
--- /dev/null
+++ b/src/modules/utils/bmpfilter.cpp
@@ -0,0 +1,242 @@
+/*
+
+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 <olectl.h>
+
+#include "m_png.h"
+#include "m_imgsrvc.h"
+
+static INT_PTR sttBitmapLoader( const TCHAR* ptszFileName )
+{
+ IPicture *pic;
+ HBITMAP hBmp,hBmpCopy;
+ HBITMAP hOldBitmap, hOldBitmap2;
+ BITMAP bmpInfo;
+ HDC hdc,hdcMem1,hdcMem2;
+ short picType;
+
+ TCHAR szFilename[MAX_PATH];
+ if ( !pathToAbsoluteT(ptszFileName, szFilename, NULL ))
+ mir_sntprintf(szFilename, SIZEOF(szFilename), _T("%s"), ptszFileName);
+
+ int filenameLen = lstrlen(szFilename);
+ if ( filenameLen > 4 ) {
+ TCHAR* pszExt = szFilename + filenameLen - 4;
+
+ if ( ServiceExists( MS_IMG_LOAD ))
+ return CallService( MS_IMG_LOAD, (WPARAM)szFilename, IMGL_TCHAR );
+
+ if ( !lstrcmpi( pszExt, _T(".bmp")) || !lstrcmpi( pszExt, _T(".rle"))) {
+ //LoadImage can do this much faster
+ return (INT_PTR)LoadImage( hMirandaInst, szFilename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE );
+ }
+
+ if ( !lstrcmpi( pszExt, _T(".png"))) {
+ HANDLE hFile, hMap = NULL;
+ BYTE* ppMap = NULL;
+ INT_PTR cbFileSize = 0;
+ BITMAPINFOHEADER* pDib;
+ BYTE* pDibBits;
+
+ if ( !ServiceExists( MS_PNG2DIB )) {
+ MessageBox( NULL, TranslateT( "You need an image services plugin to process PNG images." ), TranslateT( "Error" ), MB_OK );
+ return 0;
+ }
+
+ if (( hFile = CreateFile( szFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL )) != INVALID_HANDLE_VALUE )
+ if (( hMap = CreateFileMapping( hFile, NULL, PAGE_READONLY, 0, 0, NULL )) != NULL )
+ if (( ppMap = ( BYTE* )MapViewOfFile( hMap, FILE_MAP_READ, 0, 0, 0 )) != NULL )
+ cbFileSize = GetFileSize( hFile, NULL );
+
+ if ( cbFileSize != 0 ) {
+ PNG2DIB param;
+ param.pSource = ppMap;
+ param.cbSourceSize = cbFileSize;
+ param.pResult = &pDib;
+ if ( CallService( MS_PNG2DIB, 0, ( LPARAM )&param )) {
+ pDibBits = ( BYTE* )( pDib+1 );
+ HDC sDC = GetDC( NULL );
+ HBITMAP hBitmap = CreateDIBitmap( sDC, pDib, CBM_INIT, pDibBits, ( BITMAPINFO* )pDib, DIB_PAL_COLORS );
+ SelectObject( sDC, hBitmap );
+ ReleaseDC( NULL, sDC );
+ GlobalFree( pDib );
+ cbFileSize = (INT_PTR)hBitmap;
+ }
+ else cbFileSize = 0;
+ }
+
+ if ( ppMap != NULL ) UnmapViewOfFile( ppMap );
+ if ( hMap != NULL ) CloseHandle( hMap );
+ if ( hFile != NULL ) CloseHandle( hFile );
+
+ return (INT_PTR)cbFileSize;
+ } }
+
+ if (S_OK != OleLoadPicturePath( LPOLESTR(( const wchar_t* )StrConvU(szFilename)), NULL, 0, 0, IID_IPicture, (PVOID*)&pic ))
+ return 0;
+
+ pic->get_Type(&picType);
+ if (picType!=PICTYPE_BITMAP) {
+ pic->Release();
+ return 0;
+ }
+ OLE_HANDLE hOleBmp;
+ pic->get_Handle(&hOleBmp);
+ hBmp = (HBITMAP)hOleBmp;
+ GetObject(hBmp,sizeof(bmpInfo),&bmpInfo);
+
+ //need to copy bitmap so we can free the IPicture
+ hdc=GetDC(NULL);
+ hdcMem1=CreateCompatibleDC(hdc);
+ hdcMem2=CreateCompatibleDC(hdc);
+ hOldBitmap=( HBITMAP )SelectObject(hdcMem1,hBmp);
+ hBmpCopy=CreateCompatibleBitmap(hdcMem1,bmpInfo.bmWidth,bmpInfo.bmHeight);
+ hOldBitmap2=( HBITMAP )SelectObject(hdcMem2,hBmpCopy);
+ BitBlt(hdcMem2,0,0,bmpInfo.bmWidth,bmpInfo.bmHeight,hdcMem1,0,0,SRCCOPY);
+ SelectObject(hdcMem1,hOldBitmap);
+ SelectObject(hdcMem2,hOldBitmap2);
+ DeleteDC(hdcMem2);
+ DeleteDC(hdcMem1);
+ ReleaseDC(NULL,hdc);
+
+ DeleteObject(hBmp);
+ pic->Release();
+ return (INT_PTR)hBmpCopy;
+}
+
+static INT_PTR BmpFilterLoadBitmap(WPARAM, LPARAM lParam)
+{
+ return sttBitmapLoader( StrConvT(( const char* )lParam ));
+}
+
+#if defined( _UNICODE )
+static INT_PTR BmpFilterLoadBitmapW(WPARAM, LPARAM lParam)
+{
+ return sttBitmapLoader(( const wchar_t* )lParam );
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+static INT_PTR BmpFilterGetStrings(WPARAM wParam,LPARAM lParam)
+{
+ int bytesLeft=wParam;
+ char *filter=(char*)lParam,*pfilter;
+
+ lstrcpynA(filter,Translate("All Bitmaps"),bytesLeft); bytesLeft-=lstrlenA(filter);
+ strncat(filter," (*.bmp;*.jpg;*.gif;*.png)",bytesLeft);
+ pfilter=filter+lstrlenA(filter)+1; bytesLeft=wParam-(pfilter-filter);
+ lstrcpynA(pfilter,"*.BMP;*.RLE;*.JPG;*.JPEG;*.GIF;*.PNG",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+
+ lstrcpynA(pfilter,Translate("Windows Bitmaps"),bytesLeft); bytesLeft-=lstrlenA(pfilter);
+ strncat(pfilter," (*.bmp;*.rle)",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+ lstrcpynA(pfilter,"*.BMP;*.RLE",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+
+ lstrcpynA(pfilter,Translate("JPEG Bitmaps"),bytesLeft); bytesLeft-=lstrlenA(pfilter);
+ strncat(pfilter," (*.jpg;*.jpeg)",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+ lstrcpynA(pfilter,"*.JPG;*.JPEG",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+
+ lstrcpynA(pfilter,Translate("GIF Bitmaps"),bytesLeft); bytesLeft-=lstrlenA(pfilter);
+ strncat(pfilter," (*.gif)",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+ lstrcpynA(pfilter,"*.GIF",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+
+ lstrcpynA(pfilter,Translate("PNG Bitmaps"),bytesLeft); bytesLeft-=lstrlenA(pfilter);
+ strncat(pfilter," (*.png)",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+ lstrcpynA(pfilter,"*.PNG",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+
+ lstrcpynA(pfilter,Translate("All Files"),bytesLeft); bytesLeft-=lstrlenA(pfilter);
+ strncat(pfilter," (*)",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+ lstrcpynA(pfilter,"*",bytesLeft);
+ pfilter+=lstrlenA(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+
+ if (bytesLeft) *pfilter='\0';
+ return 0;
+}
+
+#if defined( _UNICODE )
+static INT_PTR BmpFilterGetStringsW(WPARAM wParam,LPARAM lParam)
+{
+ int bytesLeft=wParam;
+ TCHAR *filter=(TCHAR*)lParam,*pfilter;
+
+ lstrcpyn(filter,TranslateT("All Bitmaps"),bytesLeft); bytesLeft-=lstrlen(filter);
+ _tcsncat(filter, _T(" (*.bmp;*.jpg;*.gif;*.png)"), bytesLeft );
+ pfilter=filter+lstrlen(filter)+1; bytesLeft=wParam-(pfilter-filter);
+ lstrcpyn(pfilter,_T("*.BMP;*.RLE;*.JPG;*.JPEG;*.GIF;*.PNG"),bytesLeft);
+ pfilter+=lstrlen(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+
+ lstrcpyn(pfilter,TranslateT("Windows Bitmaps"),bytesLeft); bytesLeft-=lstrlen(pfilter);
+ _tcsncat(pfilter,_T(" (*.bmp;*.rle)"),bytesLeft);
+ pfilter+=lstrlen(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+ lstrcpyn(pfilter,_T("*.BMP;*.RLE"),bytesLeft);
+ pfilter+=lstrlen(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+
+ lstrcpyn(pfilter,TranslateT("JPEG Bitmaps"),bytesLeft); bytesLeft-=lstrlen(pfilter);
+ _tcsncat(pfilter,_T(" (*.jpg;*.jpeg)"),bytesLeft);
+ pfilter+=lstrlen(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+ lstrcpyn(pfilter,_T("*.JPG;*.JPEG"),bytesLeft);
+ pfilter+=lstrlen(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+
+ lstrcpyn(pfilter,TranslateT("GIF Bitmaps"),bytesLeft); bytesLeft-=lstrlen(pfilter);
+ _tcsncat(pfilter,_T(" (*.gif)"),bytesLeft);
+ pfilter+=lstrlen(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+ lstrcpyn(pfilter,_T("*.GIF"),bytesLeft);
+ pfilter+=lstrlen(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+
+ lstrcpyn(pfilter,TranslateT("PNG Bitmaps"),bytesLeft); bytesLeft-=lstrlen(pfilter);
+ _tcsncat(pfilter,_T(" (*.png)"),bytesLeft);
+ pfilter+=lstrlen(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+ lstrcpyn(pfilter,_T("*.PNG"),bytesLeft);
+ pfilter+=lstrlen(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+
+ lstrcpyn(pfilter,TranslateT("All Files"),bytesLeft); bytesLeft-=lstrlen(pfilter);
+ _tcsncat(pfilter,_T(" (*)"),bytesLeft);
+ pfilter+=lstrlen(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+ lstrcpyn(pfilter,_T("*"),bytesLeft);
+ pfilter+=lstrlen(pfilter)+1; bytesLeft=wParam-(pfilter-filter);
+
+ if (bytesLeft) *pfilter='\0';
+ return 0;
+}
+#endif
+
+int InitBitmapFilter(void)
+{
+ CreateServiceFunction(MS_UTILS_LOADBITMAP,BmpFilterLoadBitmap);
+ CreateServiceFunction(MS_UTILS_GETBITMAPFILTERSTRINGS,BmpFilterGetStrings);
+ #if defined( _UNICODE )
+ CreateServiceFunction(MS_UTILS_GETBITMAPFILTERSTRINGSW,BmpFilterGetStringsW);
+ CreateServiceFunction(MS_UTILS_LOADBITMAPW,BmpFilterLoadBitmapW);
+ #endif
+ return 0;
+}
diff --git a/src/modules/utils/colourpicker.cpp b/src/modules/utils/colourpicker.cpp
new file mode 100644
index 0000000000..ec1a87153c
--- /dev/null
+++ b/src/modules/utils/colourpicker.cpp
@@ -0,0 +1,107 @@
+/*
+
+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"
+
+static LRESULT CALLBACK ColourPickerWndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
+{
+ switch(message) {
+ case WM_CREATE:
+ SetWindowLongPtr(hwnd,0,0);
+ SetWindowLongPtr(hwnd,sizeof(COLORREF),0);
+ break;
+ case CPM_SETDEFAULTCOLOUR:
+ SetWindowLongPtr(hwnd,sizeof(COLORREF),lParam);
+ break;
+ case CPM_GETDEFAULTCOLOUR:
+ return GetWindowLongPtr(hwnd,sizeof(COLORREF));
+ case CPM_SETCOLOUR:
+ SetWindowLongPtr(hwnd,0,lParam);
+ InvalidateRect(hwnd,NULL,FALSE);
+ break;
+ case CPM_GETCOLOUR:
+ return GetWindowLongPtr(hwnd,0);
+ case WM_LBUTTONUP:
+ {
+ CHOOSECOLOR cc={0};
+ COLORREF custColours[16]={0};
+ custColours[0]=GetWindowLongPtr(hwnd,sizeof(COLORREF));
+ cc.lStructSize=sizeof(CHOOSECOLOR);
+ cc.hwndOwner=hwnd;
+ cc.hInstance=(HWND)hMirandaInst;
+ cc.rgbResult=GetWindowLongPtr(hwnd,0);
+ cc.lpCustColors=custColours;
+ cc.Flags=CC_ANYCOLOR|CC_FULLOPEN|CC_RGBINIT;
+ if(ChooseColor(&cc)) {
+ SetWindowLongPtr(hwnd,0,cc.rgbResult);
+ SendMessage(GetParent(hwnd),WM_COMMAND,MAKEWPARAM(GetDlgCtrlID(hwnd),CPN_COLOURCHANGED),(LPARAM)hwnd);
+ InvalidateRect(hwnd,NULL,FALSE);
+ }
+ break;
+ }
+ case WM_ENABLE:
+ InvalidateRect(hwnd,NULL,FALSE);
+ break;
+ case WM_NCPAINT:
+ case WM_PAINT:
+ { PAINTSTRUCT ps;
+ HDC hdc1;
+ RECT rc;
+ HBRUSH hBrush;
+
+ hdc1=BeginPaint(hwnd,&ps);
+ GetClientRect(hwnd,&rc);
+ DrawEdge(hdc1,&rc,EDGE_ETCHED,BF_RECT);
+ InflateRect(&rc,-2,-2);
+ if(IsWindowEnabled(hwnd))
+ hBrush=CreateSolidBrush(GetWindowLongPtr(hwnd,0));
+ else
+ hBrush=CreateHatchBrush(HS_BDIAGONAL,GetSysColor(COLOR_GRAYTEXT));
+ SetBkColor(hdc1,GetSysColor(COLOR_BTNFACE));
+ FillRect(hdc1,&rc,hBrush);
+ DeleteObject(hBrush);
+ EndPaint(hwnd,&ps);
+ break;
+ }
+ case WM_DESTROY:
+ break;
+ }
+ return DefWindowProc(hwnd,message,wParam,lParam);
+}
+
+int InitColourPicker(void)
+{
+ WNDCLASS wcl;
+
+ wcl.lpfnWndProc=ColourPickerWndProc;
+ wcl.cbClsExtra=0;
+ wcl.cbWndExtra=sizeof(COLORREF)*2;
+ wcl.hInstance=hMirandaInst;
+ wcl.hCursor=NULL;
+ wcl.lpszClassName=WNDCLASS_COLOURPICKER;
+ wcl.hbrBackground=(HBRUSH)(COLOR_BTNFACE+1);
+ wcl.hIcon=NULL;
+ wcl.lpszMenuName=NULL;
+ wcl.style=CS_HREDRAW|CS_VREDRAW|CS_GLOBALCLASS;
+ RegisterClass(&wcl);
+ return 0;
+}
diff --git a/src/modules/utils/hyperlink.cpp b/src/modules/utils/hyperlink.cpp
new file mode 100644
index 0000000000..62d307a958
--- /dev/null
+++ b/src/modules/utils/hyperlink.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"
+
+struct HyperlinkWndData {
+ HFONT hEnableFont,hDisableFont;
+ RECT rcText;
+ COLORREF enableColor, disableColor, focusColor;
+ BYTE flags; /* see HLKF_* */
+};
+
+/* flags */
+#define HLKF_HASENABLECOLOR 0x1 /* dat->enableColor is not system default */
+#define HLKF_HASDISABLECOLOR 0x2 /* dat->disableColor is not system default */
+
+/* internal messages */
+#define HLK_MEASURETEXT (WM_USER+1)
+#define HLK_INVALIDATE (WM_USER+2)
+
+static LRESULT CALLBACK HyperlinkWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
+{
+ struct HyperlinkWndData *dat=(struct HyperlinkWndData*)GetWindowLongPtr(hwnd,0);
+ switch(msg) {
+ case WM_NCCREATE:
+ dat=(struct HyperlinkWndData*)mir_calloc(sizeof(struct HyperlinkWndData));
+ if(dat==NULL) return FALSE; /* fail creation */
+ SetWindowLongPtr(hwnd,0,(LONG_PTR)dat); /* always succeeds */
+ /* fall thru */
+ case WM_SYSCOLORCHANGE:
+ if(!(dat->flags&HLKF_HASENABLECOLOR)) {
+ if(GetSysColorBrush(COLOR_HOTLIGHT)==NULL) dat->enableColor=RGB(0,0,255);
+ else dat->enableColor=GetSysColor(COLOR_HOTLIGHT);
+ dat->focusColor = RGB(GetRValue(dat->enableColor) / 2, GetGValue(dat->enableColor) / 2, GetBValue(dat->enableColor) / 2);
+ }
+ if(!(dat->flags&HLKF_HASDISABLECOLOR))
+ dat->disableColor=GetSysColor(COLOR_GRAYTEXT);
+ break;
+
+ case WM_SETFOCUS:
+ case WM_KILLFOCUS:
+ RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE);
+ break;
+ case WM_MOUSEACTIVATE:
+ SetFocus(hwnd);
+ return MA_ACTIVATE;
+ case WM_GETDLGCODE:
+ {
+ if (lParam)
+ {
+ MSG *msg = (MSG *) lParam;
+ if (msg->message == WM_KEYDOWN)
+ {
+ if (msg->wParam == VK_TAB)
+ return 0;
+ if (msg->wParam == VK_ESCAPE)
+ return 0;
+ } else
+ if (msg->message == WM_CHAR)
+ {
+ if (msg->wParam == '\t')
+ return 0;
+ if (msg->wParam == 27)
+ return 0;
+ }
+ }
+ return DLGC_WANTMESSAGE;
+ }
+
+ case WM_KEYDOWN:
+ {
+ switch (wParam)
+ {
+ case VK_SPACE:
+ case VK_RETURN:
+ SendMessage(GetParent(hwnd),WM_COMMAND,MAKEWPARAM(GetDlgCtrlID(hwnd),STN_CLICKED),(LPARAM)hwnd);
+ break;
+ }
+ return 0;
+ }
+
+ case WM_LBUTTONDOWN:
+ { POINT pt;
+ POINTSTOPOINT(pt,MAKEPOINTS(lParam));
+ if(!PtInRect(&dat->rcText,pt)) break;
+ SendMessage(GetParent(hwnd),WM_COMMAND,MAKEWPARAM(GetDlgCtrlID(hwnd),STN_CLICKED),(LPARAM)hwnd);
+ return 0;
+ }
+ case WM_SETFONT:
+ { LOGFONT lf;
+ HFONT hFont;
+ if((HFONT)wParam==NULL) { /* use default system color */
+ dat->hEnableFont=dat->hDisableFont=NULL;
+ return 0;
+ }
+ if(GetObject((HFONT)wParam,sizeof(lf),&lf)) {
+ lf.lfUnderline=1;
+ hFont=CreateFontIndirect(&lf);
+ if(hFont!=NULL) {
+ dat->hEnableFont=hFont;
+ dat->hDisableFont=(HFONT)wParam;
+ if(LOWORD(lParam)) SendMessage(hwnd,HLK_INVALIDATE,0,0);
+ SendMessage(hwnd,HLK_MEASURETEXT,0,0);
+ }
+ }
+ return 0;
+ }
+ case WM_ERASEBKGND:
+ return TRUE;
+ case WM_ENABLE:
+ case HLK_INVALIDATE:
+ { RECT rcWnd;
+ POINT pt;
+ HWND hwndParent;
+ if(!GetWindowRect(hwnd,&rcWnd)) break;
+ pt.x=rcWnd.left;
+ pt.y=rcWnd.top;
+ hwndParent=GetParent(hwnd);
+ if(hwndParent==NULL) hwndParent=hwnd;
+ if(!ScreenToClient(hwndParent,&pt)) break;
+ rcWnd.right=pt.x+(rcWnd.right-rcWnd.left);
+ rcWnd.bottom=pt.y+(rcWnd.bottom-rcWnd.top);
+ rcWnd.left=pt.x;
+ rcWnd.top=pt.y;
+ InvalidateRect(hwndParent,&rcWnd,TRUE);
+ return 0;
+ }
+ case WM_GETFONT:
+ return (LRESULT)dat->hDisableFont;
+ case WM_CREATE:
+ case HLK_MEASURETEXT:
+ { TCHAR szText[256];
+ if(!GetWindowText(hwnd,szText,SIZEOF(szText))) return 0;
+ lParam=(LPARAM)szText;
+ /* fall thru */
+ case WM_SETTEXT:
+ { HFONT hPrevFont = NULL;
+ SIZE textSize;
+ RECT rc;
+ HDC hdc;
+ LONG style;
+ BOOL fMeasured=FALSE;
+ hdc=GetDC(hwnd);
+ if(hdc==NULL) return 0; /* text change failed */
+ if(dat->hEnableFont!=NULL) hPrevFont=(HFONT)SelectObject(hdc,dat->hEnableFont);
+ if(dat->hEnableFont==NULL || hPrevFont!=NULL) /* select failed? */
+ if(GetTextExtentPoint32(hdc,(TCHAR*)lParam,lstrlen((TCHAR*)lParam),&textSize))
+ if(GetClientRect(hwnd,&rc)) {
+ dat->rcText.top=0;
+ dat->rcText.bottom=dat->rcText.top+textSize.cy;
+ style=GetWindowLongPtr(hwnd,GWL_STYLE);
+ if(style&SS_CENTER) dat->rcText.left=(rc.right-textSize.cx)/2;
+ else if(style&SS_RIGHT) dat->rcText.left=rc.right-textSize.cx;
+ else dat->rcText.left=0;
+ dat->rcText.right=dat->rcText.left+textSize.cx;
+ fMeasured=TRUE;
+ }
+ if(dat->hEnableFont!=NULL && hPrevFont!=NULL) SelectObject(hdc,hPrevFont);
+ ReleaseDC(hwnd,hdc);
+ if(!fMeasured) return 0; /* text change failed */
+ SendMessage(hwnd,HLK_INVALIDATE,0,0);
+ break;
+ }}
+ case WM_SETCURSOR:
+ { POINT pt;
+ HCURSOR hCursor;
+ if(!GetCursorPos(&pt)) return FALSE;
+ if(!ScreenToClient(hwnd,&pt)) return FALSE;
+ if(PtInRect(&dat->rcText,pt)) {
+ hCursor=(HCURSOR)GetClassLongPtr(hwnd,GCLP_HCURSOR);
+ if(hCursor==NULL) hCursor=LoadCursor(NULL,IDC_HAND); /* Win2000+ */
+ }
+ else hCursor=LoadCursor(NULL,IDC_ARROW);
+ SetCursor(hCursor);
+ return TRUE;
+ }
+ case HLK_SETENABLECOLOUR:
+ { COLORREF prevColor=dat->enableColor;
+ dat->enableColor=(COLORREF)wParam;
+ dat->focusColor = RGB(GetRValue(dat->enableColor) / 2, GetGValue(dat->enableColor) / 2, GetBValue(dat->enableColor) / 2);
+ dat->flags|=HLKF_HASENABLECOLOR;
+ return (LRESULT)prevColor;
+ }
+ case HLK_SETDISABLECOLOUR:
+ { COLORREF prevColor=dat->disableColor;
+ dat->disableColor=(COLORREF)wParam;
+ dat->flags|=HLKF_HASDISABLECOLOR;
+ return (LRESULT)prevColor;
+ }
+ case WM_NCPAINT:
+ return 0;
+ case WM_PAINT:
+ { HFONT hPrevFont;
+ RECT rc;
+ TCHAR szText[256];
+ UINT alignFlag;
+ COLORREF textColor;
+ PAINTSTRUCT ps;
+ HDC hdc;
+
+ hdc=BeginPaint(hwnd,&ps);
+ if(hdc!=NULL) {
+ if(IsWindowEnabled(hwnd)) {
+ hPrevFont=(HFONT)SelectObject(hdc,dat->hEnableFont);
+ textColor = (GetFocus() == hwnd) ? dat->focusColor : dat->enableColor;
+ } else {
+ hPrevFont=(HFONT)SelectObject(hdc,dat->hDisableFont);
+ textColor=dat->disableColor;
+ }
+ if(GetClientRect(hwnd,&rc) && GetWindowText(hwnd,szText,SIZEOF(szText))) {
+ if (drawThemeParentBackground && IsWinVerXPPlus())
+ {
+ BOOL fSmoothing;
+ UINT fSmoothingType;
+ SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &fSmoothing, 0);
+ SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &fSmoothingType, 0);
+ if (fSmoothing && fSmoothingType == FE_FONTSMOOTHINGCLEARTYPE)
+ drawThemeParentBackground(hwnd, hdc, &rc);
+ }
+ SetBkMode(hdc,TRANSPARENT);
+ SetTextColor(hdc,textColor);
+ alignFlag=(GetWindowLongPtr(hwnd,GWL_STYLE)&(SS_CENTER|SS_RIGHT|SS_LEFT));
+ DrawText(hdc,szText,-1,&rc,alignFlag|DT_NOPREFIX|DT_SINGLELINE|DT_TOP);
+ }
+ if(hPrevFont!=NULL) SelectObject(hdc,hPrevFont);
+ EndPaint(hwnd,&ps);
+ }
+ return 0;
+ }
+ case WM_NCDESTROY:
+ if(dat->hEnableFont!=NULL) DeleteObject(dat->hEnableFont);
+ mir_free(dat);
+ break;
+ }
+ return DefWindowProc(hwnd,msg,wParam,lParam);
+}
+
+int InitHyperlink(void)
+{
+ WNDCLASS wcl;
+
+ wcl.lpfnWndProc=HyperlinkWndProc;
+ wcl.cbClsExtra=0;
+ wcl.cbWndExtra=sizeof(struct HyperlinkWndData*);
+ wcl.hInstance=hMirandaInst;
+ if(IsWinVer2000Plus()) wcl.hCursor=NULL;
+ else wcl.hCursor=LoadCursor(wcl.hInstance,MAKEINTRESOURCE(IDC_HYPERLINKHAND));
+ wcl.lpszClassName=WNDCLASS_HYPERLINK;
+ wcl.hbrBackground=NULL;
+ wcl.hIcon=NULL;
+ wcl.lpszMenuName=NULL;
+ wcl.style=CS_HREDRAW|CS_VREDRAW|CS_GLOBALCLASS|CS_PARENTDC;
+ RegisterClass(&wcl); /* automatically unregistered on exit */
+ return 0;
+}
diff --git a/src/modules/utils/imgconv.cpp b/src/modules/utils/imgconv.cpp
new file mode 100644
index 0000000000..e25953e471
--- /dev/null
+++ b/src/modules/utils/imgconv.cpp
@@ -0,0 +1,152 @@
+/*
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2010 Miranda 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"
+
+typedef DWORD ARGB;
+
+void InitBitmapInfo(BITMAPINFO &bmi, const SIZE &size)
+{
+ ZeroMemory(&bmi, sizeof(BITMAPINFO));
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ bmi.bmiHeader.biBitCount = 32;
+
+ bmi.bmiHeader.biWidth = size.cx;
+ bmi.bmiHeader.biHeight = size.cy;
+}
+
+void ConvertToPARGB32(HDC hdc, ARGB *pargb, HBITMAP hbmp, SIZE& sizImage, int cxRow)
+{
+ BITMAPINFO bmi;
+ InitBitmapInfo(bmi, sizImage);
+
+ void *pvBits = malloc(sizImage.cx * 4 * sizImage.cy);
+ if (GetDIBits(hdc, hbmp, 0, bmi.bmiHeader.biHeight, pvBits, &bmi, DIB_RGB_COLORS) == bmi.bmiHeader.biHeight)
+ {
+ ULONG cxDelta = cxRow - bmi.bmiHeader.biWidth;
+ ARGB *pargbMask = (ARGB *)pvBits;
+
+ for (ULONG y = bmi.bmiHeader.biHeight + 1; --y; )
+ {
+ for (ULONG x = bmi.bmiHeader.biWidth + 1; --x; )
+ {
+ if (*pargbMask++)
+ {
+ // transparent pixel
+ *pargb++ = 0;
+ }
+ else
+ {
+ // opaque pixel
+ *pargb++ |= 0xFF000000;
+ }
+ }
+
+ pargb += cxDelta;
+ }
+ }
+ free(pvBits);
+}
+
+bool HasAlpha( ARGB *pargb, SIZE& sizImage, int cxRow)
+{
+ ULONG cxDelta = cxRow - sizImage.cx;
+ for (ULONG y = sizImage.cy; y--; )
+ {
+ for (ULONG x = sizImage.cx; x--; )
+ {
+ if (*pargb++ & 0xFF000000)
+ return true;
+ }
+ pargb += cxDelta;
+ }
+
+ return false;
+}
+
+void ConvertBufferToPARGB32(HANDLE hPaintBuffer, HDC hdc, HICON hIcon, SIZE& sizIcon)
+{
+ RGBQUAD *prgbQuad;
+ int cxRow;
+ HRESULT hr = getBufferedPaintBits(hPaintBuffer, &prgbQuad, &cxRow);
+ if (SUCCEEDED(hr))
+ {
+ ARGB *pargb = (ARGB *)prgbQuad;
+ if (!HasAlpha(pargb, sizIcon, cxRow))
+ {
+ ICONINFO info;
+ if (GetIconInfo(hIcon, &info))
+ {
+ if (info.hbmMask)
+ ConvertToPARGB32(hdc, pargb, info.hbmMask, sizIcon, cxRow);
+
+ DeleteObject(info.hbmColor);
+ DeleteObject(info.hbmMask);
+ }
+ }
+ }
+}
+
+HBITMAP ConvertIconToBitmap(HICON hicon, HIMAGELIST hIml, int iconId)
+{
+ SIZE sizIcon;
+ sizIcon.cx = GetSystemMetrics(SM_CXSMICON);
+ sizIcon.cy = GetSystemMetrics(SM_CYSMICON);
+
+ RECT rcIcon = { 0, 0, sizIcon.cx, sizIcon.cy };
+
+ HDC hdc = CreateCompatibleDC(NULL);
+
+ BITMAPINFO bmi;
+ InitBitmapInfo(bmi, sizIcon);
+
+ HBITMAP hbmp = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, NULL, NULL, 0);
+ HBITMAP hbmpOld = (HBITMAP)SelectObject(hdc, hbmp);
+
+ BLENDFUNCTION bfAlpha = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
+ BP_PAINTPARAMS paintParams = {0};
+ paintParams.cbSize = sizeof(paintParams);
+ paintParams.dwFlags = BPPF_ERASE;
+ paintParams.pBlendFunction = &bfAlpha;
+
+ HDC hdcBuffer;
+ HANDLE hPaintBuffer = beginBufferedPaint(hdc, &rcIcon, BPBF_DIB, &paintParams, &hdcBuffer);
+ if (hPaintBuffer)
+ {
+ if (hIml)
+ ImageList_Draw(hIml, iconId, hdc, 0, 0, ILD_TRANSPARENT);
+ else
+ DrawIconEx(hdcBuffer, 0, 0, hicon, sizIcon.cx, sizIcon.cy, 0, NULL, DI_NORMAL);
+
+ // If icon did not have an alpha channel we need to convert buffer to PARGB
+ ConvertBufferToPARGB32(hPaintBuffer, hdc, hicon, sizIcon);
+
+ // This will write the buffer contents to the destination bitmap
+ endBufferedPaint(hPaintBuffer, TRUE);
+ }
+
+ SelectObject(hdc, hbmpOld);
+ DeleteDC(hdc);
+
+ return hbmp;
+}
diff --git a/src/modules/utils/md5.cpp b/src/modules/utils/md5.cpp
new file mode 100644
index 0000000000..0fcaccb9ae
--- /dev/null
+++ b/src/modules/utils/md5.cpp
@@ -0,0 +1,374 @@
+/*
+ Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ L. Peter Deutsch
+ ghost@aladdin.com
+
+ */
+/* $Id: md5.c 2874 2006-05-16 21:38:00Z ghazan $ */
+/*
+ Independent implementation of MD5 (RFC 1321).
+
+ This code implements the MD5 Algorithm defined in RFC 1321, whose
+ text is available at
+ http://www.ietf.org/rfc/rfc1321.txt
+ The code is derived from the text of the RFC, including the test suite
+ (section A.5) but excluding the rest of Appendix A. It does not include
+ any code or documentation that is identified in the RFC as being
+ copyrighted.
+
+ The original and principal author of md5.c is L. Peter Deutsch
+ <ghost@aladdin.com>. Other authors are noted in the change history
+ that follows (in reverse chronological order):
+
+ 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
+ either statically or dynamically; added missing #include <string.h>
+ in library.
+ 2002-03-11 lpd Corrected argument list for main(), and added int return
+ type, in test program and T value program.
+ 2002-02-21 lpd Added missing #include <stdio.h> in test program.
+ 2000-07-03 lpd Patched to eliminate warnings about "constant is
+ unsigned in ANSI C, signed in traditional"; made test program
+ self-checking.
+ 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
+ 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
+ 1999-05-03 lpd Original version.
+ */
+
+// (C) 2005 Joe @ Whale - changed to compile with Miranda
+
+#include "commonheaders.h"
+
+
+#define T_MASK ((mir_md5_word_t)~0)
+#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
+#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
+#define T3 0x242070db
+#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
+#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
+#define T6 0x4787c62a
+#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
+#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
+#define T9 0x698098d8
+#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
+#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
+#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
+#define T13 0x6b901122
+#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
+#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
+#define T16 0x49b40821
+#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
+#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
+#define T19 0x265e5a51
+#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
+#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
+#define T22 0x02441453
+#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
+#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
+#define T25 0x21e1cde6
+#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
+#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
+#define T28 0x455a14ed
+#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
+#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
+#define T31 0x676f02d9
+#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
+#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
+#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
+#define T35 0x6d9d6122
+#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
+#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
+#define T38 0x4bdecfa9
+#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
+#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
+#define T41 0x289b7ec6
+#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
+#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
+#define T44 0x04881d05
+#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
+#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
+#define T47 0x1fa27cf8
+#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
+#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
+#define T50 0x432aff97
+#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
+#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
+#define T53 0x655b59c3
+#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
+#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
+#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
+#define T57 0x6fa87e4f
+#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
+#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
+#define T60 0x4e0811a1
+#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
+#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
+#define T63 0x2ad7d2bb
+#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
+
+//gfd*
+static void md5_process(mir_md5_state_t *pms, const mir_md5_byte_t *data /*[64]*/)
+{
+ mir_md5_word_t
+ a = pms->abcd[0], b = pms->abcd[1],
+ c = pms->abcd[2], d = pms->abcd[3];
+ mir_md5_word_t t;
+ /* Define storage for little-endian or both types of CPUs. */
+ mir_md5_word_t xbuf[16];
+ const mir_md5_word_t *X;
+
+ {
+ /*
+ * Determine dynamically whether this is a big-endian or
+ * little-endian machine, since we can use a more efficient
+ * algorithm on the latter.
+ */
+ static const int w = 1;
+
+ if (*((const mir_md5_byte_t *)&w)) /* dynamic little-endian */
+ {
+ /*
+ * On little-endian machines, we can process properly aligned
+ * data without copying it.
+ */
+ if (!((data - (const mir_md5_byte_t *)0) & 3)) {
+ /* data are properly aligned */
+ X = (const mir_md5_word_t *)data;
+ } else {
+ /* not aligned */
+ memcpy(xbuf, data, 64);
+ X = xbuf;
+ }
+ }
+ else /* dynamic big-endian */
+ {
+ /*
+ * On big-endian machines, we must arrange the bytes in the
+ * right order.
+ */
+ const mir_md5_byte_t *xp = data;
+ int i;
+
+ X = xbuf; /* (dynamic only) */
+ for (i = 0; i < 16; ++i, xp += 4)
+ xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
+ }
+ }
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+ /* Round 1. */
+ /* Let [abcd k s i] denote the operation
+ a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define SET1(a, b, c, d, k, s, Ti)\
+ t = a + F(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET1(a, b, c, d, 0, 7, T1);
+ SET1(d, a, b, c, 1, 12, T2);
+ SET1(c, d, a, b, 2, 17, T3);
+ SET1(b, c, d, a, 3, 22, T4);
+ SET1(a, b, c, d, 4, 7, T5);
+ SET1(d, a, b, c, 5, 12, T6);
+ SET1(c, d, a, b, 6, 17, T7);
+ SET1(b, c, d, a, 7, 22, T8);
+ SET1(a, b, c, d, 8, 7, T9);
+ SET1(d, a, b, c, 9, 12, T10);
+ SET1(c, d, a, b, 10, 17, T11);
+ SET1(b, c, d, a, 11, 22, T12);
+ SET1(a, b, c, d, 12, 7, T13);
+ SET1(d, a, b, c, 13, 12, T14);
+ SET1(c, d, a, b, 14, 17, T15);
+ SET1(b, c, d, a, 15, 22, T16);
+
+ /* Round 2. */
+ /* Let [abcd k s i] denote the operation
+ a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
+#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define SET2(a, b, c, d, k, s, Ti)\
+ t = a + G(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET2(a, b, c, d, 1, 5, T17);
+ SET2(d, a, b, c, 6, 9, T18);
+ SET2(c, d, a, b, 11, 14, T19);
+ SET2(b, c, d, a, 0, 20, T20);
+ SET2(a, b, c, d, 5, 5, T21);
+ SET2(d, a, b, c, 10, 9, T22);
+ SET2(c, d, a, b, 15, 14, T23);
+ SET2(b, c, d, a, 4, 20, T24);
+ SET2(a, b, c, d, 9, 5, T25);
+ SET2(d, a, b, c, 14, 9, T26);
+ SET2(c, d, a, b, 3, 14, T27);
+ SET2(b, c, d, a, 8, 20, T28);
+ SET2(a, b, c, d, 13, 5, T29);
+ SET2(d, a, b, c, 2, 9, T30);
+ SET2(c, d, a, b, 7, 14, T31);
+ SET2(b, c, d, a, 12, 20, T32);
+
+ /* Round 3. */
+ /* Let [abcd k s t] denote the operation
+ a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define SET3(a, b, c, d, k, s, Ti)\
+ t = a + H(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET3(a, b, c, d, 5, 4, T33);
+ SET3(d, a, b, c, 8, 11, T34);
+ SET3(c, d, a, b, 11, 16, T35);
+ SET3(b, c, d, a, 14, 23, T36);
+ SET3(a, b, c, d, 1, 4, T37);
+ SET3(d, a, b, c, 4, 11, T38);
+ SET3(c, d, a, b, 7, 16, T39);
+ SET3(b, c, d, a, 10, 23, T40);
+ SET3(a, b, c, d, 13, 4, T41);
+ SET3(d, a, b, c, 0, 11, T42);
+ SET3(c, d, a, b, 3, 16, T43);
+ SET3(b, c, d, a, 6, 23, T44);
+ SET3(a, b, c, d, 9, 4, T45);
+ SET3(d, a, b, c, 12, 11, T46);
+ SET3(c, d, a, b, 15, 16, T47);
+ SET3(b, c, d, a, 2, 23, T48);
+
+ /* Round 4. */
+ /* Let [abcd k s t] denote the operation
+ a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+#define SET4(a, b, c, d, k, s, Ti)\
+ t = a + I(b,c,d) + X[k] + Ti;\
+ a = ROTATE_LEFT(t, s) + b
+ /* Do the following 16 operations. */
+ SET4(a, b, c, d, 0, 6, T49);
+ SET4(d, a, b, c, 7, 10, T50);
+ SET4(c, d, a, b, 14, 15, T51);
+ SET4(b, c, d, a, 5, 21, T52);
+ SET4(a, b, c, d, 12, 6, T53);
+ SET4(d, a, b, c, 3, 10, T54);
+ SET4(c, d, a, b, 10, 15, T55);
+ SET4(b, c, d, a, 1, 21, T56);
+ SET4(a, b, c, d, 8, 6, T57);
+ SET4(d, a, b, c, 15, 10, T58);
+ SET4(c, d, a, b, 6, 15, T59);
+ SET4(b, c, d, a, 13, 21, T60);
+ SET4(a, b, c, d, 4, 6, T61);
+ SET4(d, a, b, c, 11, 10, T62);
+ SET4(c, d, a, b, 2, 15, T63);
+ SET4(b, c, d, a, 9, 21, T64);
+
+ /* Then perform the following additions. (That is increment each
+ of the four registers by the value it had before this block
+ was started.) */
+ pms->abcd[0] += a;
+ pms->abcd[1] += b;
+ pms->abcd[2] += c;
+ pms->abcd[3] += d;
+}
+
+void md5_init(mir_md5_state_t *pms)
+{
+ pms->count[0] = pms->count[1] = 0;
+ pms->abcd[0] = 0x67452301;
+ pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
+ pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
+ pms->abcd[3] = 0x10325476;
+}
+
+void md5_append(mir_md5_state_t *pms, const mir_md5_byte_t *data, int nbytes)
+{
+ const mir_md5_byte_t *p = data;
+ int left = nbytes;
+ int offset = (pms->count[0] >> 3) & 63;
+ mir_md5_word_t nbits = (mir_md5_word_t)(nbytes << 3);
+
+ if (nbytes <= 0)
+ return;
+
+ /* Update the message length. */
+ pms->count[1] += nbytes >> 29;
+ pms->count[0] += nbits;
+ if (pms->count[0] < nbits)
+ pms->count[1]++;
+
+ /* Process an initial partial block. */
+ if (offset) {
+ int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
+
+ memcpy(pms->buf + offset, p, copy);
+ if (offset + copy < 64)
+ return;
+ p += copy;
+ left -= copy;
+ md5_process(pms, pms->buf);
+ }
+
+ /* Process full blocks. */
+ for (; left >= 64; p += 64, left -= 64)
+ md5_process(pms, p);
+
+ /* Process a final partial block. */
+ if (left)
+ memcpy(pms->buf, p, left);
+}
+
+void md5_finish(mir_md5_state_t *pms, mir_md5_byte_t digest[16])
+{
+ static const mir_md5_byte_t pad[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ mir_md5_byte_t data[8];
+ int i;
+
+ /* Save the length before padding. */
+ for (i = 0; i < 8; ++i)
+ data[i] = (mir_md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
+ /* Pad to 56 bytes mod 64. */
+ md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
+ /* Append the length. */
+ md5_append(pms, data, 8);
+ for (i = 0; i < 16; ++i)
+ digest[i] = (mir_md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
+}
+
+void md5_hash_string(const mir_md5_byte_t *data, int len, mir_md5_byte_t digest[16])
+{
+ mir_md5_state_t state;
+ md5_init(&state);
+ md5_append(&state, data, len);
+ md5_finish(&state, digest);
+}
+
+INT_PTR GetMD5Interface(WPARAM, LPARAM lParam)
+{
+ struct MD5_INTERFACE *md5i = (struct MD5_INTERFACE*) lParam;
+ if ( md5i == NULL )
+ return 1;
+ if ( md5i->cbSize != sizeof( struct MD5_INTERFACE ))
+ return 1;
+
+ md5i->md5_init = md5_init;
+ md5i->md5_append = md5_append;
+ md5i->md5_finish = md5_finish;
+ md5i->md5_hash = md5_hash_string;
+ return 0;
+}
diff --git a/src/modules/utils/openurl.cpp b/src/modules/utils/openurl.cpp
new file mode 100644
index 0000000000..ef66d89f8c
--- /dev/null
+++ b/src/modules/utils/openurl.cpp
@@ -0,0 +1,228 @@
+/*
+
+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 <ctype.h>
+
+#define DDEMESSAGETIMEOUT 1000
+#define WNDCLASS_DDEMSGWINDOW _T("MirandaDdeMsgWindow")
+
+struct DdeMsgWindowData {
+ int fAcked,fData;
+ HWND hwndDde;
+};
+
+static LRESULT CALLBACK DdeMessageWindow(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
+{
+ struct DdeMsgWindowData *dat;
+ ATOM hSzItem;
+ HGLOBAL hDdeData;
+
+ dat=(struct DdeMsgWindowData*)GetWindowLongPtr(hwnd,0);
+ switch(msg) {
+ case WM_DDE_ACK:
+ dat->fAcked=1;
+ dat->hwndDde=(HWND)wParam;
+ return 0;
+ case WM_DDE_DATA:
+ UnpackDDElParam(msg,lParam,(PUINT_PTR)&hDdeData,(PUINT_PTR)&hSzItem);
+ dat->fData=1;
+ if(hDdeData) {
+ DDEDATA *data;
+ int release;
+ data=(DDEDATA*)GlobalLock(hDdeData);
+ if(data->fAckReq) {
+ DDEACK ack={0};
+ PostMessage((HWND)wParam,WM_DDE_ACK,(WPARAM)hwnd,PackDDElParam(WM_DDE_ACK,*(PUINT)&ack,(UINT)hSzItem));
+ }
+ else GlobalDeleteAtom(hSzItem);
+ release=data->fRelease;
+ GlobalUnlock(hDdeData);
+ if(release) GlobalFree(hDdeData);
+ }
+ else GlobalDeleteAtom(hSzItem);
+ return 0;
+ }
+ return DefWindowProc(hwnd,msg,wParam,lParam);
+}
+
+static int DoDdeRequest(const char *szItemName,HWND hwndDdeMsg)
+{
+ ATOM hSzItemName;
+ DWORD timeoutTick,thisTick;
+ MSG msg;
+ struct DdeMsgWindowData *dat=(struct DdeMsgWindowData*)GetWindowLongPtr(hwndDdeMsg,0);
+
+ hSzItemName=GlobalAddAtomA(szItemName);
+ if(!PostMessage(dat->hwndDde,WM_DDE_REQUEST,(WPARAM)hwndDdeMsg,MAKELPARAM(CF_TEXT,hSzItemName))) {
+ GlobalDeleteAtom(hSzItemName);
+ return 1;
+ }
+ timeoutTick=GetTickCount()+5000;
+ dat->fData=0; dat->fAcked=0;
+ do {
+ if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ if(dat->fData || dat->fAcked) break;
+ thisTick=GetTickCount();
+ if(thisTick>timeoutTick) break;
+ } while(MsgWaitForMultipleObjects(0,NULL,FALSE,timeoutTick-thisTick,QS_ALLINPUT)==WAIT_OBJECT_0);
+
+ if(!dat->fData) {
+ GlobalDeleteAtom(hSzItemName);
+ return 1;
+ }
+ return 0;
+}
+
+//see Q160957 and http://developer.netscape.com/docs/manuals/communicator/DDE/index.htm
+static int DdeOpenUrl(const char *szBrowser,char *szUrl,int newWindow,HWND hwndDdeMsg)
+{
+ ATOM hSzBrowser,hSzTopic;
+ DWORD_PTR dwResult;
+ char *szItemName;
+ struct DdeMsgWindowData *dat=(struct DdeMsgWindowData*)GetWindowLongPtr(hwndDdeMsg,0);
+
+ hSzBrowser=GlobalAddAtomA(szBrowser);
+ hSzTopic=GlobalAddAtomA("WWW_OpenURL");
+ dat->fAcked=0;
+ if(!SendMessageTimeout(HWND_BROADCAST,WM_DDE_INITIATE,(WPARAM)hwndDdeMsg,MAKELPARAM(hSzBrowser,hSzTopic),SMTO_ABORTIFHUNG|SMTO_NORMAL,DDEMESSAGETIMEOUT,&dwResult)
+ || !dat->fAcked) {
+ GlobalDeleteAtom(hSzTopic);
+ GlobalDeleteAtom(hSzBrowser);
+ return 1;
+ }
+ szItemName=(char*)mir_alloc(lstrlenA(szUrl)+7);
+ wsprintfA(szItemName,"\"%s\",,%d",szUrl,newWindow?0:-1);
+ if(DoDdeRequest(szItemName,hwndDdeMsg)) {
+ mir_free(szItemName);
+ GlobalDeleteAtom(hSzTopic);
+ GlobalDeleteAtom(hSzBrowser);
+ return 1;
+ }
+ PostMessage(dat->hwndDde,WM_DDE_TERMINATE,(WPARAM)hwndDdeMsg,0);
+ GlobalDeleteAtom(hSzTopic);
+ GlobalDeleteAtom(hSzBrowser);
+ mir_free(szItemName);
+ return 0;
+}
+
+typedef struct {
+ char *szUrl;
+ int newWindow;
+} TOpenUrlInfo;
+
+static void OpenURLThread(void *arg)
+{
+ TOpenUrlInfo *hUrlInfo = (TOpenUrlInfo*)arg;
+ char *szResult;
+ HWND hwndDdeMsg;
+ struct DdeMsgWindowData msgWndData={0};
+ char *pszProtocol;
+ HKEY hKey;
+ char szSubkey[80];
+ char szCommandName[MAX_PATH];
+ DWORD dataLength;
+ int success=0;
+
+ if (!hUrlInfo->szUrl) return;
+ hwndDdeMsg=CreateWindow(WNDCLASS_DDEMSGWINDOW,_T(""),0,0,0,0,0,NULL,NULL,hMirandaInst,NULL);
+ SetWindowLongPtr(hwndDdeMsg,0,(LONG_PTR)&msgWndData);
+
+ if(!_strnicmp(hUrlInfo->szUrl,"ftp:",4) || !_strnicmp(hUrlInfo->szUrl,"ftp.",4)) pszProtocol="ftp";
+ if(!_strnicmp(hUrlInfo->szUrl,"mailto:",7)) pszProtocol="mailto";
+ if(!_strnicmp(hUrlInfo->szUrl,"news:",5)) pszProtocol="news";
+ else pszProtocol="http";
+ wsprintfA(szSubkey,"%s\\shell\\open\\command",pszProtocol);
+ if(RegOpenKeyExA(HKEY_CURRENT_USER,szSubkey,0,KEY_QUERY_VALUE,&hKey)==ERROR_SUCCESS
+ || RegOpenKeyExA(HKEY_CLASSES_ROOT,szSubkey,0,KEY_QUERY_VALUE,&hKey)==ERROR_SUCCESS) {
+ dataLength=SIZEOF(szCommandName);
+ if(RegQueryValueEx(hKey,NULL,NULL,NULL,(PBYTE)szCommandName,&dataLength)==ERROR_SUCCESS) {
+ _strlwr(szCommandName);
+ if(strstr(szCommandName,"mozilla") || strstr(szCommandName,"netscape"))
+ success=(DdeOpenUrl("mozilla",hUrlInfo->szUrl,hUrlInfo->newWindow,hwndDdeMsg)==0 || DdeOpenUrl("netscape",hUrlInfo->szUrl,hUrlInfo->newWindow,hwndDdeMsg)==0);
+ else if(strstr(szCommandName,"iexplore") || strstr(szCommandName,"msimn"))
+ success=0==DdeOpenUrl("iexplore",hUrlInfo->szUrl,hUrlInfo->newWindow,hwndDdeMsg);
+ else if(strstr(szCommandName,"opera"))
+ success=0==DdeOpenUrl("opera",hUrlInfo->szUrl,hUrlInfo->newWindow,hwndDdeMsg);
+ //opera's the default anyway
+ }
+ RegCloseKey(hKey);
+ }
+
+ DestroyWindow(hwndDdeMsg);
+ if(success) return;
+
+ //wack a protocol on it
+ if((isalpha(hUrlInfo->szUrl[0]) && hUrlInfo->szUrl[1]==':') || hUrlInfo->szUrl[0]=='\\') {
+ szResult=(char*)mir_alloc(lstrlenA(hUrlInfo->szUrl)+9);
+ wsprintfA(szResult,"file:///%s",hUrlInfo->szUrl);
+ }
+ else {
+ int i;
+ for(i=0;isalpha(hUrlInfo->szUrl[i]);i++);
+ if(hUrlInfo->szUrl[i]==':') szResult=mir_strdup(hUrlInfo->szUrl);
+ else {
+ if(!_strnicmp(hUrlInfo->szUrl,"ftp.",4)) {
+ szResult=(char*)mir_alloc(lstrlenA(hUrlInfo->szUrl)+7);
+ wsprintfA(szResult,"ftp://%s",hUrlInfo->szUrl);
+ }
+ else {
+ szResult=(char*)mir_alloc(lstrlenA(hUrlInfo->szUrl)+8);
+ wsprintfA(szResult,"http://%s",hUrlInfo->szUrl);
+ }
+ }
+ }
+ ShellExecuteA(NULL, "open", szResult, NULL, NULL, SW_SHOWDEFAULT);
+ mir_free(szResult);
+ mir_free(hUrlInfo->szUrl);
+ mir_free(hUrlInfo);
+ return;
+}
+
+static INT_PTR OpenURL(WPARAM wParam,LPARAM lParam) {
+ TOpenUrlInfo *hUrlInfo = (TOpenUrlInfo*)mir_alloc(sizeof(TOpenUrlInfo));
+ hUrlInfo->szUrl = (char*)lParam?mir_strdup((char*)lParam):NULL;
+ hUrlInfo->newWindow = (int)wParam;
+ forkthread(OpenURLThread, 0, (void*)hUrlInfo);
+ return 0;
+}
+
+int InitOpenUrl(void)
+{
+ WNDCLASS wcl;
+ wcl.lpfnWndProc=DdeMessageWindow;
+ wcl.cbClsExtra=0;
+ wcl.cbWndExtra=sizeof(void*);
+ wcl.hInstance=hMirandaInst;
+ wcl.hCursor=NULL;
+ wcl.lpszClassName=WNDCLASS_DDEMSGWINDOW;
+ wcl.hbrBackground=NULL;
+ wcl.hIcon=NULL;
+ wcl.lpszMenuName=NULL;
+ wcl.style=0;
+ RegisterClass(&wcl);
+ CreateServiceFunction(MS_UTILS_OPENURL,OpenURL);
+ return 0;
+}
diff --git a/src/modules/utils/path.cpp b/src/modules/utils/path.cpp
new file mode 100644
index 0000000000..80333a3075
--- /dev/null
+++ b/src/modules/utils/path.cpp
@@ -0,0 +1,600 @@
+/*
+
+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 "../database/profilemanager.h"
+#include "../srfile/file.h"
+
+extern TCHAR g_profileDir[MAX_PATH];
+
+static char szMirandaPath[MAX_PATH];
+static char szMirandaPathLower[MAX_PATH];
+
+static INT_PTR replaceVars(WPARAM wParam, LPARAM lParam);
+
+static int pathIsAbsolute(const char *path)
+{
+ if ( strlen(path) <= 2 )
+ return 0;
+ if ((path[1]==':'&&path[2]=='\\')||(path[0]=='\\'&&path[1]=='\\'))
+ return 1;
+ return 0;
+}
+
+static INT_PTR pathToRelative(WPARAM wParam, LPARAM lParam)
+{
+ char *pSrc = (char*)wParam;
+ char *pOut = (char*)lParam;
+ if (!pSrc||!strlen(pSrc)||strlen(pSrc)>MAX_PATH) return 0;
+ if (!pathIsAbsolute(pSrc)) {
+ mir_snprintf(pOut, MAX_PATH, "%s", pSrc);
+ return strlen(pOut);
+ }
+ else {
+ char szTmp[MAX_PATH];
+
+ mir_snprintf(szTmp, SIZEOF(szTmp), "%s", pSrc);
+ _strlwr(szTmp);
+ if (strstr(szTmp, szMirandaPathLower)) {
+ mir_snprintf(pOut, MAX_PATH, "%s", pSrc+strlen(szMirandaPathLower));
+ return strlen(pOut);
+ }
+ else {
+ mir_snprintf(pOut, MAX_PATH, "%s", pSrc);
+ return strlen(pOut);
+ }
+ }
+}
+
+int pathToAbsolute(const char *pSrc, char *pOut, char* base)
+{
+ if ( !pSrc || !strlen( pSrc ) || strlen( pSrc ) > MAX_PATH )
+ return 0;
+
+ if ( base == NULL )
+ base = szMirandaPath;
+
+ char buf[MAX_PATH];
+ if ( pSrc[0] < ' ')
+ return mir_snprintf( pOut, MAX_PATH, "%s", pSrc );
+ else if ( pathIsAbsolute( pSrc ))
+ return GetFullPathNameA(pSrc, MAX_PATH, pOut, NULL);
+ else if ( pSrc[0] != '\\' )
+ mir_snprintf( buf, MAX_PATH, "%s%s", base, pSrc );
+ else
+ mir_snprintf( buf, MAX_PATH, "%s%s", base, pSrc+1 );
+
+ return GetFullPathNameA(buf, MAX_PATH, pOut, NULL);
+}
+
+static INT_PTR pathToAbsolute(WPARAM wParam, LPARAM lParam)
+{
+ return pathToAbsolute((char*)wParam, (char*)lParam, szMirandaPath);
+}
+
+void CreatePathToFile( char* szFilePath )
+{
+ char* pszLastBackslash = strrchr( szFilePath, '\\' );
+ if ( pszLastBackslash == NULL )
+ return;
+
+ *pszLastBackslash = '\0';
+ CreateDirectoryTree( szFilePath );
+ *pszLastBackslash = '\\';
+}
+
+int CreateDirectoryTree( const char *szDir )
+{
+ DWORD dwAttributes;
+ char *pszLastBackslash, szTestDir[ MAX_PATH ];
+
+ lstrcpynA( szTestDir, szDir, SIZEOF( szTestDir ));
+ if (( dwAttributes = GetFileAttributesA( szTestDir )) != INVALID_FILE_ATTRIBUTES && ( dwAttributes & FILE_ATTRIBUTE_DIRECTORY ))
+ return 0;
+
+ pszLastBackslash = strrchr( szTestDir, '\\' );
+ if ( pszLastBackslash == NULL )
+ return 0;
+
+ *pszLastBackslash = '\0';
+ CreateDirectoryTree( szTestDir );
+ *pszLastBackslash = '\\';
+ return ( CreateDirectoryA( szTestDir, NULL ) == 0 ) ? GetLastError() : 0;
+}
+
+static INT_PTR createDirTree(WPARAM, LPARAM lParam)
+{
+ if ( lParam == 0 )
+ return 1;
+
+ return CreateDirectoryTree(( char* )lParam );
+}
+
+#ifdef _UNICODE
+static TCHAR szMirandaPathW[MAX_PATH];
+static TCHAR szMirandaPathWLower[MAX_PATH];
+
+static int pathIsAbsoluteW(const TCHAR *path)
+{
+ if ( lstrlen(path) <= 2 )
+ return 0;
+ if ((path[1]==':'&&path[2]=='\\')||(path[0]=='\\'&&path[1]=='\\'))
+ return 1;
+ return 0;
+}
+
+static INT_PTR pathToRelativeW(WPARAM wParam, LPARAM lParam)
+{
+ TCHAR *pSrc = (TCHAR*)wParam;
+ TCHAR *pOut = (TCHAR*)lParam;
+ if ( !pSrc || !lstrlen(pSrc) || lstrlen(pSrc) > MAX_PATH )
+ return 0;
+
+ if ( !pathIsAbsoluteW( pSrc ))
+ mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc);
+ else {
+ TCHAR szTmp[MAX_PATH];
+
+ mir_sntprintf(szTmp, SIZEOF(szTmp), _T("%s"), pSrc);
+ _tcslwr(szTmp);
+ if (_tcsstr(szTmp, szMirandaPathWLower))
+ mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc+lstrlen(szMirandaPathWLower));
+ else
+ mir_sntprintf(pOut, MAX_PATH, _T("%s"), pSrc);
+ }
+ return lstrlen(pOut);
+}
+
+int pathToAbsoluteW(const TCHAR *pSrc, TCHAR *pOut, TCHAR* base)
+{
+ if ( !pSrc || !wcslen(pSrc) || wcslen(pSrc) > MAX_PATH)
+ return 0;
+
+ if ( base == NULL )
+ base = szMirandaPathW;
+
+ TCHAR buf[MAX_PATH];
+ if ( pSrc[0] < ' ')
+ return mir_sntprintf( pOut, MAX_PATH, _T("%s"), pSrc );
+ else if ( pathIsAbsoluteW( pSrc ))
+ return GetFullPathName(pSrc, MAX_PATH, pOut, NULL);
+ else if ( pSrc[0] != '\\' )
+ mir_sntprintf( buf, MAX_PATH, _T("%s%s"), base, pSrc );
+ else
+ mir_sntprintf( buf, MAX_PATH, _T("%s%s"), base, pSrc+1 );
+
+ return GetFullPathName(buf, MAX_PATH, pOut, NULL);
+}
+
+static INT_PTR pathToAbsoluteW(WPARAM wParam, LPARAM lParam)
+{
+ return pathToAbsoluteW((TCHAR*)wParam, (TCHAR*)lParam, szMirandaPathW);
+}
+
+void CreatePathToFileW( WCHAR* wszFilePath )
+{
+ WCHAR* pszLastBackslash = wcsrchr( wszFilePath, '\\' );
+ if ( pszLastBackslash == NULL )
+ return;
+
+ *pszLastBackslash = '\0';
+ CreateDirectoryTreeW( wszFilePath );
+ *pszLastBackslash = '\\';
+}
+
+int CreateDirectoryTreeW( const WCHAR* szDir )
+{
+ DWORD dwAttributes;
+ WCHAR* pszLastBackslash, szTestDir[ MAX_PATH ];
+
+ lstrcpynW( szTestDir, szDir, SIZEOF( szTestDir ));
+ if (( dwAttributes = GetFileAttributesW( szTestDir )) != INVALID_FILE_ATTRIBUTES && ( dwAttributes & FILE_ATTRIBUTE_DIRECTORY ))
+ return 0;
+
+ pszLastBackslash = wcsrchr( szTestDir, '\\' );
+ if ( pszLastBackslash == NULL )
+ return 0;
+
+ *pszLastBackslash = '\0';
+ CreateDirectoryTreeW( szTestDir );
+ *pszLastBackslash = '\\';
+ return ( CreateDirectoryW( szTestDir, NULL ) == 0 ) ? GetLastError() : 0;
+}
+
+static INT_PTR createDirTreeW(WPARAM, LPARAM lParam)
+{
+ if ( lParam == 0 )
+ return 1;
+
+ return CreateDirectoryTreeW(( WCHAR* )lParam );
+}
+
+int InitPathUtilsW(void)
+{
+ GetModuleFileName(hMirandaInst, szMirandaPathW, SIZEOF(szMirandaPathW));
+ TCHAR *p = _tcsrchr(szMirandaPathW,'\\');
+ if ( p )
+ p[1] = 0;
+ mir_sntprintf(szMirandaPathWLower, SIZEOF(szMirandaPathWLower), _T("%s"), szMirandaPathW);
+ _tcslwr(szMirandaPathWLower);
+ CreateServiceFunction(MS_UTILS_PATHTORELATIVEW, pathToRelativeW);
+ CreateServiceFunction(MS_UTILS_PATHTOABSOLUTEW, pathToAbsoluteW);
+ CreateServiceFunction(MS_UTILS_CREATEDIRTREEW, createDirTreeW);
+ return 0;
+}
+#endif
+
+TCHAR *GetContactID(HANDLE hContact)
+{
+ TCHAR *theValue = {0};
+ char *szProto = ( char* )CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ if (DBGetContactSettingByte(hContact, szProto, "ChatRoom", 0) == 1) {
+ DBVARIANT dbv;
+ if (!DBGetContactSettingTString(hContact, szProto, "ChatRoomID", &dbv)) {
+ theValue = (TCHAR *)mir_tstrdup(dbv.ptszVal);
+ DBFreeVariant(&dbv);
+ return theValue;
+ } }
+ else {
+ CONTACTINFO ci = {0};
+ ci.cbSize = sizeof(ci);
+ ci.hContact = hContact;
+ ci.szProto = szProto;
+ ci.dwFlag = CNF_UNIQUEID | CNF_TCHAR;
+ if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) {
+ switch (ci.type) {
+ case CNFT_ASCIIZ:
+ return (TCHAR *)ci.pszVal;
+ break;
+ case CNFT_DWORD:
+ return _itot(ci.dVal, (TCHAR *)mir_alloc(sizeof(TCHAR)*32), 10);
+ break;
+ } } }
+ return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Variables parser
+
+#define XSTR(target, s) _xstrselect(target, s, _T(s))
+
+static __forceinline int _xcscmp(const char *s1, const char *s2) { return strcmp(s1, s2); }
+static __forceinline int _xcsncmp(const char *s1, const char *s2, size_t n) { return strncmp(s1, s2, n); }
+static __forceinline size_t _xcslen(const char *s1) { return strlen(s1); }
+static __forceinline char *_xcscpy(char *s1, const char *s2) { return strcpy(s1, s2); }
+static __forceinline char *_xcsncpy(char *s1, const char *s2, size_t n) { return strncpy(s1, s2, n); }
+static __forceinline char *_xstrselect(char *, char *s1, TCHAR *s2) { return s1; }
+static __forceinline char *_itox(char *, int a) { return itoa(a, (char *)mir_alloc(sizeof(char)*20), 10); }
+static __forceinline char *mir_a2x(char *, char *s) { return mir_strdup(s); }
+static __forceinline char *GetContactNickX(char *, HANDLE hContact)
+{
+ return mir_strdup((char *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, 0));
+}
+static __forceinline char *GetContactIDX(char *, HANDLE hContact)
+{
+ TCHAR *id = GetContactID(hContact);
+ char* res = mir_t2a(id);
+ mir_free(id);
+ return res;
+}
+static __forceinline char *GetEnvironmentVariableX(char *variable)
+{
+ char result[512];
+ if (GetEnvironmentVariableA(variable, result, SIZEOF(result)))
+ return mir_strdup(result);
+ return NULL;
+}
+static __forceinline char *GetProfileDirX( char* )
+{
+ return mir_t2a( g_profileDir );
+}
+static __forceinline char *SHGetSpecialFolderPathX(int iCSIDL, char* var)
+{
+ char result[512];
+ if (shGetSpecialFolderPathA && shGetSpecialFolderPathA(NULL, result, iCSIDL, FALSE))
+ return mir_strdup(result);
+ return NULL;
+}
+static __forceinline char *GetModulePathX(char *, HMODULE hModule)
+{
+ char result[MAX_PATH];
+ GetModuleFileNameA(hModule, result, sizeof(result));
+ char* str = strrchr(result, '\\');
+ if (str) *str = 0;
+ return mir_strdup(result);
+}
+static __forceinline char *GetUserNameX(char *)
+{
+ char result[128];
+ DWORD size = SIZEOF(result);
+ if (GetUserNameA(result, &size))
+ return mir_strdup(result);
+ return NULL;
+}
+static __forceinline char *GetProfileNameX(char *)
+{
+ TCHAR szProfileName[MAX_PATH];
+ _tcscpy( szProfileName, g_profileName );
+ TCHAR *pos = _tcsrchr(szProfileName, '.');
+ if ( lstrcmp( pos, _T(".dat")) == 0 )
+ *pos = 0;
+ return mir_t2a( szProfileName );
+}
+static __forceinline char *GetPathVarX(char *, int code)
+{
+ TCHAR szFullPath[MAX_PATH], szProfileName[MAX_PATH];
+ _tcscpy( szProfileName, g_profileName );
+ _tcslwr( szProfileName );
+ TCHAR *pos = _tcsrchr(szProfileName, '.');
+ if ( lstrcmp( pos, _T(".dat")) == 0 )
+ *pos = 0;
+
+ switch( code ) {
+ case 1:
+ mir_sntprintf(szFullPath, SIZEOF(szFullPath), _T("%s\\%s\\AvatarCache"), g_profileDir, szProfileName);
+ break;
+ case 2:
+ mir_sntprintf(szFullPath, SIZEOF(szFullPath), _T("%s\\%s\\Logs"), g_profileDir, szProfileName);
+ break;
+ case 3:
+ mir_sntprintf(szFullPath, SIZEOF(szFullPath), _T("%s\\%s"), g_profileDir, szProfileName);
+ break;
+ }
+ return makeFileName( szFullPath );
+}
+
+#ifdef _UNICODE
+static __forceinline int _xcscmp(const TCHAR *s1, const TCHAR *s2) { return _tcscmp(s1, s2); }
+static __forceinline int _xcsncmp(const TCHAR *s1, const TCHAR *s2, size_t n) { return _tcsncmp(s1, s2, n); }
+static __forceinline size_t _xcslen(const TCHAR *s1) { return _tcslen(s1); }
+static __forceinline TCHAR *_xcscpy(TCHAR *s1, const TCHAR *s2) { return _tcscpy(s1, s2); }
+static __forceinline TCHAR *_xcsncpy(TCHAR *s1, const TCHAR *s2, size_t n) { return _tcsncpy(s1, s2, n); }
+static __forceinline TCHAR *_xstrselect(TCHAR *, char *s1, TCHAR *s2) { return s2; }
+static __forceinline TCHAR *_itox(TCHAR *, int a) { return _itot(a, (TCHAR *)mir_alloc(sizeof(TCHAR)*20), 10); }
+static __forceinline TCHAR *mir_a2x(TCHAR *, char *s) { return mir_a2t(s); }
+static __forceinline TCHAR *GetContactNickX(TCHAR *, HANDLE hContact)
+{
+ return mir_tstrdup((TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR));
+}
+static __forceinline TCHAR *GetContactIDX(TCHAR *, HANDLE hContact)
+{
+ return GetContactID(hContact);
+}
+static __forceinline TCHAR *GetEnvironmentVariableX(TCHAR *variable)
+{
+ TCHAR result[512];
+ if (GetEnvironmentVariable(variable, result, SIZEOF(result)))
+ return mir_tstrdup(result);
+ return NULL;
+}
+static __forceinline TCHAR *SHGetSpecialFolderPathX(int iCSIDL, TCHAR* var)
+{
+ TCHAR result[512];
+ if (shGetSpecialFolderPath && shGetSpecialFolderPath(NULL, result, iCSIDL, FALSE))
+ return mir_tstrdup(result);
+ return NULL;
+}
+static __forceinline TCHAR *GetProfileDirX( TCHAR* )
+{
+ return mir_tstrdup( g_profileDir );
+}
+static __forceinline TCHAR *GetModulePathX(TCHAR *, HMODULE hModule)
+{
+ TCHAR result[MAX_PATH];
+ GetModuleFileName(hModule, result, SIZEOF(result));
+ TCHAR* str = _tcsrchr(result, '\\');
+ if (str) *str = 0;
+ return mir_tstrdup(result);
+}
+static __forceinline TCHAR *GetUserNameX(TCHAR *)
+{
+ TCHAR result[128];
+ DWORD size = SIZEOF(result);
+ if (GetUserName(result, &size))
+ return mir_tstrdup(result);
+ return NULL;
+}
+static __forceinline TCHAR *GetProfileNameX(TCHAR *)
+{
+ TCHAR szProfileName[MAX_PATH];
+ _tcscpy( szProfileName, g_profileName );
+ TCHAR *pos = _tcsrchr(szProfileName, '.');
+ if ( lstrcmp( pos, _T(".dat")) == 0 )
+ *pos = 0;
+ return mir_tstrdup( szProfileName );
+}
+static __forceinline TCHAR *GetPathVarX(TCHAR *, int code)
+{
+ TCHAR szFullPath[MAX_PATH], szProfileName[MAX_PATH];
+ _tcscpy( szProfileName, g_profileName );
+ TCHAR *pos = _tcsrchr(szProfileName, '.');
+ if ( lstrcmp( pos, _T(".dat")) == 0 )
+ *pos = 0;
+
+ switch( code ) {
+ case 1:
+ mir_sntprintf(szFullPath, SIZEOF(szFullPath), _T("%s\\%s\\AvatarCache"), g_profileDir, szProfileName);
+ break;
+ case 2:
+ mir_sntprintf(szFullPath, SIZEOF(szFullPath), _T("%s\\%s\\Logs"), g_profileDir, szProfileName);
+ break;
+ case 3:
+ mir_sntprintf(szFullPath, SIZEOF(szFullPath), _T("%s\\%s"), g_profileDir, szProfileName);
+ break;
+ }
+ return mir_tstrdup( szFullPath );
+}
+#endif
+
+template<typename XCHAR>
+XCHAR *GetInternalVariable(XCHAR *key, size_t keyLength, HANDLE hContact)
+{
+ XCHAR *theValue = NULL;
+ XCHAR *theKey = (XCHAR *)_alloca(sizeof(XCHAR) * (keyLength + 1));
+ _xcsncpy(theKey, key, keyLength);
+ theKey[keyLength] = 0;
+
+ if (hContact) {
+ if (!_xcscmp(theKey, XSTR(key, "nick")))
+ theValue = GetContactNickX(key, hContact);
+ else if (!_xcscmp(theKey, XSTR(key, "proto")))
+ theValue = mir_a2x(key, (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact,0));
+ else if (!_xcscmp(theKey, XSTR(key, "userid")))
+ theValue = GetContactIDX(key, hContact);
+ }
+
+ if (!theValue) {
+ if (!_xcscmp(theKey, XSTR(key, "miranda_path")))
+ theValue = GetModulePathX(key, NULL);
+ else if (!_xcscmp(theKey, XSTR(key, "appdata")))
+ theValue = SHGetSpecialFolderPathX(CSIDL_APPDATA, theKey);
+ else if (!_xcscmp(theKey, XSTR(key, "mydocuments")))
+ theValue = SHGetSpecialFolderPathX(CSIDL_PERSONAL, theKey);
+ else if (!_xcscmp(theKey, XSTR(key, "desktop")))
+ theValue = SHGetSpecialFolderPathX(CSIDL_DESKTOPDIRECTORY, theKey);
+ else if (!_xcscmp(theKey, XSTR(key, "miranda_profile")))
+ theValue = GetProfileDirX(key);
+ else if (!_xcscmp(theKey, XSTR(key, "miranda_profilename")))
+ theValue = GetProfileNameX(key);
+ else if (!_xcscmp(theKey, XSTR(key, "username")))
+ theValue = GetUserNameX(key);
+ else if (!_xcscmp(theKey, XSTR(key, "miranda_avatarcache")))
+ theValue = GetPathVarX(key,1);
+ else if (!_xcscmp(theKey, XSTR(key, "miranda_logpath")))
+ theValue = GetPathVarX(key,2);
+ else if (!_xcscmp(theKey, XSTR(key, "miranda_userdata")))
+ theValue = GetPathVarX(key,3);
+ }
+
+ if (!theValue)
+ theValue = GetEnvironmentVariableX(theKey);
+
+ return theValue;
+}
+
+template<typename XCHAR>
+XCHAR *GetVariableFromArray(REPLACEVARSARRAY *vars, XCHAR *key, size_t keyLength, HANDLE hContact, bool *bFree)
+{
+ *bFree = false;
+ for (REPLACEVARSARRAY *var = vars; var && var->lptzKey; ++var)
+ if ((_xcslen((XCHAR *)var->lptzKey) == keyLength) && !_xcsncmp(key, (XCHAR *)var->lptzKey, keyLength))
+ return (XCHAR *)var->lptzValue;
+
+ *bFree = true;
+ return GetInternalVariable(key, keyLength, hContact);
+}
+
+template<typename XCHAR>
+XCHAR *ReplaceVariables(XCHAR *str, REPLACEVARSDATA *data)
+{
+ if (!str)
+ return NULL;
+
+ XCHAR *p;
+ XCHAR *varStart = 0;
+ size_t length = 0;
+ bool bFree;
+
+ for (p = str; *p; ++p) {
+ if (*p == '%') {
+ if (varStart) {
+ if (p == varStart)
+ length++;
+ else if (XCHAR *value = GetVariableFromArray(data->variables, varStart, p-varStart, data->hContact, &bFree)) {
+ length += _xcslen(value);
+ if (bFree) mir_free(value);
+ }
+ else // variable not found
+ length += p-varStart+2;
+
+ varStart = 0;
+ }
+ else varStart = p+1;
+ }
+ else if (!varStart)
+ length++;
+ }
+
+ XCHAR *result = (XCHAR *)mir_alloc(sizeof(XCHAR) * (length + 1));
+ XCHAR *q = result;
+ varStart = NULL;
+
+ for (p = str; *p; ++p) {
+ if (*p == '%') {
+ if (varStart) {
+ if (p == varStart)
+ *q++ = '%';
+ else if (XCHAR *value = GetVariableFromArray(data->variables, varStart, p-varStart, data->hContact, &bFree)) {
+ _xcscpy(q, value);
+ q += _xcslen(value);
+ if (bFree) mir_free(value);
+ }
+ else {
+ // variable not found
+ _xcsncpy(q, varStart-1, p-varStart+2);
+ q += p-varStart+2;
+ }
+ varStart = 0;
+ }
+ else varStart = p+1;
+ }
+ else if (!varStart)
+ *q++ = *p;
+ }
+
+ *q = 0;
+
+ return result;
+}
+
+static INT_PTR replaceVars(WPARAM wParam, LPARAM lParam)
+{
+ REPLACEVARSDATA *data = (REPLACEVARSDATA *)lParam;
+ if (!(data->dwFlags & RVF_UNICODE))
+ return (INT_PTR)ReplaceVariables<char>((char *)wParam, data);
+
+#ifdef _UNICODE
+ return (INT_PTR)ReplaceVariables<WCHAR>((WCHAR *)wParam, data);
+#else
+ return NULL;
+#endif
+}
+
+int InitPathUtils(void)
+{
+ char *p = 0;
+ GetModuleFileNameA(hMirandaInst, szMirandaPath, SIZEOF(szMirandaPath));
+ p = strrchr(szMirandaPath,'\\');
+ if ( p )
+ p[1] = 0;
+ mir_snprintf(szMirandaPathLower, MAX_PATH, "%s", szMirandaPath);
+ _strlwr(szMirandaPathLower);
+ CreateServiceFunction(MS_UTILS_PATHTORELATIVE, pathToRelative);
+ CreateServiceFunction(MS_UTILS_PATHTOABSOLUTE, pathToAbsolute);
+ CreateServiceFunction(MS_UTILS_CREATEDIRTREE, createDirTree);
+ CreateServiceFunction(MS_UTILS_REPLACEVARS, replaceVars);
+#ifdef _UNICODE
+ return InitPathUtilsW();
+#else
+ return 0;
+#endif
+}
diff --git a/src/modules/utils/resizer.cpp b/src/modules/utils/resizer.cpp
new file mode 100644
index 0000000000..ea0daa057a
--- /dev/null
+++ b/src/modules/utils/resizer.cpp
@@ -0,0 +1,152 @@
+/*
+
+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"
+
+typedef struct {
+ DWORD helpID;
+ DWORD exStyle;
+ DWORD style;
+ short x;
+ short y;
+ short cx;
+ short cy;
+ DWORD id;
+} START_OF_DLGITEMTEMPLATEEX;
+
+typedef struct {
+ WORD dlgVer;
+ WORD signature;
+ DWORD helpID;
+ DWORD exStyle;
+ DWORD style;
+ WORD cDlgItems;
+ short x;
+ short y;
+ short cx;
+ short cy;
+} START_OF_DLGTEMPLATEEX;
+
+INT_PTR ResizeDialog(WPARAM, LPARAM lParam)
+{
+ UTILRESIZEDIALOG *urd=(UTILRESIZEDIALOG*)lParam;
+ HDWP hDwp;
+ int i;
+ DLGITEMTEMPLATE *pItem = NULL;
+ START_OF_DLGITEMTEMPLATEEX *pItemEx = NULL;
+ RECT rc;
+ PWORD pWord;
+ DLGTEMPLATE *pTemplate;
+ START_OF_DLGTEMPLATEEX *pTemplateEx;
+ UTILRESIZECONTROL urc;
+ int procResult;
+ int extendedDlg,itemCount;
+
+ if(urd==NULL||urd->cbSize!=sizeof(UTILRESIZEDIALOG)) return 1;
+ pTemplate=(DLGTEMPLATE*)LockResource(LoadResource(urd->hInstance,FindResourceA(urd->hInstance,urd->lpTemplate,MAKEINTRESOURCEA(5))));
+ pTemplateEx=(START_OF_DLGTEMPLATEEX*)pTemplate;
+ extendedDlg=pTemplateEx->signature==0xFFFF;
+ if(extendedDlg && pTemplateEx->dlgVer!=1)
+ return 1;
+
+ if(extendedDlg) pWord=(PWORD)(pTemplateEx+1);
+ else pWord=(PWORD)(pTemplate+1);
+ if(*pWord==0xFFFF) pWord+=2; else while(*pWord++); //menu
+ if(*pWord==0xFFFF) pWord+=2; else while(*pWord++); //class
+ while(*pWord++); //title
+ if(extendedDlg) {
+ if(pTemplateEx->style&DS_SETFONT) {
+ pWord+=3; //font size,weight,italic
+ while(*pWord++); //font name
+ }
+ }
+ else {
+ if(pTemplate->style&DS_SETFONT) {
+ pWord++; //font size
+ while(*pWord++); //font name
+ }
+ }
+
+ urc.cbSize=sizeof(UTILRESIZECONTROL);
+ rc.left=0; rc.top=0;
+ if(extendedDlg) {rc.right=pTemplateEx->cx; rc.bottom=pTemplateEx->cy;}
+ else {rc.right=pTemplate->cx; rc.bottom=pTemplate->cy;}
+ MapDialogRect(urd->hwndDlg,&rc);
+ urc.dlgOriginalSize.cx=rc.right; urc.dlgOriginalSize.cy=rc.bottom;
+ GetClientRect(urd->hwndDlg,&rc);
+ urc.dlgNewSize.cx=rc.right; urc.dlgNewSize.cy=rc.bottom;
+
+ if(extendedDlg) itemCount=pTemplateEx->cDlgItems;
+ else itemCount=pTemplate->cdit;
+ hDwp=BeginDeferWindowPos(itemCount);
+ for(i=0;i<itemCount;i++) {
+ if((UINT_PTR)pWord&2) pWord++; //dword align
+
+ if(extendedDlg) {
+ pItemEx=(START_OF_DLGITEMTEMPLATEEX*)pWord;
+ pWord=(PWORD)(pItemEx+1);
+
+ urc.wId=pItemEx->id;
+ urc.rcItem.left=pItemEx->x; urc.rcItem.top=pItemEx->y;
+ urc.rcItem.right=urc.rcItem.left+pItemEx->cx; urc.rcItem.bottom=urc.rcItem.top+pItemEx->cy;
+ }
+ else {
+ pItem=(DLGITEMTEMPLATE*)pWord;
+ pWord=(PWORD)(pItem+1);
+
+ urc.wId=pItem->id;
+ urc.rcItem.left=pItem->x; urc.rcItem.top=pItem->y;
+ urc.rcItem.right=urc.rcItem.left+pItem->cx; urc.rcItem.bottom=urc.rcItem.top+pItem->cy;
+ }
+ if(*pWord==0xFFFF) pWord+=2; else while(*pWord++); //menu
+ if(*pWord==0xFFFF) pWord+=2; else while(*pWord++); //class
+ pWord+=1+(1+*pWord)/2; //creation data
+
+ if(urc.wId==65535) continue; //using this breaks the dwp, so just ignore it
+
+ MapDialogRect(urd->hwndDlg,&urc.rcItem);
+ procResult=(urd->pfnResizer)(urd->hwndDlg,urd->lParam,&urc);
+ if(procResult&RD_ANCHORX_RIGHT) {
+ urc.rcItem.left+=urc.dlgNewSize.cx-urc.dlgOriginalSize.cx;
+ urc.rcItem.right+=urc.dlgNewSize.cx-urc.dlgOriginalSize.cx;
+ }
+ else if(procResult&RD_ANCHORX_WIDTH)
+ urc.rcItem.right+=urc.dlgNewSize.cx-urc.dlgOriginalSize.cx;
+ else if(procResult&RD_ANCHORX_CENTRE) {
+ urc.rcItem.left+=(urc.dlgNewSize.cx-urc.dlgOriginalSize.cx)/2;
+ urc.rcItem.right+=(urc.dlgNewSize.cx-urc.dlgOriginalSize.cx)/2;
+ }
+ if(procResult&RD_ANCHORY_BOTTOM) {
+ urc.rcItem.top+=urc.dlgNewSize.cy-urc.dlgOriginalSize.cy;
+ urc.rcItem.bottom+=urc.dlgNewSize.cy-urc.dlgOriginalSize.cy;
+ }
+ else if(procResult&RD_ANCHORY_HEIGHT)
+ urc.rcItem.bottom+=urc.dlgNewSize.cy-urc.dlgOriginalSize.cy;
+ else if(procResult&RD_ANCHORY_CENTRE) {
+ urc.rcItem.top+=(urc.dlgNewSize.cy-urc.dlgOriginalSize.cy)/2;
+ urc.rcItem.bottom+=(urc.dlgNewSize.cy-urc.dlgOriginalSize.cy)/2;
+ }
+ hDwp = DeferWindowPos(hDwp,GetDlgItem(urd->hwndDlg,extendedDlg?pItemEx->id:pItem->id),0,urc.rcItem.left,urc.rcItem.top,urc.rcItem.right-urc.rcItem.left,urc.rcItem.bottom-urc.rcItem.top,SWP_NOZORDER);
+ }
+ EndDeferWindowPos(hDwp);
+ return 0;
+}
diff --git a/src/modules/utils/sha1.cpp b/src/modules/utils/sha1.cpp
new file mode 100644
index 0000000000..c89a60ca46
--- /dev/null
+++ b/src/modules/utils/sha1.cpp
@@ -0,0 +1,175 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is SHA 180-1 Reference Implementation (Compact version).
+ *
+ * The Initial Developer of the Original Code is
+ * Paul Kocher of Cryptography Research.
+ * Portions created by the Initial Developer are Copyright (C) 1995-9
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "commonheaders.h"
+
+static void shaHashBlock(mir_sha1_ctx *ctx);
+
+void shaInit(mir_sha1_ctx *ctx) {
+ int i;
+
+ ctx->lenW = 0;
+ ctx->sizeHi = ctx->sizeLo = 0;
+
+ /* Initialize H with the magic constants (see FIPS180 for constants)
+ */
+ ctx->H[0] = 0x67452301L;
+ ctx->H[1] = 0xefcdab89L;
+ ctx->H[2] = 0x98badcfeL;
+ ctx->H[3] = 0x10325476L;
+ ctx->H[4] = 0xc3d2e1f0L;
+
+ for (i = 0; i < 80; i++)
+ ctx->W[i] = 0;
+}
+
+
+void shaUpdate(mir_sha1_ctx *ctx, mir_sha1_byte_t *dataIn, int len) {
+ int i;
+
+ /* Read the data into W and process blocks as they get full
+ */
+ for (i = 0; i < len; i++) {
+ ctx->W[ctx->lenW / 4] <<= 8;
+ ctx->W[ctx->lenW / 4] |= (unsigned long)dataIn[i];
+ if ((++ctx->lenW) % 64 == 0) {
+ shaHashBlock(ctx);
+ ctx->lenW = 0;
+ }
+ ctx->sizeLo += 8;
+ ctx->sizeHi += (ctx->sizeLo < 8);
+ }
+}
+
+
+void shaFinal(mir_sha1_ctx *ctx, mir_sha1_byte_t hashout[20]) {
+ unsigned char pad0x80 = 0x80;
+ unsigned char pad0x00 = 0x00;
+ unsigned char padlen[8];
+ int i;
+
+ /* Pad with a binary 1 (e.g. 0x80), then zeroes, then length
+ */
+ padlen[0] = (unsigned char)((ctx->sizeHi >> 24) & 255);
+ padlen[1] = (unsigned char)((ctx->sizeHi >> 16) & 255);
+ padlen[2] = (unsigned char)((ctx->sizeHi >> 8) & 255);
+ padlen[3] = (unsigned char)((ctx->sizeHi >> 0) & 255);
+ padlen[4] = (unsigned char)((ctx->sizeLo >> 24) & 255);
+ padlen[5] = (unsigned char)((ctx->sizeLo >> 16) & 255);
+ padlen[6] = (unsigned char)((ctx->sizeLo >> 8) & 255);
+ padlen[7] = (unsigned char)((ctx->sizeLo >> 0) & 255);
+ shaUpdate(ctx, &pad0x80, 1);
+ while (ctx->lenW != 56)
+ shaUpdate(ctx, &pad0x00, 1);
+ shaUpdate(ctx, padlen, 8);
+
+ /* Output hash
+ */
+ for (i = 0; i < 20; i++) {
+ hashout[i] = (unsigned char)(ctx->H[i / 4] >> 24);
+ ctx->H[i / 4] <<= 8;
+ }
+
+ /*
+ * Re-initialize the context (also zeroizes contents)
+ */
+ shaInit(ctx);
+}
+
+
+void shaBlock(mir_sha1_byte_t *dataIn, int len, mir_sha1_byte_t hashout[20]) {
+ mir_sha1_ctx ctx;
+
+ shaInit(&ctx);
+ shaUpdate(&ctx, dataIn, len);
+ shaFinal(&ctx, hashout);
+}
+
+
+#define SHA_ROTL(X,n) (((X) << (n)) | ((X) >> (32-(n))))
+
+static void shaHashBlock(mir_sha1_ctx *ctx) {
+ int t;
+ unsigned long A,B,C,D,E,TEMP;
+
+ for (t = 16; t <= 79; t++)
+ ctx->W[t] =
+ SHA_ROTL(ctx->W[t-3] ^ ctx->W[t-8] ^ ctx->W[t-14] ^ ctx->W[t-16], 1);
+
+ A = ctx->H[0];
+ B = ctx->H[1];
+ C = ctx->H[2];
+ D = ctx->H[3];
+ E = ctx->H[4];
+
+ for (t = 0; t <= 19; t++) {
+ TEMP = SHA_ROTL(A,5) + (((C^D)&B)^D) + E + ctx->W[t] + 0x5a827999L;
+ E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
+ }
+ for (t = 20; t <= 39; t++) {
+ TEMP = SHA_ROTL(A,5) + (B^C^D) + E + ctx->W[t] + 0x6ed9eba1L;
+ E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
+ }
+ for (t = 40; t <= 59; t++) {
+ TEMP = SHA_ROTL(A,5) + ((B&C)|(D&(B|C))) + E + ctx->W[t] + 0x8f1bbcdcL;
+ E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
+ }
+ for (t = 60; t <= 79; t++) {
+ TEMP = SHA_ROTL(A,5) + (B^C^D) + E + ctx->W[t] + 0xca62c1d6L;
+ E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
+ }
+
+ ctx->H[0] += A;
+ ctx->H[1] += B;
+ ctx->H[2] += C;
+ ctx->H[3] += D;
+ ctx->H[4] += E;
+}
+
+INT_PTR GetSHA1Interface(WPARAM, LPARAM lParam)
+{
+ struct SHA1_INTERFACE *sha1i = (struct SHA1_INTERFACE*) lParam;
+ if ( sha1i == NULL )
+ return 1;
+ if ( sha1i->cbSize != sizeof( struct SHA1_INTERFACE ))
+ return 1;
+
+ sha1i->sha1_init = shaInit;
+ sha1i->sha1_append = shaUpdate;
+ sha1i->sha1_finish = shaFinal;
+ sha1i->sha1_hash = shaBlock;
+ return 0;
+}
diff --git a/src/modules/utils/timeutils.cpp b/src/modules/utils/timeutils.cpp
new file mode 100644
index 0000000000..a0d4c02e46
--- /dev/null
+++ b/src/modules/utils/timeutils.cpp
@@ -0,0 +1,277 @@
+/*
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2010 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.
+
+implements services to handle location - based timezones, instead of
+simple UTC offsets.
+*/
+
+#include "commonheaders.h"
+
+//KB167296
+void UnixTimeToFileTime(time_t ts, LPFILETIME pft)
+{
+ unsigned __int64 ll = UInt32x32To64(ts, 10000000) + 116444736000000000i64;
+ pft->dwLowDateTime = (DWORD)ll;
+ pft->dwHighDateTime = ll >> 32;
+}
+
+time_t FileTimeToUnixTime(LPFILETIME pft)
+{
+ unsigned __int64 ll = (unsigned __int64)pft->dwHighDateTime << 32 | pft->dwLowDateTime;
+ ll -= 116444736000000000i64;
+ return (time_t)(ll / 10000000);
+}
+
+void FormatTime(const SYSTEMTIME *st, const TCHAR *szFormat, TCHAR *szDest, int cbDest)
+{
+ if (szDest == NULL || cbDest == 0) return;
+
+ TCHAR *pDest = szDest;
+ int destCharsLeft = cbDest - 1;
+
+ for (const TCHAR* pFormat = szFormat; *pFormat; ++pFormat)
+ {
+ DWORD fmt;
+ bool date, iso = false;
+ switch (*pFormat)
+ {
+ case 't':
+ fmt = TIME_NOSECONDS;
+ date = false;
+ break;
+
+ case 's':
+ fmt = 0;
+ date = false;
+ break;
+
+ case 'm':
+ fmt = TIME_NOMINUTESORSECONDS;
+ date = false;
+ break;
+
+ case 'd':
+ fmt = DATE_SHORTDATE;
+ date = true;
+ break;
+
+ case 'D':
+ fmt = DATE_LONGDATE;
+ date = true;
+ break;
+
+ case 'I':
+ iso = true;
+ break;
+
+ default:
+ if (destCharsLeft--)
+ *pDest++ = *pFormat;
+ continue;
+ }
+
+ TCHAR dateTimeStr[64];
+ int dateTimeStrLen;
+
+ if (iso)
+ {
+ dateTimeStrLen = mir_sntprintf(dateTimeStr, SIZEOF(dateTimeStr),
+ _T("%d-%02d-%02dT%02d:%02d:%02dZ"),
+ st->wYear, st->wMonth, st->wDay,
+ st->wHour, st->wMinute, st->wSecond) + 1;
+ }
+ else if (date)
+ dateTimeStrLen = GetDateFormat(LOCALE_USER_DEFAULT, fmt, st, NULL,
+ dateTimeStr, SIZEOF(dateTimeStr));
+ else
+ dateTimeStrLen = GetTimeFormat(LOCALE_USER_DEFAULT, fmt, st, NULL,
+ dateTimeStr, SIZEOF(dateTimeStr));
+
+ if (dateTimeStrLen) --dateTimeStrLen;
+ if (destCharsLeft < dateTimeStrLen) dateTimeStrLen = destCharsLeft;
+ memcpy(pDest, dateTimeStr, dateTimeStrLen * sizeof(dateTimeStr[0]));
+ destCharsLeft -= dateTimeStrLen;
+ pDest += dateTimeStrLen;
+ }
+ *pDest = 0;
+}
+
+
+#ifndef _UNICODE
+void ConvertToAbsolute (const SYSTEMTIME * pstLoc, const SYSTEMTIME * pstDst, SYSTEMTIME * pstDstAbs)
+{
+ static int iDays [12] = { 31, 28, 31, 30, 31, 30,
+ 31, 31, 30, 31, 30, 31 } ;
+ int iDay ;
+
+ // Set up the aboluste date structure except for wDay, which we must find
+
+ pstDstAbs->wYear = pstLoc->wYear ; // Notice from local date/time
+ pstDstAbs->wMonth = pstDst->wMonth ;
+ pstDstAbs->wDayOfWeek = pstDst->wDayOfWeek ;
+
+ pstDstAbs->wHour = pstDst->wHour ;
+ pstDstAbs->wMinute = pstDst->wMinute ;
+ pstDstAbs->wSecond = pstDst->wSecond ;
+ pstDstAbs->wMilliseconds = pstDst->wMilliseconds ;
+
+ // Fix the iDays array for leap years
+
+ if ((pstLoc->wYear % 4 == 0) && ((pstLoc->wYear % 100 != 0) ||
+ (pstLoc->wYear % 400 == 0)))
+ {
+ iDays[1] = 29 ;
+ }
+
+ // Find a day of the month that falls on the same
+ // day of the week as the transition.
+
+ // Suppose today is the 20th of the month (pstLoc->wDay = 20)
+ // Suppose today is a Wednesday (pstLoc->wDayOfWeek = 3)
+ // Suppose the transition occurs on a Friday (pstDst->wDayOfWeek = 5)
+ // Then iDay = 31, meaning that the 31st falls on a Friday
+ // (The 7 is this formula avoids negatives.)
+
+ iDay = pstLoc->wDay + pstDst->wDayOfWeek + 7 - pstLoc->wDayOfWeek ;
+
+ // Now shrink iDay to a value between 1 and 7.
+
+ iDay = (iDay - 1) % 7 + 1 ;
+
+ // Now iDay is a day of the month ranging from 1 to 7.
+ // Recall that the wDay field of the structure can range
+ // from 1 to 5, 1 meaning "first", 2 meaning "second",
+ // and 5 meaning "last".
+ // So, increase iDay so it's the proper day of the month.
+
+ iDay += 7 * (pstDst->wDay - 1) ;
+
+ // Could be that iDay overshot the end of the month, so
+ // fix it up using the number of days in each month
+
+ if (iDay > iDays[pstDst->wMonth - 1])
+ iDay -= 7 ;
+
+ // Assign that day to the structure.
+
+ pstDstAbs->wDay = iDay ;
+}
+
+BOOL LocalGreaterThanTransition (const SYSTEMTIME * pstLoc, const SYSTEMTIME * pstTran)
+{
+ FILETIME ftLoc, ftTran ;
+ LARGE_INTEGER liLoc, liTran ;
+ SYSTEMTIME stTranAbs ;
+
+ // Easy case: Just compare the two months
+
+ if (pstLoc->wMonth != pstTran->wMonth)
+ return (pstLoc->wMonth > pstTran->wMonth) ;
+
+ // Well, we're in a transition month. That requires a bit more work.
+
+ // Check if pstDst is in absolute or day-in-month format.
+ // (See documentation of TIME_ZONE_INFORMATION, StandardDate field.)
+
+ if (pstTran->wYear) // absolute format (haven't seen one yet!)
+ {
+ stTranAbs = * pstTran ;
+ }
+ else // day-in-month format
+ {
+ ConvertToAbsolute (pstLoc, pstTran, &stTranAbs) ;
+ }
+
+ // Now convert both date/time structures to large integers & compare
+
+ SystemTimeToFileTime (pstLoc, &ftLoc) ;
+ liLoc = * (LARGE_INTEGER *) (void *) &ftLoc ;
+
+ SystemTimeToFileTime (&stTranAbs, &ftTran) ;
+ liTran = * (LARGE_INTEGER *) (void *) &ftTran ;
+
+ return (liLoc.QuadPart > liTran.QuadPart) ;
+}
+
+BOOL MySystemTimeToTzSpecificLocalTime(LPTIME_ZONE_INFORMATION ptzi, LPSYSTEMTIME pstUtc, LPSYSTEMTIME pstLoc)
+{
+ // st is UTC
+
+ FILETIME ft ;
+ LARGE_INTEGER li ;
+ SYSTEMTIME stDst ;
+
+ if (IsWinVerNT())
+ return SystemTimeToTzSpecificLocalTime(ptzi, pstUtc, pstLoc);
+
+ // Convert time to a LARGE_INTEGER and subtract the bias
+
+ SystemTimeToFileTime (pstUtc, &ft) ;
+ li = * (LARGE_INTEGER *) (void *) &ft;
+ li.QuadPart -= (LONGLONG) 600000000 * ptzi->Bias ;
+
+ // Convert to a local date/time before application of daylight saving time.
+ // The local date/time must be used to determine when the conversion occurs.
+
+ ft = * (FILETIME *) (void *) &li ;
+ FileTimeToSystemTime (&ft, pstLoc) ;
+
+ // Find the time assuming Daylight Saving Time
+
+ li.QuadPart -= (LONGLONG) 600000000 * ptzi->DaylightBias ;
+ ft = * (FILETIME *) (void *) &li ;
+ FileTimeToSystemTime (&ft, &stDst) ;
+
+ // Now put li back the way it was
+
+ li.QuadPart += (LONGLONG) 600000000 * ptzi->DaylightBias ;
+
+ if (ptzi->StandardDate.wMonth) // ie, daylight savings time
+ {
+ // Northern hemisphere
+ if ((ptzi->DaylightDate.wMonth < ptzi->StandardDate.wMonth) &&
+
+ (stDst.wMonth >= pstLoc->wMonth) && // avoid the end of year problem
+
+ LocalGreaterThanTransition (pstLoc, &ptzi->DaylightDate) &&
+ !LocalGreaterThanTransition (&stDst, &ptzi->StandardDate))
+ {
+ li.QuadPart -= (LONGLONG) 600000000 * ptzi->DaylightBias ;
+ }
+ // Southern hemisphere
+
+ else if ((ptzi->StandardDate.wMonth < ptzi->DaylightDate.wMonth) &&
+ (!LocalGreaterThanTransition (&stDst, &ptzi->StandardDate) ||
+ LocalGreaterThanTransition (pstLoc, &ptzi->DaylightDate)))
+ {
+ li.QuadPart -= (LONGLONG) 600000000 * ptzi->DaylightBias ;
+ }
+ else
+ {
+ li.QuadPart -= (LONGLONG) 600000000 * ptzi->StandardBias ;
+ }
+ }
+
+ ft = * (FILETIME *) (void *) &li ;
+ FileTimeToSystemTime (&ft, pstLoc) ;
+ return TRUE ;
+}
+#endif
diff --git a/src/modules/utils/timezones.cpp b/src/modules/utils/timezones.cpp
new file mode 100644
index 0000000000..7d22cbec1e
--- /dev/null
+++ b/src/modules/utils/timezones.cpp
@@ -0,0 +1,662 @@
+/*
+Miranda IM: the free IM client for Microsoft* Windows*
+
+Copyright 2010 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.
+
+implements services to handle location - based timezones, instead of
+simple UTC offsets.
+*/
+
+#include <commonheaders.h>
+
+TIME_API tmi;
+
+#if _MSC_VER < 1500
+ typedef struct _TIME_DYNAMIC_ZONE_INFORMATION_T {
+ LONG Bias;
+ WCHAR StandardName[ 32 ];
+ SYSTEMTIME StandardDate;
+ LONG StandardBias;
+ WCHAR DaylightName[ 32 ];
+ SYSTEMTIME DaylightDate;
+ LONG DaylightBias;
+ WCHAR TimeZoneKeyName[ 128 ];
+ BOOLEAN DynamicDaylightTimeDisabled;
+ } DYNAMIC_TIME_ZONE_INFORMATION;
+#endif
+
+typedef DWORD (WINAPI *pfnGetDynamicTimeZoneInformation_t)(DYNAMIC_TIME_ZONE_INFORMATION *pdtzi);
+static pfnGetDynamicTimeZoneInformation_t pfnGetDynamicTimeZoneInformation;
+
+typedef HRESULT (WINAPI *pfnSHLoadIndirectString_t)(LPCWSTR pszSource, LPWSTR pszOutBuf, UINT cchOutBuf, void **ppvReserved);
+static pfnSHLoadIndirectString_t pfnSHLoadIndirectString;
+
+typedef LANGID (WINAPI *pfnGetUserDefaultUILanguage_t)(void);
+static pfnGetUserDefaultUILanguage_t pfnGetUserDefaultUILanguage;
+
+typedef LANGID (WINAPI *pfnGetSystemDefaultUILanguage_t)(void);
+static pfnGetSystemDefaultUILanguage_t pfnGetSystemDefaultUILanguage;
+
+typedef LPARAM (WINAPI *pfnSendMessageW_t)(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
+static pfnSendMessageW_t pfnSendMessageW;
+
+typedef struct _REG_TZI_FORMAT
+{
+ LONG Bias;
+ LONG StandardBias;
+ LONG DaylightBias;
+ SYSTEMTIME StandardDate;
+ SYSTEMTIME DaylightDate;
+} REG_TZI_FORMAT;
+
+#define MIM_TZ_DISPLAYLEN 128
+
+struct MIM_TIMEZONE
+{
+ unsigned hash;
+ int offset;
+
+ TCHAR tszName[MIM_TZ_NAMELEN]; // windows name for the time zone
+ wchar_t szDisplay[MIM_TZ_DISPLAYLEN]; // more descriptive display name (that's what usually appears in dialogs)
+ // every hour should be sufficient.
+ TIME_ZONE_INFORMATION tzi;
+
+ static int compareBias(const MIM_TIMEZONE* p1, const MIM_TIMEZONE* p2)
+ { return p2->tzi.Bias - p1->tzi.Bias; }
+};
+
+typedef struct
+{
+ DWORD timestamp; // last time updated
+ MIM_TIMEZONE myTZ; // set to my own timezone
+} TZ_INT_INFO;
+
+static TZ_INT_INFO myInfo;
+bool muiInstalled;
+
+static OBJLIST<MIM_TIMEZONE> g_timezones(55, NumericKeySortT);
+static LIST<MIM_TIMEZONE> g_timezonesBias(55, MIM_TIMEZONE::compareBias);
+
+void FormatTime (const SYSTEMTIME *st, const TCHAR *szFormat, TCHAR *szDest, int cbDest);
+void UnixTimeToFileTime(time_t ts, LPFILETIME pft);
+time_t FileTimeToUnixTime(LPFILETIME pft);
+
+#ifdef _UNICODE
+#define fnSystemTimeToTzSpecificLocalTime SystemTimeToTzSpecificLocalTime
+#else
+BOOL MySystemTimeToTzSpecificLocalTime(LPTIME_ZONE_INFORMATION ptzi, LPSYSTEMTIME pstUtc, LPSYSTEMTIME pstLoc);
+#define fnSystemTimeToTzSpecificLocalTime MySystemTimeToTzSpecificLocalTime
+#endif
+
+
+static int timeapiGetTimeZoneTime(HANDLE hTZ, SYSTEMTIME *st)
+{
+ if (st == NULL) return 1;
+
+ MIM_TIMEZONE *tz = (MIM_TIMEZONE*)hTZ;
+ if (tz == UTC_TIME_HANDLE)
+ GetSystemTime(st);
+ else if (tz && tz != &myInfo.myTZ)
+ {
+ SYSTEMTIME sto;
+ GetSystemTime(&sto);
+ return !fnSystemTimeToTzSpecificLocalTime(&tz->tzi, &sto, st);
+ }
+ else
+ GetLocalTime(st);
+
+ return 0;
+}
+
+static LPCTSTR timeapiGetTzName(HANDLE hTZ)
+{
+ MIM_TIMEZONE *tz = (MIM_TIMEZONE*)hTZ;
+ if (tz == NULL)
+ return myInfo.myTZ.tszName;
+ else if (tz == UTC_TIME_HANDLE)
+ return _T("UTC");
+
+ return tz->tszName;
+}
+
+static void CalcTsOffset(MIM_TIMEZONE *tz)
+{
+ SYSTEMTIME st, stl;
+ GetSystemTime(&st);
+
+ FILETIME ft;
+ SystemTimeToFileTime(&st, &ft);
+ time_t ts1 = FileTimeToUnixTime(&ft);
+
+ if (!fnSystemTimeToTzSpecificLocalTime(&tz->tzi, &st, &stl))
+ return;
+
+ SystemTimeToFileTime(&stl, &ft);
+ time_t ts2 = FileTimeToUnixTime(&ft);
+
+ tz->offset = ts2 - ts1;
+}
+
+static bool IsSameTime(MIM_TIMEZONE *tz)
+{
+ SYSTEMTIME st, stl;
+
+ if (tz == &myInfo.myTZ)
+ return true;
+
+ timeapiGetTimeZoneTime(tz, &stl);
+ timeapiGetTimeZoneTime(NULL, &st);
+
+ return st.wHour == stl.wHour && st.wMinute == stl.wMinute;
+}
+
+static HANDLE timeapiGetInfoByName(LPCTSTR tszName, DWORD dwFlags)
+{
+ if (tszName == NULL)
+ return (dwFlags & (TZF_DIFONLY | TZF_KNOWNONLY)) ? NULL : &myInfo.myTZ;
+
+ if (_tcscmp(myInfo.myTZ.tszName, tszName) == 0)
+ return (dwFlags & TZF_DIFONLY) ? NULL : &myInfo.myTZ;
+
+ MIM_TIMEZONE tzsearch;
+ tzsearch.hash = hashstr(tszName);
+
+ MIM_TIMEZONE *tz = g_timezones.find(&tzsearch);
+ if (tz == NULL)
+ return (dwFlags & (TZF_DIFONLY | TZF_KNOWNONLY)) ? NULL : &myInfo.myTZ;
+
+ if (dwFlags & TZF_DIFONLY)
+ return IsSameTime(tz) ? NULL : tz;
+
+ return tz;
+}
+
+static HANDLE timeapiGetInfoByContact(HANDLE hContact, DWORD dwFlags)
+{
+ if (hContact == NULL)
+ return (dwFlags & (TZF_DIFONLY | TZF_KNOWNONLY)) ? NULL : &myInfo.myTZ;
+
+ DBVARIANT dbv;
+ if (!DBGetContactSettingTString(hContact, "UserInfo", "TzName", &dbv))
+ {
+ HANDLE res = timeapiGetInfoByName(dbv.ptszVal, dwFlags);
+ DBFreeVariant(&dbv);
+ if (res) return res;
+ }
+
+ signed char timezone = (signed char)DBGetContactSettingByte(hContact, "UserInfo", "Timezone", -1);
+ if (timezone == -1)
+ {
+ char* szProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ if (!DBGetContactSettingTString(hContact, szProto, "TzName", &dbv))
+ {
+ HANDLE res = timeapiGetInfoByName(dbv.ptszVal, dwFlags);
+ DBFreeVariant(&dbv);
+ if (res) return res;
+ }
+ timezone = (signed char)DBGetContactSettingByte(hContact, szProto, "Timezone", -1);
+ }
+
+ if (timezone != -1)
+ {
+ MIM_TIMEZONE tzsearch;
+ tzsearch.tzi.Bias = timezone * 30;
+ if (myInfo.myTZ.tzi.Bias == tzsearch.tzi.Bias)
+ {
+ if (dwFlags & TZF_DIFONLY) return NULL;
+ return &myInfo.myTZ;
+ }
+
+ int i = g_timezonesBias.getIndex(&tzsearch);
+ while (i >= 0 && g_timezonesBias[i]->tzi.Bias == tzsearch.tzi.Bias) --i;
+
+ int delta = LONG_MAX;
+ for (int j = ++i; j < g_timezonesBias.getCount() && g_timezonesBias[j]->tzi.Bias == tzsearch.tzi.Bias; ++j)
+ {
+ int delta1 = abs(g_timezonesBias[j]->tzi.DaylightDate.wMonth - myInfo.myTZ.tzi.DaylightDate.wMonth);
+ if (delta1 <= delta)
+ {
+ delta = delta1;
+ i = j;
+ }
+ }
+
+ if (i >= 0)
+ {
+ MIM_TIMEZONE *tz = g_timezonesBias[i];
+ return ((dwFlags & TZF_DIFONLY) && IsSameTime(tz)) ? NULL : tz;
+ }
+ }
+ return (dwFlags & (TZF_DIFONLY | TZF_KNOWNONLY)) ? NULL : &myInfo.myTZ;
+}
+
+static void timeapiSetInfoByContact(HANDLE hContact, HANDLE hTZ)
+{
+ MIM_TIMEZONE *tz = (MIM_TIMEZONE*)hTZ;
+
+ if (hContact == NULL) return;
+
+ if (tz)
+ {
+ DBWriteContactSettingTString(hContact, "UserInfo", "TzName", tz->tszName);
+ DBWriteContactSettingByte(hContact, "UserInfo", "Timezone", (char)((tz->tzi.Bias + tz->tzi.StandardBias) / 30));
+ }
+ else
+ {
+ DBDeleteContactSetting(hContact, "UserInfo", "TzName");
+ DBDeleteContactSetting(hContact, "UserInfo", "Timezone");
+ }
+}
+
+static int timeapiPrintDateTime(HANDLE hTZ, LPCTSTR szFormat, LPTSTR szDest, int cbDest, DWORD dwFlags)
+{
+ MIM_TIMEZONE *tz = (MIM_TIMEZONE*)hTZ;
+ if (tz == NULL && (dwFlags & (TZF_DIFONLY | TZF_KNOWNONLY)))
+ return 1;
+
+ SYSTEMTIME st;
+ if (timeapiGetTimeZoneTime(tz, &st))
+ return 1;
+
+ FormatTime(&st, szFormat, szDest, cbDest);
+
+ return 0;
+}
+
+static int timeapiPrintTimeStamp(HANDLE hTZ, time_t ts, LPCTSTR szFormat, LPTSTR szDest, int cbDest, DWORD dwFlags)
+{
+ MIM_TIMEZONE *tz = (MIM_TIMEZONE*)hTZ;
+ if (tz == NULL && (dwFlags & (TZF_DIFONLY | TZF_KNOWNONLY)))
+ return 1;
+
+ FILETIME ft;
+
+ if (tz == NULL) tz = &myInfo.myTZ;
+ if (tz == NULL)
+ {
+ FILETIME lft;
+
+ UnixTimeToFileTime(ts, &lft);
+ FileTimeToLocalFileTime(&lft, &ft);
+ }
+ else if (tz == UTC_TIME_HANDLE)
+ UnixTimeToFileTime(ts, &ft);
+ else
+ {
+ if (tz->offset == INT_MIN)
+ CalcTsOffset(tz);
+
+ UnixTimeToFileTime(ts + tz->offset, &ft);
+ }
+
+ SYSTEMTIME st;
+ FileTimeToSystemTime(&ft, &st);
+
+ FormatTime(&st, szFormat, szDest, cbDest);
+
+ return 0;
+}
+
+static LPTIME_ZONE_INFORMATION timeapiGetTzi(HANDLE hTZ)
+{
+ MIM_TIMEZONE *tz = (MIM_TIMEZONE*)hTZ;
+ return tz ? &tz->tzi : &myInfo.myTZ.tzi;
+}
+
+
+static time_t timeapiTimeStampToTimeZoneTimeStamp(HANDLE hTZ, time_t ts)
+{
+ MIM_TIMEZONE *tz = (MIM_TIMEZONE*)hTZ;
+
+ if (tz == NULL) tz = &myInfo.myTZ;
+ if (tz == NULL)
+ {
+ FILETIME ft, lft;
+
+ UnixTimeToFileTime(ts, &ft);
+ FileTimeToLocalFileTime(&ft, &lft);
+ return FileTimeToUnixTime(&lft);
+ }
+ else if (tz == UTC_TIME_HANDLE)
+ return ts;
+
+ if (tz->offset == INT_MIN)
+ CalcTsOffset(tz);
+
+ return ts + tz->offset;
+}
+
+typedef struct
+{
+ UINT addStr, getSel, setSel, getData, setData;
+} ListMessages;
+
+static const ListMessages lbMessages =
+{ LB_ADDSTRING, LB_GETCURSEL, LB_SETCURSEL, LB_GETITEMDATA, LB_SETITEMDATA };
+
+static const ListMessages cbMessages =
+{ CB_ADDSTRING, CB_GETCURSEL, CB_SETCURSEL, CB_GETITEMDATA, CB_SETITEMDATA };
+
+static const ListMessages *GetListMessages(HWND hWnd, DWORD dwFlags)
+{
+ if (!(dwFlags & (TZF_PLF_CB | TZF_PLF_LB)))
+ {
+ TCHAR tszClassName[128];
+ GetClassName(hWnd, tszClassName, SIZEOF(tszClassName));
+ if (!_tcsicmp(tszClassName, _T("COMBOBOX")))
+ dwFlags |= TZF_PLF_CB;
+ else if(!_tcsicmp(tszClassName, _T("LISTBOX")))
+ dwFlags |= TZF_PLF_LB;
+ }
+ if (dwFlags & TZF_PLF_CB)
+ return & cbMessages;
+ else if(dwFlags & TZF_PLF_LB)
+ return & lbMessages;
+ else
+ return NULL;
+}
+
+
+static int timeapiSelectListItem(HANDLE hContact, HWND hWnd, DWORD dwFlags)
+{
+ if (hWnd == NULL) // nothing to do
+ return -1;
+
+ const ListMessages *lstMsg = GetListMessages(hWnd, dwFlags);
+ if (lstMsg == NULL) return -1;
+
+ int iSelection = 0;
+ if (hContact)
+ {
+ DBVARIANT dbv;
+ if (!DBGetContactSettingTString(hContact, "UserInfo", "TzName", &dbv))
+ {
+ unsigned hash = hashstr(dbv.ptszVal);
+ for (int i = 0; i < g_timezonesBias.getCount(); ++i)
+ {
+ if (hash == g_timezonesBias[i]->hash)
+ {
+ iSelection = i + 1;
+ break;
+ }
+ }
+ DBFreeVariant(&dbv);
+ }
+ }
+
+ SendMessage(hWnd, lstMsg->setSel, iSelection, 0);
+ return iSelection;
+}
+
+
+static int timeapiPrepareList(HANDLE hContact, HWND hWnd, DWORD dwFlags)
+{
+ if (hWnd == NULL) // nothing to do
+ return 0;
+
+ const ListMessages *lstMsg = GetListMessages(hWnd, dwFlags);
+ if (lstMsg == NULL) return 0;
+
+ SendMessage(hWnd, lstMsg->addStr, 0, (LPARAM)TranslateT("<unspecified>"));
+
+ for (int i = 0; i < g_timezonesBias.getCount(); ++i)
+ {
+ MIM_TIMEZONE *tz = g_timezonesBias[i];
+
+ if (pfnSendMessageW)
+ pfnSendMessageW(hWnd, lstMsg->addStr, 0, (LPARAM)tz->szDisplay);
+ else
+ SendMessage(hWnd, lstMsg->addStr, 0, (LPARAM)StrConvTu(tz->szDisplay));
+
+ SendMessage(hWnd, lstMsg->setData, i + 1, (LPARAM)tz);
+ }
+
+ return timeapiSelectListItem(hContact, hWnd, dwFlags);
+}
+
+
+static void timeapiStoreListResult(HANDLE hContact, HWND hWnd, DWORD dwFlags)
+{
+ const ListMessages *lstMsg = GetListMessages(hWnd, dwFlags);
+ if (lstMsg == NULL) return;
+
+ LRESULT offset = SendMessage(hWnd, lstMsg->getSel, 0, 0);
+ if (offset > 0)
+ {
+ MIM_TIMEZONE *tz = (MIM_TIMEZONE*)SendMessage(hWnd, lstMsg->getData, offset, 0);
+ if ((INT_PTR)tz != CB_ERR && tz != NULL)
+ timeapiSetInfoByContact(hContact, tz);
+ }
+ else
+ timeapiSetInfoByContact(hContact, NULL);
+}
+
+
+static INT_PTR GetTimeApi( WPARAM, LPARAM lParam )
+{
+ TIME_API* tmi = (TIME_API*)lParam;
+ if (tmi == NULL)
+ return FALSE;
+
+ if (tmi->cbSize != sizeof(TIME_API))
+ return FALSE;
+
+ tmi->createByName = timeapiGetInfoByName;
+ tmi->createByContact = timeapiGetInfoByContact;
+ tmi->storeByContact = timeapiSetInfoByContact;
+
+ tmi->printDateTime = timeapiPrintDateTime;
+ tmi->printTimeStamp = timeapiPrintTimeStamp;
+
+ tmi->prepareList = timeapiPrepareList;
+ tmi->selectListItem = timeapiSelectListItem;
+ tmi->storeListResults = timeapiStoreListResult;
+
+ tmi->getTimeZoneTime = timeapiGetTimeZoneTime;
+ tmi->timeStampToTimeZoneTimeStamp = timeapiTimeStampToTimeZoneTimeStamp;
+ tmi->getTzi = timeapiGetTzi;
+ tmi->getTzName = timeapiGetTzName;
+
+ return TRUE;
+}
+
+static INT_PTR TimestampToLocal(WPARAM wParam, LPARAM)
+{
+ return timeapiTimeStampToTimeZoneTimeStamp(NULL, (time_t)wParam);
+}
+
+static INT_PTR TimestampToStringT(WPARAM wParam, LPARAM lParam)
+{
+ DBTIMETOSTRINGT *tts = (DBTIMETOSTRINGT*)lParam;
+ if (tts == NULL) return 0;
+
+ timeapiPrintTimeStamp(NULL, (time_t)wParam, tts->szFormat, tts->szDest, tts->cbDest, 0);
+ return 0;
+}
+
+#ifdef _UNICODE
+static INT_PTR TimestampToStringA(WPARAM wParam, LPARAM lParam)
+{
+ DBTIMETOSTRING *tts = (DBTIMETOSTRING*)lParam;
+ if (tts == NULL) return 0;
+
+ TCHAR *szDest = (TCHAR*)alloca(tts->cbDest);
+ timeapiPrintTimeStamp(NULL, (time_t)wParam, StrConvT(tts->szFormat), szDest, tts->cbDest, 0);
+ WideCharToMultiByte(CP_ACP, 0, szDest, -1, tts->szDest, tts->cbDest, NULL, NULL);
+ return 0;
+}
+#endif
+
+void GetLocalizedString(HKEY hSubKey, const TCHAR *szName, wchar_t *szBuf, DWORD cbLen)
+{
+ szBuf[0] = 0;
+ if (muiInstalled)
+ {
+ TCHAR tszTempBuf[MIM_TZ_NAMELEN], tszName[30];
+ mir_sntprintf(tszName, SIZEOF(tszName), _T("MUI_%s"), szName);
+ DWORD dwLength = cbLen * sizeof(TCHAR);
+ if (ERROR_SUCCESS == RegQueryValueEx(hSubKey, tszName, NULL, NULL, (unsigned char *)tszTempBuf, &dwLength))
+ {
+ tszTempBuf[min(dwLength / sizeof(TCHAR), cbLen - 1)] = 0;
+ if (pfnSHLoadIndirectString)
+ pfnSHLoadIndirectString(StrConvU(tszTempBuf), szBuf, cbLen, NULL);
+ }
+ }
+ if (szBuf[0] == 0)
+ {
+ DWORD dwLength = cbLen * sizeof(wchar_t);
+
+#ifdef _UNICODE
+ RegQueryValueEx(hSubKey, szName, NULL, NULL, (unsigned char *)szBuf, &dwLength);
+ szBuf[min(dwLength / sizeof(TCHAR), cbLen - 1)] = 0;
+#else
+ char* szBufP = (char*)alloca(dwLength);
+ RegQueryValueEx(hSubKey, szName, NULL, NULL, (unsigned char *)szBufP, &dwLength);
+ szBufP[min(dwLength, cbLen * sizeof(wchar_t) - 1)] = 0;
+ MultiByteToWideChar(CP_ACP, 0, szBufP, -1, szBuf, cbLen);
+#endif
+ }
+}
+
+void RecalculateTime(void)
+{
+ GetTimeZoneInformation(&myInfo.myTZ.tzi);
+ myInfo.timestamp = time(NULL);
+ myInfo.myTZ.offset = INT_MIN;
+
+ bool found = false;
+ DYNAMIC_TIME_ZONE_INFORMATION dtzi;
+
+ if (pfnGetDynamicTimeZoneInformation && pfnGetDynamicTimeZoneInformation(&dtzi) != TIME_ZONE_ID_INVALID)
+ {
+ TCHAR *myTzKey = mir_u2t(dtzi.TimeZoneKeyName);
+ _tcscpy(myInfo.myTZ.tszName, myTzKey);
+ mir_free(myTzKey);
+ found = true;
+ }
+
+ for (int i = 0; i < g_timezones.getCount(); ++i)
+ {
+ MIM_TIMEZONE &tz = g_timezones[i];
+ if (tz.offset != INT_MIN) tz.offset = INT_MIN;
+
+ if (!found)
+ {
+ if (!wcscmp(tz.tzi.StandardName, myInfo.myTZ.tzi.StandardName) ||
+ !wcscmp(tz.tzi.DaylightName, myInfo.myTZ.tzi.DaylightName))
+ {
+ _tcscpy(myInfo.myTZ.tszName, tz.tszName);
+ found = true;
+ }
+ }
+ }
+}
+
+void InitTimeZones(void)
+{
+ REG_TZI_FORMAT tzi;
+ HKEY hKey;
+
+ const TCHAR *tszKey = IsWinVerNT() ?
+ _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones") :
+ _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Time Zones");
+
+ /*
+ * use GetDynamicTimeZoneInformation() on Vista+ - this will return a structure with
+ * the registry key name, so finding our own time zone later will be MUCH easier for
+ * localized systems or systems with a MUI pack installed
+ */
+ if (IsWinVerVistaPlus())
+ pfnGetDynamicTimeZoneInformation = (pfnGetDynamicTimeZoneInformation_t)GetProcAddress(GetModuleHandle(_T("kernel32")), "GetDynamicTimeZoneInformation");
+
+ if (IsWinVer2000Plus())
+ {
+ pfnSHLoadIndirectString = (pfnSHLoadIndirectString_t)GetProcAddress(GetModuleHandle(_T("shlwapi")), "SHLoadIndirectString");
+ pfnGetSystemDefaultUILanguage = (pfnGetSystemDefaultUILanguage_t)GetProcAddress(GetModuleHandle(_T("kernel32")), "GetSystemDefaultUILanguage");
+ pfnGetUserDefaultUILanguage = (pfnGetUserDefaultUILanguage_t)GetProcAddress(GetModuleHandle(_T("kernel32")), "GetUserDefaultUILanguage");
+ muiInstalled = pfnSHLoadIndirectString && pfnGetSystemDefaultUILanguage() != pfnGetUserDefaultUILanguage();
+ }
+
+ pfnSendMessageW = (pfnSendMessageW_t)GetProcAddress(GetModuleHandle(_T("user32")), "SendMessageW");
+
+ if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, tszKey, 0, KEY_ENUMERATE_SUB_KEYS, &hKey))
+ {
+ DWORD dwIndex = 0;
+ HKEY hSubKey;
+ TCHAR tszName[MIM_TZ_NAMELEN];
+
+ DWORD dwSize = SIZEOF(tszName);
+ while (ERROR_NO_MORE_ITEMS != RegEnumKeyEx(hKey, dwIndex++, tszName, &dwSize, NULL, NULL, 0, NULL))
+ {
+ if (ERROR_SUCCESS == RegOpenKeyEx(hKey, tszName, 0, KEY_QUERY_VALUE, &hSubKey))
+ {
+ dwSize = sizeof(tszName);
+
+ DWORD dwLength = sizeof(tzi);
+ if (ERROR_SUCCESS != RegQueryValueEx(hSubKey, _T("TZI"), NULL, NULL, (unsigned char *)&tzi, &dwLength))
+ continue;
+
+ MIM_TIMEZONE *tz = new MIM_TIMEZONE;
+
+ tz->tzi.Bias = tzi.Bias;
+ tz->tzi.StandardDate = tzi.StandardDate;
+ tz->tzi.StandardBias = tzi.StandardBias;
+ tz->tzi.DaylightDate = tzi.DaylightDate;
+ tz->tzi.DaylightBias = tzi.DaylightBias;
+
+ _tcscpy(tz->tszName, tszName);
+ tz->hash = hashstr(tszName);
+ tz->offset = INT_MIN;
+
+ GetLocalizedString(hSubKey, _T("Display"), tz->szDisplay, SIZEOF(tz->szDisplay));
+ GetLocalizedString(hSubKey, _T("Std"), tz->tzi.StandardName, SIZEOF(tz->tzi.StandardName));
+ GetLocalizedString(hSubKey, _T("Dlt"), tz->tzi.DaylightName, SIZEOF(tz->tzi.DaylightName));
+
+ g_timezones.insert(tz);
+ g_timezonesBias.insert(tz);
+
+ RegCloseKey(hSubKey);
+ }
+ dwSize = SIZEOF(tszName);
+ }
+ RegCloseKey(hKey);
+ }
+
+ RecalculateTime();
+
+ CreateServiceFunction(MS_SYSTEM_GET_TMI, GetTimeApi);
+
+ CreateServiceFunction(MS_DB_TIME_TIMESTAMPTOLOCAL, TimestampToLocal);
+ CreateServiceFunction(MS_DB_TIME_TIMESTAMPTOSTRINGT, TimestampToStringT);
+#ifdef _UNICODE
+ CreateServiceFunction(MS_DB_TIME_TIMESTAMPTOSTRING, TimestampToStringA);
+#else
+ CreateServiceFunction(MS_DB_TIME_TIMESTAMPTOSTRING, TimestampToStringT);
+#endif
+
+
+ tmi.cbSize = sizeof(tmi);
+ GetTimeApi(0, (LPARAM)&tmi);
+}
+
+void UninitTimeZones(void)
+{
+ g_timezonesBias.destroy();
+ g_timezones.destroy();
+}
diff --git a/src/modules/utils/utf.cpp b/src/modules/utils/utf.cpp
new file mode 100644
index 0000000000..ad6683d2ed
--- /dev/null
+++ b/src/modules/utils/utf.cpp
@@ -0,0 +1,413 @@
+/*
+
+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.
+
+ Copyright 2000 Alexandre Julliard of Wine project
+ (UTF-8 conversion routines)
+
+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"
+
+/* number of following bytes in sequence based on first byte value (for bytes above 0x7f) */
+static const char utf8_length[128] =
+{
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x80-0x8f */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x90-0x9f */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xa0-0xaf */
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xb0-0xbf */
+ 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0xc0-0xcf */
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0xd0-0xdf */
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* 0xe0-0xef */
+ 3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0 /* 0xf0-0xff */
+};
+
+/* first byte mask depending on UTF-8 sequence length */
+static const unsigned char utf8_mask[4] = { 0x7f, 0x1f, 0x0f, 0x07 };
+
+/* minimum Unicode value depending on UTF-8 sequence length */
+static const unsigned int utf8_minval[4] = { 0x0, 0x80, 0x800, 0x10000 };
+
+
+/* get the next char value taking surrogates into account */
+static unsigned int getSurrogateValue(const wchar_t *src, unsigned int srclen)
+{
+ if (src[0] >= 0xd800 && src[0] <= 0xdfff) /* surrogate pair */
+ {
+ if (src[0] > 0xdbff || /* invalid high surrogate */
+ srclen <= 1 || /* missing low surrogate */
+ src[1] < 0xdc00 || src[1] > 0xdfff) /* invalid low surrogate */
+ return 0;
+ return 0x10000 + ((src[0] & 0x3ff) << 10) + (src[1] & 0x3ff);
+ }
+ return src[0];
+}
+
+/* query necessary dst length for src string */
+static int Ucs2toUtf8Len(const wchar_t *src, unsigned int srclen)
+{
+ int len;
+ unsigned int val;
+
+ for (len = 0; srclen; srclen--, src++)
+ {
+ if (*src < 0x80) /* 0x00-0x7f: 1 byte */
+ {
+ len++;
+ continue;
+ }
+ if (*src < 0x800) /* 0x80-0x7ff: 2 bytes */
+ {
+ len += 2;
+ continue;
+ }
+ if (!(val = getSurrogateValue(src, srclen)))
+ {
+ return -2;
+ }
+ if (val < 0x10000) /* 0x800-0xffff: 3 bytes */
+ len += 3;
+ else /* 0x10000-0x10ffff: 4 bytes */
+ {
+ len += 4;
+ src++;
+ srclen--;
+ }
+ }
+ return len;
+}
+
+int Ucs2toUtf8Len(const wchar_t *src)
+{
+ if ( src == 0 )
+ return 0;
+
+ return Ucs2toUtf8Len( src, (int)wcslen( src ));
+}
+
+/* wide char to UTF-8 string conversion */
+/* return -1 on dst buffer overflow, -2 on invalid input char */
+int Ucs2toUtf8(const wchar_t *src, int srclen, char *dst, int dstlen)
+{
+ int len;
+
+ for (len = dstlen; srclen; srclen--, src++)
+ {
+ WCHAR ch = *src;
+ unsigned int val;
+
+ if (ch < 0x80) /* 0x00-0x7f: 1 byte */
+ {
+ if (!len--) return -1; /* overflow */
+ *dst++ = ch;
+ continue;
+ }
+
+ if (ch < 0x800) /* 0x80-0x7ff: 2 bytes */
+ {
+ if ((len -= 2) < 0) return -1; /* overflow */
+ dst[1] = 0x80 | (ch & 0x3f);
+ ch >>= 6;
+ dst[0] = 0xc0 | ch;
+ dst += 2;
+ continue;
+ }
+
+ if (!(val = getSurrogateValue(src, srclen)))
+ {
+ return -2;
+ }
+
+ if (val < 0x10000) /* 0x800-0xffff: 3 bytes */
+ {
+ if ((len -= 3) < 0) return -1; /* overflow */
+ dst[2] = 0x80 | (val & 0x3f);
+ val >>= 6;
+ dst[1] = 0x80 | (val & 0x3f);
+ val >>= 6;
+ dst[0] = 0xe0 | val;
+ dst += 3;
+ }
+ else /* 0x10000-0x10ffff: 4 bytes */
+ {
+ if ((len -= 4) < 0) return -1; /* overflow */
+ dst[3] = 0x80 | (val & 0x3f);
+ val >>= 6;
+ dst[2] = 0x80 | (val & 0x3f);
+ val >>= 6;
+ dst[1] = 0x80 | (val & 0x3f);
+ val >>= 6;
+ dst[0] = 0xf0 | val;
+ dst += 4;
+ src++;
+ srclen--;
+ }
+ }
+ return dstlen - len;
+}
+
+/* helper for the various utf8 mbstowcs functions */
+static unsigned int decodeUtf8Char(unsigned char ch, const char **str, const char *strend)
+{
+ unsigned int len = utf8_length[ch-0x80];
+ unsigned int res = ch & utf8_mask[len];
+ const char *end = *str + len;
+
+ if (end > strend) return ~0;
+ switch(len)
+ {
+ case 3:
+ if ((ch = end[-3] ^ 0x80) >= 0x40) break;
+ res = (res << 6) | ch;
+ (*str)++;
+ case 2:
+ if ((ch = end[-2] ^ 0x80) >= 0x40) break;
+ res = (res << 6) | ch;
+ (*str)++;
+ case 1:
+ if ((ch = end[-1] ^ 0x80) >= 0x40) break;
+ res = (res << 6) | ch;
+ (*str)++;
+ if (res < utf8_minval[len]) break;
+ return res;
+ }
+ return ~0;
+}
+
+/* query necessary dst length for src string */
+static inline int Utf8toUcs2Len(const char *src, int srclen)
+{
+ int ret = 0;
+ unsigned int res;
+ const char *srcend = src + srclen;
+
+ while (src < srcend)
+ {
+ unsigned char ch = *src++;
+ if (ch < 0x80) /* special fast case for 7-bit ASCII */
+ {
+ ret++;
+ continue;
+ }
+ if ((res = decodeUtf8Char(ch, &src, srcend)) <= 0x10ffff)
+ {
+ if (res > 0xffff) ret++;
+ ret++;
+ }
+ else return -2; /* bad char */
+ /* otherwise ignore it */
+ }
+ return ret;
+}
+
+/* UTF-8 to wide char string conversion */
+/* return -1 on dst buffer overflow, -2 on invalid input char */
+int Utf8toUcs2(const char *src, int srclen, wchar_t *dst, int dstlen)
+{
+ unsigned int res;
+ const char *srcend = src + srclen;
+ wchar_t *dstend = dst + dstlen;
+
+ while ((dst < dstend) && (src < srcend))
+ {
+ unsigned char ch = *src++;
+ if (ch < 0x80) /* special fast case for 7-bit ASCII */
+ {
+ *dst++ = ch;
+ continue;
+ }
+ if ((res = decodeUtf8Char(ch, &src, srcend)) <= 0xffff)
+ {
+ *dst++ = res;
+ }
+ else if (res <= 0x10ffff) /* we need surrogates */
+ {
+ if (dst == dstend - 1) return -1; /* overflow */
+ res -= 0x10000;
+ *dst++ = 0xd800 | (res >> 10);
+ *dst++ = 0xdc00 | (res & 0x3ff);
+ }
+ else return -2; /* bad char */
+ /* otherwise ignore it */
+ }
+ if (src < srcend) return -1; /* overflow */
+ return dstlen - (dstend - dst);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Utf8Decode - converts UTF8-encoded string to the UCS2/MBCS format
+
+char* Utf8DecodeCP(char* str, int codepage, wchar_t** ucs2)
+{
+ int len;
+ bool needs_free = false;
+ wchar_t* tempBuf = NULL;
+ if ( ucs2 )
+ *ucs2 = NULL;
+
+ if (str == NULL)
+ return NULL;
+
+ len = (int)strlen(str);
+
+ if (len < 2) {
+ if (ucs2 != NULL) {
+ *ucs2 = tempBuf = (wchar_t*)mir_alloc((len + 1) * sizeof(wchar_t));
+ MultiByteToWideChar(codepage, 0, str, len, tempBuf, len);
+ tempBuf[len] = 0;
+ }
+ return str;
+ }
+
+ int destlen = Utf8toUcs2Len(str, len);
+ if (destlen < 0)
+ return NULL;
+
+ if (ucs2 == NULL) {
+ __try
+ {
+ tempBuf = (wchar_t*)alloca((destlen + 1) * sizeof(wchar_t));
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ tempBuf = NULL;
+ needs_free = true;
+ }
+ }
+
+ if ( tempBuf == NULL ) {
+ tempBuf = (wchar_t*)mir_alloc((destlen + 1) * sizeof(wchar_t));
+ if ( tempBuf == NULL )
+ return NULL;
+ }
+
+ Utf8toUcs2(str, len, tempBuf, destlen);
+ tempBuf[destlen] = 0;
+ WideCharToMultiByte(codepage, 0, tempBuf, -1, str, len + 1, "?", NULL);
+
+ if (ucs2)
+ *ucs2 = tempBuf;
+ else if (needs_free)
+ mir_free(tempBuf);
+
+ return str;
+}
+
+char* Utf8Decode(char* str, wchar_t** ucs2)
+{
+ return Utf8DecodeCP(str, LangPackGetDefaultCodePage(), ucs2);
+}
+
+wchar_t* Utf8DecodeUcs2(const char* str)
+{
+ if (str == NULL)
+ return NULL;
+
+ int len = (int)strlen(str);
+
+ int destlen = Utf8toUcs2Len(str, len);
+ if (destlen < 0) return NULL;
+
+ wchar_t* ucs2 = (wchar_t*)mir_alloc((destlen + 1) * sizeof(wchar_t));
+ if (ucs2 == NULL) return NULL;
+
+ if (Utf8toUcs2(str, len, ucs2, destlen) >= 0)
+ {
+ ucs2[destlen] = 0;
+ return ucs2;
+ }
+
+ mir_free(ucs2);
+
+ return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Utf8Encode - converts MBCS string to the UTF8-encoded format
+
+char* Utf8EncodeCP(const char* src, int codepage)
+{
+ int len;
+ bool needs_free = false;
+ char* result = NULL;
+ wchar_t* tempBuf;
+
+ if (src == NULL)
+ return NULL;
+
+ len = (int)strlen(src);
+
+ __try
+ {
+ tempBuf = (wchar_t*)alloca((len + 1) * sizeof(wchar_t));
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ tempBuf = (wchar_t*)mir_alloc((len + 1) * sizeof(wchar_t));
+ if (tempBuf == NULL) return NULL;
+ needs_free = true;
+ }
+
+ len = MultiByteToWideChar(codepage, 0, src, -1, tempBuf, len + 1);
+
+ int destlen = Ucs2toUtf8Len(tempBuf, len);
+ if (destlen >= 0)
+ {
+ result = (char*)mir_alloc(destlen + 1);
+ if (result)
+ {
+ Ucs2toUtf8(tempBuf, len, result, destlen);
+ result[destlen] = 0;
+ }
+ }
+
+ if (needs_free)
+ mir_free(tempBuf);
+
+ return result;
+}
+
+char* Utf8Encode(const char* src)
+{
+ return Utf8EncodeCP(src, LangPackGetDefaultCodePage());
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Utf8Encode - converts UCS2 string to the UTF8-encoded format
+
+char* Utf8EncodeUcs2(const wchar_t* src)
+{
+ if (src == NULL)
+ return NULL;
+
+ int len = (int)wcslen(src);
+
+ int destlen = Ucs2toUtf8Len(src, len);
+ if (destlen < 0) return NULL;
+
+ char* result = (char*)mir_alloc(destlen + 1);
+ if (result == NULL)
+ return NULL;
+
+ Ucs2toUtf8(src, len, result, destlen);
+ result[destlen] = 0;
+
+ return result;
+}
diff --git a/src/modules/utils/utils.cpp b/src/modules/utils/utils.cpp
new file mode 100644
index 0000000000..9e81b3084b
--- /dev/null
+++ b/src/modules/utils/utils.cpp
@@ -0,0 +1,587 @@
+/*
+
+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_PTR ResizeDialog(WPARAM wParam,LPARAM lParam);
+int InitOpenUrl(void);
+int InitWindowList(void);
+void FreeWindowList(void);
+int InitHyperlink(void);
+int InitColourPicker(void);
+int InitBitmapFilter(void);
+void InitXmlApi(void);
+void InitTimeZones(void);
+void UninitTimeZones(void);
+
+INT_PTR GetMD5Interface(WPARAM, LPARAM);
+INT_PTR GetSHA1Interface(WPARAM, LPARAM);
+
+static BOOL bModuleInitialized = FALSE;
+
+static struct CountryListEntry countries[]={
+ {0 ,"Unspecified"},
+ {9999,"Other"},
+ {0xFFFF,"Unknown"},
+ {93 ,"Afghanistan"},
+ {355 ,"Albania"},
+ {213 ,"Algeria"},
+ {376 ,"Andorra"},
+ {244 ,"Angola"},
+ {1264,"Anguilla"}, /* change county code to NANP (from 101) */
+ {1268,"Antigua and Barbuda"}, /* change county code to NANP (from 1021) */
+// {5902,"Antilles"}, /* removed: it is not a country, it's a group of islands from diffrent countries (all are included in the list)*/
+ {54 ,"Argentina"},
+ {374 ,"Armenia"},
+ {297 ,"Aruba"},
+ {247 ,"Ascension Island"},
+ {61 ,"Australia"},
+ {6720 ,"Australia, Antarctic Territory"}, /* added country code 672(0)*/
+ {614 ,"Australia, Christmas Island"}, /* rename (from Christmas Island) and change to official county code 61(4) (from 672) */
+ {61891,"Australia, Cocos (Keeling) Islands"}, /* rename and change to official county code 61(891) (from 6102) */
+ {6723 ,"Australia, Norfolk Island"}, /* rename (from Norfolk Island) and change to official county code 672(3) (from 6722) */
+ {43 ,"Austria"},
+ {994 ,"Azerbaijan"},
+ {1242,"Bahamas"}, /* change county code to NANP (from 103) */
+ {973 ,"Bahrain"},
+ {880 ,"Bangladesh"},
+ {1246,"Barbados"}, /* change county code to NANP (from 103) */
+// {120 ,"Barbuda"}, /* removed: it is not a country and no special island, see Antigua and Barbuda*/
+ {375 ,"Belarus"},
+ {32 ,"Belgium"},
+ {501 ,"Belize"},
+ {229 ,"Benin"},
+ {1441,"Bermuda"}, /* change county code to NANP (from 105) */
+ {975 ,"Bhutan"},
+ {591 ,"Bolivia"},
+ {387 ,"Bosnia and Herzegovina"},
+ {267 ,"Botswana"},
+ {55 ,"Brazil"},
+ {673 ,"Brunei"},
+ {359 ,"Bulgaria"},
+ {226 ,"Burkina Faso"},
+ {257 ,"Burundi"},
+ {855 ,"Cambodia"},
+ {237 ,"Cameroon"},
+ {1002,"Canada"}, /* change county code to NANP (from 107 to virtual 1(002) -> reflect NANP*/
+ {238 ,"Cape Verde Islands"},
+ {1345,"Cayman Islands"}, /* change county code to NANP (from 108) */
+ {236 ,"Central African Republic"},
+ {235 ,"Chad"},
+ {56 ,"Chile, Republic of"},
+ {86 ,"China"},
+// {6101,"Cocos-Keeling Islands"}, /* removed (double): see Australia, Cocos (Keeling) Islands */
+ {57 ,"Colombia"},
+ {269 ,"Comoros"}, /* change county code (from 2691) */
+ {243 ,"Congo, Democratic Republic of (Zaire)"},
+ {242 ,"Congo, Republic of the"},
+ {682 ,"Cook Islands"},
+ {506 ,"Costa Rica"},
+ {225 ,"Cote d'Ivoire (Ivory Coast)"},
+ {385 ,"Croatia"},
+ {53 ,"Cuba"},
+ {357 ,"Greek, Republic of South Cyprus"}, /* rename coz Turkey, Republic of Northern Cyprus */
+ {420 ,"Czech Republic"},
+ {45 ,"Denmark"},
+ {246 ,"Diego Garcia"},
+ {253 ,"Djibouti"},
+ {1767,"Dominica"}, /* change county code to NANP (from 109) */
+ {1809,"Dominican Republic"}, /* change county code to NANP 809, 829, 849 (from 110) */
+ {593 ,"Ecuador"},
+ {20 ,"Egypt"},
+ {503 ,"El Salvador"},
+ {240 ,"Equatorial Guinea"},
+ {291 ,"Eritrea"},
+ {372 ,"Estonia"},
+ {251 ,"Ethiopia"},
+ {3883,"Europe"}, /* add county code +388 3 official European Telephony Numbering Space*/
+ {298 ,"Faeroe Islands"},
+ {500 ,"Falkland Islands"},
+ {679 ,"Fiji"},
+ {358 ,"Finland"},
+ {33 ,"France"},
+ {5901,"French Antilles"},
+ {594 ,"French Guiana"},
+ {689 ,"French Polynesia"},
+ {241 ,"Gabon"},
+ {220 ,"Gambia"},
+ {995 ,"Georgia"},
+ {49 ,"Germany"},
+ {233 ,"Ghana"},
+ {350 ,"Gibraltar"},
+ {30 ,"Greece"},
+ {299 ,"Greenland"},
+ {1473,"Grenada"}, /* change county code to NANP (from 111) */
+ {590 ,"Guadeloupe"},
+ {1671,"Guam, US Territory of"}, /* change county code to NANP (from 671) */
+ {502 ,"Guatemala"},
+ {224 ,"Guinea"},
+ {245 ,"Guinea-Bissau"},
+ {592 ,"Guyana"},
+ {509 ,"Haiti"},
+ {504 ,"Honduras"},
+ {852 ,"Hong Kong"},
+ {36 ,"Hungary"},
+ {354 ,"Iceland"},
+ {91 ,"India"},
+ {62 ,"Indonesia"},
+ {98 ,"Iran (Islamic Republic of)"},
+ {964 ,"Iraq"},
+ {353 ,"Ireland"},
+ {972 ,"Israel"},
+ {39 ,"Italy"},
+ {1876,"Jamaica"}, /* change county code to NANP (from 112) */
+ {81 ,"Japan"},
+ {962 ,"Jordan"},
+ {705 ,"Kazakhstan"},
+ {254 ,"Kenya"},
+ {686 ,"Kiribati"},
+ {850 ,"Korea, North"},
+ {82 ,"Korea, South"},
+ {965 ,"Kuwait"},
+ {996 ,"Kyrgyzstan"}, /* change county code (from 706) */
+ {856 ,"Laos"},
+ {371 ,"Latvia"},
+ {961 ,"Lebanon"},
+ {266 ,"Lesotho"},
+ {231 ,"Liberia"},
+ {218 ,"Libyan Arab Jamahiriya"},
+ {423 ,"Liechtenstein"}, /* change county code (from 4101) */
+ {370 ,"Lithuania"},
+ {352 ,"Luxembourg"},
+ {853 ,"Macau"},
+ {389 ,"Macedonia, Republic of"}, /* rename coz war */
+ {261 ,"Madagascar"},
+ {265 ,"Malawi"},
+ {60 ,"Malaysia"},
+ {960 ,"Maldives"},
+ {223 ,"Mali"},
+ {356 ,"Malta"},
+ {692 ,"Marshall Islands"},
+ {596 ,"Martinique"},
+ {222 ,"Mauritania"},
+ {230 ,"Mauritius"},
+ {262 ,"Mayotte Island"}, /* change county code coz bug (from 269) */
+ {52 ,"Mexico"},
+ {691 ,"Micronesia, Federated States of"},
+ {373 ,"Moldova, Republic of"},
+ {377 ,"Monaco"},
+ {976 ,"Mongolia"},
+ {1664,"Montserrat"}, /* change county code to NANP (from 113) */
+ {212 ,"Morocco"},
+ {258 ,"Mozambique"},
+ {95 ,"Myanmar"},
+ {264 ,"Namibia"},
+ {674 ,"Nauru"},
+ {977 ,"Nepal"},
+ {31 ,"Netherlands"},
+ {599 ,"Netherlands Antilles"}, /* dissolved 2010 */
+ {5995 ,"St. Maarten"}, /* add new country in 2010 (from Netherlands Antilles) */
+ {5999 ,"Curacao"}, /* add new country in 2010 (from Netherlands Antilles) */
+ {5997 ,"Netherlands (Bonaire Island)"}, /* add new Part of Netherlands in 2010 (from Netherlands Antilles) */
+ {59946,"Netherlands (Saba Island)"}, /* add new Part of Netherlands in 2010 (from Netherlands Antilles) */
+ {59938,"Netherlands (St. Eustatius Island)"}, /* add new Part of Netherlands in 2010 (from Netherlands Antilles) */
+ // {114 ,"Nevis"}, /* removed: it is not a country, it's part of Saint Kitts and Nevis*/
+ {687 ,"New Caledonia"},
+ {64 ,"New Zealand"},
+ {505 ,"Nicaragua"},
+ {227 ,"Niger"},
+ {234 ,"Nigeria"},
+ {683 ,"Niue"},
+ {1670,"Northern Mariana Islands, US Territory of"}, /* added NANP */
+ {47 ,"Norway"},
+ {968 ,"Oman"},
+ {92 ,"Pakistan"},
+ {680 ,"Palau"},
+ {507 ,"Panama"},
+ {675 ,"Papua New Guinea"},
+ {595 ,"Paraguay"},
+ {51 ,"Peru"},
+ {63 ,"Philippines"},
+ {48 ,"Poland"},
+ {351 ,"Portugal"},
+ {1939,"Puerto Rico"}, /* change county code to NANP 939, 787 (from 121) */
+ {974 ,"Qatar"},
+ {262 ,"Reunion Island"},
+ {40 ,"Romania"},
+// {6701,"Rota Island"}, /* removed: it is not a country it is part of Northern Mariana Islands, US Territory of */
+ {7 ,"Russia"},
+ {250 ,"Rwanda"},
+ {1684,"Samoa (USA)"}, /* rename (from American Samoa) change county code to NANP (from 684) */
+ {685 ,"Samoa, Western"}, /* rename (from Western Samoa) */
+ {290 ,"Saint Helena"},
+// {115 ,"Saint Kitts"}, /* removed: it is not a country it is part of Saint Kitts and Nevis*/
+ {1869,"Saint Kitts and Nevis"}, /* change county code to NANP (from 1141) */
+ {1758,"Saint Lucia"}, /* change county code to NANP (from 122) */
+ {508 ,"Saint Pierre and Miquelon"},
+ {1784,"Saint Vincent and the Grenadines"}, /* change county code to NANP (from 116) */
+// {670 ,"Saipan Island"}, /* removed: it is not a country it is part of Northern Mariana Islands, US Territory of */
+ {378 ,"San Marino"},
+ {239 ,"Sao Tome and Principe"},
+ {966 ,"Saudi Arabia"},
+ {442 ,"Scotland"},
+ {221 ,"Senegal"},
+ {248 ,"Seychelles"},
+ {232 ,"Sierra Leone"},
+ {65 ,"Singapore"},
+ {421 ,"Slovakia"},
+ {386 ,"Slovenia"},
+ {677 ,"Solomon Islands"},
+ {252 ,"Somalia"},
+ {27 ,"South Africa"},
+ {34 ,"Spain"},
+ {3492,"Spain, Canary Islands"}, /*rename and change county code to 34(92) spain + canary code*/
+ {94 ,"Sri Lanka"},
+ {249 ,"Sudan"},
+ {597 ,"Suriname"},
+ {268 ,"Swaziland"},
+ {46 ,"Sweden"},
+ {41 ,"Switzerland"},
+ {963 ,"Syrian Arab Republic"},
+ {886 ,"Taiwan"},
+ {992 ,"Tajikistan"}, /* change county code (from 708) */
+ {255 ,"Tanzania"},
+ {66 ,"Thailand"},
+// {6702,"Tinian Island"}, /* removed: it is not a country it is part of Northern Mariana Islands, US Territory of */
+ {670 ,"Timor, East"}, /* added (is part off Northern Mariana Islands but not US Territory*/
+ {228 ,"Togo"},
+ {690 ,"Tokelau"},
+ {676 ,"Tonga"},
+ {1868,"Trinidad and Tobago"}, /* change county code to NANP (from 1141) */
+ {216 ,"Tunisia"},
+ {90 ,"Turkey"},
+ {90392,"Turkey, Republic of Northern Cyprus"}, /* added (is diffrent from Greek part)*/
+ {993 ,"Turkmenistan"}, /* change county code (from 709) */
+ {1649,"Turks and Caicos Islands"}, /* change county code to NANP (from 118) */
+ {688 ,"Tuvalu"},
+ {256 ,"Uganda"},
+ {380 ,"Ukraine"},
+ {971 ,"United Arab Emirates"},
+ {44 ,"United Kingdom"},
+ {598 ,"Uruguay"},
+ {1 ,"USA"},
+ {998 ,"Uzbekistan"}, /* change county code (from 711) */
+ {678 ,"Vanuatu"},
+ {379 ,"Vatican City"},
+ {58 ,"Venezuela"},
+ {84 ,"Vietnam"},
+ {1284,"Virgin Islands (UK)"}, /* change county code to NANP (from 105) - rename coz Virgin Islands (USA) */
+ {1340,"Virgin Islands (USA)"}, /* change county code to NANP (from 123) */
+ {441 ,"Wales"},
+ {681 ,"Wallis and Futuna Islands"},
+ {967 ,"Yemen"},
+ {38 ,"Yugoslavia"}, /* added for old values like birth-country */
+ {381 ,"Serbia, Republic of"}, /* rename need (from Yugoslavia)*/
+ {383 ,"Kosovo, Republic of"}, /*change country code (from 3811), rename need (from Yugoslavia - Serbia) */
+ {382 ,"Montenegro, Republic of"}, /* rename need (from Yugoslavia - Montenegro) */
+ {260 ,"Zambia"},
+ {263 ,"Zimbabwe"},
+};
+
+static INT_PTR GetCountryByNumber(WPARAM wParam, LPARAM)
+{
+ int i;
+
+ for(i=0; i < SIZEOF(countries); i++ )
+ if((int)wParam==countries[i].id) return (INT_PTR)countries[i].szName;
+ return (INT_PTR)NULL;
+}
+
+static INT_PTR GetCountryList(WPARAM wParam,LPARAM lParam)
+{
+ *(int*)wParam = SIZEOF(countries);
+ *(struct CountryListEntry**)lParam=countries;
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static INT_PTR SaveWindowPosition(WPARAM, LPARAM lParam)
+{
+ SAVEWINDOWPOS *swp=(SAVEWINDOWPOS*)lParam;
+ WINDOWPLACEMENT wp;
+ char szSettingName[64];
+
+ wp.length=sizeof(wp);
+ GetWindowPlacement(swp->hwnd,&wp);
+ mir_snprintf(szSettingName, SIZEOF(szSettingName), "%sx", swp->szNamePrefix);
+ DBWriteContactSettingDword(swp->hContact,swp->szModule,szSettingName,wp.rcNormalPosition.left);
+ mir_snprintf(szSettingName, SIZEOF(szSettingName), "%sy", swp->szNamePrefix);
+ DBWriteContactSettingDword(swp->hContact,swp->szModule,szSettingName,wp.rcNormalPosition.top);
+ mir_snprintf(szSettingName, SIZEOF(szSettingName), "%swidth", swp->szNamePrefix);
+ DBWriteContactSettingDword(swp->hContact,swp->szModule,szSettingName,wp.rcNormalPosition.right-wp.rcNormalPosition.left);
+ mir_snprintf(szSettingName, SIZEOF(szSettingName), "%sheight", swp->szNamePrefix);
+ DBWriteContactSettingDword(swp->hContact,swp->szModule,szSettingName,wp.rcNormalPosition.bottom-wp.rcNormalPosition.top);
+ return 0;
+}
+
+
+static INT_PTR AssertInsideScreen(WPARAM wParam, LPARAM lParam)
+{
+ LPRECT rc = (LPRECT) wParam;
+ if (rc == NULL)
+ return -1;
+
+ RECT rcScreen;
+ SystemParametersInfo(SPI_GETWORKAREA, 0, &rcScreen, FALSE);
+
+ if (MyMonitorFromWindow)
+ {
+ if (MyMonitorFromRect(rc, MONITOR_DEFAULTTONULL))
+ return 0;
+
+ MONITORINFO mi = {0};
+ HMONITOR hMonitor = MyMonitorFromRect(rc, MONITOR_DEFAULTTONEAREST);
+ mi.cbSize = sizeof(mi);
+ if (MyGetMonitorInfo(hMonitor, &mi))
+ rcScreen = mi.rcWork;
+ }
+ else
+ {
+ RECT rcDest;
+ if (IntersectRect(&rcDest, &rcScreen, rc))
+ return 0;
+ }
+
+ if (rc->top >= rcScreen.bottom)
+ OffsetRect(rc, 0, rcScreen.bottom - rc->bottom);
+ else if (rc->bottom <= rcScreen.top)
+ OffsetRect(rc, 0, rcScreen.top - rc->top);
+ if (rc->left >= rcScreen.right)
+ OffsetRect(rc, rcScreen.right - rc->right, 0);
+ else if (rc->right <= rcScreen.left)
+ OffsetRect(rc, rcScreen.left - rc->left, 0);
+
+ return 1;
+}
+
+
+static INT_PTR RestoreWindowPosition(WPARAM wParam,LPARAM lParam)
+{
+ SAVEWINDOWPOS *swp=(SAVEWINDOWPOS*)lParam;
+ WINDOWPLACEMENT wp;
+ char szSettingName[64];
+ int x,y;
+
+ wp.length=sizeof(wp);
+ GetWindowPlacement(swp->hwnd,&wp);
+ mir_snprintf(szSettingName, SIZEOF(szSettingName), "%sx", swp->szNamePrefix);
+ x=DBGetContactSettingDword(swp->hContact,swp->szModule,szSettingName,-1);
+ mir_snprintf(szSettingName, SIZEOF(szSettingName), "%sy", swp->szNamePrefix);
+ y=(int)DBGetContactSettingDword(swp->hContact,swp->szModule,szSettingName,-1);
+ if(x==-1) return 1;
+ if(wParam&RWPF_NOSIZE) {
+ OffsetRect(&wp.rcNormalPosition,x-wp.rcNormalPosition.left,y-wp.rcNormalPosition.top);
+ }
+ else {
+ wp.rcNormalPosition.left=x;
+ wp.rcNormalPosition.top=y;
+ mir_snprintf(szSettingName, SIZEOF(szSettingName), "%swidth", swp->szNamePrefix);
+ wp.rcNormalPosition.right=wp.rcNormalPosition.left+DBGetContactSettingDword(swp->hContact,swp->szModule,szSettingName,-1);
+ mir_snprintf(szSettingName, SIZEOF(szSettingName), "%sheight", swp->szNamePrefix);
+ wp.rcNormalPosition.bottom=wp.rcNormalPosition.top+DBGetContactSettingDword(swp->hContact,swp->szModule,szSettingName,-1);
+ }
+ wp.flags=0;
+ if (wParam & RWPF_HIDDEN)
+ wp.showCmd = SW_HIDE;
+ if (wParam & RWPF_NOACTIVATE)
+ wp.showCmd = SW_SHOWNOACTIVATE;
+
+ if (!(wParam & RWPF_NOMOVE))
+ AssertInsideScreen((WPARAM) &wp.rcNormalPosition, 0);
+
+ SetWindowPlacement(swp->hwnd,&wp);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static INT_PTR RestartMiranda(WPARAM, LPARAM)
+{
+ TCHAR mirandaPath[ MAX_PATH ], cmdLine[ 100 ];
+ PROCESS_INFORMATION pi;
+ STARTUPINFO si = { 0 };
+ si.cb = sizeof(si);
+ GetModuleFileName( NULL, mirandaPath, SIZEOF(mirandaPath));
+ mir_sntprintf( cmdLine, SIZEOF( cmdLine ), _T("/restart:%d"), GetCurrentProcessId());
+ CreateProcess( mirandaPath, cmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi );
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+typedef BOOL (APIENTRY *PGENRANDOM)( PVOID, ULONG );
+
+static INT_PTR GenerateRandom(WPARAM wParam, LPARAM lParam)
+{
+ if (wParam == 0 || lParam == 0) return 0;
+
+ PGENRANDOM pfnRtlGenRandom = NULL;
+ HMODULE hModule = GetModuleHandleA("advapi32");
+ if (hModule)
+ {
+ pfnRtlGenRandom = (PGENRANDOM)GetProcAddress(hModule, "SystemFunction036");
+ if (pfnRtlGenRandom)
+ {
+ if (!pfnRtlGenRandom((PVOID)lParam, wParam))
+ pfnRtlGenRandom = NULL;
+ }
+ }
+ if (pfnRtlGenRandom == NULL)
+ {
+ srand(GetTickCount());
+ unsigned short* buf = (unsigned short*)lParam;
+ for ( ; (long)(wParam-=2) >= 0; )
+ *(buf++) = (unsigned short)rand();
+ if (lParam < 0)
+ *(char*)buf = (char)(rand() & 0xFF);
+ }
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+#if defined( _UNICODE )
+char* __fastcall rtrim(char* str)
+{
+ if (str == NULL) return NULL;
+ char* p = strchr(str, 0);
+ while (--p >= str)
+ {
+ switch (*p)
+ {
+ case ' ': case '\t': case '\n': case '\r':
+ *p = 0; break;
+ default:
+ return str;
+ }
+ }
+ return str;
+}
+#endif
+
+TCHAR* __fastcall rtrim(TCHAR *str)
+{
+ if (str == NULL) return NULL;
+ TCHAR* p = _tcschr(str, 0);
+ while (--p >= str)
+ {
+ switch (*p)
+ {
+ case ' ': case '\t': case '\n': case '\r':
+ *p = 0; break;
+ default:
+ return str;
+ }
+ }
+ return str;
+}
+
+char* __fastcall ltrim(char* str)
+{
+ if (str == NULL) return NULL;
+ char* p = str;
+
+ for (;;)
+ {
+ switch (*p)
+ {
+ case ' ': case '\t': case '\n': case '\r':
+ ++p; break;
+ default:
+ memmove(str, p, strlen(p) + 1);
+ return str;
+ }
+ }
+}
+
+char* __fastcall ltrimp(char* str)
+{
+ if (str == NULL) return NULL;
+ char* p = str;
+
+ for (;;)
+ {
+ switch (*p)
+ {
+ case ' ': case '\t': case '\n': case '\r':
+ ++p; break;
+ default:
+ return p;
+ }
+ }
+}
+
+bool __fastcall wildcmp(char * name, char * mask)
+{
+ char * last='\0';
+ for(;; mask++, name++)
+ {
+ if(*mask != '?' && *mask != *name) break;
+ if(*name == '\0') return ((BOOL)!*mask);
+ }
+ if(*mask != '*') return FALSE;
+ for(;; mask++, name++)
+ {
+ while(*mask == '*')
+ {
+ last = mask++;
+ if(*mask == '\0') return ((BOOL)!*mask); /* true */
+ }
+ if(*name == '\0') return ((BOOL)!*mask); /* *mask == EOS */
+ if(*mask != '?' && *mask != *name) name -= (size_t)(mask - last) - 1, mask = last;
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int LoadUtilsModule(void)
+{
+ bModuleInitialized = TRUE;
+
+ CreateServiceFunction(MS_UTILS_RESIZEDIALOG,ResizeDialog);
+ CreateServiceFunction(MS_UTILS_SAVEWINDOWPOSITION,SaveWindowPosition);
+ CreateServiceFunction(MS_UTILS_RESTOREWINDOWPOSITION,RestoreWindowPosition);
+ CreateServiceFunction(MS_UTILS_ASSERTINSIDESCREEN,AssertInsideScreen);
+ CreateServiceFunction(MS_UTILS_GETCOUNTRYBYNUMBER,GetCountryByNumber);
+ CreateServiceFunction(MS_UTILS_GETCOUNTRYLIST,GetCountryList);
+ CreateServiceFunction(MS_UTILS_GETRANDOM,GenerateRandom);
+ CreateServiceFunction(MS_SYSTEM_RESTART,RestartMiranda);
+ CreateServiceFunction(MS_SYSTEM_GET_MD5I,GetMD5Interface);
+ CreateServiceFunction(MS_SYSTEM_GET_SHA1I,GetSHA1Interface);
+ InitOpenUrl();
+ InitWindowList();
+ InitHyperlink();
+ InitColourPicker();
+ InitBitmapFilter();
+ InitXmlApi();
+ InitTimeZones();
+ return 0;
+}
+
+void UnloadUtilsModule(void)
+{
+ if ( !bModuleInitialized ) return;
+
+ FreeWindowList();
+ UninitTimeZones();
+}
diff --git a/src/modules/utils/windowlist.cpp b/src/modules/utils/windowlist.cpp
new file mode 100644
index 0000000000..b7ea59eb58
--- /dev/null
+++ b/src/modules/utils/windowlist.cpp
@@ -0,0 +1,101 @@
+/*
+
+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"
+
+static WINDOWLISTENTRY *windowList=NULL;
+static int windowListCount=0;
+static int nextWindowListId=1;
+
+static INT_PTR AllocWindowList(WPARAM, LPARAM)
+{
+ return nextWindowListId++;
+}
+
+static INT_PTR AddToWindowList(WPARAM, LPARAM lParam)
+{
+ windowList=(WINDOWLISTENTRY*)mir_realloc(windowList,sizeof(WINDOWLISTENTRY)*(windowListCount+1));
+ windowList[windowListCount++]=*(WINDOWLISTENTRY*)lParam;
+ return 0;
+}
+
+static INT_PTR RemoveFromWindowList(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+ for(i=0;i<windowListCount;i++)
+ if(windowList[i].hwnd==(HWND)lParam && windowList[i].hList==(HANDLE)wParam) {
+ MoveMemory(&windowList[i],&windowList[i+1],sizeof(WINDOWLISTENTRY)*(windowListCount-i-1));
+ windowListCount--;
+ return 0;
+ }
+ return 1;
+}
+
+static INT_PTR FindInWindowList(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+ for(i=0;i<windowListCount;i++)
+ if(windowList[i].hContact==(HANDLE)lParam && windowList[i].hList==(HANDLE)wParam)
+ return (INT_PTR)windowList[i].hwnd;
+ return (INT_PTR)(HWND)NULL;
+}
+
+static INT_PTR BroadcastToWindowList(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+ MSG *msg=(MSG*)lParam;
+ for(i=0;i<windowListCount;i++)
+ if(windowList[i].hList==(HANDLE)wParam)
+ SendMessage(windowList[i].hwnd,msg->message,msg->wParam,msg->lParam);
+ return 0;
+}
+
+static INT_PTR BroadcastToWindowListAsync(WPARAM wParam,LPARAM lParam)
+{
+ int i;
+ MSG *msg=(MSG*)lParam;
+ for(i=0;i<windowListCount;i++)
+ if(windowList[i].hList==(HANDLE)wParam)
+ PostMessage(windowList[i].hwnd,msg->message,msg->wParam,msg->lParam);
+ return 0;
+}
+
+int InitWindowList(void)
+{
+ CreateServiceFunction(MS_UTILS_ALLOCWINDOWLIST,AllocWindowList);
+ CreateServiceFunction(MS_UTILS_ADDTOWINDOWLIST,AddToWindowList);
+ CreateServiceFunction(MS_UTILS_REMOVEFROMWINDOWLIST,RemoveFromWindowList);
+ CreateServiceFunction(MS_UTILS_BROADCASTTOWINDOWLIST,BroadcastToWindowList);
+ CreateServiceFunction(MS_UTILS_BROADCASTTOWINDOWLIST_ASYNC,BroadcastToWindowListAsync);
+ CreateServiceFunction(MS_UTILS_FINDWINDOWINLIST,FindInWindowList);
+ return 0;
+}
+
+void FreeWindowList(void)
+{
+ if ( windowList ) {
+ mir_free(windowList);
+ windowList = NULL;
+ }
+ windowListCount=0;
+ nextWindowListId=1;
+}
diff --git a/src/modules/visibility/visibility.cpp b/src/modules/visibility/visibility.cpp
new file mode 100644
index 0000000000..aa319cf715
--- /dev/null
+++ b/src/modules/visibility/visibility.cpp
@@ -0,0 +1,297 @@
+/*
+
+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"
+
+static void SetListGroupIcons(HWND hwndList,HANDLE hFirstItem,HANDLE hParentItem,int *groupChildCount)
+{
+ int typeOfFirst;
+ int iconOn[2]={1,1};
+ int childCount[2]={0,0},i;
+ int iImage;
+ HANDLE hItem,hChildItem;
+
+ typeOfFirst=SendMessage(hwndList,CLM_GETITEMTYPE,(WPARAM)hFirstItem,0);
+ //check groups
+ if(typeOfFirst==CLCIT_GROUP) hItem=hFirstItem;
+ else hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTGROUP,(LPARAM)hFirstItem);
+ while(hItem) {
+ hChildItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_CHILD,(LPARAM)hItem);
+ if(hChildItem) SetListGroupIcons(hwndList,hChildItem,hItem,childCount);
+ for( i=0; i < SIZEOF(iconOn); i++)
+ if(iconOn[i] && SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,i)==0) iconOn[i]=0;
+ hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTGROUP,(LPARAM)hItem);
+ }
+ //check contacts
+ if(typeOfFirst==CLCIT_CONTACT) hItem=hFirstItem;
+ else hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTCONTACT,(LPARAM)hFirstItem);
+ while(hItem) {
+ for ( i=0; i < SIZEOF(iconOn); i++) {
+ iImage=SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,i);
+ if(iconOn[i] && iImage==0) iconOn[i]=0;
+ if(iImage!=0xFF) childCount[i]++;
+ }
+ hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTCONTACT,(LPARAM)hItem);
+ }
+ //set icons
+ for( i=0; i < SIZEOF(iconOn); i++) {
+ SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hParentItem,MAKELPARAM(i,childCount[i]?(iconOn[i]?i+1:0):0xFF));
+ if(groupChildCount) groupChildCount[i]+=childCount[i];
+ }
+}
+
+static void SetAllChildIcons(HWND hwndList,HANDLE hFirstItem,int iColumn,int iImage)
+{
+ int typeOfFirst,iOldIcon;
+ HANDLE hItem,hChildItem;
+
+ typeOfFirst=SendMessage(hwndList,CLM_GETITEMTYPE,(WPARAM)hFirstItem,0);
+ //check groups
+ if(typeOfFirst==CLCIT_GROUP) hItem=hFirstItem;
+ else hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTGROUP,(LPARAM)hFirstItem);
+ while(hItem) {
+ hChildItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_CHILD,(LPARAM)hItem);
+ if(hChildItem) SetAllChildIcons(hwndList,hChildItem,iColumn,iImage);
+ hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTGROUP,(LPARAM)hItem);
+ }
+ //check contacts
+ if(typeOfFirst==CLCIT_CONTACT) hItem=hFirstItem;
+ else hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTCONTACT,(LPARAM)hFirstItem);
+ while(hItem) {
+ iOldIcon=SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,iColumn);
+ if(iOldIcon!=0xFF && iOldIcon!=iImage) SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(iColumn,iImage));
+ hItem=(HANDLE)SendMessage(hwndList,CLM_GETNEXTITEM,CLGN_NEXTCONTACT,(LPARAM)hItem);
+ }
+}
+
+static void ResetListOptions(HWND hwndList)
+{
+ int i;
+
+ SendMessage(hwndList,CLM_SETBKBITMAP,0,(LPARAM)(HBITMAP)NULL);
+ SendMessage(hwndList,CLM_SETBKCOLOR,GetSysColor(COLOR_WINDOW),0);
+ SendMessage(hwndList,CLM_SETGREYOUTFLAGS,0,0);
+ SendMessage(hwndList,CLM_SETLEFTMARGIN,2,0);
+ SendMessage(hwndList,CLM_SETINDENT,10,0);
+ for(i=0;i<=FONTID_MAX;i++)
+ SendMessage(hwndList,CLM_SETTEXTCOLOR,i,GetSysColor(COLOR_WINDOWTEXT));
+ SetWindowLongPtr(hwndList,GWL_STYLE,GetWindowLongPtr(hwndList,GWL_STYLE)|CLS_SHOWHIDDEN);
+}
+
+static void SetAllContactIcons(HWND hwndList)
+{
+ HANDLE hContact,hItem;
+ char *szProto;
+ DWORD flags;
+ WORD status;
+
+ hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDFIRST,0,0);
+ do {
+ hItem=(HANDLE)SendMessage(hwndList,CLM_FINDCONTACT,(WPARAM)hContact,0);
+ if(hItem) {
+ szProto=(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM)hContact,0);
+ if(szProto==NULL) {flags=0; status=0;}
+ else {
+ flags=CallProtoService(szProto,PS_GETCAPS,PFLAGNUM_1,0);
+ status=DBGetContactSettingWord(hContact,szProto,"ApparentMode",0);
+ }
+ if(flags&PF1_INVISLIST) {
+ if(SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(0,0))==0xFF)
+ SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(0,status==ID_STATUS_ONLINE?1:0));
+ }
+ if(flags&PF1_VISLIST) {
+ if(SendMessage(hwndList,CLM_GETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(1,0))==0xFF)
+ SendMessage(hwndList,CLM_SETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(1,status==ID_STATUS_OFFLINE?2:0));
+ }
+ }
+ } while(hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)hContact,0));
+}
+
+static INT_PTR CALLBACK DlgProcVisibilityOpts(HWND hwndDlg, UINT msg, WPARAM, LPARAM lParam)
+{
+ static HICON hVisibleIcon,hInvisibleIcon;
+ static HANDLE hItemAll;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ { HIMAGELIST hIml;
+ hIml=ImageList_Create(GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),(IsWinVerXPPlus()?ILC_COLOR32:ILC_COLOR16)|ILC_MASK,3,3);
+ ImageList_AddIcon_IconLibLoaded(hIml,SKINICON_OTHER_SMALLDOT);
+ ImageList_AddIcon_IconLibLoaded(hIml,SKINICON_STATUS_INVISIBLE);
+ ImageList_AddIcon_IconLibLoaded(hIml,SKINICON_STATUS_OFFLINE);
+ SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_SETEXTRAIMAGELIST,0,(LPARAM)hIml);
+ hVisibleIcon=ImageList_GetIcon(hIml,1,ILD_NORMAL);
+ SendDlgItemMessage(hwndDlg,IDC_VISIBLEICON,STM_SETICON,(WPARAM)hVisibleIcon,0);
+ hInvisibleIcon=ImageList_GetIcon(hIml,2,ILD_NORMAL);
+ SendDlgItemMessage(hwndDlg,IDC_INVISIBLEICON,STM_SETICON,(WPARAM)hInvisibleIcon,0);
+ }
+
+ ResetListOptions(GetDlgItem(hwndDlg,IDC_LIST));
+ SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_SETEXTRACOLUMNS,2,0);
+
+ { CLCINFOITEM cii={0};
+ cii.cbSize=sizeof(cii);
+ cii.flags=CLCIIF_GROUPFONT;
+ cii.pszText=TranslateT("** All contacts **");
+ hItemAll=(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_ADDINFOITEM,0,(LPARAM)&cii);
+ }
+
+ SetAllContactIcons(GetDlgItem(hwndDlg,IDC_LIST));
+ SetListGroupIcons(GetDlgItem(hwndDlg,IDC_LIST),(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETNEXTITEM,CLGN_ROOT,0),hItemAll,NULL);
+ return TRUE;
+ case WM_SETFOCUS:
+ SetFocus(GetDlgItem(hwndDlg,IDC_LIST));
+ break;
+ case WM_NOTIFY:
+ switch(((LPNMHDR)lParam)->idFrom) {
+ case IDC_LIST:
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case CLN_NEWCONTACT:
+ case CLN_LISTREBUILT:
+ SetAllContactIcons(GetDlgItem(hwndDlg,IDC_LIST));
+ //fall through
+ case CLN_CONTACTMOVED:
+ SetListGroupIcons(GetDlgItem(hwndDlg,IDC_LIST),(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETNEXTITEM,CLGN_ROOT,0),hItemAll,NULL);
+ break;
+ case CLN_OPTIONSCHANGED:
+ ResetListOptions(GetDlgItem(hwndDlg,IDC_LIST));
+ break;
+ case NM_CLICK:
+ { HANDLE hItem;
+ NMCLISTCONTROL *nm=(NMCLISTCONTROL*)lParam;
+ DWORD hitFlags;
+ int iImage;
+ int itemType;
+
+ // Make sure we have an extra column
+ if (nm->iColumn == -1)
+ break;
+
+ // Find clicked item
+ hItem = (HANDLE)SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_HITTEST, (WPARAM)&hitFlags, MAKELPARAM(nm->pt.x,nm->pt.y));
+ // Nothing was clicked
+ if (hItem == NULL) break;
+ // It was not a visbility icon
+ if (!(hitFlags & CLCHT_ONITEMEXTRA)) break;
+
+ // Get image in clicked column (0=none, 1=visible, 2=invisible)
+ iImage = SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(nm->iColumn, 0));
+ if (iImage == 0)
+ iImage=nm->iColumn + 1;
+ else
+ if (iImage == 1 || iImage == 2)
+ iImage = 0;
+
+ // Get item type (contact, group, etc...)
+ itemType = SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_GETITEMTYPE, (WPARAM)hItem, 0);
+
+ // Update list, making sure that the options are mutually exclusive
+ if (itemType == CLCIT_CONTACT) { // A contact
+ SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(nm->iColumn, iImage));
+ if (iImage && SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(nm->iColumn?0:1,0))!=0xFF)
+ SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(nm->iColumn?0:1, 0));
+ }
+ else if (itemType == CLCIT_INFO) { // All Contacts
+ SetAllChildIcons(GetDlgItem(hwndDlg, IDC_LIST), hItem, nm->iColumn, iImage);
+ if (iImage)
+ SetAllChildIcons(GetDlgItem(hwndDlg, IDC_LIST), hItem, nm->iColumn?0:1, 0);
+ }
+ else if (itemType == CLCIT_GROUP) { // A group
+ hItem = (HANDLE)SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_GETNEXTITEM, CLGN_CHILD, (LPARAM)hItem);
+ if (hItem) {
+ SetAllChildIcons(GetDlgItem(hwndDlg, IDC_LIST), hItem, nm->iColumn, iImage);
+ if (iImage)
+ SetAllChildIcons(GetDlgItem(hwndDlg, IDC_LIST), hItem, nm->iColumn?0:1, 0);
+ }
+ }
+ // Update the all/none icons
+ SetListGroupIcons(GetDlgItem(hwndDlg, IDC_LIST), (HANDLE)SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_GETNEXTITEM, CLGN_ROOT, 0), hItemAll, NULL);
+
+ // Activate Apply button
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+ }
+ break;
+ case 0:
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case PSN_APPLY:
+ { HANDLE hContact,hItem;
+ int set,i,iImage;
+
+ hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDFIRST,0,0);
+ do {
+ hItem=(HANDLE)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_FINDCONTACT,(WPARAM)hContact,0);
+ if(hItem) {
+ set=0;
+ for(i=0;i<2;i++) {
+ iImage=SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETEXTRAIMAGE,(WPARAM)hItem,MAKELPARAM(i,0));
+ if(iImage==i+1) {
+ CallContactService(hContact,PSS_SETAPPARENTMODE,iImage==1?ID_STATUS_ONLINE:ID_STATUS_OFFLINE,0);
+ set=1;
+ break;
+ }
+ }
+ if(!set) CallContactService(hContact,PSS_SETAPPARENTMODE,0,0);
+ }
+ } while(hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)hContact,0));
+ return TRUE;
+ }
+ }
+ break;
+ }
+ break;
+ case WM_DESTROY:
+ DestroyIcon(hVisibleIcon);
+ DestroyIcon(hInvisibleIcon);
+ { HIMAGELIST hIml=(HIMAGELIST)SendDlgItemMessage(hwndDlg,IDC_LIST,CLM_GETEXTRAIMAGELIST,0,0);
+ ImageList_Destroy(hIml);
+ }
+ break;
+ }
+ return FALSE;
+}
+
+static int VisibilityOptInitialise(WPARAM wParam, LPARAM)
+{
+ OPTIONSDIALOGPAGE odp = { 0 };
+ odp.cbSize = sizeof(odp);
+ odp.position = 850000000;
+ odp.hInstance = hMirandaInst;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_VISIBILITY);
+ odp.pszTitle = LPGEN("Visibility");
+ odp.pszGroup = LPGEN("Status");
+ odp.pfnDlgProc = DlgProcVisibilityOpts;
+ odp.flags = ODPF_BOLDGROUPS;
+ CallService( MS_OPT_ADDPAGE, wParam, ( LPARAM )&odp );
+ return 0;
+}
+
+int LoadVisibilityModule(void)
+{
+ HookEvent(ME_OPT_INITIALISE,VisibilityOptInitialise);
+ return 0;
+}
diff --git a/src/modules/xml/xmlApi.cpp b/src/modules/xml/xmlApi.cpp
new file mode 100644
index 0000000000..08887dd448
--- /dev/null
+++ b/src/modules/xml/xmlApi.cpp
@@ -0,0 +1,446 @@
+/*
+
+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 "xmlParser.h"
+
+static HXML xmlapiCreateNode( LPCTSTR name, LPCTSTR text, char isDeclaration )
+{
+ XMLNode result = XMLNode::createXMLTopNode( name, isDeclaration );
+ if ( text )
+ result.updateText( text );
+ return result.detach();
+}
+
+static void xmlapiDestroyNode( HXML n )
+{
+ XMLNode tmp; tmp.attach(n);
+}
+
+static HXML xmlapiParseString( LPCTSTR str, int* datalen, LPCTSTR tag )
+{
+ if (str == NULL) return NULL;
+
+ XMLResults res;
+ XMLNode result = XMLNode::parseString( str, tag, &res );
+
+ if ( datalen != NULL )
+ datalen[0] += res.nChars;
+
+ return (res.error == eXMLErrorNone || (tag != NULL && res.error == eXMLErrorMissingEndTag)) ? result.detach() : NULL;
+}
+
+static HXML xmlapiAddChild( HXML _n, LPCTSTR name, LPCTSTR text )
+{
+ XMLNode result = XMLNode(_n).addChild( name );
+ if ( text != NULL )
+ result.updateText( text );
+ return result;
+}
+
+static void xmlapiAddChild2( HXML _child, HXML _parent )
+{
+ XMLNode child(_child), parent(_parent);
+ parent.addChild( child );
+}
+
+static HXML xmlapiCopyNode( HXML _n )
+{
+ XMLNode result = XMLNode(_n);
+ return result.detach();
+}
+
+static LPCTSTR xmlapiGetAttr( HXML _n, int i )
+{
+ return XMLNode(_n).getAttributeValue( i );
+}
+
+static int xmlapiGetAttrCount( HXML _n )
+{
+ return XMLNode(_n).nAttribute();
+}
+
+static LPCTSTR xmlapiGetAttrName( HXML _n, int i )
+{
+ return XMLNode(_n).getAttributeName( i );
+}
+
+static HXML xmlapiGetChild( HXML _n, int i )
+{
+ return XMLNode(_n).getChildNode( i );
+}
+
+static HXML xmlapiGetChildByAttrValue( HXML _n, LPCTSTR name, LPCTSTR attrName, LPCTSTR attrValue )
+{
+ return XMLNode(_n).getChildNodeWithAttribute( name, attrName, attrValue );
+}
+
+static int xmlapiGetChildCount( HXML _n )
+{
+ return XMLNode(_n).nChildNode();
+}
+
+static HXML xmlapiGetFirstChild( HXML _n )
+{
+ return XMLNode(_n).getChildNode( 0 );
+}
+
+static HXML xmlapiGetNthChild( HXML _n, LPCTSTR name, int i )
+{
+ return XMLNode(_n).getChildNode( name, i );
+}
+
+static HXML xmlapiGetNextChild( HXML _n, LPCTSTR name, int* i )
+{
+ return XMLNode(_n).getChildNode( name, i );
+}
+
+static HXML xmlapiGetNextNode( HXML _n )
+{
+ return XMLNode(_n).getNextNode( );
+}
+
+static HXML xmlapiGetChildByPath( HXML _n, LPCTSTR path, char createNodeIfMissing )
+{
+ return XMLNode(_n).getChildNodeByPath( path, createNodeIfMissing );
+}
+
+static LPCTSTR xmlapiGetName( HXML _n )
+{
+ return XMLNode(_n).getName();
+}
+
+static HXML xmlapiGetParent( HXML _n )
+{
+ return XMLNode(_n).getParentNode();
+}
+
+static LPCTSTR xmlapiGetText( HXML _n )
+{
+ return XMLNode(_n).getInnerText();
+}
+
+static LPCTSTR xmlapiGetAttrValue( HXML _n, LPCTSTR attrName )
+{
+ return XMLNode(_n).getAttribute( attrName );
+}
+
+static void xmlapiSetText( HXML _n, LPCTSTR _text )
+{
+ XMLNode(_n).updateText( _text );
+}
+
+static LPTSTR xmlapiToString( HXML _n, int* datalen )
+{
+ return XMLNode(_n).createXMLString( 0, datalen );
+}
+
+static void xmlapiAddAttr( HXML _n, LPCTSTR attrName, LPCTSTR attrValue )
+{
+ if ( attrName != NULL && attrValue != NULL )
+ XMLNode(_n).addAttribute( attrName, attrValue );
+}
+
+static void xmlapiAddAttrInt( HXML _n, LPCTSTR attrName, int attrValue )
+{
+ TCHAR buf[40];
+ _itot( attrValue, buf, 10 );
+ XMLNode(_n).addAttribute( attrName, buf );
+}
+
+static void xmlapiFree( void* p )
+{
+ free( p );
+}
+
+// XML API v2 methods
+static int xmlapiGetTextCount( HXML _n )
+{
+ return XMLNode(_n).nText();
+}
+
+static LPCTSTR xmlapiGetTextByIndex( HXML _n, int i )
+{
+ return XMLNode(_n).getText( i );
+}
+
+static void xmlapiSetTextByIndex( HXML _n, int i, LPCTSTR value )
+{
+ XMLNode(_n).updateText( value, i );
+}
+
+static void xmlapiAddText( HXML _n, LPCTSTR value, XML_ELEMENT_POS pos )
+{
+ XMLNode(_n).addText( value, ( XMLElementPosition )pos );
+}
+
+static LPTSTR xmlapiToStringWithFormatting( HXML _n, int* datalen )
+{
+ return XMLNode(_n).createXMLString( 1, datalen );
+}
+
+static int xmlapiGetClearCount( HXML _n )
+{
+ return XMLNode(_n).nClear();
+}
+
+static LPCTSTR xmlapiGetClear( HXML _n, int i, LPCTSTR *openTag, LPCTSTR *closeTag )
+{
+ XMLClear c = XMLNode(_n).getClear( i );
+ if ( openTag )
+ *openTag = c.lpszOpenTag;
+ if ( closeTag )
+ *closeTag = c.lpszCloseTag;
+ return c.lpszValue;
+}
+
+static void xmlapiAddClear( HXML _n, LPCTSTR lpszValue, LPCTSTR openTag, LPCTSTR closeTag, XML_ELEMENT_POS pos )
+{
+ XMLNode(_n).addClear( lpszValue, openTag, closeTag, ( XMLElementPosition )pos );
+}
+
+static void xmlapiSetClear( HXML _n, int i, LPCTSTR lpszValue )
+{
+ XMLNode(_n).updateClear( lpszValue, i );
+}
+
+static int xmlapiGetElement( HXML _n, XML_ELEMENT_POS pos, XML_ELEMENT_TYPE *type, HXML *child, LPCTSTR *value, LPCTSTR *name, LPCTSTR *openTag, LPCTSTR *closeTag )
+{
+ // reset all values
+ if ( child )
+ *child = NULL;
+ if ( value )
+ *value = NULL;
+ if ( name )
+ *name = NULL;
+ if ( openTag )
+ *openTag = NULL;
+ if ( closeTag )
+ *closeTag = NULL;
+
+ if ( !type || pos >= XMLNode(_n).nElement())
+ return false;
+ XMLNodeContents c( XMLNode(_n).enumContents( ( XMLElementPosition )pos ));
+ switch ( c.etype ) {
+ case eNodeChild:
+ {
+ *type = XML_ELEM_TYPE_CHILD;
+ if ( child )
+ *child = c.child;
+ } break;
+ case eNodeAttribute:
+ {
+ *type = XML_ELEM_TYPE_ATTRIBUTE;
+ if ( name )
+ *name = c.attrib.lpszName;
+ if ( value )
+ *value = c.attrib.lpszValue;
+ } break;
+ case eNodeText:
+ {
+ *type = XML_ELEM_TYPE_TEXT;
+ if ( value )
+ *value = c.text;
+ } break;
+ case eNodeClear:
+ {
+ *type = XML_ELEM_TYPE_CLEAR;
+ if ( value )
+ *value = c.clear.lpszValue;
+ if ( openTag )
+ *openTag = c.clear.lpszOpenTag;
+ if ( closeTag )
+ *closeTag = c.clear.lpszCloseTag;
+ } break;
+ case eNodeNULL:
+ {
+ return false;
+ } break;
+ }
+ return true;
+}
+
+static int xmlapiGetElementCount( HXML _n )
+{
+ return XMLNode(_n).nElement();
+}
+
+static char xmlapiIsDeclaration( HXML _n )
+{
+ return XMLNode(_n).isDeclaration();
+}
+
+static HXML xmlapiDeepCopy( HXML _n )
+{
+ return XMLNode(_n).deepCopy().detach();
+}
+
+static HXML xmlapiAddChildEx( HXML _n, LPCTSTR name, char isDeclaration, XML_ELEMENT_POS pos )
+{
+ return XMLNode(_n).addChild( name, isDeclaration, ( XMLElementPosition )pos );
+}
+
+static void xmlapiAddChildEx2( HXML _n, HXML parent, XML_ELEMENT_POS pos )
+{
+ XMLNode(_n).addChild( parent, ( XMLElementPosition )pos );
+}
+
+static void xmlapiSetAttrByIndex( HXML _n, int i, LPCTSTR value )
+{
+ XMLNode(_n).updateAttribute( value, NULL, i );
+}
+
+static void xmlapiSetAttrByName( HXML _n, LPCTSTR name, LPCTSTR value )
+{
+ XMLNode(_n).updateAttribute( value, NULL, name );
+}
+
+static void xmlapiDeleteNodeContent( HXML _n )
+{
+ XMLNode(_n).deleteNodeContent();
+}
+
+static void xmlapiDeleteAttrByIndex( HXML _n, int i )
+{
+ XMLNode(_n).deleteAttribute( i );
+}
+
+static void xmlapiDeleteAttrByName( HXML _n, LPCTSTR name )
+{
+ XMLNode(_n).deleteAttribute( name );
+}
+
+static void xmlapiDeleteText( HXML _n, int i )
+{
+ XMLNode(_n).deleteText( i );
+}
+
+static void xmlapiDeleteClear( HXML _n, int i )
+{
+ XMLNode(_n).deleteClear( i );
+}
+
+static XML_ELEMENT_POS xmlapiPositionOfText( HXML _n, int i )
+{
+ return ( XML_ELEMENT_POS )XMLNode(_n).positionOfText( i );
+}
+
+static XML_ELEMENT_POS xmlapiPositionOfClear( HXML _n, int i )
+{
+ return ( XML_ELEMENT_POS )XMLNode(_n).positionOfClear( i );
+}
+
+static XML_ELEMENT_POS xmlapiPositionOfChildByIndex( HXML _n, int i )
+{
+ return ( XML_ELEMENT_POS )XMLNode(_n).positionOfChildNode( i );
+}
+
+static XML_ELEMENT_POS xmlapiPositionOfChildByNode( HXML _n, HXML child )
+{
+ return ( XML_ELEMENT_POS )XMLNode(_n).positionOfChildNode( child );
+}
+
+static XML_ELEMENT_POS xmlapiPositionOfChildByName( HXML _n, LPCTSTR name, int i )
+{
+ return ( XML_ELEMENT_POS )XMLNode(_n).positionOfChildNode( name, i );
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static INT_PTR GetXmlApi( WPARAM, LPARAM lParam )
+{
+ XML_API* xi = ( XML_API* )lParam;
+ if ( xi == NULL )
+ return FALSE;
+
+ if ( xi->cbSize != XML_API_SIZEOF_V1 && xi->cbSize != sizeof(XML_API))
+ return FALSE;
+
+ xi->createNode = xmlapiCreateNode;
+ xi->destroyNode = xmlapiDestroyNode;
+
+ xi->parseString = xmlapiParseString;
+ xi->toString = xmlapiToString;
+ xi->freeMem = xmlapiFree;
+
+ xi->addChild = xmlapiAddChild;
+ xi->addChild2 = xmlapiAddChild2;
+ xi->copyNode = xmlapiCopyNode;
+ xi->getChild = xmlapiGetChild;
+ xi->getChildByAttrValue = xmlapiGetChildByAttrValue;
+ xi->getChildCount = xmlapiGetChildCount;
+ xi->getFirstChild = xmlapiGetFirstChild;
+ xi->getNthChild = xmlapiGetNthChild;
+ xi->getNextChild = xmlapiGetNextChild;
+ xi->getNextNode = xmlapiGetNextNode;
+ xi->getChildByPath = xmlapiGetChildByPath;
+ xi->getName = xmlapiGetName;
+ xi->getParent = xmlapiGetParent;
+ xi->getText = xmlapiGetText;
+ xi->setText = xmlapiSetText;
+
+ xi->getAttr = xmlapiGetAttr;
+ xi->getAttrCount = xmlapiGetAttrCount;
+ xi->getAttrName = xmlapiGetAttrName;
+ xi->getAttrValue = xmlapiGetAttrValue;
+ xi->addAttr = xmlapiAddAttr;
+ xi->addAttrInt = xmlapiAddAttrInt;
+
+ if ( xi->cbSize > XML_API_SIZEOF_V1 ) {
+ xi->isDeclaration = xmlapiIsDeclaration;
+ xi->toStringWithFormatting = xmlapiToStringWithFormatting;
+ xi->deepCopy = xmlapiDeepCopy;
+ xi->setAttrByIndex = xmlapiSetAttrByIndex;
+ xi->setAttrByName = xmlapiSetAttrByName;
+ xi->addChildEx = xmlapiAddChildEx;
+ xi->addChildEx2 = xmlapiAddChildEx2;
+ xi->getTextCount = xmlapiGetTextCount;
+ xi->getTextByIndex = xmlapiGetTextByIndex;
+ xi->addText = xmlapiAddText;
+ xi->setTextByIndex = xmlapiSetTextByIndex;
+ xi->getClearCount = xmlapiGetClearCount;
+ xi->getClear = xmlapiGetClear;
+ xi->addClear = xmlapiAddClear;
+ xi->setClear = xmlapiSetClear;
+ xi->getElementCount = xmlapiGetElementCount;
+ xi->getElement = xmlapiGetElement;
+
+ xi->deleteNodeContent = xmlapiDeleteNodeContent;
+ xi->deleteAttrByIndex = xmlapiDeleteAttrByIndex;
+ xi->deleteAttrByName = xmlapiDeleteAttrByName;
+ xi->deleteText = xmlapiDeleteText;
+ xi->deleteClear = xmlapiDeleteClear;
+
+ xi->positionOfChildByIndex = xmlapiPositionOfChildByIndex;
+ xi->positionOfChildByNode = xmlapiPositionOfChildByNode;
+ xi->positionOfChildByName = xmlapiPositionOfChildByName;
+ xi->positionOfText = xmlapiPositionOfText;
+ xi->positionOfClear = xmlapiPositionOfClear;
+ }
+ return TRUE;
+}
+
+void InitXmlApi( void )
+{
+ CreateServiceFunction( MS_SYSTEM_GET_XI, GetXmlApi );
+}
diff --git a/src/modules/xml/xmlParser.cpp b/src/modules/xml/xmlParser.cpp
new file mode 100644
index 0000000000..f2afae563f
--- /dev/null
+++ b/src/modules/xml/xmlParser.cpp
@@ -0,0 +1,3061 @@
+/**
+****************************************************************************
+* <P> XML.c - implementation file for basic XML parser written in ANSI C++
+* for portability. It works by using recursion and a node tree for breaking
+* down the elements of an XML document. </P>
+*
+* @version V2.43
+* @author Frank Vanden Berghen
+*
+* NOTE:
+*
+* If you add "#define STRICT_PARSING", on the first line of this file
+* the parser will see the following XML-stream:
+* <a><b>some text</b><b>other text </a>
+* as an error. Otherwise, this tring will be equivalent to:
+* <a><b>some text</b><b>other text</b></a>
+*
+* NOTE:
+*
+* If you add "#define APPROXIMATE_PARSING" on the first line of this file
+* the parser will see the following XML-stream:
+* <data name="n1">
+* <data name="n2">
+* <data name="n3" />
+* as equivalent to the following XML-stream:
+* <data name="n1" />
+* <data name="n2" />
+* <data name="n3" />
+* This can be useful for badly-formed XML-streams but prevent the use
+* of the following XML-stream (problem is: tags at contiguous levels
+* have the same names):
+* <data name="n1">
+* <data name="n2">
+* <data name="n3" />
+* </data>
+* </data>
+*
+* NOTE:
+*
+* If you add "#define _XMLPARSER_NO_MESSAGEBOX_" on the first line of this file
+* the "openFileHelper" function will always display error messages inside the
+* console instead of inside a message-box-window. Message-box-windows are
+* available on windows 9x/NT/2000/XP/Vista only.
+*
+* Copyright (c) 2002, Business-Insight
+* <a href="http://www.Business-Insight.com">Business-Insight</a>
+* All rights reserved.
+* See the file "AFPL-license.txt" about the licensing terms
+*
+****************************************************************************
+*/
+
+#include "commonheaders.h"
+#include "xmlParser.h"
+
+#include <memory.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+XMLCSTR XMLNode::getVersion() { return _CXML("v2.43"); }
+void freeXMLString(XMLSTR t){if(t)free(t);}
+
+static XMLNode::XMLCharEncoding characterEncoding=XMLNode::char_encoding_UTF8;
+static char guessWideCharChars=1, dropWhiteSpace=1, removeCommentsInMiddleOfText=1;
+
+inline int mmin( const int t1, const int t2 ) { return t1 < t2 ? t1 : t2; }
+
+// You can modify the initialization of the variable "XMLClearTags" below
+// to change the clearTags that are currently recognized by the library.
+// The number on the second columns is the length of the string inside the
+// first column.
+// The "<!DOCTYPE" declaration must be the second in the list.
+// The "<!--" declaration must be the third in the list.
+// All ClearTag Strings must start with the '<' character.
+typedef struct { XMLCSTR lpszOpen; int openTagLen; XMLCSTR lpszClose;} ALLXMLClearTag;
+static ALLXMLClearTag XMLClearTags[] =
+{
+ { _CXML("<![CDATA["),9, _CXML("]]>") },
+ { _CXML("<!DOCTYPE"),9, _CXML(">") },
+ { _CXML("<!--") ,4, _CXML("-->") },
+ { _CXML("<PRE>") ,5, _CXML("</PRE>") },
+ // { _CXML("<Script>") ,8, _CXML("</Script>")},
+ { NULL ,0, NULL }
+};
+
+// You can modify the initialization of the variable "XMLEntities" below
+// to change the character entities that are currently recognized by the library.
+// The number on the second columns is the length of the string inside the
+// first column. Additionally, the syntaxes "&#xA0;" and "&#160;" are recognized.
+typedef struct { XMLCSTR s; int l; XMLCHAR c;} XMLCharacterEntity;
+static XMLCharacterEntity XMLEntities[] =
+{
+ { _CXML("&amp;" ), 5, _CXML('&' )},
+ { _CXML("&lt;" ), 4, _CXML('<' )},
+ { _CXML("&gt;" ), 4, _CXML('>' )},
+ { _CXML("&quot;"), 6, _CXML('\"')},
+ { _CXML("&apos;"), 6, _CXML('\'')},
+ { NULL , 0, '\0' }
+};
+
+// When rendering the XMLNode to a string (using the "createXMLString" function),
+// you can ask for a beautiful formatting. This formatting is using the
+// following indentation character:
+#define INDENTCHAR _CXML('\t')
+
+// The following function parses the XML errors into a user friendly string.
+// You can edit this to change the output language of the library to something else.
+XMLCSTR XMLNode::getError(XMLError xerror)
+{
+ switch (xerror)
+ {
+ case eXMLErrorNone: return _CXML("No error");
+ case eXMLErrorMissingEndTag: return _CXML("Warning: Unmatched end tag");
+ case eXMLErrorNoXMLTagFound: return _CXML("Warning: No XML tag found");
+ case eXMLErrorEmpty: return _CXML("Error: No XML data");
+ case eXMLErrorMissingTagName: return _CXML("Error: Missing start tag name");
+ case eXMLErrorMissingEndTagName: return _CXML("Error: Missing end tag name");
+ case eXMLErrorUnmatchedEndTag: return _CXML("Error: Unmatched end tag");
+ case eXMLErrorUnmatchedEndClearTag: return _CXML("Error: Unmatched clear tag end");
+ case eXMLErrorUnexpectedToken: return _CXML("Error: Unexpected token found");
+ case eXMLErrorNoElements: return _CXML("Error: No elements found");
+ case eXMLErrorFileNotFound: return _CXML("Error: File not found");
+ case eXMLErrorFirstTagNotFound: return _CXML("Error: First Tag not found");
+ case eXMLErrorUnknownCharacterEntity:return _CXML("Error: Unknown character entity");
+ case eXMLErrorCharacterCodeAbove255: return _CXML("Error: Character code above 255 is forbidden in MultiByte char mode.");
+ case eXMLErrorCharConversionError: return _CXML("Error: unable to convert between WideChar and MultiByte chars");
+ case eXMLErrorCannotOpenWriteFile: return _CXML("Error: unable to open file for writing");
+ case eXMLErrorCannotWriteFile: return _CXML("Error: cannot write into file");
+
+ case eXMLErrorBase64DataSizeIsNotMultipleOf4: return _CXML("Warning: Base64-string length is not a multiple of 4");
+ case eXMLErrorBase64DecodeTruncatedData: return _CXML("Warning: Base64-string is truncated");
+ case eXMLErrorBase64DecodeIllegalCharacter: return _CXML("Error: Base64-string contains an illegal character");
+ case eXMLErrorBase64DecodeBufferTooSmall: return _CXML("Error: Base64 decode output buffer is too small");
+ };
+ return _CXML("Unknown");
+}
+
+/////////////////////////////////////////////////////////////////////////
+// Here start the abstraction layer to be OS-independent //
+/////////////////////////////////////////////////////////////////////////
+
+// Here is an abstraction layer to access some common string manipulation functions.
+// The abstraction layer is currently working for gcc, Microsoft Visual Studio 6.0,
+// Microsoft Visual Studio .NET, CC (sun compiler) and Borland C++.
+// If you plan to "port" the library to a new system/compiler, all you have to do is
+// to edit the following lines.
+#ifdef XML_NO_WIDE_CHAR
+char myIsTextWideChar(const void *b, int len) { return FALSE; }
+#else
+#if defined (UNDER_CE) || !defined(_XMLWINDOWS)
+char myIsTextWideChar(const void *b, int len) // inspired by the Wine API: RtlIsTextUnicode
+{
+#ifdef sun
+ // for SPARC processors: wchar_t* buffers must always be alligned, otherwise it's a char* buffer.
+ if ((((unsigned long)b)%sizeof(wchar_t))!=0) return FALSE;
+#endif
+ const wchar_t *s=(const wchar_t*)b;
+
+ // buffer too small:
+ if (len<(int)sizeof(wchar_t)) return FALSE;
+
+ // odd length test
+ if (len&1) return FALSE;
+
+ /* only checks the first 256 characters */
+ len=mmin(256,len/sizeof(wchar_t));
+
+ // Check for the special byte order:
+ if (*((unsigned short*)s) == 0xFFFE) return TRUE; // IS_TEXT_UNICODE_REVERSE_SIGNATURE;
+ if (*((unsigned short*)s) == 0xFEFF) return TRUE; // IS_TEXT_UNICODE_SIGNATURE
+
+ // checks for ASCII characters in the UNICODE stream
+ int i,stats=0;
+ for (i=0; i<len; i++) if (s[i]<=(unsigned short)255) stats++;
+ if (stats>len/2) return TRUE;
+
+ // Check for UNICODE NULL chars
+ for (i=0; i<len; i++) if (!s[i]) return TRUE;
+
+ return FALSE;
+}
+#else
+char myIsTextWideChar(const void *b,int l) { return (char)IsTextUnicode((CONST LPVOID)b,l,NULL); }
+#endif
+#endif
+
+#ifdef _XMLWINDOWS
+// for Microsoft Visual Studio 6.0 and Microsoft Visual Studio .NET and Borland C++ Builder 6.0
+#ifdef _XMLWIDECHAR
+wchar_t *myMultiByteToWideChar(const char *s, XMLNode::XMLCharEncoding ce)
+{
+ int i;
+ if (ce==XMLNode::char_encoding_UTF8) i=(int)MultiByteToWideChar(CP_UTF8,0 ,s,-1,NULL,0);
+ else i=(int)MultiByteToWideChar(CP_ACP ,MB_PRECOMPOSED,s,-1,NULL,0);
+ if (i<0) return NULL;
+ wchar_t *d=(wchar_t *)malloc((i+1)*sizeof(XMLCHAR));
+ if (ce==XMLNode::char_encoding_UTF8) i=(int)MultiByteToWideChar(CP_UTF8,0 ,s,-1,d,i);
+ else i=(int)MultiByteToWideChar(CP_ACP ,MB_PRECOMPOSED,s,-1,d,i);
+ d[i]=0;
+ return d;
+}
+static inline FILE *xfopen(XMLCSTR filename,XMLCSTR mode) { return _wfopen(filename,mode); }
+static inline int xstrlen(XMLCSTR c) { return (int)wcslen(c); }
+static inline int xstrnicmp(XMLCSTR c1, XMLCSTR c2, int l) { return _wcsnicmp(c1,c2,l);}
+static inline int xstrncmp(XMLCSTR c1, XMLCSTR c2, int l) { return wcsncmp(c1,c2,l);}
+static inline int xstricmp(XMLCSTR c1, XMLCSTR c2) { return _wcsicmp(c1,c2); }
+static inline XMLSTR xstrstr(XMLCSTR c1, XMLCSTR c2) { return (XMLSTR)wcsstr(c1,c2); }
+static inline XMLSTR xstrcpy(XMLSTR c1, XMLCSTR c2) { return (XMLSTR)wcscpy(c1,c2); }
+#else
+char *myWideCharToMultiByte(const wchar_t *s)
+{
+ UINT codePage=CP_ACP; if (characterEncoding==XMLNode::char_encoding_UTF8) codePage=CP_UTF8;
+ int i=(int)WideCharToMultiByte(codePage, // code page
+ 0, // performance and mapping flags
+ s, // wide-character string
+ -1, // number of chars in string
+ NULL, // buffer for new string
+ 0, // size of buffer
+ NULL, // default for unmappable chars
+ NULL // set when default char used
+ );
+ if (i<0) return NULL;
+ char *d=(char*)malloc(i+1);
+ WideCharToMultiByte(codePage, // code page
+ 0, // performance and mapping flags
+ s, // wide-character string
+ -1, // number of chars in string
+ d, // buffer for new string
+ i, // size of buffer
+ NULL, // default for unmappable chars
+ NULL // set when default char used
+ );
+ d[i]=0;
+ return d;
+}
+static inline FILE *xfopen(XMLCSTR filename,XMLCSTR mode) { return fopen(filename,mode); }
+static inline int xstrlen(XMLCSTR c) { return (int)strlen(c); }
+#ifdef __BORLANDC__
+static inline int xstrnicmp(XMLCSTR c1, XMLCSTR c2, int l) { return strnicmp(c1,c2,l);}
+static inline int xstricmp(XMLCSTR c1, XMLCSTR c2) { return stricmp(c1,c2); }
+#else
+static inline int xstrnicmp(XMLCSTR c1, XMLCSTR c2, int l) { return _strnicmp(c1,c2,l);}
+static inline int xstricmp(XMLCSTR c1, XMLCSTR c2) { return _stricmp(c1,c2); }
+#endif
+static inline int xstrncmp(XMLCSTR c1, XMLCSTR c2, int l) { return strncmp(c1,c2,l);}
+static inline XMLSTR xstrstr(XMLCSTR c1, XMLCSTR c2) { return (XMLSTR)strstr(c1,c2); }
+static inline XMLSTR xstrcpy(XMLSTR c1, XMLCSTR c2) { return (XMLSTR)strcpy(c1,c2); }
+#endif
+#else
+// for gcc and CC
+#ifdef XML_NO_WIDE_CHAR
+char *myWideCharToMultiByte(const wchar_t *s) { return NULL; }
+#else
+char *myWideCharToMultiByte(const wchar_t *s)
+{
+ const wchar_t *ss=s;
+ int i=(int)wcsrtombs(NULL,&ss,0,NULL);
+ if (i<0) return NULL;
+ char *d=(char *)malloc(i+1);
+ wcsrtombs(d,&s,i,NULL);
+ d[i]=0;
+ return d;
+}
+#endif
+#ifdef _XMLWIDECHAR
+wchar_t *myMultiByteToWideChar(const char *s, XMLNode::XMLCharEncoding ce)
+{
+ const char *ss=s;
+ int i=(int)mbsrtowcs(NULL,&ss,0,NULL);
+ if (i<0) return NULL;
+ wchar_t *d=(wchar_t *)malloc((i+1)*sizeof(wchar_t));
+ mbsrtowcs(d,&s,i,NULL);
+ d[i]=0;
+ return d;
+}
+int xstrlen(XMLCSTR c) { return wcslen(c); }
+#ifdef sun
+// for CC
+#include <widec.h>
+static inline int xstrnicmp(XMLCSTR c1, XMLCSTR c2, int l) { return wsncasecmp(c1,c2,l);}
+static inline int xstrncmp(XMLCSTR c1, XMLCSTR c2, int l) { return wsncmp(c1,c2,l);}
+static inline int xstricmp(XMLCSTR c1, XMLCSTR c2) { return wscasecmp(c1,c2); }
+#else
+static inline int xstrncmp(XMLCSTR c1, XMLCSTR c2, int l) { return wcsncmp(c1,c2,l);}
+#ifdef __linux__
+// for gcc/linux
+static inline int xstrnicmp(XMLCSTR c1, XMLCSTR c2, int l) { return wcsncasecmp(c1,c2,l);}
+static inline int xstricmp(XMLCSTR c1, XMLCSTR c2) { return wcscasecmp(c1,c2); }
+#else
+#include <wctype.h>
+// for gcc/non-linux (MacOS X 10.3, FreeBSD 6.0, NetBSD 3.0, OpenBSD 3.8, AIX 4.3.2, HP-UX 11, IRIX 6.5, OSF/1 5.1, Cygwin, mingw)
+static inline int xstricmp(XMLCSTR c1, XMLCSTR c2)
+{
+ wchar_t left,right;
+ do
+ {
+ left=towlower(*c1++); right=towlower(*c2++);
+ } while (left&&(left==right));
+ return (int)left-(int)right;
+}
+static inline int xstrnicmp(XMLCSTR c1, XMLCSTR c2, int l)
+{
+ wchar_t left,right;
+ while(l--)
+ {
+ left=towlower(*c1++); right=towlower(*c2++);
+ if ((!left)||(left!=right)) return (int)left-(int)right;
+ }
+ return 0;
+}
+#endif
+#endif
+static inline XMLSTR xstrstr(XMLCSTR c1, XMLCSTR c2) { return (XMLSTR)wcsstr(c1,c2); }
+static inline XMLSTR xstrcpy(XMLSTR c1, XMLCSTR c2) { return (XMLSTR)wcscpy(c1,c2); }
+static inline FILE *xfopen(XMLCSTR filename,XMLCSTR mode)
+{
+ char *filenameAscii=myWideCharToMultiByte(filename);
+ FILE *f;
+ if (mode[0]==_CXML('r')) f=fopen(filenameAscii,"rb");
+ else f=fopen(filenameAscii,"wb");
+ free(filenameAscii);
+ return f;
+}
+#else
+static inline FILE *xfopen(XMLCSTR filename,XMLCSTR mode) { return fopen(filename,mode); }
+static inline int xstrlen(XMLCSTR c) { return strlen(c); }
+static inline int xstrnicmp(XMLCSTR c1, XMLCSTR c2, int l) { return strncasecmp(c1,c2,l);}
+static inline int xstrncmp(XMLCSTR c1, XMLCSTR c2, int l) { return strncmp(c1,c2,l);}
+static inline int xstricmp(XMLCSTR c1, XMLCSTR c2) { return strcasecmp(c1,c2); }
+static inline XMLSTR xstrstr(XMLCSTR c1, XMLCSTR c2) { return (XMLSTR)strstr(c1,c2); }
+static inline XMLSTR xstrcpy(XMLSTR c1, XMLCSTR c2) { return (XMLSTR)strcpy(c1,c2); }
+#endif
+static inline int _strnicmp(const char *c1,const char *c2, int l) { return strncasecmp(c1,c2,l);}
+#endif
+
+
+///////////////////////////////////////////////////////////////////////////////
+// the "xmltoc,xmltob,xmltoi,xmltol,xmltof,xmltoa" functions //
+///////////////////////////////////////////////////////////////////////////////
+// These 6 functions are not used inside the XMLparser.
+// There are only here as "convenience" functions for the user.
+// If you don't need them, you can delete them without any trouble.
+#ifdef _XMLWIDECHAR
+#ifdef _XMLWINDOWS
+// for Microsoft Visual Studio 6.0 and Microsoft Visual Studio .NET and Borland C++ Builder 6.0
+char xmltob(XMLCSTR t,char v){ if (t&&(*t)) return (char)_wtoi(t); return v; }
+int xmltoi(XMLCSTR t,int v){ if (t&&(*t)) return _wtoi(t); return v; }
+long xmltol(XMLCSTR t,long v){ if (t&&(*t)) return _wtol(t); return v; }
+double xmltof(XMLCSTR t,double v){ if (t&&(*t)) swscanf(t, L"%lf", &v); /*v=_wtof(t);*/ return v; }
+#else
+#ifdef sun
+// for CC
+#include <widec.h>
+char xmltob(XMLCSTR t,char v){ if (t) return (char)wstol(t,NULL,10); return v; }
+int xmltoi(XMLCSTR t,int v){ if (t) return (int)wstol(t,NULL,10); return v; }
+long xmltol(XMLCSTR t,long v){ if (t) return wstol(t,NULL,10); return v; }
+#else
+// for gcc
+char xmltob(XMLCSTR t,char v){ if (t) return (char)wcstol(t,NULL,10); return v; }
+int xmltoi(XMLCSTR t,int v){ if (t) return (int)wcstol(t,NULL,10); return v; }
+long xmltol(XMLCSTR t,long v){ if (t) return wcstol(t,NULL,10); return v; }
+#endif
+double xmltof(XMLCSTR t,double v){ if (t&&(*t)) swscanf(t, L"%lf", &v); /*v=_wtof(t);*/ return v; }
+#endif
+#else
+char xmltob(XMLCSTR t,char v){ if (t&&(*t)) return (char)atoi(t); return v; }
+int xmltoi(XMLCSTR t,int v){ if (t&&(*t)) return atoi(t); return v; }
+long xmltol(XMLCSTR t,long v){ if (t&&(*t)) return atol(t); return v; }
+double xmltof(XMLCSTR t,double v){ if (t&&(*t)) return atof(t); return v; }
+#endif
+XMLCSTR xmltoa(XMLCSTR t,XMLCSTR v){ if (t) return t; return v; }
+XMLCHAR xmltoc(XMLCSTR t,const XMLCHAR v){ if (t&&(*t)) return *t; return v; }
+
+/////////////////////////////////////////////////////////////////////////
+// the "openFileHelper" function //
+/////////////////////////////////////////////////////////////////////////
+
+// Since each application has its own way to report and deal with errors, you should modify & rewrite
+// the following "openFileHelper" function to get an "error reporting mechanism" tailored to your needs.
+XMLNode XMLNode::openFileHelper(XMLCSTR filename, XMLCSTR tag)
+{
+ // guess the value of the global parameter "characterEncoding"
+ // (the guess is based on the first 200 bytes of the file).
+ FILE *f=xfopen(filename,_CXML("rb"));
+ if (f)
+ {
+ char bb[205];
+ int l=(int)fread(bb,1,200,f);
+ setGlobalOptions(guessCharEncoding(bb,l),guessWideCharChars,dropWhiteSpace,removeCommentsInMiddleOfText);
+ fclose(f);
+ }
+
+ // parse the file
+ XMLResults pResults;
+ XMLNode xnode=XMLNode::parseFile(filename,tag,&pResults);
+
+ // display error message (if any)
+ if (pResults.error != eXMLErrorNone)
+ {
+ // create message
+ char message[2000],*s1=(char*)"",*s3=(char*)""; XMLCSTR s2=_CXML("");
+ if (pResults.error==eXMLErrorFirstTagNotFound) { s1=(char*)"First Tag should be '"; s2=tag; s3=(char*)"'.\n"; }
+ sprintf(message,
+#ifdef _XMLWIDECHAR
+ "XML Parsing error inside file '%S'.\n%S\nAt line %i, column %i.\n%s%S%s"
+#else
+ "XML Parsing error inside file '%s'.\n%s\nAt line %i, column %i.\n%s%s%s"
+#endif
+ ,filename,XMLNode::getError(pResults.error),pResults.nLine,pResults.nColumn,s1,s2,s3);
+
+ // display message
+#if defined(_XMLWINDOWS) && !defined(UNDER_CE) && !defined(_XMLPARSER_NO_MESSAGEBOX_)
+ MessageBoxA(NULL,message,"XML Parsing error",MB_OK|MB_ICONERROR|MB_TOPMOST);
+#else
+ printf("%s",message);
+#endif
+ exit(255);
+ }
+ return xnode;
+}
+
+/////////////////////////////////////////////////////////////////////////
+// Here start the core implementation of the XMLParser library //
+/////////////////////////////////////////////////////////////////////////
+
+// You should normally not change anything below this point.
+
+#ifndef _XMLWIDECHAR
+// If "characterEncoding=ascii" then we assume that all characters have the same length of 1 byte.
+// If "characterEncoding=UTF8" then the characters have different lengths (from 1 byte to 4 bytes).
+// If "characterEncoding=ShiftJIS" then the characters have different lengths (from 1 byte to 2 bytes).
+// This table is used as lookup-table to know the length of a character (in byte) based on the
+// content of the first byte of the character.
+// (note: if you modify this, you must always have XML_utf8ByteTable[0]=0 ).
+static const char XML_utf8ByteTable[256] =
+{
+ // 0 1 2 3 4 5 6 7 8 9 a b c d e f
+ 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x00
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x10
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x20
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x30
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x40
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x50
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x60
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x70 End of ASCII range
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x80 0x80 to 0xc1 invalid
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x90
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0xa0
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0xb0
+ 1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,// 0xc0 0xc2 to 0xdf 2 byte
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,// 0xd0
+ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,// 0xe0 0xe0 to 0xef 3 byte
+ 4,4,4,4,4,1,1,1,1,1,1,1,1,1,1,1 // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid
+};
+static const char XML_legacyByteTable[256] =
+{
+ 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
+};
+static const char XML_sjisByteTable[256] =
+{
+ // 0 1 2 3 4 5 6 7 8 9 a b c d e f
+ 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x00
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x10
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x20
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x30
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x40
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x50
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x60
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x70
+ 1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,// 0x80 0x81 to 0x9F 2 bytes
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,// 0x90
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0xa0
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0xb0
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0xc0
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0xd0
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,// 0xe0 0xe0 to 0xef 2 bytes
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 // 0xf0
+};
+static const char XML_gb2312ByteTable[256] =
+{
+ // 0 1 2 3 4 5 6 7 8 9 a b c d e f
+ 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x00
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x10
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x20
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x30
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x40
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x50
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x60
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x70
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x80
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x90
+ 1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,// 0xa0 0xa1 to 0xf7 2 bytes
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,// 0xb0
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,// 0xc0
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,// 0xd0
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,// 0xe0
+ 2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1 // 0xf0
+};
+static const char XML_gbk_big5_ByteTable[256] =
+{
+ // 0 1 2 3 4 5 6 7 8 9 a b c d e f
+ 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x00
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x10
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x20
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x30
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x40
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x50
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x60
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,// 0x70
+ 1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,// 0x80 0x81 to 0xfe 2 bytes
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,// 0x90
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,// 0xa0
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,// 0xb0
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,// 0xc0
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,// 0xd0
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,// 0xe0
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1 // 0xf0
+};
+static const char *XML_ByteTable=(const char *)XML_utf8ByteTable; // the default is "characterEncoding=XMLNode::encoding_UTF8"
+#endif
+
+
+XMLNode XMLNode::emptyXMLNode;
+XMLClear XMLNode::emptyXMLClear={ NULL, NULL, NULL};
+XMLAttribute XMLNode::emptyXMLAttribute={ NULL, NULL};
+
+// Enumeration used to decipher what type a token is
+typedef enum XMLTokenTypeTag
+{
+ eTokenText = 0,
+ eTokenQuotedText,
+ eTokenTagStart, /* "<" */
+ eTokenTagEnd, /* "</" */
+ eTokenCloseTag, /* ">" */
+ eTokenEquals, /* "=" */
+ eTokenDeclaration, /* "<?" */
+ eTokenShortHandClose, /* "/>" */
+ eTokenClear,
+ eTokenError
+} XMLTokenType;
+
+// Main structure used for parsing XML
+typedef struct XML
+{
+ XMLCSTR lpXML;
+ XMLCSTR lpszText;
+ int nIndex,nIndexMissigEndTag;
+ enum XMLError error;
+ XMLCSTR lpEndTag;
+ int cbEndTag;
+ XMLCSTR lpNewElement;
+ int cbNewElement;
+ int nFirst;
+} XML;
+
+typedef struct
+{
+ ALLXMLClearTag *pClr;
+ XMLCSTR pStr;
+} NextToken;
+
+// Enumeration used when parsing attributes
+typedef enum Attrib
+{
+ eAttribName = 0,
+ eAttribEquals,
+ eAttribValue
+} Attrib;
+
+// Enumeration used when parsing elements to dictate whether we are currently
+// inside a tag
+typedef enum XMLStatus
+{
+ eInsideTag = 0,
+ eOutsideTag
+} XMLStatus;
+
+XMLError XMLNode::writeToFile(XMLCSTR filename, const char *encoding, char nFormat) const
+{
+ if (!d) return eXMLErrorNone;
+ FILE *f=xfopen(filename,_CXML("wb"));
+ if (!f) return eXMLErrorCannotOpenWriteFile;
+#ifdef _XMLWIDECHAR
+ unsigned char h[2]={ 0xFF, 0xFE };
+ if (!fwrite(h,2,1,f))
+ {
+ fclose(f);
+ return eXMLErrorCannotWriteFile;
+ }
+ if ((!isDeclaration())&&((d->lpszName)||(!getChildNode().isDeclaration())))
+ {
+ if (!fwrite(L"<?xml version=\"1.0\" encoding=\"utf-16\"?>\n",sizeof(wchar_t)*40,1,f))
+ {
+ fclose(f);
+ return eXMLErrorCannotWriteFile;
+ }
+ }
+#else
+ if ((!isDeclaration())&&((d->lpszName)||(!getChildNode().isDeclaration())))
+ {
+ if (characterEncoding==char_encoding_UTF8)
+ {
+ // header so that windows recognize the file as UTF-8:
+ unsigned char h[3]={0xEF,0xBB,0xBF};
+ if (!fwrite(h,3,1,f))
+ {
+ fclose(f);
+ return eXMLErrorCannotWriteFile;
+ }
+ encoding="utf-8";
+ } else if (characterEncoding==char_encoding_ShiftJIS) encoding="SHIFT-JIS";
+
+ if (!encoding) encoding="ISO-8859-1";
+ if (fprintf(f,"<?xml version=\"1.0\" encoding=\"%s\"?>\n",encoding)<0)
+ {
+ fclose(f);
+ return eXMLErrorCannotWriteFile;
+ }
+ } else
+ {
+ if (characterEncoding==char_encoding_UTF8)
+ {
+ unsigned char h[3]={0xEF,0xBB,0xBF};
+ if (!fwrite(h,3,1,f))
+ {
+ fclose(f);
+ return eXMLErrorCannotWriteFile;
+ }
+ }
+ }
+#endif
+ int i;
+ XMLSTR t=createXMLString(nFormat,&i);
+ if (!fwrite(t,sizeof(XMLCHAR)*i,1,f))
+ {
+ free(t);
+ fclose(f);
+ return eXMLErrorCannotWriteFile;
+ }
+ if (fclose(f)!=0)
+ {
+ free(t);
+ return eXMLErrorCannotWriteFile;
+ }
+ free(t);
+ return eXMLErrorNone;
+}
+
+// Duplicate a given string.
+XMLSTR stringDup(XMLCSTR lpszData, int cbData)
+{
+ if (lpszData==NULL) return NULL;
+
+ XMLSTR lpszNew;
+ if (cbData==-1) cbData=(int)xstrlen(lpszData);
+ lpszNew = (XMLSTR)malloc((cbData+1) * sizeof(XMLCHAR));
+ if (lpszNew)
+ {
+ memcpy(lpszNew, lpszData, (cbData) * sizeof(XMLCHAR));
+ lpszNew[cbData] = (XMLCHAR)NULL;
+ }
+ return lpszNew;
+}
+
+XMLSTR ToXMLStringTool::toXMLUnSafe(XMLSTR dest,XMLCSTR source)
+{
+ XMLSTR dd=dest;
+ XMLCHAR ch;
+ XMLCharacterEntity *entity;
+ while ((ch=*source))
+ {
+ entity=XMLEntities;
+ do
+ {
+ if (ch==entity->c) {xstrcpy(dest,entity->s); dest+=entity->l; source++; goto out_of_loop1; }
+ entity++;
+ } while(entity->s);
+#ifdef _XMLWIDECHAR
+ *(dest++)=*(source++);
+#else
+ switch(XML_ByteTable[(unsigned char)ch])
+ {
+ case 4: *(dest++)=*(source++);
+ case 3: *(dest++)=*(source++);
+ case 2: *(dest++)=*(source++);
+ case 1: *(dest++)=*(source++);
+ }
+#endif
+out_of_loop1:
+ ;
+ }
+ *dest=0;
+ return dd;
+}
+
+// private (used while rendering):
+int ToXMLStringTool::lengthXMLString(XMLCSTR source)
+{
+ int r=0;
+ XMLCharacterEntity *entity;
+ XMLCHAR ch;
+ while ((ch=*source))
+ {
+ entity=XMLEntities;
+ do
+ {
+ if (ch==entity->c) { r+=entity->l; source++; goto out_of_loop1; }
+ entity++;
+ } while(entity->s);
+#ifdef _XMLWIDECHAR
+ r++; source++;
+#else
+ ch=XML_ByteTable[(unsigned char)ch]; r+=ch; source+=ch;
+#endif
+out_of_loop1:
+ ;
+ }
+ return r;
+}
+
+ToXMLStringTool::~ToXMLStringTool(){ freeBuffer(); }
+void ToXMLStringTool::freeBuffer(){ if (buf) free(buf); buf=NULL; buflen=0; }
+XMLSTR ToXMLStringTool::toXML(XMLCSTR source)
+{
+ if (!source)
+ {
+ if (buflen<1) { buflen=1; buf=(XMLSTR)malloc(sizeof(XMLCHAR)); }
+ *buf=0;
+ return buf;
+ }
+ int l=lengthXMLString(source)+1;
+ if (l>buflen) { freeBuffer(); buflen=l; buf=(XMLSTR)malloc(l*sizeof(XMLCHAR)); }
+ return toXMLUnSafe(buf,source);
+}
+
+// private:
+XMLSTR fromXMLString(XMLCSTR s, int lo, XML *pXML)
+{
+ // This function is the opposite of the function "toXMLString". It decodes the escape
+ // sequences &amp;, &quot;, &apos;, &lt;, &gt; and replace them by the characters
+ // &,",',<,>. This function is used internally by the XML Parser. All the calls to
+ // the XML library will always gives you back "decoded" strings.
+ //
+ // in: string (s) and length (lo) of string
+ // out: new allocated string converted from xml
+ if (!s) return NULL;
+
+ int ll=0,j;
+ XMLSTR d;
+ XMLCSTR ss=s;
+ XMLCharacterEntity *entity;
+ while ((lo>0)&&(*s))
+ {
+ if (*s==_CXML('&'))
+ {
+ if ((lo>2)&&(s[1]==_CXML('#')))
+ {
+ s+=2; lo-=2;
+ if ((*s==_CXML('X'))||(*s==_CXML('x'))) { s++; lo--; }
+ while ((*s)&&(*s!=_CXML(';'))&&((lo--)>0)) s++;
+ if (*s!=_CXML(';'))
+ {
+ pXML->error=eXMLErrorUnknownCharacterEntity;
+ return NULL;
+ }
+ s++; lo--;
+ } else
+ {
+ entity=XMLEntities;
+ do
+ {
+ if ((lo>=entity->l)&&(xstrnicmp(s,entity->s,entity->l)==0)) { s+=entity->l; lo-=entity->l; break; }
+ entity++;
+ } while(entity->s);
+ if (!entity->s)
+ {
+ pXML->error=eXMLErrorUnknownCharacterEntity;
+ return NULL;
+ }
+ }
+ } else
+ {
+#ifdef _XMLWIDECHAR
+ s++; lo--;
+#else
+ j=XML_ByteTable[(unsigned char)*s]; s+=j; lo-=j; ll+=j-1;
+#endif
+ }
+ ll++;
+ }
+
+ d=(XMLSTR)malloc((ll+1)*sizeof(XMLCHAR));
+ s=d;
+ while (ll-->0)
+ {
+ if (*ss==_CXML('&'))
+ {
+ if (ss[1]==_CXML('#'))
+ {
+ ss+=2; j=0;
+ if ((*ss==_CXML('X'))||(*ss==_CXML('x')))
+ {
+ ss++;
+ while (*ss!=_CXML(';'))
+ {
+ if ((*ss>=_CXML('0'))&&(*ss<=_CXML('9'))) j=(j<<4)+*ss-_CXML('0');
+ else if ((*ss>=_CXML('A'))&&(*ss<=_CXML('F'))) j=(j<<4)+*ss-_CXML('A')+10;
+ else if ((*ss>=_CXML('a'))&&(*ss<=_CXML('f'))) j=(j<<4)+*ss-_CXML('a')+10;
+ else { free((void*)s); pXML->error=eXMLErrorUnknownCharacterEntity;return NULL;}
+ ss++;
+ }
+ } else
+ {
+ while (*ss!=_CXML(';'))
+ {
+ if ((*ss>=_CXML('0'))&&(*ss<=_CXML('9'))) j=(j*10)+*ss-_CXML('0');
+ else { free((void*)s); pXML->error=eXMLErrorUnknownCharacterEntity;return NULL;}
+ ss++;
+ }
+ }
+#ifndef _XMLWIDECHAR
+ if (j>255) { free((void*)s); pXML->error=eXMLErrorCharacterCodeAbove255;return NULL;}
+#endif
+ (*d++)=(XMLCHAR)j; ss++;
+ } else
+ {
+ entity=XMLEntities;
+ do
+ {
+ if (xstrnicmp(ss,entity->s,entity->l)==0) { *(d++)=entity->c; ss+=entity->l; break; }
+ entity++;
+ } while(entity->s);
+ }
+ } else
+ {
+#ifdef _XMLWIDECHAR
+ *(d++)=*(ss++);
+#else
+ switch(XML_ByteTable[(unsigned char)*ss])
+ {
+ case 4: *(d++)=*(ss++); ll--;
+ case 3: *(d++)=*(ss++); ll--;
+ case 2: *(d++)=*(ss++); ll--;
+ case 1: *(d++)=*(ss++);
+ }
+#endif
+ }
+ }
+ *d=0;
+
+#ifndef _XMLWIDECHAR
+ if (characterEncoding != XMLNode::char_encoding_legacy)
+ Utf8Decode((XMLSTR)s, NULL );
+#endif
+
+ return (XMLSTR)s;
+}
+
+#define XML_isSPACECHAR(ch) ((ch==_CXML('\n'))||(ch==_CXML(' '))||(ch== _CXML('\t'))||(ch==_CXML('\r')))
+
+// private:
+char myTagCompare(XMLCSTR cclose, XMLCSTR copen)
+// !!!! WARNING strange convention&:
+// return 0 if equals
+// return 1 if different
+{
+ if (!cclose) return 1;
+ int l=(int)xstrlen(cclose);
+ if (xstrnicmp(cclose, copen, l)!=0) return 1;
+ const XMLCHAR c=copen[l];
+ if (XML_isSPACECHAR(c)||
+ (c==_CXML('/' ))||
+ (c==_CXML('<' ))||
+ (c==_CXML('>' ))||
+ (c==_CXML('=' ))) return 0;
+ return 1;
+}
+
+// Obtain the next character from the string.
+static inline XMLCHAR getNextChar(XML *pXML)
+{
+ XMLCHAR ch = pXML->lpXML[pXML->nIndex];
+#ifdef _XMLWIDECHAR
+ if (ch!=0) pXML->nIndex++;
+#else
+ pXML->nIndex+=XML_ByteTable[(unsigned char)ch];
+#endif
+ return ch;
+}
+
+// Find the next token in a string.
+// pcbToken contains the number of characters that have been read.
+static NextToken GetNextToken(XML *pXML, int *pcbToken, enum XMLTokenTypeTag *pType)
+{
+ NextToken result;
+ XMLCHAR ch;
+ XMLCHAR chTemp;
+ int indexStart,nFoundMatch,nIsText=FALSE;
+ result.pClr=NULL; // prevent warning
+
+ // Find next non-white space character
+ do { indexStart=pXML->nIndex; ch=getNextChar(pXML); } while XML_isSPACECHAR(ch);
+
+ if (ch)
+ {
+ // Cache the current string pointer
+ result.pStr = &pXML->lpXML[indexStart];
+
+ // check for standard tokens
+ switch(ch)
+ {
+ // Check for quotes
+ case _CXML('\''):
+ case _CXML('\"'):
+ // Type of token
+ *pType = eTokenQuotedText;
+ chTemp = ch;
+
+ // Set the size
+ nFoundMatch = FALSE;
+
+ // Search through the string to find a matching quote
+ while((ch = getNextChar(pXML)))
+ {
+ if (ch==chTemp) { nFoundMatch = TRUE; break; }
+ if (ch==_CXML('<')) break;
+ }
+
+ // If we failed to find a matching quote
+ if (nFoundMatch == FALSE)
+ {
+ pXML->nIndex=indexStart+1;
+ nIsText=TRUE;
+ break;
+ }
+
+ // 4.02.2002
+ // if (FindNonWhiteSpace(pXML)) pXML->nIndex--;
+
+ break;
+
+ // Equals (used with attribute values)
+ case _CXML('='):
+ *pType = eTokenEquals;
+ break;
+
+ // Close tag
+ case _CXML('>'):
+ *pType = eTokenCloseTag;
+ break;
+
+ // Check for tag start and tag end
+ case _CXML('<'):
+
+ {
+ // First check whether the token is in the clear tag list (meaning it
+ // does not need formatting).
+ ALLXMLClearTag *ctag=XMLClearTags;
+ do
+ {
+ if (!xstrncmp(ctag->lpszOpen, result.pStr, ctag->openTagLen))
+ {
+ result.pClr=ctag;
+ pXML->nIndex+=ctag->openTagLen-1;
+ *pType=eTokenClear;
+ return result;
+ }
+ ctag++;
+ } while(ctag->lpszOpen);
+
+ // Peek at the next character to see if we have an end tag '</',
+ // or an xml declaration '<?'
+ chTemp = pXML->lpXML[pXML->nIndex];
+
+ // If we have a tag end...
+ if (chTemp == _CXML('/'))
+ {
+ // Set the type and ensure we point at the next character
+ getNextChar(pXML);
+ *pType = eTokenTagEnd;
+ }
+
+ // If we have an XML declaration tag
+ else if (chTemp == _CXML('?'))
+ {
+
+ // Set the type and ensure we point at the next character
+ getNextChar(pXML);
+ *pType = eTokenDeclaration;
+ }
+
+ // Otherwise we must have a start tag
+ else
+ {
+ *pType = eTokenTagStart;
+ }
+ break;
+ }
+
+ // Check to see if we have a short hand type end tag ('/>').
+ case _CXML('/'):
+
+ // Peek at the next character to see if we have a short end tag '/>'
+ chTemp = pXML->lpXML[pXML->nIndex];
+
+ // If we have a short hand end tag...
+ if (chTemp == _CXML('>'))
+ {
+ // Set the type and ensure we point at the next character
+ getNextChar(pXML);
+ *pType = eTokenShortHandClose;
+ break;
+ }
+
+ // If we haven't found a short hand closing tag then drop into the
+ // text process
+
+ // Other characters
+ default:
+ nIsText = TRUE;
+ }
+
+ // If this is a TEXT node
+ if (nIsText)
+ {
+ // Indicate we are dealing with text
+ *pType = eTokenText;
+ while((ch = getNextChar(pXML)))
+ {
+ if XML_isSPACECHAR(ch)
+ {
+ indexStart++; break;
+
+ } else if (ch==_CXML('/'))
+ {
+ // If we find a slash then this maybe text or a short hand end tag
+ // Peek at the next character to see it we have short hand end tag
+ ch=pXML->lpXML[pXML->nIndex];
+ // If we found a short hand end tag then we need to exit the loop
+ if (ch==_CXML('>')) { pXML->nIndex--; break; }
+
+ } else if ((ch==_CXML('<'))||(ch==_CXML('>'))||(ch==_CXML('=')))
+ {
+ pXML->nIndex--; break;
+ }
+ }
+ }
+ *pcbToken = pXML->nIndex-indexStart;
+ } else
+ {
+ // If we failed to obtain a valid character
+ *pcbToken = 0;
+ *pType = eTokenError;
+ result.pStr=NULL;
+ }
+
+ return result;
+}
+
+XMLCSTR XMLNode::updateName_WOSD(XMLSTR lpszName)
+{
+ if (!d) { free(lpszName); return NULL; }
+ if (d->lpszName&&(lpszName!=d->lpszName)) free((void*)d->lpszName);
+ d->lpszName=lpszName;
+ return lpszName;
+}
+
+// private:
+XMLNode::XMLNode(struct XMLNodeDataTag *p){ d=p; (p->ref_count)++; }
+XMLNode::XMLNode(XMLNodeData *pParent, XMLSTR lpszName, char isDeclaration)
+{
+ d=(XMLNodeData*)malloc(sizeof(XMLNodeData));
+ d->ref_count=1;
+
+ d->lpszName=NULL;
+ d->nChild= 0;
+ d->nText = 0;
+ d->nClear = 0;
+ d->nAttribute = 0;
+
+ d->isDeclaration = isDeclaration;
+
+ d->pParent = pParent;
+ d->pChild= NULL;
+ d->pText= NULL;
+ d->pClear= NULL;
+ d->pAttribute= NULL;
+ d->pOrder= NULL;
+
+ d->pInnerText= NULL;
+
+ updateName_WOSD(lpszName);
+
+ d->lpszNS = NULL;
+ if ( lpszName && pParent && pParent->lpszName && !pParent->isDeclaration) {
+ TCHAR* p = _tcschr( lpszName, ':' );
+ if ( p ) {
+ *p = 0;
+ d->lpszNS = d->lpszName;
+ d->lpszName = p+1;
+ }
+ }
+}
+
+XMLNode XMLNode::createXMLTopNode_WOSD(XMLSTR lpszName, char isDeclaration) { return XMLNode(NULL,lpszName,isDeclaration); }
+XMLNode XMLNode::createXMLTopNode(XMLCSTR lpszName, char isDeclaration) { return XMLNode(NULL,stringDup(lpszName),isDeclaration); }
+
+#define MEMORYINCREASE 50
+
+static inline void myFree(void *p) { if (p) free(p); }
+static inline void *myRealloc(void *p, int newsize, int memInc, int sizeofElem)
+{
+ if (p==NULL) { if (memInc) return malloc(memInc*sizeofElem); return malloc(sizeofElem); }
+ if ((memInc==0)||((newsize%memInc)==0)) p=realloc(p,(newsize+memInc)*sizeofElem);
+ // if (!p)
+ // {
+ // printf("XMLParser Error: Not enough memory! Aborting...\n"); exit(220);
+ // }
+ return p;
+}
+
+// private:
+XMLElementPosition XMLNode::findPosition(XMLNodeData *d, int index, XMLElementType xxtype)
+{
+ if (index<0) return -1;
+ int i=0,j=(int)((index<<2)+xxtype),*o=d->pOrder; while (o[i]!=j) i++; return i;
+}
+
+// private:
+// update "order" information when deleting a content of a XMLNode
+int XMLNode::removeOrderElement(XMLNodeData *d, XMLElementType t, int index)
+{
+ int n=d->nChild+d->nText+d->nClear, *o=d->pOrder,i=findPosition(d,index,t);
+ memmove(o+i, o+i+1, (n-i)*sizeof(int));
+ for (;i<n;i++)
+ if ((o[i]&3)==(int)t) o[i]-=4;
+ // We should normally do:
+ // d->pOrder=(int)realloc(d->pOrder,n*sizeof(int));
+ // but we skip reallocation because it's too time consuming.
+ // Anyway, at the end, it will be free'd completely at once.
+ return i;
+}
+
+void *XMLNode::addToOrder(int memoryIncrease,int *_pos, int nc, void *p, int size, XMLElementType xtype)
+{
+ // in: *_pos is the position inside d->pOrder ("-1" means "EndOf")
+ // out: *_pos is the index inside p
+ p=myRealloc(p,(nc+1),memoryIncrease,size);
+ int n=d->nChild+d->nText+d->nClear;
+ d->pOrder=(int*)myRealloc(d->pOrder,n+1,memoryIncrease*3,sizeof(int));
+ int pos=*_pos,*o=d->pOrder;
+
+ if ((pos<0)||(pos>=n)) { *_pos=nc; o[n]=(int)((nc<<2)+xtype); return p; }
+
+ int i=pos;
+ memmove(o+i+1, o+i, (n-i)*sizeof(int));
+
+ while ((pos<n)&&((o[pos]&3)!=(int)xtype)) pos++;
+ if (pos==n) { *_pos=nc; o[n]=(int)((nc<<2)+xtype); return p; }
+
+ o[i]=o[pos];
+ for (i=pos+1;i<=n;i++) if ((o[i]&3)==(int)xtype) o[i]+=4;
+
+ *_pos=pos=o[pos]>>2;
+ memmove(((char*)p)+(pos+1)*size,((char*)p)+pos*size,(nc-pos)*size);
+
+ return p;
+}
+
+// Add a child node to the given element.
+XMLNode XMLNode::addChild_priv(int memoryIncrease, XMLSTR lpszName, char isDeclaration, int pos)
+{
+ if (!lpszName) return emptyXMLNode;
+ d->pChild=(XMLNode*)addToOrder(memoryIncrease,&pos,d->nChild,d->pChild,sizeof(XMLNode),eNodeChild);
+ d->pChild[pos].d=NULL;
+ d->pChild[pos]=XMLNode(d,lpszName,isDeclaration);
+ d->nChild++;
+ return d->pChild[pos];
+}
+
+// Add an attribute to an element.
+XMLAttribute *XMLNode::addAttribute_priv(int memoryIncrease,XMLSTR lpszName, XMLSTR lpszValuev)
+{
+ if (!lpszName) return &emptyXMLAttribute;
+ if (!d) { myFree(lpszName); myFree(lpszValuev); return &emptyXMLAttribute; }
+ int nc=d->nAttribute;
+ d->pAttribute=(XMLAttribute*)myRealloc(d->pAttribute,(nc+1),memoryIncrease,sizeof(XMLAttribute));
+ XMLAttribute *pAttr=d->pAttribute+nc;
+ pAttr->lpszName = lpszName;
+ pAttr->lpszValue = lpszValuev;
+ d->nAttribute++;
+
+ TCHAR* p = _tcschr( lpszName, ':' );
+ if ( p )
+ if ( !lstrcmp( p+1, d->lpszNS ) || ( d->pParent && !lstrcmp( p+1, d->pParent->lpszNS )))
+ *p = 0;
+
+ return pAttr;
+}
+
+// Add text to the element.
+XMLCSTR XMLNode::addText_priv(int memoryIncrease, XMLSTR lpszValue, int pos)
+{
+ if (!lpszValue) return NULL;
+ if (!d) { myFree(lpszValue); return NULL; }
+ invalidateInnerText();
+ d->pText=(XMLCSTR*)addToOrder(memoryIncrease,&pos,d->nText,d->pText,sizeof(XMLSTR),eNodeText);
+ d->pText[pos]=lpszValue;
+ d->nText++;
+ return lpszValue;
+}
+
+// Add clear (unformatted) text to the element.
+XMLClear *XMLNode::addClear_priv(int memoryIncrease, XMLSTR lpszValue, XMLCSTR lpszOpen, XMLCSTR lpszClose, int pos)
+{
+ if (!lpszValue) return &emptyXMLClear;
+ if (!d) { myFree(lpszValue); return &emptyXMLClear; }
+ invalidateInnerText();
+ d->pClear=(XMLClear *)addToOrder(memoryIncrease,&pos,d->nClear,d->pClear,sizeof(XMLClear),eNodeClear);
+ XMLClear *pNewClear=d->pClear+pos;
+ pNewClear->lpszValue = lpszValue;
+ if (!lpszOpen) lpszOpen=XMLClearTags->lpszOpen;
+ if (!lpszClose) lpszClose=XMLClearTags->lpszClose;
+ pNewClear->lpszOpenTag = lpszOpen;
+ pNewClear->lpszCloseTag = lpszClose;
+ d->nClear++;
+ return pNewClear;
+}
+
+// private:
+// Parse a clear (unformatted) type node.
+char XMLNode::parseClearTag(void *px, void *_pClear)
+{
+ XML *pXML=(XML *)px;
+ ALLXMLClearTag pClear=*((ALLXMLClearTag*)_pClear);
+ int cbTemp=0;
+ XMLCSTR lpszTemp=NULL;
+ XMLCSTR lpXML=&pXML->lpXML[pXML->nIndex];
+ static XMLCSTR docTypeEnd=_CXML("]>");
+
+ // Find the closing tag
+ // Seems the <!DOCTYPE need a better treatment so lets handle it
+ if (pClear.lpszOpen==XMLClearTags[1].lpszOpen)
+ {
+ XMLCSTR pCh=lpXML;
+ while (*pCh)
+ {
+ if (*pCh==_CXML('<')) { pClear.lpszClose=docTypeEnd; lpszTemp=xstrstr(lpXML,docTypeEnd); break; }
+ else if (*pCh==_CXML('>')) { lpszTemp=pCh; break; }
+#ifdef _XMLWIDECHAR
+ pCh++;
+#else
+ pCh+=XML_ByteTable[(unsigned char)(*pCh)];
+#endif
+ }
+ } else lpszTemp=xstrstr(lpXML, pClear.lpszClose);
+
+ if (lpszTemp)
+ {
+ // Cache the size and increment the index
+ cbTemp = (int)(lpszTemp - lpXML);
+
+ pXML->nIndex += cbTemp+(int)xstrlen(pClear.lpszClose);
+
+ // Add the clear node to the current element
+ addClear_priv(MEMORYINCREASE,cbTemp?stringDup(lpXML,cbTemp):NULL, pClear.lpszOpen, pClear.lpszClose,-1);
+ return 0;
+ }
+
+ // If we failed to find the end tag
+ pXML->error = eXMLErrorUnmatchedEndClearTag;
+ return 1;
+}
+
+void XMLNode::exactMemory(XMLNodeData *d)
+{
+ if (d->pOrder) d->pOrder=(int*)realloc(d->pOrder,(d->nChild+d->nText+d->nClear)*sizeof(int));
+ if (d->pChild) d->pChild=(XMLNode*)realloc(d->pChild,d->nChild*sizeof(XMLNode));
+ if (d->pAttribute) d->pAttribute=(XMLAttribute*)realloc(d->pAttribute,d->nAttribute*sizeof(XMLAttribute));
+ if (d->pText) d->pText=(XMLCSTR*)realloc(d->pText,d->nText*sizeof(XMLSTR));
+ if (d->pClear) d->pClear=(XMLClear *)realloc(d->pClear,d->nClear*sizeof(XMLClear));
+}
+
+char XMLNode::maybeAddTxT(void *pa, XMLCSTR tokenPStr)
+{
+ XML *pXML=(XML *)pa;
+ XMLCSTR lpszText=pXML->lpszText;
+ if (!lpszText) return 0;
+ if (dropWhiteSpace) while (XML_isSPACECHAR(*lpszText)&&(lpszText!=tokenPStr)) lpszText++;
+ int cbText = (int)(tokenPStr - lpszText);
+ if (!cbText) { pXML->lpszText=NULL; return 0; }
+ if (dropWhiteSpace) { cbText--; while ((cbText)&&XML_isSPACECHAR(lpszText[cbText])) cbText--; cbText++; }
+ if (!cbText) { pXML->lpszText=NULL; return 0; }
+ XMLSTR lpt=fromXMLString(lpszText,cbText,pXML);
+ if (!lpt) return 1;
+ pXML->lpszText=NULL;
+ if (removeCommentsInMiddleOfText && d->nText && d->nClear)
+ {
+ // if the previous insertion was a comment (<!-- -->) AND
+ // if the previous previous insertion was a text then, delete the comment and append the text
+ int n=d->nChild+d->nText+d->nClear-1,*o=d->pOrder;
+ if (((o[n]&3)==eNodeClear)&&((o[n-1]&3)==eNodeText))
+ {
+ int i=o[n]>>2;
+ if (d->pClear[i].lpszOpenTag==XMLClearTags[2].lpszOpen)
+ {
+ deleteClear(i);
+ i=o[n-1]>>2;
+ n=xstrlen(d->pText[i]);
+ int n2=xstrlen(lpt)+1;
+ d->pText[i]=(XMLSTR)realloc((void*)d->pText[i],(n+n2)*sizeof(XMLCHAR));
+ if (!d->pText[i]) return 1;
+ memcpy((void*)(d->pText[i]+n),lpt,n2*sizeof(XMLCHAR));
+ free(lpt);
+ return 0;
+ }
+ }
+ }
+ addText_priv(MEMORYINCREASE,lpt,-1);
+ return 0;
+}
+// private:
+// Recursively parse an XML element.
+int XMLNode::ParseXMLElement(void *pa)
+{
+ XML *pXML=(XML *)pa;
+ int cbToken;
+ enum XMLTokenTypeTag xtype;
+ NextToken token;
+ XMLCSTR lpszTemp=NULL;
+ int cbTemp=0;
+ char nDeclaration;
+ XMLNode pNew;
+ enum XMLStatus status; // inside or outside a tag
+ enum Attrib attrib = eAttribName;
+
+ assert(pXML);
+
+ // If this is the first call to the function
+ if (pXML->nFirst)
+ {
+ // Assume we are outside of a tag definition
+ pXML->nFirst = FALSE;
+ status = eOutsideTag;
+ } else
+ {
+ // If this is not the first call then we should only be called when inside a tag.
+ status = eInsideTag;
+ }
+
+ // Iterate through the tokens in the document
+ for(;;)
+ {
+ // Obtain the next token
+ token = GetNextToken(pXML, &cbToken, &xtype);
+
+ if (xtype != eTokenError)
+ {
+ // Check the current status
+ switch(status)
+ {
+
+ // If we are outside of a tag definition
+ case eOutsideTag:
+
+ // Check what type of token we obtained
+ switch(xtype)
+ {
+ // If we have found text or quoted text
+ case eTokenText:
+ case eTokenCloseTag: /* '>' */
+ case eTokenShortHandClose: /* '/>' */
+ case eTokenQuotedText:
+ case eTokenEquals:
+ break;
+
+ // If we found a start tag '<' and declarations '<?'
+ case eTokenTagStart:
+ case eTokenDeclaration:
+
+ // Cache whether this new element is a declaration or not
+ nDeclaration = (xtype == eTokenDeclaration);
+
+ // If we have node text then add this to the element
+ if (maybeAddTxT(pXML,token.pStr)) return FALSE;
+
+ // Find the name of the tag
+ token = GetNextToken(pXML, &cbToken, &xtype);
+
+ // Return an error if we couldn't obtain the next token or
+ // it wasnt text
+ if (xtype != eTokenText)
+ {
+ pXML->error = eXMLErrorMissingTagName;
+ return FALSE;
+ }
+
+ // If we found a new element which is the same as this
+ // element then we need to pass this back to the caller..
+
+#ifdef APPROXIMATE_PARSING
+ if (d->lpszName &&
+ myTagCompare(d->lpszName, token.pStr) == 0)
+ {
+ // Indicate to the caller that it needs to create a
+ // new element.
+ pXML->lpNewElement = token.pStr;
+ pXML->cbNewElement = cbToken;
+ return TRUE;
+ } else
+#endif
+ {
+ // If the name of the new element differs from the name of
+ // the current element we need to add the new element to
+ // the current one and recurse
+ pNew = addChild_priv(MEMORYINCREASE,stringDup(token.pStr,cbToken), nDeclaration,-1);
+
+ while (!pNew.isEmpty())
+ {
+ // Callself to process the new node. If we return
+ // FALSE this means we dont have any more
+ // processing to do...
+
+ if (!pNew.ParseXMLElement(pXML)) return FALSE;
+ else
+ {
+ // If the call to recurse this function
+ // evented in a end tag specified in XML then
+ // we need to unwind the calls to this
+ // function until we find the appropriate node
+ // (the element name and end tag name must
+ // match)
+ if (pXML->cbEndTag)
+ {
+ // If we are back at the root node then we
+ // have an unmatched end tag
+ if (!d->lpszName)
+ {
+ pXML->error=eXMLErrorUnmatchedEndTag;
+ return FALSE;
+ }
+
+ // If the end tag matches the name of this
+ // element then we only need to unwind
+ // once more...
+
+ if (myTagCompare(d->lpszName, pXML->lpEndTag)==0)
+ {
+ pXML->cbEndTag = 0;
+ }
+
+ return TRUE;
+ } else
+ if (pXML->cbNewElement)
+ {
+ // If the call indicated a new element is to
+ // be created on THIS element.
+
+ // If the name of this element matches the
+ // name of the element we need to create
+ // then we need to return to the caller
+ // and let it process the element.
+
+ if (myTagCompare(d->lpszName, pXML->lpNewElement)==0)
+ {
+ return TRUE;
+ }
+
+ // Add the new element and recurse
+ pNew = addChild_priv(MEMORYINCREASE,stringDup(pXML->lpNewElement,pXML->cbNewElement),0,-1);
+ pXML->cbNewElement = 0;
+ }
+ else
+ {
+ // If we didn't have a new element to create
+ pNew = emptyXMLNode;
+
+ }
+ }
+ }
+ }
+ break;
+
+ // If we found an end tag
+ case eTokenTagEnd:
+
+ // If we have node text then add this to the element
+ if (maybeAddTxT(pXML,token.pStr)) return FALSE;
+
+ // Find the name of the end tag
+ token = GetNextToken(pXML, &cbTemp, &xtype);
+
+ // The end tag should be text
+ if (xtype != eTokenText)
+ {
+ pXML->error = eXMLErrorMissingEndTagName;
+ return FALSE;
+ }
+ lpszTemp = token.pStr;
+
+ // After the end tag we should find a closing tag
+ token = GetNextToken(pXML, &cbToken, &xtype);
+ if (xtype != eTokenCloseTag)
+ {
+ pXML->error = eXMLErrorMissingEndTagName;
+ return FALSE;
+ }
+ pXML->lpszText=pXML->lpXML+pXML->nIndex;
+
+ // We need to return to the previous caller. If the name
+ // of the tag cannot be found we need to keep returning to
+ // caller until we find a match
+ if (!d->lpszNS) {
+ if (myTagCompare(d->lpszName, lpszTemp) != 0)
+#ifdef STRICT_PARSING
+ {
+LBL_Error:
+ pXML->error=eXMLErrorUnmatchedEndTag;
+ pXML->nIndexMissigEndTag=pXML->nIndex;
+ return FALSE;
+ }
+#else
+ {
+LBL_Error:
+ pXML->error=eXMLErrorMissingEndTag;
+ pXML->nIndexMissigEndTag=pXML->nIndex;
+ pXML->lpEndTag = lpszTemp;
+ pXML->cbEndTag = cbTemp;
+ }
+#endif
+ }
+ else {
+ const TCHAR* p = _tcschr( lpszTemp, ':' );
+ if ( !p )
+ goto LBL_Error;
+
+ if (myTagCompare(d->lpszName, p+1) != 0)
+ goto LBL_Error;
+ }
+
+ // Return to the caller
+ exactMemory(d);
+ return TRUE;
+
+ // If we found a clear (unformatted) token
+ case eTokenClear:
+ // If we have node text then add this to the element
+ if (maybeAddTxT(pXML,token.pStr)) return FALSE;
+ if (parseClearTag(pXML, token.pClr)) return FALSE;
+ pXML->lpszText=pXML->lpXML+pXML->nIndex;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ // If we are inside a tag definition we need to search for attributes
+ case eInsideTag:
+
+ // Check what part of the attribute (name, equals, value) we
+ // are looking for.
+ switch(attrib)
+ {
+ // If we are looking for a new attribute
+ case eAttribName:
+
+ // Check what the current token type is
+ switch(xtype)
+ {
+ // If the current type is text...
+ // Eg. 'attribute'
+ case eTokenText:
+ // Cache the token then indicate that we are next to
+ // look for the equals
+ lpszTemp = token.pStr;
+ cbTemp = cbToken;
+ attrib = eAttribEquals;
+ break;
+
+ // If we found a closing tag...
+ // Eg. '>'
+ case eTokenCloseTag:
+ // We are now outside the tag
+ status = eOutsideTag;
+ pXML->lpszText=pXML->lpXML+pXML->nIndex;
+ break;
+
+ // If we found a short hand '/>' closing tag then we can
+ // return to the caller
+ case eTokenShortHandClose:
+ exactMemory(d);
+ pXML->lpszText=pXML->lpXML+pXML->nIndex;
+ return TRUE;
+
+ // Errors...
+ case eTokenQuotedText: /* '"SomeText"' */
+ case eTokenTagStart: /* '<' */
+ case eTokenTagEnd: /* '</' */
+ case eTokenEquals: /* '=' */
+ case eTokenDeclaration: /* '<?' */
+ case eTokenClear:
+ pXML->error = eXMLErrorUnexpectedToken;
+ return FALSE;
+ default: break;
+ }
+ break;
+
+ // If we are looking for an equals
+ case eAttribEquals:
+ // Check what the current token type is
+ switch(xtype)
+ {
+ // If the current type is text...
+ // Eg. 'Attribute AnotherAttribute'
+ case eTokenText:
+ // Add the unvalued attribute to the list
+ addAttribute_priv(MEMORYINCREASE,stringDup(lpszTemp,cbTemp), NULL);
+ // Cache the token then indicate. We are next to
+ // look for the equals attribute
+ lpszTemp = token.pStr;
+ cbTemp = cbToken;
+ break;
+
+ // If we found a closing tag 'Attribute >' or a short hand
+ // closing tag 'Attribute />'
+ case eTokenShortHandClose:
+ case eTokenCloseTag:
+ // If we are a declaration element '<?' then we need
+ // to remove extra closing '?' if it exists
+ pXML->lpszText=pXML->lpXML+pXML->nIndex;
+
+ if (d->isDeclaration &&
+ (lpszTemp[cbTemp-1]) == _CXML('?'))
+ {
+ cbTemp--;
+ if (d->pParent && d->pParent->pParent) xtype = eTokenShortHandClose;
+ }
+
+ if (cbTemp)
+ {
+ // Add the unvalued attribute to the list
+ addAttribute_priv(MEMORYINCREASE,stringDup(lpszTemp,cbTemp), NULL);
+ }
+
+ // If this is the end of the tag then return to the caller
+ if (xtype == eTokenShortHandClose)
+ {
+ exactMemory(d);
+ return TRUE;
+ }
+
+ // We are now outside the tag
+ status = eOutsideTag;
+ break;
+
+ // If we found the equals token...
+ // Eg. 'Attribute ='
+ case eTokenEquals:
+ // Indicate that we next need to search for the value
+ // for the attribute
+ attrib = eAttribValue;
+ break;
+
+ // Errors...
+ case eTokenQuotedText: /* 'Attribute "InvalidAttr"'*/
+ case eTokenTagStart: /* 'Attribute <' */
+ case eTokenTagEnd: /* 'Attribute </' */
+ case eTokenDeclaration: /* 'Attribute <?' */
+ case eTokenClear:
+ pXML->error = eXMLErrorUnexpectedToken;
+ return FALSE;
+ default: break;
+ }
+ break;
+
+ // If we are looking for an attribute value
+ case eAttribValue:
+ // Check what the current token type is
+ switch(xtype)
+ {
+ // If the current type is text or quoted text...
+ // Eg. 'Attribute = "Value"' or 'Attribute = Value' or
+ // 'Attribute = 'Value''.
+ case eTokenText:
+ case eTokenQuotedText:
+ // If we are a declaration element '<?' then we need
+ // to remove extra closing '?' if it exists
+ if (d->isDeclaration &&
+ (token.pStr[cbToken-1]) == _CXML('?'))
+ {
+ cbToken--;
+ }
+
+ if (cbTemp)
+ {
+ // Add the valued attribute to the list
+ if (xtype==eTokenQuotedText) { token.pStr++; cbToken-=2; }
+ XMLSTR attrVal=(XMLSTR)token.pStr;
+ if (attrVal)
+ {
+ attrVal=fromXMLString(attrVal,cbToken,pXML);
+ if (!attrVal) return FALSE;
+ }
+ addAttribute_priv(MEMORYINCREASE,stringDup(lpszTemp,cbTemp),attrVal);
+ }
+
+ // Indicate we are searching for a new attribute
+ attrib = eAttribName;
+ break;
+
+ // Errors...
+ case eTokenTagStart: /* 'Attr = <' */
+ case eTokenTagEnd: /* 'Attr = </' */
+ case eTokenCloseTag: /* 'Attr = >' */
+ case eTokenShortHandClose: /* "Attr = />" */
+ case eTokenEquals: /* 'Attr = =' */
+ case eTokenDeclaration: /* 'Attr = <?' */
+ case eTokenClear:
+ pXML->error = eXMLErrorUnexpectedToken;
+ return FALSE;
+ break;
+ default: break;
+ }
+ }
+ }
+ }
+ // If we failed to obtain the next token
+ else
+ {
+ if ((!d->isDeclaration)&&(d->pParent))
+ {
+#ifdef STRICT_PARSING
+ pXML->error=eXMLErrorUnmatchedEndTag;
+#else
+ pXML->error=eXMLErrorMissingEndTag;
+#endif
+ pXML->nIndexMissigEndTag=pXML->nIndex;
+ }
+ maybeAddTxT(pXML,pXML->lpXML+pXML->nIndex);
+ return FALSE;
+ }
+ }
+}
+
+// Count the number of lines and columns in an XML string.
+static void CountLinesAndColumns(XMLCSTR lpXML, int nUpto, XMLResults *pResults)
+{
+ XMLCHAR ch;
+ assert(lpXML);
+ assert(pResults);
+
+ struct XML xml={ lpXML,lpXML, 0, 0, eXMLErrorNone, NULL, 0, NULL, 0, TRUE };
+
+ pResults->nLine = 1;
+ pResults->nColumn = 1;
+ while (xml.nIndex<nUpto)
+ {
+ ch = getNextChar(&xml);
+ if (ch != _CXML('\n')) pResults->nColumn++;
+ else
+ {
+ pResults->nLine++;
+ pResults->nColumn=1;
+ }
+ }
+}
+
+// Parse XML and return the root element.
+XMLNode XMLNode::parseString(XMLCSTR lpszXML, XMLCSTR tag, XMLResults *pResults)
+{
+ if (!lpszXML)
+ {
+ if (pResults)
+ {
+ pResults->error=eXMLErrorNoElements;
+ pResults->nLine=0;
+ pResults->nColumn=0;
+ }
+ return emptyXMLNode;
+ }
+
+ XMLNode xnode(NULL,NULL,FALSE);
+ struct XML xml={ lpszXML, lpszXML, 0, 0, eXMLErrorNone, NULL, 0, NULL, 0, TRUE };
+
+ // Create header element
+ xnode.ParseXMLElement(&xml);
+ enum XMLError error = xml.error;
+ if (!xnode.nChildNode()) error=eXMLErrorNoXMLTagFound;
+ if ((xnode.nChildNode()==1)&&(xnode.nElement()==1)) xnode=xnode.getChildNode(); // skip the empty node
+
+ // If no error occurred
+ if ((error==eXMLErrorNone)||(error==eXMLErrorMissingEndTag)||(error==eXMLErrorNoXMLTagFound))
+ {
+ XMLCSTR name=xnode.getName();
+ if (tag&&(*tag)&&((!name)||(xstricmp(name,tag))))
+ {
+ xnode=xnode.getChildNode(tag);
+ if (xnode.isEmpty())
+ {
+ if (pResults)
+ {
+ pResults->error=eXMLErrorFirstTagNotFound;
+ pResults->nLine=0;
+ pResults->nColumn=0;
+ pResults->nChars=xml.nIndex;
+ }
+ return emptyXMLNode;
+ }
+ }
+ } else
+ {
+ // Cleanup: this will destroy all the nodes
+ xnode = emptyXMLNode;
+ }
+
+
+ // If we have been given somewhere to place results
+ if (pResults)
+ {
+ pResults->error = error;
+
+ // If we have an error
+ if (error!=eXMLErrorNone)
+ {
+ if (error==eXMLErrorMissingEndTag) xml.nIndex=xml.nIndexMissigEndTag;
+ // Find which line and column it starts on.
+ CountLinesAndColumns(xml.lpXML, xml.nIndex, pResults);
+ }
+
+ pResults->nChars = xml.nIndex;
+ }
+ return xnode;
+}
+
+XMLNode XMLNode::parseFile(XMLCSTR filename, XMLCSTR tag, XMLResults *pResults)
+{
+ if (pResults) { pResults->nLine=0; pResults->nColumn=0; }
+ FILE *f=xfopen(filename,_CXML("rb"));
+ if (f==NULL) { if (pResults) pResults->error=eXMLErrorFileNotFound; return emptyXMLNode; }
+ fseek(f,0,SEEK_END);
+ int l=(int)ftell(f),headerSz=0;
+ if (!l) { if (pResults) pResults->error=eXMLErrorEmpty; fclose(f); return emptyXMLNode; }
+ fseek(f,0,SEEK_SET);
+ unsigned char *buf=(unsigned char*)malloc(l+4);
+ l=(int)fread(buf,1,l,f);
+ fclose(f);
+ buf[l]=0;buf[l+1]=0;buf[l+2]=0;buf[l+3]=0;
+#ifdef _XMLWIDECHAR
+ if (guessWideCharChars)
+ {
+ if (!myIsTextWideChar(buf,l))
+ {
+ XMLNode::XMLCharEncoding ce=XMLNode::char_encoding_legacy;
+ if ((buf[0]==0xef)&&(buf[1]==0xbb)&&(buf[2]==0xbf)) { headerSz=3; ce=XMLNode::char_encoding_UTF8; }
+ XMLSTR b2=myMultiByteToWideChar((const char*)(buf+headerSz),ce);
+ if (!b2)
+ {
+ // todo: unable to convert
+ }
+ free(buf); buf=(unsigned char*)b2; headerSz=0;
+ } else
+ {
+ if ((buf[0]==0xef)&&(buf[1]==0xff)) headerSz=2;
+ if ((buf[0]==0xff)&&(buf[1]==0xfe)) headerSz=2;
+ }
+ } else
+ {
+ if ((buf[0]==0xef)&&(buf[1]==0xff)) headerSz=2;
+ if ((buf[0]==0xff)&&(buf[1]==0xfe)) headerSz=2;
+ if ((buf[0]==0xef)&&(buf[1]==0xbb)&&(buf[2]==0xbf)) headerSz=3;
+ }
+#else
+ if (guessWideCharChars)
+ {
+ if (myIsTextWideChar(buf,l))
+ {
+ if ((buf[0]==0xef)&&(buf[1]==0xff)) headerSz=2;
+ if ((buf[0]==0xff)&&(buf[1]==0xfe)) headerSz=2;
+ char *b2=myWideCharToMultiByte((const wchar_t*)(buf+headerSz));
+ free(buf); buf=(unsigned char*)b2; headerSz=0;
+ } else
+ {
+ if ((buf[0]==0xef)&&(buf[1]==0xbb)&&(buf[2]==0xbf)) headerSz=3;
+ }
+ } else
+ {
+ if ((buf[0]==0xef)&&(buf[1]==0xff)) headerSz=2;
+ if ((buf[0]==0xff)&&(buf[1]==0xfe)) headerSz=2;
+ if ((buf[0]==0xef)&&(buf[1]==0xbb)&&(buf[2]==0xbf)) headerSz=3;
+ }
+#endif
+
+ if (!buf) { if (pResults) pResults->error=eXMLErrorCharConversionError; return emptyXMLNode; }
+ XMLNode x=parseString((XMLSTR)(buf+headerSz),tag,pResults);
+ free(buf);
+ return x;
+}
+
+static inline void charmemset(XMLSTR dest,XMLCHAR c,int l) { while (l--) *(dest++)=c; }
+// private:
+// Creates an user friendly XML string from a given element with
+// appropriate white space and carriage returns.
+//
+// This recurses through all subnodes then adds contents of the nodes to the
+// string.
+int XMLNode::CreateXMLStringR(XMLNodeData *pEntry, XMLSTR lpszMarker, int nFormat)
+{
+ int nResult = 0;
+ int cb=nFormat<0?0:nFormat;
+ int cbElement;
+ int nChildFormat=-1;
+ int nElementI=pEntry->nChild+pEntry->nText+pEntry->nClear;
+ int i,j;
+ if ((nFormat>=0)&&(nElementI==1)&&(pEntry->nText==1)&&(!pEntry->isDeclaration)) nFormat=-2;
+
+ assert(pEntry);
+
+#define LENSTR(lpsz) (lpsz ? xstrlen(lpsz) : 0)
+
+ // If the element has no name then assume this is the head node.
+ cbElement = (int)LENSTR(pEntry->lpszName);
+
+ if (cbElement)
+ {
+ // "<elementname "
+ if (lpszMarker)
+ {
+ if (cb) charmemset(lpszMarker, INDENTCHAR, cb);
+ nResult = cb;
+ lpszMarker[nResult++]=_CXML('<');
+ if (pEntry->isDeclaration) lpszMarker[nResult++]=_CXML('?');
+ xstrcpy(&lpszMarker[nResult], pEntry->lpszName);
+ nResult+=cbElement;
+ lpszMarker[nResult++]=_CXML(' ');
+
+ } else
+ {
+ nResult+=cbElement+2+cb;
+ if (pEntry->isDeclaration) nResult++;
+ }
+
+ // Enumerate attributes and add them to the string
+ XMLAttribute *pAttr=pEntry->pAttribute;
+ for (i=0; i<pEntry->nAttribute; i++)
+ {
+ // "Attrib
+ cb = (int)LENSTR(pAttr->lpszName);
+ if (cb)
+ {
+ if (lpszMarker) xstrcpy(&lpszMarker[nResult], pAttr->lpszName);
+ nResult += cb;
+ // "Attrib=Value "
+ if (pAttr->lpszValue)
+ {
+ cb=(int)ToXMLStringTool::lengthXMLString(pAttr->lpszValue);
+ if (lpszMarker)
+ {
+ lpszMarker[nResult]=_CXML('=');
+ lpszMarker[nResult+1]=_CXML('"');
+ if (cb) ToXMLStringTool::toXMLUnSafe(&lpszMarker[nResult+2],pAttr->lpszValue);
+ lpszMarker[nResult+cb+2]=_CXML('"');
+ }
+ nResult+=cb+3;
+ }
+ if (lpszMarker) lpszMarker[nResult] = _CXML(' ');
+ nResult++;
+ }
+ pAttr++;
+ }
+
+ if (pEntry->isDeclaration)
+ {
+ if (lpszMarker)
+ {
+ lpszMarker[nResult-1]=_CXML('?');
+ lpszMarker[nResult]=_CXML('>');
+ }
+ nResult++;
+ if (nFormat!=-1)
+ {
+ if (lpszMarker) lpszMarker[nResult]=_CXML('\n');
+ nResult++;
+ }
+ } else
+ // If there are child nodes we need to terminate the start tag
+ if (nElementI)
+ {
+ if (lpszMarker) lpszMarker[nResult-1]=_CXML('>');
+ if (nFormat>=0)
+ {
+ if (lpszMarker) lpszMarker[nResult]=_CXML('\n');
+ nResult++;
+ }
+ } else nResult--;
+ }
+
+ // Calculate the child format for when we recurse. This is used to
+ // determine the number of spaces used for prefixes.
+ if (nFormat!=-1)
+ {
+ if (cbElement&&(!pEntry->isDeclaration)) nChildFormat=nFormat+1;
+ else nChildFormat=nFormat;
+ }
+
+ // Enumerate through remaining children
+ for (i=0; i<nElementI; i++)
+ {
+ j=pEntry->pOrder[i];
+ switch((XMLElementType)(j&3))
+ {
+ // Text nodes
+ case eNodeText:
+ {
+ // "Text"
+ XMLCSTR pChild=pEntry->pText[j>>2];
+ cb = (int)ToXMLStringTool::lengthXMLString(pChild);
+ if (cb)
+ {
+ if (nFormat>=0)
+ {
+ if (lpszMarker)
+ {
+ charmemset(&lpszMarker[nResult],INDENTCHAR,nFormat+1);
+ ToXMLStringTool::toXMLUnSafe(&lpszMarker[nResult+nFormat+1],pChild);
+ lpszMarker[nResult+nFormat+1+cb]=_CXML('\n');
+ }
+ nResult+=cb+nFormat+2;
+ } else
+ {
+ if (lpszMarker) ToXMLStringTool::toXMLUnSafe(&lpszMarker[nResult], pChild);
+ nResult += cb;
+ }
+ }
+ break;
+ }
+
+ // Clear type nodes
+ case eNodeClear:
+ {
+ XMLClear *pChild=pEntry->pClear+(j>>2);
+ // "OpenTag"
+ cb = (int)LENSTR(pChild->lpszOpenTag);
+ if (cb)
+ {
+ if (nFormat!=-1)
+ {
+ if (lpszMarker)
+ {
+ charmemset(&lpszMarker[nResult], INDENTCHAR, nFormat+1);
+ xstrcpy(&lpszMarker[nResult+nFormat+1], pChild->lpszOpenTag);
+ }
+ nResult+=cb+nFormat+1;
+ }
+ else
+ {
+ if (lpszMarker)xstrcpy(&lpszMarker[nResult], pChild->lpszOpenTag);
+ nResult += cb;
+ }
+ }
+
+ // "OpenTag Value"
+ cb = (int)LENSTR(pChild->lpszValue);
+ if (cb)
+ {
+ if (lpszMarker) xstrcpy(&lpszMarker[nResult], pChild->lpszValue);
+ nResult += cb;
+ }
+
+ // "OpenTag Value CloseTag"
+ cb = (int)LENSTR(pChild->lpszCloseTag);
+ if (cb)
+ {
+ if (lpszMarker) xstrcpy(&lpszMarker[nResult], pChild->lpszCloseTag);
+ nResult += cb;
+ }
+
+ if (nFormat!=-1)
+ {
+ if (lpszMarker) lpszMarker[nResult] = _CXML('\n');
+ nResult++;
+ }
+ break;
+ }
+
+ // Element nodes
+ case eNodeChild:
+ {
+ // Recursively add child nodes
+ nResult += CreateXMLStringR(pEntry->pChild[j>>2].d, lpszMarker ? lpszMarker + nResult : 0, nChildFormat);
+ break;
+ }
+ default: break;
+ }
+ }
+
+ if ((cbElement)&&(!pEntry->isDeclaration))
+ {
+ // If we have child entries we need to use long XML notation for
+ // closing the element - "<elementname>blah blah blah</elementname>"
+ if (nElementI)
+ {
+ // "</elementname>\0"
+ if (lpszMarker)
+ {
+ if (nFormat >=0)
+ {
+ charmemset(&lpszMarker[nResult], INDENTCHAR,nFormat);
+ nResult+=nFormat;
+ }
+
+ lpszMarker[nResult]=_CXML('<'); lpszMarker[nResult+1]=_CXML('/');
+ nResult += 2;
+ xstrcpy(&lpszMarker[nResult], pEntry->lpszName);
+ nResult += cbElement;
+
+ lpszMarker[nResult]=_CXML('>');
+ if (nFormat == -1) nResult++;
+ else
+ {
+ lpszMarker[nResult+1]=_CXML('\n');
+ nResult+=2;
+ }
+ } else
+ {
+ if (nFormat>=0) nResult+=cbElement+4+nFormat;
+ else if (nFormat==-1) nResult+=cbElement+3;
+ else nResult+=cbElement+4;
+ }
+ } else
+ {
+ // If there are no children we can use shorthand XML notation -
+ // "<elementname/>"
+ // "/>\0"
+ if (lpszMarker)
+ {
+ lpszMarker[nResult]=_CXML('/'); lpszMarker[nResult+1]=_CXML('>');
+ if (nFormat != -1) lpszMarker[nResult+2]=_CXML('\n');
+ }
+ nResult += nFormat == -1 ? 2 : 3;
+ }
+ }
+
+ return nResult;
+}
+
+#undef LENSTR
+
+// Create an XML string
+// @param int nFormat - 0 if no formatting is required
+// otherwise nonzero for formatted text
+// with carriage returns and indentation.
+// @param int *pnSize - [out] pointer to the size of the
+// returned string not including the
+// NULL terminator.
+// @return XMLSTR - Allocated XML string, you must free
+// this with free().
+XMLSTR XMLNode::createXMLString(int nFormat, int *pnSize) const
+{
+ if (!d) { if (pnSize) *pnSize=0; return NULL; }
+
+ XMLSTR lpszResult = NULL;
+ int cbStr;
+
+ // Recursively Calculate the size of the XML string
+ if (!dropWhiteSpace) nFormat=0;
+ nFormat = nFormat ? 0 : -1;
+ cbStr = CreateXMLStringR(d, 0, nFormat);
+ // Alllocate memory for the XML string + the NULL terminator and
+ // create the recursively XML string.
+ lpszResult=(XMLSTR)malloc((cbStr+1)*sizeof(XMLCHAR));
+ CreateXMLStringR(d, lpszResult, nFormat);
+ lpszResult[cbStr]=_CXML('\0');
+ if (pnSize) *pnSize = cbStr;
+ return lpszResult;
+}
+
+int XMLNode::detachFromParent(XMLNodeData *d)
+{
+ XMLNode *pa=d->pParent->pChild;
+ int i=0;
+ while (((void*)(pa[i].d))!=((void*)d)) i++;
+ d->pParent->nChild--;
+ if (d->pParent->nChild) memmove(pa+i,pa+i+1,(d->pParent->nChild-i)*sizeof(XMLNode));
+ else { free(pa); d->pParent->pChild=NULL; }
+ return removeOrderElement(d->pParent,eNodeChild,i);
+}
+
+XMLNode::~XMLNode()
+{
+ if (!d) return;
+ d->ref_count--;
+ emptyTheNode(0);
+}
+void XMLNode::deleteNodeContent()
+{
+ if (!d) return;
+ if (d->pParent) { detachFromParent(d); d->pParent=NULL; d->ref_count--; }
+ emptyTheNode(1);
+}
+void XMLNode::emptyTheNode(char force)
+{
+ XMLNodeData *dd=d; // warning: must stay this way!
+ if ((dd->ref_count==0)||force)
+ {
+ if (d->pParent) detachFromParent(d);
+ int i;
+ XMLNode *pc;
+ for(i=0; i<dd->nChild; i++)
+ {
+ pc=dd->pChild+i;
+ pc->d->pParent=NULL;
+ pc->d->ref_count--;
+ pc->emptyTheNode(force);
+ }
+ myFree(dd->pChild);
+ for(i=0; i<dd->nText; i++) free((void*)dd->pText[i]);
+ myFree(dd->pText);
+ for(i=0; i<dd->nClear; i++) free((void*)dd->pClear[i].lpszValue);
+ myFree(dd->pClear);
+ for(i=0; i<dd->nAttribute; i++)
+ {
+ free((void*)dd->pAttribute[i].lpszName);
+ if (dd->pAttribute[i].lpszValue) free((void*)dd->pAttribute[i].lpszValue);
+ }
+ myFree(dd->pAttribute);
+ myFree(dd->pOrder);
+ myFree(dd->pInnerText);
+ if (dd->lpszNS)
+ myFree((void*)dd->lpszNS);
+ else
+ myFree((void*)dd->lpszName);
+ dd->nChild=0; dd->nText=0; dd->nClear=0; dd->nAttribute=0;
+ dd->pChild=NULL; dd->pText=NULL; dd->pClear=NULL; dd->pAttribute=NULL;
+ dd->pOrder=NULL; dd->pInnerText=NULL; dd->lpszNS=dd->lpszName=NULL; dd->pParent=NULL;
+ }
+ if (dd->ref_count==0)
+ {
+ free(dd);
+ d=NULL;
+ }
+}
+void XMLNode::invalidateInnerText()
+{
+ if (!d) return;
+ myFree(d->pInnerText);
+ d->pInnerText= NULL;
+}
+
+XMLNode& XMLNode::operator=( const XMLNode& A )
+{
+ // shallow copy
+ if (this != &A)
+ {
+ if (d) { d->ref_count--; emptyTheNode(0); }
+ d=A.d;
+ if (d) (d->ref_count) ++ ;
+ }
+ return *this;
+}
+
+XMLNode::XMLNode(const XMLNode &A)
+{
+ // shallow copy
+ d=A.d;
+ if (d) (d->ref_count)++ ;
+}
+
+XMLNode XMLNode::deepCopy() const
+{
+ if (!d) return XMLNode::emptyXMLNode;
+ XMLNode x(NULL,stringDup(d->lpszName),d->isDeclaration);
+ XMLNodeData *p=x.d;
+ int n=d->nAttribute;
+ if (n)
+ {
+ p->nAttribute=n; p->pAttribute=(XMLAttribute*)malloc(n*sizeof(XMLAttribute));
+ while (n--)
+ {
+ p->pAttribute[n].lpszName=stringDup(d->pAttribute[n].lpszName);
+ p->pAttribute[n].lpszValue=stringDup(d->pAttribute[n].lpszValue);
+ }
+ }
+ if (d->pOrder)
+ {
+ n=(d->nChild+d->nText+d->nClear)*sizeof(int); p->pOrder=(int*)malloc(n); memcpy(p->pOrder,d->pOrder,n);
+ }
+ n=d->nText;
+ if (n)
+ {
+ p->nText=n; p->pText=(XMLCSTR*)malloc(n*sizeof(XMLCSTR));
+ while(n--) p->pText[n]=stringDup(d->pText[n]);
+ }
+ n=d->nClear;
+ if (n)
+ {
+ p->nClear=n; p->pClear=(XMLClear*)malloc(n*sizeof(XMLClear));
+ while (n--)
+ {
+ p->pClear[n].lpszCloseTag=d->pClear[n].lpszCloseTag;
+ p->pClear[n].lpszOpenTag=d->pClear[n].lpszOpenTag;
+ p->pClear[n].lpszValue=stringDup(d->pClear[n].lpszValue);
+ }
+ }
+ n=d->nChild;
+ if (n)
+ {
+ p->nChild=n; p->pChild=(XMLNode*)malloc(n*sizeof(XMLNode));
+ while (n--)
+ {
+ p->pChild[n].d=NULL;
+ p->pChild[n]=d->pChild[n].deepCopy();
+ p->pChild[n].d->pParent=p;
+ }
+ }
+ return x;
+}
+
+XMLNode XMLNode::addChild(XMLNode childNode, int pos)
+{
+ XMLNodeData *dc=childNode.d;
+ if ((!dc)||(!d)) return childNode;
+ if (!dc->lpszName)
+ {
+ // this is a root node: todo: correct fix
+ int j=pos;
+ while (dc->nChild)
+ {
+ addChild(dc->pChild[0],j);
+ if (pos>=0) j++;
+ }
+ return childNode;
+ }
+ if (dc->pParent) { if ((detachFromParent(dc)<=pos)&&(dc->pParent==d)) pos--; } else dc->ref_count++;
+ dc->pParent=d;
+ // int nc=d->nChild;
+ // d->pChild=(XMLNode*)myRealloc(d->pChild,(nc+1),memoryIncrease,sizeof(XMLNode));
+ d->pChild=(XMLNode*)addToOrder(0,&pos,d->nChild,d->pChild,sizeof(XMLNode),eNodeChild);
+ d->pChild[pos].d=dc;
+ d->nChild++;
+ return childNode;
+}
+
+void XMLNode::deleteAttribute(int i)
+{
+ if ((!d)||(i<0)||(i>=d->nAttribute)) return;
+ d->nAttribute--;
+ XMLAttribute *p=d->pAttribute+i;
+ free((void*)p->lpszName);
+ if (p->lpszValue) free((void*)p->lpszValue);
+ if (d->nAttribute) memmove(p,p+1,(d->nAttribute-i)*sizeof(XMLAttribute)); else { free(p); d->pAttribute=NULL; }
+}
+
+void XMLNode::deleteAttribute(XMLAttribute *a){ if (a) deleteAttribute(a->lpszName); }
+void XMLNode::deleteAttribute(XMLCSTR lpszName)
+{
+ int j=0;
+ getAttribute(lpszName,&j);
+ if (j) deleteAttribute(j-1);
+}
+
+XMLAttribute *XMLNode::updateAttribute_WOSD(XMLSTR lpszNewValue, XMLSTR lpszNewName,int i)
+{
+ if (!d) { if (lpszNewValue) free(lpszNewValue); if (lpszNewName) free(lpszNewName); return NULL; }
+ if (i>=d->nAttribute)
+ {
+ if (lpszNewName) return addAttribute_WOSD(lpszNewName,lpszNewValue);
+ return NULL;
+ }
+ XMLAttribute *p=d->pAttribute+i;
+ if (p->lpszValue&&p->lpszValue!=lpszNewValue) free((void*)p->lpszValue);
+ p->lpszValue=lpszNewValue;
+ if (lpszNewName&&p->lpszName!=lpszNewName) { free((void*)p->lpszName); p->lpszName=lpszNewName; };
+ return p;
+}
+
+XMLAttribute *XMLNode::updateAttribute_WOSD(XMLAttribute *newAttribute, XMLAttribute *oldAttribute)
+{
+ if (oldAttribute) return updateAttribute_WOSD((XMLSTR)newAttribute->lpszValue,(XMLSTR)newAttribute->lpszName,oldAttribute->lpszName);
+ return addAttribute_WOSD((XMLSTR)newAttribute->lpszName,(XMLSTR)newAttribute->lpszValue);
+}
+
+XMLAttribute *XMLNode::updateAttribute_WOSD(XMLSTR lpszNewValue, XMLSTR lpszNewName,XMLCSTR lpszOldName)
+{
+ int j=0;
+ getAttribute(lpszOldName,&j);
+ if (j) return updateAttribute_WOSD(lpszNewValue,lpszNewName,j-1);
+ else
+ {
+ if (lpszNewName) return addAttribute_WOSD(lpszNewName,lpszNewValue);
+ else return addAttribute_WOSD(stringDup(lpszOldName),lpszNewValue);
+ }
+}
+
+int XMLNode::indexText(XMLCSTR lpszValue) const
+{
+ if (!d) return -1;
+ int i,l=d->nText;
+ if (!lpszValue) { if (l) return 0; return -1; }
+ XMLCSTR *p=d->pText;
+ for (i=0; i<l; i++) if (lpszValue==p[i]) return i;
+ return -1;
+}
+
+void XMLNode::deleteText(int i)
+{
+ if ((!d)||(i<0)||(i>=d->nText)) return;
+ invalidateInnerText();
+ d->nText--;
+ XMLCSTR *p=d->pText+i;
+ free((void*)*p);
+ if (d->nText) memmove(p,p+1,(d->nText-i)*sizeof(XMLCSTR)); else { free(p); d->pText=NULL; }
+ removeOrderElement(d,eNodeText,i);
+}
+
+void XMLNode::deleteText(XMLCSTR lpszValue) { deleteText(indexText(lpszValue)); }
+
+XMLCSTR XMLNode::updateText_WOSD(XMLSTR lpszNewValue, int i)
+{
+ if (!d) { if (lpszNewValue) free(lpszNewValue); return NULL; }
+ if (i>=d->nText) return addText_WOSD(lpszNewValue);
+ invalidateInnerText();
+ XMLCSTR *p=d->pText+i;
+ if (*p!=lpszNewValue) { free((void*)*p); *p=lpszNewValue; }
+ return lpszNewValue;
+}
+
+XMLCSTR XMLNode::updateText_WOSD(XMLSTR lpszNewValue, XMLCSTR lpszOldValue)
+{
+ if (!d) { if (lpszNewValue) free(lpszNewValue); return NULL; }
+ int i=indexText(lpszOldValue);
+ if (i>=0) return updateText_WOSD(lpszNewValue,i);
+ return addText_WOSD(lpszNewValue);
+}
+
+void XMLNode::deleteClear(int i)
+{
+ if ((!d)||(i<0)||(i>=d->nClear)) return;
+ invalidateInnerText();
+ d->nClear--;
+ XMLClear *p=d->pClear+i;
+ free((void*)p->lpszValue);
+ if (d->nClear) memmove(p,p+1,(d->nClear-i)*sizeof(XMLClear)); else { free(p); d->pClear=NULL; }
+ removeOrderElement(d,eNodeClear,i);
+}
+
+int XMLNode::indexClear(XMLCSTR lpszValue) const
+{
+ if (!d) return -1;
+ int i,l=d->nClear;
+ if (!lpszValue) { if (l) return 0; return -1; }
+ XMLClear *p=d->pClear;
+ for (i=0; i<l; i++) if (lpszValue==p[i].lpszValue) return i;
+ return -1;
+}
+
+void XMLNode::deleteClear(XMLCSTR lpszValue) { deleteClear(indexClear(lpszValue)); }
+void XMLNode::deleteClear(XMLClear *a) { if (a) deleteClear(a->lpszValue); }
+
+XMLClear *XMLNode::updateClear_WOSD(XMLSTR lpszNewContent, int i)
+{
+ if (!d) { if (lpszNewContent) free(lpszNewContent); return NULL; }
+ if (i>=d->nClear) return addClear_WOSD(lpszNewContent);
+ invalidateInnerText();
+ XMLClear *p=d->pClear+i;
+ if (lpszNewContent!=p->lpszValue) { free((void*)p->lpszValue); p->lpszValue=lpszNewContent; }
+ return p;
+}
+
+XMLClear *XMLNode::updateClear_WOSD(XMLSTR lpszNewContent, XMLCSTR lpszOldValue)
+{
+ if (!d) { if (lpszNewContent) free(lpszNewContent); return NULL; }
+ int i=indexClear(lpszOldValue);
+ if (i>=0) return updateClear_WOSD(lpszNewContent,i);
+ return addClear_WOSD(lpszNewContent);
+}
+
+XMLClear *XMLNode::updateClear_WOSD(XMLClear *newP,XMLClear *oldP)
+{
+ if (oldP) return updateClear_WOSD((XMLSTR)newP->lpszValue,(XMLSTR)oldP->lpszValue);
+ return NULL;
+}
+
+int XMLNode::nChildNode(XMLCSTR name) const
+{
+ if (!d) return 0;
+ int i,j=0,n=d->nChild;
+ XMLNode *pc=d->pChild;
+ for (i=0; i<n; i++)
+ {
+ if (xstricmp(pc->d->lpszName, name)==0) j++;
+ pc++;
+ }
+ return j;
+}
+
+XMLNode XMLNode::getChildNode(XMLCSTR name, int *j) const
+{
+ if (!d) return emptyXMLNode;
+ int i=0,n=d->nChild;
+ if (j) i=*j;
+ XMLNode *pc=d->pChild+i;
+ for (; i<n; i++)
+ {
+ if (!xstricmp(pc->d->lpszName, name))
+ {
+ if (j) *j=i+1;
+ return *pc;
+ }
+ pc++;
+ }
+ return emptyXMLNode;
+}
+
+XMLNode XMLNode::getChildNode(XMLCSTR name, int j) const
+{
+ if (!d) return emptyXMLNode;
+ if (j>=0)
+ {
+ int i=0;
+ while (j-->0) getChildNode(name,&i);
+ return getChildNode(name,&i);
+ }
+ int i=d->nChild;
+ while (i--) if (!xstricmp(name,d->pChild[i].d->lpszName)) break;
+ if (i<0) return emptyXMLNode;
+ return getChildNode(i);
+}
+
+XMLNode XMLNode::getNextNode() const
+{
+ if (!d) return emptyXMLNode;
+ XMLNodeDataTag *par=d->pParent;
+ if (!par) return emptyXMLNode;
+ int i,n=par->nChild;
+ for (i=0; i<n; ++i)
+ {
+ if (par->pChild[i].d == d) break;
+ }
+ return XMLNode(par).getChildNode(d->lpszName, &++i);
+}
+
+XMLNode XMLNode::getChildNodeByPath(XMLCSTR _path, char createMissing, XMLCHAR sep)
+{
+ XMLSTR path=stringDup(_path);
+ XMLNode x=getChildNodeByPathNonConst(path,createMissing,sep);
+ if (path) free(path);
+ return x;
+}
+
+XMLNode XMLNode::getChildNodeByPathNonConst(XMLSTR path, char createIfMissing, XMLCHAR sep)
+{
+ if ((!path)||(!(*path))) return *this;
+ XMLNode xn,xbase=*this;
+ XMLCHAR *tend1,sepString[2]; sepString[0]=sep; sepString[1]=0;
+ tend1=xstrstr(path,sepString);
+ while(tend1)
+ {
+ *tend1=0;
+ xn=xbase.getChildNode(path);
+ if (xn.isEmpty())
+ {
+ if (createIfMissing) xn=xbase.addChild(path);
+ else { *tend1=sep; return XMLNode::emptyXMLNode; }
+ }
+ *tend1=sep;
+ xbase=xn;
+ path=tend1+1;
+ tend1=xstrstr(path,sepString);
+ }
+ xn=xbase.getChildNode(path);
+ if (xn.isEmpty()&&createIfMissing) xn=xbase.addChild(path);
+ return xn;
+}
+
+XMLElementPosition XMLNode::positionOfText (int i) const { if (i>=d->nText ) i=d->nText-1; return findPosition(d,i,eNodeText ); }
+XMLElementPosition XMLNode::positionOfClear (int i) const { if (i>=d->nClear) i=d->nClear-1; return findPosition(d,i,eNodeClear); }
+XMLElementPosition XMLNode::positionOfChildNode(int i) const { if (i>=d->nChild) i=d->nChild-1; return findPosition(d,i,eNodeChild); }
+XMLElementPosition XMLNode::positionOfText (XMLCSTR lpszValue) const { return positionOfText (indexText (lpszValue)); }
+XMLElementPosition XMLNode::positionOfClear(XMLCSTR lpszValue) const { return positionOfClear(indexClear(lpszValue)); }
+XMLElementPosition XMLNode::positionOfClear(XMLClear *a) const { if (a) return positionOfClear(a->lpszValue); return positionOfClear(); }
+XMLElementPosition XMLNode::positionOfChildNode(XMLNode x) const
+{
+ if ((!d)||(!x.d)) return -1;
+ XMLNodeData *dd=x.d;
+ XMLNode *pc=d->pChild;
+ int i=d->nChild;
+ while (i--) if (pc[i].d==dd) return findPosition(d,i,eNodeChild);
+ return -1;
+}
+XMLElementPosition XMLNode::positionOfChildNode(XMLCSTR name, int count) const
+{
+ if (!name) return positionOfChildNode(count);
+ int j=0;
+ do { getChildNode(name,&j); if (j<0) return -1; } while (count--);
+ return findPosition(d,j-1,eNodeChild);
+}
+
+XMLNode XMLNode::getChildNodeWithAttribute(XMLCSTR name,XMLCSTR attributeName,XMLCSTR attributeValue, int *k) const
+{
+ int i=0,j;
+ if (k) i=*k;
+ XMLNode x;
+ XMLCSTR t;
+ do
+ {
+ x=getChildNode(name,&i);
+ if (!x.isEmpty())
+ {
+ if (attributeValue)
+ {
+ j=0;
+ do
+ {
+ t=x.getAttribute(attributeName,&j);
+ if (t&&(xstricmp(attributeValue,t)==0)) { if (k) *k=i; return x; }
+ } while (t);
+ } else
+ {
+ if (x.isAttributeSet(attributeName)) { if (k) *k=i; return x; }
+ }
+ }
+ } while (!x.isEmpty());
+ return emptyXMLNode;
+}
+
+// Find an attribute on an node.
+XMLCSTR XMLNode::getAttribute(XMLCSTR lpszAttrib, int *j) const
+{
+ if (!d) return NULL;
+ int i=0,n=d->nAttribute;
+ if (j) i=*j;
+ XMLAttribute *pAttr=d->pAttribute+i;
+ for (; i<n; i++)
+ {
+ if (xstricmp(pAttr->lpszName, lpszAttrib)==0)
+ {
+ if (j) *j=i+1;
+ return pAttr->lpszValue;
+ }
+ pAttr++;
+ }
+ return NULL;
+}
+
+char XMLNode::isAttributeSet(XMLCSTR lpszAttrib) const
+{
+ if (!d) return FALSE;
+ int i,n=d->nAttribute;
+ XMLAttribute *pAttr=d->pAttribute;
+ for (i=0; i<n; i++)
+ {
+ if (xstricmp(pAttr->lpszName, lpszAttrib)==0)
+ {
+ return TRUE;
+ }
+ pAttr++;
+ }
+ return FALSE;
+}
+
+XMLCSTR XMLNode::getAttribute(XMLCSTR name, int j) const
+{
+ if (!d) return NULL;
+ int i=0;
+ while (j-->0) getAttribute(name,&i);
+ return getAttribute(name,&i);
+}
+
+XMLNodeContents XMLNode::enumContents(int i) const
+{
+ XMLNodeContents c;
+ if (!d) { c.etype=eNodeNULL; return c; }
+ if (i<d->nAttribute)
+ {
+ c.etype=eNodeAttribute;
+ c.attrib=d->pAttribute[i];
+ return c;
+ }
+ i-=d->nAttribute;
+ c.etype=(XMLElementType)(d->pOrder[i]&3);
+ i=(d->pOrder[i])>>2;
+ switch (c.etype)
+ {
+ case eNodeChild: c.child = d->pChild[i]; break;
+ case eNodeText: c.text = d->pText[i]; break;
+ case eNodeClear: c.clear = d->pClear[i]; break;
+ default: break;
+ }
+ return c;
+}
+
+XMLCSTR XMLNode::getInnerText() const
+{
+ if (!d) return NULL;
+ if (nText() <= 1 && nClear() == 0) return getText();
+ if (d->pInnerText) return d->pInnerText;
+
+ int count = nElement();
+ int i, length = 1;
+ for (i = 0; i < count; ++i)
+ {
+ XMLNodeContents c = enumContents(i);
+ switch (c.etype)
+ {
+ case eNodeText:
+ length += xstrlen(c.text);
+ break;
+ case eNodeClear:
+ length += xstrlen(c.clear.lpszValue);
+ break;
+ }
+ }
+ XMLCHAR *buf = (XMLCHAR *)malloc(sizeof(XMLCHAR) * length);
+ XMLCHAR *pos = buf;
+ for (i = 0; i < count; ++i)
+ {
+ XMLNodeContents c = enumContents(i);
+ switch (c.etype)
+ {
+ case eNodeText:
+ xstrcpy(pos, c.text);
+ pos += xstrlen(c.text);
+ break;
+ case eNodeClear:
+ xstrcpy(pos, c.clear.lpszValue);
+ pos += xstrlen(c.clear.lpszValue);
+ break;
+ }
+ }
+ return d->pInnerText = buf;
+}
+
+XMLCSTR XMLNode::getName() const { if (!d) return NULL; return d->lpszName; }
+int XMLNode::nText() const { if (!d) return 0; return d->nText; }
+int XMLNode::nChildNode() const { if (!d) return 0; return d->nChild; }
+int XMLNode::nAttribute() const { if (!d) return 0; return d->nAttribute; }
+int XMLNode::nClear() const { if (!d) return 0; return d->nClear; }
+int XMLNode::nElement() const { if (!d) return 0; return d->nAttribute+d->nChild+d->nText+d->nClear; }
+XMLClear XMLNode::getClear (int i) const { if ((!d)||(i>=d->nClear )) return emptyXMLClear; return d->pClear[i]; }
+XMLAttribute XMLNode::getAttribute (int i) const { if ((!d)||(i>=d->nAttribute)) return emptyXMLAttribute; return d->pAttribute[i]; }
+XMLCSTR XMLNode::getAttributeName (int i) const { if ((!d)||(i>=d->nAttribute)) return NULL; return d->pAttribute[i].lpszName; }
+XMLCSTR XMLNode::getAttributeValue(int i) const { if ((!d)||(i>=d->nAttribute)) return NULL; return d->pAttribute[i].lpszValue; }
+XMLCSTR XMLNode::getText (int i) const { if ((!d)||(i>=d->nText )) return NULL; return d->pText[i]; }
+XMLNode XMLNode::getChildNode (int i) const { if ((!d)||(i>=d->nChild )) return emptyXMLNode; return d->pChild[i]; }
+XMLNode XMLNode::getParentNode ( ) const { if ((!d)||(!d->pParent )) return emptyXMLNode; return XMLNode(d->pParent); }
+char XMLNode::isDeclaration ( ) const { if (!d) return 0; return d->isDeclaration; }
+char XMLNode::isEmpty ( ) const { return (d==NULL); }
+XMLNode XMLNode::emptyNode ( ) { return XMLNode::emptyXMLNode; }
+
+XMLNode XMLNode::addChild(XMLCSTR lpszName, char isDeclaration, XMLElementPosition pos)
+{ return addChild_priv(0,stringDup(lpszName),isDeclaration,pos); }
+XMLNode XMLNode::addChild_WOSD(XMLSTR lpszName, char isDeclaration, XMLElementPosition pos)
+{ return addChild_priv(0,lpszName,isDeclaration,pos); }
+XMLAttribute *XMLNode::addAttribute(XMLCSTR lpszName, XMLCSTR lpszValue)
+{ return addAttribute_priv(0,stringDup(lpszName),stringDup(lpszValue)); }
+XMLAttribute *XMLNode::addAttribute_WOSD(XMLSTR lpszName, XMLSTR lpszValuev)
+{ return addAttribute_priv(0,lpszName,lpszValuev); }
+XMLCSTR XMLNode::addText(XMLCSTR lpszValue, XMLElementPosition pos)
+{ return addText_priv(0,stringDup(lpszValue),pos); }
+XMLCSTR XMLNode::addText_WOSD(XMLSTR lpszValue, XMLElementPosition pos)
+{ return addText_priv(0,lpszValue,pos); }
+XMLClear *XMLNode::addClear(XMLCSTR lpszValue, XMLCSTR lpszOpen, XMLCSTR lpszClose, XMLElementPosition pos)
+{ return addClear_priv(0,stringDup(lpszValue),lpszOpen,lpszClose,pos); }
+XMLClear *XMLNode::addClear_WOSD(XMLSTR lpszValue, XMLCSTR lpszOpen, XMLCSTR lpszClose, XMLElementPosition pos)
+{ return addClear_priv(0,lpszValue,lpszOpen,lpszClose,pos); }
+XMLCSTR XMLNode::updateName(XMLCSTR lpszName)
+{ return updateName_WOSD(stringDup(lpszName)); }
+XMLAttribute *XMLNode::updateAttribute(XMLAttribute *newAttribute, XMLAttribute *oldAttribute)
+{ return updateAttribute_WOSD(stringDup(newAttribute->lpszValue),stringDup(newAttribute->lpszName),oldAttribute->lpszName); }
+XMLAttribute *XMLNode::updateAttribute(XMLCSTR lpszNewValue, XMLCSTR lpszNewName,int i)
+{ return updateAttribute_WOSD(stringDup(lpszNewValue),stringDup(lpszNewName),i); }
+XMLAttribute *XMLNode::updateAttribute(XMLCSTR lpszNewValue, XMLCSTR lpszNewName,XMLCSTR lpszOldName)
+{ return updateAttribute_WOSD(stringDup(lpszNewValue),stringDup(lpszNewName),lpszOldName); }
+XMLCSTR XMLNode::updateText(XMLCSTR lpszNewValue, int i)
+{ return updateText_WOSD(stringDup(lpszNewValue),i); }
+XMLCSTR XMLNode::updateText(XMLCSTR lpszNewValue, XMLCSTR lpszOldValue)
+{ return updateText_WOSD(stringDup(lpszNewValue),lpszOldValue); }
+XMLClear *XMLNode::updateClear(XMLCSTR lpszNewContent, int i)
+{ return updateClear_WOSD(stringDup(lpszNewContent),i); }
+XMLClear *XMLNode::updateClear(XMLCSTR lpszNewValue, XMLCSTR lpszOldValue)
+{ return updateClear_WOSD(stringDup(lpszNewValue),lpszOldValue); }
+XMLClear *XMLNode::updateClear(XMLClear *newP,XMLClear *oldP)
+{ return updateClear_WOSD(stringDup(newP->lpszValue),oldP->lpszValue); }
+
+char XMLNode::setGlobalOptions(XMLCharEncoding _characterEncoding, char _guessWideCharChars,
+ char _dropWhiteSpace, char _removeCommentsInMiddleOfText)
+{
+ guessWideCharChars=_guessWideCharChars; dropWhiteSpace=_dropWhiteSpace; removeCommentsInMiddleOfText=_removeCommentsInMiddleOfText;
+#ifdef _XMLWIDECHAR
+ if (_characterEncoding) characterEncoding=_characterEncoding;
+#else
+ switch(_characterEncoding)
+ {
+ case char_encoding_UTF8: characterEncoding=_characterEncoding; XML_ByteTable=XML_utf8ByteTable; break;
+ case char_encoding_legacy: characterEncoding=_characterEncoding; XML_ByteTable=XML_legacyByteTable; break;
+ case char_encoding_ShiftJIS: characterEncoding=_characterEncoding; XML_ByteTable=XML_sjisByteTable; break;
+ case char_encoding_GB2312: characterEncoding=_characterEncoding; XML_ByteTable=XML_gb2312ByteTable; break;
+ case char_encoding_Big5:
+ case char_encoding_GBK: characterEncoding=_characterEncoding; XML_ByteTable=XML_gbk_big5_ByteTable; break;
+ default: return 1;
+ }
+#endif
+ return 0;
+}
+
+XMLNode::XMLCharEncoding XMLNode::guessCharEncoding(void *buf,int l, char useXMLEncodingAttribute)
+{
+#ifdef _XMLWIDECHAR
+ return (XMLCharEncoding)0;
+#else
+ if (l<25) return (XMLCharEncoding)0;
+ if (guessWideCharChars&&(myIsTextWideChar(buf,l))) return (XMLCharEncoding)0;
+ unsigned char *b=(unsigned char*)buf;
+ if ((b[0]==0xef)&&(b[1]==0xbb)&&(b[2]==0xbf)) return char_encoding_UTF8;
+
+ // Match utf-8 model ?
+ XMLCharEncoding bestGuess=char_encoding_UTF8;
+ int i=0;
+ while (i<l)
+ switch (XML_utf8ByteTable[b[i]])
+ {
+ case 4: i++; if ((i<l)&&(b[i]& 0xC0)!=0x80) { bestGuess=char_encoding_legacy; i=l; } // 10bbbbbb ?
+ case 3: i++; if ((i<l)&&(b[i]& 0xC0)!=0x80) { bestGuess=char_encoding_legacy; i=l; } // 10bbbbbb ?
+ case 2: i++; if ((i<l)&&(b[i]& 0xC0)!=0x80) { bestGuess=char_encoding_legacy; i=l; } // 10bbbbbb ?
+ case 1: i++; break;
+ case 0: i=l;
+ }
+ if (!useXMLEncodingAttribute) return bestGuess;
+ // if encoding is specified and different from utf-8 than it's non-utf8
+ // otherwise it's utf-8
+ char bb[201];
+ l=mmin(l,200);
+ memcpy(bb,buf,l); // copy buf into bb to be able to do "bb[l]=0"
+ bb[l]=0;
+ b=(unsigned char*)strstr(bb,"encoding");
+ if (!b) return bestGuess;
+ b+=8; while XML_isSPACECHAR(*b) b++; if (*b!='=') return bestGuess;
+ b++; while XML_isSPACECHAR(*b) b++; if ((*b!='\'')&&(*b!='"')) return bestGuess;
+ b++; while XML_isSPACECHAR(*b) b++;
+
+ if ((xstrnicmp((char*)b,"utf-8",5)==0)||
+ (xstrnicmp((char*)b,"utf8",4)==0))
+ {
+ if (bestGuess==char_encoding_legacy) return char_encoding_error;
+ return char_encoding_UTF8;
+ }
+
+ if ((xstrnicmp((char*)b,"shiftjis",8)==0)||
+ (xstrnicmp((char*)b,"shift-jis",9)==0)||
+ (xstrnicmp((char*)b,"sjis",4)==0)) return char_encoding_ShiftJIS;
+
+ if (xstrnicmp((char*)b,"GB2312",6)==0) return char_encoding_GB2312;
+ if (xstrnicmp((char*)b,"Big5",4)==0) return char_encoding_Big5;
+ if (xstrnicmp((char*)b,"GBK",3)==0) return char_encoding_GBK;
+
+ return char_encoding_legacy;
+#endif
+}
+#undef XML_isSPACECHAR
+
+//////////////////////////////////////////////////////////
+// Here starts the base64 conversion functions. //
+//////////////////////////////////////////////////////////
+
+static const char base64Fillchar = _CXML('='); // used to mark partial words at the end
+
+// this lookup table defines the base64 encoding
+XMLCSTR base64EncodeTable=_CXML("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
+
+// Decode Table gives the index of any valid base64 character in the Base64 table]
+// 96: '=' - 97: space char - 98: illegal char - 99: end of string
+const unsigned char base64DecodeTable[] = {
+ 99,98,98,98,98,98,98,98,98,97, 97,98,98,97,98,98,98,98,98,98, 98,98,98,98,98,98,98,98,98,98, //00 -29
+ 98,98,97,98,98,98,98,98,98,98, 98,98,98,62,98,98,98,63,52,53, 54,55,56,57,58,59,60,61,98,98, //30 -59
+ 98,96,98,98,98, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14, 15,16,17,18,19,20,21,22,23,24, //60 -89
+ 25,98,98,98,98,98,98,26,27,28, 29,30,31,32,33,34,35,36,37,38, 39,40,41,42,43,44,45,46,47,48, //90 -119
+ 49,50,51,98,98,98,98,98,98,98, 98,98,98,98,98,98,98,98,98,98, 98,98,98,98,98,98,98,98,98,98, //120 -149
+ 98,98,98,98,98,98,98,98,98,98, 98,98,98,98,98,98,98,98,98,98, 98,98,98,98,98,98,98,98,98,98, //150 -179
+ 98,98,98,98,98,98,98,98,98,98, 98,98,98,98,98,98,98,98,98,98, 98,98,98,98,98,98,98,98,98,98, //180 -209
+ 98,98,98,98,98,98,98,98,98,98, 98,98,98,98,98,98,98,98,98,98, 98,98,98,98,98,98,98,98,98,98, //210 -239
+ 98,98,98,98,98,98,98,98,98,98, 98,98,98,98,98,98 //240 -255
+};
+
+XMLParserBase64Tool::~XMLParserBase64Tool(){ freeBuffer(); }
+
+void XMLParserBase64Tool::freeBuffer(){ if (buf) free(buf); buf=NULL; buflen=0; }
+
+int XMLParserBase64Tool::encodeLength(int inlen, char formatted)
+{
+ unsigned int i=((inlen-1)/3*4+4+1);
+ if (formatted) i+=inlen/54;
+ return i;
+}
+
+XMLSTR XMLParserBase64Tool::encode(unsigned char *inbuf, unsigned int inlen, char formatted)
+{
+ int i=encodeLength(inlen,formatted),k=17,eLen=inlen/3,j;
+ alloc(i*sizeof(XMLCHAR));
+ XMLSTR curr=(XMLSTR)buf;
+ for(i=0;i<eLen;i++)
+ {
+ // Copy next three bytes into lower 24 bits of int, paying attention to sign.
+ j=(inbuf[0]<<16)|(inbuf[1]<<8)|inbuf[2]; inbuf+=3;
+ // Encode the int into four chars
+ *(curr++)=base64EncodeTable[ j>>18 ];
+ *(curr++)=base64EncodeTable[(j>>12)&0x3f];
+ *(curr++)=base64EncodeTable[(j>> 6)&0x3f];
+ *(curr++)=base64EncodeTable[(j )&0x3f];
+ if (formatted) { if (!k) { *(curr++)=_CXML('\n'); k=18; } k--; }
+ }
+ eLen=inlen-eLen*3; // 0 - 2.
+ if (eLen==1)
+ {
+ *(curr++)=base64EncodeTable[ inbuf[0]>>2 ];
+ *(curr++)=base64EncodeTable[(inbuf[0]<<4)&0x3F];
+ *(curr++)=base64Fillchar;
+ *(curr++)=base64Fillchar;
+ } else if (eLen==2)
+ {
+ j=(inbuf[0]<<8)|inbuf[1];
+ *(curr++)=base64EncodeTable[ j>>10 ];
+ *(curr++)=base64EncodeTable[(j>> 4)&0x3f];
+ *(curr++)=base64EncodeTable[(j<< 2)&0x3f];
+ *(curr++)=base64Fillchar;
+ }
+ *(curr++)=0;
+ return (XMLSTR)buf;
+}
+
+unsigned int XMLParserBase64Tool::decodeSize(XMLCSTR data,XMLError *xe)
+{
+ if (!data) return 0;
+ if (xe) *xe=eXMLErrorNone;
+ int size=0;
+ unsigned char c;
+ //skip any extra characters (e.g. newlines or spaces)
+ while (*data)
+ {
+#ifdef _XMLWIDECHAR
+ if (*data>255) { if (xe) *xe=eXMLErrorBase64DecodeIllegalCharacter; return 0; }
+#endif
+ c=base64DecodeTable[(unsigned char)(*data)];
+ if (c<97) size++;
+ else if (c==98) { if (xe) *xe=eXMLErrorBase64DecodeIllegalCharacter; return 0; }
+ data++;
+ }
+ if (xe&&(size%4!=0)) *xe=eXMLErrorBase64DataSizeIsNotMultipleOf4;
+ if (size==0) return 0;
+ do { data--; size--; } while(*data==base64Fillchar); size++;
+ return (unsigned int)((size*3)/4);
+}
+
+unsigned char XMLParserBase64Tool::decode(XMLCSTR data, unsigned char *buf, int len, XMLError *xe)
+{
+ if (!data) return 0;
+ if (xe) *xe=eXMLErrorNone;
+ int i=0,p=0;
+ unsigned char d,c;
+ for(;;)
+ {
+
+#ifdef _XMLWIDECHAR
+#define BASE64DECODE_READ_NEXT_CHAR(c) \
+ do { \
+ if (data[i]>255){ c=98; break; } \
+ c=base64DecodeTable[(unsigned char)data[i++]]; \
+ }while (c==97); \
+ if(c==98){ if(xe)*xe=eXMLErrorBase64DecodeIllegalCharacter; return 0; }
+#else
+#define BASE64DECODE_READ_NEXT_CHAR(c) \
+ do { c=base64DecodeTable[(unsigned char)data[i++]]; }while (c==97); \
+ if(c==98){ if(xe)*xe=eXMLErrorBase64DecodeIllegalCharacter; return 0; }
+#endif
+
+ BASE64DECODE_READ_NEXT_CHAR(c)
+ if (c==99) { return 2; }
+ if (c==96)
+ {
+ if (p==(int)len) return 2;
+ if (xe) *xe=eXMLErrorBase64DecodeTruncatedData;
+ return 1;
+ }
+
+ BASE64DECODE_READ_NEXT_CHAR(d)
+ if ((d==99)||(d==96)) { if (xe) *xe=eXMLErrorBase64DecodeTruncatedData; return 1; }
+ if (p==(int)len) { if (xe) *xe=eXMLErrorBase64DecodeBufferTooSmall; return 0; }
+ buf[p++]=(unsigned char)((c<<2)|((d>>4)&0x3));
+
+ BASE64DECODE_READ_NEXT_CHAR(c)
+ if (c==99) { if (xe) *xe=eXMLErrorBase64DecodeTruncatedData; return 1; }
+ if (p==(int)len)
+ {
+ if (c==96) return 2;
+ if (xe) *xe=eXMLErrorBase64DecodeBufferTooSmall;
+ return 0;
+ }
+ if (c==96) { if (xe) *xe=eXMLErrorBase64DecodeTruncatedData; return 1; }
+ buf[p++]=(unsigned char)(((d<<4)&0xf0)|((c>>2)&0xf));
+
+ BASE64DECODE_READ_NEXT_CHAR(d)
+ if (d==99 ) { if (xe) *xe=eXMLErrorBase64DecodeTruncatedData; return 1; }
+ if (p==(int)len)
+ {
+ if (d==96) return 2;
+ if (xe) *xe=eXMLErrorBase64DecodeBufferTooSmall;
+ return 0;
+ }
+ if (d==96) { if (xe) *xe=eXMLErrorBase64DecodeTruncatedData; return 1; }
+ buf[p++]=(unsigned char)(((c<<6)&0xc0)|d);
+ }
+}
+#undef BASE64DECODE_READ_NEXT_CHAR
+
+void XMLParserBase64Tool::alloc(int newsize)
+{
+ if ((!buf)&&(newsize)) { buf=malloc(newsize); buflen=newsize; return; }
+ if (newsize>buflen) { buf=realloc(buf,newsize); buflen=newsize; }
+}
+
+unsigned char *XMLParserBase64Tool::decode(XMLCSTR data, int *outlen, XMLError *xe)
+{
+ if (xe) *xe=eXMLErrorNone;
+ if (!data) { *outlen=0; return (unsigned char*)""; }
+ unsigned int len=decodeSize(data,xe);
+ if (outlen) *outlen=len;
+ if (!len) return NULL;
+ alloc(len+1);
+ if(!decode(data,(unsigned char*)buf,len,xe)){ return NULL; }
+ return (unsigned char*)buf;
+}
+
+//////////////////////////////////////////////////////////
+// Helpers for external C APIs. //
+//////////////////////////////////////////////////////////
+
+XMLNode::XMLNode( HXML h ) :
+d(( XMLNodeDataTag* )h )
+{
+ if (d)
+ d->ref_count++;
+}
+
+void XMLNode::attach( HXML h )
+{
+ d = ( XMLNodeDataTag* )h;
+}
+
+HXML XMLNode::detach()
+{
+ HXML res = (HXML)d;
+ d = NULL;
+ return res;
+}
diff --git a/src/modules/xml/xmlParser.h b/src/modules/xml/xmlParser.h
new file mode 100644
index 0000000000..5a216ab0cb
--- /dev/null
+++ b/src/modules/xml/xmlParser.h
@@ -0,0 +1,746 @@
+/****************************************************************************/
+/*! \mainpage XMLParser library
+ * \section intro_sec Introduction
+ *
+ * This is a basic XML parser written in ANSI C++ for portability.
+ * It works by using recursion and a node tree for breaking
+ * down the elements of an XML document.
+ *
+ * @version V2.43
+ * @author Frank Vanden Berghen
+ *
+ * Copyright (c) 2002, Business-Insight
+ * <a href="http://www.Business-Insight.com">Business-Insight</a>
+ * All rights reserved.
+ * See the file <a href="../../AFPL-license.txt">AFPL-license.txt</a> about the licensing terms
+ *
+ * \section tutorial First Tutorial
+ * You can follow a simple <a href="../../xmlParser.html">Tutorial</a> to know the basics...
+ *
+ * \section usage General usage: How to include the XMLParser library inside your project.
+ *
+ * The library is composed of two files: <a href="../../xmlParser.cpp">xmlParser.cpp</a> and
+ * <a href="../../xmlParser.h">xmlParser.h</a>. These are the ONLY 2 files that you need when
+ * using the library inside your own projects.
+ *
+ * All the functions of the library are documented inside the comments of the file
+ * <a href="../../xmlParser.h">xmlParser.h</a>. These comments can be transformed in
+ * full-fledged HTML documentation using the DOXYGEN software: simply type: "doxygen doxy.cfg"
+ *
+ * By default, the XMLParser library uses (char*) for string representation.To use the (wchar_t*)
+ * version of the library, you need to define the "_UNICODE" preprocessor definition variable
+ * (this is usually done inside your project definition file) (This is done automatically for you
+ * when using Visual Studio).
+ *
+ * \section example Advanced Tutorial and Many Examples of usage.
+ *
+ * Some very small introductory examples are described inside the Tutorial file
+ * <a href="../../xmlParser.html">xmlParser.html</a>
+ *
+ * Some additional small examples are also inside the file <a href="../../xmlTest.cpp">xmlTest.cpp</a>
+ * (for the "char*" version of the library) and inside the file
+ * <a href="../../xmlTestUnicode.cpp">xmlTestUnicode.cpp</a> (for the "wchar_t*"
+ * version of the library). If you have a question, please review these additionnal examples
+ * before sending an e-mail to the author.
+ *
+ * To build the examples:
+ * - linux/unix: type "make"
+ * - solaris: type "make -f makefile.solaris"
+ * - windows: Visual Studio: double-click on xmlParser.dsw
+ * (under Visual Studio .NET, the .dsp and .dsw files will be automatically converted to .vcproj and .sln files)
+ *
+ * In order to build the examples you need some additional files:
+ * - linux/unix: makefile
+ * - solaris: makefile.solaris
+ * - windows: Visual Studio: *.dsp, xmlParser.dsw and also xmlParser.lib and xmlParser.dll
+ *
+ * \section debugging Debugging with the XMLParser library
+ *
+ * \subsection debugwin Debugging under WINDOWS
+ *
+ * Inside Visual C++, the "debug versions" of the memory allocation functions are
+ * very slow: Do not forget to compile in "release mode" to get maximum speed.
+ * When I had to debug a software that was using the XMLParser Library, it was usually
+ * a nightmare because the library was sooOOOoooo slow in debug mode (because of the
+ * slow memory allocations in Debug mode). To solve this
+ * problem, during all the debugging session, I am now using a very fast DLL version of the
+ * XMLParser Library (the DLL is compiled in release mode). Using the DLL version of
+ * the XMLParser Library allows me to have lightening XML parsing speed even in debug!
+ * Other than that, the DLL version is useless: In the release version of my tool,
+ * I always use the normal, ".cpp"-based, XMLParser Library (I simply include the
+ * <a href="../../xmlParser.cpp">xmlParser.cpp</a> and
+ * <a href="../../xmlParser.h">xmlParser.h</a> files into the project).
+ *
+ * The file <a href="../../XMLNodeAutoexp.txt">XMLNodeAutoexp.txt</a> contains some
+ * "tweaks" that improve substancially the display of the content of the XMLNode objects
+ * inside the Visual Studio Debugger. Believe me, once you have seen inside the debugger
+ * the "smooth" display of the XMLNode objects, you cannot live without it anymore!
+ *
+ * \subsection debuglinux Debugging under LINUX/UNIX
+ *
+ * The speed of the debug version of the XMLParser library is tolerable so no extra
+ * work.has been done.
+ *
+ ****************************************************************************/
+
+#ifndef __INCLUDE_XML_NODE__
+#define __INCLUDE_XML_NODE__
+
+#include <stdlib.h>
+
+#ifdef _UNICODE
+// If you comment the next "define" line then the library will never "switch to" _UNICODE (wchar_t*) mode (16/32 bits per characters).
+// This is useful when you get error messages like:
+// 'XMLNode::openFileHelper' : cannot convert parameter 2 from 'const char [5]' to 'const wchar_t *'
+// The _XMLWIDECHAR preprocessor variable force the XMLParser library into either utf16/32-mode (the proprocessor variable
+// must be defined) or utf8-mode(the pre-processor variable must be undefined).
+#define _XMLWIDECHAR
+#endif
+
+#if defined(WIN32) || defined(UNDER_CE) || defined(_WIN32) || defined(WIN64) || defined(__BORLANDC__)
+// comment the next line if you are under windows and the compiler is not Microsoft Visual Studio (6.0 or .NET) or Borland
+#define _XMLWINDOWS
+#endif
+
+#ifdef XMLDLLENTRY
+#undef XMLDLLENTRY
+#endif
+#ifdef _USE_XMLPARSER_DLL
+#ifdef _DLL_EXPORTS_
+#define XMLDLLENTRY __declspec(dllexport)
+#else
+#define XMLDLLENTRY __declspec(dllimport)
+#endif
+#else
+#define XMLDLLENTRY
+#endif
+
+// uncomment the next line if you want no support for wchar_t* (no need for the <wchar.h> or <tchar.h> libraries anymore to compile)
+//#define XML_NO_WIDE_CHAR
+
+#ifdef XML_NO_WIDE_CHAR
+#undef _XMLWINDOWS
+#undef _XMLWIDECHAR
+#endif
+
+#ifdef _XMLWINDOWS
+#include <tchar.h>
+#else
+#define XMLDLLENTRY
+#ifndef XML_NO_WIDE_CHAR
+#include <wchar.h> // to have 'wcsrtombs' for ANSI version
+ // to have 'mbsrtowcs' for WIDECHAR version
+#endif
+#endif
+
+// Some common types for char set portable code
+#ifdef _XMLWIDECHAR
+ #define _CXML(c) L ## c
+ #define XMLCSTR const wchar_t *
+ #define XMLSTR wchar_t *
+ #define XMLCHAR wchar_t
+#else
+ #define _CXML(c) c
+ #define XMLCSTR const char *
+ #define XMLSTR char *
+ #define XMLCHAR char
+#endif
+#ifndef FALSE
+ #define FALSE 0
+#endif /* FALSE */
+#ifndef TRUE
+ #define TRUE 1
+#endif /* TRUE */
+
+
+/// Enumeration for XML parse errors.
+typedef enum XMLError
+{
+ eXMLErrorNone = 0,
+ eXMLErrorMissingEndTag,
+ eXMLErrorNoXMLTagFound,
+ eXMLErrorEmpty,
+ eXMLErrorMissingTagName,
+ eXMLErrorMissingEndTagName,
+ eXMLErrorUnmatchedEndTag,
+ eXMLErrorUnmatchedEndClearTag,
+ eXMLErrorUnexpectedToken,
+ eXMLErrorNoElements,
+ eXMLErrorFileNotFound,
+ eXMLErrorFirstTagNotFound,
+ eXMLErrorUnknownCharacterEntity,
+ eXMLErrorCharacterCodeAbove255,
+ eXMLErrorCharConversionError,
+ eXMLErrorCannotOpenWriteFile,
+ eXMLErrorCannotWriteFile,
+
+ eXMLErrorBase64DataSizeIsNotMultipleOf4,
+ eXMLErrorBase64DecodeIllegalCharacter,
+ eXMLErrorBase64DecodeTruncatedData,
+ eXMLErrorBase64DecodeBufferTooSmall
+} XMLError;
+
+
+/// Enumeration used to manage type of data. Use in conjunction with structure XMLNodeContents
+typedef enum XMLElementType
+{
+ eNodeChild=0,
+ eNodeAttribute=1,
+ eNodeText=2,
+ eNodeClear=3,
+ eNodeNULL=4
+} XMLElementType;
+
+/// Structure used to obtain error details if the parse fails.
+typedef struct XMLResults
+{
+ enum XMLError error;
+ int nLine,nColumn,nChars;
+} XMLResults;
+
+/// Structure for XML clear (unformatted) node (usually comments)
+typedef struct XMLClear {
+ XMLCSTR lpszValue; XMLCSTR lpszOpenTag; XMLCSTR lpszCloseTag;
+} XMLClear;
+
+/// Structure for XML attribute.
+typedef struct XMLAttribute {
+ XMLCSTR lpszName; XMLCSTR lpszValue;
+} XMLAttribute;
+
+/// XMLElementPosition are not interchangeable with simple indexes
+typedef int XMLElementPosition;
+
+struct XMLNodeContents;
+
+/** @defgroup XMLParserGeneral The XML parser */
+
+/// Main Class representing a XML node
+/**
+ * All operations are performed using this class.
+ * \note The constructors of the XMLNode class are protected, so use instead one of these four methods to get your first instance of XMLNode:
+ * <ul>
+ * <li> XMLNode::parseString </li>
+ * <li> XMLNode::parseFile </li>
+ * <li> XMLNode::openFileHelper </li>
+ * <li> XMLNode::createXMLTopNode (or XMLNode::createXMLTopNode_WOSD)</li>
+ * </ul> */
+typedef struct XMLDLLENTRY XMLNode
+{
+private:
+
+ struct XMLNodeDataTag;
+
+ /// Constructors are protected, so use instead one of: XMLNode::parseString, XMLNode::parseFile, XMLNode::openFileHelper, XMLNode::createXMLTopNode
+ XMLNode(struct XMLNodeDataTag *pParent, XMLSTR lpszName, char isDeclaration);
+ /// Constructors are protected, so use instead one of: XMLNode::parseString, XMLNode::parseFile, XMLNode::openFileHelper, XMLNode::createXMLTopNode
+ XMLNode(struct XMLNodeDataTag *p);
+
+public:
+ static XMLCSTR getVersion();///< Return the XMLParser library version number
+
+ /** @defgroup conversions Parsing XML files/strings to an XMLNode structure and Rendering XMLNode's to files/string.
+ * @ingroup XMLParserGeneral
+ * @{ */
+
+ /// Parse an XML string and return the root of a XMLNode tree representing the string.
+ static XMLNode parseString (XMLCSTR lpXMLString, XMLCSTR tag=NULL, XMLResults *pResults=NULL);
+ /**< The "parseString" function parse an XML string and return the root of a XMLNode tree. The "opposite" of this function is
+ * the function "createXMLString" that re-creates an XML string from an XMLNode tree. If the XML document is corrupted, the
+ * "parseString" method will initialize the "pResults" variable with some information that can be used to trace the error.
+ * If you still want to parse the file, you can use the APPROXIMATE_PARSING option as explained inside the note at the
+ * beginning of the "xmlParser.cpp" file.
+ *
+ * @param lpXMLString the XML string to parse
+ * @param tag the name of the first tag inside the XML file. If the tag parameter is omitted, this function returns a node that represents the head of the xml document including the declaration term (<? ... ?>).
+ * @param pResults a pointer to a XMLResults variable that will contain some information that can be used to trace the XML parsing error. You can have a user-friendly explanation of the parsing error with the "getError" function.
+ */
+
+ /// Parse an XML file and return the root of a XMLNode tree representing the file.
+ static XMLNode parseFile (XMLCSTR filename, XMLCSTR tag=NULL, XMLResults *pResults=NULL);
+ /**< The "parseFile" function parse an XML file and return the root of a XMLNode tree. The "opposite" of this function is
+ * the function "writeToFile" that re-creates an XML file from an XMLNode tree. If the XML document is corrupted, the
+ * "parseFile" method will initialize the "pResults" variable with some information that can be used to trace the error.
+ * If you still want to parse the file, you can use the APPROXIMATE_PARSING option as explained inside the note at the
+ * beginning of the "xmlParser.cpp" file.
+ *
+ * @param filename the path to the XML file to parse
+ * @param tag the name of the first tag inside the XML file. If the tag parameter is omitted, this function returns a node that represents the head of the xml document including the declaration term (<? ... ?>).
+ * @param pResults a pointer to a XMLResults variable that will contain some information that can be used to trace the XML parsing error. You can have a user-friendly explanation of the parsing error with the "getError" function.
+ */
+
+ /// Parse an XML file and return the root of a XMLNode tree representing the file. A very crude error checking is made. An attempt to guess the Char Encoding used in the file is made.
+ static XMLNode openFileHelper(XMLCSTR filename, XMLCSTR tag=NULL);
+ /**< The "openFileHelper" function reports to the screen all the warnings and errors that occurred during parsing of the XML file.
+ * This function also tries to guess char Encoding (UTF-8, ASCII or SHIT-JIS) based on the first 200 bytes of the file. Since each
+ * application has its own way to report and deal with errors, you should rather use the "parseFile" function to parse XML files
+ * and program yourself thereafter an "error reporting" tailored for your needs (instead of using the very crude "error reporting"
+ * mechanism included inside the "openFileHelper" function).
+ *
+ * If the XML document is corrupted, the "openFileHelper" method will:
+ * - display an error message on the console (or inside a messageBox for windows).
+ * - stop execution (exit).
+ *
+ * I strongly suggest that you write your own "openFileHelper" method tailored to your needs. If you still want to parse
+ * the file, you can use the APPROXIMATE_PARSING option as explained inside the note at the beginning of the "xmlParser.cpp" file.
+ *
+ * @param filename the path of the XML file to parse.
+ * @param tag the name of the first tag inside the XML file. If the tag parameter is omitted, this function returns a node that represents the head of the xml document including the declaration term (<? ... ?>).
+ */
+
+ static XMLCSTR getError(XMLError error); ///< this gives you a user-friendly explanation of the parsing error
+
+ /// Create an XML string starting from the current XMLNode.
+ XMLSTR createXMLString(int nFormat=1, int *pnSize=NULL) const;
+ /**< The returned string should be free'd using the "freeXMLString" function.
+ *
+ * If nFormat==0, no formatting is required otherwise this returns an user friendly XML string from a given element
+ * with appropriate white spaces and carriage returns. if pnSize is given it returns the size in character of the string. */
+
+ /// Save the content of an xmlNode inside a file
+ XMLError writeToFile(XMLCSTR filename,
+ const char *encoding=NULL,
+ char nFormat=1) const;
+ /**< If nFormat==0, no formatting is required otherwise this returns an user friendly XML string from a given element with appropriate white spaces and carriage returns.
+ * If the global parameter "characterEncoding==encoding_UTF8", then the "encoding" parameter is ignored and always set to "utf-8".
+ * If the global parameter "characterEncoding==encoding_ShiftJIS", then the "encoding" parameter is ignored and always set to "SHIFT-JIS".
+ * If "_XMLWIDECHAR=1", then the "encoding" parameter is ignored and always set to "utf-16".
+ * If no "encoding" parameter is given the "ISO-8859-1" encoding is used. */
+ /** @} */
+
+ /** @defgroup navigate Navigate the XMLNode structure
+ * @ingroup XMLParserGeneral
+ * @{ */
+ XMLCSTR getName() const; ///< name of the node
+ XMLCSTR getText(int i=0) const; ///< return ith text field
+ XMLCSTR getInnerText() const;
+ int nText() const; ///< nbr of text field
+ XMLNode getParentNode() const; ///< return the parent node
+ XMLNode getChildNode(int i=0) const; ///< return ith child node
+ XMLNode getChildNode(XMLCSTR name, int i) const; ///< return ith child node with specific name (return an empty node if failing). If i==-1, this returns the last XMLNode with the given name.
+ XMLNode getChildNode(XMLCSTR name, int *i=NULL) const; ///< return next child node with specific name (return an empty node if failing)
+ XMLNode getChildNodeWithAttribute(XMLCSTR tagName,
+ XMLCSTR attributeName,
+ XMLCSTR attributeValue=NULL,
+ int *i=NULL) const; ///< return child node with specific name/attribute (return an empty node if failing)
+ XMLNode getChildNodeByPath(XMLSTR path, char createNodeIfMissing=0, XMLCHAR sep='/');
+ ///< return the first child node with specific path. WARNING: the value of the parameter "path" is destroyed!
+ XMLNode getChildNodeByPath(XMLCSTR path, char createNodeIfMissing=0, XMLCHAR sep='/');
+ ///< return the first child node with specific path
+ XMLNode getChildNodeByPathNonConst(XMLSTR path, char createNodeIfMissing=0, XMLCHAR sep='/');
+ ///< return the first child node with specific path.
+ XMLNode getNextNode() const;
+
+ int nChildNode(XMLCSTR name) const; ///< return the number of child node with specific name
+ int nChildNode() const; ///< nbr of child node
+ XMLAttribute getAttribute(int i=0) const; ///< return ith attribute
+ XMLCSTR getAttributeName(int i=0) const; ///< return ith attribute name
+ XMLCSTR getAttributeValue(int i=0) const; ///< return ith attribute value
+ char isAttributeSet(XMLCSTR name) const; ///< test if an attribute with a specific name is given
+ XMLCSTR getAttribute(XMLCSTR name, int i) const; ///< return ith attribute content with specific name (return a NULL if failing)
+ XMLCSTR getAttribute(XMLCSTR name, int *i=NULL) const; ///< return next attribute content with specific name (return a NULL if failing)
+ int nAttribute() const; ///< nbr of attribute
+ XMLClear getClear(int i=0) const; ///< return ith clear field (comments)
+ int nClear() const; ///< nbr of clear field
+ XMLNodeContents enumContents(XMLElementPosition i) const; ///< enumerate all the different contents (attribute,child,text, clear) of the current XMLNode. The order is reflecting the order of the original file/string. NOTE: 0 <= i < nElement();
+ int nElement() const; ///< nbr of different contents for current node
+ char isEmpty() const; ///< is this node Empty?
+ char isDeclaration() const; ///< is this node a declaration <? .... ?>
+ XMLNode deepCopy() const; ///< deep copy (duplicate/clone) a XMLNode
+ static XMLNode emptyNode(); ///< return XMLNode::emptyXMLNode;
+ /** @} */
+
+ ~XMLNode();
+ XMLNode(const XMLNode &A); ///< to allow shallow/fast copy:
+ XMLNode& operator=( const XMLNode& A ); ///< to allow shallow/fast copy:
+
+ XMLNode(): d(NULL){};
+ static XMLNode emptyXMLNode;
+ static XMLClear emptyXMLClear;
+ static XMLAttribute emptyXMLAttribute;
+
+ /** helpers for external C applications **/
+ XMLNode( HXML h );
+ void attach( HXML h );
+ HXML detach();
+ operator HXML() const { return (HXML)d; }
+
+ /** @defgroup xmlModify Create or Update the XMLNode structure
+ * @ingroup XMLParserGeneral
+ * The functions in this group allows you to create from scratch (or update) a XMLNode structure. Start by creating your top
+ * node with the "createXMLTopNode" function and then add new nodes with the "addChild" function. The parameter 'pos' gives
+ * the position where the childNode, the text or the XMLClearTag will be inserted. The default value (pos=-1) inserts at the
+ * end. The value (pos=0) insert at the beginning (Insertion at the beginning is slower than at the end). <br>
+ *
+ * REMARK: 0 <= pos < nChild()+nText()+nClear() <br>
+ */
+
+ /** @defgroup creation Creating from scratch a XMLNode structure
+ * @ingroup xmlModify
+ * @{ */
+ static XMLNode createXMLTopNode(XMLCSTR lpszName, char isDeclaration=FALSE); ///< Create the top node of an XMLNode structure
+ XMLNode addChild(XMLCSTR lpszName, char isDeclaration=FALSE, XMLElementPosition pos=-1); ///< Add a new child node
+ XMLNode addChild(XMLNode nodeToAdd, XMLElementPosition pos=-1); ///< If the "nodeToAdd" has some parents, it will be detached from it's parents before being attached to the current XMLNode
+ XMLAttribute *addAttribute(XMLCSTR lpszName, XMLCSTR lpszValuev); ///< Add a new attribute
+ XMLCSTR addText(XMLCSTR lpszValue, XMLElementPosition pos=-1); ///< Add a new text content
+ XMLClear *addClear(XMLCSTR lpszValue, XMLCSTR lpszOpen=NULL, XMLCSTR lpszClose=NULL, XMLElementPosition pos=-1);
+ /**< Add a new clear tag
+ * @param lpszOpen default value "<![CDATA["
+ * @param lpszClose default value "]]>"
+ */
+ /** @} */
+
+ /** @defgroup xmlUpdate Updating Nodes
+ * @ingroup xmlModify
+ * Some update functions:
+ * @{
+ */
+ XMLCSTR updateName(XMLCSTR lpszName); ///< change node's name
+ XMLAttribute *updateAttribute(XMLAttribute *newAttribute, XMLAttribute *oldAttribute); ///< if the attribute to update is missing, a new one will be added
+ XMLAttribute *updateAttribute(XMLCSTR lpszNewValue, XMLCSTR lpszNewName=NULL,int i=0); ///< if the attribute to update is missing, a new one will be added
+ XMLAttribute *updateAttribute(XMLCSTR lpszNewValue, XMLCSTR lpszNewName,XMLCSTR lpszOldName);///< set lpszNewName=NULL if you don't want to change the name of the attribute if the attribute to update is missing, a new one will be added
+ XMLCSTR updateText(XMLCSTR lpszNewValue, int i=0); ///< if the text to update is missing, a new one will be added
+ XMLCSTR updateText(XMLCSTR lpszNewValue, XMLCSTR lpszOldValue); ///< if the text to update is missing, a new one will be added
+ XMLClear *updateClear(XMLCSTR lpszNewContent, int i=0); ///< if the clearTag to update is missing, a new one will be added
+ XMLClear *updateClear(XMLClear *newP,XMLClear *oldP); ///< if the clearTag to update is missing, a new one will be added
+ XMLClear *updateClear(XMLCSTR lpszNewValue, XMLCSTR lpszOldValue); ///< if the clearTag to update is missing, a new one will be added
+ /** @} */
+
+ /** @defgroup xmlDelete Deleting Nodes or Attributes
+ * @ingroup xmlModify
+ * Some deletion functions:
+ * @{
+ */
+ /// The "deleteNodeContent" function forces the deletion of the content of this XMLNode and the subtree.
+ void deleteNodeContent();
+ /**< \note The XMLNode instances that are referring to the part of the subtree that has been deleted CANNOT be used anymore!!. Unexpected results will occur if you continue using them. */
+ void deleteAttribute(int i=0); ///< Delete the ith attribute of the current XMLNode
+ void deleteAttribute(XMLCSTR lpszName); ///< Delete the attribute with the given name (the "strcmp" function is used to find the right attribute)
+ void deleteAttribute(XMLAttribute *anAttribute); ///< Delete the attribute with the name "anAttribute->lpszName" (the "strcmp" function is used to find the right attribute)
+ void deleteText(int i=0); ///< Delete the Ith text content of the current XMLNode
+ void deleteText(XMLCSTR lpszValue); ///< Delete the text content "lpszValue" inside the current XMLNode (direct "pointer-to-pointer" comparison is used to find the right text)
+ void deleteClear(int i=0); ///< Delete the Ith clear tag inside the current XMLNode
+ void deleteClear(XMLCSTR lpszValue); ///< Delete the clear tag "lpszValue" inside the current XMLNode (direct "pointer-to-pointer" comparison is used to find the clear tag)
+ void deleteClear(XMLClear *p); ///< Delete the clear tag "p" inside the current XMLNode (direct "pointer-to-pointer" comparison on the lpszName of the clear tag is used to find the clear tag)
+ /** @} */
+
+ /** @defgroup xmlWOSD ???_WOSD functions.
+ * @ingroup xmlModify
+ * The strings given as parameters for the "add" and "update" methods that have a name with
+ * the postfix "_WOSD" (that means "WithOut String Duplication")(for example "addText_WOSD")
+ * will be free'd by the XMLNode class. For example, it means that this is incorrect:
+ * \code
+ * xNode.addText_WOSD("foo");
+ * xNode.updateAttribute_WOSD("#newcolor" ,NULL,"color");
+ * \endcode
+ * In opposition, this is correct:
+ * \code
+ * xNode.addText("foo");
+ * xNode.addText_WOSD(stringDup("foo"));
+ * xNode.updateAttribute("#newcolor" ,NULL,"color");
+ * xNode.updateAttribute_WOSD(stringDup("#newcolor"),NULL,"color");
+ * \endcode
+ * Typically, you will never do:
+ * \code
+ * char *b=(char*)malloc(...);
+ * xNode.addText(b);
+ * free(b);
+ * \endcode
+ * ... but rather:
+ * \code
+ * char *b=(char*)malloc(...);
+ * xNode.addText_WOSD(b);
+ * \endcode
+ * ('free(b)' is performed by the XMLNode class)
+ * @{ */
+ static XMLNode createXMLTopNode_WOSD(XMLSTR lpszName, char isDeclaration=FALSE); ///< Create the top node of an XMLNode structure
+ XMLNode addChild_WOSD(XMLSTR lpszName, char isDeclaration=FALSE, XMLElementPosition pos=-1); ///< Add a new child node
+ XMLAttribute *addAttribute_WOSD(XMLSTR lpszName, XMLSTR lpszValue); ///< Add a new attribute
+ XMLCSTR addText_WOSD(XMLSTR lpszValue, XMLElementPosition pos=-1); ///< Add a new text content
+ XMLClear *addClear_WOSD(XMLSTR lpszValue, XMLCSTR lpszOpen=NULL, XMLCSTR lpszClose=NULL, XMLElementPosition pos=-1); ///< Add a new clear Tag
+
+ XMLCSTR updateName_WOSD(XMLSTR lpszName); ///< change node's name
+ XMLAttribute *updateAttribute_WOSD(XMLAttribute *newAttribute, XMLAttribute *oldAttribute); ///< if the attribute to update is missing, a new one will be added
+ XMLAttribute *updateAttribute_WOSD(XMLSTR lpszNewValue, XMLSTR lpszNewName=NULL,int i=0); ///< if the attribute to update is missing, a new one will be added
+ XMLAttribute *updateAttribute_WOSD(XMLSTR lpszNewValue, XMLSTR lpszNewName,XMLCSTR lpszOldName); ///< set lpszNewName=NULL if you don't want to change the name of the attribute if the attribute to update is missing, a new one will be added
+ XMLCSTR updateText_WOSD(XMLSTR lpszNewValue, int i=0); ///< if the text to update is missing, a new one will be added
+ XMLCSTR updateText_WOSD(XMLSTR lpszNewValue, XMLCSTR lpszOldValue); ///< if the text to update is missing, a new one will be added
+ XMLClear *updateClear_WOSD(XMLSTR lpszNewContent, int i=0); ///< if the clearTag to update is missing, a new one will be added
+ XMLClear *updateClear_WOSD(XMLClear *newP,XMLClear *oldP); ///< if the clearTag to update is missing, a new one will be added
+ XMLClear *updateClear_WOSD(XMLSTR lpszNewValue, XMLCSTR lpszOldValue); ///< if the clearTag to update is missing, a new one will be added
+ /** @} */
+
+ /** @defgroup xmlPosition Position helper functions (use in conjunction with the update&add functions
+ * @ingroup xmlModify
+ * These are some useful functions when you want to insert a childNode, a text or a XMLClearTag in the
+ * middle (at a specified position) of a XMLNode tree already constructed. The value returned by these
+ * methods is to be used as last parameter (parameter 'pos') of addChild, addText or addClear.
+ * @{ */
+ XMLElementPosition positionOfText(int i=0) const;
+ XMLElementPosition positionOfText(XMLCSTR lpszValue) const;
+ XMLElementPosition positionOfClear(int i=0) const;
+ XMLElementPosition positionOfClear(XMLCSTR lpszValue) const;
+ XMLElementPosition positionOfClear(XMLClear *a) const;
+ XMLElementPosition positionOfChildNode(int i=0) const;
+ XMLElementPosition positionOfChildNode(XMLNode x) const;
+ XMLElementPosition positionOfChildNode(XMLCSTR name, int i=0) const; ///< return the position of the ith childNode with the specified name if (name==NULL) return the position of the ith childNode
+ /** @} */
+
+ /// Enumeration for XML character encoding.
+ typedef enum XMLCharEncoding
+ {
+ char_encoding_error=0,
+ char_encoding_UTF8=1,
+ char_encoding_legacy=2,
+ char_encoding_ShiftJIS=3,
+ char_encoding_GB2312=4,
+ char_encoding_Big5=5,
+ char_encoding_GBK=6 // this is actually the same as Big5
+ } XMLCharEncoding;
+
+ /** \addtogroup conversions
+ * @{ */
+
+ /// Sets the global options for the conversions
+ static char setGlobalOptions(XMLCharEncoding characterEncoding=XMLNode::char_encoding_UTF8, char guessWideCharChars=1,
+ char dropWhiteSpace=1, char removeCommentsInMiddleOfText=1);
+ /**< The "setGlobalOptions" function allows you to change four global parameters that affect string & file
+ * parsing. First of all, you most-probably will never have to change these 3 global parameters.
+ *
+ * @param guessWideCharChars If "guessWideCharChars"=1 and if this library is compiled in WideChar mode, then the
+ * XMLNode::parseFile and XMLNode::openFileHelper functions will test if the file contains ASCII
+ * characters. If this is the case, then the file will be loaded and converted in memory to
+ * WideChar before being parsed. If 0, no conversion will be performed.
+ *
+ * @param guessWideCharChars If "guessWideCharChars"=1 and if this library is compiled in ASCII/UTF8/char* mode, then the
+ * XMLNode::parseFile and XMLNode::openFileHelper functions will test if the file contains WideChar
+ * characters. If this is the case, then the file will be loaded and converted in memory to
+ * ASCII/UTF8/char* before being parsed. If 0, no conversion will be performed.
+ *
+ * @param characterEncoding This parameter is only meaningful when compiling in char* mode (multibyte character mode).
+ * In wchar_t* (wide char mode), this parameter is ignored. This parameter should be one of the
+ * three currently recognized encodings: XMLNode::encoding_UTF8, XMLNode::encoding_ascii,
+ * XMLNode::encoding_ShiftJIS.
+ *
+ * @param dropWhiteSpace In most situations, text fields containing only white spaces (and carriage returns)
+ * are useless. Even more, these "empty" text fields are annoying because they increase the
+ * complexity of the user's code for parsing. So, 99% of the time, it's better to drop
+ * the "empty" text fields. However The XML specification indicates that no white spaces
+ * should be lost when parsing the file. So to be perfectly XML-compliant, you should set
+ * dropWhiteSpace=0. A note of caution: if you set "dropWhiteSpace=0", the parser will be
+ * slower and your code will be more complex.
+ *
+ * @param removeCommentsInMiddleOfText To explain this parameter, let's consider this code:
+ * \code
+ * XMLNode x=XMLNode::parseString("<a>foo<!-- hello -->bar<!DOCTYPE world >chu</a>","a");
+ * \endcode
+ * If removeCommentsInMiddleOfText=0, then we will have:
+ * \code
+ * x.getText(0) -> "foo"
+ * x.getText(1) -> "bar"
+ * x.getText(2) -> "chu"
+ * x.getClear(0) --> "<!-- hello -->"
+ * x.getClear(1) --> "<!DOCTYPE world >"
+ * \endcode
+ * If removeCommentsInMiddleOfText=1, then we will have:
+ * \code
+ * x.getText(0) -> "foobar"
+ * x.getText(1) -> "chu"
+ * x.getClear(0) --> "<!DOCTYPE world >"
+ * \endcode
+ *
+ * \return "0" when there are no errors. If you try to set an unrecognized encoding then the return value will be "1" to signal an error.
+ *
+ * \note Sometime, it's useful to set "guessWideCharChars=0" to disable any conversion
+ * because the test to detect the file-type (ASCII/UTF8/char* or WideChar) may fail (rarely). */
+
+ /// Guess the character encoding of the string (ascii, utf8 or shift-JIS)
+ static XMLCharEncoding guessCharEncoding(void *buffer, int bufLen, char useXMLEncodingAttribute=1);
+ /**< The "guessCharEncoding" function try to guess the character encoding. You most-probably will never
+ * have to use this function. It then returns the appropriate value of the global parameter
+ * "characterEncoding" described in the XMLNode::setGlobalOptions. The guess is based on the content of a buffer of length
+ * "bufLen" bytes that contains the first bytes (minimum 25 bytes; 200 bytes is a good value) of the
+ * file to be parsed. The XMLNode::openFileHelper function is using this function to automatically compute
+ * the value of the "characterEncoding" global parameter. There are several heuristics used to do the
+ * guess. One of the heuristic is based on the "encoding" attribute. The original XML specifications
+ * forbids to use this attribute to do the guess but you can still use it if you set
+ * "useXMLEncodingAttribute" to 1 (this is the default behavior and the behavior of most parsers).
+ * If an inconsistency in the encoding is detected, then the return value is "0". */
+ /** @} */
+
+private:
+ // these are functions and structures used internally by the XMLNode class (don't bother about them):
+
+ typedef struct XMLNodeDataTag // to allow shallow copy and "intelligent/smart" pointers (automatic delete):
+ {
+ XMLCSTR lpszName; // Element name (=NULL if root)
+ XMLCSTR lpszNS; // Namespace
+ int nChild, // Number of child nodes
+ nText, // Number of text fields
+ nClear, // Number of Clear fields (comments)
+ nAttribute; // Number of attributes
+ char isDeclaration; // Whether node is an XML declaration - '<?xml ?>'
+ struct XMLNodeDataTag *pParent; // Pointer to parent element (=NULL if root)
+ XMLNode *pChild; // Array of child nodes
+ XMLCSTR *pText; // Array of text fields
+ XMLClear *pClear; // Array of clear fields
+ XMLAttribute *pAttribute; // Array of attributes
+ int *pOrder; // order of the child_nodes,text_fields,clear_fields
+ int ref_count; // for garbage collection (smart pointers)
+ XMLSTR pInnerText; // cached value of inner text, for memory manadgement purposes
+ } XMLNodeData;
+ XMLNodeData *d;
+
+ char parseClearTag(void *px, void *pa);
+ char maybeAddTxT(void *pa, XMLCSTR tokenPStr);
+ int ParseXMLElement(void *pXML);
+ void *addToOrder(int memInc, int *_pos, int nc, void *p, int size, XMLElementType xtype);
+ int indexText(XMLCSTR lpszValue) const;
+ int indexClear(XMLCSTR lpszValue) const;
+ XMLNode addChild_priv(int,XMLSTR,char,int);
+ XMLAttribute *addAttribute_priv(int,XMLSTR,XMLSTR);
+ XMLCSTR addText_priv(int,XMLSTR,int);
+ XMLClear *addClear_priv(int,XMLSTR,XMLCSTR,XMLCSTR,int);
+ void emptyTheNode(char force);
+ void invalidateInnerText();
+ static inline XMLElementPosition findPosition(XMLNodeData *d, int index, XMLElementType xtype);
+ static int CreateXMLStringR(XMLNodeData *pEntry, XMLSTR lpszMarker, int nFormat);
+ static int removeOrderElement(XMLNodeData *d, XMLElementType t, int index);
+ static void exactMemory(XMLNodeData *d);
+ static int detachFromParent(XMLNodeData *d);
+} XMLNode;
+
+/// This structure is given by the function XMLNode::enumContents.
+typedef struct XMLNodeContents
+{
+ /// This dictates what's the content of the XMLNodeContent
+ enum XMLElementType etype;
+ /**< should be an union to access the appropriate data. Compiler does not allow union of object with constructor... too bad. */
+ XMLNode child;
+ XMLAttribute attrib;
+ XMLCSTR text;
+ XMLClear clear;
+
+} XMLNodeContents;
+
+/** @defgroup StringAlloc String Allocation/Free functions
+* @ingroup xmlModify
+* @{ */
+/// Duplicate (copy in a new allocated buffer) the source string.
+XMLDLLENTRY XMLSTR stringDup(XMLCSTR source, int cbData=-1);
+/**< This is
+* a very handy function when used with all the "XMLNode::*_WOSD" functions (\link xmlWOSD \endlink).
+* @param cbData If !=0 then cbData is the number of chars to duplicate. New strings allocated with
+* this function should be free'd using the "freeXMLString" function. */
+
+/// to free the string allocated inside the "stringDup" function or the "createXMLString" function.
+XMLDLLENTRY void freeXMLString(XMLSTR t); // {free(t);}
+/** @} */
+
+/** @defgroup atoX ato? like functions
+* @ingroup XMLParserGeneral
+* The "xmlto?" functions are equivalents to the atoi, atol, atof functions.
+* The only difference is: If the variable "xmlString" is NULL, than the return value
+* is "defautValue". These 6 functions are only here as "convenience" functions for the
+* user (they are not used inside the XMLparser). If you don't need them, you can
+* delete them without any trouble.
+*
+* @{ */
+XMLDLLENTRY char xmltob(XMLCSTR xmlString,char defautValue=0);
+XMLDLLENTRY int xmltoi(XMLCSTR xmlString,int defautValue=0);
+XMLDLLENTRY long xmltol(XMLCSTR xmlString,long defautValue=0);
+XMLDLLENTRY double xmltof(XMLCSTR xmlString,double defautValue=.0);
+XMLDLLENTRY XMLCSTR xmltoa(XMLCSTR xmlString,XMLCSTR defautValue=_CXML(""));
+XMLDLLENTRY XMLCHAR xmltoc(XMLCSTR xmlString,const XMLCHAR defautValue=_CXML('\0'));
+/** @} */
+
+/** @defgroup ToXMLStringTool Helper class to create XML files using "printf", "fprintf", "cout",... functions.
+* @ingroup XMLParserGeneral
+* @{ */
+/// Helper class to create XML files using "printf", "fprintf", "cout",... functions.
+/** The ToXMLStringTool class helps you creating XML files using "printf", "fprintf", "cout",... functions.
+* The "ToXMLStringTool" class is processing strings so that all the characters
+* &,",',<,> are replaced by their XML equivalent:
+* \verbatim &amp;, &quot;, &apos;, &lt;, &gt; \endverbatim
+* Using the "ToXMLStringTool class" and the "fprintf function" is THE most efficient
+* way to produce VERY large XML documents VERY fast.
+* \note If you are creating from scratch an XML file using the provided XMLNode class
+* you must not use the "ToXMLStringTool" class (because the "XMLNode" class does the
+* processing job for you during rendering).*/
+typedef struct XMLDLLENTRY ToXMLStringTool
+{
+public:
+ ToXMLStringTool(): buf(NULL),buflen(0){}
+ ~ToXMLStringTool();
+ void freeBuffer();///<call this function when you have finished using this object to release memory used by the internal buffer.
+
+ XMLSTR toXML(XMLCSTR source);///< returns a pointer to an internal buffer that contains a XML-encoded string based on the "source" parameter.
+
+ /** The "toXMLUnSafe" function is deprecated because there is a possibility of
+ * "destination-buffer-overflow". It converts the string
+ * "source" to the string "dest". */
+ static XMLSTR toXMLUnSafe(XMLSTR dest,XMLCSTR source); ///< deprecated: use "toXML" instead
+ static int lengthXMLString(XMLCSTR source); ///< deprecated: use "toXML" instead
+
+private:
+ XMLSTR buf;
+ int buflen;
+} ToXMLStringTool;
+/** @} */
+
+/** @defgroup XMLParserBase64Tool Helper class to include binary data inside XML strings using "Base64 encoding".
+* @ingroup XMLParserGeneral
+* @{ */
+/// Helper class to include binary data inside XML strings using "Base64 encoding".
+/** The "XMLParserBase64Tool" class allows you to include any binary data (images, sounds,...)
+* into an XML document using "Base64 encoding". This class is completely
+* separated from the rest of the xmlParser library and can be removed without any problem.
+* To include some binary data into an XML file, you must convert the binary data into
+* standard text (using "encode"). To retrieve the original binary data from the
+* b64-encoded text included inside the XML file, use "decode". Alternatively, these
+* functions can also be used to "encrypt/decrypt" some critical data contained inside
+* the XML (it's not a strong encryption at all, but sometimes it can be useful). */
+typedef struct XMLDLLENTRY XMLParserBase64Tool
+{
+public:
+ XMLParserBase64Tool(): buf(NULL),buflen(0){}
+ ~XMLParserBase64Tool();
+ void freeBuffer();///< Call this function when you have finished using this object to release memory used by the internal buffer.
+
+ /**
+ * @param formatted If "formatted"=true, some space will be reserved for a carriage-return every 72 chars. */
+ static int encodeLength(int inBufLen, char formatted=0); ///< return the length of the base64 string that encodes a data buffer of size inBufLen bytes.
+
+ /**
+ * The "base64Encode" function returns a string containing the base64 encoding of "inByteLen" bytes
+ * from "inByteBuf". If "formatted" parameter is true, then there will be a carriage-return every 72 chars.
+ * The string will be free'd when the XMLParserBase64Tool object is deleted.
+ * All returned strings are sharing the same memory space. */
+ XMLSTR encode(unsigned char *inByteBuf, unsigned int inByteLen, char formatted=0); ///< returns a pointer to an internal buffer containing the base64 string containing the binary data encoded from "inByteBuf"
+
+ /// returns the number of bytes which will be decoded from "inString".
+ static unsigned int decodeSize(XMLCSTR inString, XMLError *xe=NULL);
+
+ /**
+ * The "decode" function returns a pointer to a buffer containing the binary data decoded from "inString"
+ * The output buffer will be free'd when the XMLParserBase64Tool object is deleted.
+ * All output buffer are sharing the same memory space.
+ * @param inString If "instring" is malformed, NULL will be returned */
+ unsigned char* decode(XMLCSTR inString, int *outByteLen=NULL, XMLError *xe=NULL); ///< returns a pointer to an internal buffer containing the binary data decoded from "inString"
+
+ /**
+ * decodes data from "inString" to "outByteBuf". You need to provide the size (in byte) of "outByteBuf"
+ * in "inMaxByteOutBuflen". If "outByteBuf" is not large enough or if data is malformed, then "FALSE"
+ * will be returned; otherwise "TRUE". */
+ static unsigned char decode(XMLCSTR inString, unsigned char *outByteBuf, int inMaxByteOutBuflen, XMLError *xe=NULL); ///< deprecated.
+
+private:
+ void *buf;
+ int buflen;
+ void alloc(int newsize);
+}XMLParserBase64Tool;
+/** @} */
+
+#undef XMLDLLENTRY
+
+#endif
diff --git a/src/res/Icon_exit.ico b/src/res/Icon_exit.ico
new file mode 100644
index 0000000000..9a1d7e60e3
--- /dev/null
+++ b/src/res/Icon_exit.ico
Binary files differ
diff --git a/src/res/Icon_show_hide.ico b/src/res/Icon_show_hide.ico
new file mode 100644
index 0000000000..fce8d96c0e
--- /dev/null
+++ b/src/res/Icon_show_hide.ico
Binary files differ
diff --git a/src/res/Off.ico b/src/res/Off.ico
new file mode 100644
index 0000000000..447b1ae4f6
--- /dev/null
+++ b/src/res/Off.ico
Binary files differ
diff --git a/src/res/On.ico b/src/res/On.ico
new file mode 100644
index 0000000000..43e377a9ea
--- /dev/null
+++ b/src/res/On.ico
Binary files differ
diff --git a/src/res/_blank.ico b/src/res/_blank.ico
new file mode 100644
index 0000000000..7845f62fed
--- /dev/null
+++ b/src/res/_blank.ico
Binary files differ
diff --git a/src/res/arrow_sort_column_down.bmp b/src/res/arrow_sort_column_down.bmp
new file mode 100644
index 0000000000..1fc197f530
--- /dev/null
+++ b/src/res/arrow_sort_column_down.bmp
Binary files differ
diff --git a/src/res/arrow_sort_column_up.bmp b/src/res/arrow_sort_column_up.bmp
new file mode 100644
index 0000000000..271acc970e
--- /dev/null
+++ b/src/res/arrow_sort_column_up.bmp
Binary files differ
diff --git a/src/res/chat_join.ico b/src/res/chat_join.ico
new file mode 100644
index 0000000000..72197fcc23
--- /dev/null
+++ b/src/res/chat_join.ico
Binary files differ
diff --git a/src/res/chat_leave.ico b/src/res/chat_leave.ico
new file mode 100644
index 0000000000..97cd85fa67
--- /dev/null
+++ b/src/res/chat_leave.ico
Binary files differ
diff --git a/src/res/check_off.ico b/src/res/check_off.ico
new file mode 100644
index 0000000000..7cb0afddd9
--- /dev/null
+++ b/src/res/check_off.ico
Binary files differ
diff --git a/src/res/check_on.ico b/src/res/check_on.ico
new file mode 100644
index 0000000000..5a2b81aeed
--- /dev/null
+++ b/src/res/check_on.ico
Binary files differ
diff --git a/src/res/contact_add.ico b/src/res/contact_add.ico
new file mode 100644
index 0000000000..a6a7e6f38c
--- /dev/null
+++ b/src/res/contact_add.ico
Binary files differ
diff --git a/src/res/contact_delete.ico b/src/res/contact_delete.ico
new file mode 100644
index 0000000000..6e39da592b
--- /dev/null
+++ b/src/res/contact_delete.ico
Binary files differ
diff --git a/src/res/contact_groups.ico b/src/res/contact_groups.ico
new file mode 100644
index 0000000000..a05bc55dbb
--- /dev/null
+++ b/src/res/contact_groups.ico
Binary files differ
diff --git a/src/res/contact_rename.ico b/src/res/contact_rename.ico
new file mode 100644
index 0000000000..790d09fa28
--- /dev/null
+++ b/src/res/contact_rename.ico
Binary files differ
diff --git a/src/res/contact_view_details.ico b/src/res/contact_view_details.ico
new file mode 100644
index 0000000000..e66f079830
--- /dev/null
+++ b/src/res/contact_view_details.ico
Binary files differ
diff --git a/src/res/cursor_drag_copy.cur b/src/res/cursor_drag_copy.cur
new file mode 100644
index 0000000000..89c7c960d5
--- /dev/null
+++ b/src/res/cursor_drag_copy.cur
Binary files differ
diff --git a/src/res/cursor_drop_user.cur b/src/res/cursor_drop_user.cur
new file mode 100644
index 0000000000..a84b19e28b
--- /dev/null
+++ b/src/res/cursor_drop_user.cur
Binary files differ
diff --git a/src/res/cursor_hyperlink.cur b/src/res/cursor_hyperlink.cur
new file mode 100644
index 0000000000..f0f548c828
--- /dev/null
+++ b/src/res/cursor_hyperlink.cur
Binary files differ
diff --git a/src/res/group_closed.ico b/src/res/group_closed.ico
new file mode 100644
index 0000000000..adb48b70a5
--- /dev/null
+++ b/src/res/group_closed.ico
Binary files differ
diff --git a/src/res/group_opened.ico b/src/res/group_opened.ico
new file mode 100644
index 0000000000..f15dbd5427
--- /dev/null
+++ b/src/res/group_opened.ico
Binary files differ
diff --git a/src/res/icon_accmgr.ico b/src/res/icon_accmgr.ico
new file mode 100644
index 0000000000..47169d588d
--- /dev/null
+++ b/src/res/icon_accmgr.ico
Binary files differ
diff --git a/src/res/icon_all.ico b/src/res/icon_all.ico
new file mode 100644
index 0000000000..6f7ca32ce0
--- /dev/null
+++ b/src/res/icon_all.ico
Binary files differ
diff --git a/src/res/icon_ansi.ico b/src/res/icon_ansi.ico
new file mode 100644
index 0000000000..ff863bf6ff
--- /dev/null
+++ b/src/res/icon_ansi.ico
Binary files differ
diff --git a/src/res/icon_auth_request.ico b/src/res/icon_auth_request.ico
new file mode 100644
index 0000000000..1ba34d7244
--- /dev/null
+++ b/src/res/icon_auth_request.ico
Binary files differ
diff --git a/src/res/icon_changefont.ico b/src/res/icon_changefont.ico
new file mode 100644
index 0000000000..4c8bff603a
--- /dev/null
+++ b/src/res/icon_changefont.ico
Binary files differ
diff --git a/src/res/icon_connecting.ico b/src/res/icon_connecting.ico
new file mode 100644
index 0000000000..76d708cc7d
--- /dev/null
+++ b/src/res/icon_connecting.ico
Binary files differ
diff --git a/src/res/icon_down_arrow.ico b/src/res/icon_down_arrow.ico
new file mode 100644
index 0000000000..1fd67fdb0f
--- /dev/null
+++ b/src/res/icon_down_arrow.ico
Binary files differ
diff --git a/src/res/icon_file.ico b/src/res/icon_file.ico
new file mode 100644
index 0000000000..f47fd1a9c9
--- /dev/null
+++ b/src/res/icon_file.ico
Binary files differ
diff --git a/src/res/icon_find_user.ico b/src/res/icon_find_user.ico
new file mode 100644
index 0000000000..1a4c13653b
--- /dev/null
+++ b/src/res/icon_find_user.ico
Binary files differ
diff --git a/src/res/icon_help.ico b/src/res/icon_help.ico
new file mode 100644
index 0000000000..e4bb7da7e0
--- /dev/null
+++ b/src/res/icon_help.ico
Binary files differ
diff --git a/src/res/icon_history.ico b/src/res/icon_history.ico
new file mode 100644
index 0000000000..e757b93e54
--- /dev/null
+++ b/src/res/icon_history.ico
Binary files differ
diff --git a/src/res/icon_loaded.ico b/src/res/icon_loaded.ico
new file mode 100644
index 0000000000..98f3453450
--- /dev/null
+++ b/src/res/icon_loaded.ico
Binary files differ
diff --git a/src/res/icon_mail.ico b/src/res/icon_mail.ico
new file mode 100644
index 0000000000..e101d8550e
--- /dev/null
+++ b/src/res/icon_mail.ico
Binary files differ
diff --git a/src/res/icon_message.ico b/src/res/icon_message.ico
new file mode 100644
index 0000000000..6ec8d7301d
--- /dev/null
+++ b/src/res/icon_message.ico
Binary files differ
diff --git a/src/res/icon_notloaded.ico b/src/res/icon_notloaded.ico
new file mode 100644
index 0000000000..42537f0695
--- /dev/null
+++ b/src/res/icon_notloaded.ico
Binary files differ
diff --git a/src/res/icon_options.ico b/src/res/icon_options.ico
new file mode 100644
index 0000000000..1cbc247e8b
--- /dev/null
+++ b/src/res/icon_options.ico
Binary files differ
diff --git a/src/res/icon_search_all.ico b/src/res/icon_search_all.ico
new file mode 100644
index 0000000000..08f61cf65a
--- /dev/null
+++ b/src/res/icon_search_all.ico
Binary files differ
diff --git a/src/res/icon_small_dot.ico b/src/res/icon_small_dot.ico
new file mode 100644
index 0000000000..12ffcb1997
--- /dev/null
+++ b/src/res/icon_small_dot.ico
Binary files differ
diff --git a/src/res/icon_sms.ico b/src/res/icon_sms.ico
new file mode 100644
index 0000000000..adb5bbd83f
--- /dev/null
+++ b/src/res/icon_sms.ico
Binary files differ
diff --git a/src/res/icon_typing.ico b/src/res/icon_typing.ico
new file mode 100644
index 0000000000..a2dcf7fd17
--- /dev/null
+++ b/src/res/icon_typing.ico
Binary files differ
diff --git a/src/res/icon_undo.ico b/src/res/icon_undo.ico
new file mode 100644
index 0000000000..23ecb07f0f
--- /dev/null
+++ b/src/res/icon_undo.ico
Binary files differ
diff --git a/src/res/icon_unicode.ico b/src/res/icon_unicode.ico
new file mode 100644
index 0000000000..0e3107380c
--- /dev/null
+++ b/src/res/icon_unicode.ico
Binary files differ
diff --git a/src/res/icon_url.ico b/src/res/icon_url.ico
new file mode 100644
index 0000000000..6baf15c3c5
--- /dev/null
+++ b/src/res/icon_url.ico
Binary files differ
diff --git a/src/res/icon_window.ico b/src/res/icon_window.ico
new file mode 100644
index 0000000000..fda869dd3a
--- /dev/null
+++ b/src/res/icon_window.ico
Binary files differ
diff --git a/src/res/icon_windows.ico b/src/res/icon_windows.ico
new file mode 100644
index 0000000000..f6538a9bf3
--- /dev/null
+++ b/src/res/icon_windows.ico
Binary files differ
diff --git a/src/res/miranda_home.ico b/src/res/miranda_home.ico
new file mode 100644
index 0000000000..2328a8ef16
--- /dev/null
+++ b/src/res/miranda_home.ico
Binary files differ
diff --git a/src/res/miranda_logo.ico b/src/res/miranda_logo.ico
new file mode 100644
index 0000000000..e36ab7bb46
--- /dev/null
+++ b/src/res/miranda_logo.ico
Binary files differ
diff --git a/src/res/miranda_manager.ico b/src/res/miranda_manager.ico
new file mode 100644
index 0000000000..6706ec2f6c
--- /dev/null
+++ b/src/res/miranda_manager.ico
Binary files differ
diff --git a/src/res/status_DND.ico b/src/res/status_DND.ico
new file mode 100644
index 0000000000..b362cd34f8
--- /dev/null
+++ b/src/res/status_DND.ico
Binary files differ
diff --git a/src/res/status_NA.ico b/src/res/status_NA.ico
new file mode 100644
index 0000000000..95324ff888
--- /dev/null
+++ b/src/res/status_NA.ico
Binary files differ
diff --git a/src/res/status_away.ico b/src/res/status_away.ico
new file mode 100644
index 0000000000..85a04f8771
--- /dev/null
+++ b/src/res/status_away.ico
Binary files differ
diff --git a/src/res/status_free4chat.ico b/src/res/status_free4chat.ico
new file mode 100644
index 0000000000..399a8f232d
--- /dev/null
+++ b/src/res/status_free4chat.ico
Binary files differ
diff --git a/src/res/status_invisible.ico b/src/res/status_invisible.ico
new file mode 100644
index 0000000000..301504a56b
--- /dev/null
+++ b/src/res/status_invisible.ico
Binary files differ
diff --git a/src/res/status_locked.ico b/src/res/status_locked.ico
new file mode 100644
index 0000000000..7a9c950f84
--- /dev/null
+++ b/src/res/status_locked.ico
Binary files differ
diff --git a/src/res/status_occupied.ico b/src/res/status_occupied.ico
new file mode 100644
index 0000000000..69f63a6fce
--- /dev/null
+++ b/src/res/status_occupied.ico
Binary files differ
diff --git a/src/res/status_offline.ico b/src/res/status_offline.ico
new file mode 100644
index 0000000000..1cf8daa5f4
--- /dev/null
+++ b/src/res/status_offline.ico
Binary files differ
diff --git a/src/res/status_on_the_phone.ico b/src/res/status_on_the_phone.ico
new file mode 100644
index 0000000000..bc71dd8da8
--- /dev/null
+++ b/src/res/status_on_the_phone.ico
Binary files differ
diff --git a/src/res/status_online.ico b/src/res/status_online.ico
new file mode 100644
index 0000000000..91329f0f11
--- /dev/null
+++ b/src/res/status_online.ico
Binary files differ
diff --git a/src/res/status_out2lunch.ico b/src/res/status_out2lunch.ico
new file mode 100644
index 0000000000..07443be63b
--- /dev/null
+++ b/src/res/status_out2lunch.ico
Binary files differ
diff --git a/src/res/status_user_online.ico b/src/res/status_user_online.ico
new file mode 100644
index 0000000000..2e1bdfa485
--- /dev/null
+++ b/src/res/status_user_online.ico
Binary files differ
diff --git a/src/resource.h b/src/resource.h
new file mode 100644
index 0000000000..412428440c
--- /dev/null
+++ b/src/resource.h
@@ -0,0 +1,528 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by resource.rc
+//
+#define IDC_AUTHICON 1
+#define IDC_NOTOALL 3
+#define IDC_APPLY 3
+#define IDC_DECIDELATER 3
+#define IDI_MIRANDA 102
+#define IDD_ABOUT 103
+#define IDI_SMS 103
+#define IDI_ONLINE 104
+#define IDI_OFFLINE 105
+#define IDD_CUSTOM_FONT 106
+#define IDD_OPT_FONTS 107
+#define IDD_OPT_GENMENU 108
+#define IDD_OPT_PROTOCOLORDER 109
+#define IDD_OPT_ICOLIB 110
+#define IDD_ICOLIB_IMPORT 111
+#define IDD_MODERNOPT_FONTS 112
+#define IDD_ADDED 115
+#define IDD_URLSEND 119
+#define IDD_URLRECV 120
+#define IDD_AUTHREQ 121
+#define IDD_DETAILS 125
+#define IDD_HISTORY 127
+#define IDI_AWAY 128
+#define IDI_FREE4CHAT 129
+#define IDI_INVISIBLE 130
+#define IDI_NA 131
+#define IDI_LOAD 132
+#define IDD_OPT_SOUND 134
+#define IDI_RECVMSG 136
+#define IDI_URL 138
+#define IDD_MODERNOPT_ACCOUNTS 139
+#define IDD_MODERNOPT_MODULES 140
+#define IDD_MODERNOPT_STATUS 141
+#define IDD_MODERNOPT_IDLE 142
+#define IDD_MODERNOPT_IGNORE 143
+#define IDI_DND 158
+#define IDI_OCCUPIED 159
+#define IDI_USERDETAILS 160
+#define IDI_FINDUSER 161
+#define IDI_HELP 162
+#define IDI_OPTIONS 163
+#define IDI_MIRANDAWEBSITE 172
+#define IDI_RENAME 173
+#define IDI_HISTORY 174
+#define IDI_DELETE 175
+#define IDR_CONTEXT 180
+#define IDR_ICOLIB_CONTEXT 181
+#define IDC_DROP 183
+#define IDD_HISTORY_FIND 192
+#define IDI_SENDEMAIL 193
+#define IDD_FILERECV 194
+#define IDD_PROFILEMANAGER 197
+#define IDR_CLISTMENU 199
+#define IDI_BLANK 200
+#define IDD_FINDADD 201
+#define IDI_USERONLINE 201
+#define IDI_GROUPSHUT 202
+#define IDD_OPTIONS 203
+#define IDI_GROUPOPEN 203
+#define IDD_FILESEND 205
+#define IDI_NOTICK 205
+#define IDD_OPT_PLUGINS 206
+#define IDI_TICK 206
+#define IDD_OPT_ICONS 207
+#define IDI_FILE 207
+#define IDI_ADDCONTACT 210
+#define IDI_SMALLDOT 211
+#define IDI_FILLEDBLOB 212
+#define IDD_READAWAYMSG 213
+#define IDI_EMPTYBLOB 213
+#define IDD_OPT_IGNORE 214
+#define IDC_HYPERLINKHAND 214
+#define IDD_OPT_VISIBILITY 215
+#define IDC_DROPUSER 215
+#define IDD_SETAWAYMSG 216
+#define IDI_DETAILSLOGO 216
+#define IDD_OPT_AWAYMSG 217
+#define IDI_UNICODE 218
+#define IDI_ANSI 219
+#define IDD_INFO_SUMMARY 220
+#define IDI_LOADED 220
+#define IDD_INFO_CONTACT 221
+#define IDR_CREDITS 221
+#define IDI_NOTLOADED 221
+#define IDD_INFO_BACKGROUND 222
+#define IDD_INFO_NOTES 223
+#define IDD_ADDEMAIL 226
+#define IDD_ICONINDEX 227
+#define IDD_INFO_LOCATION 231
+#define IDD_INFO_WORK 232
+#define IDD_ADDPHONE 233
+#define IDD_INSTALLINI 235
+#define IDD_WARNINICHANGE 236
+#define IDD_INIIMPORTDONE 237
+#define IDB_SORTCOLUP 239
+#define IDB_SORTCOLDOWN 240
+#define IDD_OPT_NETLIB 246
+#define IDD_NETLIBLOGOPTS 247
+#define IDD_FILETRANSFERINFO 249
+#define IDD_OPT_FILETRANSFER 250
+#define IDD_FILEEXISTS 251
+#define IDD_DELETECONTACT 254
+#define IDD_ADDCONTACT 257
+#define IDD_OPT_CONTACT 261
+#define IDI_DOWNARROW 264
+#define IDD_OPT_IDLE 268
+#define IDD_PROFILE_SELECTION 269
+#define IDD_PROFILE_NEW 270
+#define IDI_TYPING 274
+#define IDD_UPDATE_NOTIFY 275
+#define IDD_OPT_UPDATENOTIFY 276
+#define IDD_OPT_KEYBINDINGS 277
+#define IDD_OPT_HOTKEYS 278
+#define IDI_UNDO 279
+#define IDI_WINDOW 280
+#define IDI_WINDOWS 281
+#define IDI_ACCMGR 282
+#define IDD_ACCMGR 283
+#define IDD_ACCFORM 284
+#define IDD_WAITRESTART 285
+#define IDD_FTMGR 286
+#define IDD_FTPAGE 287
+#define IDD_OPT_KEYWORDFILTER 288
+#define IDI_JOINCHAT 289
+#define IDD_CHOOSE_FONT_EFFECT 289
+#define IDI_LEAVECHAT 290
+#define IDI_STATUS_LOCKED 291
+#define IDI_SHOWHIDE 292
+#define IDI_EXIT 293
+#define IDD_ERROR_LIST 300
+#define IDD_OPT_ERRORS 301
+#define IDD_OPTIONSPAGE 318
+#define IDI_MOVETOGROUP 319
+#define IDI_ON 320
+#define IDI_OFF 322
+#define IDC_SAVE 1001
+#define IDI_ONTHEPHONE 1002
+#define IDC_MESSAGE 1002
+#define IDI_OUTTOLUNCH 1003
+#define IDC_AUTOCLOSE 1004
+#define IDC_FROM 1005
+#define IDC_AUTOMIN 1005
+#define IDC_DATE 1006
+#define IDC_DUMPRECV 1006
+#define IDC_AUTOCLEAR 1007
+#define IDC_MSG 1008
+#define IDC_PROXYDNS 1008
+#define IDC_NAME 1009
+#define IDC_PROXYTYPE 1009
+#define IDC_STATIC23 1010
+#define IDC_NAMEVAL 1010
+#define IDC_LNK_NETWORK 1010
+#define IDC_LNK_ADDONS 1011
+#define IDC_SPECIFYPORTS 1013
+#define IDC_ST_ENTERMSG 1013
+#define IDC_ST_ENTERURL 1014
+#define IDC_SPECIFYPORTSO 1014
+#define IDC_ENABLEUPNP 1015
+#define IDC_VALIDATESSL 1016
+#define IDC_SHOWNAMES 1024
+#define IDC_ABOUT 1032
+#define IDC_MYNOTES 1033
+#define IDC_URLS 1037
+#define IDC_REPLY 1039
+#define IDC_URL 1041
+#define IDC_FONTGROUP 1042
+#define IDC_BTN_RESET 1045
+#define IDC_REASON 1046
+#define IDC_BTN_UNDO 1047
+#define IDC_DENYREASON 1047
+#define IDC_EMAIL 1048
+#define IDC_NAMENICK 1049
+#define IDC_NAMEFIRST 1050
+#define IDC_NAMELAST 1051
+#define IDC_NICK 1053
+#define IDC_BTN_EXPORT 1054
+#define IDC_FONTLIST 1056
+#define IDC_CHOOSEFONT 1057
+#define IDC_EFFECT 1058
+#define IDC_EFFECT_STATIC 1059
+#define IDC_GENDER 1060
+#define IDC_CITY 1061
+#define IDC_MARITAL 1061
+#define IDC_STATE 1062
+#define IDC_COUNTRY 1063
+#define IDC_AGE 1064
+#define IDC_ZIP 1064
+#define IDC_PHONE 1065
+#define IDC_STREET 1065
+#define IDC_COMPANY 1066
+#define IDC_LANGUAGE1 1066
+#define IDC_TIMEZONE 1067
+#define IDC_DEPARTMENT 1067
+#define IDC_LOCALTIME 1068
+#define IDC_DETAILS 1069
+#define IDC_POSITION 1069
+#define IDC_LANGUAGE2 1069
+#define IDC_ADD 1070
+#define IDC_LANGUAGE3 1070
+#define IDC_TIMEZONESELECT 1071
+#define IDC_MOREOPTIONS 1071
+#define IDC_USERMENU 1071
+#define IDC_EDIT 1078
+#define IDC_LIST 1079
+#define IDC_HISTORY 1080
+#define IDC_MENUOBJECTS 1081
+#define IDC_MENUITEMS 1082
+#define IDC_NOTSUPPORTWARNING 1083
+#define IDC_INSERTSEPARATOR 1084
+#define IDC_GENMENU_SERVICE 1085
+#define IDC_GENMENU_CUSTOMNAME 1086
+#define IDC_GENMENU_SET 1087
+#define IDC_GENMENU_DEFAULT 1089
+#define IDC_CANVAS 1094
+#define IDC_CANVAS2 1095
+#define IDC_BUILDTIME 1108
+#define IDC_CREDITSFILE 1109
+#define IDC_NUMBER 1113
+#define IDC_FINDWHAT 1131
+#define IDC_FIND 1132
+#define IDC_FILE 1133
+#define IDC_PROFILELIST 1134
+#define IDC_EFFECT_COMBO 1140
+#define IDC_TABS 1141
+#define IDC_RESULTS 1142
+#define IDC_STATUS 1144
+#define IDC_USEPROXY 1148
+#define IDC_PROXYAUTH 1149
+#define IDC_PROXYHOST 1150
+#define IDC_PROXYPORT 1151
+#define IDC_PROXYUSER 1152
+#define IDC_PROXYPASS 1153
+#define IDC_STATIC12 1155
+#define IDC_STATIC21 1156
+#define IDC_STATIC22 1157
+#define IDC_STATIC31 1158
+#define IDC_STATIC32 1159
+#define IDC_CHANGE 1164
+#define IDC_PREVIEW 1165
+#define IDC_CHOOSE 1169
+#define IDC_TO 1170
+#define IDC_VERSION 1179
+#define IDC_ICONSET 1183
+#define IDC_BROWSE 1184
+#define IDC_RUNATSTARTBROWSE 1185
+#define IDC_PAGETREE 1186
+#define IDC_RUNNOW 1186
+#define IDC_RETRIEVING 1193
+#define IDC_GETMORE 1200
+#define IDC_VISIBLEICON 1204
+#define IDC_INVISIBLEICON 1205
+#define IDC_FILEICON 1206
+#define IDC_ONLINEICON 1207
+#define IDC_FILENAMES 1208
+#define IDC_ALLICON 1208
+#define IDC_DONTREPLY 1209
+#define IDC_NONEICON 1209
+#define IDC_USEPREVIOUS 1210
+#define IDC_TYPINGICON 1210
+#define IDC_NODIALOG 1211
+#define IDC_USESPECIFIC 1212
+#define IDC_FILEDIR 1213
+#define IDC_TRANSFERCOMPLETED 1214
+#define IDC_ALLFILESPROGRESS 1217
+#define IDC_WHITERECT 1221
+#define IDC_ALLSPEED 1221
+#define IDC_FIRSTNAME 1224
+#define IDC_LASTNAME 1225
+#define IDC_DOBDAY 1226
+#define IDC_DOBMONTH 1227
+#define IDC_WEBPAGE 1228
+#define IDC_DOBYEAR 1228
+#define IDC_UPDATING 1231
+#define IDC_NAMEORDER 1234
+#define IDC_RECONNECTREQD 1239
+#define IDC_IMPORT 1241
+#define IDC_TOMAIN 1243
+#define IDC_TOPROTO 1244
+#define IDC_PROTOLIST 1245
+#define IDC_TODEFICON 1246
+#define IDC_IMPORTMULTI 1247
+#define IDC_EFFECT_COLOUR1 1266
+#define IDC_BKGCOLOUR 1269
+#define IDC_EFFECT_COLOUR2 1269
+#define IDC_FILENAME 1271
+#define IDC_FONTCOLOUR 1282
+#define IDC_INTERESTS 1305
+#define IDC_EMAILS 1306
+#define IDC_PAST 1307
+#define IDC_PHONES 1308
+#define IDC_SMS 1310
+#define IDC_AREA 1312
+#define IDC_UPDATE 1313
+#define IDC_ININAME 1333
+#define IDC_VIEWINI 1334
+#define IDC_SECURITYINFO 1335
+#define IDC_SETTINGNAME 1336
+#define IDC_NEWVALUE 1337
+#define IDC_WARNNOMORE 1338
+#define IDC_DELETE 1339
+#define IDC_RECYCLE 1340
+#define IDC_NEWNAME 1341
+#define IDC_MOVE 1342
+#define IDC_LEAVE 1343
+#define IDC_EXPERT 1346
+#define IDC_CATEGORYLIST 1366
+#define IDC_LOADICONS 1369
+#define IDC_STICONSGROUP 1371
+#define IDC_MSGICON 1375
+#define IDC_URLICON 1376
+#define IDC_STNOPAGE 1377
+#define IDC_STCHECKMARKS 1380
+#define IDC_STATUSBAR 1389
+#define IDC_PROTOIDGROUP 1392
+#define IDC_BYPROTOID 1393
+#define IDC_PROTOID 1394
+#define IDC_EMAILGROUP 1395
+#define IDC_BYEMAIL 1396
+#define IDC_STNAMENICK 1397
+#define IDC_NAMEGROUP 1398
+#define IDC_BYNAME 1399
+#define IDC_STNAMEFIRST 1400
+#define IDC_STNAMELAST 1401
+#define IDC_ADVANCEDGROUP 1402
+#define IDC_BYADVANCED 1403
+#define IDC_ADVANCED 1404
+#define IDC_PROTOCOLORDER 1405
+#define IDC_TINYEXTENDEDGROUP 1406
+#define IDC_RESETPROTOCOLDATA 1407
+#define IDC_BYCUSTOM 1408
+#define IDC_PROTOCOLORDERWARNING 1409
+#define IDC_STSIMPLERIGHT 1440
+#define IDC_NETLIBUSERS 1443
+#define IDC_STOFTENPORT 1445
+#define IDC_STATIC52 1447
+#define IDC_STATIC43 1448
+#define IDC_LOGOPTIONS 1449
+#define IDC_PORTSRANGE 1450
+#define IDC_PORTSRANGEO 1452
+#define IDC_STATIC54 1453
+#define IDC_TOOUTPUTDEBUGSTRING 1455
+#define IDC_TOFILE 1456
+#define IDC_RUNATSTART 1458
+#define IDC_DUMPSENT 1464
+#define IDC_DUMPPROXY 1466
+#define IDC_TEXTDUMPS 1467
+#define IDC_AUTODETECTTEXT 1468
+#define IDC_TIMEFORMAT 1469
+#define IDC_FILENAMEBROWSE 1470
+#define IDC_SHOWTHISDLGATSTART 1471
+#define IDC_DUMPSSL 1473
+#define IDC_FILEDIRBROWSE 1475
+#define IDC_SCANCMDLINEBROWSE 1476
+#define IDC_ALLTRANSFERRED 1477
+#define IDC_OPENFOLDER 1478
+#define IDC_OPENFILE 1479
+#define IDC_TOTALSIZE 1480
+#define IDC_CONTACT 1480
+#define IDC_AUTOACCEPT 1484
+#define IDC_SCANCMDLINE 1485
+#define IDC_WARNBEFOREOPENING 1488
+#define IDC_SCANDURINGDL 1489
+#define IDC_SCANAFTERDL 1490
+#define IDC_NOSCANNER 1491
+#define IDC_ST_CMDLINE 1492
+#define IDC_ST_CMDLINEHELP 1493
+#define IDC_PROPERTIES 1496
+#define IDC_RESUME 1497
+#define IDC_EXISTINGICON 1499
+#define IDC_RESUMEALL 1500
+#define IDC_OVERWRITE 1501
+#define IDC_OVERWRITEALL 1502
+#define IDC_SKIP 1503
+#define IDC_EXISTINGSIZE 1506
+#define IDC_EXISTINGDATE 1507
+#define IDC_EXISTINGTYPE 1508
+#define IDC_NEWICON 1509
+#define IDC_NEWSIZE 1510
+#define IDC_NEWDATE 1511
+#define IDC_NEWTYPE 1512
+#define IDC_SAVEAS 1513
+#define IDC_AUTORENAME 1514
+#define IDC_ASK 1516
+#define IDC_RENAME 1519
+#define IDC_VIRUSSCANNERGROUP 1520
+#define IDC_HIDE 1534
+#define IDC_TOPLINE 1535
+#define IDC_MYHANDLE 1540
+#define IDC_GROUP 1541
+#define IDC_ADDED 1542
+#define IDC_AUTH 1543
+#define IDC_DELETEHISTORY 1560
+#define IDC_AUTHREQ 1577
+#define IDC_AUTHGB 1578
+#define IDC_PROTOCOL 1580
+#define IDC_CONTRIBLINK 1586
+#define IDC_DEVS 1589
+#define IDC_TXT_TITLE1 1592
+#define IDC_TXT_TITLE2 1593
+#define IDC_TXT_TITLE3 1594
+#define IDC_TXT_TITLE4 1595
+#define IDC_TXT_TITLE5 1596
+#define IDC_TXT_TITLE6 1597
+#define IDC_TXT_TITLE7 1598
+#define IDC_TXT_TITLE8 1599
+#define IDC_PREVIEWSMALL 1600
+#define IDC_PREVIEWGENERAL 1601
+#define IDC_PREVIEWHEADER 1602
+#define IDC_CHOOSEFONTHEADER 1603
+#define IDC_CHOOSEFONTGENERAL 1604
+#define IDC_CHOOSEFONTSMALL 1605
+#define IDC_IDLEONWINDOWS 1637
+#define IDC_IDLEONMIRANDA 1638
+#define IDC_SCREENSAVER 1642
+#define IDC_LOCKED 1643
+#define IDC_IDLESHORT 1644
+#define IDC_UPGRADE 1645
+#define IDC_FULLSCREEN 1645
+#define IDC_IDLE1STTIME 1646
+#define IDC_IDLEPRIVATE 1649
+#define IDC_AASTATUS 1650
+#define IDC_AASHORTIDLE 1651
+#define IDC_SOUNDTREE 1657
+#define IDC_LOCATION 1659
+#define IDC_SGROUP 1660
+#define IDC_SLOC 1661
+#define IDC_PROFILENAME 1673
+#define IDC_PROFILEDRIVERS 1674
+#define IDC_PLUGLIST 1676
+#define IDC_PLUGINLONGINFO 1677
+#define IDC_PLUGINAUTHOR 1679
+#define IDC_PLUGININFOFRAME 1680
+#define IDC_PLUGINCPYR 1681
+#define IDC_PLUGINURL 1682
+#define IDC_PLUGINPID 1683
+#define IDC_PLUGINEMAIL 1684
+#define IDC_IDLESPIN 1687
+#define IDC_NODBDRIVERS 1690
+#define IDC_IDLESTATUSLOCK 1691
+#define IDC_RESTART 1692
+#define IDC_TAB 1693
+#define IDC_IDLETERMINAL 1694
+#define IDC_ENABLESOUNDS 1695
+#define IDC_NEWVERSIONLABEL 1696
+#define IDC_CURRENTVERSION 1697
+#define IDC_DOWNLOAD 1699
+#define IDC_ENABLEUPDATES 1700
+#define IDC_ENABLEALPHA 1701
+#define IDC_RESETMENU 1702
+#define IDC_KEYWORD_FILTER 1704
+#define IDC_FILTER 1706
+#define IDC_PATH 1707
+#define IDC_LV_HOTKEYS 1708
+#define IDC_HOTKEY 1709
+#define IDC_SM_COMBO 1710
+#define IDC_SM_LABEL 1711
+#define IDC_REMOVE 1712
+#define IDC_ACCLIST 1713
+#define IDC_ACCNAME 1714
+#define IDC_PROTOTYPECOMBO 1715
+#define IDC_ACCINTERNALNAME 1716
+#define IDC_OPTIONS 1717
+#define IDC_CLEAR 1718
+#define IDC_PROGRESSBAR 1719
+#define IDC_TXT_ACCOUNT 1720
+#define IDC_TXT_ADDITIONAL 1721
+#define IDC_TXT_INFO 1722
+#define IDC_CONTACTNAME 1724
+#define IDC_FRAME 1725
+#define IDC_LST_STATUS 1726
+#define IDC_ALLPRECENTS 1727
+#define IDC_ENABLE_KEYWORDFILTERING 1729
+#define IDC_BKGCOLOUR_STATIC 1730
+#define IDC_LST_ERRORS 1731
+#define IDC_LV_ERRORS 1733
+#define IDC_HEADERBAR 1734
+#define IDC_LV_LEGEND 1735
+#define IDC_ENABLEBETA 1737
+#define IDC_ENABLESTABLE 1738
+#define IDC_STORELASTPROFILE 1739
+#define IDC_RADIO1 1740
+#define IDC_RADIO2 1741
+#define IDC_ADDCHECK 1742
+#define IDC_GETMOREPLUGINS 1744
+#define IDC_DISABLEMENUICONS 1745
+#define IDC_EFFECT_COLOUR_TEXT1 1853
+#define IDC_EFFECT_COLOUR_SPIN1 1854
+#define IDC_EFFECT_COLOUR_TEXT2 11803
+#define IDC_EFFECT_COLOUR_SPIN2 11806
+#define IDI_SEARCHALL 32548
+#define ID_ICQ_EXIT 40001
+#define IDM_COPY 40001
+#define ID_RESET 40002
+#define POPUP_HIDEEMPTYGROUPS 40003
+#define POPUP_NEWSUBGROUP 40004
+#define POPUP_HIDEOFFLINE 40005
+#define POPUP_GROUPHIDEOFFLINE 40006
+#define POPUP_HIDEOFFLINEROOT 40007
+#define POPUP_DISABLEGROUPS 40008
+#define IDC_SENDMESSAGE 40009
+#define IDM_COPYALL 40011
+#define IDM_SELECTALL 40012
+#define IDM_CLEAR 40013
+#define IDM_OPENNEW 40014
+#define IDM_OPENEXISTING 40015
+#define IDM_COPYLINK 40016
+#define POPUP_HIDEMIRANDA 40017
+#define ID_CANCELCHANGE 40018
+#define ID_TRAY_HIDE 40038
+#define ID_TRAY_EXIT 40040
+#define POPUP_NEWGROUP 40050
+#define POPUP_RENAMEGROUP 40052
+#define POPUP_DELETEGROUP 40053
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 323
+#define _APS_NEXT_COMMAND_VALUE 40018
+#define _APS_NEXT_CONTROL_VALUE 1746
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/src/resource.rc b/src/resource.rc
new file mode 100644
index 0000000000..a367648a04
--- /dev/null
+++ b/src/resource.rc
@@ -0,0 +1,2042 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include <windows.h>
+#include <winres.h>
+#include "../include/statusmodes.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (United States) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_ACCFORM DIALOGEX 0, 0, 205, 119
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Enter account name (for example, My Google)",IDC_STATIC,7,7,191,9
+ EDITTEXT IDC_ACCNAME,7,18,191,12,ES_AUTOHSCROLL
+ LTEXT "Choose the protocol type",IDC_STATIC,7,35,191,11
+ COMBOBOX IDC_PROTOTYPECOMBO,7,46,191,60,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Specify the internal account name (optional)",IDC_STATIC,7,65,191,8
+ EDITTEXT IDC_ACCINTERNALNAME,7,76,191,12,ES_AUTOHSCROLL
+ PUSHBUTTON "OK",IDOK,92,98,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,148,98,50,14
+END
+
+IDD_AUTHREQ DIALOGEX 0, 0, 271, 197
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Authorization Request"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "",IDC_HEADERBAR,"MHeaderbarCtrl",0x0,0,0,271,25
+ DEFPUSHBUTTON "&Authorize",IDOK,17,176,50,14
+ PUSHBUTTON "&Deny",IDCANCEL,97,176,50,14
+ PUSHBUTTON "Decide &Later",IDC_DECIDELATER,175,176,74,14
+ CONTROL "&I",IDC_DETAILS,"MButtonClass",WS_TABSTOP,248,29,16,14,WS_EX_NOACTIVATE | 0x10000000L
+ LTEXT "Reason:",IDC_STATIC,7,39,101,10,SS_CENTERIMAGE
+ EDITTEXT IDC_REASON,7,50,257,54,ES_MULTILINE | ES_READONLY | NOT WS_BORDER | WS_VSCROLL | WS_HSCROLL,WS_EX_STATICEDGE
+ LTEXT "Denial Reason:",IDC_STATIC,7,111,89,10,SS_CENTERIMAGE | SS_REALSIZECONTROL
+ EDITTEXT IDC_DENYREASON,7,124,257,32,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | NOT WS_BORDER,WS_EX_STATICEDGE
+ CONTROL "Add to contact list if authorized",IDC_ADDCHECK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,18,162,239,10
+END
+
+IDD_ADDCONTACT DIALOGEX 0, 0, 230, 151
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Add %s"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "&Add",IDOK,20,130,72,14
+ PUSHBUTTON "&Cancel",IDCANCEL,139,130,71,14
+ EDITTEXT IDC_MYHANDLE,6,16,90,12,ES_AUTOHSCROLL
+ COMBOBOX IDC_GROUP,112,16,110,60,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ CONTROL "Send ""You were added""",IDC_ADDED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,46,204,10
+ CONTROL "Send authorization request",IDC_AUTH,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,60,204,10
+ LTEXT "Custom name:",IDC_STATIC,6,4,70,10
+ LTEXT "Group:",IDC_STATIC,112,4,70,10
+ GROUPBOX "Options",IDC_STATIC,7,33,216,43
+ GROUPBOX "Authorization Request",IDC_AUTHGB,7,79,216,45
+ EDITTEXT IDC_AUTHREQ,13,89,204,29,ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL
+END
+
+IDD_ADDED DIALOGEX 0, 0, 241, 70
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "You Were Added"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "",IDC_HEADERBAR,"MHeaderbarCtrl",0x0,0,0,241,25
+ PUSHBUTTON "&Close",IDCANCEL,90,51,60,14
+ CONTROL "&I",IDC_DETAILS,"MButtonClass",WS_TABSTOP,217,29,16,14,WS_EX_NOACTIVATE | 0x10000000L
+ CONTROL "&U",IDC_ADD,"MButtonClass",WS_TABSTOP,197,29,16,14,WS_EX_NOACTIVATE | 0x10000000L
+END
+
+IDD_ABOUT DIALOGEX 0, 0, 212, 131
+STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "About Miranda IM"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "Miranda IM\n%s",IDC_HEADERBAR,"MHeaderbarCtrl",WS_TABSTOP,0,0,212,25
+ LTEXT "",IDC_WHITERECT,0,25,213,81
+ DEFPUSHBUTTON "OK",IDOK,152,112,55,14
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,0,106,213,1
+ LTEXT "",IDC_DEVS,5,32,202,42
+ EDITTEXT IDC_BUILDTIME,4,91,146,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ PUSHBUTTON "Credits >",IDC_CONTRIBLINK,5,112,55,14
+ EDITTEXT IDC_CREDITSFILE,4,32,202,67,ES_CENTER | ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER | WS_VSCROLL
+END
+
+IDD_DELETECONTACT DIALOGEX 0, 0, 294, 93
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Delete Contact"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ PUSHBUTTON "&Yes",IDYES,58,38,65,14
+ DEFPUSHBUTTON "&No",IDNO,172,38,65,14
+ CONTROL "Hide from list only, in order to keep their history and ignore/visibility settings",IDC_HIDE,
+ "Button",BS_AUTOCHECKBOX | BS_MULTILINE | WS_TABSTOP,7,65,270,9
+ LTEXT "Use Options->Ignore (expert mode) to unhide contacts.",IDC_STATIC,20,78,257,8
+ CONTROL "Are you sure you want to delete %s?",IDC_TOPLINE,"Static",SS_SIMPLE | SS_NOPREFIX | WS_GROUP,7,7,270,8
+ LTEXT "This will erase all history and settings for this contact!",IDC_STATIC,7,18,239,14
+END
+
+IDD_OPT_CONTACT DIALOGEX 0, 0, 199, 147
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Contact Display Options",IDC_STATIC,13,7,176,133
+ LTEXT "Instead of displaying contacts by their nickname, drag to choose another order:",IDC_STATIC,19,17,165,27
+ CONTROL "Tree1",IDC_NAMEORDER,"SysTreeView32",TVS_NOTOOLTIPS | TVS_FULLROWSELECT | WS_BORDER | WS_HSCROLL | WS_TABSTOP,19,48,164,86
+END
+
+IDD_PROFILEMANAGER DIALOGEX 0, 0, 400, 211
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Miranda IM Profile Manager"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "",IDC_NAME,"MHeaderbarCtrl",0x0,0,0,400,25
+ CONTROL "Tab1",IDC_TABS,"SysTabControl32",TCS_HOTTRACK | WS_TABSTOP,4,31,393,160
+ PUSHBUTTON "&Run",IDOK,298,194,48,14
+ PUSHBUTTON "&Exit",IDCANCEL,348,194,48,14
+ RTEXT "Start in Service Mode with",IDC_SM_LABEL,10,196,106,10
+ COMBOBOX IDC_SM_COMBO,120,195,123,12,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+END
+
+IDD_FINDADD DIALOGEX 0, 0, 427, 257
+STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Find/Add Contacts"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Search:",IDC_STATIC,5,32,37,8
+ CONTROL "",IDC_PROTOLIST,"ComboBoxEx32",CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP,42,30,80,88
+ GROUPBOX "",IDC_PROTOIDGROUP,5,46,117,32
+ CONTROL "",IDC_BYPROTOID,"Button",BS_AUTORADIOBUTTON,11,46,85,10
+ EDITTEXT IDC_PROTOID,11,59,105,12,ES_AUTOHSCROLL
+ GROUPBOX "",IDC_EMAILGROUP,5,83,117,32
+ CONTROL "E-mail address",IDC_BYEMAIL,"Button",BS_AUTORADIOBUTTON,11,83,80,10
+ EDITTEXT IDC_EMAIL,11,96,105,12,ES_AUTOHSCROLL
+ GROUPBOX "",IDC_NAMEGROUP,5,120,117,59
+ CONTROL "Name",IDC_BYNAME,"Button",BS_AUTORADIOBUTTON,11,120,49,10
+ LTEXT "Nick:",IDC_STNAMENICK,11,135,31,8,NOT WS_GROUP
+ EDITTEXT IDC_NAMENICK,42,134,74,12,ES_AUTOHSCROLL
+ LTEXT "First:",IDC_STNAMEFIRST,11,150,31,8,NOT WS_GROUP
+ EDITTEXT IDC_NAMEFIRST,42,147,74,12,ES_AUTOHSCROLL
+ LTEXT "Last:",IDC_STNAMELAST,11,163,31,8,NOT WS_GROUP
+ EDITTEXT IDC_NAMELAST,42,161,74,12,ES_AUTOHSCROLL
+ GROUPBOX "",IDC_ADVANCEDGROUP,5,184,117,32
+ CONTROL "Advanced",IDC_BYADVANCED,"Button",BS_AUTORADIOBUTTON,11,184,62,10
+ CONTROL "Advanced >>",IDC_ADVANCED,"Button",BS_AUTOCHECKBOX | BS_PUSHLIKE | WS_TABSTOP,11,196,105,14
+ GROUPBOX "",IDC_TINYEXTENDEDGROUP,5,190,117,25
+ DEFPUSHBUTTON "&Search",IDOK,5,222,117,17
+ CONTROL "List1",IDC_RESULTS,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_AUTOARRANGE | WS_BORDER | WS_TABSTOP,129,30,293,191
+ CONTROL "More options",IDC_MOREOPTIONS,"MButtonClass",WS_DISABLED | WS_TABSTOP,272,225,77,14,WS_EX_NOACTIVATE | 0x10000000L
+ PUSHBUTTON "Add to list",IDC_ADD,354,225,68,14,WS_DISABLED
+ CONTROL "",IDC_STATUSBAR,"msctls_statusbar32",WS_TABSTOP | 0x100,0,244,427,10
+ CONTROL "Custom",IDC_BYCUSTOM,"Button",BS_AUTORADIOBUTTON,11,190,89,10
+ CONTROL "Find/Add Contacts\nHere you can add contacts to your contact list",IDC_HEADERBAR,
+ "MHeaderbarCtrl",0x0,0,0,427,25
+END
+
+IDD_OPTIONS DIALOGEX 0, 0, 428, 303
+STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Options"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ COMBOBOX IDC_KEYWORD_FILTER,336,6,88,79,CBS_DROPDOWN | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ CONTROL "Options\nConfigure your Miranda Instant Messenger options",IDC_HEADERBAR,
+ "MHeaderbarCtrl",0x0,0,0,428,25
+ DEFPUSHBUTTON "OK",IDOK,265,283,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,319,283,50,14
+ PUSHBUTTON "Apply",IDC_APPLY,374,283,50,14
+ CONTROL "Tree1",IDC_PAGETREE,"SysTreeView32",TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT | TVS_DISABLEDRAGDROP | TVS_SHOWSELALWAYS | TVS_TRACKSELECT | TVS_NOHSCROLL | WS_BORDER | WS_TABSTOP,4,30,102,249
+ CONTROL "",IDC_TAB,"SysTabControl32",NOT WS_VISIBLE | WS_TABSTOP,111,30,313,249
+ CONTROL "Show expert options",IDC_EXPERT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,284,102,10
+ CTEXT "Please select a subentry from the list",IDC_STNOPAGE,111,30,313,251,SS_CENTERIMAGE
+END
+
+IDD_OPTIONSPAGE DIALOGEX 0, 0, 321, 303
+STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Options"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ COMBOBOX IDC_KEYWORD_FILTER,336,37,88,79,CBS_DROPDOWN | CBS_SORT | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP
+ CONTROL "Options\nConfigure your Miranda Instant Messenger options",IDC_HEADERBAR,
+ "MHeaderbarCtrl",0x0,0,0,325,25
+ DEFPUSHBUTTON "OK",IDOK,158,283,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,212,283,50,14
+ PUSHBUTTON "Apply",IDC_APPLY,267,283,50,14
+ CONTROL "",IDC_TAB,"SysTabControl32",NOT WS_VISIBLE | WS_TABSTOP,4,32,313,249
+ CONTROL "Show expert options",IDC_EXPERT,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,347,254,62,10
+ CTEXT "Please select a subentry from the list",IDC_STNOPAGE,4,30,313,251,SS_CENTERIMAGE
+ CONTROL "",IDC_PAGETREE,"SysTreeView32",TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT | TVS_DISABLEDRAGDROP | TVS_SHOWSELALWAYS | TVS_TRACKSELECT | TVS_NOHSCROLL | NOT WS_VISIBLE | WS_BORDER | WS_TABSTOP,347,86,52,137
+END
+
+IDD_READAWAYMSG DIALOGEX 0, 0, 187, 72
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "%s Message for %s"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "&Cancel",IDOK,69,53,50,14
+ CTEXT "Retrieving %s message...",IDC_RETRIEVING,5,21,177,8,SS_NOPREFIX
+ EDITTEXT IDC_MSG,5,5,177,43,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | NOT WS_VISIBLE | WS_VSCROLL
+END
+
+IDD_SETAWAYMSG DIALOGEX 0, 0, 187, 72
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Change %s Message"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "Closing in %d",IDOK,61,53,65,14
+ EDITTEXT IDC_MSG,5,5,177,43,ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL
+END
+
+IDD_DETAILS DIALOGEX 0, 0, 318, 210
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "%s: User Details"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "%s\nView personal user details and more",IDC_HEADERBAR,
+ "MHeaderbarCtrl",0x0,0,0,318,25
+ CONTROL "",IDC_PAGETREE,"SysTreeView32",TVS_DISABLEDRAGDROP | TVS_SHOWSELALWAYS | TVS_NOTOOLTIPS | TVS_TRACKSELECT | TVS_FULLROWSELECT | TVS_NONEVENHEIGHT | WS_HSCROLL | WS_TABSTOP,3,30,76,176,WS_EX_STATICEDGE
+ CONTROL "Tab1",IDC_TABS,"SysTabControl32",TCS_HOTTRACK | TCS_MULTILINE | WS_TABSTOP,85,29,228,158
+ PUSHBUTTON "Update Now",IDC_UPDATE,85,191,55,14,WS_DISABLED
+ CTEXT "Updating",IDC_UPDATING,145,194,113,8,SS_NOPREFIX | SS_CENTERIMAGE
+ DEFPUSHBUTTON "OK",IDOK,263,191,50,14
+END
+
+IDD_INFO_SUMMARY DIALOGEX 0, 0, 222, 132
+STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Nickname:",IDC_STATIC,5,5,46,8
+ EDITTEXT IDC_NICK,51,5,166,8,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "First name:",IDC_STATIC,5,18,46,8
+ EDITTEXT IDC_FIRSTNAME,51,18,74,8,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "Gender:",IDC_STATIC,126,18,44,8
+ EDITTEXT IDC_GENDER,170,18,47,8,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "Last name:",IDC_STATIC,5,31,46,8
+ EDITTEXT IDC_LASTNAME,51,31,74,8,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "Age:",IDC_STATIC,126,31,44,8
+ EDITTEXT IDC_AGE,170,31,47,8,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "E-mail:",IDC_STATIC,5,44,46,8
+ CONTROL "",IDC_EMAIL,"Hyperlink",WS_TABSTOP,51,44,166,8
+ LTEXT "Date of birth:",IDC_STATIC,5,58,59,8
+ EDITTEXT IDC_DOBDAY,66,58,8,8,ES_RIGHT | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ EDITTEXT IDC_DOBMONTH,76,58,16,8,ES_RIGHT | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ EDITTEXT IDC_DOBYEAR,94,58,20,8,ES_RIGHT | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "Marital status:",IDC_STATIC,5,71,76,8
+ EDITTEXT IDC_MARITAL,83,71,87,8,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+END
+
+IDD_INFO_CONTACT DIALOGEX 0, 0, 222, 132
+STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "E-mail:",IDC_STATIC,5,5,212,8
+ CONTROL "List1",IDC_EMAILS,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_NOLABELWRAP | LVS_AUTOARRANGE | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,5,14,212,50
+ LTEXT "Phone:",IDC_STATIC,5,68,212,8
+ CONTROL "List1",IDC_PHONES,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_NOLABELWRAP | LVS_AUTOARRANGE | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,5,77,212,50
+END
+
+IDD_INFO_BACKGROUND DIALOGEX 0, 0, 222, 132
+STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Web page:",IDC_STATIC,5,5,44,8
+ CONTROL "",IDC_WEBPAGE,"Hyperlink",WS_TABSTOP,49,5,168,8
+ LTEXT "Past background:",IDC_STATIC,5,18,212,8
+ CONTROL "List1",IDC_PAST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_NOLABELWRAP | LVS_AUTOARRANGE | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,5,27,212,44
+ LTEXT "Interests:",IDC_STATIC,5,74,212,8
+ CONTROL "List1",IDC_INTERESTS,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_NOLABELWRAP | LVS_AUTOARRANGE | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,5,83,212,44
+END
+
+IDD_INFO_NOTES DIALOGEX 0, 0, 222, 132
+STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "About:",IDC_STATIC,5,5,212,8
+ EDITTEXT IDC_ABOUT,5,13,212,45,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | WS_VSCROLL
+ LTEXT "My notes:",IDC_STATIC,5,61,212,8
+ EDITTEXT IDC_MYNOTES,5,69,212,58,ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL
+END
+
+IDD_INFO_LOCATION DIALOGEX 0, 0, 222, 147
+STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Street:",IDC_STATIC,5,5,51,8
+ EDITTEXT IDC_STREET,56,5,161,16,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "City:",IDC_STATIC,5,22,51,8
+ EDITTEXT IDC_CITY,56,22,161,8,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "State:",IDC_STATIC,5,33,51,8
+ EDITTEXT IDC_STATE,56,33,161,8,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "Postal code:",IDC_STATIC,5,44,51,8
+ EDITTEXT IDC_ZIP,56,44,161,8,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "Country:",IDC_STATIC,5,55,51,8
+ EDITTEXT IDC_COUNTRY,56,55,161,8,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "Spoken languages:",IDC_STATIC,5,70,51,16
+ EDITTEXT IDC_LANGUAGE1,56,70,161,8,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ EDITTEXT IDC_LANGUAGE2,56,78,161,8,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ EDITTEXT IDC_LANGUAGE3,56,86,161,8,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "Timezone:",IDC_STATIC,5,97,51,8
+ EDITTEXT IDC_TIMEZONE,56,97,161,8,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "Local time:",IDC_STATIC,5,108,51,8
+ EDITTEXT IDC_LOCALTIME,56,108,161,8,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ COMBOBOX IDC_TIMEZONESELECT,4,132,214,46,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Set custom time zone",IDC_STATIC,5,121,212,8
+END
+
+IDD_INFO_WORK DIALOGEX 0, 0, 222, 132
+STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Company:",IDC_STATIC,5,5,51,8
+ EDITTEXT IDC_COMPANY,56,5,161,8,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "Department:",IDC_STATIC,5,17,51,8
+ EDITTEXT IDC_DEPARTMENT,56,17,161,8,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "Position:",IDC_STATIC,5,28,51,8
+ EDITTEXT IDC_POSITION,56,28,161,8,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "Street:",IDC_STATIC,5,48,51,8
+ EDITTEXT IDC_STREET,56,48,161,16,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "City:",IDC_STATIC,5,65,51,8
+ EDITTEXT IDC_CITY,56,65,161,8,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "State:",IDC_STATIC,5,76,51,8
+ EDITTEXT IDC_STATE,56,76,161,8,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "Postal code:",IDC_STATIC,5,87,51,8
+ EDITTEXT IDC_ZIP,56,87,161,8,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "Country:",IDC_STATIC,5,98,51,8
+ EDITTEXT IDC_COUNTRY,56,98,161,8,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "Website:",IDC_STATIC,5,109,51,8
+ CONTROL "",IDC_WEBPAGE,"Hyperlink",WS_TABSTOP,57,109,160,8
+END
+
+IDD_ADDEMAIL DIALOGEX 0, 0, 187, 42
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Add E-Mail Address"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ EDITTEXT IDC_EMAIL,5,5,177,12,ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK",IDOK,36,23,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,102,23,50,14
+END
+
+IDD_ADDPHONE DIALOGEX 0, 0, 210, 91
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Add Phone Number"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Enter country, area code and phone number:",IDC_STATIC,5,5,200,8
+ COMBOBOX IDC_COUNTRY,21,15,66,120,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ EDITTEXT IDC_AREA,91,15,36,12,ES_AUTOHSCROLL | ES_NUMBER
+ EDITTEXT IDC_NUMBER,131,15,74,12,ES_AUTOHSCROLL | ES_NUMBER
+ LTEXT "Or enter a full international number:",IDC_STATIC,5,30,200,8
+ EDITTEXT IDC_PHONE,21,40,184,12,ES_AUTOHSCROLL
+ CONTROL "Phone can receive SMS text messages",IDC_SMS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,56,200,10
+ DEFPUSHBUTTON "OK",IDOK,47,72,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,113,72,50,14
+END
+
+IDD_INSTALLINI DIALOGEX 0, 0, 213, 103
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Install Database Settings"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "Yes",IDOK,26,84,50,14
+ PUSHBUTTON "No",IDCANCEL,81,84,50,14
+ LTEXT "A file containing new database settings has been placed in the Miranda IM directory.",IDC_STATIC,5,5,203,16
+ LTEXT "Do you want to import the settings now?",IDC_STATIC,5,69,203,8
+ PUSHBUTTON "No to all",IDC_NOTOALL,136,84,50,14
+ LTEXT "",IDC_ININAME,5,24,143,16,SS_NOPREFIX | SS_CENTERIMAGE
+ PUSHBUTTON "&View contents",IDC_VIEWINI,150,25,58,14
+ LTEXT "Security systems to prevent malicious changes are in place and you will be warned before changes that are not known to be safe.",IDC_SECURITYINFO,5,43,203,24
+END
+
+IDD_WARNINICHANGE DIALOGEX 0, 0, 187, 113
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Database Setting Change"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Database settings are being imported from",IDC_STATIC,5,5,177,8
+ CONTROL "",IDC_ININAME,"Static",SS_SIMPLE | SS_NOPREFIX | WS_GROUP,5,13,177,8
+ LTEXT "This file wishes to change the setting",IDC_STATIC,5,24,177,8
+ CONTROL "",IDC_SETTINGNAME,"Static",SS_SIMPLE | SS_NOPREFIX | WS_GROUP,12,33,170,8
+ LTEXT "to the value",IDC_STATIC,5,42,177,8
+ CONTROL "",IDC_NEWVALUE,"Static",SS_SIMPLE | SS_NOPREFIX | WS_GROUP,12,51,170,8
+ LTEXT "",IDC_SECURITYINFO,5,60,177,8
+ LTEXT "Do you want to allow this change?",IDC_STATIC,5,71,177,8
+ CONTROL "&Allow all further changes to this section",IDC_WARNNOMORE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,80,169,10
+ DEFPUSHBUTTON "&Yes",IDYES,5,94,50,14
+ PUSHBUTTON "&No",IDNO,59,94,50,14
+ PUSHBUTTON "Cancel Import",IDCANCEL,123,94,59,14
+END
+
+IDD_INIIMPORTDONE DIALOGEX 0, 0, 186, 73
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Database Import Complete"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "The import has completed from",IDC_STATIC,5,5,176,8
+ CONTROL "",IDC_ININAME,"Static",SS_SIMPLE | SS_NOPREFIX | WS_GROUP,5,13,176,8
+ LTEXT "What do you want to do with the file now?",IDC_STATIC,5,24,176,8
+ PUSHBUTTON "&Recycle",IDC_RECYCLE,5,36,50,14
+ PUSHBUTTON "&Delete",IDC_DELETE,68,36,50,14
+ EDITTEXT IDC_NEWNAME,5,55,117,12,ES_AUTOHSCROLL
+ PUSHBUTTON "&Move/Rename",IDC_MOVE,124,54,57,14
+ PUSHBUTTON "&Leave",IDC_LEAVE,131,36,50,14
+END
+
+IDD_NETLIBLOGOPTS DIALOGEX 0, 0, 314, 259
+STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Netlib Log Options"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Show",IDC_STATIC,6,2,302,118
+ CONTROL "Tree1",IDC_FILTER,"SysTreeView32",TVS_DISABLEDRAGDROP | TVS_NOTOOLTIPS | TVS_NONEVENHEIGHT | WS_BORDER | WS_HSCROLL | WS_TABSTOP,14,13,160,81
+ CONTROL "Received bytes",IDC_DUMPRECV,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,181,13,122,10
+ CONTROL "Sent bytes",IDC_DUMPSENT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,181,26,122,10
+ CONTROL "Additional data due to proxy communication",IDC_DUMPPROXY,
+ "Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | WS_TABSTOP,181,39,122,18
+ CONTROL "Text dumps where available",IDC_TEXTDUMPS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,181,69,122,10
+ CONTROL "Auto-detect text",IDC_AUTODETECTTEXT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,181,83,122,10
+ CONTROL "Calling modules' names",IDC_SHOWNAMES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,181,96,122,10
+ COMBOBOX IDC_TIMEFORMAT,14,100,160,69,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ GROUPBOX "Log to",IDC_STATIC,6,122,302,66
+ CONTROL "OutputDebugString()",IDC_TOOUTPUTDEBUGSTRING,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,132,122,10
+ CONTROL "File",IDC_TOFILE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,146,44,10
+ EDITTEXT IDC_FILENAME,14,159,270,12,ES_AUTOHSCROLL
+ PUSHBUTTON "...",IDC_FILENAMEBROWSE,288,159,15,12
+ LTEXT "",IDC_PATH,14,174,294,10
+ GROUPBOX "Run programm when Miranda IM starts (eg tail -f, dbgview, etc):",IDC_STATIC,6,188,302,32
+ EDITTEXT IDC_RUNATSTART,14,200,203,12,ES_AUTOHSCROLL
+ PUSHBUTTON "...",IDC_RUNATSTARTBROWSE,220,200,15,12
+ PUSHBUTTON "Run now",IDC_RUNNOW,241,200,60,12
+ CONTROL "Show this dialog box when Miranda IM starts",IDC_SHOWTHISDLGATSTART,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,226,294,10
+ PUSHBUTTON "Save as default",IDC_SAVE,6,241,79,14
+ DEFPUSHBUTTON "Ok",IDOK,173,241,54,14
+ PUSHBUTTON "Cancel",IDCANCEL,249,241,54,14
+ CONTROL "SSL Traffic",IDC_DUMPSSL,"Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | WS_TABSTOP,181,56,122,10
+END
+
+IDD_HISTORY_FIND DIALOGEX 0, 0, 230, 46
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Find"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ EDITTEXT IDC_FINDWHAT,48,11,115,12,ES_AUTOHSCROLL
+ DEFPUSHBUTTON "&Find Next",IDOK,173,7,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,173,24,50,14
+ LTEXT "Find What:",IDC_STATIC,7,13,39,9
+END
+
+IDD_FILESEND DIALOGEX 0, 0, 256, 177
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Send File(s)"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ EDITTEXT IDC_MSG,6,102,245,46,ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL
+ DEFPUSHBUTTON "&Send",IDOK,67,157,50,15
+ PUSHBUTTON "Cancel",IDCANCEL,140,157,50,15
+ LTEXT "To:",IDC_STATIC,6,23,24,9,SS_CENTERIMAGE
+ CONTROL "",IDC_TO,"Static",SS_SIMPLE | SS_NOPREFIX | WS_GROUP,43,24,159,9
+ LTEXT "File(s):",IDC_STATIC,7,39,30,8
+ EDITTEXT IDC_FILE,38,38,213,31,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY
+ PUSHBUTTON "&Choose Again...",IDC_CHOOSE,39,74,77,14
+ RTEXT "Total size:",IDC_STATIC,119,76,68,8
+ CONTROL "",IDC_TOTALSIZE,"Static",SS_SIMPLE | SS_NOPREFIX | WS_GROUP,191,76,58,8
+ LTEXT "Description:",IDC_STATIC,6,93,96,8
+ CONTROL "6",IDC_USERMENU,"MButtonClass",WS_TABSTOP,195,5,16,14,WS_EX_NOACTIVATE | 0x10000000L
+ CONTROL "&D",IDC_DETAILS,"MButtonClass",WS_TABSTOP,213,5,16,14,WS_EX_NOACTIVATE | 0x10000000L
+ CONTROL "&H",IDC_HISTORY,"MButtonClass",WS_TABSTOP,231,5,16,14,WS_EX_NOACTIVATE | 0x10000000L
+ CONTROL "",IDC_PROTOCOL,"Button",BS_OWNERDRAW | WS_TABSTOP,5,7,12,12
+ LTEXT "",IDC_NAME,19,7,151,9,SS_NOPREFIX | SS_CENTERIMAGE
+END
+
+IDD_FILERECV DIALOGEX 0, 0, 256, 174
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Incoming File Transfer"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "A&ccept",IDOK,68,155,50,14
+ PUSHBUTTON "&Decline",IDCANCEL,138,155,50,14
+ LTEXT "From:",IDC_STATIC,6,20,24,9,SS_CENTERIMAGE
+ CONTROL "",IDC_FROM,"Static",SS_SIMPLE | SS_NOPREFIX | WS_GROUP,39,21,159,9
+ LTEXT "Date:",IDC_STATIC,6,35,28,9,SS_CENTERIMAGE
+ CONTROL "",IDC_DATE,"Static",SS_SIMPLE | SS_NOPREFIX | WS_GROUP,39,34,159,9
+ LTEXT "Files:",IDC_STATIC,6,50,28,8
+ EDITTEXT IDC_FILENAMES,39,50,210,16,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "Description:",IDC_STATIC,6,69,64,8
+ EDITTEXT IDC_MSG,6,79,243,45,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY
+ LTEXT "Save to:",IDC_STATIC,6,131,34,8
+ PUSHBUTTON "...",IDC_FILEDIRBROWSE,235,130,14,10
+ COMBOBOX IDC_FILEDIR,45,129,187,108,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP
+ CONTROL "&A",IDC_ADD,"MButtonClass",WS_TABSTOP,177,5,16,14,WS_EX_NOACTIVATE | 0x10000000L
+ CONTROL "6",IDC_USERMENU,"MButtonClass",WS_TABSTOP,195,5,16,14,WS_EX_NOACTIVATE | 0x10000000L
+ CONTROL "&D",IDC_DETAILS,"MButtonClass",WS_TABSTOP,213,5,16,14,WS_EX_NOACTIVATE | 0x10000000L
+ CONTROL "&H",IDC_HISTORY,"MButtonClass",WS_TABSTOP,231,5,16,14,WS_EX_NOACTIVATE | 0x10000000L
+ CONTROL "",IDC_PROTOCOL,"Button",BS_OWNERDRAW | WS_TABSTOP,5,7,12,12
+ LTEXT "",IDC_NAME,19,7,151,9,SS_NOPREFIX | SS_CENTERIMAGE
+END
+
+IDD_FILETRANSFERINFO DIALOGEX 0, 0, 256, 44
+STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "Contact menu",IDC_CONTACT,"MButtonClass",WS_TABSTOP,5,1,16,14,WS_EX_NOACTIVATE | 0x10000000L
+ CONTROL "",IDC_CONTACTNAME,"Static",SS_LEFTNOWORDWRAP | SS_CENTERIMAGE | SS_WORDELLIPSIS | WS_GROUP,25,1,174,14
+ CONTROL "Open...",IDC_OPENFILE,"MButtonClass",WS_DISABLED | WS_TABSTOP,203,1,16,14,WS_EX_NOACTIVATE | 0x10000000L
+ CONTROL "Open folder",IDC_OPENFOLDER,"MButtonClass",WS_TABSTOP,219,1,16,14,WS_EX_NOACTIVATE | 0x10000000L
+ CONTROL "Cancel",IDCANCEL,"MButtonClass",WS_TABSTOP,235,1,16,14,WS_EX_NOACTIVATE | 0x10000000L
+ CONTROL "",IDC_ALLFILESPROGRESS,"msctls_progress32",PBS_SMOOTH | NOT WS_VISIBLE | WS_DISABLED,25,16,190,12
+ CONTROL "",IDC_STATUS,"Static",SS_LEFTNOWORDWRAP | SS_NOPREFIX | WS_GROUP,25,17,190,10
+ ICON "",IDC_FILEICON,25,15,16,14,SS_CENTERIMAGE | SS_REALSIZEIMAGE
+ CONTROL "Transfer completed, open file(s).",IDC_TRANSFERCOMPLETED,
+ "Hyperlink",NOT WS_VISIBLE | WS_TABSTOP,42,17,173,10
+ LTEXT "No data transferred",IDC_ALLTRANSFERRED,25,29,226,14,SS_NOPREFIX | SS_CENTERIMAGE
+ RTEXT "",IDC_ALLSPEED,25,29,226,14,SS_NOPREFIX | SS_CENTERIMAGE
+ LTEXT "",IDC_ALLPRECENTS,218,14,33,14,SS_CENTERIMAGE
+ CONTROL "",IDC_FRAME,"Static",SS_ETCHEDHORZ,1,43,254,1
+END
+
+IDD_FILEEXISTS DIALOGEX 0, 0, 288, 181
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "File Already Exists"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ PUSHBUTTON "Resume",IDC_RESUME,5,144,65,14
+ PUSHBUTTON "Resume all",IDC_RESUMEALL,5,162,65,14
+ PUSHBUTTON "Overwrite",IDC_OVERWRITE,76,144,65,14
+ PUSHBUTTON "Overwrite all",IDC_OVERWRITEALL,76,162,65,14
+ PUSHBUTTON "Save as...",IDC_SAVEAS,147,144,65,14
+ PUSHBUTTON "Auto rename",IDC_AUTORENAME,147,162,65,14
+ PUSHBUTTON "Skip",IDC_SKIP,218,144,65,14
+ PUSHBUTTON "Cancel transfer",IDCANCEL,218,162,65,14
+ LTEXT "You are about to receive the file",IDC_STATIC,5,5,278,8
+ EDITTEXT IDC_FILENAME,15,16,268,8,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ GROUPBOX "Existing file",IDC_STATIC,5,29,278,61
+ ICON "",IDC_EXISTINGICON,14,45,20,20,SS_NOTIFY
+ LTEXT "Size:",IDC_STATIC,40,42,27,8
+ LTEXT "",IDC_EXISTINGSIZE,67,42,35,8
+ RTEXT "Last modified:",IDC_STATIC,103,42,58,8
+ LTEXT "",IDC_EXISTINGDATE,166,42,115,8
+ LTEXT "Type:",IDC_STATIC,40,55,27,8
+ LTEXT "",IDC_EXISTINGTYPE,67,55,214,8
+ PUSHBUTTON "Open file",IDC_OPENFILE,12,70,62,13
+ PUSHBUTTON "Open folder",IDC_OPENFOLDER,82,70,62,13
+ PUSHBUTTON "File properties",IDC_PROPERTIES,201,70,74,13
+ GROUPBOX "File being received",IDC_STATIC,5,95,278,42
+ ICON "",IDC_NEWICON,14,110,20,20,SS_NOTIFY
+ LTEXT "Size:",IDC_STATIC,40,108,27,8
+ LTEXT "",IDC_NEWSIZE,67,108,35,8
+ RTEXT "Last modified:",IDC_STATIC,103,108,58,8
+ LTEXT "",IDC_NEWDATE,166,108,115,8
+ LTEXT "Type:",IDC_STATIC,40,121,27,8
+ LTEXT "",IDC_NEWTYPE,67,121,214,8
+END
+
+IDD_URLSEND DIALOGEX 0, 0, 215, 126
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ COMBOBOX IDC_URLS,5,30,205,92,CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP
+ EDITTEXT IDC_MESSAGE,5,57,205,44,ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL
+ DEFPUSHBUTTON "&Send",IDOK,54,107,50,14
+ PUSHBUTTON "&Cancel",IDCANCEL,113,107,50,14
+ CONTROL "",IDC_PROTOCOL,"Button",BS_OWNERDRAW | WS_TABSTOP,5,7,12,12
+ LTEXT "",IDC_NAME,19,7,118,9,SS_NOPREFIX | SS_CENTERIMAGE
+ CONTROL "&A",IDC_ADD,"MButtonClass",WS_TABSTOP,140,5,16,14,WS_EX_NOACTIVATE | 0x10000000L
+ CONTROL "6",IDC_USERMENU,"MButtonClass",WS_TABSTOP,158,5,16,14,WS_EX_NOACTIVATE | 0x10000000L
+ CONTROL "&D",IDC_DETAILS,"MButtonClass",WS_TABSTOP,176,5,16,14,WS_EX_NOACTIVATE | 0x10000000L
+ CONTROL "&H",IDC_HISTORY,"MButtonClass",WS_TABSTOP,194,5,16,14,WS_EX_NOACTIVATE | 0x10000000L
+ LTEXT "Enter URL:",IDC_ST_ENTERURL,5,20,205,8
+ LTEXT "Enter description:",IDC_ST_ENTERMSG,5,47,205,8
+END
+
+IDD_URLRECV DIALOGEX 0, 0, 215, 140
+STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "URL Received"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "&Open URL",IDOK,"MButtonClass",WS_TABSTOP,11,120,57,14,WS_EX_NOACTIVATE | 0x10000000L
+ PUSHBUTTON "&Reply",IDC_REPLY,82,120,50,14
+ PUSHBUTTON "&Close",IDCANCEL,148,120,50,14
+ CONTROL "",IDC_PROTOCOL,"Button",BS_OWNERDRAW | WS_TABSTOP,5,7,12,12
+ LTEXT "",IDC_NAME,19,7,118,9,SS_NOPREFIX | SS_CENTERIMAGE
+ CONTROL "&A",IDC_ADD,"MButtonClass",WS_TABSTOP,140,5,16,14,WS_EX_NOACTIVATE | 0x10000000L
+ CONTROL "6",IDC_USERMENU,"MButtonClass",WS_TABSTOP,158,5,16,14,WS_EX_NOACTIVATE | 0x10000000L
+ CONTROL "&D",IDC_DETAILS,"MButtonClass",WS_TABSTOP,176,5,16,14,WS_EX_NOACTIVATE | 0x10000000L
+ CONTROL "&H",IDC_HISTORY,"MButtonClass",WS_TABSTOP,194,5,16,14,WS_EX_NOACTIVATE | 0x10000000L
+ LTEXT "Date:",IDC_STATIC,5,21,29,8
+ EDITTEXT IDC_DATE,34,21,176,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER
+ LTEXT "URL:",IDC_STATIC,5,33,205,8
+ EDITTEXT IDC_URL,5,43,205,12,ES_AUTOHSCROLL | ES_READONLY
+ LTEXT "Description:",IDC_ST_ENTERMSG,5,60,205,8
+ EDITTEXT IDC_MSG,5,70,205,44,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | WS_VSCROLL
+END
+
+IDD_HISTORY DIALOGEX 0, 0, 296, 166
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Message History"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "Close",IDOK,239,144,50,14
+ EDITTEXT IDC_EDIT,7,83,282,52,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | WS_VSCROLL
+ LISTBOX IDC_LIST,7,7,282,72,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "&Find...",IDC_FIND,7,144,50,14
+ PUSHBUTTON "Delete",IDC_DELETEHISTORY,66,144,50,14
+END
+
+IDD_OPT_SOUND DIALOGEX 0, 0, 285, 240
+STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Sounds",IDC_STATIC,4,4,277,154
+ PUSHBUTTON "&Change...",IDC_CHANGE,16,213,50,14
+ PUSHBUTTON "&Preview",IDC_PREVIEW,70,213,50,14
+ CONTROL "Download more sounds",IDC_GETMORE,"Hyperlink",WS_TABSTOP | 0x2,127,216,137,8
+ CONTROL "Tree1",IDC_SOUNDTREE,"SysTreeView32",TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT | TVS_DISABLEDRAGDROP | TVS_SHOWSELALWAYS | TVS_FULLROWSELECT | WS_BORDER | WS_TABSTOP,12,33,261,119
+ GROUPBOX "Sound Information",IDC_SGROUP,4,162,277,71
+ LTEXT "Location:",IDC_SLOC,17,190,40,9
+ EDITTEXT IDC_LOCATION,65,190,208,13,ES_AUTOHSCROLL | ES_READONLY
+ LTEXT "Name:",IDC_NAME,17,174,39,9
+ LTEXT "",IDC_NAMEVAL,64,174,209,9
+ CONTROL "Enable sound events",IDC_ENABLESOUNDS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,17,261,10
+END
+
+IDD_OPT_ICONS DIALOGEX 0, 0, 257, 193
+STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Icons",IDC_STICONSGROUP,4,4,248,185
+ LTEXT "Show category:",IDC_STATIC,12,18,66,16
+ LISTBOX IDC_CATEGORYLIST,114,17,129,41,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+ CONTROL "List1",IDC_PREVIEW,"SysListView32",LVS_SINGLESEL | LVS_AUTOARRANGE | WS_BORDER | WS_TABSTOP,12,66,231,83
+ PUSHBUTTON "&Load icon set...",IDC_LOADICONS,12,158,94,13
+ PUSHBUTTON "&Import icons >>",IDC_IMPORT,154,158,89,13
+ CONTROL "Download more icons",IDC_GETMORE,"Hyperlink",WS_TABSTOP | 0x1,12,178,232,8
+ LTEXT "",IDC_STSIMPLERIGHT,200,104,8,32,NOT WS_VISIBLE
+END
+
+IDD_OPT_IGNORE DIALOGEX 0, 0, 313, 240
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "The following events are being ignored:",IDC_STATIC,8,14,297,8
+ ICON IDI_RECVMSG,IDC_MSGICON,8,172,20,20,SS_CENTERIMAGE
+ LTEXT "Messages",IDC_STATIC,28,178,70,8,SS_NOPREFIX | SS_CENTERIMAGE
+ ICON IDI_URL,IDC_URLICON,8,187,20,20,SS_CENTERIMAGE
+ LTEXT "URLs",IDC_STATIC,28,193,70,8,SS_NOPREFIX | SS_CENTERIMAGE
+ ICON IDI_FILE,IDC_FILEICON,8,202,20,20,SS_CENTERIMAGE
+ LTEXT "Files",IDC_STATIC,28,208,70,8,SS_NOPREFIX | SS_CENTERIMAGE
+ ICON IDI_USERONLINE,IDC_ONLINEICON,96,172,20,20,SS_CENTERIMAGE
+ LTEXT "Online Notification",IDC_STATIC,116,178,107,8,SS_NOPREFIX | SS_CENTERIMAGE
+ ICON IDI_MIRANDA,IDC_AUTHICON,96,187,20,20,SS_CENTERIMAGE
+ LTEXT "Auth Requests",IDC_STATIC,116,193,107,8,SS_NOPREFIX | SS_CENTERIMAGE
+ ICON IDI_FILLEDBLOB,IDC_ALLICON,221,187,20,20,SS_CENTERIMAGE
+ LTEXT "All Events",IDC_STATIC,241,193,66,8,SS_NOPREFIX | SS_CENTERIMAGE
+ ICON IDI_EMPTYBLOB,IDC_NONEICON,221,202,20,20,SS_CENTERIMAGE
+ LTEXT "None",IDC_STATIC,241,208,66,8,SS_NOPREFIX | SS_CENTERIMAGE
+ CTEXT "Only the ticked contacts will be shown on the main contact list",IDC_STCHECKMARKS,8,227,297,8
+ CONTROL "",IDC_LIST,"CListControl",WS_TABSTOP | 0x3da,8,26,297,146,WS_EX_CLIENTEDGE
+ GROUPBOX "Ignore",IDC_STATIC,0,0,313,240
+ ICON IDI_ADDCONTACT,IDC_ADDED,96,202,20,20,SS_CENTERIMAGE
+ LTEXT "Added Notification",IDC_STATIC,116,208,107,8,SS_NOPREFIX | SS_CENTERIMAGE
+ ICON IDI_TYPING,IDC_TYPINGICON,221,172,20,20,SS_CENTERIMAGE
+ LTEXT "Typing",IDC_STATIC,241,178,66,8,SS_NOPREFIX | SS_CENTERIMAGE
+END
+
+IDD_OPT_VISIBILITY DIALOGEX 0, 0, 313, 240
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Visibility",IDC_STATIC,0,0,313,240
+ CONTROL "",IDC_LIST,"CListControl",WS_TABSTOP | 0x1d0,8,14,297,183,WS_EX_CLIENTEDGE
+ ICON IDI_ONLINE,IDC_VISIBLEICON,8,203,20,20,SS_CENTERIMAGE
+ LTEXT "You are visible to this person even when in invisible mode",IDC_STATIC,26,209,279,8,SS_NOPREFIX | SS_CENTERIMAGE
+ ICON IDI_INVISIBLE,IDC_INVISIBLEICON,8,218,20,20,SS_CENTERIMAGE
+ LTEXT "You are never visible to this person",IDC_STATIC,26,224,279,8,SS_NOPREFIX | SS_CENTERIMAGE
+END
+
+IDD_OPT_AWAYMSG DIALOGEX 0, 0, 263, 151
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Status Messages",IDC_STATIC,4,5,255,142
+ COMBOBOX IDC_STATUS,12,19,240,97,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ CONTROL "Do not reply to requests for this message",IDC_DONTREPLY,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,24,37,227,10
+ CONTROL "Do not pop up dialog asking for new message",IDC_NODIALOG,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,24,50,227,10
+ CONTROL "By default, use the same message as last time",IDC_USEPREVIOUS,
+ "Button",BS_AUTORADIOBUTTON,23,65,227,10
+ CONTROL "By default, use this message:",IDC_USESPECIFIC,"Button",BS_AUTORADIOBUTTON,23,78,227,10
+ EDITTEXT IDC_MSG,33,91,219,38,ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL
+ LTEXT "Use %time% for the current time, %date% for the current date",IDC_STATIC,33,131,219,8
+END
+
+IDD_ICONINDEX DIALOGEX 0, 0, 219, 197
+STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Icon Index"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ RTEXT "Icon library:",IDC_STATIC,4,6,54,8
+ EDITTEXT IDC_ICONSET,60,4,139,12,ES_AUTOHSCROLL
+ PUSHBUTTON "...",IDC_BROWSE,201,5,14,10
+ LTEXT "Drag icons to main list to assign them:",IDC_STATIC,4,18,211,8
+ CONTROL "List1",IDC_PREVIEW,"SysListView32",LVS_SINGLESEL | LVS_AUTOARRANGE | WS_BORDER | WS_TABSTOP,4,27,211,82
+ GROUPBOX "Import multiple",IDC_IMPORTMULTI,4,122,211,61
+ CONTROL "To main icons",IDC_TOMAIN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,132,74,12
+ CONTROL "To",IDC_TOPROTO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,165,25,12
+ COMBOBOX IDC_PROTOLIST,34,164,79,58,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "<< &Import",IDC_IMPORT,164,164,48,14,WS_DISABLED
+ CONTROL "Download more icons",IDC_GETMORE,"Hyperlink",WS_TABSTOP | 0x1,4,185,211,8
+ CONTROL "To default status icons",IDC_TODEFICON,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,148,123,12
+END
+
+IDD_OPT_NETLIB DIALOGEX 0, 0, 313, 235
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ COMBOBOX IDC_NETLIBUSERS,0,1,231,110,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "Logging...",IDC_LOGOPTIONS,241,1,60,13
+ GROUPBOX "Outgoing Connections",IDC_STATIC12,0,18,313,148
+ CONTROL "Use proxy server",IDC_USEPROXY,"Button",BS_3STATE | WS_TABSTOP,7,29,159,9
+ LTEXT "Type:",IDC_STATIC21,19,43,57,8,WS_DISABLED
+ COMBOBOX IDC_PROXYTYPE,80,40,86,62,CBS_DROPDOWNLIST | WS_DISABLED | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Host:",IDC_STATIC22,19,58,57,8,WS_DISABLED
+ EDITTEXT IDC_PROXYHOST,80,56,86,12,ES_AUTOHSCROLL | WS_DISABLED
+ LTEXT "Port:",IDC_STATIC23,177,58,35,8,WS_DISABLED
+ EDITTEXT IDC_PROXYPORT,213,56,35,12,ES_AUTOHSCROLL | ES_NUMBER | WS_DISABLED
+ LTEXT "(often %d)",IDC_STOFTENPORT,258,57,48,8,WS_DISABLED
+ CONTROL "Use Custom Login (Domain login picked up automatically)",IDC_PROXYAUTH,
+ "Button",BS_3STATE | WS_DISABLED | WS_TABSTOP,20,80,286,10
+ LTEXT "Username:",IDC_STATIC31,32,94,47,8,WS_DISABLED
+ EDITTEXT IDC_PROXYUSER,80,92,86,12,ES_AUTOHSCROLL | WS_DISABLED
+ LTEXT "Password:",IDC_STATIC32,177,94,49,8,WS_DISABLED
+ EDITTEXT IDC_PROXYPASS,232,92,74,12,ES_PASSWORD | ES_AUTOHSCROLL | WS_DISABLED
+ CONTROL "Resolve hostnames through proxy",IDC_PROXYDNS,"Button",BS_3STATE | WS_DISABLED | WS_TABSTOP,20,115,202,10
+ CONTROL "Port Range:",IDC_SPECIFYPORTSO,"Button",BS_3STATE | BS_TOP | BS_MULTILINE | WS_TABSTOP,7,130,72,9
+ EDITTEXT IDC_PORTSRANGEO,80,129,142,12,ES_AUTOHSCROLL | WS_DISABLED
+ LTEXT "Example: 1050-1070, 2000-2010, 2500",IDC_STATIC54,80,144,196,8,WS_DISABLED
+ CONTROL "Validate SSL certificates",IDC_VALIDATESSL,"Button",BS_3STATE | BS_TOP | BS_MULTILINE | WS_TABSTOP,7,154,299,9
+ GROUPBOX "Incoming Connections",IDC_STATIC43,0,167,313,52
+ CONTROL "Port Range:",IDC_SPECIFYPORTS,"Button",BS_3STATE | BS_TOP | BS_MULTILINE | WS_TABSTOP,7,179,72,9
+ EDITTEXT IDC_PORTSRANGE,80,178,142,12,ES_AUTOHSCROLL | WS_DISABLED
+ LTEXT "Example: 1050-1070, 2000-2010, 2500",IDC_STATIC52,80,193,196,8,WS_DISABLED
+ CONTROL "Enable UPnP port mapping",IDC_ENABLEUPNP,"Button",BS_3STATE | BS_TOP | BS_MULTILINE | WS_TABSTOP,7,204,299,9
+ CTEXT "You will need to reconnect for the changes you have made on this page to take effect.",IDC_RECONNECTREQD,4,224,307,8,NOT WS_VISIBLE
+END
+
+IDD_OPT_FILETRANSFER DIALOGEX 0, 0, 313, 232
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Receiving files",IDC_STATIC,0,0,313,90
+ LTEXT "Received files folder:",IDC_STATIC,8,15,82,8
+ EDITTEXT IDC_FILEDIR,92,13,190,12,ES_AUTOHSCROLL
+ PUSHBUTTON "...",IDC_FILEDIRBROWSE,287,14,15,11
+ LTEXT "Variables Allowed: %userid%, %nick%, %proto%, %miranda_path%, %userprofile%",IDC_STATIC,8,27,294,11,WS_DISABLED
+ CONTROL "Auto-accept incoming files from people on my contact list",IDC_AUTOACCEPT,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,39,294,10
+ CONTROL "Minimize the file transfer window",IDC_AUTOMIN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,17,52,285,10
+ CONTROL "Close window when transfer completes",IDC_AUTOCLOSE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,65,294,10
+ CONTROL "Clear completed transfers on window closing",IDC_AUTOCLEAR,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,76,294,10
+ GROUPBOX "Virus scanner",IDC_VIRUSSCANNERGROUP,0,90,313,93
+ LTEXT "Scan files:",IDC_STATIC,8,102,43,9,SS_CENTERIMAGE
+ CONTROL "Never, do not use virus scanning",IDC_NOSCANNER,"Button",BS_AUTORADIOBUTTON,52,102,250,10
+ CONTROL "When all files have been downloaded",IDC_SCANAFTERDL,
+ "Button",BS_AUTORADIOBUTTON,52,114,250,10
+ CONTROL "As each file finishes downloading",IDC_SCANDURINGDL,
+ "Button",BS_AUTORADIOBUTTON,52,126,250,10
+ LTEXT "Command line:",IDC_ST_CMDLINE,7,142,62,8
+ COMBOBOX IDC_SCANCMDLINE,70,141,213,71,CBS_DROPDOWN | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "...",IDC_SCANCMDLINEBROWSE,287,142,15,11
+ LTEXT "%f will be replaced by the file or folder name to be scanned",IDC_ST_CMDLINEHELP,70,155,232,8
+ CONTROL "Warn me before opening a file that has not been scanned",IDC_WARNBEFOREOPENING,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,168,294,10
+ GROUPBOX "If incoming files already exist",IDC_STATIC,0,187,313,41
+ CONTROL "Ask me",IDC_ASK,"Button",BS_AUTORADIOBUTTON,8,200,73,10
+ CONTROL "Resume",IDC_RESUME,"Button",BS_AUTORADIOBUTTON,82,200,125,10
+ CONTROL "Overwrite",IDC_OVERWRITE,"Button",BS_AUTORADIOBUTTON,8,212,73,10
+ CONTROL "Rename (append "" (1)"", etc.)",IDC_RENAME,"Button",BS_AUTORADIOBUTTON,82,212,125,10
+ LTEXT "You will always be asked about files from people not on your contact list",IDC_STATIC,212,198,90,24
+END
+
+IDD_OPT_IDLE DIALOGEX 0, 0, 312, 190
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_BORDER
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "Become idle if the following is left unattended:",IDC_IDLESHORT,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,25,18,259,9
+ CONTROL "Windows",IDC_IDLEONWINDOWS,"Button",BS_AUTORADIOBUTTON,45,31,104,9
+ CONTROL "Miranda",IDC_IDLEONMIRANDA,"Button",BS_AUTORADIOBUTTON,45,43,103,9
+ EDITTEXT IDC_IDLE1STTIME,59,59,27,14,ES_AUTOHSCROLL | ES_NUMBER
+ CONTROL "Spin2",IDC_IDLESPIN,"msctls_updown32",UDS_WRAP | UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_HOTTRACK,71,55,12,23
+ CONTROL "Become idle if the screen saver is active",IDC_SCREENSAVER,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,25,83,265,9
+ CONTROL "Become idle if the computer is locked (2000/XP+ only)",IDC_LOCKED,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,25,105,265,9
+ CONTROL "Become idle if a terminal session is disconnected",IDC_IDLETERMINAL,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,25,116,265,10
+ CONTROL "Do not let protocols report any idle information",IDC_IDLEPRIVATE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,25,131,251,9
+ LTEXT "minute(s)",IDC_STATIC,91,61,76,9
+ RTEXT "for",IDC_STATIC,12,59,41,9
+ COMBOBOX IDC_AASTATUS,161,146,64,50,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ CONTROL "Change my status mode to:",IDC_AASHORTIDLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,25,147,132,11
+ CONTROL "Do not set status back to online when returning from idle",IDC_IDLESTATUSLOCK,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,35,164,254,10
+ GROUPBOX "Idle Options",IDC_STATIC,3,3,304,182
+ CONTROL "Become idle if application full screen",IDC_FULLSCREEN,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,25,94,265,9
+END
+
+IDD_PROFILE_SELECTION DIALOGEX 0, 0, 386, 142
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "List1",IDC_PROFILELIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_TABSTOP,3,2,382,137
+END
+
+IDD_PROFILE_NEW DIALOGEX 0, 0, 386, 142
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Please complete the following form to create a new user profile",IDC_STATIC,7,7,231,16
+ EDITTEXT IDC_PROFILENAME,67,27,75,12,ES_AUTOHSCROLL
+ COMBOBOX IDC_PROFILEDRIVERS,67,72,75,56,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Profile",IDC_STATIC,20,28,40,9
+ LTEXT "e.g. Workplace",IDC_STATIC,161,28,77,11
+ LTEXT "You can select a different profile driver from the default, it may offer more features or abilities, if in doubt use the default.",IDC_STATIC,7,49,231,17
+ LTEXT "e.g. Miranda Database",IDC_STATIC,154,73,84,11
+ LTEXT "Driver",IDC_STATIC,20,74,43,9
+ LTEXT "Problem: Unable to find any database drivers, this means you can not create a new profile, you need to get dbx_3x.dll",IDC_NODBDRIVERS,7,113,231,22,NOT WS_VISIBLE
+END
+
+IDD_OPT_PLUGINS DIALOGEX 0, 0, 315, 252
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "List1",IDC_PLUGLIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_AUTOARRANGE | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,4,4,306,110
+ CONTROL "Download more plugins",IDC_GETMOREPLUGINS,"Hyperlink",WS_TABSTOP,4,116,306,8
+ GROUPBOX "",IDC_PLUGININFOFRAME,4,125,307,125,BS_RIGHT
+ EDITTEXT IDC_PLUGINLONGINFO,50,136,253,25,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | ES_WANTRETURN | NOT WS_BORDER
+ EDITTEXT IDC_PLUGINAUTHOR,50,165,253,18,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | ES_WANTRETURN | NOT WS_BORDER
+ CONTROL "",IDC_PLUGINEMAIL,"Hyperlink",WS_TABSTOP,50,188,208,10
+ CONTROL "",IDC_PLUGINURL,"Hyperlink",WS_TABSTOP,50,201,254,10
+ EDITTEXT IDC_PLUGINPID,50,214,254,12,ES_READONLY | ES_WANTRETURN | NOT WS_BORDER
+ EDITTEXT IDC_PLUGINCPYR,50,227,254,12,ES_AUTOHSCROLL | ES_READONLY | ES_WANTRETURN | NOT WS_BORDER
+ RTEXT "Description:",IDC_STATIC,8,136,38,10
+ RTEXT "Author(s):",IDC_STATIC,8,165,38,10
+ RTEXT "E-mail:",IDC_STATIC,8,188,38,10
+ RTEXT "Homepage:",IDC_STATIC,10,200,38,9
+ RTEXT "Unique ID:",IDC_STATIC,7,214,38,10
+ RTEXT "Copyright:",IDC_STATIC,8,227,38,10
+ CTEXT "Please restart Miranda IM for your changes to take effect.",IDC_RESTART,14,240,288,8,NOT WS_VISIBLE
+END
+
+IDD_OPT_FONTS DIALOGEX 0, 0, 316, 251
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Fonts and Colors",IDC_STATIC,0,0,315,250
+ CONTROL "Tree1",IDC_FONTGROUP,"SysTreeView32",TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT | TVS_SHOWSELALWAYS | TVS_FULLROWSELECT | WS_BORDER | WS_TABSTOP,4,10,102,235
+ LISTBOX IDC_FONTLIST,109,10,201,186,LBS_OWNERDRAWVARIABLE | LBS_NOINTEGRALHEIGHT | LBS_EXTENDEDSEL | WS_VSCROLL | WS_TABSTOP
+ CONTROL "",IDC_BKGCOLOUR,"ColourPicker",WS_TABSTOP,196,199,30,14
+ CONTROL "...",IDC_EFFECT,"MButtonClass",NOT WS_VISIBLE | WS_TABSTOP,196,199,30,14
+ CONTROL "",IDC_FONTCOLOUR,"ColourPicker",WS_TABSTOP,196,215,30,14
+ CONTROL "...",IDC_CHOOSEFONT,"MButtonClass",WS_TABSTOP,196,231,30,14
+ PUSHBUTTON "Undo",IDC_BTN_UNDO,109,199,73,14
+ PUSHBUTTON "Reset",IDC_BTN_RESET,109,215,73,14
+ PUSHBUTTON "Export...",IDC_BTN_EXPORT,109,231,73,14
+ LTEXT "Color/Background",IDC_BKGCOLOUR_STATIC,231,199,79,14,SS_CENTERIMAGE
+ LTEXT "Text Effect",IDC_EFFECT_STATIC,231,199,79,14,SS_CENTERIMAGE | NOT WS_VISIBLE
+ LTEXT "Text Color",IDC_STATIC,231,215,79,14,SS_CENTERIMAGE
+ LTEXT "Choose Font",IDC_STATIC,231,231,79,14,SS_CENTERIMAGE
+END
+
+IDD_CUSTOM_FONT DIALOGEX 13, 54, 287, 196
+STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CONTEXTHELP | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Font"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "&Font:",1088,7,7,40,9
+ COMBOBOX 1136,7,16,98,76,CBS_SIMPLE | CBS_OWNERDRAWFIXED | CBS_AUTOHSCROLL | CBS_SORT | CBS_HASSTRINGS | CBS_DISABLENOSCROLL | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Font st&yle:",1089,110,7,44,9
+ COMBOBOX 1137,110,16,74,76,CBS_SIMPLE | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP
+ LTEXT "\nStyles and effects are disabled for this font.",1095,110,16,74,76
+ LTEXT "&Size:",1090,189,7,30,9
+ COMBOBOX 1138,190,16,36,76,CBS_SIMPLE | CBS_OWNERDRAWFIXED | CBS_AUTOHSCROLL | CBS_SORT | CBS_HASSTRINGS | CBS_DISABLENOSCROLL | WS_VSCROLL | WS_TABSTOP
+ GROUPBOX "Effects",1072,7,97,98,72,WS_GROUP
+ CONTROL "Stri&keout",1040,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,110,49,10
+ CONTROL "&Underline",1041,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,123,51,10
+ LTEXT "&Color:",1091,13,136,30,9,NOT WS_VISIBLE
+ COMBOBOX 1139,13,146,82,100,CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | CBS_AUTOHSCROLL | CBS_HASSTRINGS | NOT WS_VISIBLE | WS_BORDER | WS_VSCROLL | WS_TABSTOP
+ GROUPBOX "Sample",1073,110,97,116,43,WS_GROUP
+ CTEXT "AaBbYyZz",1092,118,111,100,23,SS_NOPREFIX | NOT WS_VISIBLE
+ LTEXT "",1093,7,172,219,20,SS_NOPREFIX | NOT WS_GROUP
+ LTEXT "Sc&ript:",1094,110,147,30,9
+ COMBOBOX 1140,110,157,116,30,CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | CBS_AUTOHSCROLL | CBS_HASSTRINGS | WS_BORDER | WS_VSCROLL | WS_TABSTOP
+ DEFPUSHBUTTON "OK",IDOK,231,16,45,14,WS_GROUP
+ PUSHBUTTON "Cancel",IDCANCEL,231,32,45,14,WS_GROUP
+ PUSHBUTTON "&Apply",1026,231,48,45,14,WS_GROUP
+ PUSHBUTTON "&Help",1038,231,64,45,14,WS_GROUP
+END
+
+IDD_OPT_ICOLIB DIALOGEX 0, 0, 316, 251
+STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Icons",IDC_STICONSGROUP,0,0,315,250
+ CONTROL "List1",IDC_PREVIEW,"SysListView32",LVS_AUTOARRANGE | WS_BORDER | WS_TABSTOP,109,10,201,207
+ PUSHBUTTON "&Load icon set...",IDC_LOADICONS,116,220,94,13
+ PUSHBUTTON "&Import icons >>",IDC_IMPORT,215,220,89,13
+ CONTROL "Download more icons",IDC_GETMORE,"Hyperlink",WS_TABSTOP | 0x1,109,237,201,8
+ CONTROL "Tree1",IDC_CATEGORYLIST,"SysTreeView32",TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT | TVS_SHOWSELALWAYS | TVS_FULLROWSELECT | TVS_NOHSCROLL | WS_BORDER | WS_TABSTOP,4,10,102,235
+END
+
+IDD_ICOLIB_IMPORT DIALOGEX 0, 0, 217, 194
+STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+EXSTYLE WS_EX_TOOLWINDOW | WS_EX_CONTROLPARENT
+CAPTION "Icon Index"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ RTEXT "Icon library:",IDC_STATIC,5,6,44,8
+ EDITTEXT IDC_ICONSET,53,4,127,12,ES_AUTOHSCROLL
+ PUSHBUTTON "...",IDC_BROWSE,186,5,14,10
+ LTEXT "Drag icons to main list to assign them:",IDC_STATIC,4,18,207,8
+ CONTROL "List1",IDC_PREVIEW,"SysListView32",LVS_SINGLESEL | LVS_AUTOARRANGE | WS_BORDER | WS_TABSTOP,4,27,208,163
+END
+
+IDD_OPT_GENMENU DIALOGEX 0, 0, 316, 254
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Menu Objects",IDC_STATIC,5,2,140,99
+ CONTROL "Tree2",IDC_MENUOBJECTS,"SysTreeView32",TVS_SHOWSELALWAYS | WS_BORDER | WS_HSCROLL | WS_TABSTOP,11,13,128,82
+ GROUPBOX "Menu Items",IDC_STATIC,149,2,161,248
+ CONTROL "Tree1",IDC_MENUITEMS,"SysTreeView32",TVS_SHOWSELALWAYS | WS_DISABLED | WS_BORDER | WS_HSCROLL | WS_TABSTOP,156,13,148,212
+ GROUPBOX "Protocol menus",IDC_STATIC,5,100,140,37
+ CONTROL "Move to the main menu",IDC_RADIO1,"Button",BS_AUTORADIOBUTTON,11,111,128,8
+ CONTROL "Move to the status bar",IDC_RADIO2,"Button",BS_AUTORADIOBUTTON,11,123,130,8
+ LTEXT "Warning!\r\nThis MenuObject not support user defined options.",IDC_NOTSUPPORTWARNING,10,140,136,32,NOT WS_VISIBLE
+ PUSHBUTTON "Insert separator",IDC_INSERTSEPARATOR,39,180,97,14,WS_DISABLED
+ LTEXT "Service:",IDC_STATIC,4,201,29,8
+ EDITTEXT IDC_GENMENU_SERVICE,36,199,108,14,ES_AUTOHSCROLL | ES_READONLY
+ LTEXT "Name:",IDC_STATIC,4,218,29,8
+ EDITTEXT IDC_GENMENU_CUSTOMNAME,36,215,108,14,ES_AUTOHSCROLL | WS_DISABLED
+ PUSHBUTTON "Default",IDC_GENMENU_DEFAULT,18,234,55,15,WS_DISABLED
+ PUSHBUTTON "Set",IDC_GENMENU_SET,78,234,55,15,WS_DISABLED
+ CONTROL "Disable icons",IDC_DISABLEMENUICONS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,156,234,91,10
+ PUSHBUTTON "Reset",IDC_RESETMENU,254,230,50,14
+END
+
+IDD_OPT_PROTOCOLORDER DIALOGEX 0, 0, 300, 211
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CTEXT "Note: Miranda IM will have to be restarted for changes to take effect.",IDC_PROTOCOLORDERWARNING,5,190,289,14,NOT WS_VISIBLE
+ GROUPBOX "Account Order && Visibility",IDC_STATIC,75,0,147,185
+ CONTROL "Tree1",IDC_PROTOCOLORDER,"SysTreeView32",TVS_NOTOOLTIPS | WS_BORDER | WS_TABSTOP,85,40,132,95
+ LTEXT "Show protocols in the following order, drag to choose another order:",IDC_STATIC,85,15,132,20
+ PUSHBUTTON "Reset",IDC_RESETPROTOCOLDATA,120,140,50,14,BS_NOTIFY
+END
+
+IDD_UPDATE_NOTIFY DIALOGEX 0, 0, 259, 103
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Miranda IM v%s Now Available"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "A new version of Miranda IM is now available. Click the download button to download this new update.",IDC_MESSAGE,7,7,245,21
+ LTEXT "Latest Version:",IDC_NEWVERSIONLABEL,7,47,65,8
+ LTEXT "Your Version:",IDC_STATIC,7,32,65,8
+ LTEXT "",IDC_CURRENTVERSION,77,32,97,8
+ CONTROL "",IDC_VERSION,"Hyperlink",WS_TABSTOP,77,47,97,8
+ LTEXT "",IDC_UPDATE,77,47,97,8
+ PUSHBUTTON "&Download Now",IDC_DOWNLOAD,7,61,66,15
+ DEFPUSHBUTTON "&Close",IDOK,202,84,50,15
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,7,80,245,1
+END
+
+IDD_OPT_UPDATENOTIFY DIALOGEX 0, 0, 268, 94
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Update Notification Options",IDC_STATIC,2,0,265,94
+ CONTROL "Automatically check for new versions of Miranda IM",IDC_ENABLEUPDATES,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,11,13,237,10
+ LTEXT "Check for updates for the following:",IDC_STATIC,12,32,230,8
+ CONTROL "Stable releases",IDC_ENABLESTABLE,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,25,46,230,10
+ CONTROL "Preview releases (beta)",IDC_ENABLEBETA,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,25,61,230,10
+ CONTROL "Development releases (alpha)",IDC_ENABLEALPHA,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,25,76,230,10
+END
+
+IDD_OPT_KEYBINDINGS DIALOGEX 0, 0, 316, 251
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Key Bindings",IDC_STATIC,0,0,315,250
+ CONTROL "Tree1",IDC_CATEGORYLIST,"SysTreeView32",TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT | TVS_SHOWSELALWAYS | TVS_FULLROWSELECT | WS_BORDER | WS_TABSTOP,4,10,102,235
+ LTEXT "Shortcut:",IDC_STATIC,109,10,146,12
+ EDITTEXT IDC_PREVIEW,109,21,146,12
+ CONTROL "Add",IDC_ADD,"MButtonClass",WS_TABSTOP,260,19,50,14
+ LTEXT "",IDC_MESSAGE,109,37,201,41
+ LISTBOX IDC_LIST,109,80,146,52,WS_VSCROLL | WS_TABSTOP
+ CONTROL "Remove",IDC_DELETE,"MButtonClass",WS_TABSTOP,260,80,50,14
+ PUSHBUTTON "Undo Changes",IDC_BTN_UNDO,109,140,96,14
+ PUSHBUTTON "Reset To Default",IDC_BTN_RESET,214,140,96,14
+END
+
+IDD_OPT_HOTKEYS DIALOGEX 0, 0, 316, 251
+STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Hotkeys",IDC_STICONSGROUP,0,0,315,250
+ CONTROL "List1",IDC_LV_HOTKEYS,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_AUTOARRANGE | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,4,10,306,202
+ EDITTEXT IDC_HOTKEY,192,205,118,14,ES_CENTER | ES_AUTOHSCROLL | NOT WS_VISIBLE
+ CONTROL "",IDC_CANVAS,"Static",SS_OWNERDRAW,4,217,306,14,WS_EX_TRANSPARENT
+ CONTROL "",IDC_CANVAS2,"Static",SS_OWNERDRAW,4,231,306,14,WS_EX_TRANSPARENT
+END
+
+IDD_ACCMGR DIALOGEX 0, 0, 350, 245
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Accounts"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "Accounts\nConfigure your IM accounts",IDC_HEADERBAR,
+ "MHeaderbarCtrl",0x0,0,0,350,25
+ LISTBOX IDC_ACCLIST,7,32,130,187,LBS_SORT | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Account information:",IDC_TXT_ACCOUNT,142,32,201,8
+ LTEXT "Welcome to Miranda IM's account manager!\nHere you can set up your IM accounts.\n\nSelect 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.",IDC_TXT_INFO,157,45,186,134
+ LTEXT "Additional:",IDC_TXT_ADDITIONAL,142,184,201,8
+ CONTROL "Configure network...",IDC_LNK_NETWORK,"Hyperlink",WS_TABSTOP,157,197,186,11
+ CONTROL "Get more protocols...",IDC_LNK_ADDONS,"Hyperlink",WS_TABSTOP,157,208,186,11
+ CONTROL "&Add...",IDC_ADD,"MButtonClass",WS_TABSTOP,7,224,16,14,WS_EX_NOACTIVATE | 0x10000000L
+ CONTROL "&Edit",IDC_EDIT,"MButtonClass",WS_TABSTOP,26,224,16,14,WS_EX_NOACTIVATE | 0x10000000L
+ CONTROL "&Options",IDC_OPTIONS,"MButtonClass",WS_TABSTOP,45,224,16,14,WS_EX_NOACTIVATE | 0x10000000L
+ CONTROL "&Upgrade",IDC_UPGRADE,"MButtonClass",WS_TABSTOP,64,224,16,14,WS_EX_NOACTIVATE | 0x10000000L
+ CONTROL "&Remove...",IDC_REMOVE,"MButtonClass",WS_TABSTOP,83,224,16,14,WS_EX_NOACTIVATE | 0x10000000L
+ DEFPUSHBUTTON "OK",IDOK,239,224,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,293,224,50,14
+END
+
+IDD_WAITRESTART DIALOGEX 0, 0, 167, 70
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION
+EXSTYLE WS_EX_TOOLWINDOW
+CAPTION "Miranda IM"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "Miranda IM is being restarted.\nPlease wait...",IDC_STATIC,7,7,153,18
+ CONTROL "",IDC_PROGRESSBAR,"msctls_progress32",WS_BORDER,7,30,153,14
+ PUSHBUTTON "Close",IDCANCEL,110,49,50,14
+END
+
+IDD_FTMGR DIALOGEX 0, 0, 276, 255
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+CAPTION "File Transfers"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "",IDC_TABS,"SysTabControl32",0x0,7,7,262,224
+ PUSHBUTTON "Clear completed",IDC_CLEAR,7,234,100,14
+ PUSHBUTTON "Close",IDCANCEL,219,234,50,14
+END
+
+IDD_FTPAGE DIALOGEX 0, 0, 320, 183
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VSCROLL | WS_SYSMENU
+EXSTYLE WS_EX_CONTROLPARENT | WS_EX_STATICEDGE
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+END
+
+IDD_OPT_KEYWORDFILTER DIALOGEX 0, 0, 251, 73
+STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "Enable keyword search in options dialog",IDC_ENABLE_KEYWORDFILTERING,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,4,4,243,10
+ LTEXT "If this option is checked it allows you to search for option pages that contain the search string or plugin name.",IDC_STATIC,4,20,243,49,NOT WS_GROUP
+END
+
+IDD_ERROR_LIST DIALOGEX 0, 0, 312, 209
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Error Console"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LISTBOX IDC_LST_ERRORS,5,5,301,198,LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+END
+
+IDD_OPT_ERRORS DIALOGEX 0, 0, 316, 251
+STYLE DS_SETFONT | DS_3DLOOK | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ GROUPBOX "Error notifications",IDC_STATIC,0,0,315,250
+ CONTROL "",IDC_LV_ERRORS,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,4,10,306,235
+END
+
+IDD_MODERNOPT_FONTS DIALOGEX 0, 0, 260, 210
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ LTEXT "Headers:",IDC_TXT_TITLE1,0,0,259,8
+ PUSHBUTTON "...",IDC_CHOOSEFONTHEADER,244,30,16,14
+ LTEXT "This font is used to display main section titles or text elements.",IDC_STATIC,10,11,249,16,SS_CENTERIMAGE
+ LTEXT "Normal text:",IDC_TXT_TITLE2,0,55,259,8
+ PUSHBUTTON "...",IDC_CHOOSEFONTGENERAL,244,84,16,14
+ LTEXT "This font is used to display most text element or section bodies.",IDC_STATIC,10,66,249,16,SS_CENTERIMAGE
+ LTEXT "Minor notes:",IDC_TXT_TITLE3,0,109,259,8
+ PUSHBUTTON "...",IDC_CHOOSEFONTSMALL,244,139,16,14
+ LTEXT "This font is used to display various addtional notes.",IDC_STATIC,10,120,249,16,SS_CENTERIMAGE
+ CONTROL "",IDC_PREVIEWSMALL,"Static",SS_OWNERDRAW,10,139,229,15,WS_EX_STATICEDGE
+ CONTROL "",IDC_PREVIEWGENERAL,"Static",SS_OWNERDRAW,10,84,229,15,WS_EX_STATICEDGE
+ CONTROL "",IDC_PREVIEWHEADER,"Static",SS_OWNERDRAW,10,30,229,15,WS_EX_STATICEDGE
+END
+
+IDD_MODERNOPT_ACCOUNTS DIALOGEX 0, 0, 368, 210
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ LISTBOX IDC_ACCLIST,0,0,162,192,LBS_SORT | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Account information:",IDC_TXT_ACCOUNT,167,0,201,8
+ LTEXT "Welcome to Miranda IM's account manager!\nHere you can set up your IM accounts.\n\nSelect an account from the list on the left to see the available options. Alternatively, just click on the ""New"" button underneath the list to set up a new IM account.",IDC_TXT_INFO,182,13,186,134
+ CONTROL "&Add...",IDC_ADD,"MButtonClass",WS_TABSTOP,0,196,16,14,WS_EX_NOACTIVATE | 0x10000000L
+ CONTROL "&Edit",IDC_EDIT,"MButtonClass",WS_TABSTOP,22,196,16,14,WS_EX_NOACTIVATE | 0x10000000L
+ CONTROL "&Options",IDC_OPTIONS,"MButtonClass",WS_TABSTOP,38,196,16,14,WS_EX_NOACTIVATE | 0x10000000L
+ CONTROL "&Upgrade",IDC_UPGRADE,"MButtonClass",WS_TABSTOP,54,196,16,14,WS_EX_NOACTIVATE | 0x10000000L
+ CONTROL "&Remove...",IDC_REMOVE,"MButtonClass",WS_TABSTOP,76,196,16,14,WS_EX_NOACTIVATE | 0x10000000L
+ LTEXT "Additional:",IDC_TXT_ADDITIONAL,167,157,201,8
+ CONTROL "Configure network...",IDC_LNK_NETWORK,"Hyperlink",WS_TABSTOP,183,170,186,11
+ CONTROL "Get more protocols...",IDC_LNK_ADDONS,"Hyperlink",WS_TABSTOP,183,181,186,11
+END
+
+IDD_MODERNOPT_MODULES DIALOGEX 0, 0, 369, 210
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ EDITTEXT IDC_PLUGINLONGINFO,65,133,304,25,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | ES_WANTRETURN | NOT WS_BORDER
+ EDITTEXT IDC_PLUGINAUTHOR,65,160,304,12,ES_AUTOHSCROLL | ES_READONLY | ES_WANTRETURN | NOT WS_BORDER
+ CONTROL "",IDC_PLUGINEMAIL,"Hyperlink",WS_TABSTOP,65,172,304,10
+ CONTROL "",IDC_PLUGINURL,"Hyperlink",WS_TABSTOP,65,184,304,10
+ EDITTEXT IDC_PLUGINCPYR,65,197,304,12,ES_AUTOHSCROLL | ES_READONLY | ES_WANTRETURN | NOT WS_BORDER
+ RTEXT "Description:",IDC_TXT_TITLE1,-1,133,60,10
+ RTEXT "Author(s):",IDC_TXT_TITLE2,0,160,60,10
+ RTEXT "E-mail:",IDC_TXT_TITLE3,0,172,60,10
+ RTEXT "Homepage:",IDC_TXT_TITLE4,0,184,60,9
+ RTEXT "Copyright:",IDC_TXT_TITLE6,0,197,60,10
+ CONTROL "",IDC_PLUGLIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_AUTOARRANGE | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,0,0,369,128
+END
+
+IDD_MODERNOPT_STATUS DIALOGEX 0, 0, 369, 113
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ COMBOBOX IDC_STATUS,2,54,16,97,CBS_DROPDOWNLIST | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP
+ CONTROL "Do not reply to requests for this message",IDC_DONTREPLY,
+ "Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,0,33,10,10
+ CONTROL "Do not pop up dialog asking for new message",IDC_NODIALOG,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,105,93,264,10
+ CONTROL "By default, use the same message as last time",IDC_USEPREVIOUS,
+ "Button",BS_AUTORADIOBUTTON,105,13,227,10
+ CONTROL "By default, use this message:",IDC_USESPECIFIC,"Button",BS_AUTORADIOBUTTON,105,26,227,10
+ EDITTEXT IDC_MSG,125,39,244,38,ES_MULTILINE | ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL
+ CTEXT "Use %time% for the current time, %date% for the current date",IDC_STATIC,125,78,244,8,SS_CENTERIMAGE
+ LTEXT "Status messages:",IDC_TXT_TITLE1,0,0,246,8
+ LISTBOX IDC_LST_STATUS,10,13,90,95,LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+END
+
+IDD_MODERNOPT_IDLE DIALOGEX 0, 0, 369, 64
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ CONTROL "Become idle if computer is left unattended for:",IDC_IDLESHORT,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,13,171,9
+ CONTROL "Windows",IDC_IDLEONWINDOWS,"Button",BS_AUTORADIOBUTTON | NOT WS_VISIBLE,325,25,26,9
+ CONTROL "Miranda",IDC_IDLEONMIRANDA,"Button",BS_AUTORADIOBUTTON | NOT WS_VISIBLE,287,37,15,9
+ EDITTEXT IDC_IDLE1STTIME,181,11,27,12,ES_AUTOHSCROLL | ES_NUMBER
+ CONTROL "",IDC_IDLESPIN,"msctls_updown32",UDS_WRAP | UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_HOTTRACK,193,7,11,23
+ CONTROL "Become idle if the screen saver is active",IDC_SCREENSAVER,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,25,268,9
+ CONTROL "Become idle if the computer is locked (2000/XP+ only)",IDC_LOCKED,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,37,249,9
+ CONTROL "Become idle if a terminal session is disconnected",IDC_IDLETERMINAL,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,49,265,10
+ CONTROL "Do not let protocols report any idle information",IDC_IDLEPRIVATE,
+ "Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,303,13,22,9
+ LTEXT "minute(s)",IDC_STATIC,213,13,76,9,SS_CENTERIMAGE
+ COMBOBOX IDC_AASTATUS,325,46,23,50,CBS_DROPDOWNLIST | NOT WS_VISIBLE | WS_VSCROLL | WS_TABSTOP
+ CONTROL "Change my status mode to:",IDC_AASHORTIDLE,"Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,334,11,23,11
+ CONTROL "Do not set status back to online when returning from idle",IDC_IDLESTATUSLOCK,
+ "Button",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,299,24,16,10
+ LTEXT "Idle (auto-away):",IDC_TXT_TITLE1,0,0,246,8
+END
+
+IDD_MODERNOPT_IGNORE DIALOGEX 0, 0, 369, 210
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ CONTROL "",IDC_LIST,"CListControl",WS_TABSTOP | 0x3da,10,13,358,135,WS_EX_CLIENTEDGE
+ LTEXT "Event icon legend:",IDC_TXT_TITLE2,0,153,119,8
+ LTEXT "Choose events you wish to ingonre:",IDC_TXT_TITLE1,0,0,246,8
+ CONTROL "",IDC_LV_LEGEND,"SysListView32",LVS_LIST | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,10,166,358,43
+END
+
+IDD_CHOOSE_FONT_EFFECT DIALOGEX 13, 54, 226, 103
+STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CONTEXTHELP | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Font Effect"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Effect:",IDC_STATIC,12,12,66,12,SS_CENTERIMAGE
+ COMBOBOX IDC_EFFECT_COMBO,84,12,126,30,CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | WS_BORDER | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Base colour:",IDC_STATIC,12,30,66,12,SS_CENTERIMAGE
+ CONTROL "",IDC_EFFECT_COLOUR1,"ColourPicker",WS_TABSTOP,84,30,30,12
+ LTEXT "opacity:",IDC_STATIC,126,30,42,12,SS_CENTERIMAGE
+ EDITTEXT IDC_EFFECT_COLOUR_TEXT1,168,30,42,12,ES_NUMBER
+ CONTROL "",IDC_EFFECT_COLOUR_SPIN1,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_HOTTRACK,200,30,11,12
+ LTEXT "Secondary colour:",IDC_STATIC,12,48,66,12,SS_CENTERIMAGE
+ CONTROL "",IDC_EFFECT_COLOUR2,"ColourPicker",WS_TABSTOP,84,48,30,12
+ LTEXT "opacity:",IDC_STATIC,126,48,42,12,SS_CENTERIMAGE
+ EDITTEXT IDC_EFFECT_COLOUR_TEXT2,168,48,42,12,ES_NUMBER
+ CONTROL "",IDC_EFFECT_COLOUR_SPIN2,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_HOTTRACK,200,48,11,12
+ DEFPUSHBUTTON "OK",IDOK,114,78,45,14,WS_GROUP
+ PUSHBUTTON "Cancel",IDCANCEL,168,78,45,14,WS_GROUP
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_AUTHREQ, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 264
+ BOTTOMMARGIN, 190
+ END
+
+ IDD_ADDCONTACT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 223
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 144
+ END
+
+ IDD_ADDED, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 233
+ TOPMARGIN, 3
+ BOTTOMMARGIN, 65
+ END
+
+ IDD_ABOUT, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 207
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 126
+ END
+
+ IDD_DELETECONTACT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 286
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 88
+ END
+
+ IDD_OPT_CONTACT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 192
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 140
+ END
+
+ IDD_FINDADD, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 422
+ VERTGUIDE, 11
+ VERTGUIDE, 42
+ VERTGUIDE, 53
+ VERTGUIDE, 116
+ VERTGUIDE, 122
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 252
+ END
+
+ IDD_OPTIONS, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 424
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 297
+ END
+
+ IDD_OPTIONSPAGE, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 297
+ END
+
+ IDD_READAWAYMSG, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 182
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 67
+ END
+
+ IDD_SETAWAYMSG, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 182
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 67
+ END
+
+ IDD_DETAILS, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 233
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 205
+ END
+
+ IDD_INFO_SUMMARY, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 217
+ VERTGUIDE, 51
+ VERTGUIDE, 126
+ VERTGUIDE, 170
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 127
+ HORZGUIDE, 22
+ HORZGUIDE, 35
+ HORZGUIDE, 48
+ HORZGUIDE, 62
+ END
+
+ IDD_INFO_CONTACT, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 217
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 127
+ END
+
+ IDD_INFO_BACKGROUND, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 217
+ VERTGUIDE, 49
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 127
+ END
+
+ IDD_INFO_NOTES, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 217
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 127
+ END
+
+ IDD_INFO_LOCATION, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 217
+ VERTGUIDE, 56
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 142
+ HORZGUIDE, 22
+ HORZGUIDE, 33
+ HORZGUIDE, 45
+ HORZGUIDE, 56
+ HORZGUIDE, 70
+ HORZGUIDE, 95
+ HORZGUIDE, 106
+ END
+
+ IDD_INFO_WORK, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 217
+ VERTGUIDE, 56
+ VERTGUIDE, 126
+ VERTGUIDE, 170
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 127
+ HORZGUIDE, 16
+ HORZGUIDE, 27
+ HORZGUIDE, 44
+ HORZGUIDE, 61
+ HORZGUIDE, 72
+ HORZGUIDE, 83
+ HORZGUIDE, 94
+ HORZGUIDE, 105
+ END
+
+ IDD_ADDEMAIL, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 182
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 37
+ END
+
+ IDD_ADDPHONE, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 205
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 86
+ END
+
+ IDD_INSTALLINI, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 208
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 98
+ END
+
+ IDD_WARNINICHANGE, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 182
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 108
+ END
+
+ IDD_INIIMPORTDONE, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 181
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 68
+ END
+
+ IDD_NETLIBLOGOPTS, DIALOG
+ BEGIN
+ LEFTMARGIN, 6
+ RIGHTMARGIN, 308
+ VERTGUIDE, 14
+ VERTGUIDE, 174
+ VERTGUIDE, 308
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 255
+ END
+
+ IDD_HISTORY_FIND, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 223
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 39
+ HORZGUIDE, 17
+ END
+
+ IDD_FILESEND, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 251
+ VERTGUIDE, 7
+ VERTGUIDE, 249
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 172
+ END
+
+ IDD_FILERECV, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 249
+ VERTGUIDE, 7
+ VERTGUIDE, 249
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 169
+ END
+
+ IDD_FILETRANSFERINFO, DIALOG
+ BEGIN
+ VERTGUIDE, 5
+ VERTGUIDE, 25
+ VERTGUIDE, 36
+ VERTGUIDE, 120
+ VERTGUIDE, 180
+ VERTGUIDE, 215
+ VERTGUIDE, 218
+ VERTGUIDE, 235
+ VERTGUIDE, 251
+ BOTTOMMARGIN, 43
+ HORZGUIDE, 14
+ HORZGUIDE, 28
+ HORZGUIDE, 42
+ END
+
+ IDD_FILEEXISTS, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 283
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 176
+ END
+
+ IDD_URLSEND, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 210
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 121
+ END
+
+ IDD_URLRECV, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 210
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 135
+ END
+
+ IDD_HISTORY, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 289
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 158
+ END
+
+ IDD_OPT_SOUND, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 281
+ VERTGUIDE, 12
+ VERTGUIDE, 273
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 236
+ END
+
+ IDD_OPT_ICONS, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 253
+ VERTGUIDE, 12
+ VERTGUIDE, 200
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 189
+ END
+
+ IDD_OPT_IGNORE, DIALOG
+ BEGIN
+ VERTGUIDE, 8
+ VERTGUIDE, 96
+ VERTGUIDE, 221
+ VERTGUIDE, 305
+ END
+
+ IDD_OPT_VISIBILITY, DIALOG
+ BEGIN
+ VERTGUIDE, 8
+ VERTGUIDE, 305
+ END
+
+ IDD_OPT_AWAYMSG, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 259
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 147
+ END
+
+ IDD_ICONINDEX, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 215
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 193
+ END
+
+ IDD_OPT_NETLIB, DIALOG
+ BEGIN
+ VERTGUIDE, 7
+ VERTGUIDE, 20
+ VERTGUIDE, 80
+ VERTGUIDE, 166
+ VERTGUIDE, 177
+ VERTGUIDE, 306
+ HORZGUIDE, 80
+ HORZGUIDE, 113
+ END
+
+ IDD_OPT_FILETRANSFER, DIALOG
+ BEGIN
+ VERTGUIDE, 8
+ VERTGUIDE, 302
+ END
+
+ IDD_PROFILE_NEW, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ TOPMARGIN, 7
+ END
+
+ IDD_OPT_PLUGINS, DIALOG
+ BEGIN
+ TOPMARGIN, 4
+ END
+
+ IDD_OPT_GENMENU, DIALOG
+ BEGIN
+ END
+
+ IDD_UPDATE_NOTIFY, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 179
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 83
+ END
+
+ IDD_OPT_UPDATENOTIFY, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 179
+ TOPMARGIN, 7
+ END
+
+ IDD_OPT_HOTKEYS, DIALOG
+ BEGIN
+ END
+
+ IDD_ACCMGR, DIALOG
+ BEGIN
+ VERTGUIDE, 7
+ VERTGUIDE, 23
+ VERTGUIDE, 28
+ VERTGUIDE, 44
+ VERTGUIDE, 60
+ VERTGUIDE, 76
+ VERTGUIDE, 81
+ VERTGUIDE, 137
+ VERTGUIDE, 142
+ VERTGUIDE, 157
+ VERTGUIDE, 343
+ BOTTOMMARGIN, 238
+ HORZGUIDE, 25
+ HORZGUIDE, 32
+ HORZGUIDE, 40
+ HORZGUIDE, 45
+ HORZGUIDE, 179
+ HORZGUIDE, 184
+ HORZGUIDE, 192
+ HORZGUIDE, 197
+ HORZGUIDE, 208
+ HORZGUIDE, 219
+ END
+
+ IDD_WAITRESTART, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 160
+ VERTGUIDE, 83
+ VERTGUIDE, 160
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 63
+ HORZGUIDE, 25
+ HORZGUIDE, 30
+ HORZGUIDE, 44
+ HORZGUIDE, 49
+ END
+
+ IDD_FTMGR, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 269
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 248
+ END
+
+ IDD_FTPAGE, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 303
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 176
+ END
+
+ IDD_OPT_KEYWORDFILTER, DIALOG
+ BEGIN
+ LEFTMARGIN, 4
+ RIGHTMARGIN, 247
+ TOPMARGIN, 4
+ BOTTOMMARGIN, 69
+ END
+
+ IDD_MODERNOPT_FONTS, DIALOG
+ BEGIN
+ VERTGUIDE, 10
+ VERTGUIDE, 239
+ VERTGUIDE, 244
+ HORZGUIDE, 30
+ HORZGUIDE, 45
+ HORZGUIDE, 84
+ HORZGUIDE, 99
+ HORZGUIDE, 139
+ HORZGUIDE, 154
+ END
+
+ IDD_MODERNOPT_ACCOUNTS, DIALOG
+ BEGIN
+ VERTGUIDE, 70
+ VERTGUIDE, 162
+ VERTGUIDE, 167
+ VERTGUIDE, 182
+ VERTGUIDE, 274
+ HORZGUIDE, 147
+ HORZGUIDE, 192
+ HORZGUIDE, 196
+ END
+
+ IDD_MODERNOPT_MODULES, DIALOG
+ BEGIN
+ RIGHTMARGIN, 260
+ VERTGUIDE, 60
+ VERTGUIDE, 65
+ END
+
+ IDD_MODERNOPT_STATUS, DIALOG
+ BEGIN
+ VERTGUIDE, 10
+ VERTGUIDE, 100
+ VERTGUIDE, 105
+ VERTGUIDE, 218
+ BOTTOMMARGIN, 103
+ HORZGUIDE, 8
+ HORZGUIDE, 13
+ END
+
+ IDD_MODERNOPT_IDLE, DIALOG
+ BEGIN
+ VERTGUIDE, 10
+ VERTGUIDE, 181
+ HORZGUIDE, 8
+ HORZGUIDE, 22
+ HORZGUIDE, 34
+ HORZGUIDE, 46
+ END
+
+ IDD_CHOOSE_FONT_EFFECT, DIALOG
+ BEGIN
+ HORZGUIDE, 18
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include <windows.h>\r\n"
+ "#include <winres.h>\r\n"
+ "#include ""../include/statusmodes.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_MIRANDA ICON "res/miranda_logo.ico"
+IDI_MIRANDAWEBSITE ICON "res/miranda_home.ico"
+IDI_DETAILSLOGO ICON "res/miranda_manager.ico"
+IDI_USERDETAILS ICON "res/contact_view_details.ico"
+IDI_ADDCONTACT ICON "res/contact_add.ico"
+IDI_RENAME ICON "res/contact_rename.ico"
+IDI_DELETE ICON "res/contact_delete.ico"
+IDI_GROUPSHUT ICON "res/group_closed.ico"
+IDI_GROUPOPEN ICON "res/group_opened.ico"
+IDI_USERONLINE ICON "res/status_user_online.ico"
+IDI_ONLINE ICON "res/status_online.ico"
+IDI_AWAY ICON "res/status_away.ico"
+IDI_NA ICON "res/status_NA.ico"
+IDI_OCCUPIED ICON "res/status_occupied.ico"
+IDI_DND ICON "res/status_DND.ico"
+IDI_FREE4CHAT ICON "res/status_free4chat.ico"
+IDI_INVISIBLE ICON "res/status_invisible.ico"
+IDI_ONTHEPHONE ICON "res/status_on_the_phone.ico"
+IDI_OUTTOLUNCH ICON "res/status_out2lunch.ico"
+IDI_OFFLINE ICON "res/status_offline.ico"
+IDI_LOAD ICON "res/icon_connecting.ico"
+IDI_TYPING ICON "res/icon_typing.ico"
+IDI_FINDUSER ICON "res/icon_find_user.ico"
+IDI_SEARCHALL ICON "res/icon_search_all.ico"
+IDI_OPTIONS ICON "res/icon_options.ico"
+IDI_ACCMGR ICON "res/icon_accmgr.ico"
+IDI_HELP ICON "res/icon_help.ico"
+IDI_RECVMSG ICON "res/icon_message.ico"
+IDI_FILE ICON "res/icon_file.ico"
+IDI_HISTORY ICON "res/icon_history.ico"
+IDI_URL ICON "res/icon_url.ico"
+IDI_SMS ICON "res/icon_sms.ico"
+IDI_SENDEMAIL ICON "res/icon_mail.ico"
+IDI_SMALLDOT ICON "res/icon_small_dot.ico"
+IDI_FILLEDBLOB ICON "res/icon_auth_request.ico"
+IDI_EMPTYBLOB ICON "res/icon_all.ico"
+IDI_DOWNARROW ICON "res/icon_down_arrow.ico"
+IDI_NOTICK ICON "res/check_off.ico"
+IDI_TICK ICON "res/check_on.ico"
+IDI_UNICODE ICON "res/icon_unicode.ico"
+IDI_ANSI ICON "res/icon_ansi.ico"
+IDI_LOADED ICON "res/icon_loaded.ico"
+IDI_NOTLOADED ICON "res/icon_notloaded.ico"
+IDI_BLANK ICON "res/_blank.ico"
+IDI_UNDO ICON "res/icon_undo.ico"
+IDI_WINDOW ICON "res/icon_window.ico"
+IDI_WINDOWS ICON "res/icon_windows.ico"
+IDI_JOINCHAT ICON "res/chat_join.ico"
+IDI_LEAVECHAT ICON "res/chat_leave.ico"
+IDI_STATUS_LOCKED ICON "res/status_locked.ico"
+IDI_SHOWHIDE ICON "res/Icon_show_hide.ico"
+IDI_EXIT ICON "res/Icon_exit.ico"
+IDI_MOVETOGROUP ICON "res/contact_groups.ico"
+IDI_ON ICON "res\\On.ico"
+IDI_OFF ICON "res\\Off.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Cursor
+//
+
+IDC_HYPERLINKHAND CURSOR "res/cursor_hyperlink.cur"
+IDC_DROP CURSOR "res/cursor_drag_copy.cur"
+IDC_DROPUSER CURSOR "res/cursor_drop_user.cur"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_CLISTMENU MENU
+BEGIN
+ MENUITEM SEPARATOR
+END
+
+IDR_CONTEXT MENU
+BEGIN
+ POPUP "Tray"
+ BEGIN
+ MENUITEM "&Hide/Show", ID_TRAY_HIDE
+ MENUITEM SEPARATOR
+ MENUITEM "E&xit", ID_TRAY_EXIT
+ END
+ POPUP "Nowhere"
+ BEGIN
+ MENUITEM "&New Group", POPUP_NEWGROUP
+ MENUITEM SEPARATOR
+ MENUITEM "&Hide Offline Users", POPUP_HIDEOFFLINE
+ MENUITEM "Hide &Offline Users out here", POPUP_HIDEOFFLINEROOT
+ MENUITEM "Hide &Empty Groups", POPUP_HIDEEMPTYGROUPS
+ MENUITEM "Disable &Groups", POPUP_DISABLEGROUPS
+ MENUITEM SEPARATOR
+ MENUITEM "Hide Miranda", POPUP_HIDEMIRANDA
+ END
+ POPUP "Group"
+ BEGIN
+ MENUITEM "&New Subgroup", POPUP_NEWSUBGROUP
+ MENUITEM "&Hide Offline Users in here", POPUP_GROUPHIDEOFFLINE
+ MENUITEM SEPARATOR
+ MENUITEM "&Rename Group", POPUP_RENAMEGROUP
+ MENUITEM "&Delete Group", POPUP_DELETEGROUP
+ END
+ POPUP "IconOptions"
+ BEGIN
+ MENUITEM "&Reset to default", ID_RESET
+ END
+ POPUP "find/add"
+ BEGIN
+ MENUITEM "&Add to List", IDC_ADD
+ MENUITEM SEPARATOR
+ MENUITEM "User &Details", IDC_DETAILS
+ MENUITEM "Send &Message", IDC_SENDMESSAGE
+ END
+ POPUP "Log"
+ BEGIN
+ MENUITEM "&Copy", IDM_COPY
+ MENUITEM "Co&py All", IDM_COPYALL
+ MENUITEM "Select &All", IDM_SELECTALL
+ MENUITEM SEPARATOR
+ MENUITEM "C&lear Log", IDM_CLEAR
+ END
+ POPUP "LogLink"
+ BEGIN
+ MENUITEM "Open in &new window", IDM_OPENNEW
+ MENUITEM "&Open in existing window", IDM_OPENEXISTING
+ MENUITEM "&Copy link", IDM_COPYLINK
+ END
+END
+
+IDR_ICOLIB_CONTEXT MENU
+BEGIN
+ POPUP "IconOptions"
+ BEGIN
+ MENUITEM "Cancel Change", ID_CANCELCHANGE
+ MENUITEM "&Reset To Default", ID_RESET
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXT
+//
+
+IDR_CREDITS TEXT "../docs/contributors.txt"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_SORTCOLUP BITMAP "res/arrow_sort_column_up.bmp"
+IDB_SORTCOLDOWN BITMAP "res/arrow_sort_column_down.bmp"
+#endif // English (United States) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/src/vc6.rc b/src/vc6.rc
new file mode 100644
index 0000000000..32c367505e
--- /dev/null
+++ b/src/vc6.rc
@@ -0,0 +1,3 @@
+#include "resource.rc"
+#include "version.rc"
+#include "manifest.rc"
diff --git a/src/version.rc b/src/version.rc
new file mode 100644
index 0000000000..7378cb04b4
--- /dev/null
+++ b/src/version.rc
@@ -0,0 +1,50 @@
+#include <windows.h>
+#include <winres.h>
+
+#include "../include/m_version.h"
+
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION MIRANDA_VERSION_FILEVERSION
+ PRODUCTVERSION MIRANDA_VERSION_FILEVERSION
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "000004b0"
+ BEGIN
+ VALUE "Comments", "Licensed under the terms of the GNU General Public License\0"
+ VALUE "CompanyName", " \0"
+ VALUE "FileDescription", "Miranda IM\0"
+ VALUE "FileVersion", MIRANDA_VERSION_DISPLAY
+ VALUE "InternalName", "miranda32\0"
+ VALUE "LegalCopyright", "Copyright © 2000-2010 Miranda IM Project. This software is released under the terms of the GNU General Public License.\0"
+ VALUE "LegalTrademarks", "\0"
+ VALUE "OriginalFilename", "miranda32.exe\0"
+ VALUE "PrivateBuild", "\0"
+ VALUE "ProductName", "Miranda IM\0"
+ VALUE "ProductVersion", MIRANDA_VERSION_DISPLAY
+ VALUE "SpecialBuild", "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0, 1200
+ END
+END
+
+#endif // !_MAC
+