static void ShowContactMenu(HWND hwnd, POINT pt) { ThumbInfo *pThumb = thumbList.FindThumb(hwnd); if (pThumb != NULL) { hContactMenu = Menu_BuildContactMenu(pThumb->hContact); if (hContactMenu == NULL) return; int idCommand = TrackPopupMenu(hContactMenu, TPM_RIGHTALIGN | TPM_TOPALIGN | TPM_RETURNCMD, pt.x, pt.y, 0, hwnd, NULL); CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(idCommand, MPCF_CONTACTMENU), (LPARAM)pThumb->hContact); } }
static VOID NTAPI ShowContactMenu(ULONG_PTR wParam) // wParam = hContact { POINT pt; HWND hMenuWnd = CreateWindowEx(WS_EX_TOOLWINDOW, L"static", _A2W(MODULENAME) L"_MenuWindow", 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, HWND_DESKTOP, nullptr, g_plugin.getInst(), nullptr); SetWindowLongPtr(hMenuWnd, GWLP_WNDPROC, (LONG_PTR)MenuWndProc); HMENU hMenu = Menu_BuildContactMenu(wParam); GetCursorPos(&pt); SetForegroundWindow(hMenuWnd); Clist_MenuProcessCommand(TrackPopupMenu(hMenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD, pt.x, pt.y, 0, hMenuWnd, nullptr), MPCF_CONTACTMENU, wParam); PostMessage(hMenuWnd, WM_NULL, 0, 0); DestroyMenu(hMenu); DestroyWindow(hMenuWnd); }
INT_PTR CALLBACK HistoryDlgProc(HWND hwndDlg, UINT Message, WPARAM wparam, LPARAM lparam) { MCONTACT hContact; TCHAR sztemp[1024]; switch (Message) { case WM_INITDIALOG: TranslateDialogDefault(hwndDlg); hContact = (MCONTACT)lparam; SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lparam); mir_sntprintf(sztemp, _T("%s: %s"), pcli->pfnGetContactDisplayName(hContact, 0), TranslateT("last seen history")); SetWindowText(hwndDlg, sztemp); Window_SetSkinIcon_IcoLib(hwndDlg, SKINICON_OTHER_MIRANDA); if (db_get_b(hContact, S_MOD, "OnlineAlert", 0)) CheckDlgButton(hwndDlg, IDC_STATUSCHANGE, BST_CHECKED); SendDlgItemMessage(hwndDlg, IDC_DETAILS, BM_SETIMAGE, IMAGE_ICON, (WPARAM)Skin_LoadIcon(SKINICON_OTHER_USERDETAILS)); SendDlgItemMessage(hwndDlg, IDC_USERMENU, BM_SETIMAGE, IMAGE_ICON, (WPARAM)Skin_LoadIcon(SKINICON_OTHER_DOWNARROW)); SendDlgItemMessage(hwndDlg, IDC_SENDMSG, BM_SETIMAGE, IMAGE_ICON, (WPARAM)Skin_LoadIcon(SKINICON_EVENT_MESSAGE)); //set-up tooltips SendDlgItemMessage(hwndDlg, IDC_DETAILS, BUTTONADDTOOLTIP, (WPARAM)TranslateT("View User's Details"), BATF_TCHAR); SendDlgItemMessage(hwndDlg, IDC_USERMENU, BUTTONADDTOOLTIP, (WPARAM)TranslateT("User Menu"), BATF_TCHAR); SendDlgItemMessage(hwndDlg, IDC_SENDMSG, BUTTONADDTOOLTIP, (WPARAM)TranslateT("Send Instant Message"), BATF_TCHAR); Utils_RestoreWindowPositionNoMove(hwndDlg, NULL, S_MOD, "History_"); ShowWindow(hwndDlg, SW_SHOW); return TRUE; case WM_MEASUREITEM: return Menu_MeasureItem((LPMEASUREITEMSTRUCT)lparam); case WM_DRAWITEM: return Menu_DrawItem((LPDRAWITEMSTRUCT)lparam); case WM_COMMAND: hContact = (MCONTACT)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); if (CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(wparam), MPCF_CONTACTMENU), hContact)) break; switch (LOWORD(wparam)) { case IDCANCEL: SendMessage(hwndDlg, WM_CLOSE, 0, 0); break; case IDOK: if (IsDlgButtonChecked(hwndDlg, IDC_STATUSCHANGE) == BST_CHECKED) db_set_b(hContact, S_MOD, "OnlineAlert", 1); else db_set_b(hContact, S_MOD, "OnlineAlert", 0); SendMessage(hwndDlg, WM_CLOSE, 0, 0); break; case IDC_USERMENU: { RECT rc; GetWindowRect(GetDlgItem(hwndDlg, IDC_USERMENU), &rc); HMENU hMenu = Menu_BuildContactMenu(hContact); TrackPopupMenu(hMenu, 0, rc.left, rc.bottom, 0, hwndDlg, NULL); DestroyMenu(hMenu); } break; case IDC_DETAILS: CallService(MS_USERINFO_SHOWDIALOG, hContact, 0); break; case IDC_SENDMSG: CallService(MS_MSG_SENDMESSAGE, hContact, 0); break; case IDC_TEST: debug(ParseString(LPGENT("Date: %d.%m.%y(%Y) \n Date desc: %W - %w - %E - %e \n Time: %H:%M:%S (%h-%p) \n user: %n - %u \n Status: %s \n IP: %i - %r"), hContact)); break; } break; case WM_SIZE: int dx, dy; { HDWP hDwp = BeginDeferWindowPos(6); MyResizeGetOffset(GetDlgItem(hwndDlg, IDC_HISTORYLIST), LOWORD(lparam) - 15, HIWORD(lparam) - 99, &dx, &dy); hDwp = MyResizeWindow(hDwp, hwndDlg, GetDlgItem(hwndDlg, IDC_USERMENU), dx, 0, 0, 0); hDwp = MyResizeWindow(hDwp, hwndDlg, GetDlgItem(hwndDlg, IDC_DETAILS), dx, 0, 0, 0); hDwp = MyResizeWindow(hDwp, hwndDlg, GetDlgItem(hwndDlg, IDC_SENDMSG), dx, 0, 0, 0); hDwp = MyResizeWindow(hDwp, hwndDlg, GetDlgItem(hwndDlg, IDC_HISTORYLIST), 0, 0, dx, dy); hDwp = MyResizeWindow(hDwp, hwndDlg, GetDlgItem(hwndDlg, IDC_STATUSCHANGE), 0, dy, dx, 0); hDwp = MyHorizCenterWindow(hDwp, hwndDlg, GetDlgItem(hwndDlg, IDOK), LOWORD(lparam), dy, 0); EndDeferWindowPos(hDwp); } break; case WM_GETMINMAXINFO: MINMAXINFO mmi; { memcpy(&mmi, (LPMINMAXINFO)lparam, sizeof(MINMAXINFO)); /* The minimum width in points*/ mmi.ptMinTrackSize.x = 200; /* The minimum height in points*/ mmi.ptMinTrackSize.y = 190; memcpy((LPMINMAXINFO)lparam, &mmi, sizeof(MINMAXINFO)); } break; case WM_CLOSE: DestroyWindow(hwndDlg); WindowList_Remove(hWindowList, hwndDlg); break; case WM_DESTROY: Utils_SaveWindowPosition(hwndDlg, NULL, S_MOD, "History_"); DestroyIcon((HICON)SendMessage(hwndDlg, WM_GETICON, ICON_BIG, 0)); DestroyIcon((HICON)SendMessage(hwndDlg, WM_GETICON, ICON_SMALL, 0)); break; } return FALSE; }
INT_PTR CALLBACK DlgProcUrlRecv(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) { struct UrlRcvData *dat = (struct UrlRcvData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); switch (msg) { case WM_INITDIALOG: TranslateDialogDefault(hwndDlg); Window_SetIcon_IcoLib(hwndDlg, SKINICON_EVENT_URL); Button_SetIcon_IcoLib(hwndDlg, IDC_ADD, SKINICON_OTHER_ADDCONTACT, LPGEN("Add contact permanently to list")); Button_SetIcon_IcoLib(hwndDlg, IDC_DETAILS, SKINICON_OTHER_USERDETAILS, LPGEN("View user's details")); Button_SetIcon_IcoLib(hwndDlg, IDC_HISTORY, SKINICON_OTHER_HISTORY, LPGEN("View user's history")); Button_SetIcon_IcoLib(hwndDlg, IDC_USERMENU, SKINICON_OTHER_DOWNARROW, LPGEN("User menu")); dat = (struct UrlRcvData*)mir_alloc(sizeof(struct UrlRcvData)); SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)dat); dat->hContact = ((CLISTEVENT*)lParam)->hContact; dat->hDbEvent = ((CLISTEVENT*)lParam)->hDbEvent; WindowList_Add(hUrlWindowList, hwndDlg, dat->hContact); { DBEVENTINFO dbei = { sizeof(dbei) }; dbei.cbBlob = db_event_getBlobSize(dat->hDbEvent); dbei.pBlob = (PBYTE)mir_alloc(dbei.cbBlob); db_event_get(dat->hDbEvent, &dbei); SetDlgItemTextA(hwndDlg, IDC_URL, (char*)dbei.pBlob); SetDlgItemTextA(hwndDlg, IDC_MSG, (char*)dbei.pBlob+mir_strlen((char*)dbei.pBlob)+1); mir_free(dbei.pBlob); db_event_markRead(dat->hContact, dat->hDbEvent); TCHAR *contactName = pcli->pfnGetContactDisplayName(dat->hContact, 0), msg[128]; mir_sntprintf(msg, _countof(msg), TranslateT("URL from %s"), contactName); SetWindowText(hwndDlg, msg); SetDlgItemText(hwndDlg, IDC_FROM, contactName); SendDlgItemMessage(hwndDlg, IDOK, BUTTONSETARROW, 1, 0); TCHAR str[128]; TimeZone_PrintTimeStamp(NULL, dbei.timestamp, _T("t d"), str, _countof(str), 0); SetDlgItemText(hwndDlg, IDC_DATE, str); } // From message dlg if ( !db_get_b(dat->hContact, "CList", "NotOnList", 0)) ShowWindow(GetDlgItem(hwndDlg, IDC_ADD), SW_HIDE); SendMessage(hwndDlg, DM_UPDATETITLE, 0, 0); // From message dlg end Utils_RestoreWindowPositionNoSize(hwndDlg, NULL, "SRUrl", "recv"); return TRUE; case WM_MEASUREITEM: return Menu_MeasureItem((LPMEASUREITEMSTRUCT)lParam); case WM_DRAWITEM: { LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT)lParam; if (dis->hwndItem == GetDlgItem(hwndDlg, IDC_PROTOCOL)) { char *szProto = GetContactProto(dat->hContact); if (szProto) { HICON hIcon = (HICON)CallProtoService(szProto, PS_LOADICON, PLI_PROTOCOL|PLIF_SMALL, 0); if (hIcon) { DrawIconEx(dis->hDC, dis->rcItem.left, dis->rcItem.top, hIcon, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0, NULL, DI_NORMAL); DestroyIcon(hIcon); } } } } return Menu_DrawItem((LPDRAWITEMSTRUCT)lParam); case DM_UPDATETITLE: sttUpdateTitle(hwndDlg, dat->hContact); break; case WM_COMMAND: if (!dat) break; if (CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(wParam), MPCF_CONTACTMENU), (LPARAM)dat->hContact)) break; switch(LOWORD(wParam)) { case IDOK: { RECT rc; char url[256]; HMENU hMenu = LoadMenu(hInst, MAKEINTRESOURCE(IDR_CONTEXT)); HMENU hSubMenu = GetSubMenu(hMenu, 6); TranslateMenu(hSubMenu); GetWindowRect((HWND)lParam, &rc); GetDlgItemTextA(hwndDlg, IDC_URL, url, _countof(url)); switch(TrackPopupMenu(hSubMenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, hwndDlg, NULL)) { case IDM_OPENNEW: Utils_OpenUrl(url); break; case IDM_OPENEXISTING: Utils_OpenUrl(url); break; case IDM_COPYLINK: { if ( !OpenClipboard(hwndDlg)) break; EmptyClipboard(); HGLOBAL hData = GlobalAlloc(GMEM_MOVEABLE, mir_strlen(url)+1); mir_strcpy((char*)GlobalLock(hData), url); GlobalUnlock(hData); SetClipboardData(CF_TEXT, hData); CloseClipboard(); break; } } DestroyMenu(hMenu); } return TRUE; case IDC_USERMENU: { RECT rc; HMENU hMenu = Menu_BuildContactMenu(dat->hContact); GetWindowRect(GetDlgItem(hwndDlg, IDC_USERMENU), &rc); TrackPopupMenu(hMenu, 0, rc.left, rc.bottom, 0, hwndDlg, NULL); DestroyMenu(hMenu); } break; case IDC_HISTORY: CallService(MS_HISTORY_SHOWCONTACTHISTORY, (WPARAM)dat->hContact, 0); break; case IDC_DETAILS: CallService(MS_USERINFO_SHOWDIALOG, (WPARAM)dat->hContact, 0); break; case IDC_ADD: { ADDCONTACTSTRUCT acs = {0}; acs.hContact = dat->hContact; acs.handleType = HANDLE_CONTACT; CallService(MS_ADDCONTACT_SHOW, (WPARAM)hwndDlg, (LPARAM)&acs); } if ( !db_get_b(dat->hContact, "CList", "NotOnList", 0)) { ShowWindow(GetDlgItem(hwndDlg, IDC_ADD), FALSE); } break; case IDC_REPLY: CallService(MS_MSG_SENDMESSAGE, (WPARAM)dat->hContact, 0); //fall through case IDCANCEL: DestroyWindow(hwndDlg); return TRUE; } break; case WM_DESTROY: Window_FreeIcon_IcoLib(hwndDlg); Button_FreeIcon_IcoLib(hwndDlg, IDC_ADD); Button_FreeIcon_IcoLib(hwndDlg, IDC_DETAILS); Button_FreeIcon_IcoLib(hwndDlg, IDC_HISTORY); Button_FreeIcon_IcoLib(hwndDlg, IDC_USERMENU); WindowList_Remove(hUrlWindowList, hwndDlg); mir_free(dat); Utils_SaveWindowPosition(hwndDlg, NULL, "SRUrl", "recv"); break; } return FALSE; }
INT_PTR CALLBACK DlgProcUrlSend(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) { struct UrlSendData* dat = (struct UrlSendData*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); switch (msg) { case WM_INITDIALOG: TranslateDialogDefault(hwndDlg); Window_SetIcon_IcoLib(hwndDlg, SKINICON_EVENT_URL); Button_SetIcon_IcoLib(hwndDlg, IDC_ADD, SKINICON_OTHER_ADDCONTACT, LPGEN("Add contact permanently to list")); Button_SetIcon_IcoLib(hwndDlg, IDC_DETAILS, SKINICON_OTHER_USERDETAILS, LPGEN("View user's details")); Button_SetIcon_IcoLib(hwndDlg, IDC_HISTORY, SKINICON_OTHER_HISTORY, LPGEN("View user's history")); Button_SetIcon_IcoLib(hwndDlg, IDC_USERMENU, SKINICON_OTHER_DOWNARROW, LPGEN("User menu")); SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_LIMITTEXT, 450, 0); dat = (struct UrlSendData*)mir_alloc(sizeof(struct UrlSendData)); SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)dat); dat->hContact = lParam; dat->hAckEvent = NULL; dat->hSendId = NULL; dat->sendBuffer = NULL; WindowList_Add(hUrlWindowList, hwndDlg, dat->hContact); { TCHAR *str = pcli->pfnGetContactDisplayName(dat->hContact, 0); SetDlgItemText(hwndDlg, IDC_NAME, str); } GetOpenBrowserUrls(hwndDlg, GetDlgItem(hwndDlg, IDC_URLS)); SendDlgItemMessage(hwndDlg, IDC_URLS, CB_SETCURSEL, 0, 0); if (SendDlgItemMessage(hwndDlg, IDC_URLS, CB_GETCOUNT, 0, 0))SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_URLS, CBN_SELCHANGE), 0); EnableWindow(GetDlgItem(hwndDlg, IDOK), (SendDlgItemMessage(hwndDlg, IDC_URLS, CB_GETCURSEL, 0, 0) == CB_ERR)?FALSE:TRUE); Utils_RestoreWindowPositionNoSize(hwndDlg, NULL, "SRUrl", "send"); mir_subclassWindow( GetDlgItem(hwndDlg, IDC_MESSAGE), SendEditSubclassProc); mir_subclassWindow( GetWindow(GetDlgItem(hwndDlg, IDC_URLS), GW_CHILD), SendEditSubclassProc); // From message dlg if ( !db_get_b(dat->hContact, "CList", "NotOnList", 0)) ShowWindow(GetDlgItem(hwndDlg, IDC_ADD), SW_HIDE); SendMessage(hwndDlg, DM_UPDATETITLE, 0, 0); // From message dlg end return TRUE; case WM_DDE_DATA: case WM_DDE_ACK: return DdeMessage(hwndDlg, msg, wParam, lParam); case WM_TIMER: if (wParam == 0) { //ICQ sendurl timed out KillTimer(hwndDlg, 0); MessageBox(hwndDlg, TranslateT("Send timed out"), _T(""), MB_OK); EnableWindow(GetDlgItem(hwndDlg, IDOK), TRUE); EnableWindow(GetDlgItem(hwndDlg, IDC_URLS), TRUE); SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETREADONLY, FALSE, 0); } break; case WM_MEASUREITEM: return Menu_MeasureItem((LPMEASUREITEMSTRUCT)lParam); case WM_DRAWITEM: { LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT)lParam; if (dis->hwndItem == GetDlgItem(hwndDlg, IDC_PROTOCOL)) { char *szProto = GetContactProto(dat->hContact); if (szProto) { HICON hIcon = (HICON)CallProtoService(szProto, PS_LOADICON, PLI_PROTOCOL|PLIF_SMALL, 0); if (hIcon) { DrawIconEx(dis->hDC, dis->rcItem.left, dis->rcItem.top, hIcon, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0, NULL, DI_NORMAL); DestroyIcon(hIcon); } } } } return Menu_DrawItem((LPDRAWITEMSTRUCT)lParam); case DM_UPDATETITLE: sttUpdateTitle(hwndDlg, dat->hContact); break; case WM_COMMAND: if (CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(wParam), MPCF_CONTACTMENU), (LPARAM)dat->hContact)) break; switch (LOWORD(wParam)) { case IDOK: { char *body, *url; int bodySize, urlSize; urlSize = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_URLS))+1; url = (char*)mir_alloc(urlSize); GetDlgItemTextA(hwndDlg, IDC_URLS, url, urlSize); if (url[0] == 0) { mir_free(url); break; } bodySize = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_MESSAGE))+1; body = (char*)mir_alloc(bodySize); GetDlgItemTextA(hwndDlg, IDC_MESSAGE, body, bodySize); dat->sendBuffer = (char*)mir_realloc(dat->sendBuffer, mir_strlen(url)+mir_strlen(body)+2); mir_strcpy(dat->sendBuffer, url); mir_strcpy(dat->sendBuffer+mir_strlen(url)+1, body); dat->hAckEvent = HookEventMessage(ME_PROTO_ACK, hwndDlg, HM_EVENTSENT); dat->hSendId = (HANDLE)CallContactService(dat->hContact, PSS_URL, 0, (LPARAM)dat->sendBuffer); mir_free(url); mir_free(body); //create a timeout timer SetTimer(hwndDlg, 0, TIMEOUT_URLSEND, NULL); EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE); EnableWindow(GetDlgItem(hwndDlg, IDC_URLS), FALSE); SendDlgItemMessage(hwndDlg, IDC_MESSAGE, EM_SETREADONLY, TRUE, 0); return TRUE; } case IDCANCEL: DestroyWindow(hwndDlg); return TRUE; case IDC_URLS: if (HIWORD(wParam) == CBN_SELCHANGE) { int i, urlSize; char *title; i = SendDlgItemMessage(hwndDlg, IDC_URLS, CB_GETCURSEL, 0, 0); title = (char*)SendDlgItemMessage(hwndDlg, IDC_URLS, CB_GETITEMDATA, (WPARAM)i, 0); SetDlgItemTextA(hwndDlg, IDC_MESSAGE, title); urlSize = SendDlgItemMessage(hwndDlg, IDC_URLS, CB_GETLBTEXTLEN, (WPARAM)i, 0); EnableWindow(GetDlgItem(hwndDlg, IDOK), (urlSize>0)); } else if (HIWORD(wParam) == CBN_EDITCHANGE) { int urlSize = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_URLS)); EnableWindow(GetDlgItem(hwndDlg, IDOK), (urlSize>0)); } break; case IDC_USERMENU: { RECT rc; HMENU hMenu = Menu_BuildContactMenu(dat->hContact); GetWindowRect(GetDlgItem(hwndDlg, IDC_USERMENU), &rc); TrackPopupMenu(hMenu, 0, rc.left, rc.bottom, 0, hwndDlg, NULL); DestroyMenu(hMenu); } break; case IDC_HISTORY: CallService(MS_HISTORY_SHOWCONTACTHISTORY, (WPARAM)dat->hContact, 0); break; case IDC_DETAILS: CallService(MS_USERINFO_SHOWDIALOG, (WPARAM)dat->hContact, 0); break; case IDC_ADD: ADDCONTACTSTRUCT acs = {0}; acs.hContact = dat->hContact; acs.handleType = HANDLE_CONTACT; acs.szProto = 0; CallService(MS_ADDCONTACT_SHOW, (WPARAM)hwndDlg, (LPARAM)&acs); if ( !db_get_b(dat->hContact, "CList", "NotOnList", 0)) ShowWindow(GetDlgItem(hwndDlg, IDC_ADD), FALSE); } break; case HM_EVENTSENT: { ACKDATA *ack = (ACKDATA*)lParam; if (ack->hProcess != dat->hSendId) break; if (ack->hContact != dat->hContact) break; if (ack->type != ACKTYPE_URL || ack->result != ACKRESULT_SUCCESS) break; DBEVENTINFO dbei = { 0 }; dbei.cbSize = sizeof(dbei); dbei.eventType = EVENTTYPE_URL; dbei.flags = DBEF_SENT; dbei.szModule = GetContactProto(dat->hContact); dbei.timestamp = time(NULL); dbei.cbBlob = (DWORD)(mir_strlen(dat->sendBuffer)+mir_strlen(dat->sendBuffer+mir_strlen(dat->sendBuffer)+1)+2); dbei.pBlob = (PBYTE)dat->sendBuffer; db_event_add(dat->hContact, &dbei); KillTimer(hwndDlg, 0); DestroyWindow(hwndDlg); } break; case WM_DESTROY: Window_FreeIcon_IcoLib(hwndDlg); Button_FreeIcon_IcoLib(hwndDlg, IDC_ADD); Button_FreeIcon_IcoLib(hwndDlg, IDC_DETAILS); Button_FreeIcon_IcoLib(hwndDlg, IDC_HISTORY); Button_FreeIcon_IcoLib(hwndDlg, IDC_USERMENU); WindowList_Remove(hUrlWindowList, hwndDlg); if (dat->hAckEvent) UnhookEvent(dat->hAckEvent); if (dat->sendBuffer != NULL) mir_free(dat->sendBuffer); mir_free(dat); Utils_SaveWindowPosition(hwndDlg, NULL, "SRUrl", "send"); for (int i = SendDlgItemMessage(hwndDlg, IDC_URLS, CB_GETCOUNT, 0, 0)-1;i>=0;i--) mir_free((char*)SendDlgItemMessage(hwndDlg, IDC_URLS, CB_GETITEMDATA, i, 0)); break; } return FALSE; }
LRESULT CALLBACK ContactListSubclassProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { TVITEM tvi; CCList *dat = CWndUserData(GetParent(hWnd)).GetCList(); switch (Msg) { case INTM_CONTACTDELETED: // wParam = (HANDLE)hContact { HTREEITEM hItem = dat->FindContact(wParam); if (hItem) TreeView_DeleteItem(hWnd, hItem); } break; case INTM_ICONCHANGED: // wParam = (HANDLE)hContact, lParam = IconID tvi.hItem = dat->FindContact(wParam); if (tvi.hItem) { tvi.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE; tvi.iImage = tvi.iSelectedImage = lParam; TreeView_SetItem(hWnd, &tvi); dat->SortContacts(); InvalidateRect(hWnd, nullptr, false); } break; case INTM_INVALIDATE: InvalidateRect(hWnd, nullptr, true); break; case WM_RBUTTONDOWN: SetFocus(hWnd); { TVHITTESTINFO hitTest; hitTest.pt.x = (short)LOWORD(lParam); hitTest.pt.y = (short)HIWORD(lParam); TreeView_HitTest(hWnd, &hitTest); if (hitTest.hItem && hitTest.flags & TVHT_ONITEM) TreeView_SelectItem(hWnd, hitTest.hItem); } return DefWindowProc(hWnd, Msg, wParam, lParam); case WM_LBUTTONDOWN: { POINT pt = { (short)LOWORD(lParam), (short)HIWORD(lParam) }; DWORD hitFlags; HTREEITEM hItem = dat->HitTest(&pt, &hitFlags); if (!hItem) break; if (hitFlags & MCLCHT_ONITEMICON) { if (TreeView_GetChild(hWnd, hItem)) { // if it's a group, then toggle its state NMTREEVIEW nmtv; nmtv.hdr.hwndFrom = hWnd; nmtv.hdr.idFrom = GetDlgCtrlID(hWnd); nmtv.hdr.code = TVN_ITEMEXPANDING; nmtv.action = TVE_TOGGLE; nmtv.itemNew.hItem = hItem; nmtv.itemNew.mask = TVIF_HANDLE | TVIF_STATE | TVIF_PARAM; TreeView_GetItem(hWnd, &nmtv.itemNew); nmtv.ptDrag = pt; if (SendMessage(GetParent(hWnd), WM_NOTIFY, 0, (LPARAM)&nmtv)) return 0; HTREEITEM hOldSelItem = TreeView_GetSelection(hWnd); TreeView_Expand(hWnd, hItem, TVE_TOGGLE); HTREEITEM hNewSelItem = TreeView_GetSelection(hWnd); if (hNewSelItem != hOldSelItem) { TreeView_SetItemState(hWnd, hOldSelItem, (dat->SelectedItems.Find(hOldSelItem) == -1) ? 0 : TVIS_SELECTED, TVIS_SELECTED); TreeView_SetItemState(hWnd, hNewSelItem, (dat->SelectedItems.Find(hNewSelItem) == -1) ? 0 : TVIS_SELECTED, TVIS_SELECTED); } nmtv.hdr.code = TVN_ITEMEXPANDED; TreeView_GetItem(hWnd, &nmtv.itemNew); SendMessage(GetParent(hWnd), WM_NOTIFY, 0, (LPARAM)&nmtv); return 0; } } if (hitFlags & MCLCHT_ONITEM) { if (wParam & MK_CONTROL) { SetFocus(hWnd); TREEITEMARRAY OldSelection = dat->SelectedItems; int nIndex = dat->SelectedItems.Find(hItem); if (nIndex == -1) { TreeView_SetItemState(hWnd, hItem, TVIS_SELECTED, TVIS_SELECTED); dat->SelectedItems.AddElem(hItem); } else { TreeView_SetItemState(hWnd, hItem, 0, TVIS_SELECTED); dat->SelectedItems.RemoveElem(nIndex); } dat->SelectGroups(hItem, nIndex == -1); NMCLIST nm; nm.hdr.code = MCLN_SELCHANGED; nm.hdr.hwndFrom = hWnd; nm.hdr.idFrom = GetDlgCtrlID(hWnd); nm.OldSelection = &OldSelection; nm.NewSelection = &dat->SelectedItems; SendMessage(GetParent(hWnd), WM_NOTIFY, 0, (LPARAM)&nm); return 0; } // if it was a click on the selected item and there's need to do something in this case, then send SELCHANGED notification by ourselves, as the tree control doesn't do anything if (hItem == TreeView_GetSelection(hWnd) && (dat->SelectedItems.GetSize() != 1 || (dat->SelectedItems.GetSize() == 1 && dat->SelectedItems[0] != hItem))) { TreeView_SetItemState(hWnd, hItem, TVIS_SELECTED, TVIS_SELECTED); NMTREEVIEW nm = {}; nm.hdr.code = TVN_SELCHANGED; nm.hdr.hwndFrom = hWnd; nm.hdr.idFrom = GetDlgCtrlID(hWnd); nm.itemOld.hItem = TreeView_GetSelection(hWnd); nm.itemOld.mask = TVIF_HANDLE | TVIF_STATE | TVIF_PARAM; TreeView_GetItem(hWnd, &nm.itemOld); nm.itemNew = nm.itemOld; SendMessage(GetParent(hWnd), WM_NOTIFY, 0, (LPARAM)&nm); } } } break; case WM_SETFOCUS: case WM_KILLFOCUS: for (int i = 0; i < dat->SelectedItems.GetSize(); i++) { RECT rc; if (TreeView_GetItemRect(hWnd, dat->SelectedItems[i], &rc, false)) InvalidateRect(hWnd, &rc, false); } break; case WM_SIZE: case WM_HSCROLL: InvalidateRect(hWnd, nullptr, false); break; case WM_MEASUREITEM: if (!wParam) // if the message was sent by a menu return Menu_MeasureItem(lParam); break; case WM_DRAWITEM: if (!wParam) // if the message was sent by a menu return Menu_DrawItem(lParam); break; case WM_CONTEXTMENU: { POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; HTREEITEM hItem = nullptr; if (pt.x == -1 && pt.y == -1) { if (dat->SelectedItems.GetSize() == 1) { hItem = dat->SelectedItems[0]; TreeView_EnsureVisible(hWnd, hItem); RECT rc; TreeView_GetItemRect(hWnd, hItem, &rc, true); pt.x = rc.left; pt.y = rc.bottom; } } else { DWORD hitFlags; ScreenToClient(hWnd, &pt); hItem = dat->HitTest(&pt, &hitFlags); if (!(hitFlags & MCLCHT_ONITEM)) hItem = nullptr; } if (hItem) { MCONTACT hContact = dat->GetItemData(hItem).hContact; if (IsHContactContact(hContact)) { HMENU hMenu = Menu_BuildContactMenu(hContact); if (hMenu) { ClientToScreen(hWnd, &pt); Clist_MenuProcessCommand(TrackPopupMenu(hMenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD, pt.x, pt.y, 0, hWnd, nullptr), MPCF_CONTACTMENU, hContact); DestroyMenu(hMenu); return 0; } } } } break; case WM_DESTROY: if (dat->ExtraImageList) ImageList_Destroy(dat->ExtraImageList); dat->SelectedItems.RemoveAll(); dat->Items.RemoveAll(); break; } return CallWindowProc(dat->OrigTreeViewProc, hWnd, Msg, wParam, lParam); }
/** * This static method is the window procedure for the dialog. * * @param hDlg - handle of the dialog window * @param uMsg - message to handle * @param wParam - message dependend parameter * @param lParam - message dependend parameter * * @return depends on message **/ static INT_PTR CALLBACK DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { CAnnivList *pDlg = (CAnnivList *)GetUserData(hDlg); switch (uMsg) { case WM_INITDIALOG: { HWND hCtrl; HICON hIcon; RECT rc; // link the class to the window handle pDlg = (CAnnivList *)lParam; if (!pDlg) break; SetUserData(hDlg, lParam); pDlg->_hDlg = hDlg; // init pointer listview control pDlg->_hList = GetDlgItem(hDlg, EDIT_ANNIVERSARY_DATE); if (!pDlg->_hList) break; // set icons hIcon = IcoLib_GetIcon(ICO_DLG_ANNIVERSARY); SendDlgItemMessage(hDlg, IDC_HEADERBAR, WM_SETICON, 0, (LPARAM)hIcon); SendMessage(hDlg, WM_SETICON, ICON_BIG, (LPARAM)hIcon); // insert columns into the listboxes ListView_SetExtendedListViewStyle(pDlg->_hList, LVS_EX_FULLROWSELECT); // add columns if (pDlg->AddColumn(CAnnivList::COLUMN_ETA, LPGENT("ETA"), 40) || pDlg->AddColumn(CAnnivList::COLUMN_CONTACT, LPGENT("Contact"), 160) || pDlg->AddColumn(CAnnivList::COLUMN_PROTO, LPGENT("Proto"), 50) || pDlg->AddColumn(CAnnivList::COLUMN_AGE, LPGENT("Age/Nr."), 40) || pDlg->AddColumn(CAnnivList::COLUMN_DESC, LPGENT("Anniversary"), 100) || pDlg->AddColumn(CAnnivList::COLUMN_DATE, LPGENT("Date"), 80)) break; TranslateDialogDefault(hDlg); // save minimal size GetWindowRect(hDlg, &rc); pDlg->_sizeMin.cx = rc.right - rc.left; pDlg->_sizeMin.cy = rc.bottom - rc.top; // restore position and size Utils_RestoreWindowPosition(hDlg, NULL, MODNAME, "AnnivDlg_"); //save win pos GetWindowRect(hDlg, &pDlg->_rcWin); // add filter strings if (hCtrl = GetDlgItem(hDlg, COMBO_VIEW)) { ComboBox_AddString(hCtrl, TranslateT("All contacts")); ComboBox_AddString(hCtrl, TranslateT("Birthdays only")); ComboBox_AddString(hCtrl, TranslateT("Anniversaries only")); ComboBox_AddString(hCtrl, TranslateT("Disabled reminder")); ComboBox_SetCurSel(hCtrl, pDlg->_filter.bFilterIndex); } // init reminder groups pDlg->_bRemindEnable = db_get_b(NULL, MODNAME, SET_REMIND_ENABLED, DEFVAL_REMIND_ENABLED) != REMIND_OFF; if (hCtrl = GetDlgItem(hDlg, CHECK_REMIND)) { Button_SetCheck(hCtrl, pDlg->_bRemindEnable ? BST_INDETERMINATE : BST_UNCHECKED); EnableWindow(hCtrl, pDlg->_bRemindEnable); } CheckDlgButton(hDlg, CHECK_POPUP, db_get_b(NULL, MODNAME, SET_ANNIVLIST_POPUP, FALSE) ? BST_CHECKED : BST_UNCHECKED); // set number of days to show contact in advance SetDlgItemInt(hDlg, EDIT_DAYS, pDlg->_filter.wDaysBefore, FALSE); if (hCtrl = GetDlgItem(hDlg, CHECK_DAYS)) { Button_SetCheck(hCtrl, db_get_b(NULL, MODNAME, SET_ANNIVLIST_FILTER_DAYSENABLED, FALSE)); DlgProc(hDlg, WM_COMMAND, MAKEWPARAM(CHECK_DAYS, BN_CLICKED), (LPARAM)hCtrl); } pDlg->_wmINIT = false; } return TRUE; // set propertysheet page's background white in aero mode case WM_CTLCOLORSTATIC: case WM_CTLCOLORDLG: if (IsAeroMode()) return (INT_PTR)GetStockBrush(WHITE_BRUSH); break; case WM_NOTIFY: switch (((LPNMHDR)lParam)->idFrom) { case EDIT_ANNIVERSARY_DATE: switch (((LPNMHDR)lParam)->code) { // handle changed selection case LVN_ITEMCHANGED: { CItemData *pid; HWND hCheck; pDlg->_curSel = ((LPNMLISTVIEW)lParam)->iItem; pid = pDlg->ItemData(pDlg->_curSel); if (pid && pDlg->_bRemindEnable && (hCheck = GetDlgItem(hDlg, CHECK_REMIND))) { SetDlgItemInt(hDlg, EDIT_REMIND, pid->_wDaysBefore, FALSE); Button_SetCheck(hCheck, pid->_wReminderState); DlgProc(hDlg, WM_COMMAND, MAKEWPARAM(CHECK_REMIND, BN_CLICKED), (LPARAM)hCheck); } } break; // resort the list case LVN_COLUMNCLICK: { LPNMLISTVIEW pnmv = (LPNMLISTVIEW)lParam; if (pDlg->_sortHeader == pnmv->iSubItem) pDlg->_sortOrder *= -1; else { pDlg->_sortOrder = 1; pDlg->_sortHeader = pnmv->iSubItem; } ListView_SortItemsEx(pDlg->_hList, (CMPPROC)cmpProc, pDlg); } break; // show contact menu case NM_RCLICK: { CItemData *pid = pDlg->ItemData(pDlg->_curSel); if (pid) { HMENU hPopup = Menu_BuildContactMenu(pid->_hContact); if (hPopup) { POINT pt; GetCursorPos(&pt); TrackPopupMenu(hPopup, TPM_TOPALIGN | TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, 0, hDlg, NULL); DestroyMenu(hPopup); } } } break; // handle double click on contact: show message dialog case NM_DBLCLK: { CItemData *pid = pDlg->ItemData(((LPNMITEMACTIVATE)lParam)->iItem); if (pid) CallService(MS_MSG_SENDMESSAGE,(WPARAM)pid->_hContact, NULL); } } } break; case WM_COMMAND: if (PtrIsValid(pDlg)) { CItemData* pid = pDlg->ItemData(pDlg->_curSel); // process contact menu command if (pid && CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(wParam), MPCF_CONTACTMENU), (LPARAM)pid->_hContact)) break; switch (LOWORD(wParam)) { // enable/disable reminder checkbox is clicked case CHECK_REMIND: if (pDlg->_bRemindEnable && HIWORD(wParam) == BN_CLICKED) { BYTE checkState = Button_GetCheck((HWND)lParam); EnableWindow(GetDlgItem(hDlg, EDIT_REMIND), checkState == BST_CHECKED); EnableWindow(GetDlgItem(hDlg, SPIN_REMIND), checkState == BST_CHECKED); if (pid && pid->_wReminderState != checkState) pid->_wReminderState = checkState; } break; // number of days to remind in advance is edited case EDIT_REMIND: if (pid && pDlg->_bRemindEnable && HIWORD(wParam) == EN_CHANGE) { WORD wDaysBefore = GetDlgItemInt(hDlg, LOWORD(wParam), NULL, FALSE); if (pid->_wReminderState == BST_CHECKED && pid->_wDaysBefore != wDaysBefore) { pid->_wDaysBefore = wDaysBefore; } } break; // the filter to display only contacts which have an anniversary in a certain // period of time is enabled/disabled case CHECK_DAYS: if (HIWORD(wParam) == BN_CLICKED) { BYTE isChecked = Button_GetCheck((HWND)lParam); EnableWindow(GetDlgItem(hDlg, EDIT_DAYS), isChecked); EnableWindow(GetDlgItem(hDlg, TXT_DAYS), isChecked); pDlg->_filter.wDaysBefore = isChecked ? GetDlgItemInt(hDlg, EDIT_DAYS, NULL, FALSE) : (WORD)-1; pDlg->RebuildList(); } break; // the number of days a contact must have an anniversary in advance to be displayed is edited case EDIT_DAYS: if (HIWORD(wParam) == EN_CHANGE) { WORD wNewDays = GetDlgItemInt(hDlg, LOWORD(wParam), NULL, FALSE); if (wNewDays != pDlg->_filter.wDaysBefore) { pDlg->_filter.wDaysBefore = wNewDays; pDlg->RebuildList(); } } break; // the filter selection of the filter combobox has changed case COMBO_VIEW: if (HIWORD(wParam) == CBN_SELCHANGE) { pDlg->_filter.bFilterIndex = ComboBox_GetCurSel((HWND)lParam); pDlg->RebuildList(); } } } break; case WM_DRAWITEM: return Menu_DrawItem((LPDRAWITEMSTRUCT)lParam); case WM_MEASUREITEM: return Menu_MeasureItem((LPMEASUREITEMSTRUCT)lParam); case WM_WINDOWPOSCHANGING: if (PtrIsValid(pDlg)) { WINDOWPOS *wndPos = (WINDOWPOS *)lParam; if (!pDlg->_wmINIT && (wndPos->cx != 0 || wndPos->cy != 0)) { //win pos change if ((wndPos->cx == pDlg->_rcWin.right - pDlg->_rcWin.left) && (wndPos->cy == pDlg->_rcWin.bottom - pDlg->_rcWin.top)) //win pos change (store new pos) GetWindowRect(hDlg, &pDlg->_rcWin); //win size change else { // l change if ((wndPos->cx < pDlg->_sizeMin.cx) && (wndPos->x > pDlg->_rcWin.left)) { wndPos->x = wndPos->x + wndPos->cx - pDlg->_sizeMin.cx; wndPos->cx = pDlg->_sizeMin.cx; } // r change else if (wndPos->cx < pDlg->_sizeMin.cx) wndPos->cx = pDlg->_sizeMin.cx; // t change if ((wndPos->cy < pDlg->_sizeMin.cy) && (wndPos->y > pDlg->_rcWin.top)) { wndPos->y = wndPos->y + wndPos->cy - pDlg->_sizeMin.cy; wndPos->cy = pDlg->_sizeMin.cy; } // b change else if (wndPos->cy < pDlg->_sizeMin.cy) wndPos->cy = pDlg->_sizeMin.cy; pDlg->_rcWin.left = wndPos->x; pDlg->_rcWin.right = wndPos->x + wndPos->cx; pDlg->_rcWin.top = wndPos->y; pDlg->_rcWin.bottom = wndPos->y + wndPos->cy; } } CAnchor anchor(wndPos, pDlg->_sizeMin); int anchorPos = CAnchor::ANCHOR_LEFT | CAnchor::ANCHOR_RIGHT | CAnchor::ANCHOR_TOP; anchor.MoveCtrl(IDC_HEADERBAR, anchorPos); anchor.MoveCtrl(GROUP_STATS, anchorPos); // birthday list anchor.MoveCtrl(EDIT_ANNIVERSARY_DATE, CAnchor::ANCHOR_ALL); anchorPos = CAnchor::ANCHOR_RIGHT | CAnchor::ANCHOR_BOTTOM; // filter group anchor.MoveCtrl(GROUP_FILTER, anchorPos); anchor.MoveCtrl(COMBO_VIEW, anchorPos); anchor.MoveCtrl(CHECK_DAYS, anchorPos); anchor.MoveCtrl(EDIT_DAYS, anchorPos); anchor.MoveCtrl(TXT_DAYS, anchorPos); // filter group anchor.MoveCtrl(GROUP_REMINDER, anchorPos); anchor.MoveCtrl(CHECK_REMIND, anchorPos); anchor.MoveCtrl(EDIT_REMIND, anchorPos); anchor.MoveCtrl(SPIN_REMIND, anchorPos); anchor.MoveCtrl(TXT_REMIND6, anchorPos); anchor.MoveCtrl(CHECK_POPUP, anchorPos); } break; // This message is sent if eighter the user clicked on the close button or // Miranda fires the ME_SYSTEM_SHUTDOWN event. case WM_CLOSE: DestroyWindow(hDlg); break; // If the anniversary list is destroyed somehow, the data class must be deleted, too. case WM_DESTROY: if (PtrIsValid(pDlg)) { SetUserData(hDlg, NULL); delete pDlg; } break; } return 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); SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(hInst, MAKEINTRESOURCE(IDI_CONTACTS))); SetAllContactChecks(GetDlgItem(hwndDlg, IDC_LIST), lParam); WindowList_Add(g_hSendWindowList, hwndDlg, lParam); wndData = new TSendContactsData(lParam); SetWindowLongPtr(hwndDlg, DWLP_USER, (LONG_PTR)wndData); // new dlg init wndData->hIcons[0] = InitMButton(hwndDlg, IDC_ADD, SKINICON_OTHER_ADDCONTACT, LPGENT("Add Contact Permanently to List")); wndData->hIcons[1] = InitMButton(hwndDlg, IDC_DETAILS, SKINICON_OTHER_USERDETAILS, LPGENT("View User's Details")); wndData->hIcons[2] = InitMButton(hwndDlg, IDC_HISTORY, SKINICON_OTHER_HISTORY, LPGENT("View User's History")); wndData->hIcons[3] = InitMButton(hwndDlg, IDC_USERMENU, SKINICON_OTHER_DOWNARROW, LPGENT("User Menu")); SendMessage(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); } } break; case WM_TIMER: if (wParam == TIMERID_MSGSEND) { 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; i < wndData->uacklist.Count; i++) delete g_aAckData.Remove(wndData->uacklist.Items[i]); // remove our ackdata & release structure mir_free(wndData->uacklist.Items); wndData->uacklist.Items = NULL; 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; i < wndData->uacklist.Count; i++) { TAckData *lla = g_aAckData.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; g_aAckData.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))) { MCONTACT hContact, hItem; wndData->ClearContacts(); // do not include contacts twice HWND hList = GetDlgItem(hwndDlg, IDC_LIST); hContact = FindFirstClistContact(hList, &hItem); while (hContact) { // build list of contacts to send if (SendMessage(hList, CLM_GETCHECKMARK, (WPARAM)hItem, 0)) wndData->AddContact(hContact); hContact = FindNextClistContact(hList, hContact, &hItem); } /* send contacts */ if (!wndData->SendContacts(hwndDlg)) break; SetTimer(hwndDlg, TIMERID_MSGSEND, db_get_dw(NULL, "SRMsg", "MessageTimeout", TIMEOUT_MSGSEND), NULL); } break; case IDCANCEL: DestroyWindow(hwndDlg); break; case ID_SELECTALL: { // select all contacts HWND hwndList = GetDlgItem(hwndDlg, IDC_LIST); MCONTACT hItem, hContact = FindFirstClistContact(hwndList, &hItem); while (hContact) { SendMessage(hwndList, CLM_SETCHECKMARK, (WPARAM)hItem, 1); hContact = FindNextClistContact(hwndList, hContact, &hItem); } } break; case IDC_USERMENU: { RECT rc; GetWindowRect(GetDlgItem(hwndDlg, IDC_USERMENU), &rc); HMENU hMenu = Menu_BuildContactMenu(wndData->hContact); 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; if (ack->type != ACKTYPE_CONTACTS) break; TAckData *ackData = g_aAckData.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; } DBEVENTINFO dbei = { sizeof(dbei) }; dbei.szModule = GetContactProto(ackData->hContact); dbei.eventType = EVENTTYPE_CONTACTS; dbei.flags = DBEF_SENT | DBEF_UTF; dbei.timestamp = time(NULL); //make blob TCTSend* maSend = (TCTSend*)_alloca(ackData->nContacts*sizeof(TCTSend)); memset(maSend, 0, (ackData->nContacts * sizeof(TCTSend))); dbei.cbBlob = 0; char* pBlob; int i; for (i = 0; i < ackData->nContacts; i++) { // prepare data & count size maSend[i].mcaNick = mir_utf8encodeT(pcli->pfnGetContactDisplayName(ackData->aContacts[i], 0)); maSend[i].mcaUIN = mir_utf8encodeT(ptrT(GetContactUID(ackData->aContacts[i]))); 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++) { strcpynull(pBlob, (char*)maSend[i].mcaNick); pBlob += strlennull(pBlob) + 1; strcpynull(pBlob, maSend[i].mcaUIN); pBlob += strlennull(pBlob) + 1; } db_event_add(ackData->hContact, &dbei); g_aAckData.Remove(ack->hProcess); // do not release here, still needed wndData->uacklist.Remove(ack->hProcess); // packet confirmed for (i = 0; i < ackData->nContacts; i++) { mir_free(maSend[i].mcaUIN); mir_free(maSend[i].mcaNick); } delete ackData; // all done, release structure if (!wndData->uacklist.Count) { SkinPlaySound("SentContacts"); KillTimer(hwndDlg, TIMERID_MSGSEND); if (wndData->hError) SendMessage(wndData->hError, DM_ERRORDECIDED, MSGERROR_DONE, 0); SendMessage(hwndDlg, WM_CLOSE, 0, 0); // all packets confirmed, close the dialog } } break; case WM_MEASUREITEM: return Menu_MeasureItem((LPMEASUREITEMSTRUCT)lParam); case WM_DRAWITEM: DrawProtocolIcon(hwndDlg, lParam, wndData->hContact); return Menu_DrawItem((LPDRAWITEMSTRUCT)lParam); case DM_UPDATETITLE: UpdateDialogTitle(hwndDlg, wndData ? wndData->hContact : NULL, TranslateT("Send Contacts to")); if (wndData) UpdateDialogAddButton(hwndDlg, wndData->hContact); break; case WM_CLOSE: wndData->UnhookProtoAck(); DestroyWindow(hwndDlg); break; case WM_DESTROY: WindowList_Remove(g_hSendWindowList, hwndDlg); delete wndData; break; } return FALSE; }
LRESULT CALLBACK fnContactListControlWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { ClcGroup *group; ClcContact *contact; DWORD hitFlags; int hit; ClcData *dat = (struct ClcData *) GetWindowLongPtr(hwnd, 0); if (msg >= CLM_FIRST && msg < CLM_LAST) return cli.pfnProcessExternalMessages(hwnd, dat, msg, wParam, lParam); switch (msg) { case WM_CREATE: WindowList_Add(hClcWindowList, hwnd, NULL); cli.pfnRegisterFileDropping(hwnd); if (dat == NULL) { dat = (struct ClcData *) mir_calloc(sizeof(struct ClcData)); SetWindowLongPtr(hwnd, 0, (LONG_PTR)dat); } { for (int i = 0; i <= FONTID_MAX; i++) dat->fontInfo[i].changed = 1; } dat->selection = -1; dat->iconXSpace = 20; dat->checkboxSize = 13; dat->dragAutoScrollHeight = 30; dat->iDragItem = -1; dat->iInsertionMark = -1; dat->insertionMarkHitHeight = 5; dat->iHotTrack = -1; dat->infoTipTimeout = db_get_w(NULL, "CLC", "InfoTipHoverTime", 750); dat->extraColumnSpacing = 20; dat->list.cl.increment = 30; dat->needsResort = 1; cli.pfnLoadClcOptions(hwnd, dat, TRUE); if (!IsWindowVisible(hwnd)) SetTimer(hwnd, TIMERID_REBUILDAFTER, 10, NULL); else { cli.pfnRebuildEntireList(hwnd, dat); NMCLISTCONTROL nm; nm.hdr.code = CLN_LISTREBUILT; nm.hdr.hwndFrom = hwnd; nm.hdr.idFrom = GetDlgCtrlID(hwnd); SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)& nm); } break; case INTM_SCROLLBARCHANGED: if (GetWindowLongPtr(hwnd, GWL_STYLE) & CLS_CONTACTLIST) { if (dat->noVScrollbar) ShowScrollBar(hwnd, SB_VERT, FALSE); else cli.pfnRecalcScrollBar(hwnd, dat); } break; case INTM_RELOADOPTIONS: cli.pfnLoadClcOptions(hwnd, dat, FALSE); cli.pfnSaveStateAndRebuildList(hwnd, dat); break; case WM_THEMECHANGED: cli.pfnInvalidateRect(hwnd, NULL, FALSE); break; case WM_SIZE: cli.pfnEndRename(hwnd, dat, 1); KillTimer(hwnd, TIMERID_INFOTIP); KillTimer(hwnd, TIMERID_RENAME); cli.pfnRecalcScrollBar(hwnd, dat); { // creating imagelist containing blue line for highlight RECT rc; GetClientRect(hwnd, &rc); if (rc.right == 0) break; rc.bottom = dat->rowHeight; HDC hdc = GetDC(hwnd); int depth = GetDeviceCaps(hdc, BITSPIXEL); if (depth < 16) depth = 16; HBITMAP hBmp = CreateBitmap(rc.right, rc.bottom, 1, depth, NULL); HBITMAP hBmpMask = CreateBitmap(rc.right, rc.bottom, 1, 1, NULL); HDC hdcMem = CreateCompatibleDC(hdc); HBITMAP hoBmp = (HBITMAP)SelectObject(hdcMem, hBmp); HBRUSH hBrush = CreateSolidBrush(dat->useWindowsColours ? GetSysColor(COLOR_HIGHLIGHT) : dat->selBkColour); FillRect(hdcMem, &rc, hBrush); DeleteObject(hBrush); HBITMAP hoMaskBmp = (HBITMAP)SelectObject(hdcMem, hBmpMask); FillRect(hdcMem, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH)); SelectObject(hdcMem, hoMaskBmp); SelectObject(hdcMem, hoBmp); DeleteDC(hdcMem); ReleaseDC(hwnd, hdc); if (dat->himlHighlight) ImageList_Destroy(dat->himlHighlight); dat->himlHighlight = ImageList_Create(rc.right, rc.bottom, ILC_COLOR32 | ILC_MASK, 1, 1); ImageList_Add(dat->himlHighlight, hBmp, hBmpMask); DeleteObject(hBmpMask); DeleteObject(hBmp); } break; case WM_SYSCOLORCHANGE: SendMessage(hwnd, WM_SIZE, 0, 0); break; case WM_GETDLGCODE: if (lParam) { MSG *msg = (MSG *)lParam; if (msg->message == WM_KEYDOWN) { if (msg->wParam == VK_TAB) return 0; if (msg->wParam == VK_ESCAPE && dat->hwndRenameEdit == NULL && dat->szQuickSearch[0] == 0) return 0; } if (msg->message == WM_CHAR) { if (msg->wParam == '\t') return 0; if (msg->wParam == 27 && dat->hwndRenameEdit == NULL && dat->szQuickSearch[0] == 0) return 0; } } return DLGC_WANTMESSAGE; case WM_KILLFOCUS: KillTimer(hwnd, TIMERID_INFOTIP); KillTimer(hwnd, TIMERID_RENAME); case WM_SETFOCUS: case WM_ENABLE: cli.pfnInvalidateRect(hwnd, NULL, FALSE); break; case WM_GETFONT: return (LRESULT)dat->fontInfo[FONTID_CONTACTS].hFont; case INTM_GROUPSCHANGED: { DBCONTACTWRITESETTING *dbcws = (DBCONTACTWRITESETTING *)lParam; if (dbcws->value.type == DBVT_ASCIIZ || dbcws->value.type == DBVT_UTF8) { int groupId = atoi(dbcws->szSetting) + 1; TCHAR szFullName[512]; int i, eq; //check name of group and ignore message if just being expanded/collapsed if (cli.pfnFindItem(hwnd, dat, groupId | HCONTACT_ISGROUP, &contact, &group, NULL)) { mir_tstrcpy(szFullName, contact->szText); while (group->parent) { for (i = 0; i < group->parent->cl.count; i++) if (group->parent->cl.items[i]->group == group) break; if (i == group->parent->cl.count) { szFullName[0] = '\0'; break; } group = group->parent; size_t nameLen = mir_tstrlen(group->cl.items[i]->szText); if (mir_tstrlen(szFullName) + 1 + nameLen > _countof(szFullName)) { szFullName[0] = '\0'; break; } memmove(szFullName + 1 + nameLen, szFullName, sizeof(TCHAR)*(mir_tstrlen(szFullName) + 1)); memcpy(szFullName, group->cl.items[i]->szText, sizeof(TCHAR)*nameLen); szFullName[nameLen] = '\\'; } if (dbcws->value.type == DBVT_ASCIIZ) { WCHAR* wszGrpName = mir_a2u(dbcws->value.pszVal + 1); eq = !mir_tstrcmp(szFullName, wszGrpName); mir_free(wszGrpName); } else { char* szGrpName = NEWSTR_ALLOCA(dbcws->value.pszVal + 1); WCHAR* wszGrpName; Utf8Decode(szGrpName, &wszGrpName); eq = !mir_tstrcmp(szFullName, wszGrpName); mir_free(wszGrpName); } if (eq && (contact->group->hideOffline != 0) == ((dbcws->value.pszVal[0] & GROUPF_HIDEOFFLINE) != 0)) break; //only expanded has changed: no action reqd } } cli.pfnSaveStateAndRebuildList(hwnd, dat); } break; case INTM_NAMEORDERCHANGED: cli.pfnInitAutoRebuild(hwnd); break; case INTM_CONTACTADDED: cli.pfnAddContactToTree(hwnd, dat, wParam, 1, 1); cli.pfnNotifyNewContact(hwnd, wParam); SortClcByTimer(hwnd); break; case INTM_CONTACTDELETED: cli.pfnDeleteItemFromTree(hwnd, wParam); SortClcByTimer(hwnd); break; case INTM_HIDDENCHANGED: { DBCONTACTWRITESETTING *dbcws = (DBCONTACTWRITESETTING *)lParam; if (GetWindowLongPtr(hwnd, GWL_STYLE) & CLS_SHOWHIDDEN) break; if (dbcws->value.type == DBVT_DELETED || dbcws->value.bVal == 0) { if (cli.pfnFindItem(hwnd, dat, wParam, NULL, NULL, NULL)) break; cli.pfnAddContactToTree(hwnd, dat, wParam, 1, 1); cli.pfnNotifyNewContact(hwnd, wParam); } else cli.pfnDeleteItemFromTree(hwnd, wParam); dat->needsResort = 1; SortClcByTimer(hwnd); } break; case INTM_GROUPCHANGED: { WORD iExtraImage[EXTRA_ICON_COUNT]; BYTE flags = 0; if (!cli.pfnFindItem(hwnd, dat, wParam, &contact, NULL, NULL)) memset(iExtraImage, 0xFF, sizeof(iExtraImage)); else { memcpy(iExtraImage, contact->iExtraImage, sizeof(iExtraImage)); flags = contact->flags; } cli.pfnDeleteItemFromTree(hwnd, wParam); if (GetWindowLongPtr(hwnd, GWL_STYLE) & CLS_SHOWHIDDEN || !db_get_b(wParam, "CList", "Hidden", 0)) { NMCLISTCONTROL nm; cli.pfnAddContactToTree(hwnd, dat, wParam, 1, 1); if (cli.pfnFindItem(hwnd, dat, wParam, &contact, NULL, NULL)) { memcpy(contact->iExtraImage, iExtraImage, sizeof(iExtraImage)); if (flags & CONTACTF_CHECKED) contact->flags |= CONTACTF_CHECKED; } nm.hdr.code = CLN_CONTACTMOVED; nm.hdr.hwndFrom = hwnd; nm.hdr.idFrom = GetDlgCtrlID(hwnd); nm.flags = 0; nm.hItem = (HANDLE)wParam; SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)& nm); dat->needsResort = 1; } } SetTimer(hwnd, TIMERID_REBUILDAFTER, 1, NULL); break; case INTM_ICONCHANGED: { int recalcScrollBar = 0, shouldShow; WORD status; MCONTACT hSelItem = NULL; ClcContact *selcontact = NULL; char *szProto = GetContactProto(wParam); if (szProto == NULL) status = ID_STATUS_OFFLINE; else status = db_get_w(wParam, szProto, "Status", ID_STATUS_OFFLINE); // this means an offline msg is flashing, so the contact should be shown DWORD style = GetWindowLongPtr(hwnd, GWL_STYLE); shouldShow = (style & CLS_SHOWHIDDEN || !db_get_b(wParam, "CList", "Hidden", 0)) && (!cli.pfnIsHiddenMode(dat, status) || CallService(MS_CLIST_GETCONTACTICON, wParam, 0) != lParam); contact = NULL; group = NULL; if (!cli.pfnFindItem(hwnd, dat, wParam, &contact, &group, NULL)) { if (shouldShow && CallService(MS_DB_CONTACT_IS, wParam, 0)) { if (dat->selection >= 0 && cli.pfnGetRowByIndex(dat, dat->selection, &selcontact, NULL) != -1) hSelItem = (MCONTACT)cli.pfnContactToHItem(selcontact); cli.pfnAddContactToTree(hwnd, dat, wParam, (style & CLS_CONTACTLIST) == 0, 0); recalcScrollBar = 1; cli.pfnFindItem(hwnd, dat, wParam, &contact, NULL, NULL); if (contact) { contact->iImage = (WORD)lParam; cli.pfnNotifyNewContact(hwnd, wParam); dat->needsResort = 1; } } } else { // item in list already if (contact->iImage == (WORD)lParam) break; if (!shouldShow && !(style & CLS_NOHIDEOFFLINE) && (style & CLS_HIDEOFFLINE || group->hideOffline)) { if (dat->selection >= 0 && cli.pfnGetRowByIndex(dat, dat->selection, &selcontact, NULL) != -1) hSelItem = (MCONTACT)cli.pfnContactToHItem(selcontact); cli.pfnRemoveItemFromGroup(hwnd, group, contact, (style & CLS_CONTACTLIST) == 0); recalcScrollBar = 1; } else { contact->iImage = (WORD)lParam; if (!cli.pfnIsHiddenMode(dat, status)) contact->flags |= CONTACTF_ONLINE; else contact->flags &= ~CONTACTF_ONLINE; } dat->needsResort = 1; } if (hSelItem) { ClcGroup *selgroup; if (cli.pfnFindItem(hwnd, dat, hSelItem, &selcontact, &selgroup, NULL)) dat->selection = cli.pfnGetRowsPriorTo(&dat->list, selgroup, List_IndexOf((SortedList*)&selgroup->cl, selcontact)); else dat->selection = -1; } SortClcByTimer(hwnd); } break; case INTM_NAMECHANGED: if (!cli.pfnFindItem(hwnd, dat, wParam, &contact, NULL, NULL)) break; mir_tstrncpy(contact->szText, cli.pfnGetContactDisplayName(wParam, 0), _countof(contact->szText)); dat->needsResort = 1; SortClcByTimer(hwnd); break; case INTM_PROTOCHANGED: if (!cli.pfnFindItem(hwnd, dat, wParam, &contact, NULL, NULL)) break; contact->proto = GetContactProto(wParam); cli.pfnInvalidateDisplayNameCacheEntry(wParam); mir_tstrncpy(contact->szText, cli.pfnGetContactDisplayName(wParam, 0), _countof(contact->szText)); SortClcByTimer(hwnd); break; case INTM_NOTONLISTCHANGED: if (!cli.pfnFindItem(hwnd, dat, wParam, &contact, NULL, NULL)) break; if (contact->type == CLCIT_CONTACT) { DBCONTACTWRITESETTING *dbcws = (DBCONTACTWRITESETTING *)lParam; if (dbcws->value.type == DBVT_DELETED || dbcws->value.bVal == 0) contact->flags &= ~CONTACTF_NOTONLIST; else contact->flags |= CONTACTF_NOTONLIST; cli.pfnInvalidateRect(hwnd, NULL, FALSE); } break; case INTM_INVALIDATE: cli.pfnInvalidateRect(hwnd, NULL, FALSE); break; case INTM_APPARENTMODECHANGED: if (cli.pfnFindItem(hwnd, dat, wParam, &contact, NULL, NULL)) { char *szProto = GetContactProto(wParam); if (szProto == NULL) break; WORD apparentMode = db_get_w(wParam, szProto, "ApparentMode", 0); contact->flags &= ~(CONTACTF_INVISTO | CONTACTF_VISTO); if (apparentMode == ID_STATUS_OFFLINE) contact->flags |= CONTACTF_INVISTO; else if (apparentMode == ID_STATUS_ONLINE) contact->flags |= CONTACTF_VISTO; else if (apparentMode) contact->flags |= CONTACTF_VISTO | CONTACTF_INVISTO; cli.pfnInvalidateRect(hwnd, NULL, FALSE); } break; case INTM_SETINFOTIPHOVERTIME: dat->infoTipTimeout = wParam; break; case INTM_IDLECHANGED: if (cli.pfnFindItem(hwnd, dat, wParam, &contact, NULL, NULL)) { char *szProto = GetContactProto(wParam); if (szProto == NULL) break; contact->flags &= ~CONTACTF_IDLE; if (db_get_dw(wParam, szProto, "IdleTS", 0)) contact->flags |= CONTACTF_IDLE; cli.pfnInvalidateRect(hwnd, NULL, FALSE); } break; case WM_PRINTCLIENT: cli.pfnPaintClc(hwnd, dat, (HDC)wParam, NULL); break; case WM_NCPAINT: if (wParam != 1) { POINT ptTopLeft = { 0, 0 }; HRGN hClientRgn; ClientToScreen(hwnd, &ptTopLeft); hClientRgn = CreateRectRgn(0, 0, 1, 1); CombineRgn(hClientRgn, (HRGN)wParam, NULL, RGN_COPY); OffsetRgn(hClientRgn, -ptTopLeft.x, -ptTopLeft.y); InvalidateRgn(hwnd, hClientRgn, FALSE); DeleteObject(hClientRgn); UpdateWindow(hwnd); } break; case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hwnd, &ps); /* we get so many cli.pfnInvalidateRect()'s that there is no point painting, Windows in theory shouldn't queue up WM_PAINTs in this case but it does so we'll just ignore them */ if (IsWindowVisible(hwnd)) cli.pfnPaintClc(hwnd, dat, hdc, &ps.rcPaint); EndPaint(hwnd, &ps); } break; case WM_VSCROLL: cli.pfnEndRename(hwnd, dat, 1); cli.pfnHideInfoTip(hwnd, dat); KillTimer(hwnd, TIMERID_INFOTIP); KillTimer(hwnd, TIMERID_RENAME); { int desty = dat->yScroll, noSmooth = 0; RECT clRect; GetClientRect(hwnd, &clRect); switch (LOWORD(wParam)) { case SB_LINEUP: desty -= dat->rowHeight; break; case SB_LINEDOWN: desty += dat->rowHeight; break; case SB_PAGEUP: desty -= clRect.bottom - dat->rowHeight; break; case SB_PAGEDOWN: desty += clRect.bottom - dat->rowHeight; break; case SB_BOTTOM: desty = 0x7FFFFFFF; break; case SB_TOP: desty = 0; break; case SB_THUMBTRACK: desty = HIWORD(wParam); noSmooth = 1; break; //noone has more than 4000 contacts, right? default: return 0; } cli.pfnScrollTo(hwnd, dat, desty, noSmooth); } break; case WM_MOUSEWHEEL: cli.pfnEndRename(hwnd, dat, 1); cli.pfnHideInfoTip(hwnd, dat); KillTimer(hwnd, TIMERID_INFOTIP); KillTimer(hwnd, TIMERID_RENAME); { UINT scrollLines; if (!SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &scrollLines, FALSE)) scrollLines = 3; cli.pfnScrollTo(hwnd, dat, dat->yScroll - (short)HIWORD(wParam) * dat->rowHeight * (signed)scrollLines / WHEEL_DELTA, 0); } return 0; case WM_KEYDOWN: { int selMoved = 0; int changeGroupExpand = 0; int pageSize; cli.pfnHideInfoTip(hwnd, dat); KillTimer(hwnd, TIMERID_INFOTIP); KillTimer(hwnd, TIMERID_RENAME); if (CallService(MS_CLIST_MENUPROCESSHOTKEY, wParam, MPCF_CONTACTMENU)) break; { RECT clRect; GetClientRect(hwnd, &clRect); pageSize = clRect.bottom / dat->rowHeight; } switch (wParam) { case VK_DOWN: dat->selection++; selMoved = 1; break; case VK_UP: dat->selection--; selMoved = 1; break; case VK_PRIOR: dat->selection -= pageSize; selMoved = 1; break; case VK_NEXT: dat->selection += pageSize; selMoved = 1; break; case VK_HOME: dat->selection = 0; selMoved = 1; break; case VK_END: dat->selection = cli.pfnGetGroupContentsCount(&dat->list, 1) - 1; selMoved = 1; break; case VK_LEFT: changeGroupExpand = 1; break; case VK_RIGHT: changeGroupExpand = 2; break; case VK_RETURN: cli.pfnDoSelectionDefaultAction(hwnd, dat); dat->szQuickSearch[0] = 0; if (dat->filterSearch) cli.pfnSaveStateAndRebuildList(hwnd, dat); return 0; case VK_F2: cli.pfnBeginRenameSelection(hwnd, dat); return 0; case VK_DELETE: cli.pfnDeleteFromContactList(hwnd, dat); return 0; default: { NMKEY nmkey; nmkey.hdr.hwndFrom = hwnd; nmkey.hdr.idFrom = GetDlgCtrlID(hwnd); nmkey.hdr.code = NM_KEYDOWN; nmkey.nVKey = wParam; nmkey.uFlags = HIWORD(lParam); if (SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)& nmkey)) return 0; } } if (changeGroupExpand) { if (!dat->filterSearch) dat->szQuickSearch[0] = 0; hit = cli.pfnGetRowByIndex(dat, dat->selection, &contact, &group); if (hit != -1) { if (changeGroupExpand == 1 && contact->type == CLCIT_CONTACT) { if (group == &dat->list) return 0; dat->selection = cli.pfnGetRowsPriorTo(&dat->list, group, -1); selMoved = 1; } else { if (contact->type == CLCIT_GROUP) cli.pfnSetGroupExpand(hwnd, dat, contact->group, changeGroupExpand == 2); return 0; } } else return 0; } if (selMoved) { if (!dat->filterSearch) dat->szQuickSearch[0] = 0; if (dat->selection >= cli.pfnGetGroupContentsCount(&dat->list, 1)) dat->selection = cli.pfnGetGroupContentsCount(&dat->list, 1) - 1; if (dat->selection < 0) dat->selection = 0; cli.pfnInvalidateRect(hwnd, NULL, FALSE); cli.pfnEnsureVisible(hwnd, dat, dat->selection, 0); UpdateWindow(hwnd); return 0; } } break; case WM_CHAR: cli.pfnHideInfoTip(hwnd, dat); KillTimer(hwnd, TIMERID_INFOTIP); KillTimer(hwnd, TIMERID_RENAME); if (wParam == 27) //escape dat->szQuickSearch[0] = 0; else if (wParam == '\b' && dat->szQuickSearch[0]) dat->szQuickSearch[mir_tstrlen(dat->szQuickSearch) - 1] = '\0'; else if (wParam < ' ') break; else if (wParam == ' ' && dat->szQuickSearch[0] == '\0' && GetWindowLongPtr(hwnd, GWL_STYLE) & CLS_CHECKBOXES) { NMCLISTCONTROL nm; if (cli.pfnGetRowByIndex(dat, dat->selection, &contact, NULL) == -1) break; if (contact->type != CLCIT_CONTACT) break; contact->flags ^= CONTACTF_CHECKED; if (contact->type == CLCIT_GROUP) cli.pfnSetGroupChildCheckboxes(contact->group, contact->flags & CONTACTF_CHECKED); cli.pfnRecalculateGroupCheckboxes(hwnd, dat); cli.pfnInvalidateRect(hwnd, NULL, FALSE); nm.hdr.code = CLN_CHECKCHANGED; nm.hdr.hwndFrom = hwnd; nm.hdr.idFrom = GetDlgCtrlID(hwnd); nm.flags = 0; nm.hItem = cli.pfnContactToItemHandle(contact, &nm.flags); SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)& nm); } else { TCHAR szNew[2]; szNew[0] = (TCHAR)wParam; szNew[1] = '\0'; if (mir_tstrlen(dat->szQuickSearch) >= _countof(dat->szQuickSearch) - 1) { MessageBeep(MB_OK); break; } mir_tstrcat(dat->szQuickSearch, szNew); } if (dat->filterSearch) cli.pfnSaveStateAndRebuildList(hwnd, dat); if (dat->szQuickSearch[0]) { int index; index = cli.pfnFindRowByText(hwnd, dat, dat->szQuickSearch, 1); if (index != -1) dat->selection = index; else { MessageBeep(MB_OK); dat->szQuickSearch[mir_tstrlen(dat->szQuickSearch) - 1] = '\0'; cli.pfnSaveStateAndRebuildList(hwnd, dat); } cli.pfnInvalidateRect(hwnd, NULL, FALSE); cli.pfnEnsureVisible(hwnd, dat, dat->selection, 0); } else cli.pfnInvalidateRect(hwnd, NULL, FALSE); break; case WM_SYSKEYDOWN: cli.pfnEndRename(hwnd, dat, 1); cli.pfnHideInfoTip(hwnd, dat); KillTimer(hwnd, TIMERID_INFOTIP); KillTimer(hwnd, TIMERID_RENAME); dat->iHotTrack = -1; cli.pfnInvalidateRect(hwnd, NULL, FALSE); ReleaseCapture(); if (wParam == VK_F10 && GetKeyState(VK_SHIFT) & 0x8000) break; SendMessage(GetParent(hwnd), msg, wParam, lParam); return 0; case WM_TIMER: switch (wParam) { case TIMERID_RENAME: cli.pfnBeginRenameSelection(hwnd, dat); break; case TIMERID_DRAGAUTOSCROLL: cli.pfnScrollTo(hwnd, dat, dat->yScroll + dat->dragAutoScrolling * dat->rowHeight * 2, 0); break; case TIMERID_INFOTIP: { CLCINFOTIP it; RECT clRect; POINT ptClientOffset = { 0 }; KillTimer(hwnd, wParam); GetCursorPos(&it.ptCursor); ScreenToClient(hwnd, &it.ptCursor); if (it.ptCursor.x != dat->ptInfoTip.x || it.ptCursor.y != dat->ptInfoTip.y) break; GetClientRect(hwnd, &clRect); it.rcItem.left = 0; it.rcItem.right = clRect.right; hit = cli.pfnHitTest(hwnd, dat, it.ptCursor.x, it.ptCursor.y, &contact, NULL, NULL); if (hit == -1) break; if (contact->type != CLCIT_GROUP && contact->type != CLCIT_CONTACT) break; ClientToScreen(hwnd, &it.ptCursor); ClientToScreen(hwnd, &ptClientOffset); it.isTreeFocused = GetFocus() == hwnd; it.rcItem.top = cli.pfnGetRowTopY(dat, hit) - dat->yScroll; it.rcItem.bottom = it.rcItem.top + cli.pfnGetRowHeight(dat, hit); OffsetRect(&it.rcItem, ptClientOffset.x, ptClientOffset.y); it.isGroup = contact->type == CLCIT_GROUP; it.hItem = (contact->type == CLCIT_GROUP) ? (HANDLE)contact->groupId : (HANDLE)contact->hContact; it.cbSize = sizeof(it); dat->hInfoTipItem = cli.pfnContactToHItem(contact); NotifyEventHooks(hShowInfoTipEvent, 0, (LPARAM)& it); break; } case TIMERID_REBUILDAFTER: KillTimer(hwnd, TIMERID_REBUILDAFTER); cli.pfnInvalidateRect(hwnd, NULL, FALSE); cli.pfnSaveStateAndRebuildList(hwnd, dat); break; case TIMERID_DELAYEDRESORTCLC: KillTimer(hwnd, TIMERID_DELAYEDRESORTCLC); cli.pfnInvalidateRect(hwnd, NULL, FALSE); cli.pfnSortCLC(hwnd, dat, 1); cli.pfnRecalcScrollBar(hwnd, dat); break; } break; case WM_MBUTTONDOWN: case WM_LBUTTONDOWN: if (GetFocus() != hwnd) SetFocus(hwnd); cli.pfnHideInfoTip(hwnd, dat); KillTimer(hwnd, TIMERID_INFOTIP); KillTimer(hwnd, TIMERID_RENAME); cli.pfnEndRename(hwnd, dat, 1); dat->ptDragStart.x = (short)LOWORD(lParam); dat->ptDragStart.y = (short)HIWORD(lParam); if (!dat->filterSearch) dat->szQuickSearch[0] = 0; hit = cli.pfnHitTest(hwnd, dat, (short)LOWORD(lParam), (short)HIWORD(lParam), &contact, &group, &hitFlags); if (hit != -1) { if (hit == dat->selection && hitFlags & CLCHT_ONITEMLABEL && dat->exStyle & CLS_EX_EDITLABELS) { SetCapture(hwnd); dat->iDragItem = dat->selection; dat->dragStage = DRAGSTAGE_NOTMOVED | DRAGSTAGEF_MAYBERENAME; dat->dragAutoScrolling = 0; break; } } if (hit != -1 && contact->type == CLCIT_GROUP) { if (hitFlags & CLCHT_ONITEMICON) { ClcGroup *selgroup; ClcContact *selcontact; dat->selection = cli.pfnGetRowByIndex(dat, dat->selection, &selcontact, &selgroup); cli.pfnSetGroupExpand(hwnd, dat, contact->group, -1); if (dat->selection != -1) { dat->selection = cli.pfnGetRowsPriorTo(&dat->list, selgroup, List_IndexOf((SortedList*)&selgroup->cl, selcontact)); if (dat->selection == -1) dat->selection = cli.pfnGetRowsPriorTo(&dat->list, contact->group, -1); } cli.pfnInvalidateRect(hwnd, NULL, FALSE); UpdateWindow(hwnd); break; } } if (hit != -1 && hitFlags & CLCHT_ONITEMCHECK) { NMCLISTCONTROL nm; contact->flags ^= CONTACTF_CHECKED; if (contact->type == CLCIT_GROUP) cli.pfnSetGroupChildCheckboxes(contact->group, contact->flags & CONTACTF_CHECKED); cli.pfnRecalculateGroupCheckboxes(hwnd, dat); cli.pfnInvalidateRect(hwnd, NULL, FALSE); nm.hdr.code = CLN_CHECKCHANGED; nm.hdr.hwndFrom = hwnd; nm.hdr.idFrom = GetDlgCtrlID(hwnd); nm.flags = 0; nm.hItem = cli.pfnContactToItemHandle(contact, &nm.flags); SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)&nm); } if (!(hitFlags & (CLCHT_ONITEMICON | CLCHT_ONITEMLABEL | CLCHT_ONITEMCHECK))) { NMCLISTCONTROL nm; nm.hdr.code = NM_CLICK; nm.hdr.hwndFrom = hwnd; nm.hdr.idFrom = GetDlgCtrlID(hwnd); nm.flags = 0; if (hit == -1) nm.hItem = NULL; else nm.hItem = cli.pfnContactToItemHandle(contact, &nm.flags); nm.iColumn = hitFlags & CLCHT_ONITEMEXTRA ? HIBYTE(HIWORD(hitFlags)) : -1; nm.pt = dat->ptDragStart; SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)& nm); } if (hitFlags & (CLCHT_ONITEMCHECK | CLCHT_ONITEMEXTRA)) break; dat->selection = hit; cli.pfnInvalidateRect(hwnd, NULL, FALSE); if (dat->selection != -1) cli.pfnEnsureVisible(hwnd, dat, hit, 0); UpdateWindow(hwnd); if (dat->selection != -1 && (contact->type == CLCIT_CONTACT || contact->type == CLCIT_GROUP) && !(hitFlags & (CLCHT_ONITEMEXTRA | CLCHT_ONITEMCHECK))) { SetCapture(hwnd); dat->iDragItem = dat->selection; dat->dragStage = DRAGSTAGE_NOTMOVED; dat->dragAutoScrolling = 0; } break; case WM_MOUSEMOVE: if (dat->iDragItem == -1) { int iOldHotTrack = dat->iHotTrack; if (dat->hwndRenameEdit != NULL) break; if (GetKeyState(VK_MENU) & 0x8000 || GetKeyState(VK_F10) & 0x8000) break; dat->iHotTrack = cli.pfnHitTest(hwnd, dat, (short)LOWORD(lParam), (short)HIWORD(lParam), NULL, NULL, NULL); if (iOldHotTrack != dat->iHotTrack) { if (iOldHotTrack == -1) SetCapture(hwnd); else if (dat->iHotTrack == -1) ReleaseCapture(); if (dat->exStyle & CLS_EX_TRACKSELECT) { cli.pfnInvalidateItem(hwnd, dat, iOldHotTrack); cli.pfnInvalidateItem(hwnd, dat, dat->iHotTrack); } cli.pfnHideInfoTip(hwnd, dat); } KillTimer(hwnd, TIMERID_INFOTIP); if (wParam == 0 && dat->hInfoTipItem == NULL) { dat->ptInfoTip.x = (short)LOWORD(lParam); dat->ptInfoTip.y = (short)HIWORD(lParam); SetTimer(hwnd, TIMERID_INFOTIP, dat->infoTipTimeout, NULL); } break; } if ((dat->dragStage & DRAGSTAGEM_STAGE) == DRAGSTAGE_NOTMOVED && !(dat->exStyle & CLS_EX_DISABLEDRAGDROP)) { if (abs((short)LOWORD(lParam) - dat->ptDragStart.x) >= GetSystemMetrics(SM_CXDRAG) || abs((short)HIWORD(lParam) - dat->ptDragStart.y) >= GetSystemMetrics(SM_CYDRAG)) dat->dragStage = (dat->dragStage & ~DRAGSTAGEM_STAGE) | DRAGSTAGE_ACTIVE; } if ((dat->dragStage & DRAGSTAGEM_STAGE) == DRAGSTAGE_ACTIVE) { HCURSOR hNewCursor; RECT clRect; POINT pt; int target; GetClientRect(hwnd, &clRect); pt.x = (short)LOWORD(lParam); pt.y = (short)HIWORD(lParam); hNewCursor = LoadCursor(NULL, IDC_NO); cli.pfnInvalidateRect(hwnd, NULL, FALSE); if (dat->dragAutoScrolling) { KillTimer(hwnd, TIMERID_DRAGAUTOSCROLL); dat->dragAutoScrolling = 0; } target = cli.pfnGetDropTargetInformation(hwnd, dat, pt); if (dat->dragStage & DRAGSTAGEF_OUTSIDE && target != DROPTARGET_OUTSIDE) { cli.pfnGetRowByIndex(dat, dat->iDragItem, &contact, NULL); NMCLISTCONTROL nm; nm.hdr.code = CLN_DRAGSTOP; nm.hdr.hwndFrom = hwnd; nm.hdr.idFrom = GetDlgCtrlID(hwnd); nm.flags = 0; nm.hItem = cli.pfnContactToItemHandle(contact, &nm.flags); SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)& nm); dat->dragStage &= ~DRAGSTAGEF_OUTSIDE; } switch (target) { case DROPTARGET_ONSELF: case DROPTARGET_ONCONTACT: break; case DROPTARGET_ONGROUP: hNewCursor = LoadCursor(cli.hInst, MAKEINTRESOURCE(IDC_DROPUSER)); break; case DROPTARGET_INSERTION: hNewCursor = LoadCursor(cli.hInst, MAKEINTRESOURCE(IDC_DROPUSER)); break; case DROPTARGET_OUTSIDE: { NMCLISTCONTROL nm; if (pt.x >= 0 && pt.x < clRect.right && ((pt.y < 0 && pt.y > -dat->dragAutoScrollHeight) || (pt.y >= clRect.bottom && pt.y < clRect.bottom + dat->dragAutoScrollHeight))) { if (!dat->dragAutoScrolling) { if (pt.y < 0) dat->dragAutoScrolling = -1; else dat->dragAutoScrolling = 1; SetTimer(hwnd, TIMERID_DRAGAUTOSCROLL, dat->scrollTime, NULL); } SendMessage(hwnd, WM_TIMER, TIMERID_DRAGAUTOSCROLL, 0); } dat->dragStage |= DRAGSTAGEF_OUTSIDE; cli.pfnGetRowByIndex(dat, dat->iDragItem, &contact, NULL); nm.hdr.code = CLN_DRAGGING; nm.hdr.hwndFrom = hwnd; nm.hdr.idFrom = GetDlgCtrlID(hwnd); nm.flags = 0; nm.hItem = cli.pfnContactToItemHandle(contact, &nm.flags); nm.pt = pt; if (SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)& nm)) return 0; } break; default: cli.pfnGetRowByIndex(dat, dat->iDragItem, NULL, &group); if (group->parent) hNewCursor = LoadCursor(cli.hInst, MAKEINTRESOURCE(IDC_DROPUSER)); break; } SetCursor(hNewCursor); } break; case WM_LBUTTONUP: if (dat->iDragItem == -1) break; SetCursor((HCURSOR)GetClassLongPtr(hwnd, GCLP_HCURSOR)); if (dat->exStyle & CLS_EX_TRACKSELECT) { dat->iHotTrack = cli.pfnHitTest(hwnd, dat, (short)LOWORD(lParam), (short)HIWORD(lParam), NULL, NULL, NULL); if (dat->iHotTrack == -1) ReleaseCapture(); } else ReleaseCapture(); KillTimer(hwnd, TIMERID_DRAGAUTOSCROLL); if (dat->dragStage == (DRAGSTAGE_NOTMOVED | DRAGSTAGEF_MAYBERENAME)) SetTimer(hwnd, TIMERID_RENAME, GetDoubleClickTime(), NULL); else if ((dat->dragStage & DRAGSTAGEM_STAGE) == DRAGSTAGE_ACTIVE) { POINT pt = { LOWORD(lParam), HIWORD(lParam) }; int target = cli.pfnGetDropTargetInformation(hwnd, dat, pt); switch (target) { case DROPTARGET_ONSELF: case DROPTARGET_ONCONTACT: break; case DROPTARGET_ONGROUP: { ClcContact *contactn, *contacto; cli.pfnGetRowByIndex(dat, dat->selection, &contactn, NULL); cli.pfnGetRowByIndex(dat, dat->iDragItem, &contacto, NULL); if (contacto->type == CLCIT_CONTACT) //dropee is a contact CallService(MS_CLIST_CONTACTCHANGEGROUP, (WPARAM)contacto->hContact, contactn->groupId); else if (contacto->type == CLCIT_GROUP) { //dropee is a group TCHAR szNewName[120]; mir_sntprintf(szNewName, _countof(szNewName), _T("%s\\%s"), cli.pfnGetGroupName(contactn->groupId, NULL), contacto->szText); cli.pfnRenameGroup(contacto->groupId, szNewName); } } break; case DROPTARGET_INSERTION: cli.pfnGetRowByIndex(dat, dat->iDragItem, &contact, NULL); { ClcContact *destcontact; ClcGroup *destgroup; if (cli.pfnGetRowByIndex(dat, dat->iInsertionMark, &destcontact, &destgroup) == -1 || destgroup != contact->group->parent) CallService(MS_CLIST_GROUPMOVEBEFORE, contact->groupId, 0); else { if (destcontact->type == CLCIT_GROUP) destgroup = destcontact->group; CallService(MS_CLIST_GROUPMOVEBEFORE, contact->groupId, destgroup->groupId); } } break; case DROPTARGET_OUTSIDE: cli.pfnGetRowByIndex(dat, dat->iDragItem, &contact, NULL); { NMCLISTCONTROL nm; nm.hdr.code = CLN_DROPPED; nm.hdr.hwndFrom = hwnd; nm.hdr.idFrom = GetDlgCtrlID(hwnd); nm.flags = 0; nm.hItem = cli.pfnContactToItemHandle(contact, &nm.flags); nm.pt = pt; SendMessage(GetParent(hwnd), WM_NOTIFY, 0, (LPARAM)& nm); } break; default: cli.pfnGetRowByIndex(dat, dat->iDragItem, &contact, &group); if (!group->parent) break; if (contact->type == CLCIT_GROUP) { //dropee is a group TCHAR szNewName[120]; mir_tstrncpy(szNewName, contact->szText, _countof(szNewName)); cli.pfnRenameGroup(contact->groupId, szNewName); } else if (contact->type == CLCIT_CONTACT) //dropee is a contact CallService(MS_CLIST_CONTACTCHANGEGROUP, (WPARAM)contact->hContact, 0); } } cli.pfnInvalidateRect(hwnd, NULL, FALSE); dat->iDragItem = -1; dat->iInsertionMark = -1; break; case WM_LBUTTONDBLCLK: ReleaseCapture(); dat->iHotTrack = -1; cli.pfnHideInfoTip(hwnd, dat); KillTimer(hwnd, TIMERID_RENAME); KillTimer(hwnd, TIMERID_INFOTIP); dat->selection = cli.pfnHitTest(hwnd, dat, (short)LOWORD(lParam), (short)HIWORD(lParam), &contact, NULL, &hitFlags); cli.pfnInvalidateRect(hwnd, NULL, FALSE); if (dat->selection != -1) cli.pfnEnsureVisible(hwnd, dat, dat->selection, 0); if (!(hitFlags & (CLCHT_ONITEMICON | CLCHT_ONITEMLABEL))) break; UpdateWindow(hwnd); cli.pfnDoSelectionDefaultAction(hwnd, dat); dat->szQuickSearch[0] = 0; if (dat->filterSearch) cli.pfnSaveStateAndRebuildList(hwnd, dat); break; case WM_CONTEXTMENU: cli.pfnEndRename(hwnd, dat, 1); cli.pfnHideInfoTip(hwnd, dat); KillTimer(hwnd, TIMERID_RENAME); KillTimer(hwnd, TIMERID_INFOTIP); if (GetFocus() != hwnd) SetFocus(hwnd); dat->iHotTrack = -1; if (!dat->filterSearch) dat->szQuickSearch[0] = 0; { POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; if (pt.x == -1 && pt.y == -1) { dat->selection = cli.pfnGetRowByIndex(dat, dat->selection, &contact, NULL); if (dat->selection != -1) cli.pfnEnsureVisible(hwnd, dat, dat->selection, 0); pt.x = dat->iconXSpace + 15; pt.y = cli.pfnGetRowTopY(dat, dat->selection) - dat->yScroll + (int)(cli.pfnGetRowHeight(dat, dat->selection) * .7); hitFlags = (dat->selection == -1) ? CLCHT_NOWHERE : CLCHT_ONITEMLABEL; } else { ScreenToClient(hwnd, &pt); dat->selection = cli.pfnHitTest(hwnd, dat, pt.x, pt.y, &contact, NULL, &hitFlags); } cli.pfnInvalidateRect(hwnd, NULL, FALSE); if (dat->selection != -1) cli.pfnEnsureVisible(hwnd, dat, dat->selection, 0); UpdateWindow(hwnd); if (dat->selection != -1 && hitFlags & (CLCHT_ONITEMICON | CLCHT_ONITEMCHECK | CLCHT_ONITEMLABEL)) { HMENU hMenu; if (contact->type == CLCIT_GROUP) hMenu = cli.pfnBuildGroupPopupMenu(contact->group); else if (contact->type == CLCIT_CONTACT) hMenu = Menu_BuildContactMenu(contact->hContact); else return 0; ClientToScreen(hwnd, &pt); TrackPopupMenu(hMenu, TPM_TOPALIGN | TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, 0, hwnd, NULL); DestroyMenu(hMenu); } else //call parent for new group/hide offline menu SendMessage(GetParent(hwnd), WM_CONTEXTMENU, wParam, lParam); } return 0; case WM_MEASUREITEM: return Menu_MeasureItem((LPMEASUREITEMSTRUCT)lParam); case WM_DRAWITEM: return Menu_DrawItem((LPDRAWITEMSTRUCT)lParam); case WM_COMMAND: hit = cli.pfnGetRowByIndex(dat, dat->selection, &contact, NULL); if (hit == -1) break; if (contact->type == CLCIT_CONTACT) if (CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(wParam), MPCF_CONTACTMENU), (LPARAM)contact->hContact)) break; switch (LOWORD(wParam)) { case POPUP_NEWSUBGROUP: if (contact->type != CLCIT_GROUP) break; SetWindowLongPtr(hwnd, GWL_STYLE, GetWindowLongPtr(hwnd, GWL_STYLE) & ~CLS_HIDEEMPTYGROUPS); CallService(MS_CLIST_GROUPCREATE, contact->groupId, 0); break; case POPUP_RENAMEGROUP: cli.pfnBeginRenameSelection(hwnd, dat); break; case POPUP_DELETEGROUP: if (contact->type != CLCIT_GROUP) break; CallService(MS_CLIST_GROUPDELETE, contact->groupId, 0); break; case POPUP_GROUPHIDEOFFLINE: if (contact->type != CLCIT_GROUP) break; CallService(MS_CLIST_GROUPSETFLAGS, contact->groupId, MAKELPARAM(contact->group->hideOffline ? 0 : GROUPF_HIDEOFFLINE, GROUPF_HIDEOFFLINE)); break; } break; case WM_DESTROY: cli.pfnHideInfoTip(hwnd, dat); for (int i = 0; i <= FONTID_MAX; i++) if (!dat->fontInfo[i].changed) DeleteObject(dat->fontInfo[i].hFont); if (dat->himlHighlight) ImageList_Destroy(dat->himlHighlight); if (dat->hwndRenameEdit) DestroyWindow(dat->hwndRenameEdit); if (dat->hBmpBackground) DeleteObject(dat->hBmpBackground); cli.pfnFreeGroup(&dat->list); mir_free(dat); cli.pfnUnregisterFileDropping(hwnd); WindowList_Remove(hClcWindowList, hwnd); } return DefWindowProc(hwnd, msg, wParam, lParam); }
INT_PTR CALLBACK DlgProcRecvFile(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) { FileDlgData *dat = (FileDlgData*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); switch (msg) { case WM_INITDIALOG: TranslateDialogDefault(hwndDlg); { TCHAR szPath[450]; CLISTEVENT* cle = (CLISTEVENT*)lParam; dat = (FileDlgData*)mir_calloc(sizeof(FileDlgData)); SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)dat); dat->hContact = cle->hContact; dat->hDbEvent = cle->hDbEvent; dat->hNotifyEvent = HookEventMessage(ME_PROTO_ACK, hwndDlg, HM_RECVEVENT); dat->hPreshutdownEvent = HookEventMessage(ME_SYSTEM_PRESHUTDOWN, hwndDlg, M_PRESHUTDOWN); dat->dwTicks = GetTickCount(); EnumChildWindows(hwndDlg, ClipSiblingsChildEnumProc, 0); Window_SetSkinIcon_IcoLib(hwndDlg, SKINICON_EVENT_FILE); Button_SetIcon_IcoLib(hwndDlg, IDC_ADD, SKINICON_OTHER_ADDCONTACT, LPGEN("Add contact permanently to list")); Button_SetIcon_IcoLib(hwndDlg, IDC_DETAILS, SKINICON_OTHER_USERDETAILS, LPGEN("View user's details")); Button_SetIcon_IcoLib(hwndDlg, IDC_HISTORY, SKINICON_OTHER_HISTORY, LPGEN("View user's history")); Button_SetIcon_IcoLib(hwndDlg, IDC_USERMENU, SKINICON_OTHER_DOWNARROW, LPGEN("User menu")); TCHAR *contactName = pcli->pfnGetContactDisplayName(dat->hContact, 0); SetDlgItemText(hwndDlg, IDC_FROM, contactName); GetContactReceivedFilesDir(dat->hContact, szPath, _countof(szPath), TRUE); SetDlgItemText(hwndDlg, IDC_FILEDIR, szPath); SHAutoComplete(GetWindow(GetDlgItem(hwndDlg, IDC_FILEDIR), GW_CHILD), 1); for (int i = 0; i < MAX_MRU_DIRS; i++) { char idstr[32]; mir_snprintf(idstr, "MruDir%d", i); DBVARIANT dbv; if (db_get_ts(NULL, "SRFile", idstr, &dbv)) break; SendDlgItemMessage(hwndDlg, IDC_FILEDIR, CB_ADDSTRING, 0, (LPARAM)dbv.ptszVal); db_free(&dbv); } db_event_markRead(dat->hContact, dat->hDbEvent); DBEVENTINFO dbei = { sizeof(dbei) }; dbei.cbBlob = db_event_getBlobSize(dat->hDbEvent); if (dbei.cbBlob > 4 && dbei.cbBlob <= 8196) { dbei.pBlob = (PBYTE)alloca(dbei.cbBlob + 1); db_event_get(dat->hDbEvent, &dbei); dbei.pBlob[dbei.cbBlob] = 0; dat->fs = cle->lParam ? (HANDLE)cle->lParam : (HANDLE)*(PDWORD)dbei.pBlob; char *str = (char*)dbei.pBlob + 4; ptrT ptszFileName(DbGetEventStringT(&dbei, str)); SetDlgItemText(hwndDlg, IDC_FILENAMES, ptszFileName); unsigned len = (unsigned)mir_strlen(str) + 1; if (len + 4 < dbei.cbBlob) { str += len; ptrT ptszDescription(DbGetEventStringT(&dbei, str)); SetDlgItemText(hwndDlg, IDC_MSG, ptszDescription); } } else DestroyWindow(hwndDlg); TCHAR datetimestr[64]; TimeZone_PrintTimeStamp(NULL, dbei.timestamp, _T("t d"), datetimestr, _countof(datetimestr), 0); SetDlgItemText(hwndDlg, IDC_DATE, datetimestr); ptrT info(Contact_GetInfo(CNF_UNIQUEID, dat->hContact)); SetDlgItemText(hwndDlg, IDC_NAME, (info) ? info : contactName); if (db_get_b(dat->hContact, "CList", "NotOnList", 0)) { RECT rcBtn1, rcBtn2, rcDateCtrl; GetWindowRect(GetDlgItem(hwndDlg, IDC_ADD), &rcBtn1); GetWindowRect(GetDlgItem(hwndDlg, IDC_USERMENU), &rcBtn2); GetWindowRect(GetDlgItem(hwndDlg, IDC_DATE), &rcDateCtrl); SetWindowPos(GetDlgItem(hwndDlg, IDC_DATE), 0, 0, 0, rcDateCtrl.right - rcDateCtrl.left - (rcBtn2.left - rcBtn1.left), rcDateCtrl.bottom - rcDateCtrl.top, SWP_NOZORDER | SWP_NOMOVE); } else if (db_get_b(NULL, "SRFile", "AutoAccept", 0)) { //don't check auto-min here to fix BUG#647620 PostMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDOK, BN_CLICKED), (LPARAM)GetDlgItem(hwndDlg, IDOK)); } if (!db_get_b(dat->hContact, "CList", "NotOnList", 0)) ShowWindow(GetDlgItem(hwndDlg, IDC_ADD), SW_HIDE); } return TRUE; case WM_MEASUREITEM: return Menu_MeasureItem((LPMEASUREITEMSTRUCT)lParam); case WM_DRAWITEM: { LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT)lParam; if (dis->hwndItem == GetDlgItem(hwndDlg, IDC_PROTOCOL)) { char *szProto = GetContactProto(dat->hContact); if (szProto) { HICON hIcon = (HICON)CallProtoService(szProto, PS_LOADICON, PLI_PROTOCOL|PLIF_SMALL, 0); if (hIcon) { DrawIconEx(dis->hDC, dis->rcItem.left, dis->rcItem.top, hIcon, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0, NULL, DI_NORMAL); DestroyIcon(hIcon); } } } } return Menu_DrawItem((LPDRAWITEMSTRUCT)lParam); case WM_COMMAND: if (CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(wParam), MPCF_CONTACTMENU), (LPARAM)dat->hContact)) break; switch (LOWORD(wParam)) { case IDC_FILEDIRBROWSE: { TCHAR szDirName[MAX_PATH], szExistingDirName[MAX_PATH]; GetDlgItemText(hwndDlg, IDC_FILEDIR, szDirName, _countof(szDirName)); GetLowestExistingDirName(szDirName, szExistingDirName, _countof(szExistingDirName)); if (BrowseForFolder(hwndDlg, szExistingDirName)) SetDlgItemText(hwndDlg, IDC_FILEDIR, szExistingDirName); } break; case IDOK: { //most recently used directories TCHAR szRecvDir[MAX_PATH], szDefaultRecvDir[MAX_PATH]; GetDlgItemText(hwndDlg, IDC_FILEDIR, szRecvDir, _countof(szRecvDir)); RemoveInvalidPathChars(szRecvDir); GetContactReceivedFilesDir(NULL, szDefaultRecvDir, _countof(szDefaultRecvDir), TRUE); if (_tcsnicmp(szRecvDir, szDefaultRecvDir, mir_tstrlen(szDefaultRecvDir))) { char idstr[32]; int i; DBVARIANT dbv; for (i = MAX_MRU_DIRS-2;i>=0;i--) { mir_snprintf(idstr, "MruDir%d", i); if (db_get_ts(NULL, "SRFile", idstr, &dbv)) continue; mir_snprintf(idstr, "MruDir%d", i+1); db_set_ts(NULL, "SRFile", idstr, dbv.ptszVal); db_free(&dbv); } db_set_ts(NULL, "SRFile", idstr, szRecvDir); } } EnableWindow(GetDlgItem(hwndDlg, IDC_FILENAMES), FALSE); EnableWindow(GetDlgItem(hwndDlg, IDC_MSG), FALSE); EnableWindow(GetDlgItem(hwndDlg, IDC_FILEDIR), FALSE); EnableWindow(GetDlgItem(hwndDlg, IDC_FILEDIRBROWSE), FALSE); GetDlgItemText(hwndDlg, IDC_FILEDIR, dat->szSavePath, _countof(dat->szSavePath)); GetDlgItemText(hwndDlg, IDC_FILE, dat->szFilenames, _countof(dat->szFilenames)); GetDlgItemText(hwndDlg, IDC_MSG, dat->szMsg, _countof(dat->szMsg)); dat->hwndTransfer = FtMgr_AddTransfer(dat); SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0); //check for auto-minimize here to fix BUG#647620 if (db_get_b(NULL, "SRFile", "AutoAccept", 0) && db_get_b(NULL, "SRFile", "AutoMin", 0)) { ShowWindow(hwndDlg, SW_HIDE); ShowWindow(hwndDlg, SW_SHOWMINNOACTIVE); } DestroyWindow(hwndDlg); break; case IDCANCEL: if (dat->fs) CallContactService(dat->hContact, PSS_FILEDENY, (WPARAM)dat->fs, (LPARAM)TranslateT("Canceled")); dat->fs = NULL; /* the protocol will free the handle */ DestroyWindow(hwndDlg); break; case IDC_ADD: { ADDCONTACTSTRUCT acs = { 0 }; acs.hContact = dat->hContact; acs.handleType = HANDLE_CONTACT; acs.szProto = ""; CallService(MS_ADDCONTACT_SHOW, (WPARAM)hwndDlg, (LPARAM)&acs); if (!db_get_b(dat->hContact, "CList", "NotOnList", 0)) ShowWindow(GetDlgItem(hwndDlg, IDC_ADD), SW_HIDE); } break; case IDC_USERMENU: { RECT rc; GetWindowRect((HWND)lParam, &rc); HMENU hMenu = Menu_BuildContactMenu(dat->hContact); TrackPopupMenu(hMenu, 0, rc.left, rc.bottom, 0, hwndDlg, NULL); DestroyMenu(hMenu); } break; case IDC_DETAILS: CallService(MS_USERINFO_SHOWDIALOG, (WPARAM)dat->hContact, 0); break; case IDC_HISTORY: CallService(MS_HISTORY_SHOWCONTACTHISTORY, (WPARAM)dat->hContact, 0); break; } break; case HM_RECVEVENT: { ACKDATA *ack = (ACKDATA*)lParam; if ((ack == NULL) || (ack->hProcess != dat->fs) || (ack->type != ACKTYPE_FILE) || (ack->hContact != dat->hContact)) break; if (ack->result == ACKRESULT_DENIED || ack->result == ACKRESULT_FAILED) { EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE); EnableWindow(GetDlgItem(hwndDlg, IDC_FILEDIR), FALSE); EnableWindow(GetDlgItem(hwndDlg, IDC_FILEDIRBROWSE), FALSE); SetDlgItemText(hwndDlg, IDC_MSG, TranslateT("This file transfer has been canceled by the other side")); SkinPlaySound("FileDenied"); FlashWindow(hwndDlg, TRUE); } else if (ack->result != ACKRESULT_FILERESUME) { SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDCANCEL, 0), (LPARAM)GetDlgItem(hwndDlg, IDCANCEL)); } } break; case WM_DESTROY: Window_FreeIcon_IcoLib(hwndDlg); Button_FreeIcon_IcoLib(hwndDlg, IDC_ADD); Button_FreeIcon_IcoLib(hwndDlg, IDC_DETAILS); Button_FreeIcon_IcoLib(hwndDlg, IDC_HISTORY); Button_FreeIcon_IcoLib(hwndDlg, IDC_USERMENU); FreeFileDlgData(dat); SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0); break; } return FALSE; }
INT_PTR CALLBACK DlgProcFileTransfer(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) { FileDlgData *dat = (FileDlgData*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); switch (msg) { case WM_INITDIALOG: TranslateDialogDefault(hwndDlg); dat = (FileDlgData*)lParam; SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)dat); dat->hNotifyEvent = HookEventMessage(ME_PROTO_ACK, hwndDlg, HM_RECVEVENT); dat->transferStatus.currentFileNumber = -1; if (dat->send) { if (db_mc_isMeta(dat->hContact)) dat->hContact = db_mc_getMostOnline(dat->hContact); dat->fs = (HANDLE)CallContactService(dat->hContact, PSS_FILE, (WPARAM)dat->szMsg, (LPARAM)dat->files); SetFtStatus(hwndDlg, LPGENT("Request sent, waiting for acceptance..."), FTS_TEXT); SetOpenFileButtonStyle(GetDlgItem(hwndDlg, IDC_OPENFILE), 1); dat->waitingForAcceptance = 1; // hide "open" button since it may cause potential access violations... ShowWindow(GetDlgItem(hwndDlg, IDC_OPENFILE), SW_HIDE); ShowWindow(GetDlgItem(hwndDlg, IDC_OPENFOLDER), SW_HIDE); } else { //recv CreateDirectoryTreeT(dat->szSavePath); dat->fs = (HANDLE)CallContactService(dat->hContact, PSS_FILEALLOW, (WPARAM)dat->fs, (LPARAM)dat->szSavePath); dat->transferStatus.tszWorkingDir = mir_tstrdup(dat->szSavePath); if (db_get_b(dat->hContact, "CList", "NotOnList", 0)) dat->resumeBehaviour = FILERESUME_ASK; else dat->resumeBehaviour = db_get_b(NULL, "SRFile", "IfExists", FILERESUME_ASK); SetFtStatus(hwndDlg, LPGENT("Waiting for connection..."), FTS_TEXT); } /* check we actually got an fs handle back from the protocol */ if (!dat->fs) { SetFtStatus(hwndDlg, LPGENT("Unable to initiate transfer."), FTS_TEXT); dat->waitingForAcceptance = 0; } { LOGFONT lf; HFONT hFont = (HFONT)SendDlgItemMessage(hwndDlg, IDC_CONTACTNAME, WM_GETFONT, 0, 0); GetObject(hFont, sizeof(lf), &lf); lf.lfWeight = FW_BOLD; hFont = CreateFontIndirect(&lf); SendDlgItemMessage(hwndDlg, IDC_CONTACTNAME, WM_SETFONT, (WPARAM)hFont, 0); SHFILEINFO shfi = { 0 }; SHGetFileInfo(_T(""), FILE_ATTRIBUTE_DIRECTORY, &shfi, sizeof(shfi), SHGFI_USEFILEATTRIBUTES | SHGFI_ICON | SHGFI_SMALLICON); dat->hIconFolder = shfi.hIcon; } dat->hIcon = NULL; { char *szProto = GetContactProto(dat->hContact); WORD status = db_get_w(dat->hContact, szProto, "Status", ID_STATUS_ONLINE); SendDlgItemMessage(hwndDlg, IDC_CONTACT, BM_SETIMAGE, IMAGE_ICON, (LPARAM)Skin_LoadProtoIcon(szProto, status)); } SendDlgItemMessage(hwndDlg, IDC_CONTACT, BUTTONADDTOOLTIP, (WPARAM)LPGEN("Contact menu"), 0); SendDlgItemMessage(hwndDlg, IDC_CONTACT, BUTTONSETASFLATBTN, TRUE, 0); Button_SetIcon_IcoLib(hwndDlg, IDC_OPENFILE, SKINICON_OTHER_DOWNARROW, LPGEN("Open...")); SendDlgItemMessage(hwndDlg, IDC_OPENFILE, BUTTONSETASPUSHBTN, TRUE, 0); SendDlgItemMessage(hwndDlg, IDC_OPENFOLDER, BM_SETIMAGE, IMAGE_ICON, (LPARAM)dat->hIconFolder); SendDlgItemMessage(hwndDlg, IDC_OPENFOLDER, BUTTONADDTOOLTIP, (WPARAM)LPGEN("Open folder"), 0); SendDlgItemMessage(hwndDlg, IDC_OPENFOLDER, BUTTONSETASFLATBTN, TRUE, 0); Button_SetIcon_IcoLib(hwndDlg, IDCANCEL, SKINICON_OTHER_DELETE, LPGEN("Cancel")); SetDlgItemText(hwndDlg, IDC_CONTACTNAME, pcli->pfnGetContactDisplayName(dat->hContact, 0)); if (!dat->waitingForAcceptance) SetTimer(hwndDlg, 1, 1000, NULL); return TRUE; case WM_TIMER: memmove(dat->bytesRecvedHistory + 1, dat->bytesRecvedHistory, sizeof(dat->bytesRecvedHistory) - sizeof(dat->bytesRecvedHistory[0])); dat->bytesRecvedHistory[0] = dat->transferStatus.totalProgress; if (dat->bytesRecvedHistorySize < _countof(dat->bytesRecvedHistory)) dat->bytesRecvedHistorySize++; { TCHAR szSpeed[32], szTime[32], szDisplay[96]; SYSTEMTIME st; ULARGE_INTEGER li; FILETIME ft; GetSensiblyFormattedSize((dat->bytesRecvedHistory[0] - dat->bytesRecvedHistory[dat->bytesRecvedHistorySize - 1]) / dat->bytesRecvedHistorySize, szSpeed, _countof(szSpeed), 0, 1, NULL); if (dat->bytesRecvedHistory[0] == dat->bytesRecvedHistory[dat->bytesRecvedHistorySize - 1]) mir_tstrcpy(szTime, _T("??:??:??")); else { li.QuadPart = BIGI(10000000)*(dat->transferStatus.currentFileSize - dat->transferStatus.currentFileProgress)*dat->bytesRecvedHistorySize / (dat->bytesRecvedHistory[0] - dat->bytesRecvedHistory[dat->bytesRecvedHistorySize - 1]); ft.dwHighDateTime = li.HighPart; ft.dwLowDateTime = li.LowPart; FileTimeToSystemTime(&ft, &st); GetTimeFormat(LOCALE_USER_DEFAULT, TIME_FORCE24HOURFORMAT | TIME_NOTIMEMARKER, &st, NULL, szTime, _countof(szTime)); } if (dat->bytesRecvedHistory[0] != dat->bytesRecvedHistory[dat->bytesRecvedHistorySize - 1]) { li.QuadPart = BIGI(10000000)*(dat->transferStatus.totalBytes - dat->transferStatus.totalProgress)*dat->bytesRecvedHistorySize / (dat->bytesRecvedHistory[0] - dat->bytesRecvedHistory[dat->bytesRecvedHistorySize - 1]); ft.dwHighDateTime = li.HighPart; ft.dwLowDateTime = li.LowPart; FileTimeToSystemTime(&ft, &st); GetTimeFormat(LOCALE_USER_DEFAULT, TIME_FORCE24HOURFORMAT | TIME_NOTIMEMARKER, &st, NULL, szTime, _countof(szTime)); } mir_sntprintf(szDisplay, _T("%s/%s (%s %s)"), szSpeed, TranslateT("sec"), szTime, TranslateT("remaining")); SetDlgItemText(hwndDlg, IDC_ALLSPEED, szDisplay); } break; case WM_MEASUREITEM: return Menu_MeasureItem((LPMEASUREITEMSTRUCT)lParam); case WM_DRAWITEM: return Menu_DrawItem((LPDRAWITEMSTRUCT)lParam); case WM_FT_CLEANUP: if (!dat->fs) { PostMessage(GetParent(hwndDlg), WM_FT_REMOVE, 0, (LPARAM)hwndDlg); DestroyWindow(hwndDlg); } break; case WM_COMMAND: if (!dat) break; if (CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(wParam), MPCF_CONTACTMENU), (LPARAM)dat->hContact)) break; switch (LOWORD(wParam)) { case IDOK: case IDCANCEL: PostMessage(GetParent(hwndDlg), WM_FT_REMOVE, 0, (LPARAM)hwndDlg); DestroyWindow(hwndDlg); break; case IDC_CONTACT: { RECT rc; HMENU hMenu = Menu_BuildContactMenu(dat->hContact); GetWindowRect((HWND)lParam, &rc); TrackPopupMenu(hMenu, 0, rc.left, rc.bottom, 0, hwndDlg, NULL); DestroyMenu(hMenu); } break; case IDC_TRANSFERCOMPLETED: if (dat->transferStatus.currentFileNumber <= 1 && CheckVirusScanned(hwndDlg, dat, 0)) { ShellExecute(NULL, NULL, dat->files[0], NULL, NULL, SW_SHOW); break; } case IDC_OPENFOLDER: { TCHAR *path = dat->transferStatus.tszWorkingDir; if (!path || !path[0]) { path = NEWTSTR_ALLOCA(dat->transferStatus.tszCurrentFile); TCHAR *p = _tcsrchr(path, '\\'); if (p) *p = 0; } if (path) ShellExecute(NULL, _T("open"), path, NULL, NULL, SW_SHOW); } break; case IDC_OPENFILE: TCHAR **files; if (dat->send) { if (dat->files == NULL) files = dat->transferStatus.ptszFiles; else files = dat->files; } else files = dat->files; HMENU hMenu = CreatePopupMenu(); AppendMenu(hMenu, MF_STRING, 1, TranslateT("Open folder")); AppendMenu(hMenu, MF_SEPARATOR, 0, 0); if (files && *files) { int limit; TCHAR *pszFilename, *pszNewFileName; if (dat->send) limit = dat->transferStatus.totalFiles; else limit = dat->transferStatus.currentFileNumber; // Loop over all transfered files and add them to the menu for (int i = 0; i < limit; i++) { pszFilename = _tcsrchr(files[i], '\\'); if (pszFilename == NULL) pszFilename = files[i]; else pszFilename++; if (pszFilename) { size_t cbFileNameLen = mir_tstrlen(pszFilename); pszNewFileName = (TCHAR*)mir_alloc(cbFileNameLen * 2 * sizeof(TCHAR)); TCHAR *p = pszNewFileName; for (size_t pszlen = 0; pszlen < cbFileNameLen; pszlen++) { *p++ = pszFilename[pszlen]; if (pszFilename[pszlen] == '&') *p++ = '&'; } *p = '\0'; AppendMenu(hMenu, MF_STRING, i + 10, pszNewFileName); mir_free(pszNewFileName); } } } RECT rc; GetWindowRect((HWND)lParam, &rc); CheckDlgButton(hwndDlg, IDC_OPENFILE, BST_CHECKED); int ret = TrackPopupMenu(hMenu, TPM_RETURNCMD | TPM_RIGHTALIGN, rc.right, rc.bottom, 0, hwndDlg, NULL); CheckDlgButton(hwndDlg, IDC_OPENFILE, BST_UNCHECKED); DestroyMenu(hMenu); if (ret == 1) { TCHAR *path = dat->transferStatus.tszWorkingDir; if (!path || !path[0]) { path = NEWTSTR_ALLOCA(dat->transferStatus.tszCurrentFile); TCHAR *p = _tcsrchr(path, '\\'); if (p) *p = 0; } if (path) ShellExecute(NULL, _T("open"), path, NULL, NULL, SW_SHOW); } else if (ret && CheckVirusScanned(hwndDlg, dat, ret)) ShellExecute(NULL, NULL, files[ret - 10], NULL, NULL, SW_SHOW); } break; case M_FILEEXISTSDLGREPLY: EnableWindow(hwndDlg, TRUE); { PROTOFILERESUME *pfr = (PROTOFILERESUME*)lParam; TCHAR *szOriginalFilename = (TCHAR*)wParam; char *szProto = GetContactProto(dat->hContact); switch (pfr->action) { case FILERESUME_CANCEL: if (dat->fs) CallContactService(dat->hContact, PSS_FILECANCEL, (WPARAM)dat->fs, 0); dat->fs = NULL; mir_free(szOriginalFilename); if (pfr->szFilename) mir_free((char*)pfr->szFilename); mir_free(pfr); return 0; case FILERESUME_RESUMEALL: case FILERESUME_OVERWRITEALL: dat->resumeBehaviour = pfr->action; pfr->action &= ~FILERESUMEF_ALL; break; case FILERESUME_RENAMEALL: pfr->action = FILERESUME_RENAME; { TCHAR *pszExtension, *pszFilename; if ((pszFilename = _tcsrchr(szOriginalFilename, '\\')) == NULL) pszFilename = szOriginalFilename; if ((pszExtension = _tcsrchr(pszFilename + 1, '.')) == NULL) pszExtension = pszFilename + mir_tstrlen(pszFilename); if (pfr->szFilename) mir_free((TCHAR*)pfr->szFilename); size_t size = (pszExtension - szOriginalFilename) + 21 + mir_tstrlen(pszExtension); pfr->szFilename = (TCHAR*)mir_alloc(sizeof(TCHAR)*size); for (int i = 1;; i++) { mir_sntprintf((TCHAR*)pfr->szFilename, size, _T("%.*s (%u)%s"), pszExtension - szOriginalFilename, szOriginalFilename, i, pszExtension); if (_taccess(pfr->szFilename, 0) != 0) break; } } break; } mir_free(szOriginalFilename); CallProtoService(szProto, PS_FILERESUME, (WPARAM)dat->fs, (LPARAM)pfr); if (pfr->szFilename) mir_free((char*)pfr->szFilename); mir_free(pfr); } break; case HM_RECVEVENT: { ACKDATA *ack = (ACKDATA*)lParam; if (ack->hProcess != dat->fs) break; if (ack->type != ACKTYPE_FILE) break; if (ack->hContact != dat->hContact) break; if (dat->waitingForAcceptance) { SetTimer(hwndDlg, 1, 1000, NULL); dat->waitingForAcceptance = 0; } switch (ack->result) { case ACKRESULT_SENTREQUEST: SetFtStatus(hwndDlg, LPGENT("Decision sent"), FTS_TEXT); break; case ACKRESULT_CONNECTING: SetFtStatus(hwndDlg, LPGENT("Connecting..."), FTS_TEXT); break; case ACKRESULT_CONNECTPROXY: SetFtStatus(hwndDlg, LPGENT("Connecting to proxy..."), FTS_TEXT); break; case ACKRESULT_CONNECTED: SetFtStatus(hwndDlg, LPGENT("Connected"), FTS_TEXT); break; case ACKRESULT_LISTENING: SetFtStatus(hwndDlg, LPGENT("Waiting for connection..."), FTS_TEXT); break; case ACKRESULT_INITIALISING: SetFtStatus(hwndDlg, LPGENT("Initializing..."), FTS_TEXT); break; case ACKRESULT_NEXTFILE: SetFtStatus(hwndDlg, LPGENT("Moving to next file..."), FTS_TEXT); SetDlgItemTextA(hwndDlg, IDC_FILENAME, ""); if (dat->transferStatus.currentFileNumber == 1 && dat->transferStatus.totalFiles > 1 && !dat->send) SetOpenFileButtonStyle(GetDlgItem(hwndDlg, IDC_OPENFILE), 1); if (dat->transferStatus.currentFileNumber != -1 && dat->files && !dat->send && db_get_b(NULL, "SRFile", "UseScanner", VIRUSSCAN_DISABLE) == VIRUSSCAN_DURINGDL) { if (GetFileAttributes(dat->files[dat->transferStatus.currentFileNumber])&FILE_ATTRIBUTE_DIRECTORY) PostMessage(hwndDlg, M_VIRUSSCANDONE, dat->transferStatus.currentFileNumber, 0); else { virusscanthreadstartinfo *vstsi; vstsi = (struct virusscanthreadstartinfo*)mir_alloc(sizeof(struct virusscanthreadstartinfo)); vstsi->hwndReply = hwndDlg; vstsi->szFile = mir_tstrdup(dat->files[dat->transferStatus.currentFileNumber]); vstsi->returnCode = dat->transferStatus.currentFileNumber; forkthread((void(*)(void*))RunVirusScannerThread, 0, vstsi); } } break; case ACKRESULT_FILERESUME: UpdateProtoFileTransferStatus(&dat->transferStatus, (PROTOFILETRANSFERSTATUS*)ack->lParam); { PROTOFILETRANSFERSTATUS *fts = &dat->transferStatus; SetFilenameControls(hwndDlg, dat, fts); if (_taccess(fts->tszCurrentFile, 0)) break; SetFtStatus(hwndDlg, LPGENT("File already exists"), FTS_TEXT); if (dat->resumeBehaviour == FILERESUME_ASK) { TDlgProcFileExistsParam param = { hwndDlg, fts }; ShowWindow(hwndDlg, SW_SHOWNORMAL); CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_FILEEXISTS), hwndDlg, DlgProcFileExists, (LPARAM)¶m); EnableWindow(hwndDlg, FALSE); } else { PROTOFILERESUME *pfr = (PROTOFILERESUME*)mir_alloc(sizeof(PROTOFILERESUME)); pfr->action = dat->resumeBehaviour; pfr->szFilename = NULL; PostMessage(hwndDlg, M_FILEEXISTSDLGREPLY, (WPARAM)mir_tstrdup(fts->tszCurrentFile), (LPARAM)pfr); } } SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, 1); return TRUE; case ACKRESULT_DATA: { PROTOFILETRANSFERSTATUS *fts = (PROTOFILETRANSFERSTATUS*)ack->lParam; TCHAR str[64], str2[64], szSizeDone[32], szSizeTotal[32];//, *contactName; if (dat->fileVirusScanned == NULL) dat->fileVirusScanned = (int*)mir_calloc(sizeof(int) * fts->totalFiles); // This needs to be here - otherwise we get holes in the files array if (!dat->send) { if (dat->files == NULL) dat->files = (TCHAR**)mir_calloc((fts->totalFiles + 1) * sizeof(TCHAR*)); if (fts->currentFileNumber < fts->totalFiles && dat->files[fts->currentFileNumber] == NULL) dat->files[fts->currentFileNumber] = PFTS_StringToTchar(fts->flags, fts->tszCurrentFile); } /* HACK: for 0.3.3, limit updates to around 1.1 ack per second */ if (fts->totalProgress != fts->totalBytes && GetTickCount() < (dat->dwTicks + 650)) break; // the last update was less than a second ago! dat->dwTicks = GetTickCount(); // Update local transfer status with data from protocol UpdateProtoFileTransferStatus(&dat->transferStatus, fts); fts = &dat->transferStatus; bool firstTime = false; if ((GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_ALLFILESPROGRESS), GWL_STYLE) & WS_VISIBLE) == 0) { SetFtStatus(hwndDlg, (fts->flags & PFTS_SENDING) ? LPGENT("Sending...") : LPGENT("Receiving..."), FTS_PROGRESS); SetFilenameControls(hwndDlg, dat, fts); firstTime = true; } const unsigned long lastPos = SendDlgItemMessage(hwndDlg, IDC_ALLFILESPROGRESS, PBM_GETPOS, 0, 0); const unsigned long nextPos = fts->totalBytes ? (BIGI(100) * fts->totalProgress / fts->totalBytes) : 0; if (lastPos != nextPos || firstTime) { SendDlgItemMessage(hwndDlg, IDC_ALLFILESPROGRESS, PBM_SETPOS, nextPos, 0); mir_sntprintf(str, _T("%u%%"), nextPos); SetDlgItemText(hwndDlg, IDC_ALLPRECENTS, str); } int units; GetSensiblyFormattedSize(fts->totalBytes, szSizeTotal, _countof(szSizeTotal), 0, 1, &units); GetSensiblyFormattedSize(fts->totalProgress, szSizeDone, _countof(szSizeDone), units, 0, NULL); mir_sntprintf(str, _T("%s/%s"), szSizeDone, szSizeTotal); str2[0] = 0; GetDlgItemText(hwndDlg, IDC_ALLTRANSFERRED, str2, _countof(str2)); if (mir_tstrcmp(str, str2)) SetDlgItemText(hwndDlg, IDC_ALLTRANSFERRED, str); } break; case ACKRESULT_SUCCESS: case ACKRESULT_FAILED: case ACKRESULT_DENIED: HideProgressControls(hwndDlg); KillTimer(hwndDlg, 1); if (!dat->send) SetOpenFileButtonStyle(GetDlgItem(hwndDlg, IDC_OPENFILE), 1); SetDlgItemText(hwndDlg, IDCANCEL, TranslateT("Close")); if (dat->hNotifyEvent) UnhookEvent(dat->hNotifyEvent); dat->hNotifyEvent = NULL; if (ack->result == ACKRESULT_DENIED) { dat->fs = NULL; /* protocol will free structure */ SkinPlaySound("FileDenied"); SetFtStatus(hwndDlg, LPGENT("File transfer denied"), FTS_TEXT); } else if (ack->result == ACKRESULT_FAILED) { dat->fs = NULL; /* protocol will free structure */ SkinPlaySound("FileFailed"); SetFtStatus(hwndDlg, LPGENT("File transfer failed"), FTS_TEXT); } else { SkinPlaySound("FileDone"); if (dat->send) { dat->fs = NULL; /* protocol will free structure */ SetFtStatus(hwndDlg, LPGENT("Transfer completed."), FTS_TEXT); DBEVENTINFO dbei = { 0 }; FillSendData(dat, dbei); db_event_add(dat->hContact, &dbei); if (dbei.pBlob) mir_free(dbei.pBlob); dat->files = NULL; //protocol library frees this } else { SetFtStatus(hwndDlg, (dat->transferStatus.totalFiles == 1) ? LPGENT("Transfer completed, open file.") : LPGENT("Transfer completed, open folder."), FTS_OPEN); int useScanner = db_get_b(NULL, "SRFile", "UseScanner", VIRUSSCAN_DISABLE); if (useScanner != VIRUSSCAN_DISABLE) { struct virusscanthreadstartinfo *vstsi; vstsi = (struct virusscanthreadstartinfo*)mir_alloc(sizeof(struct virusscanthreadstartinfo)); vstsi->hwndReply = hwndDlg; if (useScanner == VIRUSSCAN_DURINGDL) { vstsi->returnCode = dat->transferStatus.currentFileNumber; if (GetFileAttributes(dat->files[dat->transferStatus.currentFileNumber])&FILE_ATTRIBUTE_DIRECTORY) { PostMessage(hwndDlg, M_VIRUSSCANDONE, vstsi->returnCode, 0); mir_free(vstsi); vstsi = NULL; } else vstsi->szFile = mir_tstrdup(dat->files[dat->transferStatus.currentFileNumber]); } else { vstsi->szFile = mir_tstrdup(dat->transferStatus.tszWorkingDir); vstsi->returnCode = -1; } SetFtStatus(hwndDlg, LPGENT("Scanning for viruses..."), FTS_TEXT); if (vstsi) forkthread((void(*)(void*))RunVirusScannerThread, 0, vstsi); } else dat->fs = NULL; /* protocol will free structure */ dat->transferStatus.currentFileNumber = dat->transferStatus.totalFiles; } // else dat->send } // else ack->result PostMessage(GetParent(hwndDlg), WM_FT_COMPLETED, ack->result, (LPARAM)hwndDlg); break; } // switch ack->result } // case HM_RECVEVENT break; case M_VIRUSSCANDONE: { int done = 1; if ((int)wParam == -1) { for (int i = 0; i < dat->transferStatus.totalFiles; i++) dat->fileVirusScanned[i] = 1; } else { dat->fileVirusScanned[wParam] = 1; for (int i = 0; i < dat->transferStatus.totalFiles; i++) if (!dat->fileVirusScanned[i]) { done = 0; break; } } if (done) { dat->fs = NULL; /* protocol will free structure */ SetFtStatus(hwndDlg, LPGENT("Transfer and virus scan complete"), FTS_TEXT); } } break; case WM_SIZE: Utils_ResizeDialog(hwndDlg, hInst, MAKEINTRESOURCEA(IDD_FILETRANSFERINFO), FileTransferDlgResizer); RedrawWindow(GetDlgItem(hwndDlg, IDC_ALLTRANSFERRED), NULL, NULL, RDW_INVALIDATE | RDW_NOERASE); RedrawWindow(GetDlgItem(hwndDlg, IDC_ALLSPEED), NULL, NULL, RDW_INVALIDATE | RDW_NOERASE); RedrawWindow(GetDlgItem(hwndDlg, IDC_CONTACTNAME), NULL, NULL, RDW_INVALIDATE | RDW_NOERASE); RedrawWindow(GetDlgItem(hwndDlg, IDC_STATUS), NULL, NULL, RDW_INVALIDATE | RDW_NOERASE); break; case WM_DESTROY: KillTimer(hwndDlg, 1); HFONT hFont = (HFONT)SendDlgItemMessage(hwndDlg, IDC_CONTACTNAME, WM_GETFONT, 0, 0); DeleteObject(hFont); Button_FreeIcon_IcoLib(hwndDlg, IDC_CONTACT); Button_FreeIcon_IcoLib(hwndDlg, IDC_OPENFILE); Button_FreeIcon_IcoLib(hwndDlg, IDCANCEL); FreeFileDlgData(dat); SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0); break; } return FALSE; }
INT_PTR CALLBACK DlgProcSendFile(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) { FileDlgData *dat = (FileDlgData*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); switch (msg) { case WM_INITDIALOG: TranslateDialogDefault(hwndDlg); { struct FileSendData *fsd = (struct FileSendData*)lParam; dat = (FileDlgData*)mir_calloc(sizeof(FileDlgData)); SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)dat); dat->hContact = fsd->hContact; dat->send = 1; dat->hPreshutdownEvent = HookEventMessage(ME_SYSTEM_PRESHUTDOWN, hwndDlg, M_PRESHUTDOWN); dat->fs = NULL; dat->dwTicks = GetTickCount(); EnumChildWindows(hwndDlg, ClipSiblingsChildEnumProc, 0); mir_subclassWindow(GetDlgItem(hwndDlg, IDC_MSG), SendEditSubclassProc); Window_SetSkinIcon_IcoLib(hwndDlg, SKINICON_EVENT_FILE); Button_SetIcon_IcoLib(hwndDlg, IDC_DETAILS, SKINICON_OTHER_USERDETAILS, LPGEN("View user's details")); Button_SetIcon_IcoLib(hwndDlg, IDC_HISTORY, SKINICON_OTHER_HISTORY, LPGEN("View user's history")); Button_SetIcon_IcoLib(hwndDlg, IDC_USERMENU, SKINICON_OTHER_DOWNARROW, LPGEN("User menu")); EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE); if (fsd->ppFiles != NULL && fsd->ppFiles[0] != NULL) { int totalCount, i; for (totalCount = 0; fsd->ppFiles[totalCount]; totalCount++); dat->files = (TCHAR**)mir_alloc(sizeof(TCHAR*)*(totalCount + 1)); // Leaks for (i = 0; i < totalCount; i++) dat->files[i] = mir_tstrdup(fsd->ppFiles[i]); dat->files[totalCount] = NULL; SetFileListAndSizeControls(hwndDlg, dat); } TCHAR *contactName = pcli->pfnGetContactDisplayName(dat->hContact, 0); SetDlgItemText(hwndDlg, IDC_TO, contactName); ptrT id(Contact_GetInfo(CNF_UNIQUEID, dat->hContact)); SetDlgItemText(hwndDlg, IDC_NAME, (id) ? id : contactName); if (fsd->ppFiles == NULL) { EnableWindow(hwndDlg, FALSE); dat->closeIfFileChooseCancelled = 1; PostMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_CHOOSE, BN_CLICKED), (LPARAM)GetDlgItem(hwndDlg, IDC_CHOOSE)); } } return TRUE; case WM_MEASUREITEM: return Menu_MeasureItem((LPMEASUREITEMSTRUCT)lParam); case WM_DRAWITEM: { LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT)lParam; if (dis->hwndItem == GetDlgItem(hwndDlg, IDC_PROTOCOL)) { char *szProto = GetContactProto(dat->hContact); if (szProto) { HICON hIcon = (HICON)CallProtoService(szProto, PS_LOADICON, PLI_PROTOCOL | PLIF_SMALL, 0); if (hIcon) { DrawIconEx(dis->hDC, dis->rcItem.left, dis->rcItem.top, hIcon, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0, NULL, DI_NORMAL); DestroyIcon(hIcon); } } } } return Menu_DrawItem((LPDRAWITEMSTRUCT)lParam); case M_FILECHOOSEDONE: if (lParam != 0) { FilenameToFileList(hwndDlg, dat, (TCHAR*)lParam); mir_free((TCHAR*)lParam); dat->closeIfFileChooseCancelled = 0; } else if (dat->closeIfFileChooseCancelled) PostMessage(hwndDlg, WM_COMMAND, IDCANCEL, 0); EnableWindow(hwndDlg, TRUE); break; case WM_COMMAND: if (CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(LOWORD(wParam), MPCF_CONTACTMENU), (LPARAM)dat->hContact)) break; switch (LOWORD(wParam)) { case IDC_CHOOSE: EnableWindow(hwndDlg, FALSE); mir_forkthread(ChooseFilesThread, hwndDlg); break; case IDOK: NotifyEventHooks(hDlgSucceeded, dat->hContact, (LPARAM)hwndDlg); EnableWindow(GetDlgItem(hwndDlg, IDC_FILENAME), FALSE); EnableWindow(GetDlgItem(hwndDlg, IDC_MSG), FALSE); EnableWindow(GetDlgItem(hwndDlg, IDC_CHOOSE), FALSE); GetDlgItemText(hwndDlg, IDC_FILEDIR, dat->szSavePath, _countof(dat->szSavePath)); GetDlgItemText(hwndDlg, IDC_FILE, dat->szFilenames, _countof(dat->szFilenames)); GetDlgItemText(hwndDlg, IDC_MSG, dat->szMsg, _countof(dat->szMsg)); dat->hwndTransfer = FtMgr_AddTransfer(dat); SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0); DestroyWindow(hwndDlg); return TRUE; case IDCANCEL: NotifyEventHooks(hDlgCanceled, dat->hContact, (LPARAM)hwndDlg); DestroyWindow(hwndDlg); return TRUE; case IDC_USERMENU: { RECT rc; GetWindowRect((HWND)lParam, &rc); HMENU hMenu = Menu_BuildContactMenu(dat->hContact); TrackPopupMenu(hMenu, 0, rc.left, rc.bottom, 0, hwndDlg, NULL); DestroyMenu(hMenu); } break; case IDC_DETAILS: CallService(MS_USERINFO_SHOWDIALOG, (WPARAM)dat->hContact, 0); return TRUE; case IDC_HISTORY: CallService(MS_HISTORY_SHOWCONTACTHISTORY, (WPARAM)dat->hContact, 0); return TRUE; } break; case WM_DESTROY: Window_FreeIcon_IcoLib(hwndDlg); Button_FreeIcon_IcoLib(hwndDlg, IDC_DETAILS); Button_FreeIcon_IcoLib(hwndDlg, IDC_HISTORY); Button_FreeIcon_IcoLib(hwndDlg, IDC_USERMENU); FreeFileDlgData(dat); SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0); return TRUE; } return FALSE; }