/* Miranda NG: the free IM client for Microsoft* Windows* Copyright (C) 2012-19 Miranda NG team (https://miranda-ng.org), Copyright (c) 2000-12 Miranda IM project, all portions of this codebase are copyrighted to the people listed in contributors.txt. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "stdafx.h" ///////////////////////////////////////////////////////////////////////////////////////// // Auth Request dialog class CAuthReqDlg : public CDlgBase { MEVENT m_hDbEvent; MCONTACT m_hContact; const char *m_szProto; CCtrlCheck chkAdd; CCtrlButton btnDetails, btnLater, btnOk, btnCancel; public: CAuthReqDlg(MEVENT hEvent) : CDlgBase(g_plugin, IDD_AUTHREQ), m_hDbEvent(hEvent), btnOk(this, IDOK), btnCancel(this, IDCANCEL), btnLater(this, IDC_DECIDELATER), btnDetails(this, IDC_DETAILS), chkAdd(this, IDC_ADDCHECK) { btnOk.OnClick = Callback(this, &CAuthReqDlg::onClick_OK); btnCancel.OnClick = Callback(this, &CAuthReqDlg::onClick_Cancel); btnLater.OnClick = Callback(this, &CAuthReqDlg::onClick_Later); btnDetails.OnClick = Callback(this, &CAuthReqDlg::onClick_Details); } bool OnInitDialog() override { Button_SetSkin_IcoLib(m_hwnd, IDC_DETAILS, SKINICON_OTHER_USERDETAILS, LPGEN("View user's details")); Button_SetSkin_IcoLib(m_hwnd, IDC_ADD, SKINICON_OTHER_ADDCONTACT, LPGEN("Add contact permanently to list")); int iBlobSize = db_event_getBlobSize(m_hDbEvent); if (iBlobSize == -1) return false; // blob is: uin(DWORD), hcontact(DWORD), nick(ASCIIZ), first(ASCIIZ), last(ASCIIZ), email(ASCIIZ), reason(ASCIIZ) DBEVENTINFO dbei = {}; dbei.cbBlob = iBlobSize; dbei.pBlob = (PBYTE)alloca(dbei.cbBlob); if (db_event_get(m_hDbEvent, &dbei)) return false; m_szProto = dbei.szModule; DWORD uin = *(PDWORD)dbei.pBlob; m_hContact = DbGetAuthEventContact(&dbei); char *nick = (char*)dbei.pBlob + sizeof(DWORD) * 2; char *first = nick + mir_strlen(nick) + 1; char *last = first + mir_strlen(first) + 1; char *email = last + mir_strlen(last) + 1; char *reason = email + mir_strlen(email) + 1; SendMessage(m_hwnd, WM_SETICON, ICON_SMALL, CallProtoService(dbei.szModule, PS_LOADICON, PLI_PROTOCOL | PLIF_SMALL, 0)); SendMessage(m_hwnd, WM_SETICON, ICON_BIG, CallProtoService(dbei.szModule, PS_LOADICON, PLI_PROTOCOL | PLIF_LARGE, 0)); ptrW lastT(dbei.flags & DBEF_UTF ? mir_utf8decodeW(last) : mir_a2u(last)); ptrW firstT(dbei.flags & DBEF_UTF ? mir_utf8decodeW(first) : mir_a2u(first)); ptrW nickT(dbei.flags & DBEF_UTF ? mir_utf8decodeW(nick) : mir_a2u(nick)); ptrW emailT(dbei.flags & DBEF_UTF ? mir_utf8decodeW(email) : mir_a2u(email)); ptrW reasonT(dbei.flags & DBEF_UTF ? mir_utf8decodeW(reason) : mir_a2u(reason)); wchar_t name[128] = L""; int off = 0; if (firstT[0] && lastT[0]) off = mir_snwprintf(name, L"%s %s", (wchar_t*)firstT, (wchar_t*)lastT); else if (firstT[0]) off = mir_snwprintf(name, L"%s", (wchar_t*)firstT); else if (lastT[0]) off = mir_snwprintf(name, L"%s", (wchar_t*)lastT); if (mir_wstrlen(nickT)) { if (off) mir_snwprintf(name + off, _countof(name) - off, L" (%s)", (wchar_t*)nickT); else wcsncpy_s(name, nickT, _TRUNCATE); } if (!name[0]) wcsncpy_s(name, TranslateT(""), _TRUNCATE); PROTOACCOUNT *acc = Proto_GetAccount(dbei.szModule); wchar_t hdr[256]; if (uin && emailT[0]) mir_snwprintf(hdr, TranslateT("%s requested authorization\n%u (%s) on %s"), name, uin, (wchar_t*)emailT, acc->tszAccountName); else if (uin) mir_snwprintf(hdr, TranslateT("%s requested authorization\n%u on %s"), name, uin, acc->tszAccountName); else mir_snwprintf(hdr, TranslateT("%s requested authorization\n%s on %s"), name, emailT[0] ? (wchar_t*)emailT : TranslateT("(Unknown)"), acc->tszAccountName); SetDlgItemText(m_hwnd, IDC_HEADERBAR, hdr); SetDlgItemText(m_hwnd, IDC_REASON, reasonT); if (m_hContact == INVALID_CONTACT_ID || !db_get_b(m_hContact, "CList", "NotOnList", 0)) ShowWindow(GetDlgItem(m_hwnd, IDC_ADD), FALSE); SendDlgItemMessage(m_hwnd, IDC_DENYREASON, EM_LIMITTEXT, 255, 0); if (CallProtoService(dbei.szModule, PS_GETCAPS, PFLAGNUM_4, 0) & PF4_NOAUTHDENYREASON) { EnableWindow(GetDlgItem(m_hwnd, IDC_DENYREASON), FALSE); SetDlgItemText(m_hwnd, IDC_DENYREASON, TranslateT("Feature is not supported by protocol")); } if (!db_get_b(m_hContact, "CList", "NotOnList", 0)) { chkAdd.Disable(); chkAdd.SetState(false); } else chkAdd.SetState(true); return true; } void OnDestroy() override { Button_FreeIcon_IcoLib(m_hwnd, IDC_ADD); Button_FreeIcon_IcoLib(m_hwnd, IDC_DETAILS); DestroyIcon((HICON)SendMessage(m_hwnd, WM_SETICON, ICON_BIG, 0)); DestroyIcon((HICON)SendMessage(m_hwnd, WM_SETICON, ICON_SMALL, 0)); } void onClick_OK(CCtrlButton*) { CallProtoService(m_szProto, PS_AUTHALLOW, m_hDbEvent, 0); if (chkAdd.GetState()) Contact_AddByEvent(m_hDbEvent, m_hwnd); } void onClick_Cancel(CCtrlButton*) { if (IsWindowEnabled(GetDlgItem(m_hwnd, IDC_DENYREASON))) { wchar_t tszReason[256]; GetDlgItemText(m_hwnd, IDC_DENYREASON, tszReason, _countof(tszReason)); CallProtoService(m_szProto, PS_AUTHDENY, m_hDbEvent, (LPARAM)tszReason); } else CallProtoService(m_szProto, PS_AUTHDENY, m_hDbEvent, 0); } void onClick_Later(CCtrlButton*) { Close(); } void onClick_Details(CCtrlButton*) { CallService(MS_USERINFO_SHOWDIALOG, m_hContact, 0); } }; static INT_PTR ShowReqWindow(WPARAM, LPARAM lParam) { (new CAuthReqDlg(((CLISTEVENT *)lParam)->hDbEvent))->Show(); return 0; } ///////////////////////////////////////////////////////////////////////////////////////// class CAddedDlg : public CDlgBase { MEVENT m_hDbEvent; MCONTACT m_hContact; CCtrlButton btnDetails, btnAdd, btnOk; public: CAddedDlg(MEVENT hEvent) : CDlgBase(g_plugin, IDD_ADDED), m_hDbEvent(hEvent), btnOk(this, IDOK), btnAdd(this, IDC_ADD), btnDetails(this, IDC_DETAILS) { btnOk.OnClick = Callback(this, &CAddedDlg::onClick_OK); btnAdd.OnClick = Callback(this, &CAddedDlg::onClick_Add); btnDetails.OnClick = Callback(this, &CAddedDlg::onClick_Details); } bool OnInitDialog() override { Button_SetSkin_IcoLib(m_hwnd, IDC_DETAILS, SKINICON_OTHER_USERDETAILS, LPGEN("View user's details")); Button_SetSkin_IcoLib(m_hwnd, IDC_ADD, SKINICON_OTHER_ADDCONTACT, LPGEN("Add contact permanently to list")); // blob is: uin(DWORD), hcontact(HANDLE), nick(ASCIIZ), first(ASCIIZ), last(ASCIIZ), email(ASCIIZ) DBEVENTINFO dbei = {}; dbei.cbBlob = db_event_getBlobSize(m_hDbEvent); dbei.pBlob = (PBYTE)alloca(dbei.cbBlob); db_event_get(m_hDbEvent, &dbei); m_hContact = DbGetAuthEventContact(&dbei); DWORD uin = *(PDWORD)dbei.pBlob; char* nick = (char*)dbei.pBlob + sizeof(DWORD) * 2; char* first = nick + mir_strlen(nick) + 1; char* last = first + mir_strlen(first) + 1; char* email = last + mir_strlen(last) + 1; SendMessage(m_hwnd, WM_SETICON, ICON_SMALL, CallProtoService(dbei.szModule, PS_LOADICON, PLI_PROTOCOL | PLIF_SMALL, 0)); SendMessage(m_hwnd, WM_SETICON, ICON_BIG, CallProtoService(dbei.szModule, PS_LOADICON, PLI_PROTOCOL | PLIF_LARGE, 0)); PROTOACCOUNT* acc = Proto_GetAccount(dbei.szModule); ptrW lastT(dbei.flags & DBEF_UTF ? mir_utf8decodeW(last) : mir_a2u(last)); ptrW firstT(dbei.flags & DBEF_UTF ? mir_utf8decodeW(first) : mir_a2u(first)); ptrW nickT(dbei.flags & DBEF_UTF ? mir_utf8decodeW(nick) : mir_a2u(nick)); ptrW emailT(dbei.flags & DBEF_UTF ? mir_utf8decodeW(email) : mir_a2u(email)); wchar_t name[128] = L""; int off = 0; if (firstT[0] && lastT[0]) off = mir_snwprintf(name, L"%s %s", firstT.get(), lastT.get()); else if (firstT[0]) off = mir_snwprintf(name, L"%s", firstT.get()); else if (lastT[0]) off = mir_snwprintf(name, L"%s", lastT.get()); if (nickT[0]) { if (off) mir_snwprintf(name + off, _countof(name) - off, L" (%s)", nickT.get()); else wcsncpy_s(name, nickT, _TRUNCATE); } if (!name[0]) wcsncpy_s(name, TranslateT(""), _TRUNCATE); wchar_t hdr[256]; if (uin && emailT[0]) mir_snwprintf(hdr, TranslateT("%s added you to the contact list\n%u (%s) on %s"), name, uin, emailT.get(), acc->tszAccountName); else if (uin) mir_snwprintf(hdr, TranslateT("%s added you to the contact list\n%u on %s"), name, uin, acc->tszAccountName); else mir_snwprintf(hdr, TranslateT("%s added you to the contact list\n%s on %s"), name, emailT[0] ? emailT.get() : TranslateT("(Unknown)"), acc->tszAccountName); SetDlgItemText(m_hwnd, IDC_HEADERBAR, hdr); if (m_hContact == INVALID_CONTACT_ID || !db_get_b(m_hContact, "CList", "NotOnList", 0)) ShowWindow(GetDlgItem(m_hwnd, IDC_ADD), FALSE); return true; } void OnDestroy() override { Button_FreeIcon_IcoLib(m_hwnd, IDC_ADD); Button_FreeIcon_IcoLib(m_hwnd, IDC_DETAILS); DestroyIcon((HICON)SendMessage(m_hwnd, WM_SETICON, ICON_BIG, 0)); DestroyIcon((HICON)SendMessage(m_hwnd, WM_SETICON, ICON_SMALL, 0)); } void onClick_OK(CCtrlButton*) { Contact_AddByEvent(m_hDbEvent, m_hwnd); } void onClick_Add(CCtrlButton*) { Contact_AddByEvent(m_hDbEvent, m_hwnd); if (m_hContact == INVALID_CONTACT_ID || !db_get_b(m_hContact, "CList", "NotOnList", 0)) ShowWindow(GetDlgItem(m_hwnd, IDC_ADD), FALSE); } void onClick_Details(CCtrlButton*) { CallService(MS_USERINFO_SHOWDIALOG, m_hContact, 0); } }; static INT_PTR ShowAddedWindow(WPARAM, LPARAM lParam) { (new CAddedDlg(((CLISTEVENT *)lParam)->hDbEvent))->Show(); return 0; } ///////////////////////////////////////////////////////////////////////////////////////// #define MS_AUTH_SHOWADDED "Auth/ShowAdded" #define MS_AUTH_SHOWREQUEST "Auth/ShowRequest" static int AuthEventAdded(WPARAM, LPARAM lParam) { wchar_t szTooltip[256]; MEVENT hDbEvent = (MEVENT)lParam; DBEVENTINFO dbei = {}; db_event_get(lParam, &dbei); if (dbei.flags & (DBEF_SENT | DBEF_READ) || (dbei.eventType != EVENTTYPE_AUTHREQUEST && dbei.eventType != EVENTTYPE_ADDED)) return 0; dbei.cbBlob = db_event_getBlobSize(hDbEvent); dbei.pBlob = (PBYTE)alloca(dbei.cbBlob); db_event_get(hDbEvent, &dbei); MCONTACT hContact = DbGetAuthEventContact(&dbei); CLISTEVENT cle = {}; cle.hContact = hContact; cle.szTooltip.w = szTooltip; cle.flags = CLEF_UNICODE; cle.lParam = lParam; cle.hDbEvent = hDbEvent; ptrW szUid(Contact_GetInfo(CNF_UNIQUEID, hContact)); if (dbei.eventType == EVENTTYPE_AUTHREQUEST) { Skin_PlaySound("AuthRequest"); if (szUid) mir_snwprintf(szTooltip, TranslateT("%s requests authorization"), szUid.get()); else mir_snwprintf(szTooltip, TranslateT("%u requests authorization"), *(PDWORD)dbei.pBlob); cle.hIcon = Skin_LoadIcon(SKINICON_AUTH_REQUEST); cle.pszService = MS_AUTH_SHOWREQUEST; g_clistApi.pfnAddEvent(&cle); } else if (dbei.eventType == EVENTTYPE_ADDED) { Skin_PlaySound("AddedEvent"); if (szUid) mir_snwprintf(szTooltip, TranslateT("%s added you to their contact list"), szUid.get()); else mir_snwprintf(szTooltip, TranslateT("%u added you to their contact list"), *(PDWORD)dbei.pBlob); cle.hIcon = Skin_LoadIcon(SKINICON_AUTH_ADD); cle.pszService = MS_AUTH_SHOWADDED; g_clistApi.pfnAddEvent(&cle); } return 0; } static void CALLBACK LaunchAuth() { HookEvent(ME_DB_EVENT_ADDED, AuthEventAdded); } int LoadSendRecvAuthModule(void) { CreateServiceFunction(MS_AUTH_SHOWREQUEST, ShowReqWindow); CreateServiceFunction(MS_AUTH_SHOWADDED, ShowAddedWindow); Miranda_WaitOnHandle(LaunchAuth); g_plugin.addSound("AuthRequest", LPGENW("Alerts"), LPGENW("Authorization request")); g_plugin.addSound("AddedEvent", LPGENW("Alerts"), LPGENW("Added event")); return 0; }