From f920ef497f3299ae24fe783ce03bdd93b419f764 Mon Sep 17 00:00:00 2001 From: Kirill Volinsky Date: Fri, 18 May 2012 22:02:50 +0000 Subject: plugins folders renaming git-svn-id: http://svn.miranda-ng.org/main/trunk@60 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/MetaContacts/IcoLib.h | 37 + .../metacontacts_template.txt | 205 ++ plugins/MetaContacts/MetaContacts.rc | 335 ++++ plugins/MetaContacts/MetaContacts_10.sln | 26 + plugins/MetaContacts/MetaContacts_10.vcxproj | 274 +++ .../MetaContacts/MetaContacts_10.vcxproj.filters | 100 + plugins/MetaContacts/addto.c | 301 +++ plugins/MetaContacts/edit.c | 585 ++++++ plugins/MetaContacts/icons.c | 101 + plugins/MetaContacts/icons.h | 6 + plugins/MetaContacts/mcmenu.ico | Bin 0 -> 2550 bytes plugins/MetaContacts/mcmenuof.ico | Bin 0 -> 2550 bytes plugins/MetaContacts/mcmenuoff2.ico | Bin 0 -> 2550 bytes plugins/MetaContacts/meta_add.ico | Bin 0 -> 2550 bytes plugins/MetaContacts/meta_api.c | 245 +++ plugins/MetaContacts/meta_convert.ico | Bin 0 -> 2550 bytes plugins/MetaContacts/meta_edit.ico | Bin 0 -> 2550 bytes plugins/MetaContacts/meta_main.c | 270 +++ plugins/MetaContacts/meta_menu.c | 562 ++++++ plugins/MetaContacts/meta_options.c | 640 ++++++ plugins/MetaContacts/meta_remove2.ico | Bin 0 -> 2550 bytes plugins/MetaContacts/meta_services.c | 2106 ++++++++++++++++++++ plugins/MetaContacts/meta_set_as_default.ico | Bin 0 -> 2550 bytes plugins/MetaContacts/meta_utils.c | 1717 ++++++++++++++++ plugins/MetaContacts/metacontacts.h | 269 +++ plugins/MetaContacts/resource.h | 76 + plugins/MetaContacts/resource.rc | 6 + plugins/MetaContacts/version.h | 27 + plugins/MetaContacts/version.rc | 33 + 29 files changed, 7921 insertions(+) create mode 100644 plugins/MetaContacts/IcoLib.h create mode 100644 plugins/MetaContacts/MetaContacts translations/metacontacts_template.txt create mode 100644 plugins/MetaContacts/MetaContacts.rc create mode 100644 plugins/MetaContacts/MetaContacts_10.sln create mode 100644 plugins/MetaContacts/MetaContacts_10.vcxproj create mode 100644 plugins/MetaContacts/MetaContacts_10.vcxproj.filters create mode 100644 plugins/MetaContacts/addto.c create mode 100644 plugins/MetaContacts/edit.c create mode 100644 plugins/MetaContacts/icons.c create mode 100644 plugins/MetaContacts/icons.h create mode 100644 plugins/MetaContacts/mcmenu.ico create mode 100644 plugins/MetaContacts/mcmenuof.ico create mode 100644 plugins/MetaContacts/mcmenuoff2.ico create mode 100644 plugins/MetaContacts/meta_add.ico create mode 100644 plugins/MetaContacts/meta_api.c create mode 100644 plugins/MetaContacts/meta_convert.ico create mode 100644 plugins/MetaContacts/meta_edit.ico create mode 100644 plugins/MetaContacts/meta_main.c create mode 100644 plugins/MetaContacts/meta_menu.c create mode 100644 plugins/MetaContacts/meta_options.c create mode 100644 plugins/MetaContacts/meta_remove2.ico create mode 100644 plugins/MetaContacts/meta_services.c create mode 100644 plugins/MetaContacts/meta_set_as_default.ico create mode 100644 plugins/MetaContacts/meta_utils.c create mode 100644 plugins/MetaContacts/metacontacts.h create mode 100644 plugins/MetaContacts/resource.h create mode 100644 plugins/MetaContacts/resource.rc create mode 100644 plugins/MetaContacts/version.h create mode 100644 plugins/MetaContacts/version.rc (limited to 'plugins/MetaContacts') diff --git a/plugins/MetaContacts/IcoLib.h b/plugins/MetaContacts/IcoLib.h new file mode 100644 index 0000000000..1817df68dc --- /dev/null +++ b/plugins/MetaContacts/IcoLib.h @@ -0,0 +1,37 @@ +typedef struct { + int cbSize; + char *pszSection; //section name used to group icons + char *pszDescription; //description for options dialog + char *pszName; //name to refer to icon when playing and in db + //this name is miranda-wide. so use prefixes of your plugin + //e.g: "isee_connect", "clist_delete", etc + char *pszDefaultFile; //default icon file to use + int iDefaultIndex; +} SKINICONDESC; + +typedef struct { + int cbSize; + char *pszSection; + char *pszDescription; + char *pszName; + char *pszDefaultFile; + int iDefaultIndex; + HICON hDefaultIcon; +} SKINICONDESC2; + +// +// Add a icon into options UI +// +// wParam = (WPARAM)0 +// lParam = (LPARAM)(SKINICONDESC*)sid; +// +#define MS_SKIN2_ADDICON "Skin2/Icons/AddIcon" +// +// Retrieve HICON with name specified in lParam +// Returned HICON SHOULDN'T be destroyed, it managed by IcoLib +// +#define MS_SKIN2_GETICON "Skin2/Icons/GetIcon" +// +// Icons change notification +// +#define ME_SKIN2_ICONSCHANGED "Skin2/IconsChanged" diff --git a/plugins/MetaContacts/MetaContacts translations/metacontacts_template.txt b/plugins/MetaContacts/MetaContacts translations/metacontacts_template.txt new file mode 100644 index 0000000000..18a000e683 --- /dev/null +++ b/plugins/MetaContacts/MetaContacts translations/metacontacts_template.txt @@ -0,0 +1,205 @@ +[MetaContacts] + +[Allows the joining of several subcontacts into one] + +[Error - Database corruption.\nPlugin disabled.] + +;menu +[Toggle MetaContacts On/Off] + +[Convert to MetaContact] + +[Add to existing MetaContact...] + +[Edit MetaContact...] + +[Delete MetaContact] + +[Remove from MetaContact] + +[Force Default] + +[Unforce Default] + +[Set as MetaContact default] + +[Context] + +;dialog +[History Copy] + +[Please wait while the contact's history is copied.] + +[History Remove] + +[Please wait while the contact's history is removed.] + +[Add to Existing MetaContact] + +[Please select a MetaContact:] + +[Editing] + +[&OK] + +[&Cancel] + +[&Apply] + +[&Remove] + +[&Set as Default] + +[Move &Up] + +[Move &Down] + +[Force use of default for sending (even if offline)] + +[Information] + +[Name:] + +[Contacts] + +[Contact] + +[Id] + +[Protocol] + +[Default] + +[Yes] + +[No] + +[Options] + +[Automatically set default contact on receipt of message] + +[Always send to default contact if not offline] + +[Suppress status notification for subcontacts] + +[Hide in status bar and status menu (*requires restart, uncheck to set proto icons)] + +[Use subcontact message windows] + +[Context Menu] + +[Contact Labels] + +[Use contact's unique id] + +[Use contact's display name] + +[Function] + +[Set default and open message window] + +[Show subcontact context menu] + +[Show user information] + +[Contact List] + +[Display subcontact nickname] + +[Display subcontact display name] + +[History (** beware - change at your own risk **)] + +[Copy subcontact history to MetaContact when creating or adding] + +[Number of days to copy (0=all):] + +[Keep MetaContact history synchronized with subcontacts] + +[Keep subcontact history synchronized with MetaContact] + +[Nick] + +[Sender] + +;message +[Delete MetaContact?] + +[You are going to remove all the contacts associated with this MetaContact.\nThis will delete the MetaContact.\n\nProceed Anyway?] + +[Contact not present in the DB] + +[This contact seems not to be in the database.\nThe database could be corrupted.\nTry to remove it manually.] + +[MetaContact Conflict] + +[This contact is a MetaContact.\nYou can't add a MetaContact to another MetaContact.\n\nPlease choose another.] + +[Multiple MetaContacts] + +[This contact is already associated to a MetaContact.\nYou cannot add a contact to multiple MetaContacts.] + +[No suitable MetaContact found] + +[Either there is no MetaContact in the database (in this case you should first convert a contact into one)\nor there is none that can host this contact.\nAnother solution could be to convert this contact into a new MetaContact.\n\nConvert this contact into a new MetaContact?] + +[Adding %s...] + +[a contact] + +[No MetaContact selected] + +[Please select a MetaContact] + +[Assignment failure] + +[The operation failed: Assigning <%s> to <%s>] + +[Assignment Error] + +[Could not get MetaContact id] + +[Could not retreive MetaContact contact count] + +[Could not retreive contact protocol] + +[Contact is 'Not on List' - please add the contact to your contact list before assigning.] + +[MetaContact is full] + +[Could not write contact protocol to MetaContact] + +[Could not get unique id of contact] + +[Could not write unique id of contact to MetaContact] + +[Could not write nickname of contact to MetaContact] + +[Could not write clist displayname of contact to MetaContact] + +[Could not write contact status to MetaContact] + +[Could not write contact handle to MetaContact] + +[Could not write contact status string to MetaContact] + +[Could not write MetaContact id to contact] + +[Could not write MetaContact contact number to contact] + +[Could not write contact count to MetaContact] + +[No contacts found.] + +[There was a problem in assigning the contact to the MetaContact] + +[Database Corruption] + +[This will remove the MetaContact permanently.\n\nProceed Anyway?] + +[Are you sure?] + +; db corruption +[MetaID: ] + +[MetaContact corrupted - the number of subcontacts is incorrect.\nDelete MetaContact?] diff --git a/plugins/MetaContacts/MetaContacts.rc b/plugins/MetaContacts/MetaContacts.rc new file mode 100644 index 0000000000..1eee03456c --- /dev/null +++ b/plugins/MetaContacts/MetaContacts.rc @@ -0,0 +1,335 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Neutral (Default) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEUD) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_DEFAULT +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_METASELECT, DIALOG + BEGIN + LEFTMARGIN, 3 + RIGHTMARGIN, 252 + TOPMARGIN, 4 + BOTTOMMARGIN, 252 + END + + IDD_METAEDIT, DIALOG + BEGIN + LEFTMARGIN, 5 + RIGHTMARGIN, 378 + TOPMARGIN, 4 + BOTTOMMARGIN, 255 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_METASELECT DIALOGEX 0, 0, 256, 259 +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 to Existing MetaContact" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + CTEXT "Please select a MetaContact:",IDC_STATIC,27,11,201,14 + DEFPUSHBUTTON "&Ok",IDOK,73,238,48,14 + PUSHBUTTON "&Cancel",IDCANCEL,133,238,48,14 + LISTBOX IDC_METALIST,44,28,168,168,LBS_NOINTEGRALHEIGHT | WS_VSCROLL + CONTROL "Sort Alphabetically",IDC_CHK_SRT,"Button",BS_AUTOCHECKBOX | BS_VCENTER | WS_TABSTOP,78,210,124,13 +END + +IDD_METAEDIT DIALOGEX 0, 0, 383, 260 +STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_STATICEDGE +CAPTION "Editing" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 +BEGIN + DEFPUSHBUTTON "&OK",IDOK,106,241,50,14 + PUSHBUTTON "&Cancel",IDCANCEL,166,241,50,14 + LTEXT "Name:",IDC_STATIC,108,26,42,8 + GROUPBOX "Information",IDC_STATIC,5,4,373,45 + GROUPBOX "Contacts",IDC_FRAME,5,54,373,180 + PUSHBUTTON "&Apply",IDC_VALIDATE,226,241,50,14 + DEFPUSHBUTTON "&Remove",IDC_BTN_REM,53,181,50,14 + PUSHBUTTON "&Set as Default",IDC_BTN_SETDEFAULT,107,181,50,14 + PUSHBUTTON "Move &Up",IDC_BTN_UP,224,181,50,14 + PUSHBUTTON "Move &Down",IDC_BTN_DOWN,279,181,50,14 + EDITTEXT IDC_ED_NAME,158,23,135,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP + CONTROL "List1",IDC_LST_CONTACTS,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,53,79,276,89,WS_EX_CLIENTEDGE + GROUPBOX "",IDC_STATIC,35,66,313,138 + CONTROL "Force use of default for sending (even if offline)",IDC_CHK_FORCEDEFAULT, + "Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,110,215,209,10 + PUSHBUTTON "Send &Offline",IDC_BTN_SETOFFLINE,161,181,50,14 +END + +#endif // Neutral (Default) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// French (France) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_FRA) +#ifdef _WIN32 +LANGUAGE LANG_FRENCH, SUBLANG_FRENCH +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // French (France) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// Neutral (Sys. Default) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEUSD) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_SYS_DEFAULT +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_MCMENU ICON "mcmenu.ico" +IDI_MCMENUOFF ICON "mcmenuof.ico" +#endif // Neutral (Sys. Default) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (Australia) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_OPTIONS, DIALOG + BEGIN + VERTGUIDE, 4 + VERTGUIDE, 9 + VERTGUIDE, 137 + VERTGUIDE, 173 + HORZGUIDE, 74 + END + + IDD_COPYPROGRESS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 83 + END + + IDD_DELPROGRESS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 83 + END + + IDD_PRIORITIES, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 259 + TOPMARGIN, 7 + BOTTOMMARGIN, 150 + END + + IDD_HISTORY, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 280 + TOPMARGIN, 7 + BOTTOMMARGIN, 102 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_OPTIONS DIALOGEX 0, 0, 298, 178 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CENTER | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + CONTROL "Set default contact on receipt of message",IDC_CHK_SETDEFAULTRECV, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,4,9,290,10 + CONTROL "Always send to default contact if not offline",IDC_CHK_ALWAYSUSEDEFAULT, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,4,31,290,10 + GROUPBOX "Options",IDC_STATIC,0,0,297,178 + CONTROL "Suppress status notification for subcontacts",IDC_CHK_SUPPRESSSTATUS, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,4,42,290,10 + GROUPBOX "Context Menu",IDC_STATIC,4,79,289,58 + CONTROL "Use contact's unique id",IDC_RAD_UID,"Button",BS_AUTORADIOBUTTON | WS_GROUP,13,100,112,10 + CONTROL "Use contact's display name",IDC_RAD_DID,"Button",BS_AUTORADIOBUTTON | WS_GROUP,13,114,112,10 + GROUPBOX "Contact Labels",IDC_STATIC,9,87,120,45,WS_GROUP + GROUPBOX "Function",IDC_STATIC,133,87,155,45,WS_GROUP + CONTROL "Set default and open message window",IDC_RAD_MSG,"Button",BS_AUTORADIOBUTTON | WS_GROUP,137,98,148,10 + CONTROL "Show subcontact context menu",IDC_RAD_MENU,"Button",BS_AUTORADIOBUTTON | WS_GROUP,137,108,148,10 + CONTROL "Show user information",IDC_RAD_INFO,"Button",BS_AUTORADIOBUTTON | WS_GROUP,137,118,148,10 + GROUPBOX "Contact List",IDC_STATIC,4,139,289,33,WS_GROUP + CONTROL "Display subcontact nickname",IDC_RAD_NICK,"Button",BS_AUTORADIOBUTTON | WS_GROUP,9,149,144,10 + CONTROL "Display subcontact display name",IDC_RAD_NAME,"Button",BS_AUTORADIOBUTTON | WS_GROUP,9,160,144,10 + CONTROL "Hide in status bar and status menu (*requires restart, uncheck to set proto icons)",IDC_CHK_SUPPRESSPROTO, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,4,53,290,10 + CONTROL "Use subcontact message windows",IDC_CHK_SUBWINDOW, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,4,64,165,10 + CONTROL "Copy subcontact data",IDC_CHK_COPYDATA,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,173,64,118,10 + CONTROL "Lock name to first contact",IDC_CHK_LOCKHANDLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,173,155,115,10 + CONTROL "but only for the current conversation",IDC_CHK_TEMPDEFAULT, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,20,260,10 +END + +IDD_COPYPROGRESS DIALOG 0, 0, 186, 90 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION +CAPTION "History Copy" +FONT 8, "MS Shell Dlg" +BEGIN + CONTROL "Progress1",IDC_PROG,"msctls_progress32",0x0,28,49,130,13 + CTEXT "Please wait while the contact's history is copied.",IDC_STATIC,9,27,167,8 +END + +IDD_DELPROGRESS DIALOG 0, 0, 186, 90 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION +CAPTION "History Remove" +FONT 8, "MS Shell Dlg" +BEGIN + CONTROL "Progress1",IDC_PROG,"msctls_progress32",0x0,28,49,130,13 + CTEXT "Please wait while the contact's history is removed.",IDC_STATIC,9,27,167,8 +END + +IDD_PRIORITIES DIALOGEX 0, 0, 266, 157 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CENTER | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + GROUPBOX "Subcontact Priorities",IDC_STATIC,7,7,252,143 + EDITTEXT IDC_ED_PRIORITY,157,78,40,14,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "",IDC_SP_PRIORITY,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS,195,78,11,14 + RTEXT "Rank:",IDC_STATIC,42,81,49,8 + RTEXT "Status:",IDC_STATIC,30,57,61,8 + COMBOBOX IDC_CMB_STATUS,98,53,112,87,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + RTEXT "Protocol:",IDC_STATIC,30,31,61,8 + COMBOBOX IDC_CMB_PROTOCOL,98,28,112,112,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Reset All",IDC_BTN_RESET,87,119,91,14 + CONTROL "Default",IDC_CHK_DEFAULT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,97,81,58,10 + CTEXT "(Lower ranks are preferred)",IDC_STATIC,51,99,162,8 +END + +IDD_HISTORY DIALOGEX 0, 0, 287, 109 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CENTER | WS_CHILD +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + CONTROL "Copy subcontact history to MetaContact when creating or adding",IDC_CHK_COPYHISTORY, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,23,258,10 + RTEXT "Number of days to copy (0=all):",IDC_STATIC,13,37,125,8 + EDITTEXT IDC_ED_DAYS,158,35,31,12,ES_RIGHT | ES_AUTOHSCROLL | ES_NUMBER + CONTROL "Keep MetaContact history synchronized with subcontacts",IDC_CHK_METAHISTORY, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,60,258,10 + CONTROL "Keep subcontact history synchronized with MetaContact",IDC_CHK_SUBHISTORY, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,78,258,10 + GROUPBOX "History (** beware - change at your own risk **)",IDC_STATIC,7,7,273,95,WS_GROUP +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_MCEDIT ICON "meta_edit.ico" +IDI_MCREMOVE ICON "meta_remove2.ico" +IDI_MCCONVERT ICON "meta_convert.ico" +IDI_MCADD ICON "meta_add.ico" +IDI_MCSETDEFAULT ICON "meta_set_as_default.ico" +#endif // English (Australia) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/MetaContacts/MetaContacts_10.sln b/plugins/MetaContacts/MetaContacts_10.sln new file mode 100644 index 0000000000..636c27ec9b --- /dev/null +++ b/plugins/MetaContacts/MetaContacts_10.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MetaContacts", "MetaContacts_10.vcxproj", "{0007BE9F-DD4D-4E9B-B1C8-C5049538F862}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0007BE9F-DD4D-4E9B-B1C8-C5049538F862}.Debug|Win32.ActiveCfg = Debug|Win32 + {0007BE9F-DD4D-4E9B-B1C8-C5049538F862}.Debug|Win32.Build.0 = Debug|Win32 + {0007BE9F-DD4D-4E9B-B1C8-C5049538F862}.Debug|x64.ActiveCfg = Debug|x64 + {0007BE9F-DD4D-4E9B-B1C8-C5049538F862}.Debug|x64.Build.0 = Debug|x64 + {0007BE9F-DD4D-4E9B-B1C8-C5049538F862}.Release|Win32.ActiveCfg = Release|Win32 + {0007BE9F-DD4D-4E9B-B1C8-C5049538F862}.Release|Win32.Build.0 = Release|Win32 + {0007BE9F-DD4D-4E9B-B1C8-C5049538F862}.Release|x64.ActiveCfg = Release|x64 + {0007BE9F-DD4D-4E9B-B1C8-C5049538F862}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/plugins/MetaContacts/MetaContacts_10.vcxproj b/plugins/MetaContacts/MetaContacts_10.vcxproj new file mode 100644 index 0000000000..03708a1f26 --- /dev/null +++ b/plugins/MetaContacts/MetaContacts_10.vcxproj @@ -0,0 +1,274 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + MetaContacts + {0007BE9F-DD4D-4E9B-B1C8-C5049538F862} + MetaContacts + MFCProj + + + + DynamicLibrary + Dynamic + MultiByte + true + + + DynamicLibrary + Dynamic + MultiByte + + + Application + true + + + Application + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + $(SolutionDir)$(Configuration)/Plugins\ + $(SolutionDir)$(Configuration)/Obj/$(ProjectName)\ + true + $(SolutionDir)$(Configuration)/Plugins\ + $(SolutionDir)$(Configuration)/Obj/$(ProjectName)\ + false + true + $(SolutionDir)$(Configuration)64/Plugins\ + $(SolutionDir)$(Configuration)64/Obj/$(ProjectName)\ + $(SolutionDir)$(Configuration)64/Plugins\ + $(SolutionDir)$(Configuration)64/Obj/$(ProjectName)\ + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Debug/MetaContacts.tlb + + + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;METACONTACTS_EXPORTS;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + Use + metacontacts.h + true + Level3 + true + ProgramDatabase + false + Disabled + + + _AFXDLL;_DEBUG;%(PreprocessorDefinitions) + 0x0c09 + + + unicows.lib;user32.lib;gdi32.lib;comctl32.lib;%(AdditionalDependencies) + true + true + false + + + $(IntDir)$(TargetName).lib + MachineX86 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + .\Release/MetaContacts.tlb + + + Full + OnlyExplicitInline + Size + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_WINDOWS;_USRDLL;METACONTACTS_EXPORTS;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + Fast + false + Use + metacontacts.h + Level3 + true + + + false + true + false + + + _AFXDLL;NDEBUG;%(PreprocessorDefinitions) + 0x0c09 + + + unicows.lib;user32.lib;gdi32.lib;comctl32.lib;%(AdditionalDependencies) + true + true + 0x22010000 + false + + + $(IntDir)$(TargetName).lib + MachineX86 + true + true + + + + + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + EnableFastChecks + MultiThreadedDebug + false + Disabled + + + $(IntDir)$(TargetName).lib + true + + + + + ../../include;../ExternalAPI;%(AdditionalIncludeDirectories) + MultiThreadedDLL + Full + OnlyExplicitInline + true + Size + false + + + $(IntDir)$(TargetName).lib + true + true + true + + + + + WIN32;_DEBUG;_WINDOWS;_USRDLL;METACONTACTS_EXPORTS;_MBCS;_WINDLL;_AFXDLL + EnableFastChecks + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;METACONTACTS_EXPORTS;_MBCS;_WINDLL;_AFXDLL + + + WIN32;_DEBUG;_WINDOWS;_USRDLL;METACONTACTS_EXPORTS;_MBCS;_WINDLL;_AFXDLL + EnableFastChecks + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;METACONTACTS_EXPORTS;_MBCS;_WINDLL;_AFXDLL + + + + WIN32;_DEBUG;_WINDOWS;_USRDLL;METACONTACTS_EXPORTS;_MBCS;_WINDLL;_AFXDLL + EnableFastChecks + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;METACONTACTS_EXPORTS;_MBCS;_WINDLL;_AFXDLL + + + WIN32;_DEBUG;_WINDOWS;_USRDLL;METACONTACTS_EXPORTS;_MBCS;_WINDLL;_AFXDLL + EnableFastChecks + Create + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;METACONTACTS_EXPORTS;_MBCS;_WINDLL;_AFXDLL + Create + + + WIN32;_DEBUG;_WINDOWS;_USRDLL;METACONTACTS_EXPORTS;_MBCS;_WINDLL;_AFXDLL + EnableFastChecks + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;METACONTACTS_EXPORTS;_MBCS;_WINDLL;_AFXDLL + + + WIN32;_DEBUG;_WINDOWS;_USRDLL;METACONTACTS_EXPORTS;_MBCS;_WINDLL;_AFXDLL + EnableFastChecks + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;METACONTACTS_EXPORTS;_MBCS;_WINDLL;_AFXDLL + + + WIN32;_DEBUG;_WINDOWS;_USRDLL;METACONTACTS_EXPORTS;_MBCS;_WINDLL;_AFXDLL + EnableFastChecks + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;METACONTACTS_EXPORTS;_MBCS;_WINDLL;_AFXDLL + + + WIN32;_DEBUG;_WINDOWS;_USRDLL;METACONTACTS_EXPORTS;_MBCS;_WINDLL;_AFXDLL + EnableFastChecks + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;METACONTACTS_EXPORTS;_MBCS;_WINDLL;_AFXDLL + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/MetaContacts/MetaContacts_10.vcxproj.filters b/plugins/MetaContacts/MetaContacts_10.vcxproj.filters new file mode 100644 index 0000000000..6caf9fe0c8 --- /dev/null +++ b/plugins/MetaContacts/MetaContacts_10.vcxproj.filters @@ -0,0 +1,100 @@ + + + + + {4a8bb46c-4423-42fc-9576-78cd8badfcff} + cpp;c;cxx;rc;def;r;odl;idl;hpj;bat + + + {a442bb73-5e8b-4eb0-b6c0-0534f3ca4b87} + h;hpp;hxx;hm;inl + + + {b4847f2a-7aa8-4577-a5a1-f7adf03537ec} + ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + {a8acfb52-2cd1-4156-ad43-fcdd6773d45c} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Resource Files + + + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + Resource Files + + + translation template + + + + + Resource Files + + + Resource Files + + + \ No newline at end of file diff --git a/plugins/MetaContacts/addto.c b/plugins/MetaContacts/addto.c new file mode 100644 index 0000000000..3fcfcd2a62 --- /dev/null +++ b/plugins/MetaContacts/addto.c @@ -0,0 +1,301 @@ +/* +MetaContacts Plugin for Miranda IM. + +Copyright © 2004 Universite Louis PASTEUR, STRASBOURG. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/** @file addto.c +* +* Functions for the 'Add To' Dialog. +* Contains all the functions and all the structures +* needed to display and control the 'Add To' Dialog. +*/ +#include "metacontacts.h" + +//! Holds information about a contact. +typedef struct { + char *name; //!< Name of the contact + char *proto; //!< Protocol under which the contact has been registered + HANDLE hUser; //!< Identifier of the contact in the DB. +}USERINFO; + +//! Holds information for the callback function. +typedef struct { + USERINFO uInfo; //!< Information about the contact to add +}ADDTO_INFO; + +/** Adds all the metacontacts desired in the listview. +* +* Adds all the metacontacts present in the database in the list, +* +* @param list : \c HANDLE to the list which will contain the columns. +* @param nb_contacts : Number of loaded contacts. +* @param contacts : A list of the contacts' identifiers +* +* @param id : Reference to a list of the MetaContacts IDs loaded in the listview. +* Since this list is resized, its address must be passed. +* +* @return An integer specifying the number of rows added in the list. +*/ +int FillList(HWND list, BOOL sort) +{ + DWORD metaID; + HANDLE hMetaUser = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST,0,0); + int i=0; + int index; + //BOOL mbs = FALSE; + + while(hMetaUser) // The DB is searched through, to get all the metacontacts + { + if((metaID=DBGetContactSettingDword(hMetaUser,META_PROTO,META_ID,(DWORD)-1))==(DWORD)-1) + { + // This isn't a MetaContact, go to the next + hMetaUser = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)hMetaUser,0); + continue; + } + + + { + // get contact display name from clist + char *szCDN = (char *) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hMetaUser, 0); + + if(os_unicode_enabled) { + wchar_t *swzCDN = (wchar_t *) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hMetaUser, GCDNF_UNICODE), + *swzContactDisplayName; + + // detect if the clist provided unicode display name by comparing with non-unicode + if(szCDN && swzCDN && strncmp(szCDN, (char *)swzCDN, strlen(szCDN)) != 0) { + swzContactDisplayName = swzCDN; + } else { + // no? convert to unicode + if(szCDN) { + swzContactDisplayName = (wchar_t *) _alloca(sizeof(wchar_t) * (strlen(szCDN) + 1)); + MultiByteToWideChar(CP_ACP, 0, (char *) szCDN, -1, swzContactDisplayName, (int)strlen((char *)szCDN) + 1); + } else { + swzContactDisplayName = TranslateW(L"(Unknown Contact)"); + } + } + + // don't insert huge strings that we have to compare with later + if(wcslen(swzContactDisplayName) > 1023) + swzContactDisplayName[1024] = 0; + + if(sort) { + int j; + wchar_t buff[1024]; + for(j = 0; j < i; j++) { + SendMessageW(list, LB_GETTEXT, j, (LPARAM)buff); + if(wcscmp(buff, swzContactDisplayName) > 0) break; + } + index = SendMessageW(list, LB_INSERTSTRING, (WPARAM)j, (LPARAM)swzContactDisplayName); + } else { + index = SendMessageW(list, LB_INSERTSTRING, (WPARAM)-1, (LPARAM)swzContactDisplayName); + } + } else { + // don't insert huge strings that we have to compare with later + if(strlen(szCDN) > 1023) + szCDN[1024] = 0; + + if(sort) { + int j; + char buff[1024]; + for(j = 0; j < i; j++) { + SendMessage(list, LB_GETTEXT, j, (LPARAM)buff); + if(strcmp(buff, szCDN) > 0) break; + } + index = SendMessage(list, LB_INSERTSTRING, (WPARAM)j, (LPARAM)szCDN); + } else { + index = SendMessage(list, LB_INSERTSTRING, (WPARAM)-1, (LPARAM)szCDN); + } + } + + SendMessage(list, LB_SETITEMDATA, (WPARAM)index, (LPARAM)hMetaUser); + } + + i++; + + hMetaUser = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)hMetaUser,0); + } + return i; +} + +/** Build or update the list. +* +* @param list : \c HANDLE to the list which will contain the columns +* @param id : Reference to a list that will contain all the MetaContacts IDs loaded in the listview +* otherwise the list is only refilled \n (Warning : this value must be +* set to \c TRUE only once per Dialog display, otherwise all columns will be doubled) +* +* @returns An integer specifying the number of rows inserted or \c -1 if there was a problem +*/ +int BuildList(HWND list, BOOL sort) +{ + int ret=-1; + SendMessage(list, LB_RESETCONTENT, 0, 0); + + ret = FillList(list, sort); + + return ret; +} + +/** Callback function for the 'Add To' Dialog. +* +* All the UI is controlled here, from display to functionnalities. +* +* @param hwndDlg : \c HANDLE to the 'Add To' \c Dialog. +* @param uMsg : Specifies the message received by this dialog. +* @param wParam : Specifies additional message-specific information. +* @param lParam : Specifies additional message-specific information. +* +* @return \c TRUE if the dialog processed the message, \c FALSE if it did not. +*/ +INT_PTR CALLBACK Meta_SelectDialogProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch(msg) + { + case WM_INITDIALOG: + { + TranslateDialogDefault( hwndDlg ); + + + if(DBGetContactSettingDword((HANDLE)lParam,META_PROTO,META_ID,(DWORD)-1)!=(DWORD)-1) + { + MessageBox(hwndDlg,Translate("This contact is a MetaContact.\nYou can't add a MetaContact to another MetaContact.\n\nPlease choose another."), + Translate("MetaContact Conflict"),MB_ICONERROR); + DestroyWindow(hwndDlg); + return TRUE; + } + if(DBGetContactSettingDword((HANDLE)lParam,META_PROTO,META_LINK,(DWORD)-1)!=(DWORD)-1) + { + MessageBox(hwndDlg,Translate("This contact is already associated to a MetaContact.\nYou cannot add a contact to multiple MetaContacts."), + Translate("Multiple MetaContacts"),MB_ICONERROR); + DestroyWindow(hwndDlg); + return TRUE; + } + + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam); // user data is contact handle + + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadIconEx(I_ADD)); + //SendMessage(GetDlgItem(hwndDlg,IDC_METALIST),LVM_SETEXTENDEDLISTVIEWSTYLE,0,LVS_EX_FULLROWSELECT); + + // Initialize the graphical part + CheckDlgButton(hwndDlg,IDC_ONLYAVAIL,BST_CHECKED); // Initially checked; display all metacontacts is only an option + // Besides, we can check if there is at least one metacontact to add the contact to. + if(BuildList(GetDlgItem(hwndDlg,IDC_METALIST), FALSE)<=0) + { + if(MessageBox(hwndDlg,Translate("Either there is no MetaContact in the database (in this case you should first convert a contact into one)\n" + "or there is none that can host this contact.\n" + "Another solution could be to convert this contact into a new MetaContact.\n\nConvert this contact into a new MetaContact?"), + Translate("No suitable MetaContact found"),MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON1)==IDYES) + Meta_Convert((WPARAM)lParam,0); + DestroyWindow(hwndDlg); + return TRUE; + } + else + { + // Get the name displayed in the CList... + + // get contact display name from clist + char *szCDN = (char *) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)lParam, 0); + if(os_unicode_enabled) { + wchar_t *swzCDN = (wchar_t *) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)lParam, GCDNF_UNICODE), + *swzContactDisplayName; + wchar_t buf[256]; + + // detect if the clist provided unicode display name by comparing with non-unicode + if(szCDN && swzCDN && strncmp(szCDN, (char *)swzCDN, strlen(szCDN)) != 0) { + swzContactDisplayName = swzCDN; + } else { + // no? convert to unicode + if(szCDN) { + swzContactDisplayName = (wchar_t *) _alloca(sizeof(wchar_t) * (strlen(szCDN) + 1)); + MultiByteToWideChar(CP_ACP, 0, (char *) szCDN, -1, swzContactDisplayName, (int)strlen((char *)szCDN) + 1); + } else { + swzContactDisplayName = TranslateW(L"a contact"); + } + } + + // ... and set it to the Window title. + //MessageBoxW(hwndDlg, swzContactDisplayName, L"Setting window title", MB_OK); + + // note - the swprintf function has changed (includes size_t for vc8+) + //swprintf(buf, 256, TranslateW(L"Adding %s..."), swzContactDisplayName); + // this *should* work for vc6, 7, and 8 (thx George) + _snwprintf(buf, 256, TranslateW(L"Adding %s..."), swzContactDisplayName); + + SetWindowTextW(hwndDlg, buf); + } else { + char buf[256]; + sprintf(buf,Translate("Adding %s..."), szCDN); + SetWindowText(hwndDlg, buf); + } + + ShowWindow(hwndDlg,SW_SHOWNORMAL); + return TRUE; + } + } + case WM_COMMAND: + if(HIWORD(wParam)!=BN_CLICKED) + break; // Only clicks of buttons are relevant, let other COMMANDs through + switch(LOWORD(wParam)) + { + case IDOK: + { + HANDLE hMeta, hContact = (HANDLE)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + int item; // Get the index of the selected metacontact + if((item = SendMessage(GetDlgItem(hwndDlg, IDC_METALIST),LB_GETCURSEL, 0, 0))==-1) + return IDOK == MessageBox(hwndDlg,Translate("Please select a MetaContact"),Translate("No MetaContact selected"),MB_ICONHAND); + + hMeta = (HANDLE)SendMessage(GetDlgItem(hwndDlg, IDC_METALIST), LB_GETITEMDATA, (WPARAM)item, 0); + + { + if(!Meta_Assign(hContact,hMeta, FALSE)) + { + MessageBox(hwndDlg, Translate("Assignment to the MetaContact failed."), Translate("Assignment failure"),MB_ICONERROR); + } + } + } + case IDCANCEL: + DestroyWindow(hwndDlg); + break; + + case IDC_CHK_SRT: + SetWindowLong(GetDlgItem(hwndDlg, IDC_METALIST), GWL_STYLE, GetWindowLong(GetDlgItem(hwndDlg, IDC_METALIST), GWL_STYLE) ^ LBS_SORT); + if(BuildList(GetDlgItem(hwndDlg,IDC_METALIST), IsDlgButtonChecked(hwndDlg, IDC_CHK_SRT) ? TRUE : FALSE)<=0) + { + if(MessageBox(hwndDlg,Translate("Either there is no MetaContact in the database (in this case you should first convert a contact into one)\n" + "or there is none that can host this contact.\n" + "Another solution could be to convert this contact into a new MetaContact.\n\nConvert this contact into a new MetaContact?"), + Translate("No suitable MetaContact found"),MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON1)==IDYES) + Meta_Convert((WPARAM)lParam,0); + DestroyWindow(hwndDlg); + return TRUE; + } + break; + } + break; + case WM_DESTROY: + { // Free all allocated memory and return the focus to the CList + HWND clist = GetParent(hwndDlg); + ReleaseIconEx((HICON)SendMessage(hwndDlg, WM_SETICON, ICON_BIG, 0)); + EndDialog(hwndDlg,TRUE); + SetFocus(clist); + return TRUE; + } + } + return FALSE; // All other Message are not handled +} diff --git a/plugins/MetaContacts/edit.c b/plugins/MetaContacts/edit.c new file mode 100644 index 0000000000..9a5f55d920 --- /dev/null +++ b/plugins/MetaContacts/edit.c @@ -0,0 +1,585 @@ +/* +MetaContacts Plugin for Miranda IM. + +Copyright © 2004 Universite Louis PASTEUR, STRASBOURG. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/** @file edit.c +* +* Functions for the 'Edit' Dialog. +* Contains all the functions and all the structures +* needed to display and control the 'Edit' Dialog. +*/ +#include "metacontacts.h" + +//! Holds the differents changes that have to made +typedef struct tag_CHANGES { + HANDLE hMeta; //!< \c HANDLE of the MetaContact that is edited. + HANDLE hDefaultContact; //!< \c HANDLE of the new default contact + HANDLE hOfflineContact; + int num_deleted, //!< \c DWORD number of deleted contacts + num_contacts; //!< \c DWORD number of contacts + HANDLE hDeletedContacts[MAX_CONTACTS]; //!< \c HANDLEs of the subcontacts to be removed from this metacontact + HANDLE hContact[MAX_CONTACTS]; //!< \c HANDLEs of the subcontacts, in the order they should be in + int force_default; +} CHANGES; + +CHANGES changes; //!< \c global CHANGES structure + +/** Fills the list of contacts +* +* @param chg : Structure holding all the change info (See CHANGES). +*/ +void FillContactList(HWND hWndDlg, CHANGES *chg) { + HWND hList = GetDlgItem(hWndDlg, IDC_LST_CONTACTS); + char *proto, *field, buff[256]; + int i; + LVITEM LvItem; + DBVARIANT dbv; + LVITEMW LvItemW; // for unicode nicks + + + SendMessage(hList,LVM_DELETEALLITEMS,0,0); + + ZeroMemory(&LvItem, sizeof(LvItem)); + LvItem.mask=LVIF_TEXT; // Text Style + LvItem.cchTextMax = 256; // Max size of test + + ZeroMemory(&LvItemW, sizeof(LvItemW)); + LvItemW.mask=LVIF_TEXT; // Text Style + LvItemW.cchTextMax = 256; // Max size of test + + for(i = 0; i < chg->num_contacts; i++) { + LvItem.iItem = i; + LvItemW.iItem = i; + + { + + char *szCDN = (char *) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)chg->hContact[i], 0); + + if(os_unicode_enabled) { + wchar_t *swzCDN = (wchar_t *) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)chg->hContact[i], GCDNF_UNICODE), + *swzContactDisplayName; + + LvItemW.iSubItem = 0; // clist display name + + // detect if the clist provided unicode display name by comparing with non-unicode + if(szCDN && swzCDN && strncmp(szCDN, (char *)swzCDN, strlen(szCDN)) != 0 && wcslen(swzCDN) >= strlen(szCDN)) { + swzContactDisplayName = swzCDN; + } else { + // no? convert to unicode + if(szCDN) { + swzContactDisplayName = (wchar_t *) _alloca(sizeof(wchar_t) * (strlen(szCDN) + 1)); + MultiByteToWideChar(CP_ACP, 0, (char *) szCDN, -1, swzContactDisplayName, (int)strlen((char *)szCDN) + 1); + } else { + swzContactDisplayName = TranslateW(L"(Unknown Contact)"); + } + } + + LvItemW.pszText = swzContactDisplayName; + SendMessageW(hList, LVM_INSERTITEMW, (WPARAM)0, (LPARAM)&LvItemW); + } else { + LvItem.iSubItem = 0; // clist display name + LvItem.pszText = szCDN; + SendMessage(hList, LVM_INSERTITEM, (WPARAM)0, (LPARAM)&LvItem); + } + } + + + + LvItem.iSubItem = 1; // id + + proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)chg->hContact[i], 0); + if(proto) { + field = (char *)CallProtoService(proto,PS_GETCAPS,PFLAG_UNIQUEIDSETTING,0); + + DBGetContactSetting(chg->hContact[i],proto,field,&dbv); + switch(dbv.type) + { + case DBVT_ASCIIZ: + sprintf(buff,"%s",dbv.pszVal); + break; + case DBVT_BYTE: + sprintf(buff,"%d",dbv.bVal); + break; + case DBVT_WORD: + sprintf(buff,"%d",dbv.wVal); + break; + case DBVT_DWORD: + sprintf(buff,"%d",(int)dbv.dVal); + break; + default: + //sprintf(buff,""); + buff[0] = 0; + } + DBFreeVariant(&dbv); + + LvItem.pszText = buff; + SendMessage(hList,LVM_SETITEM,0,(LPARAM)&LvItem); // Enter text to SubItems + + LvItem.iSubItem = 2; // protocol + LvItem.pszText = proto; + SendMessage(hList,LVM_SETITEM,0,(LPARAM)&LvItem); // Enter text to SubItems + } else { + LvItem.pszText = "Unknown"; + SendMessage(hList,LVM_SETITEM,0,(LPARAM)&LvItem); // Enter text to SubItems + + LvItem.iSubItem = 2; // protocol + LvItem.pszText = "Unknown"; + SendMessage(hList,LVM_SETITEM,0,(LPARAM)&LvItem); // Enter text to SubItems + } + LvItem.iSubItem = 3; // Default (Yes/No) + LvItem.pszText = (chg->hContact[i] == chg->hDefaultContact ? Translate("Yes") : Translate("No")); + SendMessage(hList,LVM_SETITEM,0,(LPARAM)&LvItem); // Enter text to SubItems + + LvItem.iSubItem = 4; // Offline (Yes/No) + LvItem.pszText = (chg->hContact[i] == chg->hOfflineContact ? Translate("Yes") : Translate("No")); + SendMessage(hList,LVM_SETITEM,0,(LPARAM)&LvItem); // Enter text to SubItems + } +} + + +void SetListSelection(HWND hList, int sel) { + LVITEM LvItem; + + ZeroMemory(&LvItem, sizeof(LvItem)); + LvItem.iItem = sel; + LvItem.mask = LVIF_STATE; + LvItem.stateMask = LVIS_SELECTED|LVIS_FOCUSED; + LvItem.state = LVIS_SELECTED|LVIS_FOCUSED; + + SendMessage(hList, LVM_SETITEMSTATE, (WPARAM)sel, (LPARAM)&LvItem); + +} + +/** Scans the \c CHANGES and call the appropriate function for each change. +* +* @param chg : Structure holding all the change info (See CHANGES). +*/ +void ApplyChanges(CHANGES *chg) +{ + HANDLE most_online; + int i; + + // remove removed contacts + for(i = 0; i < chg->num_deleted; i++) { + Meta_Delete((WPARAM)chg->hDeletedContacts[i], 0); + if(chg->hDeletedContacts[i] == chg->hDefaultContact) + chg->hDefaultContact = 0; + if(chg->hDeletedContacts[i] == chg->hOfflineContact) + chg->hOfflineContact = 0; + } + + // set contact positions + for(i = 0; i < chg->num_contacts; i++) { + if(Meta_GetContactNumber(chg->hContact[i]) != i) + Meta_SwapContacts(chg->hMeta, Meta_GetContactNumber(chg->hContact[i]), i); + } + + NotifyEventHooks(hSubcontactsChanged, (WPARAM)chg->hMeta, (LPARAM)chg->hDefaultContact); + + // set default + if(chg->hDefaultContact) + DBWriteContactSettingDword(chg->hMeta, META_PROTO, "Default", Meta_GetContactNumber(chg->hDefaultContact)); + else + DBWriteContactSettingDword(chg->hMeta, META_PROTO, "Default", 0); + NotifyEventHooks(hEventDefaultChanged, (WPARAM)chg->hMeta, (LPARAM)chg->hDefaultContact); + + // set offline + if(chg->hOfflineContact) + DBWriteContactSettingDword(chg->hMeta, META_PROTO, "OfflineSend", Meta_GetContactNumber(chg->hOfflineContact)); + else + DBWriteContactSettingDword(chg->hMeta, META_PROTO, "OfflineSend", (DWORD)-1); + + // fix nick + most_online = Meta_GetMostOnline(chg->hMeta); + Meta_CopyContactNick(chg->hMeta, most_online); + + // fix status + Meta_FixStatus(chg->hMeta); + + // fix avatar + most_online = Meta_GetMostOnlineSupporting(chg->hMeta, PFLAGNUM_4, PF4_AVATARS); + if(most_online) { + PROTO_AVATAR_INFORMATION AI; + + AI.cbSize = sizeof(AI); + AI.hContact = chg->hMeta; + AI.format = PA_FORMAT_UNKNOWN; + strcpy(AI.filename, "X"); + + if((int)CallProtoService(META_PROTO, PS_GETAVATARINFO, 0, (LPARAM)&AI) == GAIR_SUCCESS) + DBWriteContactSettingString(chg->hMeta, "ContactPhoto", "File",AI.filename); + } + + if(MetaAPI_GetForceState((WPARAM)chg->hMeta, 0) != chg->force_default) + MetaAPI_ForceDefault((WPARAM)chg->hMeta, 0); +} + +LRESULT ProcessCustomDraw (LPARAM lParam) +{ + LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)lParam; + + switch(lplvcd->nmcd.dwDrawStage) + { + case CDDS_PREPAINT : //Before the paint cycle begins + //request notifications for individual listview items + return CDRF_NOTIFYITEMDRAW; + + case CDDS_ITEMPREPAINT: //Before an item is drawn + /* + if (((int)lplvcd->nmcd.dwItemSpec%2)==0) + { + //customize item appearance + //lplvcd->clrText = RGB(255,0,0); + lplvcd->clrTextBk = RGB(200,200,200); + } + else{ + //lplvcd->clrText = RGB(0,0,255); + lplvcd->clrTextBk = RGB(255,255,255); + } + */ + if(changes.hContact[(int)lplvcd->nmcd.dwItemSpec] == changes.hDefaultContact) { + lplvcd->clrText = RGB(255, 0, 0); + } + return CDRF_NEWFONT; + } + + return 0; +} + +/** Callback function for the 'Edit' Dialog. +* +* All the UI is controlled here, from display to functionnalities. +* +* @param hwndDlg : \c HANDLE to the 'Edit' \c Dialog. +* @param uMsg : Specifies the message received by this dialog. +* @param wParam : Specifies additional message-specific information. +* @param lParam : Specifies additional message-specific information (handle of MetaContact to edit) +* +* @return \c TRUE if the dialog processed the message, \c FALSE if it did not. +*/ +#define WMU_SETTITLE (WM_USER + 1) + +INT_PTR CALLBACK Meta_EditDialogProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + HWND hwnd; + char *str; + int sel, i; + + switch(msg) + { + case WM_INITDIALOG: + { + // Font necessary for all controls created with CreateWindowsEx + //HFONT hfDefault = GetStockObject(DEFAULT_GUI_FONT); + //HWND combo = GetDlgItem(hwndDlg,IDC_DEFAULT); + int nb_contacts, default_contact_number, offline_contact_number; + LVCOLUMN LvCol; + + TranslateDialogDefault( hwndDlg ); + + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadIconEx(I_EDIT)); + + // Disable the 'Apply' button. + EnableWindow(GetDlgItem(hwndDlg,IDC_VALIDATE),FALSE); + + // (from http://www.codeproject.com/listctrl/listview.asp) + // initialize list + hwnd = GetDlgItem(hwndDlg, IDC_LST_CONTACTS); + SendMessage(hwnd,LVM_SETEXTENDEDLISTVIEWSTYLE, 0,LVS_EX_FULLROWSELECT); // Set style + + // Create list columns + ZeroMemory(&LvCol, sizeof(LvCol)); + LvCol.mask=LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM; // Type of mask + + // Inserting Couloms as much as we want + LvCol.pszText=Translate("Contact"); // First Header Text + LvCol.cx=100; // width of column + SendMessage(hwnd,LVM_INSERTCOLUMN,0,(LPARAM)&LvCol); // Insert/Show the coloum + + LvCol.pszText=Translate("Id"); // Next coloum + LvCol.cx=130; // width of column + SendMessage(hwnd,LVM_INSERTCOLUMN,1,(LPARAM)&LvCol); // ... + LvCol.pszText=Translate("Protocol"); // + LvCol.cx=100; // width of column + SendMessage(hwnd,LVM_INSERTCOLUMN,2,(LPARAM)&LvCol); // + LvCol.pszText=Translate("Default"); // + LvCol.cx=60; // width of column + SendMessage(hwnd,LVM_INSERTCOLUMN,3,(LPARAM)&LvCol); // + LvCol.pszText=Translate("Send Offline"); // + LvCol.cx=85; // width of column + SendMessage(hwnd,LVM_INSERTCOLUMN,4,(LPARAM)&LvCol); // + + // disable buttons until a selection is made in the list + hwnd = GetDlgItem(hwndDlg, IDC_BTN_REM); + EnableWindow(hwnd, FALSE); + hwnd = GetDlgItem(hwndDlg, IDC_BTN_SETDEFAULT); + EnableWindow(hwnd, FALSE); + hwnd = GetDlgItem(hwndDlg, IDC_BTN_SETOFFLINE); + EnableWindow(hwnd, FALSE); + hwnd = GetDlgItem(hwndDlg, IDC_BTN_UP); + EnableWindow(hwnd, FALSE); + hwnd = GetDlgItem(hwndDlg, IDC_BTN_DOWN); + EnableWindow(hwnd, FALSE); + + nb_contacts = DBGetContactSettingDword((HANDLE)lParam, META_PROTO, "NumContacts", 0); + default_contact_number = DBGetContactSettingDword((HANDLE)lParam, META_PROTO, "Default", (DWORD)-1); + offline_contact_number = DBGetContactSettingDword((HANDLE)lParam, META_PROTO, "OfflineSend", (DWORD)-1); + + changes.hMeta = (HANDLE)lParam; + changes.num_contacts = nb_contacts; + changes.num_deleted = 0; + changes.hDefaultContact = Meta_GetContactHandle((HANDLE)lParam, default_contact_number); + changes.hOfflineContact = Meta_GetContactHandle((HANDLE)lParam, offline_contact_number); + for(i = 0; i < nb_contacts; i++) + changes.hContact[i] = Meta_GetContactHandle((HANDLE)lParam, i); + changes.force_default = MetaAPI_GetForceState((WPARAM)lParam, 0); + + SendMessage(hwndDlg, WMU_SETTITLE, 0, lParam); + + CheckDlgButton(hwndDlg, IDC_CHK_FORCEDEFAULT, changes.force_default); + + FillContactList(hwndDlg, &changes); + return TRUE; + } + case WMU_SETTITLE: + { + + char *szCDN = (char *) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)lParam, 0); + if(os_unicode_enabled) { + wchar_t *swzCDN = (wchar_t *) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)lParam, GCDNF_UNICODE), + *swzContactDisplayName; + + // detect if the clist provided unicode display name by comparing with non-unicode + if(szCDN && swzCDN && strncmp(szCDN, (char *)swzCDN, strlen(szCDN)) != 0 && wcslen(swzCDN) >= strlen(szCDN)) { + swzContactDisplayName = swzCDN; + } else { + // no? convert to unicode + if(szCDN) { + swzContactDisplayName = (wchar_t *) _alloca(sizeof(wchar_t) * (strlen(szCDN) + 1)); + MultiByteToWideChar(CP_ACP, 0, (char *) szCDN, -1, swzContactDisplayName, (int)strlen((char *)szCDN) + 1); + } else { + swzContactDisplayName = TranslateW(L"(Unknown Contact)"); + } + } + + SetWindowTextW(GetDlgItem(hwndDlg,IDC_ED_NAME), swzContactDisplayName); + } else { + SetWindowText(GetDlgItem(hwndDlg,IDC_ED_NAME), szCDN); + } + } + return TRUE; + case WM_NOTIFY: // the message that is being sent always + switch(LOWORD(wParam)) // hit control + { + case IDC_LST_CONTACTS: // did we hit our ListView contorl? + if(((LPNMHDR)lParam)->code == NM_CLICK) { + hwnd = GetDlgItem(hwndDlg, IDC_LST_CONTACTS); + sel=SendMessage(hwnd,LVM_GETNEXTITEM,-1,LVNI_FOCUSED|LVNI_SELECTED); // return item selected + // enable buttons + hwnd = GetDlgItem(hwndDlg, IDC_BTN_REM); + EnableWindow(hwnd, sel!=-1); + hwnd = GetDlgItem(hwndDlg, IDC_BTN_SETDEFAULT); + EnableWindow(hwnd, sel!=-1 && changes.hContact[sel] != changes.hDefaultContact); + hwnd = GetDlgItem(hwndDlg, IDC_BTN_SETOFFLINE); + EnableWindow(hwnd, sel!=-1 && changes.hContact[sel] != changes.hOfflineContact); + hwnd = GetDlgItem(hwndDlg, IDC_BTN_UP); + EnableWindow(hwnd, (sel > 0)); + hwnd = GetDlgItem(hwndDlg, IDC_BTN_DOWN); + EnableWindow(hwnd, (sel != -1) && (sel < changes.num_contacts - 1)); +/* + // custom draw stuff - change colour of listview things - doesn't affect selection :( + } else if(((LPNMHDR)lParam)->code == NM_CUSTOMDRAW) { + SetWindowLong(hwndDlg, DWL_MSGRESULT, (LONG)ProcessCustomDraw(lParam)); + return TRUE; +*/ + } + break; + } + break; + case WM_COMMAND: + switch(HIWORD(wParam)) + { + case BN_CLICKED: // A button ('Remove', 'Ok', 'Cancel' or 'Apply', normally) has been clicked + switch(LOWORD(wParam)) + { + case IDC_VALIDATE: // Apply changes, if there is still one contact attached to the metacontact. + if(changes.num_contacts == 0) // Otherwise, delete the metacontact. + { + if(MessageBox(hwndDlg,Translate("You are going to remove all the contacts associated with this MetaContact.\nThis will delete the MetaContact.\n\nProceed Anyway?"), + Translate("Delete MetaContact?"),MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON1)!=IDYES) + return TRUE; + else + { + Meta_Delete((WPARAM)changes.hMeta,(LPARAM)NULL); + DestroyWindow(hwndDlg); + return TRUE; + } + } + ApplyChanges(&changes); + + // Disable the 'Apply' button. + EnableWindow(GetDlgItem(hwndDlg,IDC_VALIDATE),FALSE); + break; + case IDOK: + if(IsWindowEnabled(GetDlgItem(hwndDlg,IDC_VALIDATE))) + { // If there are changes that could be made, + if(changes.num_contacts == 0) // do the work that would have be done if + { // the button 'Apply' has been clicked. + if(MessageBox(hwndDlg,Translate("You are going to remove all the contacts associated with this MetaContact.\nThis will delete the MetaContact.\n\nProceed Anyway?"), + Translate("Delete MetaContact?"),MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON1)!=IDYES) + { + return TRUE; + } else { + Meta_Delete((WPARAM)changes.hMeta,(LPARAM)NULL); + DestroyWindow(hwndDlg); + return TRUE; + } + } + ApplyChanges(&changes); + } + EndDialog(hwndDlg, IDOK); + return TRUE; + case IDCANCEL: // Simply close the dialog + EndDialog(hwndDlg, IDCANCEL); + return TRUE; + case IDC_BTN_SETDEFAULT: + hwnd = GetDlgItem(hwndDlg, IDC_LST_CONTACTS); + sel=SendMessage(hwnd,LVM_GETNEXTITEM,-1,LVNI_FOCUSED|LVNI_SELECTED); // return item selected + InvalidateRect(hwnd, 0, TRUE); + changes.hDefaultContact = changes.hContact[sel]; + SendMessage(hwndDlg, WMU_SETTITLE, 0, (LPARAM)changes.hContact[sel]); + + FillContactList(hwndDlg, &changes); + SetListSelection(hwnd, sel); + // Disable set default button + EnableWindow(GetDlgItem(hwndDlg,IDC_BTN_SETDEFAULT),FALSE); + // Enable the 'Apply' button. + EnableWindow(GetDlgItem(hwndDlg,IDC_VALIDATE),TRUE); + + // repaint list + return TRUE; + case IDC_BTN_SETOFFLINE: + hwnd = GetDlgItem(hwndDlg, IDC_LST_CONTACTS); + sel=SendMessage(hwnd,LVM_GETNEXTITEM,-1,LVNI_FOCUSED|LVNI_SELECTED); // return item selected + InvalidateRect(hwnd, 0, TRUE); + changes.hOfflineContact = changes.hContact[sel]; + + FillContactList(hwndDlg, &changes); + SetListSelection(hwnd, sel); + // Disable set offline button + EnableWindow(GetDlgItem(hwndDlg,IDC_BTN_SETOFFLINE),FALSE); + // Enable the 'Apply' button. + EnableWindow(GetDlgItem(hwndDlg,IDC_VALIDATE),TRUE); + + // repaint list + return TRUE; + case IDC_BTN_REM: + hwnd = GetDlgItem(hwndDlg, IDC_LST_CONTACTS); + sel=SendMessage(hwnd,LVM_GETNEXTITEM,-1,LVNI_FOCUSED|LVNI_SELECTED); // return item selected + changes.num_contacts--; + changes.hDeletedContacts[changes.num_deleted++] = changes.hContact[sel]; + if(changes.hDefaultContact == changes.hContact[sel]) { + if(changes.num_contacts > 0) { + changes.hDefaultContact = changes.hContact[0]; + str = (char *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)changes.hDefaultContact, 0); + SetWindowText(GetDlgItem(hwndDlg,IDC_ED_DEFAULT),str); + } else { + changes.hDefaultContact = 0; + SetWindowText(GetDlgItem(hwndDlg,IDC_ED_DEFAULT),"None"); + } + + } + + for(i = sel; i < changes.num_contacts; i++) + changes.hContact[i] = changes.hContact[i + 1]; + FillContactList(hwndDlg, &changes); + // disable buttons + hwnd = GetDlgItem(hwndDlg, IDC_BTN_REM); + EnableWindow(hwnd, FALSE); + hwnd = GetDlgItem(hwndDlg, IDC_BTN_SETDEFAULT); + EnableWindow(hwnd, FALSE); + hwnd = GetDlgItem(hwndDlg, IDC_BTN_SETOFFLINE); + EnableWindow(hwnd, FALSE); + hwnd = GetDlgItem(hwndDlg, IDC_BTN_UP); + EnableWindow(hwnd, FALSE); + hwnd = GetDlgItem(hwndDlg, IDC_BTN_DOWN); + EnableWindow(hwnd, FALSE); + // Enable the 'Apply' button. + EnableWindow(GetDlgItem(hwndDlg,IDC_VALIDATE),TRUE); + return TRUE; + case IDC_BTN_UP: + hwnd = GetDlgItem(hwndDlg, IDC_LST_CONTACTS); + sel=SendMessage(hwnd,LVM_GETNEXTITEM,-1,LVNI_FOCUSED|LVNI_SELECTED); // return item selected + + { + HANDLE temp = changes.hContact[sel]; + changes.hContact[sel] = changes.hContact[sel - 1]; + changes.hContact[sel - 1] = temp; + } + FillContactList(hwndDlg, &changes); + sel--; + SetListSelection(hwnd, sel); + + hwnd = GetDlgItem(hwndDlg, IDC_BTN_UP); + EnableWindow(hwnd, (sel > 0)); + hwnd = GetDlgItem(hwndDlg, IDC_BTN_DOWN); + EnableWindow(hwnd, (sel < changes.num_contacts - 1)); + // Enable the 'Apply' button. + EnableWindow(GetDlgItem(hwndDlg,IDC_VALIDATE),TRUE); + return TRUE; + case IDC_BTN_DOWN: + hwnd = GetDlgItem(hwndDlg, IDC_LST_CONTACTS); + sel=SendMessage(hwnd,LVM_GETNEXTITEM,-1,LVNI_FOCUSED|LVNI_SELECTED); // return item selected + + { + HANDLE temp = changes.hContact[sel]; + changes.hContact[sel] = changes.hContact[sel + 1]; + changes.hContact[sel + 1] = temp; + } + FillContactList(hwndDlg, &changes); + sel++; + SetListSelection(hwnd, sel); + + hwnd = GetDlgItem(hwndDlg, IDC_BTN_UP); + EnableWindow(hwnd, (sel > 0)); + hwnd = GetDlgItem(hwndDlg, IDC_BTN_DOWN); + EnableWindow(hwnd, (sel < changes.num_contacts - 1)); + // Enable the 'Apply' button. + EnableWindow(GetDlgItem(hwndDlg,IDC_VALIDATE),TRUE); + return TRUE; + case IDC_CHK_FORCEDEFAULT: + changes.force_default = IsDlgButtonChecked(hwndDlg, IDC_CHK_FORCEDEFAULT); + // Enable the 'Apply' button. + EnableWindow(GetDlgItem(hwndDlg,IDC_VALIDATE),TRUE); + return TRUE; + } + } + break; + case WM_CLOSE: + DestroyWindow(hwndDlg); + return TRUE; + + case WM_DESTROY: + ReleaseIconEx((HICON)SendMessage(hwndDlg, WM_SETICON, ICON_BIG, 0)); + EndDialog(hwndDlg, IDCANCEL); + break; + } + + return FALSE; +} diff --git a/plugins/MetaContacts/icons.c b/plugins/MetaContacts/icons.c new file mode 100644 index 0000000000..f10739ca0b --- /dev/null +++ b/plugins/MetaContacts/icons.c @@ -0,0 +1,101 @@ +#include "metacontacts.h" + +HANDLE hIcoLibIconsChanged = NULL; + + +typedef struct { + char* szDescr; + char* szName; + int defIconID; +} IconStruct; + +static IconStruct iconList[] = { + { "Toggle Off", "mc_off", IDI_MCMENUOFF }, + { "Toggle On", "mc_on", IDI_MCMENU }, + { "Convert to MetaContact", "mc_convert", IDI_MCCONVERT }, + { "Add to Existing", "mc_add", IDI_MCADD }, + { "Edit", "mc_edit", IDI_MCEDIT }, + { "Set to Default", "mc_default", IDI_MCSETDEFAULT }, + { "Remove", "mc_remove", IDI_MCREMOVE }, +}; + + +HICON LoadIconEx(IconIndex i) { + HICON hIcon; + + if (hIcoLibIconsChanged) + hIcon = (HICON)CallService(MS_SKIN2_GETICON, 0, (LPARAM)iconList[(int)i].szName); + else + hIcon = (HICON)LoadImage(hInstance, MAKEINTRESOURCE(iconList[(int)i].defIconID), IMAGE_ICON, 0, 0, 0); + + return hIcon; +} + + +void ReleaseIconEx(HICON hIcon) { + if (hIcoLibIconsChanged) + CallService(MS_SKIN2_RELEASEICON, (WPARAM)hIcon, 0); + else + DestroyIcon(hIcon); +} + +int ReloadIcons(WPARAM wParam, LPARAM lParam) { + // fix menu icons + CLISTMENUITEM menu = {0}; + + menu.cbSize = sizeof(menu); + menu.flags = CMIM_ICON; + + menu.hIcon = LoadIconEx(Meta_IsEnabled() ? I_MENUOFF : I_MENU); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuOnOff, (LPARAM)&menu); + ReleaseIconEx(menu.hIcon); + + menu.hIcon = LoadIconEx(I_CONVERT); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuConvert, (LPARAM)&menu); + ReleaseIconEx(menu.hIcon); + + menu.hIcon = LoadIconEx(I_ADD); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuAdd, (LPARAM)&menu); + ReleaseIconEx(menu.hIcon); + + menu.hIcon = LoadIconEx(I_EDIT); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuEdit, (LPARAM)&menu); + ReleaseIconEx(menu.hIcon); + + menu.hIcon = LoadIconEx(I_SETDEFAULT); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuDefault, (LPARAM)&menu); + ReleaseIconEx(menu.hIcon); + + menu.hIcon = LoadIconEx(I_REMOVE); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuDelete, (LPARAM)&menu); + ReleaseIconEx(menu.hIcon); + + return 0; +} + +void InitIcons(void) { + SKINICONDESC sid = {0}; + char path[MAX_PATH]; + int i; + + sid.cbSize = sizeof(SKINICONDESC); + sid.pszSection = META_PROTO; + sid.pszDefaultFile = path; + GetModuleFileName(hInstance, path, sizeof(path)); + + for (i = 0; i < sizeof(iconList) / sizeof(IconStruct); ++i) + { + sid.pszDescription = Translate(iconList[i].szDescr); + sid.pszName = iconList[i].szName; + sid.iDefaultIndex = -iconList[i].defIconID; + CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid); + } + + hIcoLibIconsChanged = HookEvent(ME_SKIN2_ICONSCHANGED, ReloadIcons); + + ReloadIcons(0, 0); +} + +void DeinitIcons(void) { + if (hIcoLibIconsChanged) UnhookEvent(hIcoLibIconsChanged); +} diff --git a/plugins/MetaContacts/icons.h b/plugins/MetaContacts/icons.h new file mode 100644 index 0000000000..c77b1b02fc --- /dev/null +++ b/plugins/MetaContacts/icons.h @@ -0,0 +1,6 @@ +#ifndef _ICONS_INC +#define _ICONS_INC + +#include "metacontacts.h" + +#endif diff --git a/plugins/MetaContacts/mcmenu.ico b/plugins/MetaContacts/mcmenu.ico new file mode 100644 index 0000000000..b28455c554 Binary files /dev/null and b/plugins/MetaContacts/mcmenu.ico differ diff --git a/plugins/MetaContacts/mcmenuof.ico b/plugins/MetaContacts/mcmenuof.ico new file mode 100644 index 0000000000..72749e1c70 Binary files /dev/null and b/plugins/MetaContacts/mcmenuof.ico differ diff --git a/plugins/MetaContacts/mcmenuoff2.ico b/plugins/MetaContacts/mcmenuoff2.ico new file mode 100644 index 0000000000..5b3444abb0 Binary files /dev/null and b/plugins/MetaContacts/mcmenuoff2.ico differ diff --git a/plugins/MetaContacts/meta_add.ico b/plugins/MetaContacts/meta_add.ico new file mode 100644 index 0000000000..e3907099d9 Binary files /dev/null and b/plugins/MetaContacts/meta_add.ico differ diff --git a/plugins/MetaContacts/meta_api.c b/plugins/MetaContacts/meta_api.c new file mode 100644 index 0000000000..bf3aed5d2f --- /dev/null +++ b/plugins/MetaContacts/meta_api.c @@ -0,0 +1,245 @@ +/* +MetaContacts Plugin for Miranda IM. + +Copyright © 2004 Universite Louis PASTEUR, STRASBOURG. +Copyright © 2004 Scott Ellis (www.scottellis.com.au mail@scottellis.com.au) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/** @file meta_api.c +* +* API functions needed to handle MetaContacts. +* Centralizes functions called by other plugins. +*/ + +#include "metacontacts.h" + +//get the handle for a contact's parent metacontact +//wParam=(HANDLE)hSubContact +//lParam=0 +//returns a handle to the parent metacontact, or null if this contact is not a subcontact +INT_PTR MetaAPI_GetMeta(WPARAM wParam, LPARAM lParam) { + return (int)(HANDLE)DBGetContactSettingDword((HANDLE)wParam, META_PROTO, "Handle", 0); +} + +//gets the handle for the default contact +//wParam=(HANDLE)hMetaContact +//lParam=0 +//returns a handle to the default contact, or null on failure +INT_PTR MetaAPI_GetDefault(WPARAM wParam, LPARAM lParam) { + DWORD default_contact_number = DBGetContactSettingDword((HANDLE)wParam, META_PROTO, "Default", -1); + if(default_contact_number != -1) { + return (int)Meta_GetContactHandle((HANDLE)wParam, default_contact_number); + } + return 0; +} + +//gets the contact number for the default contact +//wParam=(HANDLE)hMetaContact +//lParam=0 +//returns a DWORD contact number, or -1 on failure +INT_PTR MetaAPI_GetDefaultNum(WPARAM wParam, LPARAM lParam) { + return DBGetContactSettingDword((HANDLE)wParam, META_PROTO, "Default", -1); +} + +//gets the handle for the 'most online' contact +//wParam=(HANDLE)hMetaContact +//lParam=0 +//returns a handle to the 'most online' contact +INT_PTR MetaAPI_GetMostOnline(WPARAM wParam, LPARAM lParam) { + return (int)Meta_GetMostOnline((HANDLE)wParam); +} + +//gets the number of subcontacts for a metacontact +//wParam=(HANDLE)hMetaContact +//lParam=0 +//returns a DWORD representing the number of subcontacts for the given metacontact +INT_PTR MetaAPI_GetNumContacts(WPARAM wParam, LPARAM lParam) { + DWORD num_contacts = DBGetContactSettingDword((HANDLE)wParam, META_PROTO, "NumContacts", -1); + return num_contacts; +} + +//gets the handle of a subcontact, using the subcontact's number +//wParam=(HANDLE)hMetaContact +//lParam=(DWORD)contact number +//returns a handle to the specified subcontact +INT_PTR MetaAPI_GetContact(WPARAM wParam, LPARAM lParam) { + return (int)Meta_GetContactHandle((HANDLE)wParam, (DWORD)lParam); +} + +//sets the default contact, using the subcontact's contact number +//wParam=(HANDLE)hMetaContact +//lParam=(DWORD)contact number +//returns 0 on success +INT_PTR MetaAPI_SetDefaultContactNum(WPARAM wParam, LPARAM lParam) { + DWORD num_contacts = DBGetContactSettingDword((HANDLE)wParam, META_PROTO, "NumContacts", -1); + if(num_contacts == -1) + return 1; + if((DWORD)lParam >= num_contacts || (DWORD)lParam < 0) + return 1; + if(DBWriteContactSettingDword((HANDLE)wParam, META_PROTO, "Default", (DWORD)lParam)) + return 1; + + NotifyEventHooks(hEventDefaultChanged, wParam, (LPARAM)Meta_GetContactHandle((HANDLE)wParam, (int)lParam)); + return 0; +} + +//sets the default contact, using the subcontact's handle +//wParam=(HANDLE)hMetaContact +//lParam=(HANDLE)hSubcontact +//returns 0 on success +INT_PTR MetaAPI_SetDefaultContact(WPARAM wParam, LPARAM lParam) { + HANDLE hMeta = (HANDLE)DBGetContactSettingDword((HANDLE)lParam, META_PROTO, "Handle", 0); + DWORD contact_number = Meta_GetContactNumber((HANDLE)lParam); + if(contact_number == -1 || !hMeta || hMeta != (HANDLE)wParam) + return 1; + if(DBWriteContactSettingDword(hMeta, META_PROTO, "Default", contact_number)) + return 1; + + NotifyEventHooks(hEventDefaultChanged, wParam, lParam); + return 0; +} + +//forces the metacontact to send using a specific subcontact, using the subcontact's contact number +//wParam=(HANDLE)hMetaContact +//lParam=(DWORD)contact number +//returns 0 on success +INT_PTR MetaAPI_ForceSendContactNum(WPARAM wParam, LPARAM lParam) { + HANDLE hContact = Meta_GetContactHandle((HANDLE)wParam, (int)lParam); + HANDLE hMeta = (HANDLE)DBGetContactSettingDword(hContact, META_PROTO, "Handle", 0); + if(!hContact || !hMeta || hMeta != (HANDLE)wParam || DBGetContactSettingByte(hMeta, META_PROTO, "ForceDefault", 0)) + return 1; + + DBWriteContactSettingDword(hMeta, META_PROTO, "ForceSend", (DWORD)hContact); + + NotifyEventHooks(hEventForceSend, wParam, (LPARAM)hContact); + return 0; +} + +//forces the metacontact to send using a specific subcontact, using the subcontact's handle +//wParam=(HANDLE)hMetaContact +//lParam=(HANDLE)hSubcontact +//returns 0 on success (will fail if 'force default' is in effect) +INT_PTR MetaAPI_ForceSendContact(WPARAM wParam, LPARAM lParam) { + HANDLE hContact = (HANDLE)lParam; + HANDLE hMeta = (HANDLE)DBGetContactSettingDword(hContact, META_PROTO, "Handle", 0); + if(!hContact || !hMeta || hMeta != (HANDLE)wParam || DBGetContactSettingByte(hMeta, META_PROTO, "ForceDefault", 0)) + return 1; + + DBWriteContactSettingDword(hMeta, META_PROTO, "ForceSend", (DWORD)hContact); + + NotifyEventHooks(hEventForceSend, wParam, lParam); + return 0; +} + +//'unforces' the metacontact to send using a specific subcontact +//wParam=(HANDLE)hMetaContact +//lParam=0 +//returns 0 on success (will fail if 'force default' is in effect) +INT_PTR MetaAPI_UnforceSendContact(WPARAM wParam, LPARAM lParam) { + if(DBGetContactSettingByte((HANDLE)wParam, META_PROTO, "ForceDefault", 0)) + return 1; + + DBWriteContactSettingDword((HANDLE)wParam, META_PROTO, "ForceSend", 0); + + NotifyEventHooks(hEventUnforceSend, wParam, lParam); + return 0; +} + + +//'forces' or 'unforces' (i.e. toggles) the metacontact to send using it's default contact +// overrides 'force send' above, and will even force use of offline contacts +// will send ME_MC_FORCESEND event +//wParam=(HANDLE)hMetaContact +//lParam=0 +//returns 1(true) or 0(false) representing new state of 'force default' +INT_PTR MetaAPI_ForceDefault(WPARAM wParam, LPARAM lParam) { + // forward to menu function + Meta_ForceDefault(wParam, lParam); + return DBGetContactSettingByte((HANDLE)wParam, META_PROTO, "ForceDefault", 0); +} + +// method to get state of 'force' for a metacontact +// wParam=(HANDLE)hMetaContact +// lParam= (DWORD)&contact_number or NULL +// if lparam supplied, the contact_number of the contatct 'in force' will be copied to the address it points to, +// or if none is in force, the value (DWORD)-1 will be copied +// (v0.8.0.8+ returns 1 if 'force default' is true with *lParam == default contact number, else returns 0 with *lParam as above) +INT_PTR MetaAPI_GetForceState(WPARAM wParam, LPARAM lParam) { + HANDLE hMeta = (HANDLE)wParam; + HANDLE hContact; + + if(!hMeta) return 0; + + if(DBGetContactSettingByte(hMeta, META_PROTO, "ForceDefault", 0)) { + if(lParam) *(DWORD *)lParam = DBGetContactSettingDword((HANDLE)wParam, META_PROTO, "Default", -1); + return 1; + } + + hContact = (HANDLE)DBGetContactSettingDword(hMeta, META_PROTO, "ForceSend", 0); + + if(!hContact) { + if(lParam) *(DWORD *)lParam = -1; + } else { + if(lParam) *(DWORD *)lParam = (DWORD)Meta_GetContactNumber(hContact); + } + + return 0; +} + +// method to get protocol name - used to be sure you're dealing with a "real" metacontacts plugin :) +// wParam=lParam=0 +INT_PTR MetaAPI_GetProtoName(WPARAM wParam, LPARAM lParam) { + return (int)META_PROTO; +} + +// added 0.9.5.0 (22/3/05) +// wParam=(HANDLE)hContact +// lParam=0 +// convert a given contact into a metacontact +INT_PTR MetaAPI_ConvertToMeta(WPARAM wParam, LPARAM lParam) { + return Meta_Convert(wParam, lParam); +} + +// added 0.9.5.0 (22/3/05) +// wParam=(HANDLE)hContact +// lParam=(HANDLE)hMeta +// add an existing contact to a metacontact +INT_PTR MetaAPI_AddToMeta(WPARAM wParam, LPARAM lParam) { + return Meta_Assign((HANDLE)wParam, (HANDLE)lParam, FALSE); +} + +// added 0.9.5.0 (22/3/05) +// wParam=0 +// lParam=(HANDLE)hContact +// remove a contact from a metacontact +INT_PTR MetaAPI_RemoveFromMeta(WPARAM wParam, LPARAM lParam) { + // notice we switch args - to keep the API function consistent with the others + return Meta_Delete((WPARAM)lParam, (LPARAM)wParam); +} + +// added 0.9.13.2 (6/10/05) +// wParam=(BOOL)disable +// lParam=0 +// enable/disable the 'hidden group hack' - for clists that support subcontact hiding using 'IsSubcontact' setting +// should be called once in your 'onmodulesloaded' event handler + +BOOL meta_group_hack_disabled = FALSE; // this global flag is used in utils 'SetGroup' function + +INT_PTR MetaAPI_DisableHiddenGroup(WPARAM wParam, LPARAM lParam) { + meta_group_hack_disabled = (BOOL)wParam; + return 0; +} diff --git a/plugins/MetaContacts/meta_convert.ico b/plugins/MetaContacts/meta_convert.ico new file mode 100644 index 0000000000..747d9d1d18 Binary files /dev/null and b/plugins/MetaContacts/meta_convert.ico differ diff --git a/plugins/MetaContacts/meta_edit.ico b/plugins/MetaContacts/meta_edit.ico new file mode 100644 index 0000000000..2992671618 Binary files /dev/null and b/plugins/MetaContacts/meta_edit.ico differ diff --git a/plugins/MetaContacts/meta_main.c b/plugins/MetaContacts/meta_main.c new file mode 100644 index 0000000000..eea5e0666e --- /dev/null +++ b/plugins/MetaContacts/meta_main.c @@ -0,0 +1,270 @@ +/* +MetaContacts Plugin for Miranda IM. + +Copyright © 2004 Universite Louis PASTEUR, STRASBOURG. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/** @file meta_main.c +* +* Functions used by Miranda to launch the plugin. +* Centralizes functions needed by Miranda to get +* information about the plugin and to initialize it +* and to dispose of it properly. +*/ + +/*! \mainpage MetaContacts plugin + * \image html ulp.gif + * \section desc Description + * This library is a plugin for Miranda IM.\n + * It allows the user to group several contacts from different + * protocols (such as AIM or ICQ) into one unique metacontact.\n + * + * \section principle How does it work ? + * Only one protocol will be used at a time (the default protocol).\n + * This protocol is referenced in the proper field of the MetaContact + * section in the Database. + * + * \subsection send Emission of messages + * The plugin will search through the Database to get the default protocol + * (i.e. the protocol used to communicate with),\n and then call the Send function + * provided by this protocol. + * + * \subsection recv Reception of messages + * When a contact is converted to a metacontact, or when it is added to an existing + * metacontact, it gets a pseudo protocol \n (named "MetaContacts") in the protocol chain.\n + * Usually, when a message is received, all the protocols in the chain get this message, + * the real protocol (for example ICQ) at the end.\n But here, the message will be intercepted + * by the MetaContact protocol, which will inhibit the further reception.\n The message will + * then be redirected to the MetaContact, that will display it normally. + * + * \subsection handling Handling MetaContacts + * There are four functionnality for handling MetaContacts : + * \li Convert a contact to a MetaContact. + * \li Add a contact to an existing MetaContact. + * \li Edit a MetaContact. + * \li Delete a MetaContact. + * + * They all are accessible via the context-menu displayed when a right click has occured, + * but not at the same time : The 2 first will appear when the menu concerns a simple contact.\n + * whereas the 2 last are only accessible from a MetaContact.\n + * Those functions are self-explanatory, and a MessageBox is shown before any modification, so, for + * further information, take a look at the Dialogs shown when they are called.\n + * + * \section cvats Caveats + * Several functionnalities have not yet been developped : + * \li Assigning contacts by Drag'n'Drop + * \li Updating dynamically the status of the MetaContact + * \li Merging history of all the contacts attached to MetaContact + * \li Handling Files and URLs as well as Messages + * \li and some other little functionnalities... + * + * Some of those functionnalities will not be developped due to the architecture + * of Miranda (the 2 first, for example) + * + * \section mail Contact + * For any comment, suggestion or question, send a mail to shaalj@free.fr.\n + * This code is provided as-is, and I cannot be held responsible for any harm + * done to your database by this plugin.\n + * Test it first on a fake database before using it normally. + */ + +#include "metacontacts.h" + +// Use VersionNo.h to set the version number, and ensure resource file is not open +#include "version.h" + +struct MM_INTERFACE mmi; +BOOL os_unicode_enabled = FALSE; +int hLangpack; + +//! Information gathered by Miranda, displayed in the plugin pane of the Option Dialog +PLUGININFOEX pluginInfo={ + sizeof(PLUGININFOEX), + __PLUGIN_NAME, // altered here and on file listing, so as not to match original + PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM), + __DESC, + __AUTHOR, + __AUTHOREMAIL, + __COPYRIGHT, + __AUTHORWEB, + 0, + 0, + { 0x4c4a27cf, 0x5e64, 0x4242, { 0xa3, 0x32, 0xb9, 0x8b, 0x8, 0x24, 0x3e, 0x89 } } // {4C4A27CF-5E64-4242-A332-B98B08243E89} +}; + +HINSTANCE hInstance; //!< Global reference to the application +PLUGINLINK *pluginLink; //!< Link between Miranda and this plugin + +/** Called by Miranda to get the information associated to this plugin. +* It only returns the PLUGININFO structure, without any test on the version +* @param mirandaVersion The version of the application calling this function +*/ +__declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) +{ + if ( mirandaVersion < PLUGIN_MAKE_VERSION( 0, 8, 0, 0 )) { + MessageBox( NULL, _T("The MetaContacts cannot be loaded. It requires Miranda IM 0.8.0.0 or later."), _T("Miranda"), MB_OK|MB_ICONWARNING|MB_SETFOREGROUND|MB_TOPMOST ); + return NULL; + } + return &pluginInfo; +} + +static const MUUID interfaces[] = {MIID_PROTOCOL, MIID_METACONTACTS, MIID_LAST}; +__declspec(dllexport) const MUUID* MirandaPluginInterfaces(void) +{ + return interfaces; +} + + +/** DLL entry point +* Required to store the instance handle +*/ +BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved) +{ + hInstance=hinstDLL; + DisableThreadLibraryCalls(hInstance); + return TRUE; +} + +/** Prepare the plugin to stop +* Called by Miranda when it will exit or when the plugin gets deselected +*/ +__declspec(dllexport)int Unload(void) +{ + // see also meta_services.c, Meta_PreShutdown + Meta_CloseHandles(); + //MessageBox(0, "Unload complete", "MC", MB_OK); + return 0; +} + +BOOL IsUnicodeOS() +{ + OSVERSIONINFOW os; + memset(&os, 0, sizeof(OSVERSIONINFOW)); + os.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW); + return (GetVersionExW(&os) != 0); +} + +/** Initializes the services provided and the link to those needed +* Called when the plugin is loaded into Miranda +*/ +int __declspec(dllexport)Load(PLUGINLINK *link) +{ + PROTOCOLDESCRIPTOR pd; + DBVARIANT dbv; + + pluginLink=link; + + mir_getMMI(&mmi); + mir_getLP(&pluginInfo); + + os_unicode_enabled = IsUnicodeOS(); + + if(ServiceExists(MS_DB_SETSETTINGRESIDENT)) { // 0.6+ + CallService(MS_DB_SETSETTINGRESIDENT, TRUE, (LPARAM)(META_PROTO "/Status")); + CallService(MS_DB_SETSETTINGRESIDENT, TRUE, (LPARAM)(META_PROTO "/IdleTS")); + CallService(MS_DB_SETSETTINGRESIDENT, TRUE, (LPARAM)(META_PROTO "/ContactCountCheck")); + CallService(MS_DB_SETSETTINGRESIDENT, TRUE, (LPARAM)(META_PROTO "/Handle")); + CallService(MS_DB_SETSETTINGRESIDENT, TRUE, (LPARAM)(META_PROTO "/WindowOpen")); + } + + //set all contacts to 'offline', and initialize subcontact counter for db consistency check + { + HANDLE hContact = (HANDLE)CallService( MS_DB_CONTACT_FINDFIRST, 0, 0); + char *proto; + while(hContact != NULL) { + //proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + if(!DBGetContactSetting(hContact, "Protocol", "p", &dbv)) { + proto = dbv.pszVal; + if (proto && !lstrcmp( META_PROTO, proto)) { + DBWriteContactSettingWord(hContact, META_PROTO, "Status", ID_STATUS_OFFLINE); + DBWriteContactSettingDword(hContact, META_PROTO, "IdleTS", 0); + DBWriteContactSettingByte(hContact, META_PROTO, "ContactCountCheck", 0); + + // restore any saved defaults that might have remained if miranda was closed or crashed while a convo was happening + if(DBGetContactSettingDword(hContact, META_PROTO, "SavedDefault", (DWORD)-1) != (DWORD)-1) { + DBWriteContactSettingDword(hContact, META_PROTO, "Default", DBGetContactSettingDword(hContact, META_PROTO, "SavedDefault", 0)); + DBWriteContactSettingDword(hContact, META_PROTO, "SavedDefault", (DWORD)-1); + } + + } + DBFreeVariant(&dbv); + } + + hContact = ( HANDLE )CallService( MS_DB_CONTACT_FINDNEXT,( WPARAM )hContact, 0 ); + } + } + + Meta_ReadOptions(&options); + + + // sets subcontact handles to metacontacts, and metacontact handles to subcontacts + // (since these handles are not necessarily the same from run to run of miranda) + + // also verifies that subcontacts: have metacontacts, and that contact numbers are reasonable, + // that metacontacts: have the correct number of subcontacts, and have reasonable defaults + if(Meta_SetHandles()) { + // error - db corruption + if(!DBGetContactSettingByte(0, META_PROTO, "DisabledMessageShown", 0)) { + MessageBox(0, Translate("Error - Database corruption.\nPlugin disabled."), Translate("MetaContacts"), MB_OK | MB_ICONERROR); + DBWriteContactSettingByte(0, META_PROTO, "DisabledMessageShown", 1); + } + //Meta_HideMetaContacts(TRUE); + return 1; + } + + DBDeleteContactSetting(0, META_PROTO, "DisabledMessageShown"); + + // add our modules to the KnownModules list + { + DBVARIANT dbv; + if (DBGetContactSetting(NULL, "KnownModules", META_PROTO, &dbv)) + DBWriteContactSettingString(NULL, "KnownModules", META_PROTO, META_PROTO); + else + DBFreeVariant(&dbv); + } + + ZeroMemory(&pd,sizeof(pd)); + pd.cbSize=PROTOCOLDESCRIPTOR_V3_SIZE;//sizeof(pd); + + pd.szName=META_FILTER; + pd.type=PROTOTYPE_FILTER; + CallService(MS_PROTO_REGISTERMODULE,0,(LPARAM)&pd); + + ZeroMemory(&pd,sizeof(pd)); + pd.cbSize=PROTOCOLDESCRIPTOR_V3_SIZE;//sizeof(pd); + + pd.szName=META_PROTO; + pd.type = PROTOTYPE_PROTOCOL; + CallService(MS_PROTO_REGISTERMODULE,0,(LPARAM)&pd); + + // further db setup done in modules loaded (nick [protocol string required] & clist display name) + + Meta_InitServices(); + + // moved to 'modules loaded' event handler (in meta_services.c) because we need to + // check protocol for jabber hack, and the proto modules must be loaded + //Meta_HideLinkedContactsAndSetHandles(); + + if(ServiceExists(MS_MSG_GETWINDOWAPI)) { + message_window_api_enabled = TRUE; + } + + // for clist_meta_mw - write hidden group name to DB + DBWriteContactSettingString(0, META_PROTO, "HiddenGroupName", META_HIDDEN_GROUP); + + return 0; +} diff --git a/plugins/MetaContacts/meta_menu.c b/plugins/MetaContacts/meta_menu.c new file mode 100644 index 0000000000..36caabffa7 --- /dev/null +++ b/plugins/MetaContacts/meta_menu.c @@ -0,0 +1,562 @@ +/* +MetaContacts Plugin for Miranda IM. + +Copyright © 2004 Universite Louis PASTEUR, STRASBOURG. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/** @file meta_menu.c +* +* Functions needed to handle MetaContacts. +* Centralizes functions called when the user chooses +* an option integrated in the context-menu of the \c CList. +*/ + +#include "metacontacts.h" + +/** Convert the contact chosen into a MetaContact. +* +* Create a new MetaContact, remove the selected contact from the \c CList +* and attach it to the MetaContact. +* +* @param wParam : \c HANDLE to the contact that has been chosen. +* @param lParam : Allways set to 0. +*/ +INT_PTR Meta_Convert(WPARAM wParam,LPARAM lParam) +{ + HANDLE hMetaContact; + DBVARIANT dbv; + char *group = 0;//, *proto; + + // Get some information about the selected contact. +// proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO,wParam,0); + if(!DBGetContactSettingStringUtf((HANDLE)wParam,"CList","Group",&dbv)) { + group = _strdup(dbv.pszVal); + DBFreeVariant(&dbv); + } + + // Create a new metacontact + hMetaContact = (HANDLE)CallService(MS_DB_CONTACT_ADD,0,0); + + // Add the info for the metacontact + if(hMetaContact) + { + + DBWriteContactSettingDword(hMetaContact,META_PROTO,META_ID,nextMetaID); + DBWriteContactSettingDword(hMetaContact,META_PROTO,"NumContacts",0); + DBWriteContactSettingDword(NULL,META_PROTO,"NextMetaID",++nextMetaID); + + // Add the MetaContact protocol to the new meta contact + CallService( MS_PROTO_ADDTOCONTACT, ( WPARAM )hMetaContact, ( LPARAM )META_PROTO ); + + if(group) { + if(ServiceExists(MS_DB_CONTACT_GETSETTING_STR)) + DBWriteContactSettingStringUtf(hMetaContact,"CList","Group",group); + else + DBWriteContactSettingString(hMetaContact,"CList","Group",group); + } + + // Assign the contact to the MetaContact just created (and make default). + if(!Meta_Assign((HANDLE)wParam,hMetaContact,TRUE)) { + MessageBox(0,Translate("There was a problem in assigning the contact to the MetaContact"),Translate("Error"),MB_ICONEXCLAMATION); + CallService(MS_DB_CONTACT_DELETE, (WPARAM)hMetaContact, 0); + return 0; + } + + // hide the contact if clist groups disabled (shouldn't create one anyway since menus disabled) + if(!Meta_IsEnabled()) + DBWriteContactSettingByte(hMetaContact, "CList", "Hidden", 1); + + } + + // Update the graphics + CallService(MS_CLUI_SORTLIST,0,0); + + free(group); + return (int)hMetaContact; +} + +/** Display the 'Add to' Dialog +* +* Present a dialog in which the user can choose to which MetaContact this +* contact will be added +* +* @param wParam : \c HANDLE to the contact that has been chosen. +* @param lParam : Allways set to 0. +*/ +INT_PTR Meta_AddTo(WPARAM wParam, LPARAM lParam) +{ + HWND clui = (HWND)CallService(MS_CLUI_GETHWND,0,0); + DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_METASELECT),clui,&Meta_SelectDialogProc,(LPARAM)wParam); + return 0; +} + +/** Display the 'Edit' Dialog +* +* Present a dialog in which the user can edit some properties of the MetaContact. +* +* @param wParam : \c HANDLE to the MetaContact to be edited. +* @param lParam : Allways set to 0. +*/ +INT_PTR Meta_Edit(WPARAM wParam,LPARAM lParam) +{ + HWND clui = (HWND)CallService(MS_CLUI_GETHWND,0,0); + DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_METAEDIT),clui,Meta_EditDialogProc,(LPARAM)wParam); + return 0; +} + +/* DB/Contact/WriteSetting service +Change the value of, or create a new value with, a named setting for a specific +contact in the database to the given value + wParam=(WPARAM)(HANDLE)hContact + lParam=(LPARAM)(DBCONTACTWRITESETTING*)&dbcws +hContact should have been returned by find*contact or addcontact +Returns 0 on success or nonzero if hContact was invalid +Note that DBCONTACTGETSETTING takes a pointer to a DBVARIANT, whereas +DBCONTACTWRITESETTING contains a DBVARIANT. +Because this is such a common function there are some short helper function at +the bottom of this header that use it. +Triggers a db/contact/settingchanged event just before it returns. +*/ +//typedef struct { +// const char *szModule; // pointer to name of the module that wrote the +// // setting to get +// const char *szSetting; // pointer to name of the setting to get +// DBVARIANT value; // variant containing the value to set +//} DBCONTACTWRITESETTING; +//#define MS_DB_CONTACT_WRITESETTING "DB/Contact/WriteSetting" + +void Meta_RemoveContactNumber(HANDLE hMeta, int number) { + int i, num_contacts, default_contact; + HANDLE hContact;//, handle; + + char buffer[512], buffer2[512]; + + num_contacts = DBGetContactSettingDword(hMeta, META_PROTO, "NumContacts", 0); + default_contact = DBGetContactSettingDword(hMeta, META_PROTO, "Default", -1); + if(number >= 0 && number < num_contacts) { + + // get the handle + hContact = Meta_GetContactHandle(hMeta, number); + + // make sure this contact thinks it's part of this metacontact + if((HANDLE)DBGetContactSettingDword(hContact,META_PROTO,"Handle", 0) == hMeta) { + + // remove link to meta contact + DBDeleteContactSetting(hContact,META_PROTO,"IsSubcontact"); + DBDeleteContactSetting(hContact,META_PROTO,META_LINK); + DBDeleteContactSetting(hContact,META_PROTO,"Handle"); + DBDeleteContactSetting(hContact,META_PROTO,"ContactNumber"); + // unhide - must be done after removing link (see meta_services.c:Meta_ChangeStatus) + Meta_RestoreGroup(hContact); + DBDeleteContactSetting(hContact,META_PROTO,"OldCListGroup"); + //CallService(MS_PROTO_REMOVEFROMCONTACT,(WPARAM)hContact,(LPARAM)META_PROTO); + CallService(MS_PROTO_REMOVEFROMCONTACT,(WPARAM)hContact,(LPARAM)META_FILTER); + // stop ignoring, if we were + if(options.suppress_status) + CallService(MS_IGNORE_UNIGNORE, (WPARAM)hContact, (WPARAM)IGNOREEVENT_USERONLINE); + } + + // remove history from metacontact + //Meta_RemoveHistory(hMeta, hContact); + + // each contact from 'number' upwards will be moved down one + // and the last one will be deleted + for(i = number + 1; i < num_contacts; i++) { + Meta_SwapContacts(hMeta, i, i-1); + } + + // remove the last one + strcpy(buffer, "Protocol"); + strcat(buffer, _itoa((num_contacts - 1), buffer2, 10)); + DBDeleteContactSetting(hMeta, META_PROTO, buffer); + strcpy(buffer, "Status"); + strcat(buffer, _itoa((num_contacts - 1), buffer2, 10)); + DBDeleteContactSetting(hMeta, META_PROTO, buffer); + strcpy(buffer, "Handle"); + strcat(buffer, _itoa((num_contacts - 1), buffer2, 10)); + DBDeleteContactSetting(hMeta, META_PROTO, buffer); + strcpy(buffer, "StatusString"); + strcat(buffer, _itoa((num_contacts - 1), buffer2, 10)); + DBDeleteContactSetting(hMeta, META_PROTO, buffer); + strcpy(buffer, "Login"); + strcat(buffer, _itoa((num_contacts - 1), buffer2, 10)); + DBDeleteContactSetting(hMeta, META_PROTO, buffer); + strcpy(buffer, "Nick"); + strcat(buffer, _itoa((num_contacts - 1), buffer2, 10)); + DBDeleteContactSetting(hMeta, META_PROTO, buffer); + strcpy(buffer, "CListName"); + strcat(buffer, _itoa((num_contacts - 1), buffer2, 10)); + DBDeleteContactSetting(hMeta, META_PROTO, buffer); + + // if the default contact was equal to or greater than 'number', decrement it (and deal with ends) + if(default_contact >= number) { + default_contact--; + if(default_contact < 0) + default_contact = 0; + + DBWriteContactSettingDword(hMeta, META_PROTO, "Default", (DWORD)default_contact); + NotifyEventHooks(hEventDefaultChanged, (WPARAM)hMeta, (LPARAM)Meta_GetContactHandle(hMeta, default_contact)); + } + num_contacts--; + DBWriteContactSettingDword(hMeta, META_PROTO, "NumContacts", (DWORD)num_contacts); + + // fix nick + hContact = Meta_GetMostOnline(hMeta); + Meta_CopyContactNick(hMeta, hContact); + + // fix status + Meta_FixStatus(hMeta); + + // fix avatar + hContact = Meta_GetMostOnlineSupporting(hMeta, PFLAGNUM_4, PF4_AVATARS); + if(hContact) { + PROTO_AVATAR_INFORMATION AI; + + AI.cbSize = sizeof(AI); + AI.hContact = hMeta; + AI.format = PA_FORMAT_UNKNOWN; + strcpy(AI.filename, "X"); + + if((int)CallProtoService(META_PROTO, PS_GETAVATARINFO, 0, (LPARAM)&AI) == GAIR_SUCCESS) + DBWriteContactSettingString(hMeta, "ContactPhoto", "File",AI.filename); + } + } +} + +/** Delete a MetaContact from the database +* +* Delete a MetaContact and remove all the information +* concerning this MetaContact in the contact linked to it. +* +* @param wParam : \c HANDLE to the MetaContact to be deleted, or to the subcontact to be removed from the MetaContact +* @param lParam : \c BOOL flag indicating whether to ask 'are you sure' when deleting a MetaContact +*/ +INT_PTR Meta_Delete(WPARAM wParam,LPARAM lParam) +{ + DWORD metaID; + HANDLE hContact; + + if((metaID=DBGetContactSettingDword((HANDLE)wParam,META_PROTO,META_ID,(DWORD)-1))!=(DWORD)-1) + {// The wParam is a metacontact + if(!lParam) { // check from recursion - see second half of this function + if(MessageBox((HWND)CallService(MS_CLUI_GETHWND,0,0),Translate("This will remove the MetaContact permanently.\n\nProceed Anyway?"), + Translate("Are you sure?"),MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2)!=IDYES) + { + return 0; + } + } + + hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST,0,0); + while(hContact) + { // Scans the database to get all the contacts that have been previously linked to this MetaContact + if(DBGetContactSettingDword(hContact,META_PROTO,META_LINK,(DWORD)-1)==metaID) + { // This contact is assigned to the MetaContact that will be deleted, clear the "MetaContacts" information + DBDeleteContactSetting(hContact,META_PROTO,"IsSubcontact"); + DBDeleteContactSetting(hContact,META_PROTO,META_LINK); + DBDeleteContactSetting(hContact,META_PROTO,"Handle"); + DBDeleteContactSetting(hContact,META_PROTO,"ContactNumber"); + // unhide - must be done after removing link (see meta_services.c:Meta_ChangeStatus) + Meta_RestoreGroup(hContact); + DBDeleteContactSetting(hContact,META_PROTO,"OldCListGroup"); + + CallService(MS_PROTO_REMOVEFROMCONTACT,(WPARAM)hContact,(LPARAM)META_FILTER); + // stop ignoring, if we were + if(options.suppress_status) + CallService(MS_IGNORE_UNIGNORE, (WPARAM)hContact, (WPARAM)IGNOREEVENT_USERONLINE); + } + hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT,(WPARAM)hContact,0); + } + //DBDeleteContactSetting((HANDLE)wParam, META_PROTO, META_ID); + //DBDeleteContactSetting((HANDLE)wParam, META_PROTO, "NumContacts"); + //CallService(MS_PROTO_REMOVEFROMCONTACT,wParam,(LPARAM)META_PROTO); + NotifyEventHooks(hSubcontactsChanged, (WPARAM)wParam, 0); + CallService(MS_DB_CONTACT_DELETE,wParam,0); + } + else + {// The wParam is a simple contact + //if(lParam == 0) + // return 1; // The function has been called by the menu of a simple contact. Should not happen. + //else + {// The function has been called by the edit dialog + HANDLE hMeta = (HANDLE)DBGetContactSettingDword((HANDLE)wParam, META_PROTO, "Handle", 0); + + + DWORD num_contacts = DBGetContactSettingDword(hMeta, META_PROTO, "NumContacts", -1); + + if(num_contacts == 1) { + if(MessageBox(0,Translate("You are going to remove all the contacts associated with this MetaContact.\nThis will delete the MetaContact.\n\nProceed Anyway?"), + Translate("Delete MetaContact?"),MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON1)==IDYES) + { + // recurse - once + Meta_Delete((WPARAM)hMeta,(LPARAM)1); + } + return 0; + } + + Meta_RemoveContactNumber(hMeta, DBGetContactSettingDword((HANDLE)wParam,META_PROTO,"ContactNumber", -1)); + + CallService(MS_PROTO_REMOVEFROMCONTACT,(WPARAM)wParam,(LPARAM)META_FILTER); + } + } + return 0; +} + +/** Set contact as MetaContact default +* +* Set the given contact to be the default one for the metacontact to which it is linked. +* +* @param wParam : \c HANDLE to the MetaContact to be set as default +* @param lParam : \c HWND to the clist window + (This means the function has been called via the contact menu). +*/ +INT_PTR Meta_Default(WPARAM wParam,LPARAM lParam) +{ + HANDLE hMeta; + + if((hMeta = (HANDLE)DBGetContactSettingDword((HANDLE)wParam,META_PROTO,"Handle",0)) != 0) + { // the wParam is a subcontact + DBWriteContactSettingDword(hMeta, META_PROTO, "Default", (DWORD)Meta_GetContactNumber((HANDLE)wParam)); + NotifyEventHooks(hEventDefaultChanged, (WPARAM)hMeta, (LPARAM)(HANDLE)wParam); + } + return 0; +} + +/** Set/unset (i.e. toggle) contact to force use of default contact +* +* Set the given contact to be the default one for the metacontact to which it is linked. +* +* @param wParam : \c HANDLE to the MetaContact to be set as default +* @param lParam : \c HWND to the clist window + (This means the function has been called via the contact menu). +*/ +INT_PTR Meta_ForceDefault(WPARAM wParam,LPARAM lParam) +{ + if(DBGetContactSettingDword((HANDLE)wParam,META_PROTO, META_ID, (DWORD)-1) != (DWORD)-1) + { // the wParam is a MetaContact + + BOOL current = DBGetContactSettingByte((HANDLE)wParam, META_PROTO, "ForceDefault", 0); + current = !current; + DBWriteContactSettingByte((HANDLE)wParam, META_PROTO, "ForceDefault", (BYTE)current); + + DBWriteContactSettingDword((HANDLE)wParam, META_PROTO, "ForceSend", 0); + + if(current) NotifyEventHooks(hEventForceSend, wParam, (LPARAM)Meta_GetContactHandle((HANDLE)wParam, DBGetContactSettingDword((HANDLE)wParam, META_PROTO, "Default", -1))); + else NotifyEventHooks(hEventUnforceSend, wParam, 0); + } + return 0; +} + +INT_PTR MenuFunc0(WPARAM wParam, LPARAM lParam) {return TranslateMenuFunc((HANDLE)wParam, 0);} +INT_PTR MenuFunc1(WPARAM wParam, LPARAM lParam) {return TranslateMenuFunc((HANDLE)wParam, 1);} +INT_PTR MenuFunc2(WPARAM wParam, LPARAM lParam) {return TranslateMenuFunc((HANDLE)wParam, 2);} +INT_PTR MenuFunc3(WPARAM wParam, LPARAM lParam) {return TranslateMenuFunc((HANDLE)wParam, 3);} +INT_PTR MenuFunc4(WPARAM wParam, LPARAM lParam) {return TranslateMenuFunc((HANDLE)wParam, 4);} +INT_PTR MenuFunc5(WPARAM wParam, LPARAM lParam) {return TranslateMenuFunc((HANDLE)wParam, 5);} +INT_PTR MenuFunc6(WPARAM wParam, LPARAM lParam) {return TranslateMenuFunc((HANDLE)wParam, 6);} +INT_PTR MenuFunc7(WPARAM wParam, LPARAM lParam) {return TranslateMenuFunc((HANDLE)wParam, 7);} +INT_PTR MenuFunc8(WPARAM wParam, LPARAM lParam) {return TranslateMenuFunc((HANDLE)wParam, 8);} +INT_PTR MenuFunc9(WPARAM wParam, LPARAM lParam) {return TranslateMenuFunc((HANDLE)wParam, 9);} +INT_PTR MenuFunc10(WPARAM wParam, LPARAM lParam) {return TranslateMenuFunc((HANDLE)wParam, 10);} +INT_PTR MenuFunc11(WPARAM wParam, LPARAM lParam) {return TranslateMenuFunc((HANDLE)wParam, 11);} +INT_PTR MenuFunc12(WPARAM wParam, LPARAM lParam) {return TranslateMenuFunc((HANDLE)wParam, 12);} +INT_PTR MenuFunc13(WPARAM wParam, LPARAM lParam) {return TranslateMenuFunc((HANDLE)wParam, 13);} +INT_PTR MenuFunc14(WPARAM wParam, LPARAM lParam) {return TranslateMenuFunc((HANDLE)wParam, 14);} +INT_PTR MenuFunc15(WPARAM wParam, LPARAM lParam) {return TranslateMenuFunc((HANDLE)wParam, 15);} +INT_PTR MenuFunc16(WPARAM wParam, LPARAM lParam) {return TranslateMenuFunc((HANDLE)wParam, 16);} +INT_PTR MenuFunc17(WPARAM wParam, LPARAM lParam) {return TranslateMenuFunc((HANDLE)wParam, 17);} +INT_PTR MenuFunc18(WPARAM wParam, LPARAM lParam) {return TranslateMenuFunc((HANDLE)wParam, 18);} +INT_PTR MenuFunc19(WPARAM wParam, LPARAM lParam) {return TranslateMenuFunc((HANDLE)wParam, 19);} + +HANDLE hMenuContact[MAX_CONTACTS]; + +INT_PTR TranslateMenuFunc(HANDLE hMeta, int contact_number) { + return Meta_ContactMenuFunc((WPARAM)hMeta, (LPARAM) contact_number); +} + +/** Called when the context-menu of a contact is about to be displayed +* +* This will test which of the 4 menu item should be displayed, depending +* on which contact triggered the event +* +* @param wParam : \c HANDLE to the contact that triggered the event +* @param lParam : Always set to 0; +*/ +int Meta_ModifyMenu(WPARAM wParam, LPARAM lParam) +{ + CLISTMENUITEM mi; + DBVARIANT dbv; + HANDLE hContact; + char *proto; + char buf[512], buffer2[512]; + int i, iconIndex; + WORD status; + + mi.flags = CMIM_FLAGS; + mi.cbSize = sizeof(CLISTMENUITEM); + + if(DBGetContactSettingDword((HANDLE)wParam,META_PROTO,META_ID,-1) != (DWORD)-1) + { + int num_contacts, i; + + // save the mouse pos in case they open a subcontact menu + GetCursorPos(&menuMousePoint); + + // This is a MetaContact, show the edit, force default, and the delete menu, and hide the others + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuEdit, (LPARAM)&mi); + //mi.flags |= CMIM_NAME; + //if(DBGetContactSettingByte((HANDLE)wParam, META_PROTO, "ForceDefault", 0)) + // mi.pszName = Translate("Unforce Default"); + //else + // mi.pszName = Translate("Force Default"); + //CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuForceDefault, (LPARAM)&mi); + mi.flags = CMIM_FLAGS | CMIF_HIDDEN; + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuAdd, (LPARAM)&mi); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuConvert, (LPARAM)&mi); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuDefault, (LPARAM)&mi); + mi.flags = CMIM_FLAGS | CMIM_NAME | CMIF_HIDDEN; // we don't need delete - already in contact menu + mi.pszName = Translate("Delete MetaContact"); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuDelete, (LPARAM)&mi); + + + //show subcontact menu items + num_contacts = DBGetContactSettingDword((HANDLE)wParam, META_PROTO, "NumContacts", 0); + for(i = 0; i < MAX_CONTACTS; i++) { + if(i < num_contacts) { + hContact = Meta_GetContactHandle((HANDLE)wParam, i); + proto = _strdup((char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0)); + + if(!proto) + status = ID_STATUS_OFFLINE; + else + status = DBGetContactSettingWord(hContact, proto, "Status", ID_STATUS_OFFLINE); + + if(options.menu_contact_label == DNT_UID) { + strcpy(buf, "Login"); + strcat(buf, _itoa(i, buffer2, 10)); + + DBGetContactSetting((HANDLE)wParam,META_PROTO,buf,&dbv); + switch(dbv.type) + { + case DBVT_ASCIIZ: + mir_snprintf(buf,512,"%s",dbv.pszVal); + break; + case DBVT_BYTE: + mir_snprintf(buf,512,"%d",dbv.bVal); + break; + case DBVT_WORD: + mir_snprintf(buf,512,"%d",dbv.wVal); + break; + case DBVT_DWORD: + mir_snprintf(buf,512,"%d",dbv.dVal); + break; + default: + buf[0] = 0; + } + DBFreeVariant(&dbv); + mi.pszName = buf; + mi.flags = 0; + } else { + char *name = (char *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, 0); + char *wname = (char *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_UNICODE); + + if(wname && strncmp(name, wname, strlen(name)) != 0) { + mi.pszName = wname; + mi.flags = CMIF_UNICODE; + } + else { + mi.pszName = name; + mi.flags = 0; + } + } + + mi.flags |= CMIM_FLAGS | CMIM_NAME | CMIM_ICON; + + //mi.hIcon = LoadSkinnedProtoIcon(proto, status); + iconIndex = (int)CallService(MS_CLIST_GETCONTACTICON, (WPARAM)hContact, 0); + mi.hIcon = ImageList_GetIcon((HIMAGELIST)CallService(MS_CLIST_GETICONSIMAGELIST, 0, 0), iconIndex, 0);; + + free(proto); + + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuContact[i], (LPARAM)&mi); + DestroyIcon(mi.hIcon); + //CallService(MS_SKIN2_RELEASEICON, (WPARAM)mi.hIcon, 0); + } else { + mi.flags = CMIM_FLAGS | CMIF_HIDDEN; + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuContact[i], (LPARAM)&mi); + } + } + + // show hide nudge menu item +#define MS_NUDGE_SHOWMENU "NudgeShowMenu" +// wParam = char *szProto +// lParam = BOOL show + { + char serviceFunc[256]; + hContact = Meta_GetMostOnline((HANDLE)wParam); + mir_snprintf(serviceFunc, 256, "%s/SendNudge", (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0)); + CallService(MS_NUDGE_SHOWMENU, (WPARAM)META_PROTO, (LPARAM)ServiceExists(serviceFunc)); + } + } + else + {// This is a simple contact + if(!Meta_IsEnabled()) + { + // groups disabled - all meta menu options hidden + mi.flags = CMIM_FLAGS | CMIF_HIDDEN; + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuDefault, (LPARAM)&mi); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuDelete, (LPARAM)&mi); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuAdd, (LPARAM)&mi); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuConvert, (LPARAM)&mi); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuEdit, (LPARAM)&mi); + for(i = 0; i < MAX_CONTACTS; i++) { + mi.flags = CMIM_FLAGS | CMIF_HIDDEN; + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuContact[i], (LPARAM)&mi); + } + + } else if(DBGetContactSettingDword((HANDLE)wParam,META_PROTO,META_LINK,(DWORD)-1)!=(DWORD)-1) { + // The contact is affected to a metacontact. + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuDefault, (LPARAM)&mi); + mi.flags |= CMIM_NAME; + mi.pszName = (char *)Translate("Remove from MetaContact"); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuDelete, (LPARAM)&mi); + mi.flags = CMIM_FLAGS | CMIF_HIDDEN; + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuAdd, (LPARAM)&mi); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuConvert, (LPARAM)&mi); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuEdit, (LPARAM)&mi); + for(i = 0; i < MAX_CONTACTS; i++) { + mi.flags = CMIM_FLAGS | CMIF_HIDDEN; + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuContact[i], (LPARAM)&mi); + } + } else { + // The contact is neutral + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuAdd, (LPARAM)&mi); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuConvert, (LPARAM)&mi); + mi.flags |= CMIF_HIDDEN; + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuEdit, (LPARAM)&mi); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuDelete, (LPARAM)&mi); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuDefault, (LPARAM)&mi); + for(i = 0; i < MAX_CONTACTS; i++) { + mi.flags = CMIM_FLAGS | CMIF_HIDDEN; + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuContact[i], (LPARAM)&mi); + } + } + } + return 0; +} + + + diff --git a/plugins/MetaContacts/meta_options.c b/plugins/MetaContacts/meta_options.c new file mode 100644 index 0000000000..6fd6aa47e5 --- /dev/null +++ b/plugins/MetaContacts/meta_options.c @@ -0,0 +1,640 @@ +/* +MetaContacts Plugin for Miranda IM. + +Copyright © 2004 Universite Louis PASTEUR, STRASBOURG. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/** @file meta_menu.c +* +* Functions needed to handle MetaContacts. +* Centralizes functions called when the user chooses +* an option integrated in the context-menu of the \c CList. +*/ + +#include "metacontacts.h" + +MetaOptions options; +MetaOptions options_changes; + +INT_PTR CALLBACK DlgProcOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + HWND hw; + char buff[512]; + + switch ( msg ) { + case WM_INITDIALOG: { + TranslateDialogDefault( hwndDlg ); + options_changes = options; + + CheckDlgButton(hwndDlg, IDC_CHK_SETDEFAULTRECV, options_changes.set_default_on_recv ? TRUE : FALSE); + hw = GetDlgItem(hwndDlg, IDC_CHK_TEMPDEFAULT); + EnableWindow(hw, options_changes.set_default_on_recv); + CheckDlgButton(hwndDlg, IDC_CHK_TEMPDEFAULT, options_changes.temp_default ? TRUE : FALSE); + + CheckDlgButton(hwndDlg, IDC_CHK_ALWAYSUSEDEFAULT, options_changes.always_use_default ? TRUE : FALSE); + CheckDlgButton(hwndDlg, IDC_CHK_SUPPRESSSTATUS, options_changes.suppress_status ? TRUE : FALSE); + CheckDlgButton(hwndDlg, IDC_CHK_SUPPRESSPROTO, options_changes.suppress_proto ? TRUE : FALSE); + + CheckDlgButton(hwndDlg, IDC_RAD_UID, options_changes.menu_contact_label == DNT_UID); + CheckDlgButton(hwndDlg, IDC_RAD_DID, options_changes.menu_contact_label == DNT_DID); + + CheckDlgButton(hwndDlg, IDC_RAD_MSG, options_changes.menu_function == FT_MSG); + CheckDlgButton(hwndDlg, IDC_RAD_MENU, options_changes.menu_function == FT_MENU); + CheckDlgButton(hwndDlg, IDC_RAD_INFO, options_changes.menu_function == FT_INFO); + + CheckDlgButton(hwndDlg, IDC_RAD_NICK, options_changes.clist_contact_name == CNNT_NICK); + CheckDlgButton(hwndDlg, IDC_RAD_NAME, options_changes.clist_contact_name == CNNT_DISPLAYNAME); + CheckDlgButton(hwndDlg, IDC_CHK_LOCKHANDLE, options_changes.lockHandle ? TRUE : FALSE); + CheckDlgButton(hwndDlg, IDC_CHK_SUBWINDOW, options_changes.subcontact_windows ? TRUE : FALSE); + + CheckDlgButton(hwndDlg, IDC_CHK_METAHISTORY, options_changes.metahistory ? TRUE : FALSE); + CheckDlgButton(hwndDlg, IDC_CHK_SUBHISTORY, options_changes.subhistory ? TRUE : FALSE); + CheckDlgButton(hwndDlg, IDC_CHK_COPYDATA, options_changes.copydata ? TRUE : FALSE); + + if(!options_changes.subcontact_windows) { + hw = GetDlgItem(hwndDlg, IDC_CHK_METAHISTORY); + EnableWindow(hw, FALSE); + } else { + hw = GetDlgItem(hwndDlg, IDC_CHK_SUBHISTORY); + EnableWindow(hw, FALSE); + } + + CheckDlgButton(hwndDlg, IDC_CHK_COPYHISTORY, options_changes.copy_subcontact_history ? TRUE : FALSE); + hw = GetDlgItem(hwndDlg, IDC_ED_DAYS); + _itoa(options_changes.days_history, buff, 10); + SetWindowText(hw, buff); + + return TRUE; + } + case WM_COMMAND: + if ( HIWORD( wParam ) == BN_CLICKED ) { + switch( LOWORD( wParam )) { + case IDC_CHK_SETDEFAULTRECV: + options_changes.set_default_on_recv = IsDlgButtonChecked(hwndDlg, IDC_CHK_SETDEFAULTRECV); + hw = GetDlgItem(hwndDlg, IDC_CHK_TEMPDEFAULT); + EnableWindow(hw, options_changes.set_default_on_recv); + SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); + break; + case IDC_CHK_TEMPDEFAULT: + hw = GetDlgItem(hwndDlg, IDC_CHK_TEMPDEFAULT); + options_changes.temp_default = IsDlgButtonChecked(hwndDlg, IDC_CHK_TEMPDEFAULT); + SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); + break; + case IDC_CHK_ALWAYSUSEDEFAULT: + hw = GetDlgItem(hwndDlg, IDC_CHK_ALWAYSUSEDEFAULT); + options_changes.always_use_default = IsDlgButtonChecked(hwndDlg, IDC_CHK_ALWAYSUSEDEFAULT); + SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); + break; + case IDC_CHK_SUPPRESSSTATUS: + hw = GetDlgItem(hwndDlg, IDC_CHK_SUPPRESSSTATUS); + options_changes.suppress_status = IsDlgButtonChecked(hwndDlg, IDC_CHK_SUPPRESSSTATUS); + SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); + break; + case IDC_CHK_SUPPRESSPROTO: + hw = GetDlgItem(hwndDlg, IDC_CHK_SUPPRESSPROTO); + options_changes.suppress_proto = IsDlgButtonChecked(hwndDlg, IDC_CHK_SUPPRESSPROTO); + SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); + break; + case IDC_CHK_COPYHISTORY: + hw = GetDlgItem(hwndDlg, IDC_CHK_COPYHISTORY); + options_changes.copy_subcontact_history = IsDlgButtonChecked(hwndDlg, IDC_CHK_COPYHISTORY); + SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); + break; + case IDC_CHK_METAHISTORY: + hw = GetDlgItem(hwndDlg, IDC_CHK_METAHISTORY); + options_changes.metahistory = IsDlgButtonChecked(hwndDlg, IDC_CHK_METAHISTORY); + SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); + break; + case IDC_CHK_SUBHISTORY: + hw = GetDlgItem(hwndDlg, IDC_CHK_SUBHISTORY); + options_changes.subhistory = IsDlgButtonChecked(hwndDlg, IDC_CHK_SUBHISTORY); + SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); + break; + case IDC_CHK_COPYDATA: + hw = GetDlgItem(hwndDlg, IDC_CHK_COPYDATA); + options_changes.copydata = IsDlgButtonChecked(hwndDlg, IDC_CHK_COPYDATA); + SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); + break; + case IDC_RAD_UID: + hw = GetDlgItem(hwndDlg, IDC_RAD_UID); + if(IsDlgButtonChecked(hwndDlg, IDC_RAD_UID)) { + options_changes.menu_contact_label = DNT_UID; + CheckDlgButton(hwndDlg, IDC_RAD_DID, FALSE); + } + SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); + break; + case IDC_RAD_DID: + hw = GetDlgItem(hwndDlg, IDC_RAD_DID); + if(IsDlgButtonChecked(hwndDlg, IDC_RAD_DID)) { + options_changes.menu_contact_label = DNT_DID; + CheckDlgButton(hwndDlg, IDC_RAD_UID, FALSE); + } + SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); + break; + case IDC_RAD_MSG: + hw = GetDlgItem(hwndDlg, IDC_RAD_MSG); + if(IsDlgButtonChecked(hwndDlg, IDC_RAD_MSG)) { + options_changes.menu_function = FT_MSG; + CheckDlgButton(hwndDlg, IDC_RAD_MENU, FALSE); + CheckDlgButton(hwndDlg, IDC_RAD_INFO, FALSE); + } + SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); + break; + case IDC_RAD_MENU: + hw = GetDlgItem(hwndDlg, IDC_RAD_MENU); + if(IsDlgButtonChecked(hwndDlg, IDC_RAD_MENU)) { + options_changes.menu_function = FT_MENU; + CheckDlgButton(hwndDlg, IDC_RAD_MSG, FALSE); + CheckDlgButton(hwndDlg, IDC_RAD_INFO, FALSE); + } + SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); + break; + case IDC_RAD_INFO: + hw = GetDlgItem(hwndDlg, IDC_RAD_INFO); + if(IsDlgButtonChecked(hwndDlg, IDC_RAD_INFO)) { + options_changes.menu_function = FT_INFO; + CheckDlgButton(hwndDlg, IDC_RAD_MSG, FALSE); + CheckDlgButton(hwndDlg, IDC_RAD_MENU, FALSE); + } + SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); + break; + case IDC_RAD_NICK: + hw = GetDlgItem(hwndDlg, IDC_RAD_NICK); + if(IsDlgButtonChecked(hwndDlg, IDC_RAD_NICK)) { + options_changes.clist_contact_name = CNNT_NICK; + CheckDlgButton(hwndDlg, IDC_RAD_NAME, FALSE); + } + SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); + break; + case IDC_RAD_NAME: + hw = GetDlgItem(hwndDlg, IDC_RAD_NAME); + if(IsDlgButtonChecked(hwndDlg, IDC_RAD_NAME)) { + options_changes.clist_contact_name = CNNT_DISPLAYNAME; + CheckDlgButton(hwndDlg, IDC_RAD_NICK, FALSE); + } + SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); + break; + case IDC_CHK_SUBWINDOW: + hw = GetDlgItem(hwndDlg, IDC_CHK_SUBWINDOW); + options_changes.subcontact_windows = IsDlgButtonChecked(hwndDlg, IDC_CHK_SUBWINDOW); + + if(options_changes.subcontact_windows) { + hw = GetDlgItem(hwndDlg, IDC_CHK_METAHISTORY); + EnableWindow(hw, TRUE); + hw = GetDlgItem(hwndDlg, IDC_CHK_SUBHISTORY); + CheckDlgButton(hwndDlg, IDC_CHK_SUBHISTORY, TRUE); + EnableWindow(hw, FALSE); + options_changes.subhistory = TRUE; + } else { + hw = GetDlgItem(hwndDlg, IDC_CHK_SUBHISTORY); + EnableWindow(hw, TRUE); + hw = GetDlgItem(hwndDlg, IDC_CHK_METAHISTORY); + CheckDlgButton(hwndDlg, IDC_CHK_METAHISTORY, TRUE); + EnableWindow(hw, FALSE); + options_changes.metahistory = TRUE; + } + SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); + break; + case IDC_CHK_LOCKHANDLE: + options_changes.lockHandle = IsDlgButtonChecked(hwndDlg, IDC_CHK_LOCKHANDLE); + SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); + break; + } + } else if ( HIWORD( wParam ) == EN_CHANGE && ( HWND )lParam == GetFocus()) { + SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); + } + break; + + case WM_NOTIFY: + if (((LPNMHDR)lParam)->code == PSN_APPLY ) { + hw = GetDlgItem(hwndDlg, IDC_ED_DAYS); + GetWindowText(hw, buff, 512); + if(strlen(buff) > 0) + options_changes.days_history = atoi(buff); + + options = options_changes; + Meta_WriteOptions(&options); + + Meta_SuppressStatus(options.suppress_status); + Meta_SetAllNicks(); + return TRUE; + } + break; + } + + return FALSE; +} + +int Meta_WriteOptions(MetaOptions *opt) { + DBWriteContactSettingByte(NULL, META_PROTO, "SetDefaultOnRecv", (BYTE)(opt->set_default_on_recv ? 1 : 0)); + DBWriteContactSettingByte(NULL, META_PROTO, "TempDefault", (BYTE)(opt->temp_default ? 1 : 0)); + DBWriteContactSettingByte(NULL, META_PROTO, "AlwaysUseDefault", (BYTE)(opt->always_use_default ? 1 : 0)); + DBWriteContactSettingByte(NULL, META_PROTO, "SuppressStatus", (BYTE)(opt->suppress_status ? 1 : 0)); + DBWriteContactSettingWord(NULL, META_PROTO, "MenuContactLabel", (WORD)opt->menu_contact_label); + DBWriteContactSettingWord(NULL, META_PROTO, "MenuContactFunction", (WORD)opt->menu_function); + DBWriteContactSettingWord(NULL, META_PROTO, "CListContactName", (WORD)opt->clist_contact_name); + DBWriteContactSettingByte(NULL, META_PROTO, "SuppressProto", (BYTE)(opt->suppress_proto ? 1 : 0)); + DBWriteContactSettingByte(NULL, META_PROTO, "CopyHistory", (BYTE)(opt->copy_subcontact_history ? 1 : 0)); + DBWriteContactSettingDword(NULL, META_PROTO, "DaysHistory", (DWORD)(opt->days_history)); + DBWriteContactSettingDword(NULL, META_PROTO, "SetStatusFromOfflineDelay", (DWORD)(opt->set_status_from_offline_delay)); + DBWriteContactSettingByte(NULL, META_PROTO, "SubcontactWindows", (BYTE)(opt->subcontact_windows ? 1 : 0)); + DBWriteContactSettingByte(NULL, META_PROTO, "CopyData", (BYTE)(opt->copydata ? 1 : 0)); + DBWriteContactSettingByte(NULL, META_PROTO, "LockHandle", (BYTE)(opt->lockHandle ? 1 : 0)); + DBWriteContactSettingByte(NULL, META_PROTO, "MetaMessageIcon", (BYTE)(opt->flash_meta_message_icon ? 1 : 0)); + DBWriteContactSettingByte(NULL, META_PROTO, "CopyUserInfo", (BYTE)(opt->copy_userinfo ? 1 : 0)); + + if(!opt->subcontact_windows) + DBWriteContactSettingByte(NULL, META_PROTO, "MetaHistory", 1); + else + DBWriteContactSettingByte(NULL, META_PROTO, "MetaHistory", (BYTE)(opt->metahistory ? 1 : 0)); + + if(opt->subcontact_windows) + DBWriteContactSettingByte(NULL, META_PROTO, "SubcontactHistory", 1); + else + DBWriteContactSettingByte(NULL, META_PROTO, "SubcontactHistory", (BYTE)(opt->subhistory ? 1 : 0)); + return 0; + + DBWriteContactSettingByte(NULL, META_PROTO, "UseProtoRecv", (BYTE)(opt->use_proto_recv ? 1 : 0)); +} + +int Meta_ReadOptions(MetaOptions *opt) { + opt->set_default_on_recv = (DBGetContactSettingByte(NULL, META_PROTO, "SetDefaultOnRecv", 1) == 1 ? TRUE : FALSE); + opt->temp_default = (DBGetContactSettingByte(NULL, META_PROTO, "TempDefault", 0) == 1 ? TRUE : FALSE); + opt->always_use_default = (DBGetContactSettingByte(NULL, META_PROTO, "AlwaysUseDefault", 0) == 1 ? TRUE : FALSE); + opt->suppress_status = (DBGetContactSettingByte(NULL, META_PROTO, "SuppressStatus", 1) == 1 ? TRUE : FALSE); + opt->menu_contact_label = (int)DBGetContactSettingWord(NULL, META_PROTO, "MenuContactLabel", DNT_UID); + opt->menu_function = (int)DBGetContactSettingWord(NULL, META_PROTO, "MenuContactFunction", FT_MENU); + opt->clist_contact_name = (int)DBGetContactSettingWord(NULL, META_PROTO, "CListContactName", CNNT_NICK); + opt->suppress_proto = (DBGetContactSettingByte(NULL, META_PROTO, "SuppressProto", 0) == 1 ? TRUE : FALSE); + opt->copy_subcontact_history = (DBGetContactSettingByte(NULL, META_PROTO, "CopyHistory", 1) == 1 ? TRUE : FALSE); + opt->days_history = (int)DBGetContactSettingDword(NULL, META_PROTO, "DaysHistory", 14); + opt->set_status_from_offline_delay = (int)DBGetContactSettingDword(NULL, META_PROTO, "SetStatusFromOfflineDelay", DEFAULT_SET_STATUS_SLEEP_TIME); + opt->subcontact_windows = (DBGetContactSettingByte(NULL, META_PROTO, "SubcontactWindows", 0) == 1 ? TRUE : FALSE); + opt->copydata = (DBGetContactSettingByte(NULL, META_PROTO, "CopyData", 1) == 1 ? TRUE : FALSE); + opt->lockHandle = (DBGetContactSettingByte(NULL, META_PROTO, "LockHandle", 0) == 1 ? TRUE : FALSE); + opt->flash_meta_message_icon = (DBGetContactSettingByte(NULL, META_PROTO, "MetaMessageIcon", 1) == 1 ? TRUE : FALSE); + opt->copy_userinfo = (DBGetContactSettingByte(NULL, META_PROTO, "CopyUserInfo", 1) == 1 ? TRUE : FALSE); + + if(!opt->subcontact_windows) + opt->metahistory = TRUE; + else + opt->metahistory = (DBGetContactSettingByte(NULL, META_PROTO, "MetaHistory", 1) == 1 ? TRUE : FALSE); + + if(opt->subcontact_windows) + opt->subhistory = TRUE; + else + opt->subhistory = (DBGetContactSettingByte(NULL, META_PROTO, "SubcontactHistory", 1) == 1 ? TRUE : FALSE); + + opt->use_proto_recv = (DBGetContactSettingByte(NULL, META_PROTO, "UseProtoRecv", 1) == 1 ? TRUE : FALSE); + return 0; +} + +/* +#define ID_STATUS_OFFLINE 40071 ->8 +#define ID_STATUS_ONLINE 40072 ->0 +#define ID_STATUS_AWAY 40073 ->4 +#define ID_STATUS_DND 40074 ->7 +#define ID_STATUS_NA 40075 ->6 +#define ID_STATUS_OCCUPIED 40076 ->5 +#define ID_STATUS_FREECHAT 40077 ->1 +#define ID_STATUS_INVISIBLE 40078 ->0 +#define ID_STATUS_ONTHEPHONE 40079 ->2 +#define ID_STATUS_OUTTOLUNCH 40080 ->3 +*/ + +int GetDefaultPrio(int status) { + switch( status ) { + case ID_STATUS_OFFLINE: return 8; + case ID_STATUS_AWAY: return 4; + case ID_STATUS_DND: return 7; + case ID_STATUS_NA: return 6; + case ID_STATUS_OCCUPIED: return 5; + case ID_STATUS_FREECHAT: return 1; + case ID_STATUS_ONTHEPHONE: return 2; + case ID_STATUS_OUTTOLUNCH: return 3; + } + + return 0; +} + +typedef struct { + int prio[10]; // priority for each status + BOOL def[10]; // use default for this one? +} ProtoStatusPrio; + +ProtoStatusPrio *priorities = 0; + +int GetRealPriority(char *proto, int status) { + char szSetting[256]; + if(!proto) { + mir_snprintf(szSetting, 256, "DefaultPrio_%d", status); + return DBGetContactSettingWord(0, META_PROTO, szSetting, GetDefaultPrio(status)); + } else { + int prio; + mir_snprintf(szSetting, 256, "ProtoPrio_%s%d", proto, status); + prio = DBGetContactSettingWord(0, META_PROTO, szSetting, 0xFFFF); + if(prio == 0xFFFF) { + mir_snprintf(szSetting, 256, "DefaultPrio_%d", status); + return DBGetContactSettingWord(0, META_PROTO, szSetting, GetDefaultPrio(status)); + } else + return prio; + } + return 0xFFFF; +} + +void ReadPriorities() { + int num_protocols; + PROTOCOLDESCRIPTOR **pppDesc; + char szSetting[256]; + ProtoStatusPrio * current; + int i, j; + + CallService(MS_PROTO_ENUMPROTOCOLS, (LPARAM)&num_protocols, (WPARAM)&pppDesc); + + current = priorities = (ProtoStatusPrio *)malloc((num_protocols + 1) * sizeof(ProtoStatusPrio)); + for(i = ID_STATUS_OFFLINE; i <= ID_STATUS_OUTTOLUNCH; i++) { + mir_snprintf(szSetting, 256, "DefaultPrio_%d", i); + current->def[i - ID_STATUS_OFFLINE] = TRUE; + current->prio[i - ID_STATUS_OFFLINE] = DBGetContactSettingWord(0, META_PROTO, szSetting, GetDefaultPrio(i)); + } + for(i = 0; i < num_protocols; i++) { + current = priorities + (i + 1); + for(j = ID_STATUS_OFFLINE; j <= ID_STATUS_OUTTOLUNCH; j++) { + mir_snprintf(szSetting, 256, "ProtoPrio_%s%d", pppDesc[i]->szName, j); + current->prio[j - ID_STATUS_OFFLINE] = DBGetContactSettingWord(0, META_PROTO, szSetting, 0xFFFF); + current->def[j - ID_STATUS_OFFLINE] = (current->prio[j - ID_STATUS_OFFLINE] == 0xFFFF); + } + } +} + +void WritePriorities() { + int num_protocols; + PROTOCOLDESCRIPTOR **pppDesc; + char szSetting[256]; + ProtoStatusPrio * current = priorities; + int i, j; + + CallService(MS_PROTO_ENUMPROTOCOLS, (LPARAM)&num_protocols, (WPARAM)&pppDesc); + + for(i = ID_STATUS_OFFLINE; i <= ID_STATUS_OUTTOLUNCH; i++) { + mir_snprintf(szSetting, 256, "DefaultPrio_%d", i); + if(current->prio[i - ID_STATUS_OFFLINE] != GetDefaultPrio(i)) + DBWriteContactSettingWord(0, META_PROTO, szSetting, (WORD)current->prio[i - ID_STATUS_OFFLINE]); + else + DBDeleteContactSetting(0, META_PROTO, szSetting); + } + for(i = 0; i < num_protocols; i++) { + current = priorities + (i + 1); + for(j = ID_STATUS_OFFLINE; j <= ID_STATUS_OUTTOLUNCH; j++) { + mir_snprintf(szSetting, 256, "ProtoPrio_%s%d", pppDesc[i]->szName, j); + if(!current->def[j - ID_STATUS_OFFLINE]) + DBWriteContactSettingWord(0, META_PROTO, szSetting, (WORD)current->prio[j - ID_STATUS_OFFLINE]); + else + DBDeleteContactSetting(0, META_PROTO, szSetting); + } + } +} + +int GetIsDefault(int proto_index, int status) { + return (priorities + (proto_index + 1))->def[status - ID_STATUS_OFFLINE]; +} + +BOOL GetPriority(int proto_index, int status) { + ProtoStatusPrio * current; + if(proto_index == -1) { + current = priorities; + return current->prio[status - ID_STATUS_OFFLINE]; + } else { + current = priorities + (proto_index + 1); + if(current->def[status - ID_STATUS_OFFLINE]) { + current = priorities; + } + return current->prio[status - ID_STATUS_OFFLINE]; + } + return 0xFFFF; +} + +void SetPriority(int proto_index, int status, BOOL def, int prio) { + ProtoStatusPrio * current; + if(prio < 0) prio = 0; + if(prio > 500) prio = 500; + if(proto_index == -1) { + current = priorities; + current->prio[status - ID_STATUS_OFFLINE] = prio; + } else { + current = priorities + (proto_index + 1); + current->def[status - ID_STATUS_OFFLINE] = def; + if(!def) { + current->prio[status - ID_STATUS_OFFLINE] = prio; + } + } +} + +void ResetPriorities() { + int num_protocols; + PROTOCOLDESCRIPTOR **pppDesc; + ProtoStatusPrio * current; + int i, j; + + CallService(MS_PROTO_ENUMPROTOCOLS, (LPARAM)&num_protocols, (WPARAM)&pppDesc); + + current = priorities; + for(i = ID_STATUS_OFFLINE; i <= ID_STATUS_OUTTOLUNCH; i++) { + current->def[i - ID_STATUS_OFFLINE] = TRUE; + current->prio[i - ID_STATUS_OFFLINE] = GetDefaultPrio(i); + } + for(i = 0; i < num_protocols; i++) { + current = priorities + (i + 1); + for(j = ID_STATUS_OFFLINE; j <= ID_STATUS_OUTTOLUNCH; j++) { + current->def[j - ID_STATUS_OFFLINE] = TRUE; + } + } +} + +#define WMU_FILLSTATUSCMB (WM_USER + 0x100) +#define WMU_FILLPRIODATA (WM_USER + 0x101) + +INT_PTR CALLBACK DlgProcOptsPriorities(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + HWND hw; + + switch ( msg ) { + case WM_INITDIALOG: + TranslateDialogDefault( hwndDlg ); + SendMessage(GetDlgItem(hwndDlg, IDC_SP_PRIORITY), UDM_SETRANGE, 0, (LPARAM)MAKELONG(500, 0)); + ReadPriorities(); + { + int num_protocols; + PROTOCOLDESCRIPTOR **pppDesc; + int i, index; + + CallService(MS_PROTO_ENUMPROTOCOLS, (LPARAM)&num_protocols, (WPARAM)&pppDesc); + hw = GetDlgItem(hwndDlg, IDC_CMB_PROTOCOL); + index = SendMessage(hw, CB_INSERTSTRING, (WPARAM)-1, (LPARAM)Translate("")); + SendMessage(hw, CB_SETITEMDATA, (WPARAM)index, -1); + for(i = 0; i < num_protocols; i++) { + if(pppDesc[i]->type == PROTOTYPE_PROTOCOL) { + if(strcmp(pppDesc[i]->szName, META_PROTO) != 0) { + index = SendMessage(hw, CB_INSERTSTRING, (WPARAM)-1, (LPARAM)pppDesc[i]->szName); + SendMessage(hw, CB_SETITEMDATA, (WPARAM)index, i); + } + } + } + + SendMessage(hw, CB_SETCURSEL, 0, 0); + SendMessage(hwndDlg, WMU_FILLSTATUSCMB, 0, 0); + SendMessage(hwndDlg, WMU_FILLPRIODATA, 0, 0); + } + return FALSE; + case WMU_FILLPRIODATA: + { + int sel = SendMessage(GetDlgItem(hwndDlg, IDC_CMB_PROTOCOL), CB_GETCURSEL, 0, 0); + if(sel != -1) { + int index = SendMessage(GetDlgItem(hwndDlg, IDC_CMB_PROTOCOL), CB_GETITEMDATA, (WPARAM)sel, 0); + sel = SendMessage(GetDlgItem(hwndDlg, IDC_CMB_STATUS), CB_GETCURSEL, 0, 0); + if(sel != -1) { + int status = SendMessage(GetDlgItem(hwndDlg, IDC_CMB_STATUS), CB_GETITEMDATA, (WPARAM)sel, 0); + SetDlgItemInt(hwndDlg, IDC_ED_PRIORITY, GetPriority(index, status), FALSE); + if(index == -1) { + EnableWindow(GetDlgItem(hwndDlg, IDC_ED_PRIORITY), TRUE); + EnableWindow(GetDlgItem(hwndDlg, IDC_SP_PRIORITY), TRUE); + CheckDlgButton(hwndDlg, IDC_CHK_DEFAULT, TRUE); + EnableWindow(GetDlgItem(hwndDlg, IDC_CHK_DEFAULT), FALSE); + } else { + if(GetIsDefault(index, status)) { + CheckDlgButton(hwndDlg, IDC_CHK_DEFAULT, TRUE); + EnableWindow(GetDlgItem(hwndDlg, IDC_ED_PRIORITY), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_SP_PRIORITY), FALSE); + } else { + CheckDlgButton(hwndDlg, IDC_CHK_DEFAULT, FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_ED_PRIORITY), TRUE); + EnableWindow(GetDlgItem(hwndDlg, IDC_SP_PRIORITY), TRUE); + } + + EnableWindow(GetDlgItem(hwndDlg, IDC_CHK_DEFAULT), TRUE); + } + } + } + } + return TRUE; + case WMU_FILLSTATUSCMB: + { + int sel = SendMessage(GetDlgItem(hwndDlg, IDC_CMB_PROTOCOL), CB_GETCURSEL, 0, 0); + if(sel != -1) { + int index = SendMessage(GetDlgItem(hwndDlg, IDC_CMB_PROTOCOL), CB_GETITEMDATA, (WPARAM)sel, 0); + HWND hw = GetDlgItem(hwndDlg, IDC_CMB_STATUS); + SendMessage(hw, CB_RESETCONTENT, 0, 0); + if(index == -1) { + int i; + for(i = ID_STATUS_OFFLINE; i <= ID_STATUS_OUTTOLUNCH; i++) { + index = SendMessage(hw, CB_INSERTSTRING, (WPARAM)-1, (LPARAM)(char *)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, i, 0)); + SendMessage(hw, CB_SETITEMDATA, (WPARAM)index, i); + } + } else { + int num_protocols, caps, i; + PROTOCOLDESCRIPTOR **pppDesc; + CallService(MS_PROTO_ENUMPROTOCOLS, (LPARAM)&num_protocols, (WPARAM)&pppDesc); + + caps = CallProtoService(pppDesc[index]->szName, PS_GETCAPS, PFLAGNUM_2, 0); + + for(i = ID_STATUS_OFFLINE; i <= ID_STATUS_OUTTOLUNCH; i++) { + if(caps & Proto_Status2Flag(i)) { + index = SendMessage(hw, CB_INSERTSTRING, (WPARAM)-1, (LPARAM)(char *)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, i, 0)); + SendMessage(hw, CB_SETITEMDATA, (WPARAM)index, i); + } + } + } + SendMessage(hw, CB_SETCURSEL, 0, 0); + SendMessage(hwndDlg, WMU_FILLPRIODATA, 0, 0); + } + } + return TRUE; + case WM_COMMAND: + if ( HIWORD( wParam ) == BN_CLICKED ) { + switch( LOWORD( wParam )) { + case IDC_CHK_DEFAULT: + { + int sel = SendMessage(GetDlgItem(hwndDlg, IDC_CMB_PROTOCOL), CB_GETCURSEL, 0, 0); + if(sel != -1) { + int index = SendMessage(GetDlgItem(hwndDlg, IDC_CMB_PROTOCOL), CB_GETITEMDATA, (WPARAM)sel, 0); + sel = SendMessage(GetDlgItem(hwndDlg, IDC_CMB_STATUS), CB_GETCURSEL, 0, 0); + if(sel != -1) { + BOOL checked = IsDlgButtonChecked(hwndDlg, IDC_CHK_DEFAULT); + int status = SendMessage(GetDlgItem(hwndDlg, IDC_CMB_STATUS), CB_GETITEMDATA, (WPARAM)sel, 0); + if(checked) { + SetPriority(index, status, TRUE, 0); + SetDlgItemInt(hwndDlg, IDC_ED_PRIORITY, GetPriority(index, status), FALSE); + } else { + SetPriority(index, status, FALSE, GetDlgItemInt(hwndDlg, IDC_ED_PRIORITY, 0, FALSE)); + } + EnableWindow(GetDlgItem(hwndDlg, IDC_ED_PRIORITY), !checked); + EnableWindow(GetDlgItem(hwndDlg, IDC_SP_PRIORITY), !checked); + SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); + } + } + } + break; + case IDC_BTN_RESET: + ResetPriorities(); + SendMessage(GetDlgItem(hwndDlg, IDC_CMB_PROTOCOL), CB_SETCURSEL, 0, 0); + SendMessage(hwndDlg, WMU_FILLSTATUSCMB, 0, 0); + SendMessage(hwndDlg, WMU_FILLPRIODATA, 0, 0); + SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); + break; + } + } + if ( HIWORD( wParam ) == EN_CHANGE && LOWORD(wParam) == IDC_ED_PRIORITY && ( HWND )lParam == GetFocus()) { + int sel = SendMessage(GetDlgItem(hwndDlg, IDC_CMB_PROTOCOL), CB_GETCURSEL, 0, 0); + if(sel != -1) { + int index = SendMessage(GetDlgItem(hwndDlg, IDC_CMB_PROTOCOL), CB_GETITEMDATA, (WPARAM)sel, 0); + sel = SendMessage(GetDlgItem(hwndDlg, IDC_CMB_STATUS), CB_GETCURSEL, 0, 0); + if(sel != -1) { + int status = SendMessage(GetDlgItem(hwndDlg, IDC_CMB_STATUS), CB_GETITEMDATA, (WPARAM)sel, 0); + int prio = GetDlgItemInt(hwndDlg, IDC_ED_PRIORITY, 0, FALSE); + SetPriority(index, status, FALSE, prio); + if(prio != GetPriority(index, status)) + SetDlgItemInt(hwndDlg, IDC_ED_PRIORITY, GetPriority(index, status), FALSE); + SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); + } + } + } + if ( HIWORD( wParam ) == CBN_SELCHANGE) { + switch( LOWORD( wParam )) { + case IDC_CMB_STATUS: + SendMessage(hwndDlg, WMU_FILLPRIODATA, 0, 0); + break; + case IDC_CMB_PROTOCOL: + SendMessage(hwndDlg, WMU_FILLSTATUSCMB, 0, 0); + break; + } + } + break; + + case WM_NOTIFY: + if (((LPNMHDR)lParam)->code == PSN_APPLY ) { + WritePriorities(); + return TRUE; + } + break; + case WM_DESTROY: + free(priorities); + priorities = 0; + break; + } + + return FALSE; +} diff --git a/plugins/MetaContacts/meta_remove2.ico b/plugins/MetaContacts/meta_remove2.ico new file mode 100644 index 0000000000..ecfe29e6bf Binary files /dev/null and b/plugins/MetaContacts/meta_remove2.ico differ diff --git a/plugins/MetaContacts/meta_services.c b/plugins/MetaContacts/meta_services.c new file mode 100644 index 0000000000..bbf9177132 --- /dev/null +++ b/plugins/MetaContacts/meta_services.c @@ -0,0 +1,2106 @@ +/* +MetaContacts Plugin for Miranda IM. + +Copyright © 2004 Universite Louis PASTEUR, STRASBOURG. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +/** @file meta_services.c +* +* Functions specific to the protocol part of the plugin. +* Centralizes all the functions called by Miranda to make +* the plugin work as a protocol. +*/ + +#include "metacontacts.h" + +#define NB_SERVICES 62 //!< Number of services registered in Miranda (see Meta_CloseHandles()). +#define NB_HOOKS 17 //!< Number of hooks set up (see Meta_CloseHandles()). + +#define PREF_METANODB 0x2000 //!< Flag to indicate message should not be added to db by filter when sending + +char *pendingACK = 0; //!< Name of the protocol in which an ACK is about to come. + +int previousMode, //!< Previous status of the MetaContacts Protocol + mcStatus; //!< Current status of the MetaContacts Protocol + +HANDLE hServices[NB_SERVICES] = {0}, //!< list of all the services registered (see Meta_CloseHandles()). +hHooks[NB_HOOKS] = {0}; //!< list of all hooks set up (see Meta_CloseHandles()). + +HANDLE *hNudgeEvents = 0; +int iNudgeProtos = 0; + +HANDLE hMenuConvert, //!< \c HANDLE to the convert menu item. + hMenuAdd, //!< \c HANDLE to the add to menu item. + hMenuEdit, //!< \c HANDLE to the edit menu item. + hMenuDelete, //!< \c HANDLE to the delete menu item. + hMenuDefault, //!< \c HANDLE to the delete menu item. + hMenuForceDefault; //!< \c HANDLE to the delete menu item. + +HANDLE hMenuOnOff; //!< \c HANDLE to the enable/disable menu item. + +HANDLE hEventDefaultChanged, //!< \c HANDLE to the 'default changed' event + hEventForceSend, //!< \c HANDLE to the 'force send' event + hEventUnforceSend, //!< \c HANDLE to the 'unforce send' event + hSubcontactsChanged, //!< \c HANDLE to the 'contacts changed' event + hEventNudge; + + +DWORD nextMetaID; //!< Global variable specifying the ID value the next MetaContact will have. + +BOOL message_window_api_enabled = FALSE; //!< Global variable specifying whether the message window api ver 0.0.0.1+ is available + +// stuff for mw_clist extra icon +int proto_count = 0; +HANDLE hExtraImage[MAX_PROTOCOLS * 2]; // online and offline icons +char proto_names[MAX_PROTOCOLS * 128]; +HANDLE hProtoIcons[MAX_PROTOCOLS * 2]; // online and offline icons + +UINT_PTR setStatusTimerId = 0; +BOOL firstSetOnline = TRUE; // see Meta_SetStatus function + +/** Get the capabilities of the "MetaContacts" protocol. +* +* @param wParam : equals to one of the following values :\n + PFLAGNUM_1 | PFLAGNUM_2 | PFLAGNUM_3 | PFLAGNUM_4 | PFLAG_UNIQUEIDTEXT | PFLAG_MAXLENOFMESSAGE | PFLAG_UNIQUEIDSETTING . +* @param lParam : Allways set to 0. +* +* @return Depending on the \c WPARAM. +*/ +INT_PTR Meta_GetCaps(WPARAM wParam,LPARAM lParam) +{ + int ret = 0; + switch (wParam) { + case PFLAGNUM_1: + //ret = PF1_IM | PF1_URL | PF1_FILE | PF1_MODEMSG | PF1_AUTHREQ | PF1_ADDED; + //ret = PF1_IMSEND | PF1_URLSEND | PF1_FILESEND | PF1_MODEMSGSEND; + ret = PF1_IM | PF1_CHAT | PF1_FILESEND | PF1_MODEMSGRECV | PF1_NUMERICUSERID; + break; + case PFLAGNUM_2: + if(!options.suppress_proto) { + ret = PF2_ONLINE | PF2_INVISIBLE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND + | PF2_HEAVYDND | PF2_FREECHAT | PF2_OUTTOLUNCH | PF2_ONTHEPHONE; + } + //ret = PF2_ONLINE; + break; + case PFLAGNUM_3: + //ret = PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND | PF2_HEAVYDND; + ret = PF2_ONLINE | PF2_INVISIBLE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND + | PF2_HEAVYDND | PF2_FREECHAT | PF2_OUTTOLUNCH | PF2_ONTHEPHONE; + break; + case PFLAGNUM_4: + //ret = PF4_FORCEAUTH; + ret = PF4_SUPPORTTYPING | PF4_AVATARS; + break; + case PFLAGNUM_5: + ret = PF2_INVISIBLE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND + | PF2_HEAVYDND | PF2_FREECHAT | PF2_OUTTOLUNCH | PF2_ONTHEPHONE; + break; + case PFLAG_UNIQUEIDTEXT: + ret = (INT_PTR) Translate("Meta ID"); + break; + case PFLAG_MAXLENOFMESSAGE: + ret = 2000; + break; + case PFLAG_UNIQUEIDSETTING: + ret = (INT_PTR) META_ID; + break; + } + return ret; +} + +/** Copy the name of the protocole into lParam +* @param wParam : max size of the name +* @param lParam : reference to a char *, which will hold the name +*/ +INT_PTR Meta_GetName(WPARAM wParam,LPARAM lParam) +{ + char *name = (char *)Translate(META_PROTO); + size_t size = min(strlen(name),wParam-1); // copy only the first size bytes. + if(strncpy((char *)lParam,name,size)==NULL) + return 1; + ((char *)lParam)[size]='\0'; + return 0; +} + +/** Loads the icon corresponding to the status +* Called by the CList when the status changes. +* @param wParam : one of the following values : \n + PLI_PROTOCOL | PLI_ONLINE | PLI_OFFLINE +* @return an \c HICON in which the icon has been loaded. +*/ +INT_PTR Meta_LoadIcon(WPARAM wParam,LPARAM lParam) +{ + UINT id; + switch (wParam & 0xFFFF) + { + case PLI_PROTOCOL: + id = IDI_MCMENU; + break; + case PLI_ONLINE: + id = IDI_MCMENU; + break; + case PLI_OFFLINE: + id = IDI_MCMENU; + break; + default: + return 0; + } + + return (INT_PTR) LoadImage(hInstance, MAKEINTRESOURCE(id), IMAGE_ICON, + GetSystemMetrics(wParam & PLIF_SMALL ? SM_CXSMICON : SM_CXICON), + GetSystemMetrics(wParam & PLIF_SMALL ? SM_CYSMICON : SM_CYICON), 0); + +} + + +//static DWORD CALLBACK SetStatusThread( LPVOID param ) +void CALLBACK SetStatusThread(HWND hWnd, UINT msg, UINT_PTR id, DWORD dw) +{ + + previousMode = mcStatus; + + //Sleep(options.set_status_from_offline_delay); + + mcStatus = (int)ID_STATUS_ONLINE; + ProtoBroadcastAck(META_PROTO,NULL,ACKTYPE_STATUS,ACKRESULT_SUCCESS, (HANDLE)previousMode, mcStatus); + + //return 0; + KillTimer(0, setStatusTimerId); +} + +/** Changes the status and notifies everybody +* @param wParam : The new mode +* @param lParam : Allways set to 0. +*/ +INT_PTR Meta_SetStatus(WPARAM wParam,LPARAM lParam) +{ + // firstSetOnline starts out true - used to delay metacontact's 'onlineness' to prevent double status notifications on startup + if(mcStatus == ID_STATUS_OFFLINE && firstSetOnline) { + // causes crash on exit if miranda is closed in under options.set_status_from_offline milliseconds! + //CloseHandle( CreateThread( NULL, 0, SetStatusThread, (void *)wParam, 0, 0 )); + setStatusTimerId = SetTimer(0, 0, options.set_status_from_offline_delay, SetStatusThread); + firstSetOnline = FALSE; + } else { + previousMode = mcStatus; + mcStatus = (int)wParam; + ProtoBroadcastAck(META_PROTO,NULL,ACKTYPE_STATUS,ACKRESULT_SUCCESS, (HANDLE)previousMode, mcStatus); + } + return 0; +} + +/** Returns the current status +*/ +INT_PTR Meta_GetStatus(WPARAM wParam,LPARAM lParam) +{ + return mcStatus; +} + +////////////////////////////////////////////////////////// +/// Copied from MSN plugin - sent acks need to be from different thread :( +////////////////////////////////////////////////////////// +typedef struct tag_TFakeAckParams +{ + HANDLE hEvent; + HANDLE hContact; + LONG id; + char msg[512]; +} TFakeAckParams; + +/* +static DWORD CALLBACK sttFakeAckSuccess( LPVOID param ) +{ + TFakeAckParams *tParam = ( TFakeAckParams* )param; + WaitForSingleObject( tParam->hEvent, INFINITE ); + + Sleep( 100 ); + ProtoBroadcastAck(META_PROTO, tParam->hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, ( HANDLE )tParam->id, 0 ); + + CloseHandle( tParam->hEvent ); + free(tParam); + return 0; +} +*/ + +static DWORD CALLBACK sttFakeAckFail( LPVOID param ) +{ + TFakeAckParams *tParam = ( TFakeAckParams* )param; + WaitForSingleObject( tParam->hEvent, INFINITE ); + + Sleep( 100 ); + ProtoBroadcastAck(META_PROTO, tParam->hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, ( HANDLE )tParam->id, (WPARAM)tParam->msg ); + + CloseHandle( tParam->hEvent ); + mir_free(tParam); + return 0; +} + +/** Filter messages sent by subcontacts +* +* When groups are disabled, add an event to the DB for the metacontact to maintain history +* +* @param wParam : index of the protocol in the protocol chain. +* @param lParam : \c CCSDATA structure holding all the information about the message. +* +* @return 0 on success, 1 otherwise. +*/ + +INT_PTR MetaFilter_SendMessage(WPARAM wParam,LPARAM lParam) +{ + DBEVENTINFO dbei; + CCSDATA *ccs = (CCSDATA *) lParam; + HANDLE hMeta; + + if((hMeta = (HANDLE)DBGetContactSettingDword(ccs->hContact,META_PROTO, "Handle", (DWORD)0)) == (DWORD)0) { + return CallService(MS_PROTO_CHAINSEND, wParam, lParam); // Can't find the MetaID of the metacontact linked to + } + + // if subcontact sending, add db event to keep metacontact history correct + if(options.metahistory && !(ccs->wParam & PREF_METANODB)) { + + // reject "file As Message" messages + if(strlen((char *)ccs->lParam) > 5 && strncmp((char *)ccs->lParam, "<%fAM", 5) == 0) + return CallService(MS_PROTO_CHAINSEND, wParam, lParam); // continue processing + + // reject "data As Message" messages + if(strlen((char *)ccs->lParam) > 5 && strncmp((char *)ccs->lParam, "<%dAM", 5) == 0) + return CallService(MS_PROTO_CHAINSEND, wParam, lParam); // continue processing + + // reject "OTR" messages + if(strlen((char *)ccs->lParam) > 5 && strncmp((char *)ccs->lParam, "?OTR", 4) == 0) + return CallService(MS_PROTO_CHAINSEND, wParam, lParam); // continue processing + + ZeroMemory(&dbei, sizeof(dbei)); + dbei.cbSize = sizeof(dbei); + dbei.szModule = META_PROTO; + dbei.flags = DBEF_SENT; + dbei.timestamp = time(NULL); + dbei.eventType = EVENTTYPE_MESSAGE; + if(ccs->wParam & PREF_RTL) dbei.flags |= DBEF_RTL; + if(ccs->wParam & PREF_UTF) dbei.flags |= DBEF_UTF; + dbei.cbBlob = (DWORD)strlen((char *)ccs->lParam) + 1; + if ( ccs->wParam & PREF_UNICODE ) + dbei.cbBlob *= ( sizeof( wchar_t )+1 ); + dbei.pBlob = (PBYTE)ccs->lParam; + + CallService(MS_DB_EVENT_ADD, (WPARAM) hMeta, (LPARAM)&dbei); + } + + return CallService(MS_PROTO_CHAINSEND, wParam, lParam); +} + +INT_PTR Meta_SendNudge(WPARAM wParam,LPARAM lParam) +{ + HANDLE hMeta = (HANDLE)wParam, + hSubContact = Meta_GetMostOnline(hMeta); + + char servicefunction[ 100 ]; + char *protoName = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hSubContact, 0); + sprintf(servicefunction, "%s/SendNudge", protoName); + + return CallService(servicefunction, (WPARAM)hSubContact, lParam); + + //return CallService("NUDGE/Send", (WPARAM)hSubContact, lParam); +} + +///////////////////////////////////////////////////////////////// + +/** Send a message to the protocol specific network. +* +* Call the function specific to the protocol that belongs +* to the contact chosen to send the message. +* +* @param wParam : index of the protocol in the protocol chain. +* @param lParam : \c CCSDATA structure holding all the information abour rhe message. +* +* @return 0 on success, 1 otherwise. +*/ +INT_PTR Meta_SendMessage(WPARAM wParam,LPARAM lParam) +{ + DBEVENTINFO dbei; + CCSDATA *ccs = (CCSDATA *) lParam; + char *proto = 0; + DWORD default_contact_number; + + + if((default_contact_number = DBGetContactSettingDword(ccs->hContact,META_PROTO,"Default",(DWORD)-1)) == (DWORD)-1) + { + // This is a simple contact, let through the stack of protocols + // (this should normally not happen, since linked contacts do not appear on the list.) + return CallService(MS_PROTO_CHAINSEND, wParam, lParam); + } + else + { + char szServiceName[100]; + HANDLE most_online; + + most_online = Meta_GetMostOnline(ccs->hContact); + //DBEVENTINFO dbei; + + if(!most_online) { + DWORD dwThreadId; + HANDLE hEvent; + TFakeAckParams *tfap; + + // send failure to notify user of reason + hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); + + tfap = (TFakeAckParams *)mir_alloc(sizeof(TFakeAckParams)); + tfap->hContact = ccs->hContact; + tfap->hEvent = hEvent; + tfap->id = 10; + strcpy(tfap->msg, Translate("No online contacts found.")); + + CloseHandle( CreateThread( NULL, 0, sttFakeAckFail, tfap, 0, &dwThreadId )); + SetEvent( hEvent ); + + return 10; + } + + Meta_CopyContactNick(ccs->hContact, most_online); + + ccs->hContact = most_online; + proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)most_online, 0); + Meta_SetNick(proto); // (no matter what was there before) + + // don't bypass filters etc + strncpy(szServiceName, PSS_MESSAGE, sizeof(szServiceName)); + + if(ccs->wParam & PREF_UNICODE) { + char szTemp[100]; + _snprintf(szTemp, sizeof(szTemp), "%s%sW", proto, PSS_MESSAGE); + if (ServiceExists(szTemp)) + strncpy(szServiceName, PSS_MESSAGE "W", sizeof(szServiceName)); + } + + if(options.subhistory && !(ccs->wParam & PREF_METANODB)) { + // add sent event to subcontact + ZeroMemory(&dbei, sizeof(dbei)); + dbei.cbSize = sizeof(dbei); + dbei.szModule = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)ccs->hContact, 0); + dbei.flags = DBEF_SENT; + dbei.timestamp = time(NULL); + dbei.eventType = EVENTTYPE_MESSAGE; + if(ccs->wParam & PREF_RTL) dbei.flags |= DBEF_RTL; + if(ccs->wParam & PREF_UTF) dbei.flags |= DBEF_UTF; + dbei.cbBlob = (DWORD)strlen((char *)ccs->lParam) + 1; + if ( ccs->wParam & PREF_UNICODE ) + dbei.cbBlob *= ( sizeof( wchar_t )+1 ); + dbei.pBlob = (PBYTE)ccs->lParam; + + CallService(MS_DB_EVENT_ADD, (WPARAM) ccs->hContact, (LPARAM)&dbei); + } + + // prevent send filter from adding another copy of this send event to the db + ccs->wParam |= PREF_METANODB; + + return CallContactService(ccs->hContact, szServiceName, ccs->wParam, ccs->lParam); + } +} + +/** Transmit a message received by a contact. +* +* Forward the message received by a contact linked to a MetaContact +* to that MetaContact and inhibit the further reception of this message +* by the standard protocol of the contact. +* +* @param wParam : index of the protocol in the protocol chain. +* @param lParam : \c CCSDATA structure holding all the information about the message. +* +* @return 0 on success, 1 otherwise. +*/ +INT_PTR MetaFilter_RecvMessage(WPARAM wParam,LPARAM lParam) +{ + DBEVENTINFO dbei; + CCSDATA *ccs = (CCSDATA *) lParam; + PROTORECVEVENT *pre = (PROTORECVEVENT *) ccs->lParam; + HANDLE hMeta; + + if((hMeta = (HANDLE)DBGetContactSettingDword(ccs->hContact,META_PROTO, "Handle", (DWORD)0)) == (DWORD)0) { + CallService(MS_PROTO_CHAINRECV, wParam, (LPARAM)ccs); // Can't find the MetaID of the metacontact linked to + // this contact, let through the protocol chain + return 0; + } + + if(options.set_default_on_recv) { + if(options.temp_default && DBGetContactSettingDword(hMeta, META_PROTO, "SavedDefault", (DWORD)-1) == (DWORD)-1) + DBWriteContactSettingDword(hMeta, META_PROTO, "SavedDefault", DBGetContactSettingDword(hMeta, META_PROTO, "Default", 0)); + DBWriteContactSettingDword(hMeta, META_PROTO, "Default", DBGetContactSettingDword(ccs->hContact, META_PROTO, "ContactNumber", 0)); + NotifyEventHooks(hEventDefaultChanged, (WPARAM)hMeta, (LPARAM)ccs->hContact); // nick set in event handler + } + + // if meta disabled (now message api) or window open (message api), or using subcontact windows, + // let through but add db event for metacontact history + if(!Meta_IsEnabled() + || DBGetContactSettingByte(ccs->hContact, META_PROTO, "WindowOpen", 0) == 1 + || options.subcontact_windows) + { + + // add a clist event, so that e.g. there is an icon flashing + // (only add it when message api available, 'cause then we can remove the event when the message window is opened) + if(message_window_api_enabled + && DBGetContactSettingByte(ccs->hContact, META_PROTO, "WindowOpen", 0) == 0 + && DBGetContactSettingByte(hMeta, META_PROTO, "WindowOpen", 0) == 0 + && options.flash_meta_message_icon) + { + CLISTEVENT cle; + char toolTip[256], *contactName; + ZeroMemory(&cle, sizeof(cle)); + + cle.cbSize = sizeof(cle); + cle.hContact = hMeta; + cle.hDbEvent = ccs->hContact; // use subcontact handle as key - then we can remove all events if the subcontact window is opened + cle.hIcon = LoadSkinnedIcon(SKINICON_EVENT_MESSAGE); + cle.pszService = "MetaContacts/CListMessageEvent"; + contactName = (char *) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hMeta, 0); + _snprintf(toolTip, sizeof(toolTip), Translate("Message from %s"), contactName); + cle.pszTooltip = toolTip; + CallService(MS_CLIST_ADDEVENT, 0, (LPARAM) & cle); + } + + if(options.metahistory) { + + BOOL added = FALSE; + + // should be able to do this, but some protos mess with the memory + if(options.use_proto_recv) + { + // use the subcontact's protocol 'recv' service to add the meta's history (AIMOSCAR removes HTML here!) if possible + char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)ccs->hContact, 0); + if(proto) { + char service[256]; + HANDLE hSub = ccs->hContact; + DWORD flags = pre->flags; + mir_snprintf(service, 256, "%s%s", proto, PSR_MESSAGE); + ccs->hContact = hMeta; + pre->flags |= (DBGetContactSettingByte(hMeta, META_PROTO, "WindowOpen", 0) ? 0 : PREF_CREATEREAD); + if(ServiceExists(service) && !CallService(service, 0, (LPARAM)ccs)) + added = TRUE; + ccs->hContact = hSub; + pre->flags = flags; + } + } + + if(!added) { + // otherwise add raw db event + ZeroMemory(&dbei, sizeof(dbei)); + dbei.cbSize = sizeof(dbei); + dbei.szModule = META_PROTO; + dbei.timestamp = pre->timestamp; + dbei.flags = (DBGetContactSettingByte(hMeta, META_PROTO, "WindowOpen", 0) ? 0 : DBEF_READ); + if(pre->flags & PREF_RTL) dbei.flags |= DBEF_RTL; + if(pre->flags & PREF_UTF) dbei.flags |= DBEF_UTF; + dbei.eventType = EVENTTYPE_MESSAGE; + dbei.cbBlob = (DWORD)strlen(pre->szMessage) + 1; + if ( pre->flags & PREF_UNICODE ) { + dbei.cbBlob *= ( sizeof( wchar_t )+1 ); + } + dbei.pBlob = (PBYTE) pre->szMessage; + + CallService(MS_DB_EVENT_ADD, (WPARAM) hMeta, (LPARAM)&dbei); + } + } + + CallService(MS_PROTO_CHAINRECV, wParam, (LPARAM)ccs); + return 0; + } // else: + + /* + // add event to subcontact history (would do it in meta_recvmessage, but here we have the hcontact) + // should be able to use the method below, except some protos can mess with the memory + if(options.subhistory) { + ZeroMemory(&dbei, sizeof(dbei)); + dbei.cbSize = sizeof(dbei); + dbei.szModule = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)ccs->hContact, 0); + dbei.timestamp = pre->timestamp; + dbei.flags = (DBGetContactSettingByte(ccs->hContact, META_PROTO, "WindowOpen", 0) ? 0 : DBEF_READ); + if(pre->flags & PREF_RTL) dbei.flags |= DBEF_RTL; + dbei.eventType = EVENTTYPE_MESSAGE; + dbei.cbBlob = strlen(pre->szMessage) + 1; + if ( pre->flags & PREF_UNICODE ) + dbei.cbBlob *= ( sizeof( wchar_t )+1 ); + dbei.pBlob = (PBYTE) pre->szMessage; + + CallService(MS_DB_EVENT_ADD, (WPARAM) ccs->hContact, (LPARAM)&dbei); + } + */ + + + { + HANDLE hSub = ccs->hContact; + ccs->hContact = hMeta; // Forward to the associated MetaContact. + CallService(MS_PROTO_CHAINRECV, 0, (LPARAM)ccs); + ccs->hContact = hSub; + } + + if(options.subhistory && !(ccs->wParam & PREF_METANODB)) { + // allow event pass through and thereby be added to subcontact history + pre->flags |= (DBGetContactSettingByte(ccs->hContact, META_PROTO, "WindowOpen", 0) ? 0 : PREF_CREATEREAD); + CallService(MS_PROTO_CHAINRECV, wParam, (LPARAM)ccs); // pass through as normal + return 0; + } + + return 1; // Stop further processing. +} + +/** Receive a message for a MetaContact +* +* @return 0 +*/ +INT_PTR Meta_RecvMessage(WPARAM wParam, LPARAM lParam) +{ + DBEVENTINFO dbei; + CCSDATA *ccs = (CCSDATA *) lParam; + PROTORECVEVENT *pre = (PROTORECVEVENT *) ccs->lParam; + + char *proto; + + proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)ccs->hContact, 0); + + // contact is not a meta proto contact - just leave it + if(!proto || strcmp(proto, META_PROTO)) { + return 0; + } + + if(options.use_proto_recv) + { + // use the subcontact's protocol to add the db if possible (AIMOSCAR removes HTML here!) + HANDLE most_online = Meta_GetMostOnline(ccs->hContact); + char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)most_online, 0); + if(proto) { + char service[256]; + mir_snprintf(service, 256, "%s%s", proto, PSR_MESSAGE); + if (CallService(service, wParam, lParam) != CALLSERVICE_NOTFOUND) + return 0; + } + } + + + // otherwise, add event to db directly + ZeroMemory(&dbei, sizeof(dbei)); + dbei.cbSize = sizeof(dbei); + dbei.szModule = META_PROTO; + dbei.timestamp = pre->timestamp; + dbei.flags = (pre->flags & PREF_CREATEREAD ? DBEF_READ : 0); + if(pre->flags & PREF_RTL) dbei.flags |= DBEF_RTL; + if(pre->flags & PREF_UTF) dbei.flags |= DBEF_UTF; + dbei.eventType = EVENTTYPE_MESSAGE; + dbei.cbBlob = (DWORD)strlen(pre->szMessage) + 1; + if ( pre->flags & PREF_UNICODE ) + dbei.cbBlob *= ( sizeof( wchar_t )+1 ); + dbei.pBlob = (PBYTE) pre->szMessage; + + CallService(MS_DB_EVENT_ADD, (WPARAM) ccs->hContact, (LPARAM)&dbei); + + return 0; +} + + + +/** Called when an ACK is received. +* +* Retransmit the ACK sent by a simple contact so that it +* looks like it was the MetaContact that sends the ACK. +* +* @param wParam : Allways set to 0. +* @param lParam : Reference to a ACKDATA that contains + information about the ACK. +* @return 0 on success, 1 otherwise. +*/ +int Meta_HandleACK(WPARAM wParam, LPARAM lParam) +{ + ACKDATA *ack = (ACKDATA*) lParam; + HANDLE hUser; + + if(ack->hContact == 0 || (hUser = (HANDLE)DBGetContactSettingDword(ack->hContact,META_PROTO,"Handle",0)) == 0) + return 0; // Can't find the MetaID, let through the protocol chain + + + if(!strcmp(ack->szModule, META_PROTO)) { + return 0; // don't rebroadcast our own acks + } + + // if it's for something we don't support, ignore + if(ack->type != ACKTYPE_MESSAGE && ack->type != ACKTYPE_CHAT && ack->type != ACKTYPE_FILE && ack->type != ACKTYPE_AWAYMSG + && ack->type != ACKTYPE_AVATAR && ack->type != ACKTYPE_GETINFO) + + { + return 0; + } + + // change the hContact in the avatar info struct, if it's the avatar we're using - else drop it + if(ack->type == ACKTYPE_AVATAR) { + if(ack->result == ACKRESULT_SUCCESS || ack->result == ACKRESULT_FAILED || ack->result == ACKRESULT_STATUS) { + HANDLE most_online; + DBVARIANT dbv; + + // change avatar if the most online supporting avatars changes, or if we don't have one + most_online = Meta_GetMostOnlineSupporting(hUser, PFLAGNUM_4, PF4_AVATARS); + //if(AI.hContact == 0 || AI.hContact != most_online) { + if(ack->hContact == 0 || ack->hContact != most_online) { + return 0; + } + + //if(!DBGetContactSetting(AI.hContact, "ContactPhoto", "File", &dbv)) { + if(!DBGetContactSetting(ack->hContact, "ContactPhoto", "File", &dbv)) { + DBWriteContactSettingString(hUser, "ContactPhoto", "File", dbv.pszVal); + DBFreeVariant(&dbv); + } + + if(ack->hProcess) { + PROTO_AVATAR_INFORMATION AI; + memcpy(&AI, (PROTO_AVATAR_INFORMATION *)ack->hProcess, sizeof(PROTO_AVATAR_INFORMATION)); + if(AI.hContact) + AI.hContact = hUser; + + return ProtoBroadcastAck(META_PROTO,hUser,ack->type,ack->result, (HANDLE)&AI, ack->lParam); + } else + return ProtoBroadcastAck(META_PROTO,hUser,ack->type,ack->result, 0, ack->lParam); + } + } + + return ProtoBroadcastAck(META_PROTO,hUser,ack->type,ack->result,ack->hProcess,ack->lParam); +} + +// hiding contacts on "CList/UseGroups" setting changed can cause a crash - do it in a seperate thread during idle time +static DWORD sttHideContacts( BOOL param ) +{ + Meta_HideMetaContacts((int)param); + return 0; +} + +/** Call whenever a contact changes one of its settings (for example, the status) +** +* @param wParam \c HANDLE to the contact that has change of its setting. +* @param lParam Reference to a structure that contains the setting that has changed (not used) +*/ +int Meta_SettingChanged(WPARAM wParam, LPARAM lParam) +{ + DBCONTACTWRITESETTING *dcws = (DBCONTACTWRITESETTING *)lParam; + char buffer[512], buffer2[512]; + int contact_number; + HANDLE hMeta, most_online; + + + // hide metacontacts when groups disabled + if(wParam == 0 + && ((strcmp(dcws->szModule, "CList") == 0 && strcmp(dcws->szSetting, "UseGroups") == 0) + || (strcmp(dcws->szModule, META_PROTO) == 0 && strcmp(dcws->szSetting, "Enabled") == 0))) + { + sttHideContacts(!Meta_IsEnabled()); + return 0; + } + + if(wParam == 0 + && strcmp(dcws->szModule, "Import") == 0 && strcmp(dcws->szSetting, "Completed") == 0) + { + // import process has just been run...call startup routines... + Meta_SetHandles(); + { + HANDLE hContact = ( HANDLE )CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 ); + int meta_id; + while ( hContact != NULL ) { + if((meta_id = DBGetContactSettingDword(hContact,META_PROTO,META_ID,(DWORD)-1))!=(DWORD)-1) { + Meta_CopyData(hContact); + } + hContact = ( HANDLE )CallService( MS_DB_CONTACT_FINDNEXT,( WPARAM )hContact, 0 ); + } + } + + Meta_HideLinkedContacts(); + Meta_SuppressStatus(options.suppress_status); + } + + if(wParam == 0 + && strcmp(dcws->szModule, "CListGroups") == 0 && dcws->value.type != DBVT_DELETED && strcmp(dcws->value.pszVal, META_HIDDEN_GROUP) == 0) + { + // someone is creating our hidden group!! + + } + + // from here on, we're just interested in contact settings + if(wParam == 0) return 0; + + if((hMeta=(HANDLE)DBGetContactSettingDword((HANDLE)wParam,META_PROTO,"Handle",0))!=0 + && CallService(MS_DB_CONTACT_IS, (WPARAM)hMeta, 0)) // just to be safe + + { // This contact is attached to a MetaContact. + + contact_number = Meta_GetContactNumber((HANDLE)wParam); + if(contact_number == -1) return 0; // exit - db corruption + + if(!meta_group_hack_disabled && !strcmp(dcws->szModule, "CList") && !strcmp(dcws->szSetting, "Group") && + Meta_IsEnabled() && DBGetContactSettingByte((HANDLE)wParam, META_PROTO, "Hidden", 0) == 0 && !Miranda_Terminated()) { + if((dcws->value.type == DBVT_ASCIIZ || dcws->value.type == DBVT_UTF8) && !Meta_IsHiddenGroup(dcws->value.pszVal)) { + // subcontact group reassigned - copy to saved group + MyDBWriteContactSetting((HANDLE)wParam, META_PROTO, "OldCListGroup", &dcws->value); + DBWriteContactSettingString((HANDLE)wParam, "CList", "Group", META_HIDDEN_GROUP); + } else if(dcws->value.type == DBVT_DELETED) { + DBDeleteContactSetting((HANDLE)wParam, META_PROTO, "OldCListGroup"); + DBWriteContactSettingString((HANDLE)wParam, "CList", "Group", META_HIDDEN_GROUP); + } + } else + + // copy IP + if(!strcmp(dcws->szSetting, "IP")) { + if(dcws->value.type == DBVT_DWORD) + DBWriteContactSettingDword(hMeta, META_PROTO, "IP", dcws->value.dVal); + else + DBDeleteContactSetting(hMeta, META_PROTO, "IP"); + } else + + // copy RealIP + if(!strcmp(dcws->szSetting, "RealIP")) { + if(dcws->value.type == DBVT_DWORD) + DBWriteContactSettingDword(hMeta, META_PROTO, "RealIP", dcws->value.dVal); + else + DBDeleteContactSetting(hMeta, META_PROTO, "RealIP"); + + } else + // copy ListeningTo + if(!strcmp(dcws->szSetting, "ListeningTo")) { + switch(dcws->value.type) { + case DBVT_ASCIIZ: + DBWriteContactSettingString(hMeta, META_PROTO, "ListeningTo", dcws->value.pszVal); + break; + case DBVT_UTF8: + DBWriteContactSettingStringUtf(hMeta, META_PROTO, "ListeningTo", dcws->value.pszVal); + break; + case DBVT_WCHAR: + DBWriteContactSettingWString(hMeta, META_PROTO, "ListeningTo", dcws->value.pwszVal); + break; + case DBVT_DELETED: + DBDeleteContactSetting(hMeta, META_PROTO, "ListeningTo"); + break; + } + } else + + if(!strcmp(dcws->szSetting, "Nick") && !dcws->value.type == DBVT_DELETED) { + DBVARIANT dbv; + HANDLE most_online; + + // subcontact nick has changed - update metacontact + strcpy(buffer, "Nick"); + strcat(buffer, _itoa(contact_number, buffer2, 10)); + MyDBWriteContactSetting(hMeta, META_PROTO, buffer, &dcws->value); + + if(MyDBGetContactSetting((HANDLE)wParam, "CList", "MyHandle", &dbv)) { + strcpy(buffer, "CListName"); + strcat(buffer, _itoa(contact_number, buffer2, 10)); + MyDBWriteContactSetting(hMeta, META_PROTO, buffer, &dcws->value); + } else { + DBFreeVariant(&dbv); + } + + // copy nick to metacontact, if it's the most online + most_online = Meta_GetMostOnline(hMeta); + Meta_CopyContactNick(hMeta, most_online); + + return 0; + } else + + if(!strcmp(dcws->szSetting, "IdleTS")) { + if(dcws->value.type == DBVT_DWORD) + DBWriteContactSettingDword(hMeta, META_PROTO, "IdleTS", dcws->value.dVal); + else if(dcws->value.type == DBVT_DELETED) + DBWriteContactSettingDword(hMeta, META_PROTO, "IdleTS", 0); + } else + + if(!strcmp(dcws->szSetting, "LogonTS")) { + if(dcws->value.type == DBVT_DWORD) + DBWriteContactSettingDword(hMeta, META_PROTO, "LogonTS", dcws->value.dVal); + else if(dcws->value.type == DBVT_DELETED) + DBWriteContactSettingDword(hMeta, META_PROTO, "LogonTS", 0); + } else + + if(!strcmp(dcws->szModule, "CList") && !strcmp(dcws->szSetting, "MyHandle")) { + HANDLE most_online; + + if(dcws->value.type == DBVT_DELETED) { + DBVARIANT dbv; + + char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0); + strcpy(buffer, "CListName"); + strcat(buffer, _itoa(contact_number, buffer2, 10)); + if(proto && !MyDBGetContactSetting((HANDLE)wParam, proto, "Nick", &dbv)) { + MyDBWriteContactSetting(hMeta, META_PROTO, buffer, &dbv); + DBFreeVariant(&dbv); + } else { + DBDeleteContactSetting(hMeta, META_PROTO, buffer); + } + } else { + // subcontact clist displayname has changed - update metacontact + strcpy(buffer, "CListName"); + strcat(buffer, _itoa(contact_number, buffer2, 10)); + + MyDBWriteContactSetting(hMeta, META_PROTO, buffer, &dcws->value); + } + + // copy nick to metacontact, if it's the most online + most_online = Meta_GetMostOnline(hMeta); + Meta_CopyContactNick(hMeta, most_online); + + return 0; + } else + + if(!strcmp(dcws->szSetting, "Status") && !dcws->value.type == DBVT_DELETED) { + // subcontact changing status + + // update subcontact status setting + strcpy(buffer, "Status"); + strcat(buffer, _itoa(contact_number, buffer2, 10)); + DBWriteContactSettingWord(hMeta, META_PROTO, buffer, dcws->value.wVal); + strcpy(buffer, "StatusString"); + strcat(buffer, _itoa(contact_number, buffer2, 10)); + Meta_GetStatusString(dcws->value.wVal, buffer2, 512); + DBWriteContactSettingString(hMeta, META_PROTO, buffer, buffer2); + + // if the contact was forced, unforce it (which updates status) + if((HANDLE)DBGetContactSettingDword(hMeta, META_PROTO, "ForceSend", 0) == (HANDLE)wParam) { + MetaAPI_UnforceSendContact((WPARAM)hMeta, 0); + } else { + // set status to that of most online contact + most_online = Meta_GetMostOnline(hMeta); + Meta_CopyContactNick(hMeta, most_online); + + Meta_FixStatus(hMeta); + + Meta_CopyData(hMeta); + } + + // most online contact with avatar support might have changed - update avatar + most_online = Meta_GetMostOnlineSupporting(hMeta, PFLAGNUM_4, PF4_AVATARS); + if(most_online) { + PROTO_AVATAR_INFORMATION AI; + + AI.cbSize = sizeof(AI); + AI.hContact = hMeta; + AI.format = PA_FORMAT_UNKNOWN; + strcpy(AI.filename, "X"); + + if((int)CallProtoService(META_PROTO, PS_GETAVATARINFO, 0, (LPARAM)&AI) == GAIR_SUCCESS) + DBWriteContactSettingString(hMeta, "ContactPhoto", "File",AI.filename); + } + } else + + if(strcmp(dcws->szSetting, "XStatusId") == 0 || strcmp(dcws->szSetting, "XStatusMsg") == 0 || strcmp(dcws->szSetting, "XStatusName") == 0 || strcmp(dcws->szSetting, "StatusMsg") == 0) { + Meta_CopyData(hMeta); + } else + + if(strcmp(dcws->szSetting, "MirVer") == 0) { + Meta_CopyData(hMeta); + } else + + if(!meta_group_hack_disabled && !strcmp(dcws->szModule, "CList") && !strcmp(dcws->szSetting, "Hidden")) { + if((dcws->value.type == DBVT_DELETED || DBGetContactSettingByte((HANDLE)wParam, "CList", "Hidden", 0) == 0) + && DBGetContactSettingByte((HANDLE)wParam, META_PROTO, "Hidden", 0) == 1) + { + // a subcontact we hid (e.g. jabber) has been unhidden - hide it again :( + DBWriteContactSettingByte((HANDLE)wParam, "CList", "Hidden", 1); + } + } + } + + return 0; +} + +int Meta_ContactDeleted(WPARAM wParam, LPARAM lParam) { + HANDLE hMeta; + + // is a subcontact - update meta contact + hMeta = (HANDLE)DBGetContactSettingDword((HANDLE)wParam, META_PROTO, "Handle", 0); + if(hMeta) { + Meta_RemoveContactNumber(hMeta, DBGetContactSettingDword((HANDLE)wParam, META_PROTO, "ContactNumber", -1)); + NotifyEventHooks(hSubcontactsChanged, (WPARAM)hMeta, 0); + return 0; + } else { + // not a subcontact - is it a metacontact? + int num_contacts = DBGetContactSettingDword((HANDLE)wParam, META_PROTO, "NumContacts", 0); + int i; + HANDLE hContact; + + if(num_contacts) NotifyEventHooks(hSubcontactsChanged, (WPARAM)wParam, 0); + + // remove & restore all subcontacts + for(i = 0; i < num_contacts; i++) { + hContact = Meta_GetContactHandle((HANDLE)wParam, i); + + if(hContact && (HANDLE)DBGetContactSettingDword(hContact, META_PROTO, "Handle", 0) == (HANDLE)wParam) { + if(DBGetContactSettingByte(hContact, META_PROTO, "IsSubcontact", 0) == 1) + DBDeleteContactSetting(hContact,META_PROTO,"IsSubcontact"); + DBDeleteContactSetting(hContact,META_PROTO,META_LINK); + DBDeleteContactSetting(hContact,META_PROTO,"Handle"); + DBDeleteContactSetting(hContact,META_PROTO,"ContactNumber"); + Meta_RestoreGroup(hContact); + DBDeleteContactSetting(hContact,META_PROTO,"OldCListGroup"); + + CallService(MS_PROTO_REMOVEFROMCONTACT, (WPARAM)hContact, (LPARAM)META_FILTER); + // stop ignoring, if we were + if(options.suppress_status) + CallService(MS_IGNORE_UNIGNORE, (WPARAM)hContact, (WPARAM)IGNOREEVENT_USERONLINE); + } + } + return 0; + } + + + return 0; +} + +/** Call when we want to send a user is typing message +* +* @param wParam \c HANDLE to the contact that we are typing to +* @param lParam either PROTOTYPE_SELFTYPING_ON or PROTOTYPE_SELFTYPING_OFF +*/ +INT_PTR Meta_UserIsTyping(WPARAM wParam, LPARAM lParam) +{ + char *proto; + char buff[512]; + + if(DBGetContactSettingDword((HANDLE)wParam,META_PROTO,META_ID,(DWORD)-1) == (DWORD)-1) + { + // This is a simple contact, let through the stack of protocols + return 0; + } + else + { + // forward to sending protocol, if supported + + HANDLE most_online = Meta_GetMostOnline((HANDLE)wParam); + Meta_CopyContactNick((HANDLE)wParam, most_online); + + if(!most_online) return 0; + + proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)most_online, 0); + if(proto) { + strncpy(buff, proto, 512); + strncpy(buff + strlen(proto), PSS_USERISTYPING, 512 - strlen(proto)); + + if(ServiceExists(buff)) { + CallService(buff, (WPARAM)most_online, (LPARAM)lParam); + } + } + } + + return 0; +} + +/** Call when we want to receive a user is typing message +* +* @param wParam \c HANDLE to the contact that is typing or not +* @param lParam either PROTOTYPE_SELFTYPING_ON or PROTOTYPE_SELFTYPING_OFF +*/ +int Meta_ContactIsTyping(WPARAM wParam, LPARAM lParam) +{ + HANDLE hMeta; + + if((hMeta = (HANDLE)DBGetContactSettingDword((HANDLE)wParam,META_PROTO,"Handle",(DWORD)0)) != 0 + // check metacontacts enabled + && Meta_IsEnabled() + ) + { // This contact is attached to a MetaContact. + if(!options.subcontact_windows) { // we don't want clicking on the clist notification icon to open the metacontact message window + + // try to remove any clist events we added for subcontact + CallServiceSync(MS_CLIST_REMOVEEVENT, wParam, (LPARAM) 1); + + CallService(MS_PROTO_CONTACTISTYPING, (WPARAM)hMeta, lParam); + + // stop processing of event + return 1; + } + } + + return 0; +} + +/** Called when user info is about to be shown +* +* Returns 1 to stop event processing and opens page for metacontact default contact (returning 1 to stop it doesn't work!) +* +*/ +int Meta_UserInfo(WPARAM wParam, LPARAM lParam) +{ + DWORD default_contact_number = DBGetContactSettingDword((HANDLE)lParam, META_PROTO, "Default", (DWORD)-1); + + if(default_contact_number == -1) // not a meta contact + return 0; + + CallService(MS_USERINFO_SHOWDIALOG, (WPARAM)Meta_GetContactHandle((HANDLE)lParam, default_contact_number), 0); + + return 1; +} + +// handle message window api ver 0.0.0.1+ events - record window open/close status for subcontacts, so we know whether to +// let received messages through and add db history to metacontact, or vice versa +int Meta_MessageWindowEvent(WPARAM wParam, LPARAM lParam) { + MessageWindowEventData *mwed = (MessageWindowEventData *)lParam; + HANDLE hMeta = 0; + + message_window_api_enabled = TRUE; + + if((hMeta = (HANDLE)DBGetContactSettingDword(mwed->hContact, META_PROTO, "Handle", 0)) != 0 + || DBGetContactSettingDword(mwed->hContact, META_PROTO, META_ID, (DWORD)-1) != (DWORD)-1) + { + // contact is subcontact of metacontact, or an actual metacontact - record whether window is open or closed + if(mwed->uType == MSG_WINDOW_EVT_OPEN || mwed->uType == MSG_WINDOW_EVT_OPENING) { + DBWriteContactSettingByte(mwed->hContact, META_PROTO, "WindowOpen", 1); + + if(hMeta) { // subcontact window opened - remove clist events we added for metacontact + while(!CallService(MS_CLIST_REMOVEEVENT, (WPARAM)hMeta, (LPARAM)mwed->hContact)); + } + } else if(mwed->uType == MSG_WINDOW_EVT_CLOSE || mwed->uType == MSG_WINDOW_EVT_CLOSING) { + DBWriteContactSettingByte(mwed->hContact, META_PROTO, "WindowOpen", 0); + if(!hMeta) { // hMeta is 0 for metacontact (sorry) + DWORD saved_def; + + MetaAPI_UnforceSendContact((WPARAM)mwed->hContact, 0); + + // restore saved default contact + if(options.set_default_on_recv) { + saved_def = DBGetContactSettingDword(mwed->hContact, META_PROTO, "SavedDefault", -1); + if(options.temp_default && saved_def != (DWORD)-1) { + DBWriteContactSettingDword(mwed->hContact, META_PROTO, "Default", saved_def); + DBWriteContactSettingDword(mwed->hContact, META_PROTO, "SavedDefault", (DWORD)-1); + NotifyEventHooks(hEventDefaultChanged, (WPARAM)mwed->hContact, (LPARAM)Meta_GetContactHandle(hMeta, saved_def)); // nick set in event handler + } + } + } + } + + } + + return 0; +} +/* +int Meta_LoadIcons(WPARAM wParam, LPARAM lParam) { + PROTOCOLDESCRIPTOR **protos; + + //MessageBox(0, "LoadIcons", "Event", MB_OK); + + if(ServiceExists(MS_CLIST_EXTRA_ADD_ICON)) { + int index = 0, i; + + CallService(MS_PROTO_ENUMPROTOCOLS,(WPARAM)&proto_count,(LPARAM)&protos); + for(i = 0; i < proto_count && i < MAX_PROTOCOLS; i++) { + if(protos[i]->type!=PROTOTYPE_PROTOCOL || CallProtoService(protos[i]->szName,PS_GETCAPS,PFLAGNUM_2,0)==0) + continue; + + strncpy(proto_names + (index * 128), protos[i]->szName, 128); + hProtoIcons[index * 2] = LoadSkinnedProtoIcon(protos[i]->szName,ID_STATUS_ONLINE); + hProtoIcons[index * 2 + 1] = LoadSkinnedProtoIcon(protos[i]->szName,ID_STATUS_OFFLINE); + hExtraImage[index * 2] = 0; + hExtraImage[index * 2 + 1] = 0; + + //sprintf(buff, "Added icon (hIcon = %d, hImage = %d) for protocol %s.", hProtoIcons[index], hExtraImage[index], protos[i]->szName); + //MessageBox(0, buff, "Added Extra Icon", MB_OK); + + index++; + } + proto_count = index; + + //Meta_CListMW_ExtraIconsRebuild(0, 0); + + } + + + return 0; +} + +int Meta_CListMW_ExtraIconsRebuild(WPARAM wParam, LPARAM lParam) { + int i; + + //MessageBox(0, "IconsRebuild", "Event", MB_OK); + Meta_LoadIcons(0, 0); + + if(ServiceExists(MS_CLIST_EXTRA_ADD_ICON)) { + for(i = 0; i < proto_count; i++) { + hExtraImage[i * 2] = (HANDLE)CallService(MS_CLIST_EXTRA_ADD_ICON, (WPARAM)hProtoIcons[i * 2], 0); + hExtraImage[i * 2 + 1] = (HANDLE)CallService(MS_CLIST_EXTRA_ADD_ICON, (WPARAM)hProtoIcons[i * 2 + 1], 0); + } + } + + return 0; +} + +int Meta_CListMW_ExtraIconsApply(WPARAM wParam, LPARAM lParam) { + + //MessageBox(0, "IconsApply", "Event", MB_OK); + + if(DBGetContactSettingDword((HANDLE)wParam, META_PROTO, META_ID, (DWORD)-1) != (DWORD)-1) { + if(ServiceExists(MS_CLIST_EXTRA_SET_ICON)) { + IconExtraColumn iec; + HANDLE most_online_im = Meta_GetMostOnline((HANDLE)wParam); + int i; + + if(most_online_im) { + char *proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)most_online_im, 0); + if(proto) { + WORD status = DBGetContactSettingWord(most_online_im, proto, "Status", ID_STATUS_OFFLINE); + iec.cbSize = sizeof(iec); + for(i = 0; i < proto_count; i++) { + if(!strcmp((proto_names + i * 128), proto)) { + if(hExtraImage[i * 2 + (status == ID_STATUS_OFFLINE ? 1 : 0)]) { + iec.hImage = hExtraImage[i * 2 + (status == ID_STATUS_OFFLINE ? 1 : 0)]; + iec.ColumnType = EXTRA_ICON_ADV2; + CallService(MS_CLIST_EXTRA_SET_ICON, (WPARAM)wParam, (LPARAM)&iec); + iec.ColumnType = EXTRA_ICON_PROTO; + CallService(MS_CLIST_EXTRA_SET_ICON, (WPARAM)wParam, (LPARAM)&iec); + } + break; + } + } + } + } + } + } + return 0; +} +*/ +int Meta_ClistDoubleClicked(WPARAM wParam, LPARAM lParam) { + + if(DBGetContactSettingDword((HANDLE)wParam,META_PROTO,"Default",(WORD)-1) == (WORD)-1) + { + // This is a simple contact + return 0; + } + else + { + // -1 indicates no specific capability but respect 'ForceDefault' + HANDLE most_online = Meta_GetMostOnlineSupporting((HANDLE)wParam, PFLAGNUM_1, -1); + //DBEVENTINFO dbei; + char *proto; + char buffer[512]; + int caps; + + if(!most_online) + return 0; + + if(options.subcontact_windows) { + if(lParam) { + // contact from incoming message in lParam via (at this point) clist message event + CallService(MS_CLIST_CONTACTDOUBLECLICKED, (WPARAM)lParam, 0); + } else { + // simulate double click on most_online contact and stop event processing + CallService(MS_CLIST_CONTACTDOUBLECLICKED, (WPARAM)most_online, 0); + } + return 1; + } else { + proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)most_online, 0); + + if(proto) { + strcpy(buffer, proto); + strcat(buffer, PS_GETCAPS); + + // get the contacts messaging capabilities + caps = CallService(buffer, (WPARAM)PFLAGNUM_1, 0); + + if((caps & PF1_IMSEND) || (caps & PF1_CHAT) || (proto && strcmp(proto, "IRC") == 0)) + // let event process normally + return 0; + else { + // simulate double click on most_online contact and stop event processing + CallService(MS_CLIST_CONTACTDOUBLECLICKED, (WPARAM)most_online, 0); + return 1; + } + } else + return 0; + } + } + + return 0; +} + +INT_PTR Meta_ClistMessageEventClicked(WPARAM wParam, LPARAM lParam) { + + HANDLE hContact = ((CLISTEVENT *)lParam)->hContact; + + // hdbevent contains the id of the subcontact + return Meta_ClistDoubleClicked((WPARAM)hContact, (LPARAM)((CLISTEVENT *)lParam)->hDbEvent); +} + + +int NudgeRecieved(WPARAM wParam, LPARAM lParam) { + /* + // already being forwarded by someone + HANDLE hMeta = (HANDLE)DBGetContactSettingDword((HANDLE)wParam,META_PROTO, "Handle", (DWORD)0); + if(hMeta) + NotifyEventHooks(hEventNudge, (WPARAM)hMeta, 0); + */ + return 0; +} + +/** Called when all the plugin are loaded into Miranda. +* +* Initializes the 4 menus present in the context-menu +* and the initial value of nextMetaID +*/ +int Meta_ModulesLoaded(WPARAM wParam, LPARAM lParam) +{ + CLISTMENUITEM menu = {0}; + char buffer[512], buffer2[512], buffer3[512]; + int i; + + if(ServiceExists(MS_MSG_GETWINDOWAPI)) { + message_window_api_enabled = TRUE; + } + + if(ServiceExists(MS_UPDATE_REGISTER)) { + // register with updater + Update update = {0}; + char szVersion[16]; + + update.cbSize = sizeof(Update); + + update.szComponentName = pluginInfo.shortName; + update.pbVersion = (BYTE *)CreateVersionString(pluginInfo.version, szVersion); + update.cpbVersion = (int)strlen((char *)update.pbVersion); + update.szBetaChangelogURL = "https://server.scottellis.com.au/wsvn/mim_plugs/metacontacts/?op=log&rev=0&sc=0&isdir=1"; + + update.szUpdateURL = UPDATER_AUTOREGISTER; + + // these are the three lines that matter - the archive, the page containing the version string, and the text (or data) + // before the version that we use to locate it on the page + // (note that if the update URL and the version URL point to standard file listing entries, the backend xml + // data will be used to check for updates rather than the actual web page - this is not true for beta urls) + update.szBetaUpdateURL = "http://www.scottellis.com.au/miranda_plugins/MetaContacts.zip"; + update.szBetaVersionURL = "http://www.scottellis.com.au/miranda_plugins/ver_MetaContacts.html"; + update.pbBetaVersionPrefix = (BYTE *)"MetaContacts Plugin, version "; + + update.cpbBetaVersionPrefix = (int)strlen((char *)update.pbBetaVersionPrefix); + + CallService(MS_UPDATE_REGISTER, 0, (WPARAM)&update); + } + + + // disable group hack for older nicer versions without the fix + if(ServiceExists(MS_CLUI_GETVERSION)) { + char *version = (char *)CallService(MS_CLUI_GETVERSION, 0, 0); + if(version && strlen(version) >= strlen("CList Nicer+") && strncmp(version, "CList Nicer+", strlen("CList Nicer+")) == 0) + meta_group_hack_disabled = TRUE; + } + + // for database editor++ ver 3+ + if(ServiceExists("DBEditorpp/RegisterSingleModule")) + CallService("DBEditorpp/RegisterSingleModule",(WPARAM)META_PROTO,0); + + + hHooks[11] = (HANDLE)HookEvent(ME_CLIST_PREBUILDCONTACTMENU, Meta_ModifyMenu); + hHooks[12] = (HANDLE)HookEvent(ME_CLIST_DOUBLECLICKED, Meta_ClistDoubleClicked ); + //hHooks[13] = (HANDLE)HookEvent(ME_CLIST_EXTRA_LIST_REBUILD, Meta_CListMW_ExtraIconsRebuild); + //hHooks[14] = (HANDLE)HookEvent(ME_CLIST_EXTRA_IMAGE_APPLY, Meta_CListMW_ExtraIconsApply); + + // icons are erased on this event... + // (BUT, the me_clist_extra_list_rebuild is send FIRST...so, we ignore this one...) + hHooks[15] = 0;//(HANDLE)HookEvent(ME_SKIN_ICONSCHANGED, Meta_LoadIcons); + + menu.cbSize=sizeof(menu); + menu.flags = CMIM_ALL; + + // main menu item + menu.pszName = "Toggle MetaContacts Off"; + menu.pszService = "MetaContacts/OnOff"; + menu.position = 500010000; + hMenuOnOff = (HANDLE)CallService(MS_CLIST_ADDMAINMENUITEM,0,(LPARAM)&menu); + + // contact menu items + menu.position = -200010; + menu.pszName = "Convert to MetaContact"; + menu.pszService = "MetaContacts/Convert"; + hMenuConvert = (HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&menu); + menu.position = -200009; + menu.pszName = "Add to existing MetaContact..."; + menu.pszService = "MetaContacts/AddTo"; + hMenuAdd = (HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&menu); + + menu.position = -200010; + menu.pszName = "Edit MetaContact..."; + menu.pszService = "MetaContacts/Edit"; + hMenuEdit = (HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&menu); + menu.position = -200009; + menu.pszName = "Set as MetaContact default"; + menu.pszService = "MetaContacts/Default"; + hMenuDefault = (HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&menu); + menu.position = -200008; + menu.pszName = "Delete MetaContact"; + menu.pszService = "MetaContacts/Delete"; + hMenuDelete = (HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&menu); + //menu.pszName = "Force Default"; + //menu.pszService = "MetaContacts/ForceDefault"; + //hMenuForceDefault = (HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&menu); + + menu.flags |= CMIF_HIDDEN; + menu.pszContactOwner = META_PROTO; + + menu.position = -99000; + for(i = 0; i < MAX_CONTACTS; i++) { + menu.position--; + strcpy(buffer3, (char *)Translate("Context")); + strcat(buffer3, _itoa(i, buffer2, 10)); + menu.pszName = buffer3; + + strcpy(buffer, "MetaContacts/MenuFunc"); + strcat(buffer, _itoa(i, buffer2, 10)); + menu.pszService= buffer; + + hMenuContact[i] = (HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&menu); + } + + nextMetaID = DBGetContactSettingDword(NULL,META_PROTO,"NextMetaID",(DWORD)0); + + // attemp to subsume userinfo...(returning 1 does not prevent dialog - so disabled) + //hHooks[] = (HANDLE)HookEvent(ME_USERINFO_INITIALISE, Meta_UserInfo); + + // loop and copy data from subcontacts + if(options.copydata) { + HANDLE hContact = ( HANDLE )CallService( MS_DB_CONTACT_FINDFIRST, 0, 0 ); + int meta_id; + while ( hContact != NULL ) { + if((meta_id = DBGetContactSettingDword(hContact,META_PROTO,META_ID,(DWORD)-1))!=(DWORD)-1) { + Meta_CopyData(hContact); + } + hContact = ( HANDLE )CallService( MS_DB_CONTACT_FINDNEXT,( WPARAM )hContact, 0 ); + } + } + + Meta_HideLinkedContacts(); + + InitIcons(); + + if(!Meta_IsEnabled()) + { + // modify main menu item + menu.flags = CMIM_NAME; + menu.pszName = "Toggle MetaContacts On"; + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuOnOff, (LPARAM)&menu); + + Meta_HideMetaContacts(TRUE); + } else { + Meta_SuppressStatus(options.suppress_status); + } + + // hook srmm window close/open events - message api ver 0.0.0.1+ + hHooks[16] = (HANDLE)HookEvent(ME_MSG_WINDOWEVENT, Meta_MessageWindowEvent); + if(hHooks[16]) // message api available + message_window_api_enabled = TRUE; + + // hook protocol nudge events to forward to subcontacts + { + int i, numberOfProtocols,ret; + char str[MAXMODULELABELLENGTH + 10]; + HANDLE hNudgeEvent = NULL; + PROTOCOLDESCRIPTOR ** ppProtocolDescriptors; + ret = CallService(MS_PROTO_ENUMPROTOCOLS,(WPARAM) &numberOfProtocols,(LPARAM)&ppProtocolDescriptors); + if(ret == 0) + { + for(i = 0; i < numberOfProtocols ; i++) + { + if(ppProtocolDescriptors[i]->type == PROTOTYPE_PROTOCOL) + { + if(strcmp(ppProtocolDescriptors[i]->szName, META_PROTO)) { + sprintf(str,"%s/Nudge",ppProtocolDescriptors[i]->szName); + hNudgeEvent = HookEvent(str, NudgeRecieved); + if(hNudgeEvent != NULL) { + ++iNudgeProtos; + hNudgeEvents = realloc(hNudgeEvents, sizeof(HANDLE) * iNudgeProtos); + hNudgeEvents[iNudgeProtos - 1] = hNudgeEvent; + } + } + } + } + + } + } + return 0; +} + +static VOID CALLBACK sttMenuThread( PVOID param ) +{ + HMENU hMenu; + TPMPARAMS tpmp; + BOOL menuRet; + + hMenu = (HMENU)CallService(MS_CLIST_MENUBUILDCONTACT, (WPARAM)param, 0); + + ZeroMemory(&tpmp, sizeof(tpmp)); + tpmp.cbSize = sizeof(tpmp); + + menuRet = TrackPopupMenuEx(hMenu, TPM_RETURNCMD, menuMousePoint.x, menuMousePoint.y, (HWND)CallService(MS_CLUI_GETHWND, 0, 0), &tpmp); + + CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(menuRet), MPCF_CONTACTMENU), (LPARAM)param); + + DestroyMenu(hMenu); +} + +INT_PTR Meta_ContactMenuFunc(WPARAM wParam, LPARAM lParam) { + HANDLE hContact; + hContact = Meta_GetContactHandle((HANDLE)wParam, (int)lParam); + + if(options.menu_function == FT_MSG) { + // open message window if protocol supports message sending or chat, else simulate double click + + int caps; + char *proto; + char buffer[512]; + + proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + + if(proto) { + strcpy(buffer, proto); + strcat(buffer, PS_GETCAPS); + + caps = CallService(buffer, (WPARAM)PFLAGNUM_1, 0); + + if((caps & PF1_IMSEND) || (caps & PF1_CHAT) || (proto && strcmp(proto, "IRC") == 0)) { + // set default contact for sending/status and open message window + DBWriteContactSettingDword((HANDLE)wParam, META_PROTO, "Default", (DWORD)(int)lParam); + NotifyEventHooks(hEventDefaultChanged, wParam, (LPARAM)hContact); + CallService(MS_MSG_SENDMESSAGE, wParam, 0); + } else + // protocol does not support messaging - simulate double click + CallService(MS_CLIST_CONTACTDOUBLECLICKED, (WPARAM)hContact, 0); + } else + // protocol does not support messaging - simulate double click + CallService(MS_CLIST_CONTACTDOUBLECLICKED, (WPARAM)hContact, 0); + + } else if(options.menu_function == FT_MENU) { + // show contact's context menu + CallFunctionAsync(sttMenuThread, hContact); + } else if(options.menu_function == FT_INFO) { + // show user info for subcontact + CallService(MS_USERINFO_SHOWDIALOG, (WPARAM)hContact, 0); + } + + return 0; +} + +//////////////////// +// file transfer support - mostly not required, since subcontacts do the receiving +//////////////////// +/* +INT_PTR Meta_FileResume(WPARAM wParam, LPARAM lParam) +{ + DBVARIANT dbv; + CCSDATA *ccs = (CCSDATA *) lParam; + char *proto = 0; + + if(DBGetContactSetting(ccs->hContact,META_PROTO,"Default",&dbv)) + { + // This is a simple contact + // (this should normally not happen, since linked contacts do not appear on the list.) + return 1; + } + else + { + HANDLE most_online = Meta_GetMostOnlineSupporting(ccs->hContact, PFLAGNUM_1, PF1_FILERESUME); + //DBEVENTINFO dbei; + char szServiceName[100]; + + DBFreeVariant(&dbv); + + if(!most_online) + return 0; + + proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)most_online, 0); + + ccs->hContact = most_online; + Meta_SetNick(proto); + + _snprintf(szServiceName, sizeof(szServiceName), "%s%s", proto, PS_FILERESUME); + if (ServiceExists(szServiceName)) { + strncpy(szServiceName, PS_FILERESUME, sizeof(szServiceName)); + return (int)(CallContactService(ccs->hContact, szServiceName, ccs->wParam, ccs->lParam)); + } + } + return 1; // fail +} + +INT_PTR Meta_FileAllow(WPARAM wParam, LPARAM lParam) +{ + DBVARIANT dbv; + CCSDATA *ccs = (CCSDATA *) lParam; + char *proto = 0; + + if(DBGetContactSetting(ccs->hContact,META_PROTO,"Default",&dbv)) + { + // This is a simple contact + // (this should normally not happen, since linked contacts do not appear on the list.) + return 0; + } + else + { + HANDLE most_online = Meta_GetMostOnlineSupporting(ccs->hContact, PFLAGNUM_1, PF1_FILE); + char szServiceName[100]; + + DBFreeVariant(&dbv); + + if(!most_online) + return 0; + + proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)most_online, 0); + + ccs->hContact = most_online; + Meta_SetNick(proto); + + _snprintf(szServiceName, sizeof(szServiceName), "%s%s", proto, PSS_FILEALLOW); + if (ServiceExists(szServiceName)) { + strncpy(szServiceName, PSS_FILEALLOW, sizeof(szServiceName)); + return (int)(CallContactService(ccs->hContact, szServiceName, ccs->wParam, ccs->lParam)); + } + } + return 0; // fail +} + +INT_PTR Meta_FileDeny(WPARAM wParam, LPARAM lParam) +{ + DBVARIANT dbv; + CCSDATA *ccs = (CCSDATA *) lParam; + char *proto = 0; + + if(DBGetContactSetting(ccs->hContact,META_PROTO,"Default",&dbv)) + { + // This is a simple contact + // (this should normally not happen, since linked contacts do not appear on the list.) + return 1; + } + else + { + HANDLE most_online = Meta_GetMostOnlineSupporting(ccs->hContact, PFLAGNUM_1, PF1_FILE); + //DBEVENTINFO dbei; + char szServiceName[100]; + + DBFreeVariant(&dbv); + + if(!most_online) + return 1; + + proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)most_online, 0); + + ccs->hContact = most_online; + Meta_SetNick(proto); + + _snprintf(szServiceName, sizeof(szServiceName), "%s%s", proto, PSS_FILEDENY); + if (ServiceExists(szServiceName)) { + strncpy(szServiceName, PSS_FILEDENY, sizeof(szServiceName)); + return (int)(CallContactService(ccs->hContact, szServiceName, ccs->wParam, ccs->lParam)); + } + } + return 1; // fail +} + +INT_PTR Meta_FileRecv(WPARAM wParam, LPARAM lParam) +{ + DBVARIANT dbv; + CCSDATA *ccs = (CCSDATA *) lParam; + char *proto = 0; + + if(DBGetContactSetting(ccs->hContact,META_PROTO,"Default",&dbv)) + { + // This is a simple contact + // (this should normally not happen, since linked contacts do not appear on the list.) + return 0; + } + else + { + HANDLE most_online = Meta_GetMostOnlineSupporting(ccs->hContact, PFLAGNUM_1, PF1_FILE); + //DBEVENTINFO dbei; + char szServiceName[100]; + + DBFreeVariant(&dbv); + + if(!most_online) + return 0; + + proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)most_online, 0); + + ccs->hContact = most_online; + Meta_SetNick(proto); + + _snprintf(szServiceName, sizeof(szServiceName), "%s%s", proto, PSR_FILE); + if (ServiceExists(szServiceName)) { + strncpy(szServiceName, PSR_FILE, sizeof(szServiceName)); + return (int)(CallContactService(ccs->hContact, szServiceName, ccs->wParam, ccs->lParam)); + } + } + + return 0; +} + +int Meta_FileCancel(WPARAM wParam, LPARAM lParam) +{ + DBVARIANT dbv; + CCSDATA *ccs = (CCSDATA *) lParam; + char *proto = 0; + + if(DBGetContactSetting(ccs->hContact,META_PROTO,"Default",&dbv)) + { + // This is a simple contact + // (this should normally not happen, since linked contacts do not appear on the list.) + return 0; + } + else + { + HANDLE most_online = Meta_GetMostOnlineSupporting(ccs->hContact, PFLAGNUM_1, PF1_FILE); + //DBEVENTINFO dbei; + char szServiceName[100]; + + DBFreeVariant(&dbv); + + if(!most_online) + return 0; + + proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)most_online, 0); + + ccs->hContact = most_online; + Meta_SetNick(proto); + + _snprintf(szServiceName, sizeof(szServiceName), "%s%s", proto, PSS_FILECANCEL); + if (ServiceExists(szServiceName)) { + strncpy(szServiceName, PSS_FILECANCEL, sizeof(szServiceName)); + return (int)(CallContactService(ccs->hContact, szServiceName, ccs->wParam, ccs->lParam)); + } + } + return 0; +} +*/ + +INT_PTR Meta_FileSend(WPARAM wParam, LPARAM lParam) +{ + CCSDATA *ccs = (CCSDATA *) lParam; + char *proto = 0; + DWORD default_contact_number; + + if((default_contact_number = DBGetContactSettingDword(ccs->hContact,META_PROTO,"Default",(DWORD)-1)) == (DWORD)-1) + { + // This is a simple contact + // (this should normally not happen, since linked contacts do not appear on the list.) + //PUShowMessage("meta has no default", SM_NOTIFY); + return 0; + } + else + { + HANDLE most_online; + //DBEVENTINFO dbei; + //char szServiceName[100]; + + most_online = Meta_GetMostOnlineSupporting(ccs->hContact, PFLAGNUM_1, PF1_FILESEND); + + if(!most_online) { + //PUShowMessage("no most online for ft", SM_NOTIFY); + return 0; + } + + proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)most_online, 0); + //Meta_CopyContactNick(ccs->hContact, most_online, proto); + + if(proto) { + //ccs->hContact = most_online; + //Meta_SetNick(proto); + + // don't check for existence of service - 'accounts' based protos don't have them! + //_snprintf(szServiceName, sizeof(szServiceName), "%s%s", proto, PSS_FILE); + //if (ServiceExists(szServiceName)) { + // PUShowMessage("sending to subcontact", SM_NOTIFY); + return (int)(CallContactService(most_online, PSS_FILE, ccs->wParam, ccs->lParam)); + //} else + // PUShowMessage("no service", SM_NOTIFY); + } //else + //PUShowMessage("no proto for subcontact", SM_NOTIFY); + } + return 0; // fail +} + +INT_PTR Meta_GetAwayMsg(WPARAM wParam, LPARAM lParam) { + CCSDATA *ccs = (CCSDATA *) lParam; + char *proto = 0; + DWORD default_contact_number; + + if((default_contact_number = DBGetContactSettingDword(ccs->hContact,META_PROTO,"Default",(DWORD)-1)) == (DWORD)-1) + { + // This is a simple contact + // (this should normally not happen, since linked contacts do not appear on the list.) + return 0; + } + else + { + HANDLE most_online; + + most_online = Meta_GetMostOnlineSupporting(ccs->hContact, PFLAGNUM_1, PF1_MODEMSGRECV); + + if(!most_online) + return 0; + + proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)most_online, 0); + if(!proto) return 0; + + //Meta_CopyContactNick(ccs->hContact, most_online, proto); + + ccs->hContact = most_online; + //Meta_SetNick(proto); + + return (int)(CallContactService(ccs->hContact, PSS_GETAWAYMSG, ccs->wParam, ccs->lParam)); + } + return 0; // fail +} + +INT_PTR Meta_GetAvatarInfo(WPARAM wParam, LPARAM lParam) { + PROTO_AVATAR_INFORMATION *AI = (PROTO_AVATAR_INFORMATION *) lParam; + char *proto = 0; + DWORD default_contact_number; + + if((default_contact_number = DBGetContactSettingDword(AI->hContact,META_PROTO,"Default",(DWORD)-1)) == (DWORD)-1) + { + // This is a simple contact + // (this should normally not happen, since linked contacts do not appear on the list.) + return 0; + } + else + { + HANDLE hSub, hMeta; + char szServiceName[100]; + int result; + + hMeta = AI->hContact; + hSub = Meta_GetMostOnlineSupporting(AI->hContact, PFLAGNUM_4, PF4_AVATARS); + + if(!hSub) + return GAIR_NOAVATAR; + + proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hSub, 0); + if(!proto) return GAIR_NOAVATAR; + + AI->hContact = hSub; + + mir_snprintf(szServiceName, sizeof(szServiceName), "%s%s", proto, PS_GETAVATARINFO); + result = CallService(szServiceName, wParam, lParam); + AI->hContact = hMeta; + if (result != CALLSERVICE_NOTFOUND) return result; + } + return GAIR_NOAVATAR; // fail +} + +INT_PTR Meta_GetInfo(WPARAM wParam, LPARAM lParam) { + CCSDATA *ccs = (CCSDATA *) lParam; + char *proto = 0; + DWORD default_contact_number; + + if((default_contact_number = DBGetContactSettingDword(ccs->hContact,META_PROTO,"Default",(DWORD)-1)) == (DWORD)-1) + { + // This is a simple contact + // (this should normally not happen, since linked contacts do not appear on the list.) + return 0; + } + else + { + HANDLE most_online; + PROTO_AVATAR_INFORMATION AI; + char szServiceName[100]; + + most_online = Meta_GetMostOnlineSupporting(ccs->hContact, PFLAGNUM_4, PF4_AVATARS); + + if(!most_online) + return 0; + + proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)most_online, 0); + if(!proto) return 0; + + AI.cbSize = sizeof(AI); + AI.hContact = ccs->hContact; + AI.format = PA_FORMAT_UNKNOWN; + strcpy(AI.filename, "X"); + if((int)CallProtoService(META_PROTO, PS_GETAVATARINFO, 0, (LPARAM)&AI) == GAIR_SUCCESS) + DBWriteContactSettingString(ccs->hContact, "ContactPhoto", "File",AI.filename); + + most_online = Meta_GetMostOnline(ccs->hContact); + Meta_CopyContactNick(ccs->hContact, most_online); + + if(!most_online) + return 0; + + //Meta_CopyContactNick(ccs->hContact, most_online, proto); + + ccs->hContact = most_online; + //Meta_SetNick(proto); + + _snprintf(szServiceName, sizeof(szServiceName), "%s%s", proto, PSS_GETINFO); + if (ServiceExists(szServiceName)) { + strncpy(szServiceName, PSS_GETINFO, sizeof(szServiceName)); + return (int)(CallContactService(ccs->hContact, szServiceName, ccs->wParam, ccs->lParam)); + } + } + return 0; // fail +} + +int Meta_OptInit(WPARAM wParam, LPARAM lParam) { + OPTIONSDIALOGPAGE odp; + ZeroMemory(&odp, sizeof(odp)); + odp.cbSize = sizeof(odp); + odp.position = -790000000; + odp.hInstance = hInstance; + odp.flags = ODPF_BOLDGROUPS; + + odp.pszTemplate = MAKEINTRESOURCE(IDD_OPTIONS); + odp.pszTitle = "MetaContacts"; + odp.pszGroup = "Contact List"; + odp.pszTab = "General"; + odp.pfnDlgProc = DlgProcOpts; + CallService( MS_OPT_ADDPAGE, wParam,( LPARAM )&odp ); + + odp.pszTemplate = MAKEINTRESOURCE(IDD_PRIORITIES); + odp.pszTitle = "MetaContacts"; + odp.pszGroup = "Contact List"; + odp.pszTab = "Priorities"; + odp.pfnDlgProc = DlgProcOptsPriorities; + CallService( MS_OPT_ADDPAGE, wParam,( LPARAM )&odp ); + + odp.pszTemplate = MAKEINTRESOURCE(IDD_HISTORY); + odp.pszTitle = "MetaContacts"; + odp.pszGroup = "Contact List"; + odp.pszTab = "History"; + odp.pfnDlgProc = DlgProcOpts; + CallService( MS_OPT_ADDPAGE, wParam,( LPARAM )&odp ); + return 0; +} + +int Meta_CallMostOnline(WPARAM wParam, LPARAM lParam) { + HANDLE most_online_im = Meta_GetMostOnline((HANDLE)wParam); + + // fix nick + Meta_CopyContactNick((HANDLE)wParam, most_online_im); + + // fix status + Meta_FixStatus((HANDLE)wParam); + + // copy all other data + Meta_CopyData((HANDLE) wParam); + + return 0; +} + + +INT_PTR Meta_OnOff(WPARAM wParam, LPARAM lParam) { + CLISTMENUITEM menu; + menu.cbSize = sizeof(CLISTMENUITEM); + // just write to db - the rest is handled in the Meta_SettingChanged function + if(DBGetContactSettingByte(0, META_PROTO, "Enabled", 1)) { + DBWriteContactSettingByte(0, META_PROTO, "Enabled", 0); + // modify main menu item + menu.flags = CMIM_NAME | CMIM_ICON; + menu.hIcon = LoadIconEx(I_MENU); + menu.pszName = "Toggle MetaContacts On"; + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuOnOff, (LPARAM)&menu); + } else { + DBWriteContactSettingByte(0, META_PROTO, "Enabled", 1); + // modify main menu item + menu.flags = CMIM_NAME | CMIM_ICON; + menu.hIcon = LoadIconEx(I_MENUOFF); + menu.pszName = "Toggle MetaContacts Off"; + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuOnOff, (LPARAM)&menu); + } + ReleaseIconEx(menu.hIcon); + + return 0; +} + + +int Meta_PreShutdown(WPARAM wParam, LPARAM lParam) { + //MessageBox(0, "Preshutdown called", "MC", MB_OK); + Meta_SetStatus((WPARAM)ID_STATUS_OFFLINE, 0); + Meta_UnhideLinkedContacts(); + Meta_SuppressStatus(FALSE); + //MessageBox(0, "Status is OFFLINE", "MC", MB_OK); + //MessageBox(0, "Preshutdown complete", "MC", MB_OK); + + if(setStatusTimerId) KillTimer(0, setStatusTimerId); + + return 0; +} + +int Meta_OkToExit(WPARAM wParam, LPARAM lParam) { + Meta_SetStatus((WPARAM)ID_STATUS_OFFLINE, 0); + return 0; +} + +int Meta_OnIdleChanged(WPARAM wParam, LPARAM lParam) { + return 0; +} + +/** Initializes all services provided by the plugin +* +* Creates every function and hooks the event desired. +*/ +void Meta_InitServices() +{ + int i; + + previousMode = mcStatus = ID_STATUS_OFFLINE; + + // set hooks pointers and services pointers to zero - in case we do not initialize them all correctly + for(i=0;i