/* Miranda NG: the free IM client for Microsoft* Windows* Copyright (C) 2012-20 Miranda NG team (https://miranda-ng.org), Copyright (c) 2000-10 Miranda ICQ/IM project, all portions of this codebase are copyrighted to the people listed in contributors.txt. Portions of this code modified for Simple Status Message plugin Copyright (C) 2006-2011 Bartosz 'Dezeath' BiaƂek, (C) 2005 Harven This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "stdafx.h" #define HM_AWAYMSG (WM_USER + 10) static MWindowList hWindowList, hWindowList2; class CReadAwayMsgDlg : public CDlgBase { CCtrlButton btnCopy; MCONTACT m_hContact; HANDLE m_hSeq = nullptr; HANDLE m_hAwayMsgEvent = nullptr; public: CReadAwayMsgDlg(MCONTACT hContact) : CDlgBase(g_plugin, IDD_READAWAYMSG), btnCopy(this, IDC_COPY), m_hContact(hContact) { btnCopy.OnClick = Callback(this, &CReadAwayMsgDlg::onClick_Copy); } bool OnInitDialog() override { m_hSeq = (HANDLE)ProtoChainSend(m_hContact, PSS_GETAWAYMSG, 0, 0); m_hAwayMsgEvent = m_hSeq ? HookEventMessage(ME_PROTO_ACK, m_hwnd, HM_AWAYMSG) : nullptr; WindowList_Add(hWindowList, m_hwnd, m_hContact); wchar_t str[256], format[128]; wchar_t *contactName = Clist_GetContactDisplayName(m_hContact, 0); char *szProto = Proto_GetBaseAccountName(m_hContact); WORD dwStatus = db_get_w(m_hContact, szProto, "Status", ID_STATUS_OFFLINE); wchar_t *status = Clist_GetStatusModeDescription(dwStatus, 0); GetWindowText(m_hwnd, format, _countof(format)); mir_snwprintf(str, format, status, contactName); SetWindowText(m_hwnd, str); if (m_hSeq) { GetDlgItemText(m_hwnd, IDC_RETRIEVING, format, _countof(format)); mir_snwprintf(str, format, status); } else { mir_snwprintf(str, TranslateT("Failed to retrieve %s message."), status); SetDlgItemText(m_hwnd, IDOK, TranslateT("&Close")); } SetDlgItemText(m_hwnd, IDC_RETRIEVING, str); Window_SetProtoIcon_IcoLib(m_hwnd, szProto, dwStatus); EnableWindow(GetDlgItem(m_hwnd, IDC_COPY), FALSE); Utils_RestoreWindowPosition(m_hwnd, m_hContact, "SRAway", "AwayMsgDlg"); return true; } void OnDestroy() override { UnhookEvent(m_hAwayMsgEvent); Utils_SaveWindowPosition(m_hwnd, m_hContact, "SRAway", "AwayMsgDlg"); WindowList_Remove(hWindowList, m_hwnd); Window_FreeIcon_IcoLib(m_hwnd); } INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) override { if (msg == HM_AWAYMSG) { ACKDATA *ack = (ACKDATA *)lParam; if (ack->hContact != m_hContact || ack->type != ACKTYPE_AWAYMSG) return 0; if (ack->result != ACKRESULT_SUCCESS) return 0; if (m_hAwayMsgEvent && ack->hProcess == m_hSeq) { UnhookEvent(m_hAwayMsgEvent); m_hAwayMsgEvent = nullptr; } CMStringW wszMsg((wchar_t *)ack->lParam); wszMsg.Replace(L"\n", L"\r\n"); SetDlgItemText(m_hwnd, IDC_MSG, wszMsg); EnableWindow(GetDlgItem(m_hwnd, IDC_COPY), !wszMsg.IsEmpty()); ShowWindow(GetDlgItem(m_hwnd, IDC_RETRIEVING), SW_HIDE); ShowWindow(GetDlgItem(m_hwnd, IDC_MSG), SW_SHOW); SetDlgItemText(m_hwnd, IDOK, TranslateT("&Close")); } return CDlgBase::DlgProc(msg, wParam, lParam); } void onClick_Copy(CCtrlButton*) { if (!OpenClipboard(m_hwnd)) return; if (EmptyClipboard()) { wchar_t msg[1024]; int len = GetDlgItemText(m_hwnd, IDC_MSG, msg, _countof(msg)); if (len) { LPTSTR lptstrCopy; HGLOBAL hglbCopy = GlobalAlloc(GMEM_MOVEABLE, (len + 1) * sizeof(wchar_t)); if (hglbCopy == nullptr) { CloseClipboard(); return; } lptstrCopy = (LPTSTR)GlobalLock(hglbCopy); memcpy(lptstrCopy, msg, len * sizeof(wchar_t)); lptstrCopy[len] = (wchar_t)0; GlobalUnlock(hglbCopy); SetClipboardData(CF_UNICODETEXT, hglbCopy); } } CloseClipboard(); } }; static INT_PTR GetMessageCommand(WPARAM wParam, LPARAM) { if (HWND hwnd = WindowList_Find(hWindowList, wParam)) { SetForegroundWindow(hwnd); SetFocus(hwnd); } else { CReadAwayMsgDlg *pDlg = new CReadAwayMsgDlg(wParam); pDlg->Show(); } return 0; } ///////////////////////////////////////////////////////////////////////////////////////// class CCopyAwayMsgDlg : public CDlgBase { MCONTACT m_hContact; HANDLE m_hSeq; HANDLE m_hAwayMsgEvent; public: CCopyAwayMsgDlg(MCONTACT hContact) : CDlgBase(g_plugin, IDD_COPY), m_hContact(hContact) {} bool OnInitDialog() override { m_hSeq = (HANDLE)ProtoChainSend(m_hContact, PSS_GETAWAYMSG, 0, 0); m_hAwayMsgEvent = m_hSeq ? HookEventMessage(ME_PROTO_ACK, m_hwnd, HM_AWAYMSG) : nullptr; WindowList_Add(hWindowList2, m_hwnd, m_hContact); wchar_t str[256], format[128]; GetWindowText(m_hwnd, format, _countof(format)); mir_snwprintf(str, format, Clist_GetContactDisplayName(m_hContact)); SetWindowText(m_hwnd, str); return (m_hSeq != 0); } void OnDestroy() override { UnhookEvent(m_hAwayMsgEvent); WindowList_Remove(hWindowList2, m_hwnd); } INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) override { if (msg == HM_AWAYMSG) { ACKDATA *ack = (ACKDATA *)lParam; if (ack->hContact != m_hContact || ack->type != ACKTYPE_AWAYMSG) { Close(); return 0; } if (ack->result != ACKRESULT_SUCCESS) { Close(); return 0; } if (m_hAwayMsgEvent && ack->hProcess == m_hSeq) { UnhookEvent(m_hAwayMsgEvent); m_hAwayMsgEvent = nullptr; } if (OpenClipboard(m_hwnd)) { if (EmptyClipboard()) { CMStringW wszMsg((wchar_t *)ack->lParam); wszMsg.Replace(L"\n", L"\r\n"); if (wszMsg.GetLength()) { LPTSTR lptstrCopy; HGLOBAL hglbCopy = GlobalAlloc(GMEM_MOVEABLE, (wszMsg.GetLength() + 1) * sizeof(wchar_t)); if (hglbCopy != nullptr) { lptstrCopy = (LPTSTR)GlobalLock(hglbCopy); memcpy(lptstrCopy, wszMsg, wszMsg.GetLength() * sizeof(wchar_t)); lptstrCopy[wszMsg.GetLength()] = 0; GlobalUnlock(hglbCopy); SetClipboardData(CF_UNICODETEXT, hglbCopy); } } } CloseClipboard(); } Close(); } return CDlgBase::DlgProc(msg, wParam, lParam); } }; static INT_PTR CopyAwayMsgCommand(WPARAM wParam, LPARAM) { if (HWND hwnd = WindowList_Find(hWindowList2, wParam)) { SetForegroundWindow(hwnd); SetFocus(hwnd); } else { CCopyAwayMsgDlg *pDlg = new CCopyAwayMsgDlg(wParam); pDlg->Show(); } return 0; } ///////////////////////////////////////////////////////////////////////////////////////// static char* StrFindURL(char *pszStr) { char *pszURL = nullptr; if (pszStr != nullptr && *pszStr != '\0') { pszURL = strstr(pszStr, "www."); if (pszURL == nullptr) pszURL = strstr(pszStr, "http://"); if (pszURL == nullptr) pszURL = strstr(pszStr, "https://"); if (pszURL == nullptr) pszURL = strstr(pszStr, "ftp://"); } return pszURL; } static INT_PTR GoToURLMsgCommand(WPARAM wParam, LPARAM) { ptrA szMsg(db_get_sa(wParam, "CList", "StatusMsg")); char *szURL = StrFindURL(szMsg); if (szURL != nullptr) { int i; for (i = 0; szURL[i] != ' ' && szURL[i] != '\n' && szURL[i] != '\r' && szURL[i] != '\t' && szURL[i] != '\0'; i++); char *szMsgURL = (char *)mir_alloc(i + 1); if (szMsgURL) { mir_strncpy(szMsgURL, szURL, i + 1); Utils_OpenUrl(szMsgURL); mir_free(szMsgURL); } } return 0; } ///////////////////////////////////////////////////////////////////////////////////////// // contact menu items static HGENMENU hAwayMsgMenuItem, hCopyMsgMenuItem, hGoToURLMenuItem; static int AwayMsgPreBuildMenu(WPARAM hContact, LPARAM) { Menu_ShowItem(hCopyMsgMenuItem, false); Menu_ShowItem(hGoToURLMenuItem, false); Menu_ShowItem(hAwayMsgMenuItem, false); char *szProto = Proto_GetBaseAccountName(hContact); if (szProto == nullptr || db_get_b(hContact, szProto, "ChatRoom", 0)) return 0; int iStatus = db_get_w(hContact, szProto, "Status", ID_STATUS_OFFLINE); if (CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_MODEMSGRECV) { if (CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_3, 0) & Proto_Status2Flag(iStatus == ID_STATUS_OFFLINE ? ID_STATUS_INVISIBLE : iStatus)) { wchar_t str[128]; HANDLE hIcon = Skin_GetProtoIcon(szProto, iStatus); mir_snwprintf(str, TranslateT("Re&ad %s message"), Clist_GetStatusModeDescription(iStatus, 0)); Menu_ModifyItem(hAwayMsgMenuItem, str, hIcon, 0); IcoLib_ReleaseIcon((HICON)hIcon); ptrA szMsg(db_get_sa(hContact, "CList", "StatusMsg")); if (szMsg != nullptr) { mir_snwprintf(str, TranslateT("Copy %s message"), Clist_GetStatusModeDescription(iStatus, 0)); Menu_ModifyItem(hCopyMsgMenuItem, str); if (StrFindURL(szMsg) != nullptr) { mir_snwprintf(str, TranslateT("&Go to URL in %s message"), Clist_GetStatusModeDescription(iStatus, 0)); Menu_ModifyItem(hGoToURLMenuItem, str); } } } } return 0; } int AwayMsgPreShutdown(void) { if (hWindowList) { WindowList_Broadcast(hWindowList, WM_CLOSE, 0, 0); WindowList_Destroy(hWindowList); } if (hWindowList2) { WindowList_Broadcast(hWindowList2, WM_CLOSE, 0, 0); WindowList_Destroy(hWindowList2); } return 0; } int LoadAwayMsgModule(void) { hWindowList = WindowList_Create(); hWindowList2 = WindowList_Create(); CMenuItem mi(&g_plugin); mi.flags = CMIF_UNICODE; SET_UID(mi, 0xd3282acc, 0x9ff1, 0x4ede, 0x8a, 0x1e, 0x36, 0x72, 0x3f, 0x44, 0x4f, 0x84); CreateServiceFunction(MS_AWAYMSG_SHOWAWAYMSG, GetMessageCommand); mi.position = -2000005000; mi.name.w = LPGENW("Re&ad Away message"); mi.pszService = MS_AWAYMSG_SHOWAWAYMSG; hAwayMsgMenuItem = Menu_AddContactMenuItem(&mi); SET_UID(mi, 0x311124e9, 0xb477, 0x42ef, 0x84, 0xd2, 0xc, 0x6c, 0x50, 0x3f, 0x4a, 0x84); CreateServiceFunction(MS_SIMPLESTATUSMSG_COPYMSG, CopyAwayMsgCommand); mi.position = -2000006000; mi.hIcolibItem = g_plugin.getIconHandle(IDI_COPY); mi.name.w = LPGENW("Copy Away message"); mi.pszService = MS_SIMPLESTATUSMSG_COPYMSG; hCopyMsgMenuItem = Menu_AddContactMenuItem(&mi); SET_UID(mi, 0xe2c75070, 0x455d, 0x455f, 0xbf, 0x53, 0x86, 0x64, 0xbc, 0x14, 0xa1, 0xbe); CreateServiceFunction(MS_SIMPLESTATUSMSG_GOTOURLMSG, GoToURLMsgCommand); mi.position = -2000007000; mi.hIcolibItem = g_plugin.getIconHandle(IDI_GOTOURL); mi.name.w = LPGENW("&Go to URL in Away message"); mi.pszService = MS_SIMPLESTATUSMSG_GOTOURLMSG; hGoToURLMenuItem = Menu_AddContactMenuItem(&mi); HookEvent(ME_CLIST_PREBUILDCONTACTMENU, AwayMsgPreBuildMenu); return 0; }