From 1ca120b165c2f2d9f521a04bfc31c7956d2ce422 Mon Sep 17 00:00:00 2001 From: Vadim Dashevskiy Date: Tue, 17 Jul 2012 06:57:55 +0000 Subject: ContactsPlus, CountryFlags, CrashDumper: changed folder structure git-svn-id: http://svn.miranda-ng.org/main/trunk@1000 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/ContactsPlus/src/contacts.cpp | 31 ++ plugins/ContactsPlus/src/contacts.h | 77 ++++ plugins/ContactsPlus/src/main.cpp | 317 +++++++++++++ plugins/ContactsPlus/src/receive.cpp | 522 +++++++++++++++++++++ plugins/ContactsPlus/src/receive.h | 65 +++ plugins/ContactsPlus/src/resource.h | 44 ++ plugins/ContactsPlus/src/send.cpp | 609 +++++++++++++++++++++++++ plugins/ContactsPlus/src/send.h | 110 +++++ plugins/ContactsPlus/src/utils.cpp | 832 ++++++++++++++++++++++++++++++++++ plugins/ContactsPlus/src/utils.h | 86 ++++ 10 files changed, 2693 insertions(+) create mode 100644 plugins/ContactsPlus/src/contacts.cpp create mode 100644 plugins/ContactsPlus/src/contacts.h create mode 100644 plugins/ContactsPlus/src/main.cpp create mode 100644 plugins/ContactsPlus/src/receive.cpp create mode 100644 plugins/ContactsPlus/src/receive.h create mode 100644 plugins/ContactsPlus/src/resource.h create mode 100644 plugins/ContactsPlus/src/send.cpp create mode 100644 plugins/ContactsPlus/src/send.h create mode 100644 plugins/ContactsPlus/src/utils.cpp create mode 100644 plugins/ContactsPlus/src/utils.h (limited to 'plugins/ContactsPlus/src') diff --git a/plugins/ContactsPlus/src/contacts.cpp b/plugins/ContactsPlus/src/contacts.cpp new file mode 100644 index 0000000000..a7ba2cdfbb --- /dev/null +++ b/plugins/ContactsPlus/src/contacts.cpp @@ -0,0 +1,31 @@ +// -------------------------------------------------------------------------- +// Contacts+ for Miranda Instant Messenger +// _______________________________________ +// +// Copyright © 2002 Dominus Procellarum +// Copyright © 2004-2008 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- + +#include "contacts.h" + + +bool WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + hInst = hinstDLL; + return TRUE; +} diff --git a/plugins/ContactsPlus/src/contacts.h b/plugins/ContactsPlus/src/contacts.h new file mode 100644 index 0000000000..742f577924 --- /dev/null +++ b/plugins/ContactsPlus/src/contacts.h @@ -0,0 +1,77 @@ +// --------------------------------------------------------------------------- +// Contacts+ for Miranda Instant Messenger +// _______________________________________ +// +// Copyright © 2002 Dominus Procellarum +// Copyright © 2004-2008 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// --------------------------------------------------------------------------- + +#define _CRT_SECURE_NO_WARNINGS +#define _CRT_NONSTDC_NO_WARNINGS + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +//!!this is fake - this plugin maintains backward compatibility internally +#define MIRANDA_VER 0x0A00 + +#include "newpluginapi.h" +#include "m_system.h" +#include "m_protocols.h" +#include "m_protosvc.h" +#include "m_database.h" +#include "m_utils.h" +#include "m_langpack.h" +#include "m_skin.h" +#include "m_clist.h" +#include "m_clc.h" +#include "m_clui.h" +#include "m_addcontact.h" +#include "m_history.h" +#include "m_userinfo.h" +#include "m_button.h" +#include "m_contacts.h" +#include "m_message.h" +#include "statusmodes.h" +#include "win2k.h" + +#include "resource.h" + +#include "utils.h" +#include "send.h" +#include "receive.h" + +#define MODULENAME "SendReceiveContacts" + + +#define MS_CONTACTS_SEND "ContactsTransfer/SendContacts" +#define MS_CONTACTS_RECEIVE "ContactsTransfer/ReceiveContacts" + +// Global Variables +extern int g_UnicodeCore; +extern int g_NewProtoAPI; +extern int g_SendAckSupported; +extern int g_Utf8EventsSupported; diff --git a/plugins/ContactsPlus/src/main.cpp b/plugins/ContactsPlus/src/main.cpp new file mode 100644 index 0000000000..da43554c29 --- /dev/null +++ b/plugins/ContactsPlus/src/main.cpp @@ -0,0 +1,317 @@ +// -------------------------------------------------------------------------- +// Contacts+ for Miranda Instant Messenger +// _______________________________________ +// +// Copyright © 2002 Dominus Procellarum +// Copyright © 2004-2008 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- + +#include "contacts.h" + + +HINSTANCE hInst; + +int hLangpack; + +int g_NewProtoAPI = TRUE; + +int g_SendAckSupported = TRUE; +int g_Utf8EventsSupported = TRUE; + +HANDLE ghSendWindowList; +HANDLE ghRecvWindowList; +gAckList gaAckData; + +HANDLE hServiceSend; +HANDLE hServiceReceive; + +HANDLE hHookModulesLoaded = NULL; +HANDLE hHookDBEventAdded = NULL; +HANDLE hHookContactDeleted = NULL; +HANDLE hHookContactSettingChanged = NULL; +HANDLE hHookPreBuildContactMenu = NULL; + +HANDLE hContactMenuItem = NULL; + +int g_UnicodeCore; + +PLUGININFOEX pluginInfo = { + sizeof(PLUGININFOEX), + "Send/Receive Contacts+", + PLUGIN_MAKE_VERSION(1,5,2,0), + "Allows you to send and receive contacts", + "Joe Kucera, Todor Totev", + "jokusoftware@miranda-im.org", + "(C) 2004-2008 Joe Kucera, Original Code (C) 2002 Dominus Procellarum", + "http://addons.miranda-im.org/details.php?action=viewfile&id=1253", + UNICODE_AWARE, + {0x0324785E, 0x74CE, 0x4600, {0xB7, 0x81, 0x85, 0x17, 0x73, 0xB3, 0xEF, 0xC5 } } // {0324785E-74CE-4600-B781-851773B3EFC5} +}; + + +static int HookDBEventAdded(WPARAM wParam, LPARAM lParam) +{ + HANDLE hContact = (HANDLE)wParam; + HANDLE hDbEvent = (HANDLE)lParam; + //process the event + DBEVENTINFO dbe = {0}; + + dbe.cbSize = sizeof(DBEVENTINFO); + //get event details + CallService(MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM)&dbe); + //check if we should process the event + if (dbe.flags & (DBEF_SENT|DBEF_READ) || dbe.eventType != EVENTTYPE_CONTACTS) return 0; + //get event contents + dbe.cbBlob = CallService(MS_DB_EVENT_GETBLOBSIZE, (WPARAM)hDbEvent, 0); + if (dbe.cbBlob != -1) + dbe.pBlob = (PBYTE)_alloca(dbe.cbBlob); + CallService(MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM)&dbe); + //play received sound + SkinPlaySound("RecvContacts"); + { //add event to the contact list + CLISTEVENT cle = {0}; + TCHAR caToolTip[128]; + + cle.cbSize = sizeof(cle); + cle.hContact = hContact; + cle.hDbEvent = hDbEvent; + cle.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_CONTACTS)); + cle.pszService = MS_CONTACTS_RECEIVE; + + WCHAR tmp[MAX_PATH]; + _snprintfT(caToolTip, 64, "%s %s", SRCTranslateT("Contacts received from", tmp), (TCHAR*)GetContactDisplayNameT(hContact)); + + cle.ptszTooltip = caToolTip; + if (g_UnicodeCore) + cle.flags |= CLEF_UNICODE; + CallService(MS_CLIST_ADDEVENT, 0, (LPARAM)&cle); + } + return 0; //continue processing by other hooks +} + + +static void ProcessUnreadEvents(void) +{ + DBEVENTINFO dbei = {0}; + HANDLE hDbEvent,hContact; + + dbei.cbSize = sizeof(dbei); + + hContact = SRCFindFirstContact(); + while (hContact) + { + hDbEvent = (HANDLE)CallService(MS_DB_EVENT_FINDFIRSTUNREAD,(WPARAM)hContact,0); + + while (hDbEvent) + { + dbei.cbBlob=0; + CallService(MS_DB_EVENT_GET,(WPARAM)hDbEvent,(LPARAM)&dbei); + if (!(dbei.flags&(DBEF_SENT|DBEF_READ)) && dbei.eventType==EVENTTYPE_CONTACTS) + { //process the event + HookDBEventAdded((WPARAM)hContact, (LPARAM)hDbEvent); + } + hDbEvent = (HANDLE)CallService(MS_DB_EVENT_FINDNEXT,(WPARAM)hDbEvent,0); + } + hContact = SRCFindNextContact(hContact); + } +} + + +static bool CheckContactsServiceSupport(const char* szProto) +{ + if (g_NewProtoAPI) + { // there is no way to determine if the service exists (only proto_interface call is supported by 0.8+) + if (CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_CONTACTSEND) + return true; + } + else + { // check the real send service (only 0.7.x and older) + char serstr[MAX_PATH+30]; + + strcpy(serstr, szProto); + strcat(serstr, PSS_CONTACTS); + if (ServiceExists(serstr)) + return true; + } + return false; +} + + +static int HookPreBuildContactMenu(WPARAM wParam, LPARAM lParam) +{ + HANDLE hContact = (HANDLE)wParam; + char* szProto = GetContactProto(hContact); + int bVisible = FALSE; + + if (szProto && CheckContactsServiceSupport(szProto)) + { // known protocol, protocol supports contacts sending + // check the selected contact if it supports contacts receive + if (CallProtoService(szProto, PS_GETCAPS, PFLAG_MAXCONTACTSPERPACKET, (LPARAM)hContact)) + bVisible = TRUE; + } + + { // update contact menu item's visibility + CLISTMENUITEM mi = {0}; + + mi.cbSize = sizeof(mi); + if (bVisible) + mi.flags = CMIM_FLAGS; + else + mi.flags = CMIM_FLAGS | CMIF_HIDDEN; + + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hContactMenuItem, (LPARAM)&mi); + } + + return 0; +} + + +static int HookModulesLoaded(WPARAM wParam, LPARAM lParam) +{ + char* modules[2] = {0}; + WCHAR tmp[MAX_PATH]; + + modules[0] = MODULENAME; + CallService("DBEditorpp/RegisterModule",(WPARAM)modules,(LPARAM)1); + + CLISTMENUITEM mi = {0}; + mi.cbSize = sizeof(mi); + mi.ptszName = SRCTranslateT("Contacts", tmp); + mi.position = -2000009990; //position in menu + mi.flags = CMIF_KEEPUNTRANSLATED; + if (g_UnicodeCore) + mi.flags |= CMIF_UNICODE; + mi.pszService = MS_CONTACTS_SEND; + mi.hIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_CONTACTS)); + hContactMenuItem = Menu_AddContactMenuItem(&mi); + + hHookPreBuildContactMenu = HookEvent(ME_CLIST_PREBUILDCONTACTMENU, HookPreBuildContactMenu); + + ghSendWindowList = (HANDLE)CallService(MS_UTILS_ALLOCWINDOWLIST, 0, 0); // no need to destroy this + ghRecvWindowList = (HANDLE)CallService(MS_UTILS_ALLOCWINDOWLIST, 0, 0); // no need to destroy this + + + ProcessUnreadEvents(); + return 0; +} + + +static int HookContactSettingChanged(WPARAM wParam, LPARAM lParam) +{ + DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING*)lParam; + char *szProto = GetContactProto((HANDLE)wParam); + + if (strcmpnull(cws->szModule,"CList") && strcmpnull(cws->szModule, szProto)) return 0; + + WindowList_Broadcast(ghSendWindowList,DM_UPDATETITLE,0,0); + WindowList_Broadcast(ghRecvWindowList,DM_UPDATETITLE,0,0); + + return 0; +} + + +static int HookContactDeleted(WPARAM wParam, LPARAM lParam) +{ // if our contact gets deleted close his window + HWND h = WindowList_Find(ghSendWindowList,(HANDLE)wParam); + + if (h) + { + SendMessageT(h,WM_CLOSE,0,0); + } + + while (h = WindowList_Find(ghRecvWindowList, (HANDLE)wParam)) + { // since we hack the window list - more windows for one contact, we need to close them all + SendMessageT(h, WM_CLOSE,0,0); + } + return 0; +} + + +static INT_PTR ServiceSendCommand(WPARAM wParam, LPARAM lParam) +{ + HWND hWnd; + //find window for hContact + hWnd = WindowList_Find(ghSendWindowList, (HANDLE)wParam); + + if (!hWnd) + CreateDialogParamT(hInst, MAKEINTRESOURCE(IDD_SEND), NULL, SendDlgProc, (LPARAM)(HANDLE)wParam); + else + { + SetForegroundWindow(hWnd); + SetFocus(hWnd); + } + return 0; +} + +static INT_PTR ServiceReceiveCommand(WPARAM wParam, LPARAM lParam) +{ + CLISTEVENT* pcle = (CLISTEVENT*)lParam; + + CreateDialogParamT(hInst, MAKEINTRESOURCE(IDD_RECEIVE), NULL, RecvDlgProc, (LPARAM)pcle); + + return 0; +} + +extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) +{ + return &pluginInfo; +} + +extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = {MIID_SRCONTACTS, MIID_LAST}; + +extern "C" __declspec(dllexport) int Load(void) +{ + mir_getLP(&pluginInfo); + InitCommonControls(); + InitI18N(); + + { // Are we running under unicode Miranda core ? + char szVer[MAX_PATH]; + + CallService(MS_SYSTEM_GETVERSIONTEXT, MAX_PATH, (LPARAM)szVer); + _strlwr(szVer); + g_UnicodeCore = (strstr(szVer, "unicode") != NULL); + } + //init hooks + hHookModulesLoaded = HookEvent(ME_SYSTEM_MODULESLOADED, HookModulesLoaded); + hHookDBEventAdded = HookEvent(ME_DB_EVENT_ADDED, HookDBEventAdded); + hHookContactDeleted = HookEvent(ME_DB_CONTACT_DELETED, HookContactDeleted); + hHookContactSettingChanged = HookEvent(ME_DB_CONTACT_SETTINGCHANGED, HookContactSettingChanged); + //create services + hServiceSend = CreateServiceFunction(MS_CONTACTS_SEND, ServiceSendCommand); + hServiceReceive = CreateServiceFunction(MS_CONTACTS_RECEIVE, ServiceReceiveCommand); + //define event sounds + SkinAddNewSound("RecvContacts", LPGEN("Incoming Contacts"), "contacts.wav"); + SkinAddNewSound("SentContacts", LPGEN("Outgoing Contacts"), "ocontacts.wav"); + + return 0; +} + +extern "C" __declspec(dllexport) int Unload(void) +{ + UnhookEvent(hHookModulesLoaded); + UnhookEvent(hHookDBEventAdded); + UnhookEvent(hHookContactDeleted); + UnhookEvent(hHookContactSettingChanged); + UnhookEvent(hHookPreBuildContactMenu); + + DestroyServiceFunction(hServiceSend); + DestroyServiceFunction(hServiceReceive); + + return 0; +} diff --git a/plugins/ContactsPlus/src/receive.cpp b/plugins/ContactsPlus/src/receive.cpp new file mode 100644 index 0000000000..3d3fb2f773 --- /dev/null +++ b/plugins/ContactsPlus/src/receive.cpp @@ -0,0 +1,522 @@ +// -------------------------------------------------------------------------- +// Contacts+ for Miranda Instant Messenger +// _______________________________________ +// +// Copyright © 2002 Dominus Procellarum +// Copyright © 2004-2008 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// ----------------------------------------------------------------------------- + +#include "contacts.h" + + +/* TRecvContactsData */ + +TReceivedItem* TRecvContactsData::AddReceivedItem() { + int iItem = cbReceived; + + cbReceived++; + maReceived = (TReceivedItem**)realloc(maReceived, cbReceived*sizeof(TReceivedItem*)); + maReceived[iItem] = new TReceivedItem(); + + return maReceived[iItem]; +} + + +static int RecvDlg_Resize(HWND hwndDlg,LPARAM lParam,UTILRESIZECONTROL *urc) +{ + switch (urc->wId) + { + case IDC_CONTACTS: + return RD_ANCHORX_WIDTH | RD_ANCHORY_HEIGHT; + break; + case IDOK: + case IDDETAILS: + case IDC_ENABLEGROUPS: + case IDC_GROUPS: + return RD_ANCHORX_LEFT | RD_ANCHORY_BOTTOM; + break; + case IDC_ADD: + case IDC_HISTORY: + case IDC_USERMENU: + case IDC_DETAILS: + return RD_ANCHORX_RIGHT | RD_ANCHORY_TOP; + break; + case IDCANCEL: + return RD_ANCHORY_BOTTOM | RD_ANCHORX_RIGHT; + break; + } + return RD_ANCHORX_LEFT | RD_ANCHORY_TOP; // default +} + + +static char* ListView_GetItemTextEx(HWND hLV, int iItem, int iSubItem) +{ + LVITEM lvi = {0}; + + lvi.mask = LVIF_TEXT; + lvi.iSubItem = iSubItem; + lvi.cchTextMax = 64; + lvi.pszText = (char*)malloc(lvi.cchTextMax); + while (SendMessageT(hLV, LVM_GETITEMTEXT, iItem, (LPARAM)&lvi) == lvi.cchTextMax - 1) + { // loop until the returned size is smaller than buffer size + SAFE_FREE((void**)&lvi.pszText); + lvi.cchTextMax += 64; + lvi.pszText = (char*)malloc(lvi.cchTextMax); + } + return lvi.pszText; +} + + +static void EnableGroupCombo(HWND hwndDlg) +{ + EnableDlgItem(hwndDlg, IDC_GROUPS, SendMessageT(GetDlgItem(hwndDlg, IDC_ENABLEGROUPS), BM_GETCHECK, 0, 0)); +} + + +static void RebuildGroupCombo(HWND hwndDlg) +{ + DBVARIANT dbv = {0}; + char caGroupId[33]; + int bHasGroups = !DBGetContactSettingT(NULL, "CListGroups", "0", &dbv); + HWND hGroupsCombo = GetDlgItem(hwndDlg, IDC_GROUPS); + + DBFreeVariant(&dbv); + if (bHasGroups) + { + int curs = SendMessageT(hGroupsCombo, CB_GETCURSEL, 0, 0); + TCHAR* curst; + + EnableDlgItem(hwndDlg, IDC_ENABLEGROUPS, TRUE); + EnableGroupCombo(hwndDlg); + + if (curs != CB_ERR) + { + curst = (char*)_alloca((SendMessageT(hGroupsCombo, CB_GETLBTEXTLEN, curs, 0) + 1) * sizeof(WCHAR)); + SendMessageT(hGroupsCombo, CB_GETLBTEXT, curs, (LPARAM)curst); + } + SendMessageT(hGroupsCombo, CB_RESETCONTENT, 0, 0); + + for (int groupId=0; ; groupId++) + { + itoa(groupId, caGroupId, 10); + TCHAR* szGroup = DBGetContactSettingStringT(NULL, "CListGroups", caGroupId, NULL); + int nPrefix = g_UnicodeCore ? sizeof(WCHAR) : sizeof(char); + if (!szGroup) break; + int nIndex = SendMessageT(hGroupsCombo, CB_ADDSTRING, 0, (LPARAM)szGroup + nPrefix); + SendMessageT(hGroupsCombo, CB_SETITEMDATA, nIndex, groupId+1); + SAFE_FREE((void**)&szGroup); + } + if (curs != CB_ERR) + SendMessageT(hGroupsCombo, CB_SELECTSTRING, -1, (LPARAM)curst); + else + SendMessageT(hGroupsCombo, CB_SETCURSEL, 0, 0); + } + else + { // no groups available + EnableDlgItem(hwndDlg, IDC_ENABLEGROUPS, FALSE); + EnableDlgItem(hwndDlg, IDC_GROUPS, FALSE); + } +} + + +static HANDLE CreateTemporaryContactForItem(HWND hwndDlg, TRecvContactsData* wndData, int iItem) +{ + char* caUIN = ListView_GetItemTextEx(GetDlgItem(hwndDlg, IDC_CONTACTS), iItem, 0); + char* szProto = GetContactProto(wndData->mhContact); + wndData->rhSearch = (HANDLE)CallProtoService(szProto, PS_BASICSEARCH, 0, (LPARAM)caUIN); // find it + SAFE_FREE((void**)&wndData->haUin); + wndData->haUin = caUIN; + for (int j = 0; j < wndData->cbReceived; j++) + if (!strcmpnull(wndData->maReceived[j]->mcaUIN, caUIN)) + return (HANDLE)CallProtoService(szProto, PS_ADDTOLISTBYEVENT, MAKEWPARAM(PALF_TEMPORARY, j), (LPARAM)wndData->mhDbEvent); + return NULL; +} + + +void RecvListView_AddColumn(HWND hList, int nWidth, const char* szTitle, int nTranslate, int nItem) { + LVCOLUMN col; + WCHAR tmp[MAX_PATH]; + + + col.mask = LVCF_FMT|LVCF_WIDTH|LVCF_TEXT|LVCF_SUBITEM; + col.fmt = LVCFMT_LEFT; + col.cx = nWidth; + if (nTranslate) { + col.pszText = SRCTranslateT(szTitle, tmp); + } + else { + if (!szTitle) szTitle = "UID"; + col.pszText = ansi_to_tchar(szTitle, CallService(MS_LANGPACK_GETCODEPAGE, 0, 0)); + } + col.iSubItem = nItem; + ListView_InsertColumnT(hList, nItem, &col); + if (!nTranslate) + SAFE_FREE((void**)&col.pszText); +} + + +INT_PTR CALLBACK RecvDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + TRecvContactsData* wndData = (TRecvContactsData*)GetWindowLongPtr(hwndDlg, DWLP_USER); + + switch (msg) + { + case WM_INITDIALOG: + { + CLISTEVENT* pcle = (CLISTEVENT*)lParam; /// got it + + TranslateDialogDefault(hwndDlg); + WindowList_Add(ghRecvWindowList, hwndDlg, pcle->hContact); + SendMessageT(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(hInst, MAKEINTRESOURCE(IDI_CONTACTS))); + EnableDlgItem(hwndDlg, IDOK, FALSE); + EnableDlgItem(hwndDlg, IDDETAILS, FALSE); + wndData = new TRecvContactsData(pcle->hContact); + SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG)wndData); + wndData->mhDbEvent = pcle->hDbEvent; /// initialized, pcle not needed anymore + wndData->mhListIcon = ImageList_Create(GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),ILC_COLORDDB|ILC_MASK, 0, 1); + wndData->mhPopup = LoadMenu(hInst, MAKEINTRESOURCE(IDR_CONTACTMENU)); + TranslateMenu(wndData->mhPopup); + wndData->hHook = HookEventMessage(ME_PROTO_ACK, hwndDlg, HM_EVENTSENT); + + char *szProto = GetContactProto(wndData->mhContact); + + HWND hLV = GetDlgItem(hwndDlg, IDC_CONTACTS); + ListView_SetExtendedListViewStyle(hLV, LVS_EX_CHECKBOXES|LVS_EX_FULLROWSELECT); + // add columns + RecvListView_AddColumn(hLV, 120, (char*)CallProtoService(szProto, PS_GETCAPS, PFLAG_UNIQUEIDTEXT, 0), FALSE, 0); + RecvListView_AddColumn(hLV, 100, "Nick", TRUE, 1); + RecvListView_AddColumn(hLV, 100, "First Name", TRUE, 2); + RecvListView_AddColumn(hLV, 100, "Last Name", TRUE, 3); + + // fill in groups + SendMessageT(GetDlgItem(hwndDlg, IDC_ENABLEGROUPS), BM_SETCHECK, (WPARAM)BST_UNCHECKED, 0); + RebuildGroupCombo(hwndDlg); + + { // fill listview with received contacts + DBEVENTINFO dbe = {0}; + + dbe.cbSize = sizeof(DBEVENTINFO); + dbe.cbBlob = CallService(MS_DB_EVENT_GETBLOBSIZE, (WPARAM)wndData->mhDbEvent, 0); + if (dbe.cbBlob != -1) // this marks an invalid hDbEvent - all smashed anyway... + dbe.pBlob = (PBYTE)_alloca(dbe.cbBlob); + CallService(MS_DB_EVENT_GET, (WPARAM)wndData->mhDbEvent, (LPARAM)&dbe); + char* pcBlob = (char*)dbe.pBlob; + char* pcEnd = (char*)dbe.pBlob + dbe.cbBlob; + + HICON hiProto = LoadContactProtoIcon(wndData->mhContact); + ImageList_AddIcon(wndData->mhListIcon, hiProto); + DestroyIcon(hiProto); // imagelist copied the resource + ListView_SetImageList(hLV, wndData->mhListIcon, LVSIL_SMALL); + LVITEM lvi = {0}; + lvi.iImage = 0; + lvi.mask = LVIF_TEXT | LVIF_IMAGE; + + for (int nItem = 0; ; nItem++) + { // Nick + int strsize = (int)strlennull(pcBlob); + TReceivedItem* pItem = wndData->AddReceivedItem(); + + if (dbe.flags & DBEF_UTF) + pItem->mcaNick = utf8_to_tchar((unsigned char*)pcBlob); + else + pItem->mcaNick = ansi_to_tchar(pcBlob); + pcBlob += strsize + 1; + // UIN + strsize = (int)strlennull(pcBlob); + pItem->mcaUIN = null_strdup(pcBlob); + pcBlob += strsize + 1; + // add to listview + lvi.iItem = nItem; + lvi.pszText = pItem->mcaUIN; + ListView_InsertItem(hLV, &lvi); // with image + ListView_SetItemTextT(hLV, nItem, 1, pItem->mcaNick); + // check for end of contacts + if (pcBlob >= pcEnd) + break; + } + } + // new dlg init + wndData->hIcons[0] = InitMButton(hwndDlg, IDC_ADD, MAKEINTRESOURCEA(IDI_ADDCONTACT), "Add Contact Permanently to List"); + wndData->hIcons[1] = InitMButton(hwndDlg, IDC_DETAILS, MAKEINTRESOURCEA(IDI_USERDETAILS), "View User's Details"); + wndData->hIcons[2] = InitMButton(hwndDlg, IDC_HISTORY, MAKEINTRESOURCEA(IDI_HISTORY), "View User's History"); + wndData->hIcons[3] = InitMButton(hwndDlg, IDC_USERMENU, MAKEINTRESOURCEA(IDI_DOWNARROW), "User Menu"); + + SendMessageT(hwndDlg,DM_UPDATETITLE,0,0); + // new dialog init done + Utils_RestoreWindowPosition(hwndDlg, NULL, MODULENAME, ""); + return TRUE; + } + case WM_NOTIFY: + if (((LPNMHDR)lParam)->idFrom == IDC_CONTACTS) + { + switch (((LPNMHDR)lParam)->code) + { + case NM_DBLCLK: + { + HWND hLV = GetDlgItem(hwndDlg, IDC_CONTACTS); + if (ListView_GetSelectedCount(hLV) != 1) break; // if not clicking on item, bye + wndData->iPopupItem = ListView_GetNextItem(hLV, -1, LVNI_ALL|LVNI_SELECTED); + if (wndData->iPopupItem == -1) break; // if no item selected no user details available + return SendMessageT(hwndDlg, WM_COMMAND, ID_POPUP_USERDETAILS, 0); // show user details + } + case LVN_ITEMCHANGED: + { + LPNMLISTVIEW pNMLV = (LPNMLISTVIEW)lParam; + HWND hLV = GetDlgItem(hwndDlg, IDC_CONTACTS); // optimisation, for FOR-Cycle + bool bExistsCheckedItem = false; // there must be no checked items to disable "Add" button + + if (ListView_GetCheckState(hLV, pNMLV->iItem)) + { // the user has checked this item + bExistsCheckedItem = true; // enable "Add" button + } + else + { // loop thru items and check if at least one is checked + for (int i = 0; i < ListView_GetItemCount(hLV); i++) + if (ListView_GetCheckState(hLV, i)) + { // we found checked item, enable add, exit loop + bExistsCheckedItem = true; + break; + } + } + EnableDlgItem(hwndDlg, IDOK, bExistsCheckedItem); + EnableDlgItem(hwndDlg, IDDETAILS, ListView_GetSelectedCount(hLV) > 0); + break; + } + } + } + break; + + case WM_COMMAND: + { + if (!lParam && CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(wParam), MPCF_CONTACTMENU), (LPARAM)wndData->mhContact)) + break; + + switch(LOWORD(wParam)) + { + case IDOK: // "Add Selected" button click + { // for each selected item, find its index in the hDbEvent + // and after that add this item to the DB permanently + char* caUIN; + HWND hLV = GetDlgItem(hwndDlg, IDC_CONTACTS); + HWND hGroupsCombo = GetDlgItem(hwndDlg, IDC_GROUPS); + HWND hGroupsCheck = GetDlgItem(hwndDlg, IDC_ENABLEGROUPS); + int curs = SendMessageT(hGroupsCombo, CB_GETCURSEL, 0, 0); + TCHAR* caGroup = NULL; + int nGroupId = -1; + if (curs != CB_ERR && IsWindowEnabled(hGroupsCheck) && SendMessageT(hGroupsCheck, BM_GETCHECK, 0, 0)) + { //got groups, get the one selected in combo + TCHAR* caGroup = (TCHAR*)_alloca((SendMessageT(hGroupsCombo, CB_GETLBTEXTLEN, curs, 0) + 1) * sizeof(WCHAR)); + SendMessageT(hGroupsCombo, CB_GETLBTEXT, curs, (LPARAM)caGroup); + nGroupId = SendMessageT(hGroupsCombo, CB_GETITEMDATA, curs, 0); + } + + for (int i = 0; i < ListView_GetItemCount(hLV); i++) + if (ListView_GetCheckState(hLV, i)) + { // found checked contact item, add it + caUIN = ListView_GetItemTextEx(hLV, i, 0); + for (int j = 0; j < wndData->cbReceived; j++) // determine item index in packet + if (!strcmpnull(wndData->maReceived[j]->mcaUIN, caUIN)) + { + char* szProto = GetContactProto(wndData->mhContact); + HANDLE hContact = (HANDLE)CallProtoService(szProto, PS_ADDTOLISTBYEVENT, MAKEWPARAM(0, j), (LPARAM)wndData->mhDbEvent); + if (hContact && caGroup) + { // use newest group API if available + if (ServiceExists(MS_CLIST_CONTACTCHANGEGROUP)) + CallService(MS_CLIST_CONTACTCHANGEGROUP, (WPARAM)hContact, (LPARAM)nGroupId); + else + DBWriteContactSettingStringT(hContact, "CList", "Group", caGroup); + } + break; + } + SAFE_FREE((void**)&caUIN); + } // move to next item + break; + } + case IDDETAILS: + { // for each selected item, find its index in the hDbEvent + // and after that add this item to the DB + // finally, request Details window for this hContact + HWND hLV = GetDlgItem(hwndDlg, IDC_CONTACTS); + for (int i = 0; i < ListView_GetItemCount(hLV); i++) + if (ListView_GetItemState(hLV, i, LVIS_SELECTED)) + { + HANDLE hContact = CreateTemporaryContactForItem(hwndDlg, wndData, i); + if (hContact) + CallService(MS_USERINFO_SHOWDIALOG, (WPARAM)hContact, 0); + } + break; + } + case IDCANCEL: + { + SendMessageT(hwndDlg, WM_CLOSE, 0, 0); + break; + } + case IDC_ENABLEGROUPS: + { + EnableGroupCombo(hwndDlg); + break; + } + case IDC_GROUPS: + { // rebuild group list on popup + if (HIWORD(wParam) == CBN_DROPDOWN) + RebuildGroupCombo(hwndDlg); + break; + } + case ID_POPUP_ADDUSER: + { + HANDLE hContact = CreateTemporaryContactForItem(hwndDlg, wndData, wndData->iPopupItem); + + if (hContact) + DialogAddContactExecute(hwndDlg, hContact); + break; + } + case ID_POPUP_USERDETAILS: + { + HANDLE hContact = CreateTemporaryContactForItem(hwndDlg, wndData, wndData->iPopupItem); + + if (hContact) + CallService(MS_USERINFO_SHOWDIALOG, (WPARAM)hContact, 0 ); + break; + } + case ID_POPUP_SENDMESSAGE: + { + HANDLE hContact = CreateTemporaryContactForItem(hwndDlg, wndData, wndData->iPopupItem); + + if (hContact) + CallService(MS_MSG_SENDMESSAGE, (WPARAM)hContact, 0); + break; + } + case IDC_USERMENU: + { + RECT rc; + HMENU hMenu = (HMENU)CallService(MS_CLIST_MENUBUILDCONTACT, (WPARAM)wndData->mhContact, 0); + GetWindowRect(GetDlgItem(hwndDlg,IDC_USERMENU), &rc); + TrackPopupMenu(hMenu, 0, rc.left, rc.bottom, 0, hwndDlg, NULL); + DestroyMenu(hMenu); + break; + } + case IDC_HISTORY: + CallService(MS_HISTORY_SHOWCONTACTHISTORY,(WPARAM)wndData->mhContact,0); + break; + case IDC_DETAILS: + CallService(MS_USERINFO_SHOWDIALOG,(WPARAM)wndData->mhContact,0); + break; + case IDC_ADD: + DialogAddContactExecute(hwndDlg, wndData->mhContact); + break; + } + break; + } + case WM_CONTEXTMENU: + { + HWND hLV = GetDlgItem(hwndDlg, IDC_CONTACTS); + LVHITTESTINFO lvh; + RECT rt; + + wndData->iPopupItem = -1; + if ((HWND)wParam != hLV) break; // if not our ListView go away + lvh.pt.x = LOWORD(lParam); + lvh.pt.y = HIWORD(lParam); + if (GetWindowRect(hLV, &rt)==0) return FALSE; // ?? why this, some check ?? + ScreenToClient(hLV, &lvh.pt); // convert to ListView local coordinates + int ci = ListView_HitTest(hLV, &lvh); + if (ci==-1) break; // mouse is not over any item + wndData->iPopupItem = ci; + TrackPopupMenu(GetSubMenu(wndData->mhPopup, 0), TPM_LEFTALIGN|TPM_TOPALIGN, LOWORD(lParam), HIWORD(lParam), 0, hwndDlg, NULL); + break; + } + case HM_EVENTSENT: + { + ACKDATA *ack=(ACKDATA*)lParam; + if (ack->type!=ACKTYPE_SEARCH) break; // not search ack, go away + if (ack->hProcess!=wndData->rhSearch) break; //not our search, go away + if (ack->result==ACKRESULT_DATA) + { + HWND hLV = GetDlgItem(hwndDlg, IDC_CONTACTS); + PROTOSEARCHRESULT* psr = (PROTOSEARCHRESULT*)ack->lParam; + LVFINDINFO fi; + fi.flags = LVFI_STRING; + fi.psz = wndData->haUin; + int iLPos = ListView_FindItem(hLV, -1, &fi); + if (iLPos==-1) iLPos=0; +// ListView_SetItemText(hLV, iLPos, 0, psr->email); // not sent by ICQ, and currently unsupported either + if (strcmpnull(psr->nick, "") && psr->nick) ListView_SetItemText(hLV, iLPos, 1, psr->nick); + ListView_SetItemText(hLV, iLPos, 2, psr->firstName); + ListView_SetItemText(hLV, iLPos, 3, psr->lastName); + break; + } + SAFE_FREE((void**)&wndData->haUin); + break; + } + case WM_CLOSE: // user closed window, so destroy it + { + WindowList_Remove(ghRecvWindowList, hwndDlg); + DestroyWindow(hwndDlg); + break; + } + case WM_DESTROY: // last message received by this dialog, cleanup + { + CallService(MS_DB_EVENT_MARKREAD, (WPARAM)wndData->mhContact, (LPARAM)wndData->mhDbEvent); + Utils_SaveWindowPosition(hwndDlg, NULL, MODULENAME, ""); + ImageList_Destroy(wndData->mhListIcon); + UnhookEvent(wndData->hHook); + DestroyMenu(wndData->mhPopup); + for (int i=0; i < SIZEOF(wndData->hIcons); i++) + DestroyIcon(wndData->hIcons[i]); + delete wndData; // automatically calls destructor + break; + } + case WM_MEASUREITEM: + return CallService(MS_CLIST_MENUMEASUREITEM, wParam, lParam); + + case WM_DRAWITEM: + { + DrawProtocolIcon(hwndDlg, lParam, wndData->mhContact); + return CallService(MS_CLIST_MENUDRAWITEM, wParam, lParam); + } + case WM_SIZE: + { // make the dlg resizeable + UTILRESIZEDIALOG urd = {0}; + + if (IsIconic(hwndDlg)) break; + urd.cbSize = sizeof(urd); + urd.hInstance = hInst; + urd.hwndDlg = hwndDlg; + urd.lParam = 0; // user-defined + urd.lpTemplate = MAKEINTRESOURCEA(IDD_RECEIVE); + urd.pfnResizer = RecvDlg_Resize; + CallService(MS_UTILS_RESIZEDIALOG, 0, (LPARAM) & urd); + break; + } + case WM_GETMINMAXINFO: + { + MINMAXINFO* mmi=(MINMAXINFO*)lParam; + mmi->ptMinTrackSize.x = 480+2*GetSystemMetrics(SM_CXSIZEFRAME); + mmi->ptMinTrackSize.y = 130+2*GetSystemMetrics(SM_CYSIZEFRAME); + break; + } + case DM_UPDATETITLE: + { + UpdateDialogTitle(hwndDlg, wndData?wndData->mhContact:NULL, "Contacts from"); + if (wndData) + UpdateDialogAddButton(hwndDlg, wndData->mhContact); + break; + } + } + return FALSE; +} diff --git a/plugins/ContactsPlus/src/receive.h b/plugins/ContactsPlus/src/receive.h new file mode 100644 index 0000000000..fe35d94be6 --- /dev/null +++ b/plugins/ContactsPlus/src/receive.h @@ -0,0 +1,65 @@ +// --------------------------------------------------------------------------- +// Contacts+ for Miranda Instant Messenger +// _______________________________________ +// +// Copyright © 2002 Dominus Procellarum +// Copyright © 2004-2008 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// --------------------------------------------------------------------------- + +#ifndef __RECEIVE_H +#define __RECEIVE_H + + +#define HM_EVENTSENT (WM_USER+10) + +#define DM_UPDATETITLE (WM_USER+11) + +#define IDI_ADDCONTACT 210 +#define IDI_USERDETAILS 160 +#define IDI_HISTORY 174 +#define IDI_DOWNARROW 264 + +struct TReceivedItem { + char* mcaUIN; + TCHAR* mcaNick; + ~TReceivedItem() { SAFE_FREE((void**)&mcaUIN); SAFE_FREE((void**)&mcaNick); } + TReceivedItem() { mcaUIN = NULL; mcaNick = NULL; } +}; + +struct TRecvContactsData { + HANDLE mhDbEvent; // handle to recv DB event + HANDLE mhContact; // from whom we received this + HIMAGELIST mhListIcon;// icons for listview + HMENU mhPopup; // popup menu for listview + HANDLE hHook; // hook to event + HANDLE rhSearch; // handle to uin-search + char* haUin; + int iPopupItem; + TReceivedItem** maReceived;// received contacts + int cbReceived; + TReceivedItem* AddReceivedItem(); + HICON hIcons[4]; // icons for dialog + TRecvContactsData(HANDLE contact) { mhContact = contact; hHook = NULL; cbReceived = 0; maReceived = NULL; haUin = NULL; }; + ~TRecvContactsData() { if (cbReceived) { for(int i=0;inContacts = nContacts; + ackData->aContacts = (HANDLE*)malloc(nContacts*sizeof(HANDLE)); + memmove(ackData->aContacts, phContacts, nContacts*sizeof(HANDLE)); // copy the array of hContact for ack array + EnableDlgItem(hwndDlg, IDOK, FALSE); + EnableDlgItem(hwndDlg, IDC_LIST, FALSE); + + return TRUE; // Success +} + + +int TSendContactsData::SendContacts(HWND hwndDlg) { + char* szProto = GetContactProto(hContact); + int nMaxContacts = CallProtoService(szProto, PS_GETCAPS, PFLAG_MAXCONTACTSPERPACKET, (LPARAM)hContact); + + if (!nMaxContacts) { + ShowErrorDlg(hwndDlg, "The selected contact does not support receiving contacts.", FALSE); + return FALSE; + } + // hook event - we want to receive protocol acknowledgements + HookProtoAck(hwndDlg); + + for (int j = 0; j < nContacts / nMaxContacts; j++ ) + { // send in packets, each of nMaxContacts contacts + if (!SendContactsPacket(hwndDlg, aContacts + j*nMaxContacts, nMaxContacts)) + return FALSE; + } + if (nContacts%nMaxContacts!=0) + { + if (!SendContactsPacket(hwndDlg, aContacts + nContacts/nMaxContacts*nMaxContacts, nContacts%nMaxContacts)) + return FALSE; + } + return TRUE; +} + + +/* Send Dialog Implementation */ + +static void ResetListOptions(HWND hwndList) +{ + COLORREF bgColour,fgColour; + + SendMessageT(hwndList,CLM_SETBKBITMAP,0,(LPARAM)(HBITMAP)NULL); + bgColour=GetSysColor(COLOR_WINDOW); + SendMessageT(hwndList,CLM_SETBKCOLOR,bgColour,0); + SendMessageT(hwndList,CLM_SETGREYOUTFLAGS,0,0); + SendMessageT(hwndList,CLM_SETLEFTMARGIN,4,0); + SendMessageT(hwndList,CLM_SETINDENT,10,0); + for(int i=0; i<=FONTID_MAX; i++) + { + fgColour=(COLORREF)SendMessageT(hwndList,CLM_GETTEXTCOLOR,i,0); + if(abs(GetRValue(fgColour)-GetRValue(bgColour))<10 && + abs(GetGValue(fgColour)-GetGValue(bgColour))<10 && + abs(GetBValue(fgColour)-GetBValue(bgColour))<10) + SendMessageT(hwndList,CLM_SETTEXTCOLOR,i,GetSysColor(COLOR_WINDOWTEXT)); + } +} + + +static HANDLE FindNextClistContact(HWND hList, HANDLE hContact, HANDLE *phItem) +{ + HANDLE hNextContact = SRCFindNextContact(hContact); + HANDLE hNextItem = NULL; + + while (hNextContact && !(hNextItem = (HANDLE)SendMessageT(hList, CLM_FINDCONTACT, (WPARAM)hNextContact,0))) + hNextContact = SRCFindNextContact(hNextContact); + + if (phItem) + *phItem = hNextItem; + + return hNextContact; +} + + +static HANDLE FindFirstClistContact(HWND hList, HANDLE *phItem) +{ + HANDLE hContact = SRCFindFirstContact(); + HANDLE hItem = (HANDLE)SendMessageT(hList, CLM_FINDCONTACT, (WPARAM)hContact, 0); + + if (hContact && !hItem) + return FindNextClistContact(hList, hContact, phItem); + + if (phItem) + *phItem = hItem; + + return hContact; +} + + +bool binListEvent = FALSE; + +static void SetAllContactChecks(HWND hwndList, HANDLE hReceiver) // doubtful name +{ + HANDLE hContact, hItem; + + if (binListEvent) return; + binListEvent = TRUE; + char* szProto = GetContactProto(hReceiver); + if (szProto == NULL) return; + + if (CallService(MS_CLUI_GETCAPS, 0, 0) & CLUIF_HIDEEMPTYGROUPS && DBGetContactSettingByte(NULL, "CList", "HideEmptyGroups", SETTING_USEGROUPS_DEFAULT)) + SendMessageT(hwndList, CLM_SETHIDEEMPTYGROUPS, (WPARAM) TRUE, 0); + else + SendMessageT(hwndList, CLM_SETHIDEEMPTYGROUPS, (WPARAM) FALSE, 0); + + hContact = FindFirstClistContact(hwndList, &hItem); + while (hContact) + { + char* szProto2 = GetContactProto(hContact); + + if (strcmpnull(szProto, szProto2)) + { // different protocols or protocol undefined, remove contact, useless anyway + SendMessageT(hwndList, CLM_DELETEITEM, (WPARAM)hItem, 0); + } + else // otherwise uncheck + SendMessageT(hwndList, CLM_SETCHECKMARK,(WPARAM)hItem, 0); + + hContact = FindNextClistContact(hwndList, hContact, &hItem); + } + + binListEvent = FALSE; +} + + +INT_PTR CALLBACK SendDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + TSendContactsData* wndData = (TSendContactsData*)GetWindowLongPtr(hwndDlg, DWLP_USER); + + switch (msg) + { + case WM_INITDIALOG: + { + TranslateDialogDefault(hwndDlg); + SendMessageT(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(hInst, MAKEINTRESOURCE(IDI_CONTACTS))); + ResetListOptions(GetDlgItem(hwndDlg,IDC_LIST)); + SetAllContactChecks(GetDlgItem(hwndDlg,IDC_LIST), (HANDLE)lParam); + WindowList_Add(ghSendWindowList, hwndDlg, (HANDLE)lParam); + wndData = new TSendContactsData((HANDLE)lParam); + SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG)wndData); + // new dlg init + wndData->hIcons[0] = InitMButton(hwndDlg, IDC_ADD, MAKEINTRESOURCEA(IDI_ADDCONTACT), "Add Contact Permanently to List"); + wndData->hIcons[1] = InitMButton(hwndDlg, IDC_DETAILS, MAKEINTRESOURCEA(IDI_USERDETAILS), "View User's Details"); + wndData->hIcons[2] = InitMButton(hwndDlg, IDC_HISTORY, MAKEINTRESOURCEA(IDI_HISTORY), "View User's History"); + wndData->hIcons[3] = InitMButton(hwndDlg, IDC_USERMENU, MAKEINTRESOURCEA(IDI_DOWNARROW), "User Menu"); + + SendMessageT(hwndDlg,DM_UPDATETITLE,0,0); + // new dialog init done + return TRUE; + } + + case WM_SETFOCUS: + SetFocus(GetDlgItem(hwndDlg,IDC_LIST)); + break; + + case WM_NOTIFY: + if (((LPNMHDR)lParam)->idFrom == IDC_LIST) + { + switch (((LPNMHDR)lParam)->code) + { + case CLN_NEWCONTACT: + case CLN_LISTREBUILT: // rebuild list + if (wndData) SetAllContactChecks(GetDlgItem(hwndDlg,IDC_LIST), wndData->hContact); + case CLN_OPTIONSCHANGED: + ResetListOptions(GetDlgItem(hwndDlg,IDC_LIST)); + break; + } + } + break; + + case WM_TIMER: + if (wParam == TIMERID_MSGSEND) + { + if (!g_SendAckSupported) + { // old Miranda has this ack unimplemented, we need to send it by ourselves + ACKDATA ack = {0}; + + ack.cbSize = sizeof(ACKDATA); + ack.type = ACKTYPE_CONTACTS; + ack.result = ACKRESULT_SUCCESS; + ack.hContact = wndData->hContact; + while (wndData->uacklist.Count) + { // the uack gets empty after processing all messages :) + ack.hProcess = wndData->uacklist.Items[0]; + SendMessageT(hwndDlg, HM_EVENTSENT, NULL, (WPARAM)&ack); // this removes the ack from our array + } + break; + } + KillTimer(hwndDlg,wParam); + wndData->ShowErrorDlg(hwndDlg, "The contacts send timed out.", TRUE); + } + break; + + case DM_ERRORDECIDED: + { + EnableWindow(hwndDlg,TRUE); + wndData->hError = NULL; + switch(wParam) + { + case MSGERROR_CANCEL: + { + wndData->UnhookProtoAck(); + if (wndData->uacklist.Count) + { + for (int i=0; iuacklist.Count; i++) + { + delete gaAckData.Remove(wndData->uacklist.Items[i]); // remove our ackdata & release structure + } + SAFE_FREE((void**)&wndData->uacklist.Items); + wndData->uacklist.Count = 0; + } + EnableDlgItem(hwndDlg,IDOK,TRUE); + EnableDlgItem(hwndDlg,IDC_LIST,TRUE); + ShowWindow(hwndDlg,SW_SHOWNORMAL); + SetFocus(GetDlgItem(hwndDlg,IDC_LIST)); + break; + } + case MSGERROR_DONE: + // contacts were delivered succesfully after timeout + SetFocus(GetDlgItem(hwndDlg,IDC_LIST)); + wndData->UnhookProtoAck(); + break; + + case MSGERROR_RETRY:// resend timeouted packets + + for (int i=0; iuacklist.Count; i++) + { + TAckData* lla = gaAckData.Remove(wndData->uacklist.Items[i]); + HANDLE hProcc = (HANDLE)CallContactService(wndData->hContact, PSS_CONTACTS, MAKEWPARAM(0, lla->nContacts), (LPARAM)lla->aContacts); + + if (!hProcc) // if fatal do not include + { + wndData->uacklist.Remove(wndData->uacklist.Items[i]); + delete lla; // release the structure + continue; + } + else + { // update process code + wndData->uacklist.Items[i] = hProcc; + gaAckData.Add(hProcc, lla); + } + }// collect TAckData for our window, resend + break; + } + break; + } + + case WM_COMMAND: + { + if (!lParam && CallService(MS_CLIST_MENUPROCESSCOMMAND,MAKEWPARAM(LOWORD(wParam), MPCF_CONTACTMENU), (LPARAM)wndData->hContact)) + break; + + switch(LOWORD(wParam)) + { + case IDOK: + { + if (!IsWindowEnabled(GetDlgItem(hwndDlg,IDOK))) break; + HANDLE hContact, hItem; + wndData->ClearContacts(); // do not include contacts twice + + HWND hList = GetDlgItem(hwndDlg, IDC_LIST); + hContact = FindFirstClistContact(hList, &hItem); + while (hContact) + { + if (SendMessageT(hList, CLM_GETCHECKMARK, (WPARAM)hItem, 0)) + { // build list of contacts to send + wndData->AddContact(hContact); + } + hContact = FindNextClistContact(hList, hContact, &hItem); + } + /* send contacts */ + if (!wndData->SendContacts(hwndDlg)) + break; + + if (g_SendAckSupported) + SetTimer(hwndDlg,TIMERID_MSGSEND,DBGetContactSettingDword(NULL,"SRMsg","MessageTimeout",TIMEOUT_MSGSEND),NULL); + else + SetTimer(hwndDlg,TIMERID_MSGSEND,1000,NULL); // wait one second - if no error occures + + break; + } + case IDCANCEL: + { + DestroyWindow(hwndDlg); + break; + } + case ID_SELECTALL: + { // select all contacts + HANDLE hContact, hItem; + HWND hwndList = GetDlgItem(hwndDlg, IDC_LIST); + + hContact = FindFirstClistContact(hwndList, &hItem); + while (hContact) { + SendMessageT(hwndList,CLM_SETCHECKMARK,(WPARAM)hItem, 1); + hContact = FindNextClistContact(hwndList, hContact, &hItem); + }; + break; + } + case IDC_USERMENU: + { + RECT rc; + HMENU hMenu = (HMENU)CallService(MS_CLIST_MENUBUILDCONTACT,(WPARAM)wndData->hContact,0); + + GetWindowRect(GetDlgItem(hwndDlg,IDC_USERMENU),&rc); + TrackPopupMenu(hMenu,0,rc.left,rc.bottom,0,hwndDlg,NULL); + DestroyMenu(hMenu); + break; + } + case IDC_HISTORY: + CallService(MS_HISTORY_SHOWCONTACTHISTORY,(WPARAM)wndData->hContact,0); + break; + + case IDC_DETAILS: + CallService(MS_USERINFO_SHOWDIALOG,(WPARAM)wndData->hContact,0); + break; + + case IDC_ADD: + DialogAddContactExecute(hwndDlg, wndData->hContact); + break; + } + break; + } + case HM_EVENTSENT: + { + ACKDATA *ack=(ACKDATA*)lParam; + DBEVENTINFO dbei={0}; + + if (ack->type != ACKTYPE_CONTACTS) break; + + TAckData* ackData = gaAckData.Get(ack->hProcess); + + if (ackData == NULL) break; // on unknown hprocc go away + + if (ackData->hContact != ack->hContact) break; // this is not ours, strange + + if (ack->result == ACKRESULT_FAILED) + { // some process failed, show error dialog + KillTimer(hwndDlg, TIMERID_MSGSEND); + wndData->ShowErrorDlg(hwndDlg, (char *)ack->lParam, TRUE); + // ackData get used in error handling, released there + break; + } + + dbei.cbSize = sizeof(dbei); + dbei.szModule = GetContactProto(ackData->hContact); + dbei.eventType = EVENTTYPE_CONTACTS; + dbei.flags = DBEF_SENT; + if (g_UnicodeCore && g_Utf8EventsSupported) + dbei.flags |= DBEF_UTF; + dbei.timestamp = time(NULL); + //make blob + TCTSend* maSend = (TCTSend*)_alloca(ackData->nContacts*sizeof(TCTSend)); + ZeroMemory(maSend, ackData->nContacts*sizeof(TCTSend)); + dbei.cbBlob=0; + char* pBlob; + int i; + for (i=0; inContacts; i++) + { // prepare data & count size + if (g_UnicodeCore && g_Utf8EventsSupported) + maSend[i].mcaNick = make_utf8_string((WCHAR*)GetContactDisplayNameT(ackData->aContacts[i])); + else + maSend[i].mcaNick = (unsigned char*)null_strdup((char*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)ackData->aContacts[i], 0)); + maSend[i].mcaUIN = GetContactUID(ackData->aContacts[i], FALSE); + dbei.cbBlob += (DWORD)strlennull(maSend[i].mcaUIN) + (DWORD)strlennull((char*)maSend[i].mcaNick) + 2; + } + dbei.pBlob = (PBYTE)_alloca(dbei.cbBlob); + for (i=0, pBlob=(char*)dbei.pBlob; i < ackData->nContacts; i++) + { + strcpy(pBlob, (char*)maSend[i].mcaNick); + pBlob += strlennull(pBlob) + 1; + strcpy(pBlob, maSend[i].mcaUIN); + pBlob += strlennull(pBlob) + 1; + } + CallService(MS_DB_EVENT_ADD, (WPARAM)ackData->hContact,(LPARAM)&dbei); + gaAckData.Remove(ack->hProcess); // do not release here, still needed + wndData->uacklist.Remove(ack->hProcess); // packet confirmed + for (i=0; inContacts; i++) + { + SAFE_FREE((void**)&maSend[i].mcaUIN); + SAFE_FREE((void**)&maSend[i].mcaNick); + } + delete ackData; // all done, release structure + if (!wndData->uacklist.Count) + { + SkinPlaySound("SentContacts"); + KillTimer(hwndDlg, TIMERID_MSGSEND); + + if (wndData->hError) + SendMessageT(wndData->hError, DM_ERRORDECIDED, MSGERROR_DONE, 0); + + SendMessageT(hwndDlg, WM_CLOSE, 0, 0); // all packets confirmed, close the dialog + } + break; + } + + case WM_CLOSE: + { + wndData->UnhookProtoAck(); + DestroyWindow(hwndDlg); + break; + } + case WM_DESTROY: + { + int i; + for (i = 0; i < SIZEOF(wndData->hIcons); i++) + DestroyIcon(wndData->hIcons[i]); + WindowList_Remove(ghSendWindowList, hwndDlg); + delete wndData; + break; + } + case WM_MEASUREITEM: + return CallService(MS_CLIST_MENUMEASUREITEM,wParam,lParam); + + case WM_DRAWITEM: + { + DrawProtocolIcon(hwndDlg, lParam, wndData->hContact); + return CallService(MS_CLIST_MENUDRAWITEM,wParam,lParam); + } + case DM_UPDATETITLE: + { + UpdateDialogTitle(hwndDlg, wndData?wndData->hContact:NULL, "Send Contacts to"); + if (wndData) + UpdateDialogAddButton(hwndDlg, wndData->hContact); + break; + } + } + + return FALSE; +} + + +// Error Dialog + +INT_PTR CALLBACK ErrorDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch(msg) + { + case WM_INITDIALOG: + { + RECT rc, rcParent; + + TranslateDialogDefault(hwndDlg); + + if (lParam) + { + WCHAR tmp[MAX_PATH]; + + SetDlgItemTextT(hwndDlg, IDC_ERRORTEXT, SRCTranslateT((char*)lParam, tmp)); + } + GetWindowRect(hwndDlg, &rc); + GetWindowRect(GetParent(hwndDlg), &rcParent); + SetWindowPos(hwndDlg, 0, + (rcParent.left+rcParent.right-(rc.right-rc.left))/2, + (rcParent.top+rcParent.bottom-(rc.bottom-rc.top))/2, + 0, 0, SWP_NOZORDER|SWP_NOSIZE); + } + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wParam)) + { + case IDOK: + SendMessageT(GetParent(hwndDlg), DM_ERRORDECIDED, MSGERROR_RETRY, 0); + DestroyWindow(hwndDlg); + break; + + case IDCANCEL: + SendMessageT(GetParent(hwndDlg), DM_ERRORDECIDED, MSGERROR_CANCEL, 0); + DestroyWindow(hwndDlg); + break; + } + break; + case DM_ERRORDECIDED: + if (wParam!=MSGERROR_DONE) break; + SendMessageT(GetParent(hwndDlg), DM_ERRORDECIDED, MSGERROR_DONE, 0); + DestroyWindow(hwndDlg); + break; + } + + return FALSE; +} diff --git a/plugins/ContactsPlus/src/send.h b/plugins/ContactsPlus/src/send.h new file mode 100644 index 0000000000..c8580a4eb1 --- /dev/null +++ b/plugins/ContactsPlus/src/send.h @@ -0,0 +1,110 @@ +// --------------------------------------------------------------------------- +// Contacts+ for Miranda Instant Messenger +// _______________________________________ +// +// Copyright © 2002 Dominus Procellarum +// Copyright © 2004-2008 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// --------------------------------------------------------------------------- + +#ifndef __SEND_H +#define __SEND_H + + +#define TIMERID_MSGSEND 1024 +#define TIMEOUT_MSGSEND 9000 //ms +#define HM_EVENTSENT (WM_USER+10) +#define DM_ERRORDECIDED (WM_USER+18) +#define DM_UPDATETITLE (WM_USER+11) +#define MSGERROR_CANCEL 0 +#define MSGERROR_RETRY 1 +#define MSGERROR_DONE 2 + +#define IDI_ADDCONTACT 210 +#define IDI_USERDETAILS 160 +#define IDI_HISTORY 174 +#define IDI_DOWNARROW 264 + +struct TSendProcessList { + int Count; + HANDLE* Items; + CRITICAL_SECTION lock; + void Add(HANDLE hProcc); + void Remove(HANDLE hProcc); + TSendProcessList(); + ~TSendProcessList(); +}; + +struct TSendContactsData { // hope uack is released automaticly, static property + HANDLE hHook; // hook to event + void HookProtoAck(HWND hwndDlg); + void UnhookProtoAck(); + HANDLE* aContacts; // contacts to be sent + int nContacts; // now many UIDs shall we send? + void ClearContacts(); + void AddContact(HANDLE hContact); + HANDLE hContact; // to whom shall we send? + TSendProcessList uacklist;// ackdata - necessary for errorbox + HWND hError; // handle of error box, if any + void ShowErrorDlg(HWND hwndDlg, char* szMsg, bool bAllowRetry); + int SendContactsPacket(HWND hwndDlg, HANDLE *phContacts, int nContacts); + int SendContacts(HWND hwndDlg); + HICON hIcons[4]; // icons for dialog + TSendContactsData(HANDLE contact); + ~TSendContactsData(); +}; + +struct TAckData { + HANDLE hContact; // to whom was it sent + HANDLE* aContacts; // obj + int nContacts; // how many + TAckData(HANDLE contact) { hContact = contact; aContacts = NULL; nContacts = 0;}; + ~TAckData() { if (nContacts) SAFE_FREE((void**)&aContacts); } +}; + +typedef TAckData* PAckData; + +struct TCTSend { + char* mcaUIN; + unsigned char* mcaNick; +}; + +struct gAckItem { // some shit here + HANDLE hProcc; + PAckData ackData; + gAckItem(HANDLE procC, PAckData aData) { ackData=aData; hProcc=procC; }; + ~gAckItem() { /*delete ackData;*/ }; +}; + +struct gAckList { + gAckItem** Items; + int Count; + TAckData* Get(HANDLE hProcc) { for (int i=0; ihProcc==hProcc) { return Items[i]->ackData; }; return NULL; }; + TAckData* Add(HANDLE hProcc, TAckData* ackData) { Items=(gAckItem**)realloc(Items, (Count+1)*sizeof(gAckItem*)); Items[Count]=new gAckItem(hProcc, ackData); Count++; return ackData; }; + TAckData* Remove(HANDLE hProcc) { for (int i=0; ihProcc==hProcc) { TAckData* data=Items[i]->ackData; delete Items[i]; memmove(Items+i, Items+i+1, (Count-i-1)*sizeof(gAckItem*)); Count--; return data; }; return NULL; }; + gAckList() { Count = 0; Items = NULL; } + ~gAckList() { if (Count) { for (int i=0; ihwndItem==GetDlgItem(hwndDlg, IDC_PROTOCOL)) + { + HICON hIcon = LoadContactProtoIcon(hContact); + if (hIcon) + { + DrawIconEx(dis->hDC,dis->rcItem.left,dis->rcItem.top,hIcon,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0,NULL,DI_NORMAL); + DestroyIcon(hIcon); + } + } +} + + +void UpdateDialogTitle(HWND hwndDlg, HANDLE hContact, char* pszTitleStart) +{ + TCHAR newtitle[512]; + WCHAR str[MAX_PATH]; + TCHAR *oldTitle; + TCHAR *szStatus; + char *szProto; + + if (hContact) + { + szProto = GetContactProto(hContact); + if (szProto) + { + TCHAR *uid = GetContactUID(hContact, TRUE); + TCHAR *contactName = GetContactDisplayNameT(hContact); + + oldTitle = GetDlgItemTextT(hwndDlg, IDC_NAME); + + if (strcmpT(uid?uid:contactName, oldTitle)) + SetDlgItemTextT(hwndDlg, IDC_NAME, uid?uid:contactName); + + szStatus = MirandaStatusToStringT(szProto==NULL ? ID_STATUS_OFFLINE:DBGetContactSettingWord(hContact,szProto,"Status",ID_STATUS_OFFLINE)); + _snprintfT(newtitle, 256, "%s %s (%s)", SRCTranslateT(pszTitleStart, str), contactName, szStatus); + + SAFE_FREE((void**)&uid); + SAFE_FREE((void**)&oldTitle); + } + else + strncpyT(newtitle, SRCTranslateT(pszTitleStart, str), 256); + } + else + strncpyT(newtitle, SRCTranslateT(pszTitleStart, str), 256); + + oldTitle = GetWindowTextT(hwndDlg); + + if (strcmpT(newtitle, oldTitle)) + SetWindowTextT(hwndDlg, newtitle); + + SAFE_FREE((void**)&oldTitle); +} + + +void UpdateDialogAddButton(HWND hwndDlg, HANDLE hContact) +{ + int bVisible = DBGetContactSettingByte(hContact,"CList","NotOnList",0); + + ShowWindow(GetDlgItem(hwndDlg, IDC_ADD), bVisible?SW_SHOW:SW_HIDE); +} + + +HICON InitMButton(HWND hDlg, int idButton, LPCSTR szIcon, char* szTip) +{ + HWND hButton = GetDlgItem(hDlg, idButton); + HICON hIcon = (HICON)LoadImage(GetModuleHandle(NULL),szIcon,IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0); + + SendMessageT(hButton, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon); + SendMessageT(hButton, BUTTONSETASFLATBTN, TRUE, 0); + SendMessageT(hButton, BUTTONADDTOOLTIP, (WPARAM)Translate(szTip), 0); + + return hIcon; +} + + +HICON LoadContactProtoIcon(HANDLE hContact) +{ + char* szProto = GetContactProto(hContact); + if (szProto) + return (HICON)CallProtoService(szProto, PS_LOADICON, PLI_PROTOCOL|PLIF_SMALL, 0); + return NULL; +} + + +void EnableDlgItem(HWND hwndDlg, UINT control, int state) +{ + EnableWindow(GetDlgItem(hwndDlg, control), state); +} + + +LRESULT SendMessageT(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + if (g_UnicodeCore) + return SendMessageW(hWnd, Msg, wParam, lParam); + else + return SendMessageA(hWnd, Msg, wParam, lParam); +} + +TCHAR* GetWindowTextT(HWND hWnd) +{ + if (g_UnicodeCore) + { + int len = GetWindowTextLengthW(hWnd) + 1; + WCHAR* txt = (WCHAR*)malloc(len * sizeof(WCHAR)); + if (txt) { + txt[0] = 0; + GetWindowTextW(hWnd, txt, len); + } + return (TCHAR*)txt; + } + else + { + int len = GetWindowTextLengthA(hWnd) + 1; + char* txt = (char*)malloc(len * sizeof(char)); + if (txt) { + txt[0] = 0; + GetWindowTextA(hWnd, txt, len); + } + return (TCHAR*)txt; + } +} + +BOOL SetWindowTextT(HWND hWnd, TCHAR* lpString) +{ + if (g_UnicodeCore) + return SetWindowTextW(hWnd, (WCHAR*)lpString); + else + return SetWindowTextA(hWnd, lpString); +} + +TCHAR* GetDlgItemTextT(HWND hDlg, int nIDDlgItem) +{ + return GetWindowTextT(GetDlgItem(hDlg, nIDDlgItem)); +} + +BOOL SetDlgItemTextT(HWND hDlg, int nIDDlgItem, TCHAR* lpString) +{ + return SetWindowTextT(GetDlgItem(hDlg, nIDDlgItem), lpString); +} + +HWND CreateDialogParamT(HINSTANCE hInstance, const char* szTemplate, HWND hWndParent, DLGPROC lpDialogFunc, LPARAM dwInitParam) +{ + if (g_UnicodeCore) + return CreateDialogParamW(hInstance, (LPCWSTR)szTemplate, hWndParent, lpDialogFunc, dwInitParam); + else + return CreateDialogParamA(hInstance, szTemplate, hWndParent, lpDialogFunc, dwInitParam); +} + +int ListView_InsertColumnT(HWND hwnd, int iCol, const LPLVCOLUMN pcol) +{ + return SendMessageT(hwnd, g_UnicodeCore ? LVM_INSERTCOLUMNW : LVM_INSERTCOLUMNA, (WPARAM)iCol, (LPARAM)pcol); +} + +void ListView_SetItemTextT(HWND hwnd, int i, int iSubItem, TCHAR* pszText) +{ + LV_ITEM lvi = {0}; + + lvi.iSubItem = iSubItem; + lvi.pszText = pszText; + SendMessageT(hwnd, g_UnicodeCore ? LVM_SETITEMTEXTW : LVM_SETITEMTEXTA, (WPARAM)i, (LPARAM)&lvi); +} + + + +size_t __fastcall strlenT(const TCHAR *string) +{ + if (string) + { + if (g_UnicodeCore) + return wcslen((WCHAR*)string); + else + return strlen((char*)string); + } + return 0; +} + +TCHAR* __fastcall strdupT(const TCHAR *string) +{ + if (string) + { + if (g_UnicodeCore) + return (TCHAR*)wcsdup((WCHAR*)string); + else + return (TCHAR*)strdup((char*)string); + } + return NULL; +} + +int __fastcall strcmpT(const TCHAR *string1, const TCHAR *string2) +{ + if (!string1 || !string2) return 1; + + if (g_UnicodeCore) + return wcscmp((WCHAR*)string1, (WCHAR*)string2); + else + return strcmp((char*)string1, (char*)string2); +} + +TCHAR* __fastcall strcpyT(TCHAR* dest, const TCHAR* src) +{ + if (src) + { + if (g_UnicodeCore) + return (TCHAR*)wcscpy((WCHAR*)dest, (WCHAR*)src); + else + return (TCHAR*)strcpy((char*)dest, (char*)src); + } + return dest; +} + +TCHAR* __fastcall strncpyT(TCHAR* dest, const TCHAR* src, size_t len) +{ + if (src) + { + if (g_UnicodeCore) + return (TCHAR*)wcsncpy((WCHAR*)dest, (WCHAR*)src, len); + else + return (TCHAR*)strncpy((char*)dest, (char*)src, len); + } + return dest; +} + +TCHAR* __fastcall strcatT(TCHAR* dest, const TCHAR* src) +{ + if (src) + { + if (g_UnicodeCore) + return (TCHAR*)wcscat((WCHAR*)dest, (WCHAR*)src); + else + return (TCHAR*)strcat((char*)dest, (char*)src); + } + return dest; +} + +int _snprintfT(TCHAR *buffer, size_t count, const char* fmt, ...) +{ + va_list va; + int len; + + va_start(va, fmt); + if (g_UnicodeCore) + { + TCHAR* wfmt = ansi_to_tchar(fmt); + + len = _vsnwprintf((WCHAR*)buffer, count-1, (WCHAR*)wfmt, va); + ((WCHAR*)buffer)[count-1] = 0; + SAFE_FREE((void**)&wfmt); + } + else + { + len = _vsnprintf((char*)buffer, count-1, fmt, va); + ((char*)buffer)[count-1] = 0; + } + va_end(va); + return len; +} + +TCHAR* __fastcall SRCTranslateT(const char* src, const WCHAR* unibuf) +{ // this takes Ascii strings only!!! + char* szRes = NULL; + + if (!strlennull(src)) + { // for the case of empty strings + return ""; + } + + if (g_UnicodeCore) + { // we give WCHAR + WCHAR *unicode; + int wchars, err; + + wchars = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, src, + (int)strlennull(src), NULL, 0); + + if (wchars == 0) return NULL; // Failure + + unicode = (WCHAR*)unibuf; + if (!unicode) + unicode = (WCHAR*)malloc((wchars + 1) * sizeof(WCHAR)); + + unicode[wchars] = 0; + + err = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, src, + (int)strlennull(src), unicode, wchars); + if (err != wchars) return NULL; // Failure + + return (TCHAR*)TranslateW(unicode); + } + else + return (TCHAR*)Translate(src); +} + +static BOOL bHasCP_UTF8 = FALSE; + + +void InitI18N(void) +{ + CPINFO CPInfo; + + + bHasCP_UTF8 = GetCPInfo(CP_UTF8, &CPInfo); +} + + +// Scans a string encoded in UTF-8 to verify that it contains +// only valid sequences. It will return 1 if the string contains +// only legitimate encoding sequences; otherwise it will return 0; +// From 'Secure Programming Cookbook', John Viega & Matt Messier, 2003 +int UTF8_IsValid(const unsigned char* pszInput) +{ + int nb, i; + const unsigned char* c = pszInput; + + if (!pszInput) return 0; + + for (c = pszInput; *c; c += (nb + 1)) + { + if (!(*c & 0x80)) + nb = 0; + else if ((*c & 0xc0) == 0x80) return 0; + else if ((*c & 0xe0) == 0xc0) nb = 1; + else if ((*c & 0xf0) == 0xe0) nb = 2; + else if ((*c & 0xf8) == 0xf0) nb = 3; + else if ((*c & 0xfc) == 0xf8) nb = 4; + else if ((*c & 0xfe) == 0xfc) nb = 5; + + for (i = 1; i<=nb; i++) // we this forward, do not cross end of string + if ((*(c + i) & 0xc0) != 0x80) + return 0; + } + + return 1; +} + + +/* + * The following UTF8 routines are + * + * Copyright (C) 2001 Peter Harris + * Copyright (C) 2001 Edmund Grimley Evans + * + * under a GPL license + * + * -------------------------------------------------------------- + * Convert a string between UTF-8 and the locale's charset. + * Invalid bytes are replaced by '#', and characters that are + * not available in the target encoding are replaced by '?'. + * + * If the locale's charset is not set explicitly then it is + * obtained using nl_langinfo(CODESET), where available, the + * environment variable CHARSET, or assumed to be US-ASCII. + * + * Return value of conversion functions: + * + * -1 : memory allocation failed + * 0 : data was converted exactly + * 1 : valid data was converted approximately (using '?') + * 2 : input was invalid (but still converted, using '#') + * 3 : unknown encoding (but still converted, using '?') + */ + + + +/* + * Convert a string between UTF-8 and the locale's charset. + */ +unsigned char *make_utf8_string(const wchar_t *unicode) +{ + int size = 0; + int index = 0; + int out_index = 0; + unsigned char* out; + unsigned short c; + + if (!unicode) return NULL; + + /* first calculate the size of the target string */ + c = unicode[index++]; + while (c) + { + if (c < 0x0080) + size += 1; + else if (c < 0x0800) + size += 2; + else + size += 3; + c = unicode[index++]; + } + + out = (unsigned char*)malloc(size + 1); + if (out == NULL) + return NULL; + index = 0; + + c = unicode[index++]; + while (c) + { + if (c < 0x080) + { + out[out_index++] = (unsigned char)c; + } + else if (c < 0x800) + { + out[out_index++] = 0xc0 | (c >> 6); + out[out_index++] = 0x80 | (c & 0x3f); + } + else + { + out[out_index++] = 0xe0 | (c >> 12); + out[out_index++] = 0x80 | ((c >> 6) & 0x3f); + out[out_index++] = 0x80 | (c & 0x3f); + } + c = unicode[index++]; + } + out[out_index] = 0x00; + + return out; +} + + + +WCHAR *make_unicode_string(const unsigned char *utf8) +{ + int size = 0, index = 0, out_index = 0; + wchar_t *out; + unsigned char c; + + if (!utf8) return NULL; + + /* first calculate the size of the target string */ + c = utf8[index++]; + while (c) + { + if ((c & 0x80) == 0) + { + index += 0; + } + else if ((c & 0xe0) == 0xe0) + { + index += 2; + } + else + { + index += 1; + } + size += 1; + c = utf8[index++]; + } + + out = (wchar_t*)malloc((size + 1) * sizeof(wchar_t)); + if (out == NULL) + return NULL; + index = 0; + + c = utf8[index++]; + while (c) + { + if ((c & 0x80) == 0) + { + out[out_index++] = c; + } + else if ((c & 0xe0) == 0xe0) + { + out[out_index] = (c & 0x1F) << 12; + c = utf8[index++]; + out[out_index] |= (c & 0x3F) << 6; + c = utf8[index++]; + out[out_index++] |= (c & 0x3F); + } + else + { + out[out_index] = (c & 0x3F) << 6; + c = utf8[index++]; + out[out_index++] |= (c & 0x3F); + } + c = utf8[index++]; + } + out[out_index] = 0; + + return out; +} + + +// Returns 0 on error, 1 on success +static int utf8_decode(const unsigned char *from, char **to) +{ + int nResult = 0; + +// _ASSERTE(!(*to)); // You passed a non-zero pointer, make sure it doesnt point to unfreed memory + + // Validate the string + if (!UTF8_IsValid(from)) + return 0; + + // Use the native conversion routines when available + if (bHasCP_UTF8) + { + WCHAR *wszTemp = NULL; + int inlen = (int)strlennull((char*)from); + + wszTemp = (WCHAR *)_alloca(sizeof(WCHAR) * (inlen + 1)); + + // Convert the UTF-8 string to UCS + if (MultiByteToWideChar(CP_UTF8, 0, (char*)from, -1, wszTemp, inlen + 1)) + { + // Convert the UCS string to local ANSI codepage + *to = (char*)malloc(inlen+1); + if (WideCharToMultiByte(CP_ACP, 0, wszTemp, -1, *to, inlen+1, NULL, NULL)) + { + nResult = 1; + } + else + { + SAFE_FREE((void**)to); + } + } + } + else + { + wchar_t *unicode; + int chars; + int err; + + unicode = make_unicode_string(from); + if (unicode == NULL) + { +// fprintf(stderr, "Out of memory processing string from UTF8 to UNICODE16\n"); + return 0; + } + + chars = WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, unicode, -1, NULL, 0, NULL, NULL); + + if(chars == 0) + { +// fprintf(stderr, "Unicode translation error %d\n", GetLastError()); + SAFE_FREE((void**)&unicode); + return 0; + } + + *to = (char*)malloc((chars + 1)*sizeof(unsigned char)); + if (*to == NULL) + { +// fprintf(stderr, "Out of memory processing string to local charset\n"); + SAFE_FREE((void**)&unicode); + return 0; + } + + err = WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, unicode, -1, *to, chars, NULL, NULL); + if (err != chars) + { +// fprintf(stderr, "Unicode translation error %d\n", GetLastError()); + SAFE_FREE((void**)&unicode); + SAFE_FREE((void**)to); + return 0; + } + + SAFE_FREE((void**)&unicode); + + nResult = 1; + } + + return nResult; +} + + + +TCHAR* ansi_to_tchar(const char* src, int codepage) +{ + if (g_UnicodeCore) + { + WCHAR *unicode; + int wchars, err; + + wchars = MultiByteToWideChar(codepage, MB_PRECOMPOSED, src, (int)strlennull(src), NULL, 0); + + if (wchars == 0) return NULL; // Failure + + unicode = (WCHAR*)malloc((wchars + 1) * sizeof(WCHAR)); + unicode[wchars] = 0; + + err = MultiByteToWideChar(codepage, MB_PRECOMPOSED, src, (int)strlennull(src), unicode, wchars); + if (err != wchars) + { + SAFE_FREE((void**)&unicode); + return NULL; // Failure + } + + return (TCHAR*)unicode; + } + else + return strdupT((TCHAR*)src); +} + +char* tchar_to_ansi(const TCHAR* src) +{ + if (g_UnicodeCore) + { + char *ansi; + int chars; + int err; + + chars = WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, (WCHAR*)src, -1, NULL, 0, NULL, NULL); + + if (chars == 0) return NULL; // Failure + + ansi = (char*)malloc((chars + 1)*sizeof(char)); + if (ansi == NULL) return NULL; // Failure + + err = WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, (WCHAR*)src, -1, ansi, chars, NULL, NULL); + if (err != chars) + { + SAFE_FREE((void**)&ansi); + return NULL; + } + return ansi; + } + else + return (char*)strdupT(src); +} + +TCHAR* utf8_to_tchar(const unsigned char* utf) +{ + if (g_UnicodeCore) + return (TCHAR*)make_unicode_string(utf); + else + { + char* szAnsi = NULL; + + if (utf8_decode(utf, &szAnsi)) + return (TCHAR*)szAnsi; + else + return NULL; // Failure + } +} \ No newline at end of file diff --git a/plugins/ContactsPlus/src/utils.h b/plugins/ContactsPlus/src/utils.h new file mode 100644 index 0000000000..3bc2d8e00d --- /dev/null +++ b/plugins/ContactsPlus/src/utils.h @@ -0,0 +1,86 @@ +// --------------------------------------------------------------------------- +// Contacts+ for Miranda Instant Messenger +// _______________________________________ +// +// Copyright © 2002 Dominus Procellarum +// Copyright © 2004-2008 Joe Kucera +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// +// --------------------------------------------------------------------------- + +#ifndef __UTILS_H +#define __UTILS_H + + +extern HINSTANCE hInst; + +// utils.cpp +void __fastcall SAFE_FREE(void** p); +size_t __fastcall strlennull(const char *string); +int __fastcall strcmpnull(const char *str1, const char *str2); +char* __fastcall null_strdup(const char *string); + +char *GetContactProto(HANDLE hContact); +char *GetContactUID(HANDLE hContact, int bTchar); +TCHAR *GetContactDisplayNameT(HANDLE hContact); +TCHAR* MirandaStatusToStringT(int mirandaStatus); + +HANDLE __fastcall SRCFindFirstContact(); +HANDLE __fastcall SRCFindNextContact(HANDLE hContact); +int DBGetContactSettingT(HANDLE hContact, const char *szModule, const char* szSetting, DBVARIANT *dbv); +TCHAR* DBGetContactSettingStringT(HANDLE hContact, const char *szModule,const char* szSetting, TCHAR* szDef); +int DBWriteContactSettingStringT(HANDLE hContact, const char *szModule, const char* szSetting, TCHAR* szValue); + +void DrawProtocolIcon(HWND hwndDlg, LPARAM lParam, HANDLE hContact); +void UpdateDialogTitle(HWND hwndDlg, HANDLE hContact, char* pszTitleStart); +void UpdateDialogAddButton(HWND hwndDlg, HANDLE hContact); + +HICON InitMButton(HWND hDlg, int idButton, LPCSTR szIcon, char* szTip); + +void DialogAddContactExecute(HWND hwndDlg, HANDLE hNewContact); + +HICON LoadContactProtoIcon(HANDLE hContact); + +void EnableDlgItem(HWND hwndDlg, UINT control, int state); + +/// Unicode 2 in 1 Framework +size_t __fastcall strlenT(const TCHAR *string); +TCHAR* __fastcall strdupT(const TCHAR *string); +int __fastcall strcmpT(const TCHAR *string1, const TCHAR *string2); +TCHAR* __fastcall strcpyT(TCHAR* dest, const TCHAR* src); +TCHAR* __fastcall strncpyT(TCHAR* dest, const TCHAR* src, size_t len); +TCHAR* __fastcall strcatT(TCHAR* dest, const TCHAR* src); +int _snprintfT(TCHAR *buffer, size_t count, const char* fmt, ...); + +LRESULT SendMessageT(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); +TCHAR* GetWindowTextT(HWND hWnd); +BOOL SetWindowTextT(HWND hWnd, TCHAR* lpString); +TCHAR* GetDlgItemTextT(HWND hDlg, int nIDDlgItem); +BOOL SetDlgItemTextT(HWND hDlg, int nIDDlgItem, TCHAR* lpString); +HWND CreateDialogParamT(HINSTANCE hInstance, const char* szTemplate, HWND hWndParent, DLGPROC lpDialogFunc, LPARAM dwInitParam); +int ListView_InsertColumnT(HWND hwnd, int iCol, const LPLVCOLUMN pcol); +void ListView_SetItemTextT(HWND hwnd, int i, int iSubItem, TCHAR* pszText); + +TCHAR* __fastcall SRCTranslateT(const char* src, const WCHAR* unibuf); + +void InitI18N(void); +TCHAR* ansi_to_tchar(const char* string, int codepage = CP_ACP); +char* tchar_to_ansi(const TCHAR* src); +TCHAR* utf8_to_tchar(const unsigned char* utf); +unsigned char *make_utf8_string(const wchar_t *unicode); + + +#endif /* __UTILS_H */ \ No newline at end of file -- cgit v1.2.3