/* Copyright (C) 2006 Ricardo Pescuma Domenecci Based on work (C) Heiko Schillinger This is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this file; see the file license.txt. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "commons.h" // Prototypes /////////////////////////////////////////////////////////////////////////// PLUGININFOEX pluginInfo={ sizeof(PLUGININFOEX), "Quick Contacts", PLUGIN_MAKE_VERSION(1,0,0,0), "Open contact-specific windows by hotkey.", "Ricardo Pescuma Domenecci, Heiko Schillinger", "pescuma@miranda-im.org", "© 2007-2009 Ricardo Pescuma Domenecci", "http://pescuma.org/miranda/quickcontacts", UNICODE_AWARE, // {F93BA59C-4F48-4F2E-8A91-77A2801527A3} {0xf93ba59c, 0x4f48, 0x4f2e, {0x8a, 0x91, 0x77, 0xa2, 0x80, 0x15, 0x27, 0xa3}} }; HINSTANCE hInst; HIMAGELIST hIml; int hLangpack = 0; HANDLE hModulesLoaded = NULL; HANDLE hEventAdded = NULL; HANDLE hHotkeyPressed = NULL; HANDLE hQSShowDialog = NULL; long main_dialog_open = 0; HWND hwndMain = NULL; int ModulesLoaded(WPARAM wParam, LPARAM lParam); int EventAdded(WPARAM wparam, LPARAM lparam); int HotkeyPressed(WPARAM wParam, LPARAM lParam); INT_PTR ShowDialog(WPARAM wParam,LPARAM lParam); void FreeContacts(); int hksModule = 0; int hksAction = 0; BOOL hasNewHotkeyModule = FALSE; char *metacontacts_proto = NULL; #define IDC_ICO 12344 // Functions //////////////////////////////////////////////////////////////////////////// BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { hInst = hinstDLL; return TRUE; } extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) { return &pluginInfo; } extern "C" __declspec(dllexport) int Load() { mir_getLP(&pluginInfo); hQSShowDialog = CreateServiceFunction(MS_QC_SHOW_DIALOG, ShowDialog); // hooks hModulesLoaded = HookEvent(ME_SYSTEM_MODULESLOADED, ModulesLoaded); hEventAdded = HookEvent(ME_DB_EVENT_ADDED, EventAdded); return 0; } extern "C" __declspec(dllexport) int Unload(void) { FreeContacts(); DeInitOptions(); DestroyServiceFunction(hQSShowDialog); UnhookEvent(hModulesLoaded); UnhookEvent(hEventAdded); return 0; } // Called when all the modules are loaded int ModulesLoaded(WPARAM wParam, LPARAM lParam) { InitOptions(); // add our modules to the KnownModules list CallService("DBEditorpp/RegisterSingleModule", (WPARAM) MODULE_NAME, 0); // Get number of protocols int pcount = 0; PROTOACCOUNT** pdesc; ProtoEnumAccounts(&pcount,&pdesc); opts.num_protos = pcount; // Add hotkey to multiple services hasNewHotkeyModule = TRUE; HOTKEYDESC hkd = {0}; hkd.cbSize = sizeof(hkd); hkd.dwFlags = HKD_TCHAR; hkd.pszName = "Quick Contacts/Open dialog"; hkd.ptszDescription = LPGENT("Open dialog"); hkd.ptszSection = LPGENT("Quick Contacts"); hkd.pszService = MS_QC_SHOW_DIALOG; hkd.DefHotKey = HOTKEYCODE(HOTKEYF_CONTROL|HOTKEYF_ALT, 'Q'); Hotkey_Register(&hkd); hkd.pszService = NULL; hkd.lParam = HOTKEY_VOICE; hkd.DefHotKey = HOTKEYCODE(HOTKEYF_CONTROL, 'V'); hkd.pszName = "Quick Contacts/Voice"; hkd.ptszDescription = LPGENT("Make a voice call"); Hotkey_Register(&hkd); hkd.lParam = HOTKEY_FILE; hkd.DefHotKey = HOTKEYCODE(HOTKEYF_CONTROL, 'F'); hkd.pszName = "Quick Contacts/File"; hkd.ptszDescription = LPGENT("Send file"); Hotkey_Register(&hkd); hkd.lParam = HOTKEY_URL; hkd.DefHotKey = HOTKEYCODE(HOTKEYF_CONTROL, 'U'); hkd.pszName = "Quick Contacts/URL"; hkd.ptszDescription = LPGENT("Send URL"); Hotkey_Register(&hkd); hkd.lParam = HOTKEY_INFO; hkd.DefHotKey = HOTKEYCODE(HOTKEYF_CONTROL, 'I'); hkd.pszName = "Quick Contacts/Info"; hkd.ptszDescription = LPGENT("Open userinfo"); Hotkey_Register(&hkd); hkd.lParam = HOTKEY_HISTORY; hkd.DefHotKey = HOTKEYCODE(HOTKEYF_CONTROL, 'H'); hkd.pszName = "Quick Contacts/History"; hkd.ptszDescription = LPGENT("Open history"); Hotkey_Register(&hkd); hkd.lParam = HOTKEY_MENU; hkd.DefHotKey = HOTKEYCODE(HOTKEYF_CONTROL, 'M'); hkd.pszName = "Quick Contacts/Menu"; hkd.ptszDescription = LPGENT("Open contact menu"); Hotkey_Register(&hkd); hkd.lParam = HOTKEY_ALL_CONTACTS; hkd.DefHotKey = HOTKEYCODE(HOTKEYF_CONTROL, 'A'); hkd.pszName = "Quick Contacts/All Contacts"; hkd.ptszDescription = LPGENT("Show all contacts"); Hotkey_Register(&hkd); if (ServiceExists(MS_SKIN_ADDHOTKEY)) { SKINHOTKEYDESCEX hk = {0}; hk.cbSize = sizeof(hk); hk.pszSection = Translate("Quick Contacts"); hk.pszName = Translate("Open dialog"); hk.pszDescription = Translate("Open dialog"); hk.pszService = MS_QC_SHOW_DIALOG; hk.DefHotKey = 0; CallService(MS_SKIN_ADDHOTKEY, 0, (LPARAM)&hk); } // Get the icons for the listbox hIml = (HIMAGELIST)CallService(MS_CLIST_GETICONSIMAGELIST,0,0); // Add menu item CLISTMENUITEM mi = { sizeof(mi) }; mi.position = 500100001; mi.flags = CMIF_TCHAR; mi.ptszName = LPGENT("Quick Contacts..."); mi.pszService = MS_QC_SHOW_DIALOG; Menu_AddMainMenuItem(&mi); if (ServiceExists(MS_MC_GETPROTOCOLNAME) && ServiceExists(MS_MC_GETMETACONTACT)) metacontacts_proto = (char *) CallService(MS_MC_GETPROTOCOLNAME, 0, 0); return 0; } // called when a message/file/url was sent // handle of contact is set as window-userdata int EventAdded(WPARAM wparam, LPARAM lparam) { DBEVENTINFO dbei; ZeroMemory(&dbei,sizeof(dbei)); dbei.cbSize=sizeof(dbei); dbei.cbBlob=0; CallService(MS_DB_EVENT_GET,lparam,(LPARAM)&dbei); if( !(dbei.flags & DBEF_SENT) || dbei.flags & DBEF_READ || !DBGetContactSettingByte(NULL, MODULE_NAME, "EnableLastSentTo", 0) || DBGetContactSettingWord(NULL, MODULE_NAME, "MsgTypeRec", TYPE_GLOBAL) != TYPE_GLOBAL) return 0; DBWriteContactSettingDword(NULL, MODULE_NAME, "LastSentTo", (DWORD)(HANDLE)wparam); return 0; } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// #define IDC_ENTER 2000 // Pseudo control to handle enter in the main window // array where the contacts are put into struct c_struct { TCHAR szname[120]; TCHAR szgroup[50]; HANDLE hcontact; TCHAR proto[20]; c_struct() { szname[0] = 0; szgroup[0] = 0; hcontact = 0; proto[0] = 0; } }; LIST contacts(200); long max_proto_width; // Get the name the contact has in list // This was not made to be called by more than one thread! TCHAR tmp_list_name[120]; TCHAR *GetListName(c_struct *cs) { if (opts.group_append && cs->szgroup[0] != _T('\0')) { mir_sntprintf(tmp_list_name, MAX_REGS(tmp_list_name), _T("%s (%s)"), cs->szname, cs->szgroup); return tmp_list_name; } else { return cs->szname; } } int lstreq(TCHAR *a, TCHAR *b, size_t len = -1) { a = CharLower(_tcsdup(a)); b = CharLower(_tcsdup(b)); int ret; if (len > 0) ret = _tcsncmp(a, b, len); else ret = _tcscmp(a, b); free(a); free(b); return ret; } // simple sorting function to have // the contact array in alphabetical order void SortArray(void) { int loop,doop; c_struct *cs_temp; SortedList *sl = (SortedList *) &contacts; for(loop=0;loopszname,contacts[doop]->szname); if (cmp > 0) { cs_temp=contacts[loop]; sl->items[loop]=contacts[doop]; sl->items[doop]=cs_temp; } else if (cmp == 0) { if(lstreq(contacts[loop]->proto, contacts[doop]->proto) > 0) { cs_temp=contacts[loop]; sl->items[loop]=contacts[doop]; sl->items[doop]=cs_temp; } } } } } int GetStatus(HANDLE hContact, char *proto = NULL) { if (proto == NULL) proto = GetContactProto(hContact); if (proto == NULL) return ID_STATUS_OFFLINE; return DBGetContactSettingWord(hContact, proto, "Status", ID_STATUS_OFFLINE); } void FreeContacts() { for (int i = contacts.getCount() - 1; i >= 0; i--) { delete contacts[i]; contacts.remove(i); } } void LoadContacts(HWND hwndDlg, BOOL show_all) { BOOL metacontactsEnabled = (metacontacts_proto != NULL && DBGetContactSettingByte(0, metacontacts_proto, "Enabled", 1)); // Read last-sent-to contact from db and set handle as window-userdata HANDLE hlastsent = (HANDLE)DBGetContactSettingDword(NULL, MODULE_NAME, "LastSentTo", -1); SetWindowLongPtr(hwndMain, GWLP_USERDATA, (LONG)hlastsent); // enumerate all contacts and write them to the array // item data of listbox-strings is the array position FreeContacts(); for(HANDLE hContact = db_find_first(); hContact != NULL; hContact = db_find_next(hContact)) { char *pszProto = GetContactProto(hContact); if(pszProto != NULL) { // Get meta HANDLE hMeta = NULL; if (metacontactsEnabled) { if ((!show_all && opts.hide_subcontacts) || opts.group_append) hMeta = (HANDLE) CallService(MS_MC_GETMETACONTACT, (WPARAM)hContact, 0); } else { if (metacontacts_proto != NULL && strcmp(metacontacts_proto, pszProto) == 0) continue; } if (!show_all) { // Check if is offline and have to show if (GetStatus(hContact, pszProto) <= ID_STATUS_OFFLINE) { // See if has to show char setting[128]; mir_snprintf(setting, sizeof(setting), "ShowOffline%s", pszProto); if (!DBGetContactSettingByte(NULL, MODULE_NAME, setting, FALSE)) continue; // Check if proto offline else if (opts.hide_from_offline_proto && CallProtoService(pszProto, PS_GETSTATUS, 0, 0) <= ID_STATUS_OFFLINE) continue; } // Check if is subcontact if (opts.hide_subcontacts && hMeta != NULL) { if (!opts.keep_subcontacts_from_offline) continue; if (GetStatus(hMeta, metacontacts_proto) > ID_STATUS_OFFLINE) { continue; } else { char setting[128]; mir_snprintf(setting, sizeof(setting), "ShowOffline%s", metacontacts_proto); if (DBGetContactSettingByte(NULL, MODULE_NAME, setting, FALSE)) continue; } } } // Add to list // Get group c_struct *contact = new c_struct(); if (opts.group_append) { DBVARIANT dbv; if (DBGetContactSettingTString(hMeta == NULL ? hContact : hMeta, "CList", "Group", &dbv) == 0) { if (dbv.ptszVal != NULL) lstrcpyn(contact->szgroup, dbv.ptszVal, MAX_REGS(contact->szgroup)); DBFreeVariant(&dbv); } } // Make contact name TCHAR *tmp = (TCHAR *) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM) hContact, GCDNF_TCHAR); lstrcpyn(contact->szname, tmp, MAX_REGS(contact->szname)); PROTOACCOUNT *acc = ProtoGetAccount(pszProto); if (acc != NULL) { lstrcpyn(contact->proto, acc->tszAccountName, MAX_REGS(contact->proto)); } contact->hcontact = hContact; contacts.insert(contact); } } SortArray(); SendDlgItemMessage(hwndDlg, IDC_USERNAME, CB_RESETCONTENT, 0, 0); for(int loop = 0; loop < contacts.getCount(); loop++) { SendDlgItemMessage(hwndDlg, IDC_USERNAME, CB_SETITEMDATA, (WPARAM)SendDlgItemMessage(hwndDlg, IDC_USERNAME, CB_ADDSTRING, 0, (LPARAM) GetListName(contacts[loop])), (LPARAM)loop); } } // Enable buttons for the selected contact void EnableButtons(HWND hwndDlg, HANDLE hContact) { if (hContact == NULL) { EnableWindow(GetDlgItem(hwndDlg, IDC_MESSAGE), FALSE); EnableWindow(GetDlgItem(hwndDlg, IDC_VOICE), FALSE); EnableWindow(GetDlgItem(hwndDlg, IDC_FILE), FALSE); EnableWindow(GetDlgItem(hwndDlg, IDC_URL), FALSE); EnableWindow(GetDlgItem(hwndDlg, IDC_USERINFO), FALSE); EnableWindow(GetDlgItem(hwndDlg, IDC_HISTORY), FALSE); EnableWindow(GetDlgItem(hwndDlg, IDC_MENU), FALSE); SendMessage(GetDlgItem(hwndDlg, IDC_ICO), STM_SETICON, 0, 0); } else { // Is a meta? if (ServiceExists(MS_MC_GETMOSTONLINECONTACT)) { HANDLE hSub = (HANDLE) CallService(MS_MC_GETMOSTONLINECONTACT, (WPARAM) hContact, 0); if (hSub != NULL) hContact = hSub; } // Get caps INT_PTR caps = 0; char *pszProto = GetContactProto(hContact); if (pszProto != NULL) caps = CallProtoService(pszProto, PS_GETCAPS, PFLAGNUM_1, 0); BOOL voice = (ServiceExists(MS_VOICESERVICE_CAN_CALL) && CallService(MS_VOICESERVICE_CAN_CALL, (WPARAM)hContact, 0) > 0); EnableWindow(GetDlgItem(hwndDlg, IDC_MESSAGE), caps & PF1_IMSEND ? TRUE : FALSE); EnableWindow(GetDlgItem(hwndDlg, IDC_VOICE), voice); EnableWindow(GetDlgItem(hwndDlg, IDC_FILE), caps & PF1_FILESEND ? TRUE : FALSE); EnableWindow(GetDlgItem(hwndDlg, IDC_URL), caps & PF1_URLSEND ? TRUE : FALSE); EnableWindow(GetDlgItem(hwndDlg, IDC_USERINFO), TRUE); EnableWindow(GetDlgItem(hwndDlg, IDC_HISTORY), TRUE); EnableWindow(GetDlgItem(hwndDlg, IDC_MENU), TRUE); HICON ico = ImageList_GetIcon(hIml, CallService(MS_CLIST_GETCONTACTICON, (WPARAM) hContact, 0), ILD_IMAGE); SendMessage(GetDlgItem(hwndDlg, IDC_ICO), STM_SETICON, (WPARAM) ico, 0); } } // check if the char(s) entered appears in a contacts name int CheckText(HWND hdlg, TCHAR *sztext, BOOL only_enable = FALSE) { EnableButtons(hwndMain, NULL); if(sztext == NULL || sztext[0] == _T('\0')) return 0; int len = lstrlen(sztext); if (only_enable) { for(int loop=0;loopszname)==0 || lstreq(sztext, GetListName(contacts[loop]))==0) { EnableButtons(hwndMain, contacts[loop]->hcontact); return 0; } } } else { for(int loop=0;loophcontact); return 0; } } } EnableButtons(hwndMain, NULL); return 0; } HANDLE GetSelectedContact(HWND hwndDlg) { // First try selection int sel = SendDlgItemMessage(hwndDlg, IDC_USERNAME, CB_GETCURSEL, 0, 0); if (sel != CB_ERR) { int pos = SendDlgItemMessage(hwndDlg, IDC_USERNAME, CB_GETITEMDATA, sel, 0); if (pos != CB_ERR) return contacts[pos]->hcontact; } // Now try the name TCHAR cname[120] = _T(""); GetDlgItemText(hwndDlg, IDC_USERNAME, cname, MAX_REGS(cname)); for(int loop = 0; loop < contacts.getCount(); loop++) { if(!lstrcmpi(cname, GetListName(contacts[loop]))) return contacts[loop]->hcontact; } return NULL; } // get array position from handle int GetItemPos(HANDLE hcontact) { int loop; for(loop=0;loophcontact) return loop; } return -1; } // callback function for edit-box of the listbox // without this the autofill function isn't possible // this was done like ie does it..as far as spy++ could tell ;) LRESULT CALLBACK EditProc(HWND hdlg,UINT msg,WPARAM wparam,LPARAM lparam) { switch(msg) { case WM_CHAR: { if (wparam<32 && wparam != VK_BACK) break; TCHAR sztext[120] = _T(""); DWORD start; DWORD end; int ret = SendMessage(hdlg,EM_GETSEL,(WPARAM)&start,(LPARAM)&end); SendMessage(hdlg,WM_GETTEXT,(WPARAM)MAX_REGS(sztext),(LPARAM)sztext); BOOL at_end = (lstrlen(sztext) == (int)end); if (ret != -1) { if (wparam == VK_BACK) { if (start > 0) SendMessage(hdlg,EM_SETSEL,(WPARAM)start-1,(LPARAM)end); sztext[0]=0; } else { sztext[0]=wparam; sztext[1]=0; } SendMessage(hdlg,EM_REPLACESEL,0,(LPARAM)sztext); SendMessage(hdlg,WM_GETTEXT,(WPARAM)MAX_REGS(sztext),(LPARAM)sztext); } CheckText(hdlg, sztext, !at_end); return 1; } case WM_KEYUP: { TCHAR sztext[120] = _T(""); if (wparam == VK_RETURN) { switch(SendMessage(GetParent(hdlg),CB_GETDROPPEDSTATE,0,0)) { case FALSE: SendMessage(GetParent(GetParent(hdlg)),WM_COMMAND,MAKEWPARAM(IDC_ENTER,STN_CLICKED),0); break; case TRUE: SendMessage(GetParent(hdlg),CB_SHOWDROPDOWN,(WPARAM)FALSE,0); break; } } else if (wparam == VK_DELETE) { SendMessage(hdlg,WM_GETTEXT,(WPARAM)MAX_REGS(sztext),(LPARAM)sztext); CheckText(hdlg, sztext, TRUE); } return 0; } case WM_GETDLGCODE: return DLGC_WANTCHARS|DLGC_WANTARROWS; } return mir_callNextSubclass(hdlg, EditProc, msg, wparam, lparam); } HACCEL hAcct; HHOOK hHook; // This function filters the message queue and translates // the keyboard accelerators LRESULT CALLBACK HookProc(int code, WPARAM wparam, LPARAM lparam) { if (code!=MSGF_DIALOGBOX) return 0; MSG *msg = (MSG*)lparam; if (hasNewHotkeyModule) { int action = CallService(MS_HOTKEY_CHECK, (WPARAM) msg, (LPARAM) "Quick Contacts"); if (action != 0) { SendMessage(hwndMain, WM_COMMAND, action, 0); return 1; } } else { HWND htemp = msg->hwnd; msg->hwnd = hwndMain; if (TranslateAccelerator(msg->hwnd, hAcct, msg)) return 1; msg->hwnd=htemp; } if (msg->message == WM_KEYDOWN && msg->wParam == VK_ESCAPE) { switch(SendMessage(GetDlgItem(hwndMain, IDC_USERNAME), CB_GETDROPPEDSTATE, 0, 0)) { case FALSE: SendMessage(hwndMain, WM_CLOSE, 0, 0); break; case TRUE: SendMessage(GetDlgItem(hwndMain, IDC_USERNAME), CB_SHOWDROPDOWN, (WPARAM)FALSE, 0); break; } } return 0; } BOOL ScreenToClient(HWND hWnd, LPRECT lpRect) { BOOL ret; POINT pt; pt.x = lpRect->left; pt.y = lpRect->top; ret = ScreenToClient(hWnd, &pt); if (!ret) return ret; lpRect->left = pt.x; lpRect->top = pt.y; pt.x = lpRect->right; pt.y = lpRect->bottom; ret = ScreenToClient(hWnd, &pt); lpRect->right = pt.x; lpRect->bottom = pt.y; return ret; } BOOL MoveWindow(HWND hWnd, const RECT &rect, BOOL bRepaint) { return MoveWindow(hWnd, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, bRepaint); } static void FillButton(HWND hwndDlg, int dlgItem, TCHAR *name, TCHAR *key, HICON icon) { TCHAR tmp[256]; TCHAR *full; if (key == NULL) full = TranslateTS(name); else mir_sntprintf(full = tmp, MAX_REGS(tmp), _T("%s (%s)"), TranslateTS(name), key); SendMessage(GetDlgItem(hwndDlg, dlgItem), BUTTONSETASFLATBTN, 0, 0); SendMessage(GetDlgItem(hwndDlg, dlgItem), BUTTONADDTOOLTIP, (LPARAM) full, BATF_TCHAR); SendDlgItemMessage(hwndDlg, dlgItem, BM_SETIMAGE, IMAGE_ICON, (LPARAM) icon); } static void FillCheckbox(HWND hwndDlg, int dlgItem, TCHAR *name, TCHAR *key) { TCHAR tmp[256]; TCHAR *full; if (key == NULL) full = TranslateTS(name); else mir_sntprintf(full = tmp, MAX_REGS(tmp), _T("%s (%s)"), TranslateTS(name), key); SendMessage(GetDlgItem(hwndDlg, dlgItem), WM_SETTEXT, 0, (LPARAM) full); } static INT_PTR CALLBACK MainDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_INITDIALOG: { TranslateDialogDefault(hwndDlg); RECT rc; GetWindowRect(GetDlgItem(hwndDlg, IDC_USERNAME), &rc); ScreenToClient(hwndDlg, &rc); HWND icon = CreateWindow(_T("STATIC"), _T(""), WS_CHILD | WS_VISIBLE | SS_ICON | SS_CENTERIMAGE, rc.left - 20, rc.top + (rc.bottom - rc.top - 16) / 2, 16, 16, hwndDlg, (HMENU) IDC_ICO, hInst, NULL); if (!hasNewHotkeyModule) hAcct = LoadAccelerators(hInst, MAKEINTRESOURCE(ACCEL_TABLE)); hHook = SetWindowsHookEx(WH_MSGFILTER, HookProc, hInst, GetCurrentThreadId()); // Combo SendMessage(GetDlgItem(hwndDlg, IDC_USERNAME), EM_LIMITTEXT, (WPARAM)119,0); mir_subclassWindow(GetWindow(GetDlgItem(hwndDlg, IDC_USERNAME),GW_CHILD), EditProc); // Buttons FillCheckbox(hwndDlg, IDC_SHOW_ALL_CONTACTS, LPGENT("Show all contacts"), hasNewHotkeyModule ? NULL : LPGENT("Ctrl+A")); FillButton(hwndDlg, IDC_MESSAGE, LPGENT("Send message"), NULL, LoadSkinnedIcon(SKINICON_EVENT_MESSAGE)); if (ServiceExists(MS_VOICESERVICE_CAN_CALL)) FillButton(hwndDlg, IDC_VOICE, LPGENT("Make a voice call"), hasNewHotkeyModule ? NULL : LPGENT("Ctrl+V"), Skin_GetIcon("vca_call")); else { GetWindowRect(GetDlgItem(hwndDlg, IDC_VOICE), &rc); ScreenToClient(hwndDlg, &rc); MoveWindow(GetDlgItem(hwndDlg, IDC_MESSAGE), rc, FALSE); ShowWindow(GetDlgItem(hwndDlg, IDC_VOICE), SW_HIDE); } FillButton(hwndDlg, IDC_FILE, LPGENT("Send file"), hasNewHotkeyModule ? NULL : LPGENT("Ctrl+F"), LoadSkinnedIcon(SKINICON_EVENT_FILE)); FillButton(hwndDlg, IDC_URL, LPGENT("Send URL"), hasNewHotkeyModule ? NULL : LPGENT("Ctrl+U"), LoadSkinnedIcon(SKINICON_EVENT_URL)); FillButton(hwndDlg, IDC_USERINFO, LPGENT("Open userinfo"), hasNewHotkeyModule ? NULL : LPGENT("Ctrl+I"), LoadSkinnedIcon(SKINICON_OTHER_USERDETAILS)); FillButton(hwndDlg, IDC_HISTORY, LPGENT("Open history"), hasNewHotkeyModule ? NULL : LPGENT("Ctrl+H"), LoadSkinnedIcon(SKINICON_OTHER_HISTORY)); FillButton(hwndDlg, IDC_MENU, LPGENT("Open contact menu"), hasNewHotkeyModule ? NULL : LPGENT("Ctrl+M"), LoadSkinnedIcon(SKINICON_OTHER_DOWNARROW)); SendDlgItemMessage(hwndDlg, IDC_USERNAME, CB_SETEXTENDEDUI, (WPARAM)TRUE, 0); MagneticWindows_AddWindow(hwndDlg); Utils_RestoreWindowPositionNoSize(hwndDlg, NULL, MODULE_NAME, "window"); LoadContacts(hwndDlg, FALSE); EnableButtons(hwndDlg, NULL); if (DBGetContactSettingByte(NULL, MODULE_NAME, "EnableLastSentTo", 0)) { int pos = GetItemPos((HANDLE) DBGetContactSettingDword(NULL, MODULE_NAME, "LastSentTo", -1)); if (pos != -1) { SendDlgItemMessage(hwndDlg, IDC_USERNAME, CB_SETCURSEL, (WPARAM) pos, 0); EnableButtons(hwndDlg, contacts[pos]->hcontact); } } SetFocus(GetDlgItem(hwndDlg, IDC_USERNAME)); return TRUE; } case WM_COMMAND: { switch(LOWORD(wParam)) { case IDC_USERNAME: { if (HIWORD(wParam) == CBN_SELCHANGE) { int pos = SendDlgItemMessage(hwndDlg, IDC_USERNAME, CB_GETCURSEL, 0, 0); EnableButtons(hwndDlg, pos < contacts.getCount() ? contacts[pos]->hcontact : NULL); } break; } case IDC_ENTER: { HANDLE hContact = GetSelectedContact(hwndDlg); if (hContact == NULL) break; CallService(MS_CLIST_CONTACTDOUBLECLICKED, (WPARAM) hContact, 0); DBWriteContactSettingDword(NULL, MODULE_NAME, "LastSentTo", (DWORD) hContact); SendMessage(hwndDlg, WM_CLOSE, 0, 0); break; } case IDC_MESSAGE: { HANDLE hContact = GetSelectedContact(hwndDlg); if (hContact == NULL) { SetDlgItemText(hwndDlg, IDC_USERNAME, _T("")); SetFocus(GetDlgItem(hwndDlg, IDC_USERNAME)); break; } // Is button enabled? if (!IsWindowEnabled(GetDlgItem(hwndDlg, IDC_MESSAGE))) break; CallService(MS_MSG_SENDMESSAGET, (WPARAM) hContact, 0); DBWriteContactSettingDword(NULL, MODULE_NAME, "LastSentTo", (DWORD) hContact); SendMessage(hwndDlg, WM_CLOSE, 0, 0); break; } case HOTKEY_VOICE: case IDC_VOICE: { HANDLE hContact = GetSelectedContact(hwndDlg); if (hContact == NULL) { SetDlgItemText(hwndDlg, IDC_USERNAME, _T("")); SetFocus(GetDlgItem(hwndDlg, IDC_USERNAME)); break; } // Is button enabled? if (!IsWindowEnabled(GetDlgItem(hwndDlg, IDC_VOICE))) break; if (!ServiceExists(MS_VOICESERVICE_CALL)) break; CallService(MS_VOICESERVICE_CALL, (WPARAM) hContact, 0); DBWriteContactSettingDword(NULL, MODULE_NAME, "LastSentTo", (DWORD) hContact); SendMessage(hwndDlg, WM_CLOSE, 0, 0); break; } case HOTKEY_FILE: case IDC_FILE: { HANDLE hContact = GetSelectedContact(hwndDlg); if (hContact == NULL) { SetDlgItemText(hwndDlg, IDC_USERNAME, _T("")); SetFocus(GetDlgItem(hwndDlg, IDC_USERNAME)); break; } // Is button enabled? if (!IsWindowEnabled(GetDlgItem(hwndDlg, IDC_FILE))) break; CallService(MS_FILE_SENDFILE, (WPARAM) hContact, 0); DBWriteContactSettingDword(NULL, MODULE_NAME, "LastSentTo", (DWORD) hContact); SendMessage(hwndDlg, WM_CLOSE, 0, 0); break; } case HOTKEY_URL: case IDC_URL: { HANDLE hContact = GetSelectedContact(hwndDlg); if (hContact == NULL) { SetDlgItemText(hwndDlg, IDC_USERNAME, _T("")); SetFocus(GetDlgItem(hwndDlg, IDC_USERNAME)); break; } // Is button enabled? if (!IsWindowEnabled(GetDlgItem(hwndDlg, IDC_URL))) break; CallService(MS_URL_SENDURL, (WPARAM) hContact, 0); DBWriteContactSettingDword(NULL, MODULE_NAME, "LastSentTo", (DWORD) hContact); SendMessage(hwndDlg, WM_CLOSE, 0, 0); break; } case HOTKEY_INFO: case IDC_USERINFO: { HANDLE hContact = GetSelectedContact(hwndDlg); if (hContact == NULL) { SetDlgItemText(hwndDlg, IDC_USERNAME, _T("")); SetFocus(GetDlgItem(hwndDlg, IDC_USERNAME)); break; } // Is button enabled? if (!IsWindowEnabled(GetDlgItem(hwndDlg, IDC_USERINFO))) break; CallService(MS_USERINFO_SHOWDIALOG, (WPARAM) hContact, 0); DBWriteContactSettingDword(NULL, MODULE_NAME, "LastSentTo", (DWORD) hContact); SendMessage(hwndDlg, WM_CLOSE, 0, 0); break; } case HOTKEY_HISTORY: case IDC_HISTORY: { HANDLE hContact = GetSelectedContact(hwndDlg); if (hContact == NULL) { SetDlgItemText(hwndDlg, IDC_USERNAME, _T("")); SetFocus(GetDlgItem(hwndDlg, IDC_USERNAME)); break; } // Is button enabled? if (!IsWindowEnabled(GetDlgItem(hwndDlg, IDC_HISTORY))) break; CallService(MS_HISTORY_SHOWCONTACTHISTORY, (WPARAM) hContact, 0); DBWriteContactSettingDword(NULL, MODULE_NAME, "LastSentTo", (DWORD) hContact); SendMessage(hwndDlg, WM_CLOSE, 0, 0); break; } case HOTKEY_MENU: case IDC_MENU: { HANDLE hContact = GetSelectedContact(hwndDlg); if (hContact == NULL) { SetDlgItemText(hwndDlg, IDC_USERNAME, _T("")); SetFocus(GetDlgItem(hwndDlg, IDC_USERNAME)); break; } // Is button enabled? if (!IsWindowEnabled(GetDlgItem(hwndDlg, IDC_MENU))) break; RECT rc; GetWindowRect(GetDlgItem(hwndDlg, IDC_MENU), &rc); HMENU hMenu = (HMENU) CallService(MS_CLIST_MENUBUILDCONTACT, (WPARAM) hContact, 0); int ret = TrackPopupMenu(hMenu, TPM_TOPALIGN|TPM_RIGHTBUTTON|TPM_RETURNCMD, rc.left, rc.bottom, 0, hwndDlg, NULL); DestroyMenu(hMenu); if(ret) { SendMessage(hwndDlg, WM_CLOSE, 0, 0); CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(ret),MPCF_CONTACTMENU),(LPARAM) hContact); } DBWriteContactSettingDword(NULL, MODULE_NAME, "LastSentTo", (DWORD) hContact); break; } case HOTKEY_ALL_CONTACTS: case IDC_SHOW_ALL_CONTACTS: { // Get old text HWND hEdit = GetWindow(GetWindow(hwndDlg,GW_CHILD),GW_CHILD); TCHAR sztext[120] = _T(""); if (SendMessage(hEdit, EM_GETSEL, 0, 0) != -1) SendMessage(hEdit, EM_REPLACESEL, 0, (LPARAM)_T("")); SendMessage(hEdit, WM_GETTEXT, (WPARAM)MAX_REGS(sztext), (LPARAM)sztext); // Fill combo BOOL all = IsDlgButtonChecked(hwndDlg, IDC_SHOW_ALL_CONTACTS); if (LOWORD(wParam) == HOTKEY_ALL_CONTACTS) { // Toggle checkbox all = !all; CheckDlgButton(hwndDlg, IDC_SHOW_ALL_CONTACTS, all ? BST_CHECKED : BST_UNCHECKED); } LoadContacts(hwndDlg, all); // Return selection CheckText(hEdit, sztext); break; } } break; } case WM_CLOSE: { Utils_SaveWindowPosition(hwndDlg, NULL, MODULE_NAME, "window"); MagneticWindows_RemoveWindow(hwndDlg); DestroyWindow(hwndDlg); break; } case WM_DESTROY: { UnhookWindowsHookEx(hHook); hwndMain = NULL; FreeContacts(); InterlockedExchange(&main_dialog_open, 0); break; } case WM_NCLBUTTONDBLCLK: { MagneticWindows_SnapWindowToList(hwndDlg, MS_MW_STL_List_Left | MS_MW_STL_List_Top | MS_MW_STL_Wnd_Right | MS_MW_STL_Wnd_Top); break; } case WM_DRAWITEM: { // add icons and protocol to listbox LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam; // Handle contact menu if(lpdis->CtlID != IDC_USERNAME) { if (lpdis->CtlType == ODT_MENU) return CallService(MS_CLIST_MENUDRAWITEM,wParam,lParam); else break; } // Handle combo if(lpdis->itemID == -1) break; TEXTMETRIC tm; int icon_width=0, icon_height=0; RECT rc; GetTextMetrics(lpdis->hDC, &tm); ImageList_GetIconSize(hIml, &icon_width, &icon_height); COLORREF clrfore = SetTextColor(lpdis->hDC,GetSysColor(lpdis->itemState & ODS_SELECTED?COLOR_HIGHLIGHTTEXT:COLOR_WINDOWTEXT)); COLORREF clrback = SetBkColor(lpdis->hDC,GetSysColor(lpdis->itemState & ODS_SELECTED?COLOR_HIGHLIGHT:COLOR_WINDOW)); FillRect(lpdis->hDC, &lpdis->rcItem, GetSysColorBrush(lpdis->itemState & ODS_SELECTED ? COLOR_HIGHLIGHT : COLOR_WINDOW)); // Draw icon rc.left = lpdis->rcItem.left + 5; rc.top = (lpdis->rcItem.bottom + lpdis->rcItem.top - icon_height) / 2; ImageList_Draw(hIml, CallService(MS_CLIST_GETCONTACTICON, (WPARAM)contacts[lpdis->itemData]->hcontact, 0), lpdis->hDC, rc.left, rc.top, ILD_NORMAL); // Make rect for text rc.left += icon_width + 5; rc.right = lpdis->rcItem.right - 1; rc.top = (lpdis->rcItem.bottom + lpdis->rcItem.top - tm.tmHeight) / 2; rc.bottom = rc.top + tm.tmHeight; // Draw Protocol if (opts.num_protos > 1) { if (max_proto_width == 0) { // Has to be done, else the DC isnt the right one // Dont ask me why for(int loop = 0; loop < contacts.getCount(); loop++) { RECT rcc = { 0, 0, 0x7FFF, 0x7FFF }; DrawText(lpdis->hDC, contacts[loop]->proto, lstrlen(contacts[loop]->proto), &rcc, DT_END_ELLIPSIS | DT_NOPREFIX | DT_SINGLELINE | DT_CALCRECT); max_proto_width = max(max_proto_width, rcc.right - rcc.left); } // Fix max_proto_width if (opts.group_append && opts.group_column) max_proto_width = min(max_proto_width, (rc.right - rc.left) / 5); else if (opts.group_append) max_proto_width = min(max_proto_width, (rc.right - rc.left) / 4); else max_proto_width = min(max_proto_width, (rc.right - rc.left) / 3); } RECT rc_tmp = rc; rc_tmp.left = rc_tmp.right - max_proto_width; DrawText(lpdis->hDC, contacts[lpdis->itemData]->proto, lstrlen(contacts[lpdis->itemData]->proto), &rc_tmp, DT_END_ELLIPSIS | DT_NOPREFIX | DT_SINGLELINE); rc.right = rc_tmp.left - 5; } // Draw group if (opts.group_append && opts.group_column) { RECT rc_tmp = rc; if (opts.group_column_left) { rc_tmp.right = rc_tmp.left + (rc.right - rc.left) / 3; rc.left = rc_tmp.right + 5; } else { rc_tmp.left = rc_tmp.right - (rc.right - rc.left) / 3; rc.right = rc_tmp.left - 5; } DrawText(lpdis->hDC, contacts[lpdis->itemData]->szgroup, lstrlen(contacts[lpdis->itemData]->szgroup), &rc_tmp, DT_END_ELLIPSIS | DT_NOPREFIX | DT_SINGLELINE); } // Draw text TCHAR *name; if (opts.group_append && !opts.group_column) name = GetListName(contacts[lpdis->itemData]); else name = contacts[lpdis->itemData]->szname; DrawText(lpdis->hDC, name, lstrlen(name), &rc, DT_END_ELLIPSIS | DT_NOPREFIX | DT_SINGLELINE); // Restore old colors SetTextColor(lpdis->hDC, clrfore); SetBkColor(lpdis->hDC, clrback); return TRUE; } case WM_MEASUREITEM: { LPMEASUREITEMSTRUCT lpmis = (LPMEASUREITEMSTRUCT)lParam; // Handle contact menu if(lpmis->CtlID != IDC_USERNAME) { if (lpmis->CtlType == ODT_MENU) return CallService(MS_CLIST_MENUMEASUREITEM,wParam,lParam); else break; } // Handle combo TEXTMETRIC tm; int icon_width = 0, icon_height=0; GetTextMetrics(GetDC(hwndDlg), &tm); ImageList_GetIconSize(hIml, &icon_width, &icon_height); lpmis->itemHeight = max(icon_height, tm.tmHeight); return TRUE; } } return FALSE; } // Show the main dialog INT_PTR ShowDialog(WPARAM wParam, LPARAM lParam) { if (!main_dialog_open) { InterlockedExchange(&main_dialog_open, 1); hwndMain = CreateDialog(hInst, MAKEINTRESOURCE(IDD_MAIN), NULL, MainDlgProc); } // Show it SetForegroundWindow(hwndMain); SetFocus(hwndMain); ShowWindow(hwndMain, SW_SHOW); return 0; }