From 1979fd80424d16b2e489f9b57d01d9c7811d25a2 Mon Sep 17 00:00:00 2001 From: dartraiden Date: Mon, 2 Jan 2023 21:10:29 +0300 Subject: Update copyrights --- src/core/stdautoaway/src/autoaway.cpp | 2 +- src/core/stdautoaway/src/idle.cpp | 178 ++-- src/core/stdautoaway/src/main.cpp | 2 +- src/core/stdautoaway/src/options.cpp | 268 ++--- src/core/stdautoaway/src/stdafx.h | 2 +- src/core/stdautoaway/src/version.h | 2 +- src/core/stdaway/src/awaymsg.cpp | 2 +- src/core/stdaway/src/main.cpp | 2 +- src/core/stdaway/src/options.cpp | 280 +++--- src/core/stdaway/src/sendmsg.cpp | 2 +- src/core/stdaway/src/stdafx.h | 2 +- src/core/stdaway/src/version.h | 2 +- src/core/stdclist/src/clc.h | 2 +- src/core/stdclist/src/clcfonts.cpp | 2 +- src/core/stdclist/src/clcopts.cpp | 2 +- src/core/stdclist/src/clcpaint.cpp | 2 +- src/core/stdclist/src/clistmenus.cpp | 2 +- src/core/stdclist/src/clistopts.cpp | 2 +- src/core/stdclist/src/cluiopts.cpp | 2 +- src/core/stdclist/src/contact.cpp | 2 +- src/core/stdclist/src/init.cpp | 2 +- src/core/stdclist/src/stdafx.cxx | 2 +- src/core/stdclist/src/stdafx.h | 2 +- src/core/stdclist/src/version.h | 2 +- src/core/stdcrypt/src/encrypt.cpp | 2 +- src/core/stdcrypt/src/main.cpp | 2 +- src/core/stdcrypt/src/stdafx.h | 2 +- src/core/stdcrypt/src/stdcrypt.h | 2 +- src/core/stdcrypt/src/utils.cpp | 2 +- src/core/stdcrypt/src/version.h | 2 +- src/core/stdemail/src/email.cpp | 2 +- src/core/stdemail/src/main.cpp | 2 +- src/core/stdemail/src/stdafx.h | 2 +- src/core/stdemail/src/version.h | 2 +- src/core/stdfile/src/file.cpp | 2 +- src/core/stdfile/src/file.h | 2 +- src/core/stdfile/src/fileexistsdlg.cpp | 2 +- src/core/stdfile/src/fileopts.cpp | 2 +- src/core/stdfile/src/filerecvdlg.cpp | 2 +- src/core/stdfile/src/filesenddlg.cpp | 2 +- src/core/stdfile/src/filexferdlg.cpp | 1530 ++++++++++++++--------------- src/core/stdfile/src/ftmanager.cpp | 2 +- src/core/stdfile/src/main.cpp | 2 +- src/core/stdfile/src/stdafx.h | 2 +- src/core/stdfile/src/version.h | 2 +- src/core/stdmsg/src/chat_manager.cpp | 486 ++++----- src/core/stdmsg/src/chat_window.cpp | 550 +++++------ src/core/stdmsg/src/cmdlist.cpp | 2 +- src/core/stdmsg/src/cmdlist.h | 2 +- src/core/stdmsg/src/globals.cpp | 2 +- src/core/stdmsg/src/msgdialog.cpp | 2 +- src/core/stdmsg/src/msglog.cpp | 2 +- src/core/stdmsg/src/msgoptions.cpp | 2 +- src/core/stdmsg/src/msgs.cpp | 2 +- src/core/stdmsg/src/msgs.h | 2 +- src/core/stdmsg/src/msgtimedout.cpp | 2 +- src/core/stdmsg/src/srmm.cpp | 2 +- src/core/stdmsg/src/statusicon.cpp | 2 +- src/core/stdmsg/src/stdafx.cxx | 2 +- src/core/stdmsg/src/stdafx.h | 2 +- src/core/stdmsg/src/tabs.cpp | 1336 ++++++++++++------------- src/core/stdmsg/src/version.h | 2 +- src/core/stdpopup/src/stdafx.cxx | 34 +- src/core/stdpopup/src/version.h | 2 +- src/core/stduihist/src/history.cpp | 2 +- src/core/stduihist/src/main.cpp | 2 +- src/core/stduihist/src/stdafx.h | 2 +- src/core/stduihist/src/version.h | 2 +- src/core/stduserinfo/src/contactinfo.cpp | 2 +- src/core/stduserinfo/src/main.cpp | 2 +- src/core/stduserinfo/src/stdafx.h | 2 +- src/core/stduserinfo/src/stdinfo.cpp | 2 +- src/core/stduserinfo/src/userinfo.cpp | 2 +- src/core/stduserinfo/src/utils.h | 428 ++++---- src/core/stduserinfo/src/version.h | 2 +- src/core/stduseronline/src/main.cpp | 2 +- src/core/stduseronline/src/stdafx.h | 2 +- src/core/stduseronline/src/useronline.cpp | 2 +- src/core/stduseronline/src/version.h | 2 +- 79 files changed, 2615 insertions(+), 2615 deletions(-) (limited to 'src/core') diff --git a/src/core/stdautoaway/src/autoaway.cpp b/src/core/stdautoaway/src/autoaway.cpp index f9a7fa8379..024487ed5a 100644 --- a/src/core/stdautoaway/src/autoaway.cpp +++ b/src/core/stdautoaway/src/autoaway.cpp @@ -2,7 +2,7 @@ Miranda NG: the free IM client for Microsoft* Windows* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org), +Copyright (C) 2012-23 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. diff --git a/src/core/stdautoaway/src/idle.cpp b/src/core/stdautoaway/src/idle.cpp index aaabe0ddb2..b4faa31c4b 100644 --- a/src/core/stdautoaway/src/idle.cpp +++ b/src/core/stdautoaway/src/idle.cpp @@ -1,89 +1,89 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (C) 2012-22 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" - -static UINT_PTR g_hTimer; - -int IdleOptInit(WPARAM wParam, LPARAM); - -static int IdleObject_IsUserIdle() -{ - if (g_plugin.bIdleMethod) { - uint32_t dwTick = Miranda_GetIdle(); - return GetTickCount() - dwTick > (g_plugin.iIdleTime1st * 60 * 1000); - } - - LASTINPUTINFO ii = { sizeof(ii) }; - if (GetLastInputInfo(&ii)) - return GetTickCount() - ii.dwTime > (g_plugin.iIdleTime1st * 60 * 1000); - - return FALSE; -} - -static void CALLBACK IdleTimer(HWND, UINT, UINT_PTR idEvent, DWORD) -{ - if (g_hTimer != idEvent) - return; - - if (g_plugin.bIdleCheck && IdleObject_IsUserIdle()) - Idle_Enter(1); - - else if (g_plugin.bIdleOnSaver && IsScreenSaverRunning()) - Idle_Enter(2); - - else if (g_plugin.bIdleOnFullScr && IsFullScreen()) - Idle_Enter(3); - - else if (g_plugin.bIdleOnLock && IsWorkstationLocked()) - Idle_Enter(4); - - else if (g_plugin.bIdleOnTerminal && IsTerminalDisconnected()) - Idle_Enter(5); - - else // not idle - Idle_Enter(-1); -} - -void IdleObject_Create() -{ - g_hTimer = SetTimer(nullptr, 0, 2000, IdleTimer); -} - -void IdleObject_Destroy() -{ - KillTimer(nullptr, g_hTimer); -} - -void LoadIdleModule(void) -{ - IdleObject_Create(); - - HookEvent(ME_OPT_INITIALISE, IdleOptInit); -} - -void UnloadIdleModule() -{ - IdleObject_Destroy(); -} +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (C) 2012-23 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" + +static UINT_PTR g_hTimer; + +int IdleOptInit(WPARAM wParam, LPARAM); + +static int IdleObject_IsUserIdle() +{ + if (g_plugin.bIdleMethod) { + uint32_t dwTick = Miranda_GetIdle(); + return GetTickCount() - dwTick > (g_plugin.iIdleTime1st * 60 * 1000); + } + + LASTINPUTINFO ii = { sizeof(ii) }; + if (GetLastInputInfo(&ii)) + return GetTickCount() - ii.dwTime > (g_plugin.iIdleTime1st * 60 * 1000); + + return FALSE; +} + +static void CALLBACK IdleTimer(HWND, UINT, UINT_PTR idEvent, DWORD) +{ + if (g_hTimer != idEvent) + return; + + if (g_plugin.bIdleCheck && IdleObject_IsUserIdle()) + Idle_Enter(1); + + else if (g_plugin.bIdleOnSaver && IsScreenSaverRunning()) + Idle_Enter(2); + + else if (g_plugin.bIdleOnFullScr && IsFullScreen()) + Idle_Enter(3); + + else if (g_plugin.bIdleOnLock && IsWorkstationLocked()) + Idle_Enter(4); + + else if (g_plugin.bIdleOnTerminal && IsTerminalDisconnected()) + Idle_Enter(5); + + else // not idle + Idle_Enter(-1); +} + +void IdleObject_Create() +{ + g_hTimer = SetTimer(nullptr, 0, 2000, IdleTimer); +} + +void IdleObject_Destroy() +{ + KillTimer(nullptr, g_hTimer); +} + +void LoadIdleModule(void) +{ + IdleObject_Create(); + + HookEvent(ME_OPT_INITIALISE, IdleOptInit); +} + +void UnloadIdleModule() +{ + IdleObject_Destroy(); +} diff --git a/src/core/stdautoaway/src/main.cpp b/src/core/stdautoaway/src/main.cpp index 971fd166ff..1022f2a4d5 100644 --- a/src/core/stdautoaway/src/main.cpp +++ b/src/core/stdautoaway/src/main.cpp @@ -2,7 +2,7 @@ Standard auto away module for Miranda NG -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org) +Copyright (C) 2012-23 Miranda NG team (https://miranda-ng.org) 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 diff --git a/src/core/stdautoaway/src/options.cpp b/src/core/stdautoaway/src/options.cpp index 17a8f8381b..fed12a11f8 100644 --- a/src/core/stdautoaway/src/options.cpp +++ b/src/core/stdautoaway/src/options.cpp @@ -1,134 +1,134 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (C) 2012-22 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" - -static const uint16_t aa_Status[] = { ID_STATUS_AWAY, ID_STATUS_NA, ID_STATUS_OCCUPIED, ID_STATUS_DND }; - -int IdleGetStatusIndex(uint16_t status) -{ - for (int j = 0; j < _countof(aa_Status); j++) - if (aa_Status[j] == status) - return j; - - return 0; -} - -class COptionsDlg : public CDlgBase -{ - CCtrlEdit edt1sttime; - CCtrlSpin spinIdle; - CCtrlCombo cmbAAStatus; - CCtrlCheck chkShort, chkOnWindows, chkOnMiranda, chkScreenSaver, chkFullScreen, chkLocked; - CCtrlCheck chkPrivate, chkStatusLock, chkTerminal, chkSoundsOff, chkShortIdle; - - void ShowHide() - { - BOOL bChecked = chkShort.GetState(); - chkOnWindows.Enable(bChecked); - chkOnMiranda.Enable(bChecked); - edt1sttime.Enable(bChecked); - - bChecked = chkShortIdle.GetState(); - cmbAAStatus.Enable(bChecked); - chkStatusLock.Enable(bChecked); - } - -public: - COptionsDlg() : - CDlgBase(g_plugin, IDD_OPT_IDLE), - edt1sttime(this, IDC_IDLE1STTIME), - spinIdle(this, IDC_IDLESPIN, 60, 1), - cmbAAStatus(this, IDC_AASTATUS), - chkShort(this, IDC_IDLESHORT), - chkLocked(this, IDC_LOCKED), - chkPrivate(this, IDC_IDLEPRIVATE), - chkTerminal(this, IDC_IDLETERMINAL), - chkOnWindows(this, IDC_IDLEONWINDOWS), - chkSoundsOff(this, IDC_IDLESOUNDSOFF), - chkOnMiranda(this, IDC_IDLEONMIRANDA), - chkShortIdle(this, IDC_AASHORTIDLE), - chkStatusLock(this, IDC_IDLESTATUSLOCK), - chkFullScreen(this, IDC_FULLSCREEN), - chkScreenSaver(this, IDC_SCREENSAVER) - { - CreateLink(chkShort, g_plugin.bIdleCheck); - CreateLink(chkLocked, g_plugin.bIdleOnLock); - CreateLink(chkPrivate, g_plugin.bIdlePrivate); - CreateLink(chkTerminal, g_plugin.bIdleOnTerminal); - CreateLink(chkShortIdle, g_plugin.bAAEnable); - CreateLink(chkOnMiranda, g_plugin.bIdleMethod); - CreateLink(chkSoundsOff, g_plugin.bIdleSoundsOff); - CreateLink(chkStatusLock, g_plugin.bIdleStatusLock); - CreateLink(chkFullScreen, g_plugin.bIdleOnFullScr); - CreateLink(chkScreenSaver, g_plugin.bIdleOnSaver); - - chkShortIdle.OnChange = chkShort.OnChange = Callback(this, &COptionsDlg::onChange); - } - - bool OnInitDialog() override - { - chkOnWindows.SetState(!g_plugin.bIdleMethod); - - spinIdle.SetPosition(g_plugin.iIdleTime1st); - - for (auto &it : aa_Status) - cmbAAStatus.AddString(Clist_GetStatusModeDescription(it, 0)); - cmbAAStatus.SetCurSel(IdleGetStatusIndex(g_plugin.bAAStatus)); - - ShowHide(); - return true; - } - - bool OnApply() override - { - g_plugin.iIdleTime1st = spinIdle.GetPosition(); - - int curSel = cmbAAStatus.GetCurSel(); - if (curSel != CB_ERR) - g_plugin.bAAStatus = aa_Status[curSel]; - - // destroy any current idle and reset settings. - IdleObject_Destroy(); - IdleObject_Create(); - return true; - } - - void onChange(CCtrlCheck*) - { - ShowHide(); - } -}; - -int IdleOptInit(WPARAM wParam, LPARAM) -{ - OPTIONSDIALOGPAGE odp = {}; - odp.position = 100000000; - odp.szGroup.a = LPGEN("Status"); - odp.szTitle.a = LPGEN("Idle"); - odp.flags = ODPF_BOLDGROUPS; - odp.pDialog = new COptionsDlg(); - g_plugin.addOptions(wParam, &odp); - return 0; -} +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (C) 2012-23 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" + +static const uint16_t aa_Status[] = { ID_STATUS_AWAY, ID_STATUS_NA, ID_STATUS_OCCUPIED, ID_STATUS_DND }; + +int IdleGetStatusIndex(uint16_t status) +{ + for (int j = 0; j < _countof(aa_Status); j++) + if (aa_Status[j] == status) + return j; + + return 0; +} + +class COptionsDlg : public CDlgBase +{ + CCtrlEdit edt1sttime; + CCtrlSpin spinIdle; + CCtrlCombo cmbAAStatus; + CCtrlCheck chkShort, chkOnWindows, chkOnMiranda, chkScreenSaver, chkFullScreen, chkLocked; + CCtrlCheck chkPrivate, chkStatusLock, chkTerminal, chkSoundsOff, chkShortIdle; + + void ShowHide() + { + BOOL bChecked = chkShort.GetState(); + chkOnWindows.Enable(bChecked); + chkOnMiranda.Enable(bChecked); + edt1sttime.Enable(bChecked); + + bChecked = chkShortIdle.GetState(); + cmbAAStatus.Enable(bChecked); + chkStatusLock.Enable(bChecked); + } + +public: + COptionsDlg() : + CDlgBase(g_plugin, IDD_OPT_IDLE), + edt1sttime(this, IDC_IDLE1STTIME), + spinIdle(this, IDC_IDLESPIN, 60, 1), + cmbAAStatus(this, IDC_AASTATUS), + chkShort(this, IDC_IDLESHORT), + chkLocked(this, IDC_LOCKED), + chkPrivate(this, IDC_IDLEPRIVATE), + chkTerminal(this, IDC_IDLETERMINAL), + chkOnWindows(this, IDC_IDLEONWINDOWS), + chkSoundsOff(this, IDC_IDLESOUNDSOFF), + chkOnMiranda(this, IDC_IDLEONMIRANDA), + chkShortIdle(this, IDC_AASHORTIDLE), + chkStatusLock(this, IDC_IDLESTATUSLOCK), + chkFullScreen(this, IDC_FULLSCREEN), + chkScreenSaver(this, IDC_SCREENSAVER) + { + CreateLink(chkShort, g_plugin.bIdleCheck); + CreateLink(chkLocked, g_plugin.bIdleOnLock); + CreateLink(chkPrivate, g_plugin.bIdlePrivate); + CreateLink(chkTerminal, g_plugin.bIdleOnTerminal); + CreateLink(chkShortIdle, g_plugin.bAAEnable); + CreateLink(chkOnMiranda, g_plugin.bIdleMethod); + CreateLink(chkSoundsOff, g_plugin.bIdleSoundsOff); + CreateLink(chkStatusLock, g_plugin.bIdleStatusLock); + CreateLink(chkFullScreen, g_plugin.bIdleOnFullScr); + CreateLink(chkScreenSaver, g_plugin.bIdleOnSaver); + + chkShortIdle.OnChange = chkShort.OnChange = Callback(this, &COptionsDlg::onChange); + } + + bool OnInitDialog() override + { + chkOnWindows.SetState(!g_plugin.bIdleMethod); + + spinIdle.SetPosition(g_plugin.iIdleTime1st); + + for (auto &it : aa_Status) + cmbAAStatus.AddString(Clist_GetStatusModeDescription(it, 0)); + cmbAAStatus.SetCurSel(IdleGetStatusIndex(g_plugin.bAAStatus)); + + ShowHide(); + return true; + } + + bool OnApply() override + { + g_plugin.iIdleTime1st = spinIdle.GetPosition(); + + int curSel = cmbAAStatus.GetCurSel(); + if (curSel != CB_ERR) + g_plugin.bAAStatus = aa_Status[curSel]; + + // destroy any current idle and reset settings. + IdleObject_Destroy(); + IdleObject_Create(); + return true; + } + + void onChange(CCtrlCheck*) + { + ShowHide(); + } +}; + +int IdleOptInit(WPARAM wParam, LPARAM) +{ + OPTIONSDIALOGPAGE odp = {}; + odp.position = 100000000; + odp.szGroup.a = LPGEN("Status"); + odp.szTitle.a = LPGEN("Idle"); + odp.flags = ODPF_BOLDGROUPS; + odp.pDialog = new COptionsDlg(); + g_plugin.addOptions(wParam, &odp); + return 0; +} diff --git a/src/core/stdautoaway/src/stdafx.h b/src/core/stdautoaway/src/stdafx.h index be6446162a..aed3748da5 100644 --- a/src/core/stdautoaway/src/stdafx.h +++ b/src/core/stdautoaway/src/stdafx.h @@ -2,7 +2,7 @@ Miranda NG: the free IM client for Microsoft* Windows* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org), +Copyright (C) 2012-23 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. diff --git a/src/core/stdautoaway/src/version.h b/src/core/stdautoaway/src/version.h index 50fcd17758..e85f99715c 100644 --- a/src/core/stdautoaway/src/version.h +++ b/src/core/stdautoaway/src/version.h @@ -8,4 +8,4 @@ #define __DESCRIPTION "Core module for away state processing." #define __AUTHOR "Miranda NG team" #define __AUTHORWEB "https://miranda-ng.org/p/StdAutoAway" -#define __COPYRIGHT "© 2012-22 Miranda NG team" +#define __COPYRIGHT "© 2012-23 Miranda NG team" diff --git a/src/core/stdaway/src/awaymsg.cpp b/src/core/stdaway/src/awaymsg.cpp index 94f097fbe1..391a61383e 100644 --- a/src/core/stdaway/src/awaymsg.cpp +++ b/src/core/stdaway/src/awaymsg.cpp @@ -2,7 +2,7 @@ Miranda NG: the free IM client for Microsoft* Windows* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org), +Copyright (C) 2012-23 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. diff --git a/src/core/stdaway/src/main.cpp b/src/core/stdaway/src/main.cpp index 1dfab72a34..bf275c259a 100644 --- a/src/core/stdaway/src/main.cpp +++ b/src/core/stdaway/src/main.cpp @@ -2,7 +2,7 @@ Standard away message processing module for Miranda NG -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org) +Copyright (C) 2012-23 Miranda NG team (https://miranda-ng.org) 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 diff --git a/src/core/stdaway/src/options.cpp b/src/core/stdaway/src/options.cpp index 64943461d9..1287a623d3 100644 --- a/src/core/stdaway/src/options.cpp +++ b/src/core/stdaway/src/options.cpp @@ -1,140 +1,140 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (C) 2012-22 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" - -static const int statusModes[] = -{ - ID_STATUS_OFFLINE, ID_STATUS_ONLINE, ID_STATUS_AWAY, ID_STATUS_NA, ID_STATUS_OCCUPIED, ID_STATUS_DND, - ID_STATUS_FREECHAT, ID_STATUS_INVISIBLE, ID_STATUS_IDLE -}; - -class CAwayMsgOptsDlg : public CDlgBase -{ - struct - { - int ignore; - int noDialog; - int usePrevious; - wchar_t msg[1024]; - } - m_info[_countof(statusModes)]; - - int oldPage = -1; - - CCtrlEdit etdMsg; - CCtrlCombo cmbStatus; - CCtrlCheck chkDontReply, chkUsePrev, chkUseSpecific, chkNoDialog; - -public: - CAwayMsgOptsDlg() : - CDlgBase(g_plugin, IDD_OPT_AWAYMSG), - etdMsg(this, IDC_MSG), - cmbStatus(this, IDC_STATUS), - chkUsePrev(this, IDC_USEPREVIOUS), - chkNoDialog(this, IDC_NODIALOG), - chkDontReply(this, IDC_DONTREPLY), - chkUseSpecific(this, IDC_USESPECIFIC) - { - chkUsePrev.OnChange = chkDontReply.OnChange = chkUseSpecific.OnChange = Callback(this, &CAwayMsgOptsDlg::onSelChange_Status); - cmbStatus.OnSelChanged = Callback(this, &CAwayMsgOptsDlg::onSelChange_Status); - } - - bool OnInitDialog() override - { - for (auto &it : statusModes) { - if (!(protoModeMsgFlags & Proto_Status2Flag(it))) - continue; - - int j = cmbStatus.AddString(Clist_GetStatusModeDescription(it, 0), it); - m_info[j].ignore = g_plugin.GetStatusModeByte(it, "Ignore"); - m_info[j].noDialog = g_plugin.GetStatusModeByte(it, "NoDlg", true); - m_info[j].usePrevious = g_plugin.GetStatusModeByte(it, "UsePrev"); - - DBVARIANT dbv; - if (g_plugin.getWString(StatusModeToDbSetting(it, "Default"), &dbv)) - if (g_plugin.getWString(StatusModeToDbSetting(it, "Msg"), &dbv)) - dbv.pwszVal = mir_wstrdup(GetDefaultMessage(it)); - mir_wstrcpy(m_info[j].msg, dbv.pwszVal); - mir_free(dbv.pwszVal); - } - - cmbStatus.SetCurSel(0); - onSelChange_Status(0); - return true; - } - - bool OnApply() override - { - onSelChange_Status(0); - - for (int i = cmbStatus.GetCount() - 1; i >= 0; i--) { - int status = cmbStatus.GetItemData(i); - g_plugin.SetStatusModeByte(status, "Ignore", (uint8_t)m_info[i].ignore); - g_plugin.SetStatusModeByte(status, "NoDlg", (uint8_t)m_info[i].noDialog); - g_plugin.SetStatusModeByte(status, "UsePrev", (uint8_t)m_info[i].usePrevious); - g_plugin.setWString(StatusModeToDbSetting(status, "Default"), m_info[i].msg); - } - return true; - } - - void onSelChange_Status(CCtrlCombo*) - { - if (oldPage != -1) { - m_info[oldPage].ignore = chkDontReply.GetState(); - m_info[oldPage].noDialog = chkNoDialog.GetState(); - m_info[oldPage].usePrevious = chkUsePrev.GetState(); - etdMsg.GetText(m_info[oldPage].msg, _countof(m_info[oldPage].msg)); - } - - int i = cmbStatus.GetCurSel(); - chkDontReply.SetState(i < 0 ? 0 : m_info[i].ignore); - chkNoDialog.SetState(i < 0 ? 0 : m_info[i].noDialog); - chkUsePrev.SetState(i < 0 ? 0 : m_info[i].usePrevious); - chkUseSpecific.SetState(i < 0 ? 0 : !m_info[i].usePrevious); - - etdMsg.SetText(i < 0 ? L"" : m_info[i].msg); - - chkNoDialog.Enable(i < 0 ? 0 : !m_info[i].ignore); - chkUsePrev.Enable(i < 0 ? 0 : !m_info[i].ignore); - chkUseSpecific.Enable(i < 0 ? 0 : !m_info[i].ignore); - etdMsg.Enable(i < 0 ? 0 : !(m_info[i].ignore || m_info[i].usePrevious)); - oldPage = i; - } -}; - -int AwayMsgOptInitialise(WPARAM wParam, LPARAM) -{ - if (protoModeMsgFlags == 0) - return 0; - - OPTIONSDIALOGPAGE odp = {}; - odp.flags = ODPF_BOLDGROUPS; - odp.position = 870000000; - odp.szTitle.a = LPGEN("Status messages"); - odp.szGroup.a = LPGEN("Status"); - odp.pDialog = new CAwayMsgOptsDlg(); - g_plugin.addOptions(wParam, &odp); - return 0; -} +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (C) 2012-23 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" + +static const int statusModes[] = +{ + ID_STATUS_OFFLINE, ID_STATUS_ONLINE, ID_STATUS_AWAY, ID_STATUS_NA, ID_STATUS_OCCUPIED, ID_STATUS_DND, + ID_STATUS_FREECHAT, ID_STATUS_INVISIBLE, ID_STATUS_IDLE +}; + +class CAwayMsgOptsDlg : public CDlgBase +{ + struct + { + int ignore; + int noDialog; + int usePrevious; + wchar_t msg[1024]; + } + m_info[_countof(statusModes)]; + + int oldPage = -1; + + CCtrlEdit etdMsg; + CCtrlCombo cmbStatus; + CCtrlCheck chkDontReply, chkUsePrev, chkUseSpecific, chkNoDialog; + +public: + CAwayMsgOptsDlg() : + CDlgBase(g_plugin, IDD_OPT_AWAYMSG), + etdMsg(this, IDC_MSG), + cmbStatus(this, IDC_STATUS), + chkUsePrev(this, IDC_USEPREVIOUS), + chkNoDialog(this, IDC_NODIALOG), + chkDontReply(this, IDC_DONTREPLY), + chkUseSpecific(this, IDC_USESPECIFIC) + { + chkUsePrev.OnChange = chkDontReply.OnChange = chkUseSpecific.OnChange = Callback(this, &CAwayMsgOptsDlg::onSelChange_Status); + cmbStatus.OnSelChanged = Callback(this, &CAwayMsgOptsDlg::onSelChange_Status); + } + + bool OnInitDialog() override + { + for (auto &it : statusModes) { + if (!(protoModeMsgFlags & Proto_Status2Flag(it))) + continue; + + int j = cmbStatus.AddString(Clist_GetStatusModeDescription(it, 0), it); + m_info[j].ignore = g_plugin.GetStatusModeByte(it, "Ignore"); + m_info[j].noDialog = g_plugin.GetStatusModeByte(it, "NoDlg", true); + m_info[j].usePrevious = g_plugin.GetStatusModeByte(it, "UsePrev"); + + DBVARIANT dbv; + if (g_plugin.getWString(StatusModeToDbSetting(it, "Default"), &dbv)) + if (g_plugin.getWString(StatusModeToDbSetting(it, "Msg"), &dbv)) + dbv.pwszVal = mir_wstrdup(GetDefaultMessage(it)); + mir_wstrcpy(m_info[j].msg, dbv.pwszVal); + mir_free(dbv.pwszVal); + } + + cmbStatus.SetCurSel(0); + onSelChange_Status(0); + return true; + } + + bool OnApply() override + { + onSelChange_Status(0); + + for (int i = cmbStatus.GetCount() - 1; i >= 0; i--) { + int status = cmbStatus.GetItemData(i); + g_plugin.SetStatusModeByte(status, "Ignore", (uint8_t)m_info[i].ignore); + g_plugin.SetStatusModeByte(status, "NoDlg", (uint8_t)m_info[i].noDialog); + g_plugin.SetStatusModeByte(status, "UsePrev", (uint8_t)m_info[i].usePrevious); + g_plugin.setWString(StatusModeToDbSetting(status, "Default"), m_info[i].msg); + } + return true; + } + + void onSelChange_Status(CCtrlCombo*) + { + if (oldPage != -1) { + m_info[oldPage].ignore = chkDontReply.GetState(); + m_info[oldPage].noDialog = chkNoDialog.GetState(); + m_info[oldPage].usePrevious = chkUsePrev.GetState(); + etdMsg.GetText(m_info[oldPage].msg, _countof(m_info[oldPage].msg)); + } + + int i = cmbStatus.GetCurSel(); + chkDontReply.SetState(i < 0 ? 0 : m_info[i].ignore); + chkNoDialog.SetState(i < 0 ? 0 : m_info[i].noDialog); + chkUsePrev.SetState(i < 0 ? 0 : m_info[i].usePrevious); + chkUseSpecific.SetState(i < 0 ? 0 : !m_info[i].usePrevious); + + etdMsg.SetText(i < 0 ? L"" : m_info[i].msg); + + chkNoDialog.Enable(i < 0 ? 0 : !m_info[i].ignore); + chkUsePrev.Enable(i < 0 ? 0 : !m_info[i].ignore); + chkUseSpecific.Enable(i < 0 ? 0 : !m_info[i].ignore); + etdMsg.Enable(i < 0 ? 0 : !(m_info[i].ignore || m_info[i].usePrevious)); + oldPage = i; + } +}; + +int AwayMsgOptInitialise(WPARAM wParam, LPARAM) +{ + if (protoModeMsgFlags == 0) + return 0; + + OPTIONSDIALOGPAGE odp = {}; + odp.flags = ODPF_BOLDGROUPS; + odp.position = 870000000; + odp.szTitle.a = LPGEN("Status messages"); + odp.szGroup.a = LPGEN("Status"); + odp.pDialog = new CAwayMsgOptsDlg(); + g_plugin.addOptions(wParam, &odp); + return 0; +} diff --git a/src/core/stdaway/src/sendmsg.cpp b/src/core/stdaway/src/sendmsg.cpp index 1eaaac5cc4..dff644a928 100644 --- a/src/core/stdaway/src/sendmsg.cpp +++ b/src/core/stdaway/src/sendmsg.cpp @@ -2,7 +2,7 @@ Miranda NG: the free IM client for Microsoft* Windows* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org), +Copyright (C) 2012-23 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. diff --git a/src/core/stdaway/src/stdafx.h b/src/core/stdaway/src/stdafx.h index 4cd3dd5b24..83d5a859c9 100644 --- a/src/core/stdaway/src/stdafx.h +++ b/src/core/stdaway/src/stdafx.h @@ -2,7 +2,7 @@ Miranda NG: the free IM client for Microsoft* Windows* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org), +Copyright (C) 2012-23 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. diff --git a/src/core/stdaway/src/version.h b/src/core/stdaway/src/version.h index 1cbc94e44c..03131a5179 100644 --- a/src/core/stdaway/src/version.h +++ b/src/core/stdaway/src/version.h @@ -8,4 +8,4 @@ #define __DESCRIPTION "Core module for the away messages processing." #define __AUTHOR "Miranda NG team" #define __AUTHORWEB "https://miranda-ng.org/p/StdAway" -#define __COPYRIGHT "© 2012-22 Miranda NG team" +#define __COPYRIGHT "© 2012-23 Miranda NG team" diff --git a/src/core/stdclist/src/clc.h b/src/core/stdclist/src/clc.h index 9ecb9767af..c5a6581b38 100644 --- a/src/core/stdclist/src/clc.h +++ b/src/core/stdclist/src/clc.h @@ -2,7 +2,7 @@ Miranda NG: the free IM client for Microsoft* Windows* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org), +Copyright (C) 2012-23 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. diff --git a/src/core/stdclist/src/clcfonts.cpp b/src/core/stdclist/src/clcfonts.cpp index c5c4af1a9a..e435026332 100644 --- a/src/core/stdclist/src/clcfonts.cpp +++ b/src/core/stdclist/src/clcfonts.cpp @@ -2,7 +2,7 @@ Miranda NG: the free IM client for Microsoft* Windows* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org), +Copyright (C) 2012-23 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. diff --git a/src/core/stdclist/src/clcopts.cpp b/src/core/stdclist/src/clcopts.cpp index 688fba0c86..077cd80ca0 100644 --- a/src/core/stdclist/src/clcopts.cpp +++ b/src/core/stdclist/src/clcopts.cpp @@ -2,7 +2,7 @@ Miranda NG: the free IM client for Microsoft* Windows* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org), +Copyright (C) 2012-23 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. diff --git a/src/core/stdclist/src/clcpaint.cpp b/src/core/stdclist/src/clcpaint.cpp index 9bf6af7581..d2e59b1878 100644 --- a/src/core/stdclist/src/clcpaint.cpp +++ b/src/core/stdclist/src/clcpaint.cpp @@ -2,7 +2,7 @@ Miranda NG: the free IM client for Microsoft* Windows* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org), +Copyright (C) 2012-23 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. diff --git a/src/core/stdclist/src/clistmenus.cpp b/src/core/stdclist/src/clistmenus.cpp index 7d10154fde..57da5b4f22 100644 --- a/src/core/stdclist/src/clistmenus.cpp +++ b/src/core/stdclist/src/clistmenus.cpp @@ -2,7 +2,7 @@ Miranda NG: the free IM client for Microsoft* Windows* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org), +Copyright (C) 2012-23 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. diff --git a/src/core/stdclist/src/clistopts.cpp b/src/core/stdclist/src/clistopts.cpp index 29683b6506..3a6f435e24 100644 --- a/src/core/stdclist/src/clistopts.cpp +++ b/src/core/stdclist/src/clistopts.cpp @@ -2,7 +2,7 @@ Miranda NG: the free IM client for Microsoft* Windows* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org), +Copyright (C) 2012-23 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. diff --git a/src/core/stdclist/src/cluiopts.cpp b/src/core/stdclist/src/cluiopts.cpp index 785c0605b1..4816b59b7f 100644 --- a/src/core/stdclist/src/cluiopts.cpp +++ b/src/core/stdclist/src/cluiopts.cpp @@ -2,7 +2,7 @@ Miranda NG: the free IM client for Microsoft* Windows* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org), +Copyright (C) 2012-23 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. diff --git a/src/core/stdclist/src/contact.cpp b/src/core/stdclist/src/contact.cpp index daba1cdc61..cf9ba02cb7 100644 --- a/src/core/stdclist/src/contact.cpp +++ b/src/core/stdclist/src/contact.cpp @@ -2,7 +2,7 @@ Miranda NG: the free IM client for Microsoft* Windows* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org), +Copyright (C) 2012-23 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. diff --git a/src/core/stdclist/src/init.cpp b/src/core/stdclist/src/init.cpp index 3ca412c5f7..f379863284 100644 --- a/src/core/stdclist/src/init.cpp +++ b/src/core/stdclist/src/init.cpp @@ -2,7 +2,7 @@ Miranda NG: the free IM client for Microsoft* Windows* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org), +Copyright (C) 2012-23 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. diff --git a/src/core/stdclist/src/stdafx.cxx b/src/core/stdclist/src/stdafx.cxx index f64d25234b..ebbde0ade1 100644 --- a/src/core/stdclist/src/stdafx.cxx +++ b/src/core/stdclist/src/stdafx.cxx @@ -1,5 +1,5 @@ /* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org) +Copyright (C) 2012-23 Miranda NG team (https://miranda-ng.org) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/src/core/stdclist/src/stdafx.h b/src/core/stdclist/src/stdafx.h index d50af5e471..62b233fe55 100644 --- a/src/core/stdclist/src/stdafx.h +++ b/src/core/stdclist/src/stdafx.h @@ -2,7 +2,7 @@ Miranda NG: the free IM client for Microsoft* Windows* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org), +Copyright (C) 2012-23 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. diff --git a/src/core/stdclist/src/version.h b/src/core/stdclist/src/version.h index 1b178cd258..a652e79523 100644 --- a/src/core/stdclist/src/version.h +++ b/src/core/stdclist/src/version.h @@ -9,4 +9,4 @@ #define __DESCRIPTION "Core module for displaying contacts." #define __AUTHOR "Miranda NG team" #define __AUTHORWEB "https://miranda-ng.org/p/StdClist" -#define __COPYRIGHT "© 2012-22 Miranda NG team" +#define __COPYRIGHT "© 2012-23 Miranda NG team" diff --git a/src/core/stdcrypt/src/encrypt.cpp b/src/core/stdcrypt/src/encrypt.cpp index e9689aa374..9d605848a2 100644 --- a/src/core/stdcrypt/src/encrypt.cpp +++ b/src/core/stdcrypt/src/encrypt.cpp @@ -2,7 +2,7 @@ Miranda NG: the free IM client for Microsoft* Windows* -Copyright (C) 2012-22 Miranda NG team, +Copyright (C) 2012-23 Miranda NG team, all portions of this codebase are copyrighted to the people listed in contributors.txt. diff --git a/src/core/stdcrypt/src/main.cpp b/src/core/stdcrypt/src/main.cpp index bc53c00f54..e1dc9218a6 100644 --- a/src/core/stdcrypt/src/main.cpp +++ b/src/core/stdcrypt/src/main.cpp @@ -1,7 +1,7 @@ /* Standard encryption plugin for Miranda NG -Copyright (C) 2012-22 George Hazan +Copyright (C) 2012-23 George Hazan 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 diff --git a/src/core/stdcrypt/src/stdafx.h b/src/core/stdcrypt/src/stdafx.h index 1ea23e6c16..4b6c1e7319 100644 --- a/src/core/stdcrypt/src/stdafx.h +++ b/src/core/stdcrypt/src/stdafx.h @@ -2,7 +2,7 @@ Miranda NG: the free IM client for Microsoft* Windows* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org), +Copyright (C) 2012-23 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. diff --git a/src/core/stdcrypt/src/stdcrypt.h b/src/core/stdcrypt/src/stdcrypt.h index 791e827d1a..3966a81631 100644 --- a/src/core/stdcrypt/src/stdcrypt.h +++ b/src/core/stdcrypt/src/stdcrypt.h @@ -1,7 +1,7 @@ /* Standard encryption plugin for Miranda NG -Copyright (C) 2012-22 George Hazan +Copyright (C) 2012-23 George Hazan 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 diff --git a/src/core/stdcrypt/src/utils.cpp b/src/core/stdcrypt/src/utils.cpp index fd5b3cff22..a3279e805e 100644 --- a/src/core/stdcrypt/src/utils.cpp +++ b/src/core/stdcrypt/src/utils.cpp @@ -2,7 +2,7 @@ Miranda NG: the free IM client for Microsoft* Windows* -Copyright (C) 2012-22 Miranda NG team, +Copyright (C) 2012-23 Miranda NG team, all portions of this codebase are copyrighted to the people listed in contributors.txt. diff --git a/src/core/stdcrypt/src/version.h b/src/core/stdcrypt/src/version.h index 6f6d4f9c96..30de347877 100644 --- a/src/core/stdcrypt/src/version.h +++ b/src/core/stdcrypt/src/version.h @@ -8,4 +8,4 @@ #define __DESCRIPTION "Core module for encryption." #define __AUTHOR "Miranda NG team" #define __AUTHORWEB "https://miranda-ng.org/p/StdCrypt" -#define __COPYRIGHT "© 2012-22 Miranda NG team" +#define __COPYRIGHT "© 2012-23 Miranda NG team" diff --git a/src/core/stdemail/src/email.cpp b/src/core/stdemail/src/email.cpp index b6c68d672f..0f40657fff 100644 --- a/src/core/stdemail/src/email.cpp +++ b/src/core/stdemail/src/email.cpp @@ -2,7 +2,7 @@ Miranda NG: the free IM client for Microsoft* Windows* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org), +Copyright (C) 2012-23 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. diff --git a/src/core/stdemail/src/main.cpp b/src/core/stdemail/src/main.cpp index 344e9501a9..19aaf95380 100644 --- a/src/core/stdemail/src/main.cpp +++ b/src/core/stdemail/src/main.cpp @@ -2,7 +2,7 @@ Standard e-mail urls launcher for Miranda NG -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org) +Copyright (C) 2012-23 Miranda NG team (https://miranda-ng.org) 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 diff --git a/src/core/stdemail/src/stdafx.h b/src/core/stdemail/src/stdafx.h index 8214c32bfe..4520b2f62f 100644 --- a/src/core/stdemail/src/stdafx.h +++ b/src/core/stdemail/src/stdafx.h @@ -2,7 +2,7 @@ Miranda NG: the free IM client for Microsoft* Windows* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org), +Copyright (C) 2012-23 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. diff --git a/src/core/stdemail/src/version.h b/src/core/stdemail/src/version.h index a158424f02..dd12d45a66 100644 --- a/src/core/stdemail/src/version.h +++ b/src/core/stdemail/src/version.h @@ -8,4 +8,4 @@ #define __DESCRIPTION "Core module for e-mail urls handling." #define __AUTHOR "Miranda NG team" #define __AUTHORWEB "https://miranda-ng.org/p/StdEmail" -#define __COPYRIGHT "© 2012-22 Miranda NG team" +#define __COPYRIGHT "© 2012-23 Miranda NG team" diff --git a/src/core/stdfile/src/file.cpp b/src/core/stdfile/src/file.cpp index 8dcb922619..234f84404f 100644 --- a/src/core/stdfile/src/file.cpp +++ b/src/core/stdfile/src/file.cpp @@ -2,7 +2,7 @@ Miranda NG: the free IM client for Microsoft* Windows* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org), +Copyright (C) 2012-23 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. diff --git a/src/core/stdfile/src/file.h b/src/core/stdfile/src/file.h index b89671ab8a..2bdddb04e5 100644 --- a/src/core/stdfile/src/file.h +++ b/src/core/stdfile/src/file.h @@ -2,7 +2,7 @@ Miranda NG: the free IM client for Microsoft* Windows* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org), +Copyright (C) 2012-23 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. diff --git a/src/core/stdfile/src/fileexistsdlg.cpp b/src/core/stdfile/src/fileexistsdlg.cpp index bd715cfa24..c2e4f6dfa8 100644 --- a/src/core/stdfile/src/fileexistsdlg.cpp +++ b/src/core/stdfile/src/fileexistsdlg.cpp @@ -2,7 +2,7 @@ Miranda NG: the free IM client for Microsoft* Windows* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org), +Copyright (C) 2012-23 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. diff --git a/src/core/stdfile/src/fileopts.cpp b/src/core/stdfile/src/fileopts.cpp index f5385174e1..f0d9e1bda2 100644 --- a/src/core/stdfile/src/fileopts.cpp +++ b/src/core/stdfile/src/fileopts.cpp @@ -2,7 +2,7 @@ Miranda NG: the free IM client for Microsoft* Windows* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org), +Copyright (C) 2012-23 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. diff --git a/src/core/stdfile/src/filerecvdlg.cpp b/src/core/stdfile/src/filerecvdlg.cpp index 54aefe44c5..7a364e210e 100644 --- a/src/core/stdfile/src/filerecvdlg.cpp +++ b/src/core/stdfile/src/filerecvdlg.cpp @@ -2,7 +2,7 @@ Miranda NG: the free IM client for Microsoft* Windows* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org), +Copyright (C) 2012-23 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. diff --git a/src/core/stdfile/src/filesenddlg.cpp b/src/core/stdfile/src/filesenddlg.cpp index 017725e89d..024cf68129 100644 --- a/src/core/stdfile/src/filesenddlg.cpp +++ b/src/core/stdfile/src/filesenddlg.cpp @@ -2,7 +2,7 @@ Miranda NG: the free IM client for Microsoft* Windows* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org), +Copyright (C) 2012-23 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. diff --git a/src/core/stdfile/src/filexferdlg.cpp b/src/core/stdfile/src/filexferdlg.cpp index bcd6c16c54..32ef89ecf3 100644 --- a/src/core/stdfile/src/filexferdlg.cpp +++ b/src/core/stdfile/src/filexferdlg.cpp @@ -1,765 +1,765 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (C) 2012-22 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" -#include -#include "file.h" - -static int CheckVirusScanned(HWND hwnd, FileDlgData *dat, int i) -{ - if (dat->send) return 1; - if (dat->fileVirusScanned == nullptr) return 0; - if (dat->fileVirusScanned[i]) return 1; - if (g_plugin.getByte("WarnBeforeOpening", 1) == 0) return 1; - - return IDYES == MessageBox(hwnd, - TranslateT("This file has not yet been scanned for viruses. Are you certain you want to open it?"), - TranslateT("File received"), - MB_YESNO | MB_DEFBUTTON2); -} - -#define M_VIRUSSCANDONE (WM_USER+100) -struct virusscanthreadstartinfo -{ - wchar_t *szFile; - int returnCode; - HWND hwndReply; -}; - -wchar_t* PFTS_StringToTchar(int flags, const wchar_t *s) -{ - if (flags & PFTS_UTF) - return mir_utf8decodeW((char*)s); - if (flags & PFTS_UNICODE) - return mir_wstrdup(s); - return mir_a2u((char*)s); -} - -int PFTS_CompareWithTchar(PROTOFILETRANSFERSTATUS *ft, const wchar_t *s, wchar_t *r) -{ - if (ft->flags & PFTS_UTF) { - wchar_t *ts = mir_utf8decodeW((char*)s); - int res = mir_wstrcmp(ts, r); - mir_free(ts); - return res; - } - if (ft->flags & PFTS_UNICODE) - return mir_wstrcmp(s, r); - - wchar_t *ts = mir_a2u((char*)s); - int res = mir_wstrcmp(ts, r); - mir_free(ts); - return res; -} - -static void SetOpenFileButtonStyle(HWND hwndButton, int enabled) -{ - EnableWindow(hwndButton, enabled); -} - -void FillSendData(FileDlgData *dat, DBEVENTINFO &dbei) -{ - dbei.szModule = Proto_GetBaseAccountName(dat->hContact); - dbei.eventType = EVENTTYPE_FILE; - dbei.flags = DBEF_SENT; - dbei.timestamp = time(0); - char *szFileNames = mir_utf8encodeW(dat->szFilenames), *szMsg = mir_utf8encodeW(dat->szMsg); - dbei.flags |= DBEF_UTF; - - dbei.cbBlob = int(sizeof(uint32_t) + mir_strlen(szFileNames) + mir_strlen(szMsg) + 2); - dbei.pBlob = (uint8_t*)mir_alloc(dbei.cbBlob); - *(PDWORD)dbei.pBlob = 0; - mir_strcpy((char*)dbei.pBlob + sizeof(uint32_t), szFileNames); - mir_strcpy((char*)dbei.pBlob + sizeof(uint32_t) + mir_strlen(szFileNames) + 1, szMsg); - - mir_free(szFileNames), mir_free(szMsg); -} - -static void __cdecl RunVirusScannerThread(virusscanthreadstartinfo *info) -{ - DBVARIANT dbv; - if (!g_plugin.getWString("ScanCmdLine", &dbv)) { - if (dbv.pwszVal[0]) { - STARTUPINFO si = { 0 }; - si.cb = sizeof(si); - wchar_t *pszReplace = wcsstr(dbv.pwszVal, L"%f"); - wchar_t szCmdLine[768]; - if (pszReplace) { - if (info->szFile[mir_wstrlen(info->szFile) - 1] == '\\') - info->szFile[mir_wstrlen(info->szFile) - 1] = '\0'; - *pszReplace = 0; - mir_snwprintf(szCmdLine, L"%s\"%s\"%s", dbv.pwszVal, info->szFile, pszReplace + 2); - } - else - wcsncpy_s(szCmdLine, dbv.pwszVal, _TRUNCATE); - - PROCESS_INFORMATION pi; - if (CreateProcess(nullptr, szCmdLine, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi)) { - if (WaitForSingleObject(pi.hProcess, 3600 * 1000) == WAIT_OBJECT_0) - PostMessage(info->hwndReply, M_VIRUSSCANDONE, info->returnCode, 0); - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - } - } - db_free(&dbv); - } - mir_free(info->szFile); - mir_free(info); -} - -static void SetFilenameControls(HWND hwndDlg, FileDlgData *dat, PROTOFILETRANSFERSTATUS *fts) -{ - wchar_t msg[MAX_PATH]; - wchar_t *fnbuf = nullptr, *fn = nullptr; - SHFILEINFO shfi = {}; - - if (fts->szCurrentFile.w) { - fnbuf = mir_wstrdup(fts->szCurrentFile.w); - if ((fn = wcsrchr(fnbuf, '\\')) == nullptr) - fn = fnbuf; - else fn++; - } - - if (dat->hIcon) DestroyIcon(dat->hIcon); dat->hIcon = nullptr; - - if (fn && (fts->totalFiles > 1)) { - mir_snwprintf(msg, L"%s: %s (%d %s %d)", Clist_GetContactDisplayName(fts->hContact), fn, fts->currentFileNumber + 1, TranslateT("of"), fts->totalFiles); - - SHGetFileInfo(fn, FILE_ATTRIBUTE_DIRECTORY, &shfi, sizeof(shfi), SHGFI_USEFILEATTRIBUTES | SHGFI_ICON | SHGFI_SMALLICON); - dat->hIcon = shfi.hIcon; - } - else if (fn) { - mir_snwprintf(msg, L"%s: %s", Clist_GetContactDisplayName(fts->hContact), fn); - - SHGetFileInfo(fn, FILE_ATTRIBUTE_NORMAL, &shfi, sizeof(shfi), SHGFI_USEFILEATTRIBUTES | SHGFI_ICON | SHGFI_SMALLICON); - dat->hIcon = shfi.hIcon; - } - else { - mir_wstrncpy(msg, Clist_GetContactDisplayName(fts->hContact), _countof(msg)); - HICON hIcon = Skin_LoadIcon(SKINICON_OTHER_DOWNARROW); - dat->hIcon = CopyIcon(hIcon); - IcoLib_ReleaseIcon(hIcon, NULL); - } - - mir_free(fnbuf); - - SendDlgItemMessage(hwndDlg, IDC_FILEICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)dat->hIcon); - SetDlgItemText(hwndDlg, IDC_CONTACTNAME, msg); -} - -enum { FTS_TEXT, FTS_PROGRESS, FTS_OPEN }; -static void SetFtStatus(HWND hwndDlg, wchar_t *text, int mode) -{ - SetDlgItemText(hwndDlg, IDC_STATUS, TranslateW(text)); - SetDlgItemText(hwndDlg, IDC_TRANSFERCOMPLETED, TranslateW(text)); - - ShowWindow(GetDlgItem(hwndDlg, IDC_STATUS), (mode == FTS_TEXT) ? SW_SHOW : SW_HIDE); - ShowWindow(GetDlgItem(hwndDlg, IDC_ALLFILESPROGRESS), (mode == FTS_PROGRESS) ? SW_SHOW : SW_HIDE); - ShowWindow(GetDlgItem(hwndDlg, IDC_TRANSFERCOMPLETED), (mode == FTS_OPEN) ? SW_SHOW : SW_HIDE); - ShowWindow(GetDlgItem(hwndDlg, IDC_FILEICON), (mode == FTS_OPEN) ? SW_SHOW : SW_HIDE); -} - -static void HideProgressControls(HWND hwndDlg) -{ - RECT rc; - char buf[64]; - - GetWindowRect(GetDlgItem(hwndDlg, IDC_ALLPRECENTS), &rc); - MapWindowPoints(nullptr, hwndDlg, (LPPOINT)&rc, 2); - SetWindowPos(hwndDlg, nullptr, 0, 0, 100, rc.bottom + 3, SWP_NOMOVE | SWP_NOZORDER); - ShowWindow(GetDlgItem(hwndDlg, IDC_ALLTRANSFERRED), SW_HIDE); - ShowWindow(GetDlgItem(hwndDlg, IDC_ALLSPEED), SW_HIDE); - - _strtime(buf); - SetDlgItemTextA(hwndDlg, IDC_ALLPRECENTS, buf); - - PostMessage(GetParent(hwndDlg), WM_FT_RESIZE, 0, (LPARAM)hwndDlg); -} - -static int FileTransferDlgResizer(HWND, LPARAM param, UTILRESIZECONTROL *urc) -{ - auto *dat = (FileDlgData *)param; - - switch (urc->wId) { - case IDC_CONTACTNAME: - case IDC_STATUS: - case IDC_ALLFILESPROGRESS: - case IDC_TRANSFERCOMPLETED: - return RD_ANCHORX_WIDTH | RD_ANCHORY_TOP; - - case IDC_FRAME: - return RD_ANCHORX_WIDTH | RD_ANCHORY_BOTTOM; - case IDC_ALLPRECENTS: - case IDCANCEL: - case IDC_OPENFILE: - case IDC_OPENFOLDER: - return RD_ANCHORX_RIGHT | RD_ANCHORY_TOP; - - case IDC_ALLTRANSFERRED: - if (dat->waitingForAcceptance) - return RD_ANCHORX_WIDTH | RD_ANCHORY_TOP; - - urc->rcItem.right = urc->rcItem.left + (urc->rcItem.right - urc->rcItem.left - urc->dlgOriginalSize.cx + urc->dlgNewSize.cx) / 3; - return RD_ANCHORX_CUSTOM | RD_ANCHORY_TOP; - - case IDC_ALLSPEED: - if (dat->waitingForAcceptance) - return RD_ANCHORX_RIGHT | RD_ANCHORY_TOP; - - urc->rcItem.right = urc->rcItem.right - urc->dlgOriginalSize.cx + urc->dlgNewSize.cx; - urc->rcItem.left = urc->rcItem.left + (urc->rcItem.right - urc->rcItem.left) / 3; - return RD_ANCHORX_CUSTOM | RD_ANCHORY_TOP; - } - return RD_ANCHORX_LEFT | RD_ANCHORY_TOP; -} - -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)ProtoChainSend(dat->hContact, PSS_FILE, (WPARAM)dat->szMsg, (LPARAM)dat->files); - SetFtStatus(hwndDlg, LPGENW("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 - CreateDirectoryTreeW(dat->szSavePath); - dat->fs = (HANDLE)ProtoChainSend(dat->hContact, PSS_FILEALLOW, (WPARAM)dat->fs, (LPARAM)dat->szSavePath); - dat->transferStatus.szWorkingDir.w = mir_wstrdup(dat->szSavePath); - if (!Contact::OnList(dat->hContact)) - dat->resumeBehaviour = FILERESUME_ASK; - else - dat->resumeBehaviour = g_plugin.getByte("IfExists", FILERESUME_ASK); - SetFtStatus(hwndDlg, LPGENW("Waiting for connection..."), FTS_TEXT); - } - - /* check we actually got an fs handle back from the protocol */ - if (!dat->fs) { - SetFtStatus(hwndDlg, LPGENW("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 = {}; - SHGetFileInfo(L"", FILE_ATTRIBUTE_DIRECTORY, &shfi, sizeof(shfi), SHGFI_USEFILEATTRIBUTES | SHGFI_ICON | SHGFI_SMALLICON); - dat->hIconFolder = shfi.hIcon; - } - dat->hIcon = nullptr; - { - char *szProto = Proto_GetBaseAccountName(dat->hContact); - uint16_t 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_SetSkin_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_SetSkin_IcoLib(hwndDlg, IDCANCEL, SKINICON_OTHER_DELETE, LPGEN("Cancel")); - - SetDlgItemText(hwndDlg, IDC_CONTACTNAME, Clist_GetContactDisplayName(dat->hContact)); - - if (!dat->waitingForAcceptance) - SetTimer(hwndDlg, 1, 1000, nullptr); - 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++; - - wchar_t 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_wstrcpy(szTime, L"??:??:??"); - else { - li.QuadPart = 10000000ll * (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 = 10000000ll * (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_snwprintf(szDisplay, L"%s/%s (%s %s)", szSpeed, TranslateT("sec"), szTime, TranslateT("remaining")); - SetDlgItemText(hwndDlg, IDC_ALLSPEED, szDisplay); - break; - - case WM_MEASUREITEM: - return Menu_MeasureItem(lParam); - - case WM_DRAWITEM: - return Menu_DrawItem(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 (Clist_MenuProcessCommand(LOWORD(wParam), MPCF_CONTACTMENU, 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: - { - wchar_t *path = dat->transferStatus.szWorkingDir.w; - if (!path || !path[0]) { - path = NEWWSTR_ALLOCA(dat->transferStatus.szCurrentFile.w); - wchar_t *p = wcsrchr(path, '\\'); if (p) *p = 0; - } - - if (path) ShellExecute(NULL, L"open", path, NULL, NULL, SW_SHOW); - } - break; - - case IDC_OPENFILE: - wchar_t **files; - if (dat->send) { - if (dat->files == nullptr) - files = dat->transferStatus.pszFiles.w; - else - files = dat->files; - } - else files = dat->files; - - HMENU hMenu = CreatePopupMenu(); - AppendMenu(hMenu, MF_STRING, 1, TranslateT("Open folder")); - AppendMenu(hMenu, MF_SEPARATOR, 0, nullptr); - - if (files && *files) { - int limit; - wchar_t *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 = wcsrchr(files[i], '\\'); - if (pszFilename == nullptr) - pszFilename = files[i]; - else - pszFilename++; - - if (pszFilename) { - size_t cbFileNameLen = mir_wstrlen(pszFilename); - - pszNewFileName = (wchar_t*)mir_alloc(cbFileNameLen * 2 * sizeof(wchar_t)); - wchar_t *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, nullptr); - CheckDlgButton(hwndDlg, IDC_OPENFILE, BST_UNCHECKED); - DestroyMenu(hMenu); - - if (ret == 1) { - wchar_t *path = dat->transferStatus.szWorkingDir.w; - if (!path || !path[0]) { - path = NEWWSTR_ALLOCA(dat->transferStatus.szCurrentFile.w); - wchar_t *p = wcsrchr(path, '\\'); - if (p) - *p = 0; - } - - if (path) ShellExecute(nullptr, L"open", path, nullptr, nullptr, SW_SHOW); - } - else if (ret && CheckVirusScanned(hwndDlg, dat, ret)) - ShellExecute(nullptr, nullptr, files[ret - 10], nullptr, nullptr, SW_SHOW); - } - break; - - case M_FILEEXISTSDLGREPLY: - EnableWindow(hwndDlg, TRUE); - { - PROTOFILERESUME *pfr = (PROTOFILERESUME *)lParam; - wchar_t *szOriginalFilename = (wchar_t *)wParam; - char *szProto = Proto_GetBaseAccountName(dat->hContact); - - switch (pfr->action) { - case FILERESUME_CANCEL: - if (dat->fs) ProtoChainSend(dat->hContact, PSS_FILECANCEL, (WPARAM)dat->fs, 0); - dat->fs = nullptr; - 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; - { - wchar_t *pszExtension, *pszFilename; - if ((pszFilename = wcsrchr(szOriginalFilename, '\\')) == nullptr) pszFilename = szOriginalFilename; - if ((pszExtension = wcsrchr(pszFilename + 1, '.')) == nullptr) pszExtension = pszFilename + mir_wstrlen(pszFilename); - if (pfr->szFilename) mir_free((wchar_t *)pfr->szFilename); - size_t size = (pszExtension - szOriginalFilename) + 21 + mir_wstrlen(pszExtension); - pfr->szFilename = (wchar_t *)mir_alloc(sizeof(wchar_t) * size); - for (int i = 1;; i++) { - mir_snwprintf((wchar_t *)pfr->szFilename, size, L"%.*s (%u)%s", pszExtension - szOriginalFilename, szOriginalFilename, i, pszExtension); - if (_waccess(pfr->szFilename, 0) != 0) - break; - } - } - break; - } - mir_free(szOriginalFilename); - CallProtoService(szProto, PS_FILERESUME, (WPARAM)dat->fs, (LPARAM)pfr); - delete 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, nullptr); - dat->waitingForAcceptance = 0; - } - - switch (ack->result) { - case ACKRESULT_SENTREQUEST: SetFtStatus(hwndDlg, LPGENW("Decision sent"), FTS_TEXT); break; - case ACKRESULT_CONNECTING: SetFtStatus(hwndDlg, LPGENW("Connecting..."), FTS_TEXT); break; - case ACKRESULT_CONNECTPROXY: SetFtStatus(hwndDlg, LPGENW("Connecting to proxy..."), FTS_TEXT); break; - case ACKRESULT_CONNECTED: SetFtStatus(hwndDlg, LPGENW("Connected"), FTS_TEXT); break; - case ACKRESULT_LISTENING: SetFtStatus(hwndDlg, LPGENW("Waiting for connection..."), FTS_TEXT); break; - case ACKRESULT_INITIALISING: SetFtStatus(hwndDlg, LPGENW("Initializing..."), FTS_TEXT); break; - case ACKRESULT_NEXTFILE: - SetFtStatus(hwndDlg, LPGENW("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 && g_plugin.getByte("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 = (virusscanthreadstartinfo *)mir_alloc(sizeof(virusscanthreadstartinfo)); - vstsi->hwndReply = hwndDlg; - vstsi->szFile = mir_wstrdup(dat->files[dat->transferStatus.currentFileNumber]); - vstsi->returnCode = dat->transferStatus.currentFileNumber; - mir_forkThread(RunVirusScannerThread, vstsi); - } - } - break; - - case ACKRESULT_FILERESUME: - UpdateProtoFileTransferStatus(&dat->transferStatus, (PROTOFILETRANSFERSTATUS *)ack->lParam); - { - PROTOFILETRANSFERSTATUS *fts = &dat->transferStatus; - SetFilenameControls(hwndDlg, dat, fts); - if (_waccess(fts->szCurrentFile.w, 0)) - break; - - SetFtStatus(hwndDlg, LPGENW("File already exists"), FTS_TEXT); - if (dat->resumeBehaviour == FILERESUME_ASK) { - TDlgProcFileExistsParam param = { hwndDlg, fts }; - ShowWindow(hwndDlg, SW_SHOWNORMAL); - CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_FILEEXISTS), hwndDlg, DlgProcFileExists, (LPARAM)¶m); - EnableWindow(hwndDlg, FALSE); - } - else { - PROTOFILERESUME *pfr = new PROTOFILERESUME(); - pfr->action = dat->resumeBehaviour; - pfr->szFilename = nullptr; - PostMessage(hwndDlg, M_FILEEXISTSDLGREPLY, (WPARAM)mir_wstrdup(fts->szCurrentFile.w), (LPARAM)pfr); - } - } - SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, 1); - return TRUE; - - case ACKRESULT_DATA: - { - PROTOFILETRANSFERSTATUS *fts = (PROTOFILETRANSFERSTATUS *)ack->lParam; - wchar_t str[64], str2[64], szSizeDone[32], szSizeTotal[32];//, *contactName; - - if (dat->fileVirusScanned == nullptr) - 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 == nullptr) - dat->files = (wchar_t **)mir_calloc((fts->totalFiles + 1) * sizeof(wchar_t *)); - if (fts->currentFileNumber < fts->totalFiles && dat->files[fts->currentFileNumber] == nullptr) - dat->files[fts->currentFileNumber] = PFTS_StringToTchar(fts->flags, fts->szCurrentFile.w); - } - - /* 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) ? LPGENW("Sending...") : LPGENW("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 ? (100ll * fts->totalProgress / fts->totalBytes) : 0; - if (lastPos != nextPos || firstTime) { - SendDlgItemMessage(hwndDlg, IDC_ALLFILESPROGRESS, PBM_SETPOS, nextPos, 0); - mir_snwprintf(str, L"%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_snwprintf(str, L"%s/%s", szSizeDone, szSizeTotal); - str2[0] = 0; - GetDlgItemText(hwndDlg, IDC_ALLTRANSFERRED, str2, _countof(str2)); - if (mir_wstrcmp(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 = nullptr; - - if (ack->result == ACKRESULT_DENIED) { - dat->fs = nullptr; /* protocol will free structure */ - Skin_PlaySound("FileDenied"); - SetFtStatus(hwndDlg, LPGENW("File transfer denied"), FTS_TEXT); - } - else if (ack->result == ACKRESULT_FAILED) { - dat->fs = nullptr; /* protocol will free structure */ - Skin_PlaySound("FileFailed"); - SetFtStatus(hwndDlg, LPGENW("File transfer failed"), FTS_TEXT); - } - else { - Skin_PlaySound("FileDone"); - if (dat->send) { - dat->fs = nullptr; /* protocol will free structure */ - SetFtStatus(hwndDlg, LPGENW("Transfer completed."), FTS_TEXT); - - DBEVENTINFO dbei = {}; - FillSendData(dat, dbei); - db_event_add(dat->hContact, &dbei); - if (dbei.pBlob) - mir_free(dbei.pBlob); - dat->files = nullptr; //protocol library frees this - } - else { - SetFtStatus(hwndDlg, - (dat->transferStatus.totalFiles == 1) ? - LPGENW("Transfer completed, open file.") : - LPGENW("Transfer completed, open folder."), - FTS_OPEN); - - int useScanner = g_plugin.getByte("UseScanner", VIRUSSCAN_DISABLE); - if (useScanner != VIRUSSCAN_DISABLE) { - auto *vstsi = (virusscanthreadstartinfo *)mir_alloc(sizeof(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 = nullptr; - } - else vstsi->szFile = mir_wstrdup(dat->files[dat->transferStatus.currentFileNumber]); - } - else { - vstsi->szFile = mir_wstrdup(dat->transferStatus.szWorkingDir.w); - vstsi->returnCode = -1; - } - SetFtStatus(hwndDlg, LPGENW("Scanning for viruses..."), FTS_TEXT); - if (vstsi) - mir_forkThread(RunVirusScannerThread, vstsi); - } - else dat->fs = nullptr; /* protocol will free structure */ - - dat->transferStatus.currentFileNumber = dat->transferStatus.totalFiles; - } - } - - PostMessage(GetParent(hwndDlg), WM_FT_COMPLETED, ack->result, (LPARAM)hwndDlg); - break; - } - } - 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 = nullptr; /* protocol will free structure */ - SetFtStatus(hwndDlg, LPGENW("Transfer and virus scan complete"), FTS_TEXT); - } - } - break; - - case WM_SIZE: - Utils_ResizeDialog(hwndDlg, g_plugin.getInst(), MAKEINTRESOURCEA(IDD_FILETRANSFERINFO), FileTransferDlgResizer, LPARAM(dat)); - - 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); - - delete dat; - SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0); - break; - } - return FALSE; -} - -FileDlgData::~FileDlgData() -{ - if (fs) - ProtoChainSend(hContact, PSS_FILECANCEL, (WPARAM)fs, 0); - if (hPreshutdownEvent) - UnhookEvent(hPreshutdownEvent); - if (hNotifyEvent) - UnhookEvent(hNotifyEvent); - - FreeProtoFileTransferStatus(&transferStatus); - FreeFilesMatrix(&files); - - mir_free(fileVirusScanned); - if (hIcon) - DestroyIcon(hIcon); - if (hIconFolder) - DestroyIcon(hIconFolder); -} +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (C) 2012-23 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" +#include +#include "file.h" + +static int CheckVirusScanned(HWND hwnd, FileDlgData *dat, int i) +{ + if (dat->send) return 1; + if (dat->fileVirusScanned == nullptr) return 0; + if (dat->fileVirusScanned[i]) return 1; + if (g_plugin.getByte("WarnBeforeOpening", 1) == 0) return 1; + + return IDYES == MessageBox(hwnd, + TranslateT("This file has not yet been scanned for viruses. Are you certain you want to open it?"), + TranslateT("File received"), + MB_YESNO | MB_DEFBUTTON2); +} + +#define M_VIRUSSCANDONE (WM_USER+100) +struct virusscanthreadstartinfo +{ + wchar_t *szFile; + int returnCode; + HWND hwndReply; +}; + +wchar_t* PFTS_StringToTchar(int flags, const wchar_t *s) +{ + if (flags & PFTS_UTF) + return mir_utf8decodeW((char*)s); + if (flags & PFTS_UNICODE) + return mir_wstrdup(s); + return mir_a2u((char*)s); +} + +int PFTS_CompareWithTchar(PROTOFILETRANSFERSTATUS *ft, const wchar_t *s, wchar_t *r) +{ + if (ft->flags & PFTS_UTF) { + wchar_t *ts = mir_utf8decodeW((char*)s); + int res = mir_wstrcmp(ts, r); + mir_free(ts); + return res; + } + if (ft->flags & PFTS_UNICODE) + return mir_wstrcmp(s, r); + + wchar_t *ts = mir_a2u((char*)s); + int res = mir_wstrcmp(ts, r); + mir_free(ts); + return res; +} + +static void SetOpenFileButtonStyle(HWND hwndButton, int enabled) +{ + EnableWindow(hwndButton, enabled); +} + +void FillSendData(FileDlgData *dat, DBEVENTINFO &dbei) +{ + dbei.szModule = Proto_GetBaseAccountName(dat->hContact); + dbei.eventType = EVENTTYPE_FILE; + dbei.flags = DBEF_SENT; + dbei.timestamp = time(0); + char *szFileNames = mir_utf8encodeW(dat->szFilenames), *szMsg = mir_utf8encodeW(dat->szMsg); + dbei.flags |= DBEF_UTF; + + dbei.cbBlob = int(sizeof(uint32_t) + mir_strlen(szFileNames) + mir_strlen(szMsg) + 2); + dbei.pBlob = (uint8_t*)mir_alloc(dbei.cbBlob); + *(PDWORD)dbei.pBlob = 0; + mir_strcpy((char*)dbei.pBlob + sizeof(uint32_t), szFileNames); + mir_strcpy((char*)dbei.pBlob + sizeof(uint32_t) + mir_strlen(szFileNames) + 1, szMsg); + + mir_free(szFileNames), mir_free(szMsg); +} + +static void __cdecl RunVirusScannerThread(virusscanthreadstartinfo *info) +{ + DBVARIANT dbv; + if (!g_plugin.getWString("ScanCmdLine", &dbv)) { + if (dbv.pwszVal[0]) { + STARTUPINFO si = { 0 }; + si.cb = sizeof(si); + wchar_t *pszReplace = wcsstr(dbv.pwszVal, L"%f"); + wchar_t szCmdLine[768]; + if (pszReplace) { + if (info->szFile[mir_wstrlen(info->szFile) - 1] == '\\') + info->szFile[mir_wstrlen(info->szFile) - 1] = '\0'; + *pszReplace = 0; + mir_snwprintf(szCmdLine, L"%s\"%s\"%s", dbv.pwszVal, info->szFile, pszReplace + 2); + } + else + wcsncpy_s(szCmdLine, dbv.pwszVal, _TRUNCATE); + + PROCESS_INFORMATION pi; + if (CreateProcess(nullptr, szCmdLine, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &si, &pi)) { + if (WaitForSingleObject(pi.hProcess, 3600 * 1000) == WAIT_OBJECT_0) + PostMessage(info->hwndReply, M_VIRUSSCANDONE, info->returnCode, 0); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + } + } + db_free(&dbv); + } + mir_free(info->szFile); + mir_free(info); +} + +static void SetFilenameControls(HWND hwndDlg, FileDlgData *dat, PROTOFILETRANSFERSTATUS *fts) +{ + wchar_t msg[MAX_PATH]; + wchar_t *fnbuf = nullptr, *fn = nullptr; + SHFILEINFO shfi = {}; + + if (fts->szCurrentFile.w) { + fnbuf = mir_wstrdup(fts->szCurrentFile.w); + if ((fn = wcsrchr(fnbuf, '\\')) == nullptr) + fn = fnbuf; + else fn++; + } + + if (dat->hIcon) DestroyIcon(dat->hIcon); dat->hIcon = nullptr; + + if (fn && (fts->totalFiles > 1)) { + mir_snwprintf(msg, L"%s: %s (%d %s %d)", Clist_GetContactDisplayName(fts->hContact), fn, fts->currentFileNumber + 1, TranslateT("of"), fts->totalFiles); + + SHGetFileInfo(fn, FILE_ATTRIBUTE_DIRECTORY, &shfi, sizeof(shfi), SHGFI_USEFILEATTRIBUTES | SHGFI_ICON | SHGFI_SMALLICON); + dat->hIcon = shfi.hIcon; + } + else if (fn) { + mir_snwprintf(msg, L"%s: %s", Clist_GetContactDisplayName(fts->hContact), fn); + + SHGetFileInfo(fn, FILE_ATTRIBUTE_NORMAL, &shfi, sizeof(shfi), SHGFI_USEFILEATTRIBUTES | SHGFI_ICON | SHGFI_SMALLICON); + dat->hIcon = shfi.hIcon; + } + else { + mir_wstrncpy(msg, Clist_GetContactDisplayName(fts->hContact), _countof(msg)); + HICON hIcon = Skin_LoadIcon(SKINICON_OTHER_DOWNARROW); + dat->hIcon = CopyIcon(hIcon); + IcoLib_ReleaseIcon(hIcon, NULL); + } + + mir_free(fnbuf); + + SendDlgItemMessage(hwndDlg, IDC_FILEICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)dat->hIcon); + SetDlgItemText(hwndDlg, IDC_CONTACTNAME, msg); +} + +enum { FTS_TEXT, FTS_PROGRESS, FTS_OPEN }; +static void SetFtStatus(HWND hwndDlg, wchar_t *text, int mode) +{ + SetDlgItemText(hwndDlg, IDC_STATUS, TranslateW(text)); + SetDlgItemText(hwndDlg, IDC_TRANSFERCOMPLETED, TranslateW(text)); + + ShowWindow(GetDlgItem(hwndDlg, IDC_STATUS), (mode == FTS_TEXT) ? SW_SHOW : SW_HIDE); + ShowWindow(GetDlgItem(hwndDlg, IDC_ALLFILESPROGRESS), (mode == FTS_PROGRESS) ? SW_SHOW : SW_HIDE); + ShowWindow(GetDlgItem(hwndDlg, IDC_TRANSFERCOMPLETED), (mode == FTS_OPEN) ? SW_SHOW : SW_HIDE); + ShowWindow(GetDlgItem(hwndDlg, IDC_FILEICON), (mode == FTS_OPEN) ? SW_SHOW : SW_HIDE); +} + +static void HideProgressControls(HWND hwndDlg) +{ + RECT rc; + char buf[64]; + + GetWindowRect(GetDlgItem(hwndDlg, IDC_ALLPRECENTS), &rc); + MapWindowPoints(nullptr, hwndDlg, (LPPOINT)&rc, 2); + SetWindowPos(hwndDlg, nullptr, 0, 0, 100, rc.bottom + 3, SWP_NOMOVE | SWP_NOZORDER); + ShowWindow(GetDlgItem(hwndDlg, IDC_ALLTRANSFERRED), SW_HIDE); + ShowWindow(GetDlgItem(hwndDlg, IDC_ALLSPEED), SW_HIDE); + + _strtime(buf); + SetDlgItemTextA(hwndDlg, IDC_ALLPRECENTS, buf); + + PostMessage(GetParent(hwndDlg), WM_FT_RESIZE, 0, (LPARAM)hwndDlg); +} + +static int FileTransferDlgResizer(HWND, LPARAM param, UTILRESIZECONTROL *urc) +{ + auto *dat = (FileDlgData *)param; + + switch (urc->wId) { + case IDC_CONTACTNAME: + case IDC_STATUS: + case IDC_ALLFILESPROGRESS: + case IDC_TRANSFERCOMPLETED: + return RD_ANCHORX_WIDTH | RD_ANCHORY_TOP; + + case IDC_FRAME: + return RD_ANCHORX_WIDTH | RD_ANCHORY_BOTTOM; + case IDC_ALLPRECENTS: + case IDCANCEL: + case IDC_OPENFILE: + case IDC_OPENFOLDER: + return RD_ANCHORX_RIGHT | RD_ANCHORY_TOP; + + case IDC_ALLTRANSFERRED: + if (dat->waitingForAcceptance) + return RD_ANCHORX_WIDTH | RD_ANCHORY_TOP; + + urc->rcItem.right = urc->rcItem.left + (urc->rcItem.right - urc->rcItem.left - urc->dlgOriginalSize.cx + urc->dlgNewSize.cx) / 3; + return RD_ANCHORX_CUSTOM | RD_ANCHORY_TOP; + + case IDC_ALLSPEED: + if (dat->waitingForAcceptance) + return RD_ANCHORX_RIGHT | RD_ANCHORY_TOP; + + urc->rcItem.right = urc->rcItem.right - urc->dlgOriginalSize.cx + urc->dlgNewSize.cx; + urc->rcItem.left = urc->rcItem.left + (urc->rcItem.right - urc->rcItem.left) / 3; + return RD_ANCHORX_CUSTOM | RD_ANCHORY_TOP; + } + return RD_ANCHORX_LEFT | RD_ANCHORY_TOP; +} + +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)ProtoChainSend(dat->hContact, PSS_FILE, (WPARAM)dat->szMsg, (LPARAM)dat->files); + SetFtStatus(hwndDlg, LPGENW("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 + CreateDirectoryTreeW(dat->szSavePath); + dat->fs = (HANDLE)ProtoChainSend(dat->hContact, PSS_FILEALLOW, (WPARAM)dat->fs, (LPARAM)dat->szSavePath); + dat->transferStatus.szWorkingDir.w = mir_wstrdup(dat->szSavePath); + if (!Contact::OnList(dat->hContact)) + dat->resumeBehaviour = FILERESUME_ASK; + else + dat->resumeBehaviour = g_plugin.getByte("IfExists", FILERESUME_ASK); + SetFtStatus(hwndDlg, LPGENW("Waiting for connection..."), FTS_TEXT); + } + + /* check we actually got an fs handle back from the protocol */ + if (!dat->fs) { + SetFtStatus(hwndDlg, LPGENW("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 = {}; + SHGetFileInfo(L"", FILE_ATTRIBUTE_DIRECTORY, &shfi, sizeof(shfi), SHGFI_USEFILEATTRIBUTES | SHGFI_ICON | SHGFI_SMALLICON); + dat->hIconFolder = shfi.hIcon; + } + dat->hIcon = nullptr; + { + char *szProto = Proto_GetBaseAccountName(dat->hContact); + uint16_t 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_SetSkin_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_SetSkin_IcoLib(hwndDlg, IDCANCEL, SKINICON_OTHER_DELETE, LPGEN("Cancel")); + + SetDlgItemText(hwndDlg, IDC_CONTACTNAME, Clist_GetContactDisplayName(dat->hContact)); + + if (!dat->waitingForAcceptance) + SetTimer(hwndDlg, 1, 1000, nullptr); + 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++; + + wchar_t 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_wstrcpy(szTime, L"??:??:??"); + else { + li.QuadPart = 10000000ll * (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 = 10000000ll * (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_snwprintf(szDisplay, L"%s/%s (%s %s)", szSpeed, TranslateT("sec"), szTime, TranslateT("remaining")); + SetDlgItemText(hwndDlg, IDC_ALLSPEED, szDisplay); + break; + + case WM_MEASUREITEM: + return Menu_MeasureItem(lParam); + + case WM_DRAWITEM: + return Menu_DrawItem(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 (Clist_MenuProcessCommand(LOWORD(wParam), MPCF_CONTACTMENU, 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: + { + wchar_t *path = dat->transferStatus.szWorkingDir.w; + if (!path || !path[0]) { + path = NEWWSTR_ALLOCA(dat->transferStatus.szCurrentFile.w); + wchar_t *p = wcsrchr(path, '\\'); if (p) *p = 0; + } + + if (path) ShellExecute(NULL, L"open", path, NULL, NULL, SW_SHOW); + } + break; + + case IDC_OPENFILE: + wchar_t **files; + if (dat->send) { + if (dat->files == nullptr) + files = dat->transferStatus.pszFiles.w; + else + files = dat->files; + } + else files = dat->files; + + HMENU hMenu = CreatePopupMenu(); + AppendMenu(hMenu, MF_STRING, 1, TranslateT("Open folder")); + AppendMenu(hMenu, MF_SEPARATOR, 0, nullptr); + + if (files && *files) { + int limit; + wchar_t *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 = wcsrchr(files[i], '\\'); + if (pszFilename == nullptr) + pszFilename = files[i]; + else + pszFilename++; + + if (pszFilename) { + size_t cbFileNameLen = mir_wstrlen(pszFilename); + + pszNewFileName = (wchar_t*)mir_alloc(cbFileNameLen * 2 * sizeof(wchar_t)); + wchar_t *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, nullptr); + CheckDlgButton(hwndDlg, IDC_OPENFILE, BST_UNCHECKED); + DestroyMenu(hMenu); + + if (ret == 1) { + wchar_t *path = dat->transferStatus.szWorkingDir.w; + if (!path || !path[0]) { + path = NEWWSTR_ALLOCA(dat->transferStatus.szCurrentFile.w); + wchar_t *p = wcsrchr(path, '\\'); + if (p) + *p = 0; + } + + if (path) ShellExecute(nullptr, L"open", path, nullptr, nullptr, SW_SHOW); + } + else if (ret && CheckVirusScanned(hwndDlg, dat, ret)) + ShellExecute(nullptr, nullptr, files[ret - 10], nullptr, nullptr, SW_SHOW); + } + break; + + case M_FILEEXISTSDLGREPLY: + EnableWindow(hwndDlg, TRUE); + { + PROTOFILERESUME *pfr = (PROTOFILERESUME *)lParam; + wchar_t *szOriginalFilename = (wchar_t *)wParam; + char *szProto = Proto_GetBaseAccountName(dat->hContact); + + switch (pfr->action) { + case FILERESUME_CANCEL: + if (dat->fs) ProtoChainSend(dat->hContact, PSS_FILECANCEL, (WPARAM)dat->fs, 0); + dat->fs = nullptr; + 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; + { + wchar_t *pszExtension, *pszFilename; + if ((pszFilename = wcsrchr(szOriginalFilename, '\\')) == nullptr) pszFilename = szOriginalFilename; + if ((pszExtension = wcsrchr(pszFilename + 1, '.')) == nullptr) pszExtension = pszFilename + mir_wstrlen(pszFilename); + if (pfr->szFilename) mir_free((wchar_t *)pfr->szFilename); + size_t size = (pszExtension - szOriginalFilename) + 21 + mir_wstrlen(pszExtension); + pfr->szFilename = (wchar_t *)mir_alloc(sizeof(wchar_t) * size); + for (int i = 1;; i++) { + mir_snwprintf((wchar_t *)pfr->szFilename, size, L"%.*s (%u)%s", pszExtension - szOriginalFilename, szOriginalFilename, i, pszExtension); + if (_waccess(pfr->szFilename, 0) != 0) + break; + } + } + break; + } + mir_free(szOriginalFilename); + CallProtoService(szProto, PS_FILERESUME, (WPARAM)dat->fs, (LPARAM)pfr); + delete 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, nullptr); + dat->waitingForAcceptance = 0; + } + + switch (ack->result) { + case ACKRESULT_SENTREQUEST: SetFtStatus(hwndDlg, LPGENW("Decision sent"), FTS_TEXT); break; + case ACKRESULT_CONNECTING: SetFtStatus(hwndDlg, LPGENW("Connecting..."), FTS_TEXT); break; + case ACKRESULT_CONNECTPROXY: SetFtStatus(hwndDlg, LPGENW("Connecting to proxy..."), FTS_TEXT); break; + case ACKRESULT_CONNECTED: SetFtStatus(hwndDlg, LPGENW("Connected"), FTS_TEXT); break; + case ACKRESULT_LISTENING: SetFtStatus(hwndDlg, LPGENW("Waiting for connection..."), FTS_TEXT); break; + case ACKRESULT_INITIALISING: SetFtStatus(hwndDlg, LPGENW("Initializing..."), FTS_TEXT); break; + case ACKRESULT_NEXTFILE: + SetFtStatus(hwndDlg, LPGENW("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 && g_plugin.getByte("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 = (virusscanthreadstartinfo *)mir_alloc(sizeof(virusscanthreadstartinfo)); + vstsi->hwndReply = hwndDlg; + vstsi->szFile = mir_wstrdup(dat->files[dat->transferStatus.currentFileNumber]); + vstsi->returnCode = dat->transferStatus.currentFileNumber; + mir_forkThread(RunVirusScannerThread, vstsi); + } + } + break; + + case ACKRESULT_FILERESUME: + UpdateProtoFileTransferStatus(&dat->transferStatus, (PROTOFILETRANSFERSTATUS *)ack->lParam); + { + PROTOFILETRANSFERSTATUS *fts = &dat->transferStatus; + SetFilenameControls(hwndDlg, dat, fts); + if (_waccess(fts->szCurrentFile.w, 0)) + break; + + SetFtStatus(hwndDlg, LPGENW("File already exists"), FTS_TEXT); + if (dat->resumeBehaviour == FILERESUME_ASK) { + TDlgProcFileExistsParam param = { hwndDlg, fts }; + ShowWindow(hwndDlg, SW_SHOWNORMAL); + CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_FILEEXISTS), hwndDlg, DlgProcFileExists, (LPARAM)¶m); + EnableWindow(hwndDlg, FALSE); + } + else { + PROTOFILERESUME *pfr = new PROTOFILERESUME(); + pfr->action = dat->resumeBehaviour; + pfr->szFilename = nullptr; + PostMessage(hwndDlg, M_FILEEXISTSDLGREPLY, (WPARAM)mir_wstrdup(fts->szCurrentFile.w), (LPARAM)pfr); + } + } + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, 1); + return TRUE; + + case ACKRESULT_DATA: + { + PROTOFILETRANSFERSTATUS *fts = (PROTOFILETRANSFERSTATUS *)ack->lParam; + wchar_t str[64], str2[64], szSizeDone[32], szSizeTotal[32];//, *contactName; + + if (dat->fileVirusScanned == nullptr) + 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 == nullptr) + dat->files = (wchar_t **)mir_calloc((fts->totalFiles + 1) * sizeof(wchar_t *)); + if (fts->currentFileNumber < fts->totalFiles && dat->files[fts->currentFileNumber] == nullptr) + dat->files[fts->currentFileNumber] = PFTS_StringToTchar(fts->flags, fts->szCurrentFile.w); + } + + /* 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) ? LPGENW("Sending...") : LPGENW("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 ? (100ll * fts->totalProgress / fts->totalBytes) : 0; + if (lastPos != nextPos || firstTime) { + SendDlgItemMessage(hwndDlg, IDC_ALLFILESPROGRESS, PBM_SETPOS, nextPos, 0); + mir_snwprintf(str, L"%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_snwprintf(str, L"%s/%s", szSizeDone, szSizeTotal); + str2[0] = 0; + GetDlgItemText(hwndDlg, IDC_ALLTRANSFERRED, str2, _countof(str2)); + if (mir_wstrcmp(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 = nullptr; + + if (ack->result == ACKRESULT_DENIED) { + dat->fs = nullptr; /* protocol will free structure */ + Skin_PlaySound("FileDenied"); + SetFtStatus(hwndDlg, LPGENW("File transfer denied"), FTS_TEXT); + } + else if (ack->result == ACKRESULT_FAILED) { + dat->fs = nullptr; /* protocol will free structure */ + Skin_PlaySound("FileFailed"); + SetFtStatus(hwndDlg, LPGENW("File transfer failed"), FTS_TEXT); + } + else { + Skin_PlaySound("FileDone"); + if (dat->send) { + dat->fs = nullptr; /* protocol will free structure */ + SetFtStatus(hwndDlg, LPGENW("Transfer completed."), FTS_TEXT); + + DBEVENTINFO dbei = {}; + FillSendData(dat, dbei); + db_event_add(dat->hContact, &dbei); + if (dbei.pBlob) + mir_free(dbei.pBlob); + dat->files = nullptr; //protocol library frees this + } + else { + SetFtStatus(hwndDlg, + (dat->transferStatus.totalFiles == 1) ? + LPGENW("Transfer completed, open file.") : + LPGENW("Transfer completed, open folder."), + FTS_OPEN); + + int useScanner = g_plugin.getByte("UseScanner", VIRUSSCAN_DISABLE); + if (useScanner != VIRUSSCAN_DISABLE) { + auto *vstsi = (virusscanthreadstartinfo *)mir_alloc(sizeof(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 = nullptr; + } + else vstsi->szFile = mir_wstrdup(dat->files[dat->transferStatus.currentFileNumber]); + } + else { + vstsi->szFile = mir_wstrdup(dat->transferStatus.szWorkingDir.w); + vstsi->returnCode = -1; + } + SetFtStatus(hwndDlg, LPGENW("Scanning for viruses..."), FTS_TEXT); + if (vstsi) + mir_forkThread(RunVirusScannerThread, vstsi); + } + else dat->fs = nullptr; /* protocol will free structure */ + + dat->transferStatus.currentFileNumber = dat->transferStatus.totalFiles; + } + } + + PostMessage(GetParent(hwndDlg), WM_FT_COMPLETED, ack->result, (LPARAM)hwndDlg); + break; + } + } + 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 = nullptr; /* protocol will free structure */ + SetFtStatus(hwndDlg, LPGENW("Transfer and virus scan complete"), FTS_TEXT); + } + } + break; + + case WM_SIZE: + Utils_ResizeDialog(hwndDlg, g_plugin.getInst(), MAKEINTRESOURCEA(IDD_FILETRANSFERINFO), FileTransferDlgResizer, LPARAM(dat)); + + 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); + + delete dat; + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0); + break; + } + return FALSE; +} + +FileDlgData::~FileDlgData() +{ + if (fs) + ProtoChainSend(hContact, PSS_FILECANCEL, (WPARAM)fs, 0); + if (hPreshutdownEvent) + UnhookEvent(hPreshutdownEvent); + if (hNotifyEvent) + UnhookEvent(hNotifyEvent); + + FreeProtoFileTransferStatus(&transferStatus); + FreeFilesMatrix(&files); + + mir_free(fileVirusScanned); + if (hIcon) + DestroyIcon(hIcon); + if (hIconFolder) + DestroyIcon(hIconFolder); +} diff --git a/src/core/stdfile/src/ftmanager.cpp b/src/core/stdfile/src/ftmanager.cpp index 20206908be..56b0a168a7 100644 --- a/src/core/stdfile/src/ftmanager.cpp +++ b/src/core/stdfile/src/ftmanager.cpp @@ -2,7 +2,7 @@ Miranda NG: the free IM client for Microsoft* Windows* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org), +Copyright (C) 2012-23 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. diff --git a/src/core/stdfile/src/main.cpp b/src/core/stdfile/src/main.cpp index 275c58cf44..3797ea1e49 100644 --- a/src/core/stdfile/src/main.cpp +++ b/src/core/stdfile/src/main.cpp @@ -2,7 +2,7 @@ Standard file transfers' plugin for Miranda NG -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org) +Copyright (C) 2012-23 Miranda NG team (https://miranda-ng.org) 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 diff --git a/src/core/stdfile/src/stdafx.h b/src/core/stdfile/src/stdafx.h index b732c1278c..775d957d38 100644 --- a/src/core/stdfile/src/stdafx.h +++ b/src/core/stdfile/src/stdafx.h @@ -2,7 +2,7 @@ Miranda NG: the free IM client for Microsoft* Windows* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org), +Copyright (C) 2012-23 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. diff --git a/src/core/stdfile/src/version.h b/src/core/stdfile/src/version.h index 777678748d..2099819477 100644 --- a/src/core/stdfile/src/version.h +++ b/src/core/stdfile/src/version.h @@ -8,4 +8,4 @@ #define __DESCRIPTION "Core module for sending/receiving files." #define __AUTHOR "Miranda NG team" #define __AUTHORWEB "https://miranda-ng.org/p/StdFile" -#define __COPYRIGHT "© 2012-22 Miranda NG team" +#define __COPYRIGHT "© 2012-23 Miranda NG team" diff --git a/src/core/stdmsg/src/chat_manager.cpp b/src/core/stdmsg/src/chat_manager.cpp index b72f53acd7..b461b91703 100644 --- a/src/core/stdmsg/src/chat_manager.cpp +++ b/src/core/stdmsg/src/chat_manager.cpp @@ -1,243 +1,243 @@ -/* -Chat module plugin for Miranda IM - -Copyright 2000-12 Miranda IM, 2012-22 Miranda NG team, -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" - -pfnDoTrayIcon oldDoTrayIcon; -pfnDoPopup oldDoPopup; - -SESSION_INFO* SM_GetPrevWindow(SESSION_INFO *si) -{ - int i = g_chatApi.arSessions.indexOf(si); - if (i == -1) - return nullptr; - - for (i--; i >= 0; i--) { - SESSION_INFO *p = g_chatApi.arSessions[i]; - if (p->pDlg) - return p; - } - - return nullptr; -} - -SESSION_INFO* SM_GetNextWindow(SESSION_INFO *si) -{ - int i = g_chatApi.arSessions.indexOf(si); - if (i == -1) - return nullptr; - - for (i++; i < g_chatApi.arSessions.getCount(); i++) { - SESSION_INFO *p = g_chatApi.arSessions[i]; - if (p->pDlg) - return p; - } - - return nullptr; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -HMENU g_hMenu = nullptr; - -GlobalLogSettings g_Settings; - -static MODULEINFO* MM_CreateModule() -{ - return new MODULEINFO(); -} - -static void OnReplaceSession(SESSION_INFO *si) -{ - if (si->pDlg) - RedrawWindow(GetDlgItem(si->pDlg->GetHwnd(), IDC_SRMM_NICKLIST), nullptr, nullptr, RDW_INVALIDATE); -} - -static void OnFlashHighlight(SESSION_INFO *si, int bInactive) -{ - if (!bInactive || si->pDlg == nullptr) - return; - - if (g_Settings.bTabsEnable) - g_pTabDialog->SetMessageHighlight(si->pDlg); - else if (Chat::bFlashWindowHighlight) - si->pDlg->StartFlash(); -} - -static void OnFlashWindow(SESSION_INFO *si, int bInactive) -{ - if (!bInactive || si->pDlg == nullptr) - return; - - if (g_Settings.bTabsEnable) - g_pTabDialog->SetTabHighlight(si->pDlg); - else if (Chat::bFlashWindow) - si->pDlg->StartFlash(); -} - -static BOOL DoTrayIcon(SESSION_INFO *si, GCEVENT *gce) -{ - if (gce->iType & g_Settings.dwTrayIconFlags) - return oldDoTrayIcon(si, gce); - return TRUE; -} - -static BOOL DoPopup(SESSION_INFO *si, GCEVENT *gce) -{ - if (gce->iType & g_Settings.dwPopupFlags) - return oldDoPopup(si, gce); - return TRUE; -} - -static void OnLoadSettings() -{ - g_Settings.iX = db_get_dw(0, CHAT_MODULE, "roomx", -1); - g_Settings.iY = db_get_dw(0, CHAT_MODULE, "roomy", -1); - - g_Settings.bTabsEnable = db_get_b(0, CHAT_MODULE, "Tabs", 1) != 0; - g_Settings.bTabsAtBottom = db_get_b(0, CHAT_MODULE, "TabBottom", 0) != 0; - g_Settings.bTabCloseOnDblClick = db_get_b(0, CHAT_MODULE, "TabCloseOnDblClick", 0) != 0; - g_Settings.bAddColonToAutoComplete = db_get_b(0, CHAT_MODULE, "AddColonToAutoComplete", 1) != 0; - - g_Settings.iSplitterX = db_get_w(0, CHAT_MODULE, "SplitterX", 105); - if (g_Settings.iSplitterX <= 50) - g_Settings.iSplitterX = 105; - g_Settings.iSplitterY = db_get_w(0, CHAT_MODULE, "SplitterY", 90); - if (g_Settings.iSplitterY <= 65) - g_Settings.iSplitterY = 90; -} - -static void RegisterFonts() -{ - ColourIDW colourid = {}; - strncpy(colourid.dbSettingsGroup, CHAT_MODULE, sizeof(colourid.dbSettingsGroup)); - wcsncpy(colourid.group, LPGENW("Message sessions") L"/" LPGENW("Chat module"), _countof(colourid.group)); - - strncpy(colourid.setting, "ColorLogBG", _countof(colourid.setting)); - wcsncpy(colourid.name, LPGENW("Group chat log background"), _countof(colourid.name)); - colourid.defcolour = GetSysColor(COLOR_WINDOW); - g_plugin.addColor(&colourid); - - strncpy(colourid.setting, "ColorMessageBG", _countof(colourid.setting)); - wcsncpy(colourid.name, LPGENW("Message background"), _countof(colourid.name)); - colourid.defcolour = GetSysColor(COLOR_WINDOW); - g_plugin.addColor(&colourid); - - strncpy(colourid.setting, "ColorNicklistBG", _countof(colourid.setting)); - wcsncpy(colourid.name, LPGENW("Nick list background"), _countof(colourid.name)); - colourid.defcolour = GetSysColor(COLOR_WINDOW); - g_plugin.addColor(&colourid); - - strncpy(colourid.setting, "ColorNicklistLines", _countof(colourid.setting)); - wcsncpy(colourid.name, LPGENW("Nick list lines"), _countof(colourid.name)); - colourid.defcolour = GetSysColor(COLOR_INACTIVEBORDER); - g_plugin.addColor(&colourid); - - strncpy(colourid.setting, "ColorNicklistSelectedBG", _countof(colourid.setting)); - wcsncpy(colourid.name, LPGENW("Nick list background (selected)"), _countof(colourid.name)); - colourid.defcolour = GetSysColor(COLOR_HIGHLIGHT); - g_plugin.addColor(&colourid); -} - -static void ShowRoom(SESSION_INFO *si) -{ - if (!si) - return; - - // Do we need to create a window? - if (si->pDlg == nullptr) { - CTabbedWindow *pContainer = GetContainer(); - if (g_Settings.bTabsEnable) { - pContainer->AddPage(si); - PostMessage(pContainer->GetHwnd(), WM_SIZE, 0, 0); - } - else { - CMsgDialog *pDlg = pContainer->m_pEmbed = new CMsgDialog(pContainer, si); - pContainer->Create(); - pDlg->SetParent(pContainer->GetHwnd()); - pDlg->Create(); - pContainer->Show(); - pContainer->FixTabIcons(pDlg); - PostMessage(pContainer->GetHwnd(), WM_SIZE, 0, 0); - } - - if (si->iType != GCW_SERVER) - si->pDlg->UpdateNickList(); - else - si->pDlg->UpdateTitle(); - si->pDlg->UpdateStatusBar(); - } - else if (g_Settings.bTabsEnable && g_pTabDialog) - g_pTabDialog->m_tab.ActivatePage(g_pTabDialog->m_tab.GetDlgIndex(si->pDlg)); - - SetWindowLongPtr(si->pDlg->GetHwnd(), GWL_EXSTYLE, GetWindowLongPtr(si->pDlg->GetHwnd(), GWL_EXSTYLE) | WS_EX_APPWINDOW); - - if (IsIconic(si->pDlg->GetHwnd())) - si->pDlg->Show(SW_NORMAL); - si->pDlg->Show(SW_SHOW); - SetForegroundWindow(si->pDlg->GetHwnd()); -} - -int OnCheckPlugins(WPARAM, LPARAM) -{ - g_plugin.bSmileyInstalled = ServiceExists(MS_SMILEYADD_REPLACESMILEYS); - return 0; -} - -void Load_ChatModule() -{ - AddIcons(); - RegisterFonts(); - - CHAT_MANAGER_INITDATA data = { &g_Settings, sizeof(MODULEINFO), sizeof(SESSION_INFO), LPGENW("Message sessions") L"/" LPGENW("Chat module"), FONTMODE_USE, &g_plugin }; - Chat_CustomizeApi(&data); - - g_chatApi.MM_CreateModule = MM_CreateModule; - g_chatApi.OnReplaceSession = OnReplaceSession; - - g_chatApi.OnLoadSettings = OnLoadSettings; - g_chatApi.OnFlashWindow = OnFlashWindow; - g_chatApi.OnFlashHighlight = OnFlashHighlight; - g_chatApi.ShowRoom = ShowRoom; - - Srmm_CreateHotkey(LPGEN("Messaging"), LPGEN("Send message")); - - oldDoPopup = g_chatApi.DoPopup; g_chatApi.DoPopup = DoPopup; - oldDoTrayIcon = g_chatApi.DoTrayIcon; g_chatApi.DoTrayIcon = DoTrayIcon; - g_chatApi.ReloadSettings(); - - g_hMenu = LoadMenu(g_plugin.getInst(), MAKEINTRESOURCE(IDR_MENU)); - - HookEvent(ME_SYSTEM_MODULELOAD, OnCheckPlugins); -} - -void Unload_ChatModule() -{ - db_set_w(0, CHAT_MODULE, "SplitterX", (uint16_t)g_Settings.iSplitterX); - db_set_w(0, CHAT_MODULE, "SplitterY", (uint16_t)g_Settings.iSplitterY); - db_set_dw(0, CHAT_MODULE, "roomx", g_Settings.iX); - db_set_dw(0, CHAT_MODULE, "roomy", g_Settings.iY); - db_set_dw(0, CHAT_MODULE, "roomwidth", g_Settings.iWidth); - db_set_dw(0, CHAT_MODULE, "roomheight", g_Settings.iHeight); - - DestroyMenu(g_hMenu); -} +/* +Chat module plugin for Miranda IM + +Copyright 2000-12 Miranda IM, 2012-23 Miranda NG team, +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" + +pfnDoTrayIcon oldDoTrayIcon; +pfnDoPopup oldDoPopup; + +SESSION_INFO* SM_GetPrevWindow(SESSION_INFO *si) +{ + int i = g_chatApi.arSessions.indexOf(si); + if (i == -1) + return nullptr; + + for (i--; i >= 0; i--) { + SESSION_INFO *p = g_chatApi.arSessions[i]; + if (p->pDlg) + return p; + } + + return nullptr; +} + +SESSION_INFO* SM_GetNextWindow(SESSION_INFO *si) +{ + int i = g_chatApi.arSessions.indexOf(si); + if (i == -1) + return nullptr; + + for (i++; i < g_chatApi.arSessions.getCount(); i++) { + SESSION_INFO *p = g_chatApi.arSessions[i]; + if (p->pDlg) + return p; + } + + return nullptr; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +HMENU g_hMenu = nullptr; + +GlobalLogSettings g_Settings; + +static MODULEINFO* MM_CreateModule() +{ + return new MODULEINFO(); +} + +static void OnReplaceSession(SESSION_INFO *si) +{ + if (si->pDlg) + RedrawWindow(GetDlgItem(si->pDlg->GetHwnd(), IDC_SRMM_NICKLIST), nullptr, nullptr, RDW_INVALIDATE); +} + +static void OnFlashHighlight(SESSION_INFO *si, int bInactive) +{ + if (!bInactive || si->pDlg == nullptr) + return; + + if (g_Settings.bTabsEnable) + g_pTabDialog->SetMessageHighlight(si->pDlg); + else if (Chat::bFlashWindowHighlight) + si->pDlg->StartFlash(); +} + +static void OnFlashWindow(SESSION_INFO *si, int bInactive) +{ + if (!bInactive || si->pDlg == nullptr) + return; + + if (g_Settings.bTabsEnable) + g_pTabDialog->SetTabHighlight(si->pDlg); + else if (Chat::bFlashWindow) + si->pDlg->StartFlash(); +} + +static BOOL DoTrayIcon(SESSION_INFO *si, GCEVENT *gce) +{ + if (gce->iType & g_Settings.dwTrayIconFlags) + return oldDoTrayIcon(si, gce); + return TRUE; +} + +static BOOL DoPopup(SESSION_INFO *si, GCEVENT *gce) +{ + if (gce->iType & g_Settings.dwPopupFlags) + return oldDoPopup(si, gce); + return TRUE; +} + +static void OnLoadSettings() +{ + g_Settings.iX = db_get_dw(0, CHAT_MODULE, "roomx", -1); + g_Settings.iY = db_get_dw(0, CHAT_MODULE, "roomy", -1); + + g_Settings.bTabsEnable = db_get_b(0, CHAT_MODULE, "Tabs", 1) != 0; + g_Settings.bTabsAtBottom = db_get_b(0, CHAT_MODULE, "TabBottom", 0) != 0; + g_Settings.bTabCloseOnDblClick = db_get_b(0, CHAT_MODULE, "TabCloseOnDblClick", 0) != 0; + g_Settings.bAddColonToAutoComplete = db_get_b(0, CHAT_MODULE, "AddColonToAutoComplete", 1) != 0; + + g_Settings.iSplitterX = db_get_w(0, CHAT_MODULE, "SplitterX", 105); + if (g_Settings.iSplitterX <= 50) + g_Settings.iSplitterX = 105; + g_Settings.iSplitterY = db_get_w(0, CHAT_MODULE, "SplitterY", 90); + if (g_Settings.iSplitterY <= 65) + g_Settings.iSplitterY = 90; +} + +static void RegisterFonts() +{ + ColourIDW colourid = {}; + strncpy(colourid.dbSettingsGroup, CHAT_MODULE, sizeof(colourid.dbSettingsGroup)); + wcsncpy(colourid.group, LPGENW("Message sessions") L"/" LPGENW("Chat module"), _countof(colourid.group)); + + strncpy(colourid.setting, "ColorLogBG", _countof(colourid.setting)); + wcsncpy(colourid.name, LPGENW("Group chat log background"), _countof(colourid.name)); + colourid.defcolour = GetSysColor(COLOR_WINDOW); + g_plugin.addColor(&colourid); + + strncpy(colourid.setting, "ColorMessageBG", _countof(colourid.setting)); + wcsncpy(colourid.name, LPGENW("Message background"), _countof(colourid.name)); + colourid.defcolour = GetSysColor(COLOR_WINDOW); + g_plugin.addColor(&colourid); + + strncpy(colourid.setting, "ColorNicklistBG", _countof(colourid.setting)); + wcsncpy(colourid.name, LPGENW("Nick list background"), _countof(colourid.name)); + colourid.defcolour = GetSysColor(COLOR_WINDOW); + g_plugin.addColor(&colourid); + + strncpy(colourid.setting, "ColorNicklistLines", _countof(colourid.setting)); + wcsncpy(colourid.name, LPGENW("Nick list lines"), _countof(colourid.name)); + colourid.defcolour = GetSysColor(COLOR_INACTIVEBORDER); + g_plugin.addColor(&colourid); + + strncpy(colourid.setting, "ColorNicklistSelectedBG", _countof(colourid.setting)); + wcsncpy(colourid.name, LPGENW("Nick list background (selected)"), _countof(colourid.name)); + colourid.defcolour = GetSysColor(COLOR_HIGHLIGHT); + g_plugin.addColor(&colourid); +} + +static void ShowRoom(SESSION_INFO *si) +{ + if (!si) + return; + + // Do we need to create a window? + if (si->pDlg == nullptr) { + CTabbedWindow *pContainer = GetContainer(); + if (g_Settings.bTabsEnable) { + pContainer->AddPage(si); + PostMessage(pContainer->GetHwnd(), WM_SIZE, 0, 0); + } + else { + CMsgDialog *pDlg = pContainer->m_pEmbed = new CMsgDialog(pContainer, si); + pContainer->Create(); + pDlg->SetParent(pContainer->GetHwnd()); + pDlg->Create(); + pContainer->Show(); + pContainer->FixTabIcons(pDlg); + PostMessage(pContainer->GetHwnd(), WM_SIZE, 0, 0); + } + + if (si->iType != GCW_SERVER) + si->pDlg->UpdateNickList(); + else + si->pDlg->UpdateTitle(); + si->pDlg->UpdateStatusBar(); + } + else if (g_Settings.bTabsEnable && g_pTabDialog) + g_pTabDialog->m_tab.ActivatePage(g_pTabDialog->m_tab.GetDlgIndex(si->pDlg)); + + SetWindowLongPtr(si->pDlg->GetHwnd(), GWL_EXSTYLE, GetWindowLongPtr(si->pDlg->GetHwnd(), GWL_EXSTYLE) | WS_EX_APPWINDOW); + + if (IsIconic(si->pDlg->GetHwnd())) + si->pDlg->Show(SW_NORMAL); + si->pDlg->Show(SW_SHOW); + SetForegroundWindow(si->pDlg->GetHwnd()); +} + +int OnCheckPlugins(WPARAM, LPARAM) +{ + g_plugin.bSmileyInstalled = ServiceExists(MS_SMILEYADD_REPLACESMILEYS); + return 0; +} + +void Load_ChatModule() +{ + AddIcons(); + RegisterFonts(); + + CHAT_MANAGER_INITDATA data = { &g_Settings, sizeof(MODULEINFO), sizeof(SESSION_INFO), LPGENW("Message sessions") L"/" LPGENW("Chat module"), FONTMODE_USE, &g_plugin }; + Chat_CustomizeApi(&data); + + g_chatApi.MM_CreateModule = MM_CreateModule; + g_chatApi.OnReplaceSession = OnReplaceSession; + + g_chatApi.OnLoadSettings = OnLoadSettings; + g_chatApi.OnFlashWindow = OnFlashWindow; + g_chatApi.OnFlashHighlight = OnFlashHighlight; + g_chatApi.ShowRoom = ShowRoom; + + Srmm_CreateHotkey(LPGEN("Messaging"), LPGEN("Send message")); + + oldDoPopup = g_chatApi.DoPopup; g_chatApi.DoPopup = DoPopup; + oldDoTrayIcon = g_chatApi.DoTrayIcon; g_chatApi.DoTrayIcon = DoTrayIcon; + g_chatApi.ReloadSettings(); + + g_hMenu = LoadMenu(g_plugin.getInst(), MAKEINTRESOURCE(IDR_MENU)); + + HookEvent(ME_SYSTEM_MODULELOAD, OnCheckPlugins); +} + +void Unload_ChatModule() +{ + db_set_w(0, CHAT_MODULE, "SplitterX", (uint16_t)g_Settings.iSplitterX); + db_set_w(0, CHAT_MODULE, "SplitterY", (uint16_t)g_Settings.iSplitterY); + db_set_dw(0, CHAT_MODULE, "roomx", g_Settings.iX); + db_set_dw(0, CHAT_MODULE, "roomy", g_Settings.iY); + db_set_dw(0, CHAT_MODULE, "roomwidth", g_Settings.iWidth); + db_set_dw(0, CHAT_MODULE, "roomheight", g_Settings.iHeight); + + DestroyMenu(g_hMenu); +} diff --git a/src/core/stdmsg/src/chat_window.cpp b/src/core/stdmsg/src/chat_window.cpp index 52106ae755..8e1871dd4c 100644 --- a/src/core/stdmsg/src/chat_window.cpp +++ b/src/core/stdmsg/src/chat_window.cpp @@ -1,275 +1,275 @@ -/* -Chat module plugin for Miranda IM - -Copyright 2000-12 Miranda IM, 2012-22 Miranda NG team, -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" - -///////////////////////////////////////////////////////////////////////////////////////// - -void CMsgDialog::LoadSettings() -{ - m_clrInputBG = db_get_dw(0, CHAT_MODULE, "ColorMessageBG", GetSysColor(COLOR_WINDOW)); - LoadMsgDlgFont(MSGFONTID_MESSAGEAREA, nullptr, &m_clrInputFG); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void CMsgDialog::ShowFilterMenu() -{ - HWND hwnd = CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_FILTER), m_hwnd, FilterWndProc, (LPARAM)this); - TranslateDialogDefault(hwnd); - - RECT rc; - GetWindowRect(m_btnFilter.GetHwnd(), &rc); - SetWindowPos(hwnd, HWND_TOP, rc.left - 85, (IsWindowVisible(m_btnFilter.GetHwnd()) || IsWindowVisible(m_btnBold.GetHwnd())) ? rc.top - 206 : rc.top - 186, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW); -} - -void CMsgDialog::UpdateNickList() -{ - int i = m_nickList.SendMsg(LB_GETTOPINDEX, 0, 0); - m_nickList.SendMsg(LB_SETCOUNT, m_si->getUserList().getCount(), 0); - m_nickList.SendMsg(LB_SETTOPINDEX, i, 0); - - UpdateTitle(); -} - -void CMsgDialog::UpdateOptions() -{ - m_btnNickList.SendMsg(BM_SETIMAGE, IMAGE_ICON, (LPARAM)g_plugin.getIcon(m_bNicklistEnabled ? IDI_NICKLIST2 : IDI_NICKLIST, FALSE)); - m_btnFilter.SendMsg(BM_SETIMAGE, IMAGE_ICON, (LPARAM)g_plugin.getIcon(m_bFilterEnabled ? IDI_FILTER2 : IDI_FILTER, FALSE)); - - HICON hIcon = ImageList_GetIcon(Clist_GetImageList(), GetImageId(), ILD_TRANSPARENT); - SendMessage(m_pOwner->m_hwndStatus, SB_SETICON, 0, (LPARAM)hIcon); - DestroyIcon(hIcon); - - Window_SetIcon_IcoLib(m_pOwner->GetHwnd(), g_plugin.getIconHandle(IDI_CHANMGR)); - - m_pLog->UpdateOptions(); - - // nicklist - int ih = Chat_GetTextPixelSize(L"AQGglo", g_Settings.UserListFont, FALSE); - int ih2 = Chat_GetTextPixelSize(L"AQGglo", g_Settings.UserListHeadingsFont, FALSE); - int height = db_get_b(0, CHAT_MODULE, "NicklistRowDist", 12); - int font = ih > ih2 ? ih : ih2; - - // make sure we have space for icon! - if (g_Settings.bShowContactStatus) - font = font > 16 ? font : 16; - - m_nickList.SendMsg(LB_SETITEMHEIGHT, 0, height > font ? height : font); - InvalidateRect(m_nickList.GetHwnd(), nullptr, TRUE); - - CSuper::UpdateOptions(); -} - -void CMsgDialog::UpdateStatusBar() -{ - wchar_t *ptszDispName = m_si->pMI->ptszModDispName; - int x = 12; - x += Chat_GetTextPixelSize(ptszDispName, (HFONT)SendMessage(m_pOwner->m_hwndStatus, WM_GETFONT, 0, 0), TRUE); - x += GetSystemMetrics(SM_CXSMICON); - int iStatusbarParts[2] = { x, -1 }; - SendMessage(m_pOwner->m_hwndStatus, SB_SETPARTS, 2, (LPARAM)&iStatusbarParts); - - HICON hIcon = ImageList_GetIcon(Clist_GetImageList(), GetImageId(), ILD_TRANSPARENT); - SendMessage(m_pOwner->m_hwndStatus, SB_SETICON, 0, (LPARAM)hIcon); - DestroyIcon(hIcon); - - SendMessage(m_pOwner->m_hwndStatus, SB_SETTEXT, 0, (LPARAM)ptszDispName); - SendMessage(m_pOwner->m_hwndStatus, SB_SETTEXT, 1, (LPARAM)(m_si->ptszStatusbarText ? m_si->ptszStatusbarText : L"")); - SendMessage(m_pOwner->m_hwndStatus, SB_SETTIPTEXT, 1, (LPARAM)(m_si->ptszStatusbarText ? m_si->ptszStatusbarText : L"")); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void CLogWindow::LogEvents(LOGINFO *lin, bool bRedraw) -{ - auto *si = m_pDlg.m_si; - if (lin == nullptr || si == nullptr) - return; - - if (!bRedraw && si->iType == GCW_CHATROOM && m_pDlg.m_bFilterEnabled && (m_pDlg.m_iLogFilterFlags & lin->iType) == 0) - return; - - LOGSTREAMDATA streamData; - memset(&streamData, 0, sizeof(streamData)); - streamData.hwnd = m_rtf.GetHwnd(); - streamData.si = si; - streamData.lin = lin; - streamData.bStripFormat = FALSE; - - bool bFlag = false; - - EDITSTREAM stream = {}; - stream.pfnCallback = Srmm_LogStreamCallback; - stream.dwCookie = (DWORD_PTR)& streamData; - - SCROLLINFO scroll; - scroll.cbSize = sizeof(SCROLLINFO); - scroll.fMask = SIF_RANGE | SIF_POS | SIF_PAGE; - GetScrollInfo(m_rtf.GetHwnd(), SB_VERT, &scroll); - - POINT point = {}; - m_rtf.SendMsg(EM_GETSCROLLPOS, 0, (LPARAM)&point); - - // do not scroll to bottom if there is a selection - CHARRANGE oldsel, sel; - m_rtf.SendMsg(EM_EXGETSEL, 0, (LPARAM)&oldsel); - if (oldsel.cpMax != oldsel.cpMin) - m_rtf.SetDraw(false); - - //set the insertion point at the bottom - sel.cpMin = sel.cpMax = m_rtf.GetRichTextLength(); - m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel); - - // fix for the indent... must be a M$ bug - if (sel.cpMax == 0) - bRedraw = TRUE; - - // should the event(s) be appended to the current log - WPARAM wp = bRedraw ? SF_RTF : SFF_SELECTION | SF_RTF; - - //get the number of pixels per logical inch - if (bRedraw) { - HDC hdc = GetDC(nullptr); - g_chatApi.logPixelSY = GetDeviceCaps(hdc, LOGPIXELSY); - g_chatApi.logPixelSX = GetDeviceCaps(hdc, LOGPIXELSX); - ReleaseDC(nullptr, hdc); - m_rtf.SetDraw(false); - bFlag = true; - } - - // stream in the event(s) - streamData.lin = lin; - streamData.bRedraw = bRedraw; - m_rtf.SendMsg(EM_STREAMIN, wp, (LPARAM)&stream); - - // do smileys - if (g_plugin.bSmileyInstalled && (bRedraw || (lin->ptszText && lin->iType != GC_EVENT_JOIN && lin->iType != GC_EVENT_NICK && lin->iType != GC_EVENT_ADDSTATUS && lin->iType != GC_EVENT_REMOVESTATUS))) { - CHARRANGE newsel; - newsel.cpMax = -1; - newsel.cpMin = sel.cpMin; - if (newsel.cpMin < 0) - newsel.cpMin = 0; - - SMADD_RICHEDIT3 sm = {}; - sm.cbSize = sizeof(sm); - sm.hwndRichEditControl = m_rtf.GetHwnd(); - sm.Protocolname = si->pszModule; - sm.rangeToReplace = bRedraw ? nullptr : &newsel; - sm.disableRedraw = TRUE; - sm.hContact = si->hContact; - CallService(MS_SMILEYADD_REPLACESMILEYS, 0, (LPARAM)&sm); - } - - // scroll log to bottom if the log was previously scrolled to bottom, else restore old position - if (bRedraw || (UINT)scroll.nPos >= (UINT)scroll.nMax - scroll.nPage - 5 || scroll.nMax - scroll.nMin - scroll.nPage < 50) - ScrollToBottom(); - else - m_rtf.SendMsg(EM_SETSCROLLPOS, 0, (LPARAM)&point); - - // do we need to restore the selection - if (oldsel.cpMax != oldsel.cpMin) { - m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&oldsel); - m_rtf.SetDraw(true); - InvalidateRect(m_rtf.GetHwnd(), nullptr, TRUE); - } - - // need to invalidate the window - if (bFlag) { - sel.cpMin = sel.cpMax = m_rtf.GetRichTextLength(); - m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel); - m_rtf.SetDraw(true); - InvalidateRect(m_rtf.GetHwnd(), nullptr, TRUE); - } -} - -///////////////////////////////////////////////////////////////////////////////////////// - -INT_PTR CALLBACK CMsgDialog::FilterWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - static CMsgDialog *pDlg = nullptr; - switch (uMsg) { - case WM_INITDIALOG: - pDlg = (CMsgDialog*)lParam; - CheckDlgButton(hwndDlg, IDC_1, pDlg->m_iLogFilterFlags & GC_EVENT_ACTION ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hwndDlg, IDC_2, pDlg->m_iLogFilterFlags & GC_EVENT_MESSAGE ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hwndDlg, IDC_3, pDlg->m_iLogFilterFlags & GC_EVENT_NICK ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hwndDlg, IDC_4, pDlg->m_iLogFilterFlags & GC_EVENT_JOIN ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hwndDlg, IDC_5, pDlg->m_iLogFilterFlags & GC_EVENT_PART ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hwndDlg, IDC_6, pDlg->m_iLogFilterFlags & GC_EVENT_TOPIC ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hwndDlg, IDC_7, pDlg->m_iLogFilterFlags & GC_EVENT_ADDSTATUS ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hwndDlg, IDC_8, pDlg->m_iLogFilterFlags & GC_EVENT_INFORMATION ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hwndDlg, IDC_9, pDlg->m_iLogFilterFlags & GC_EVENT_QUIT ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hwndDlg, IDC_10, pDlg->m_iLogFilterFlags & GC_EVENT_KICK ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hwndDlg, IDC_11, pDlg->m_iLogFilterFlags & GC_EVENT_NOTICE ? BST_CHECKED : BST_UNCHECKED); - break; - - case WM_CTLCOLOREDIT: - case WM_CTLCOLORSTATIC: - SetTextColor((HDC)wParam, RGB(60, 60, 150)); - SetBkColor((HDC)wParam, GetSysColor(COLOR_WINDOW)); - return (INT_PTR)GetSysColorBrush(COLOR_WINDOW); - - case WM_ACTIVATE: - if (LOWORD(wParam) == WA_INACTIVE) { - int iFlags = 0; - - if (IsDlgButtonChecked(hwndDlg, IDC_1) == BST_CHECKED) - iFlags |= GC_EVENT_ACTION; - if (IsDlgButtonChecked(hwndDlg, IDC_2) == BST_CHECKED) - iFlags |= GC_EVENT_MESSAGE; - if (IsDlgButtonChecked(hwndDlg, IDC_3) == BST_CHECKED) - iFlags |= GC_EVENT_NICK; - if (IsDlgButtonChecked(hwndDlg, IDC_4) == BST_CHECKED) - iFlags |= GC_EVENT_JOIN; - if (IsDlgButtonChecked(hwndDlg, IDC_5) == BST_CHECKED) - iFlags |= GC_EVENT_PART; - if (IsDlgButtonChecked(hwndDlg, IDC_6) == BST_CHECKED) - iFlags |= GC_EVENT_TOPIC; - if (IsDlgButtonChecked(hwndDlg, IDC_7) == BST_CHECKED) - iFlags |= GC_EVENT_ADDSTATUS; - if (IsDlgButtonChecked(hwndDlg, IDC_8) == BST_CHECKED) - iFlags |= GC_EVENT_INFORMATION; - if (IsDlgButtonChecked(hwndDlg, IDC_9) == BST_CHECKED) - iFlags |= GC_EVENT_QUIT; - if (IsDlgButtonChecked(hwndDlg, IDC_10) == BST_CHECKED) - iFlags |= GC_EVENT_KICK; - if (IsDlgButtonChecked(hwndDlg, IDC_11) == BST_CHECKED) - iFlags |= GC_EVENT_NOTICE; - - if (iFlags & GC_EVENT_ADDSTATUS) - iFlags |= GC_EVENT_REMOVESTATUS; - - pDlg->m_iLogFilterFlags = iFlags; - if (pDlg->m_bFilterEnabled) - pDlg->RedrawLog(); - PostMessage(hwndDlg, WM_CLOSE, 0, 0); - } - break; - - case WM_CLOSE: - DestroyWindow(hwndDlg); - break; - } - - return FALSE; -} +/* +Chat module plugin for Miranda IM + +Copyright 2000-12 Miranda IM, 2012-23 Miranda NG team, +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" + +///////////////////////////////////////////////////////////////////////////////////////// + +void CMsgDialog::LoadSettings() +{ + m_clrInputBG = db_get_dw(0, CHAT_MODULE, "ColorMessageBG", GetSysColor(COLOR_WINDOW)); + LoadMsgDlgFont(MSGFONTID_MESSAGEAREA, nullptr, &m_clrInputFG); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void CMsgDialog::ShowFilterMenu() +{ + HWND hwnd = CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_FILTER), m_hwnd, FilterWndProc, (LPARAM)this); + TranslateDialogDefault(hwnd); + + RECT rc; + GetWindowRect(m_btnFilter.GetHwnd(), &rc); + SetWindowPos(hwnd, HWND_TOP, rc.left - 85, (IsWindowVisible(m_btnFilter.GetHwnd()) || IsWindowVisible(m_btnBold.GetHwnd())) ? rc.top - 206 : rc.top - 186, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW); +} + +void CMsgDialog::UpdateNickList() +{ + int i = m_nickList.SendMsg(LB_GETTOPINDEX, 0, 0); + m_nickList.SendMsg(LB_SETCOUNT, m_si->getUserList().getCount(), 0); + m_nickList.SendMsg(LB_SETTOPINDEX, i, 0); + + UpdateTitle(); +} + +void CMsgDialog::UpdateOptions() +{ + m_btnNickList.SendMsg(BM_SETIMAGE, IMAGE_ICON, (LPARAM)g_plugin.getIcon(m_bNicklistEnabled ? IDI_NICKLIST2 : IDI_NICKLIST, FALSE)); + m_btnFilter.SendMsg(BM_SETIMAGE, IMAGE_ICON, (LPARAM)g_plugin.getIcon(m_bFilterEnabled ? IDI_FILTER2 : IDI_FILTER, FALSE)); + + HICON hIcon = ImageList_GetIcon(Clist_GetImageList(), GetImageId(), ILD_TRANSPARENT); + SendMessage(m_pOwner->m_hwndStatus, SB_SETICON, 0, (LPARAM)hIcon); + DestroyIcon(hIcon); + + Window_SetIcon_IcoLib(m_pOwner->GetHwnd(), g_plugin.getIconHandle(IDI_CHANMGR)); + + m_pLog->UpdateOptions(); + + // nicklist + int ih = Chat_GetTextPixelSize(L"AQGglo", g_Settings.UserListFont, FALSE); + int ih2 = Chat_GetTextPixelSize(L"AQGglo", g_Settings.UserListHeadingsFont, FALSE); + int height = db_get_b(0, CHAT_MODULE, "NicklistRowDist", 12); + int font = ih > ih2 ? ih : ih2; + + // make sure we have space for icon! + if (g_Settings.bShowContactStatus) + font = font > 16 ? font : 16; + + m_nickList.SendMsg(LB_SETITEMHEIGHT, 0, height > font ? height : font); + InvalidateRect(m_nickList.GetHwnd(), nullptr, TRUE); + + CSuper::UpdateOptions(); +} + +void CMsgDialog::UpdateStatusBar() +{ + wchar_t *ptszDispName = m_si->pMI->ptszModDispName; + int x = 12; + x += Chat_GetTextPixelSize(ptszDispName, (HFONT)SendMessage(m_pOwner->m_hwndStatus, WM_GETFONT, 0, 0), TRUE); + x += GetSystemMetrics(SM_CXSMICON); + int iStatusbarParts[2] = { x, -1 }; + SendMessage(m_pOwner->m_hwndStatus, SB_SETPARTS, 2, (LPARAM)&iStatusbarParts); + + HICON hIcon = ImageList_GetIcon(Clist_GetImageList(), GetImageId(), ILD_TRANSPARENT); + SendMessage(m_pOwner->m_hwndStatus, SB_SETICON, 0, (LPARAM)hIcon); + DestroyIcon(hIcon); + + SendMessage(m_pOwner->m_hwndStatus, SB_SETTEXT, 0, (LPARAM)ptszDispName); + SendMessage(m_pOwner->m_hwndStatus, SB_SETTEXT, 1, (LPARAM)(m_si->ptszStatusbarText ? m_si->ptszStatusbarText : L"")); + SendMessage(m_pOwner->m_hwndStatus, SB_SETTIPTEXT, 1, (LPARAM)(m_si->ptszStatusbarText ? m_si->ptszStatusbarText : L"")); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void CLogWindow::LogEvents(LOGINFO *lin, bool bRedraw) +{ + auto *si = m_pDlg.m_si; + if (lin == nullptr || si == nullptr) + return; + + if (!bRedraw && si->iType == GCW_CHATROOM && m_pDlg.m_bFilterEnabled && (m_pDlg.m_iLogFilterFlags & lin->iType) == 0) + return; + + LOGSTREAMDATA streamData; + memset(&streamData, 0, sizeof(streamData)); + streamData.hwnd = m_rtf.GetHwnd(); + streamData.si = si; + streamData.lin = lin; + streamData.bStripFormat = FALSE; + + bool bFlag = false; + + EDITSTREAM stream = {}; + stream.pfnCallback = Srmm_LogStreamCallback; + stream.dwCookie = (DWORD_PTR)& streamData; + + SCROLLINFO scroll; + scroll.cbSize = sizeof(SCROLLINFO); + scroll.fMask = SIF_RANGE | SIF_POS | SIF_PAGE; + GetScrollInfo(m_rtf.GetHwnd(), SB_VERT, &scroll); + + POINT point = {}; + m_rtf.SendMsg(EM_GETSCROLLPOS, 0, (LPARAM)&point); + + // do not scroll to bottom if there is a selection + CHARRANGE oldsel, sel; + m_rtf.SendMsg(EM_EXGETSEL, 0, (LPARAM)&oldsel); + if (oldsel.cpMax != oldsel.cpMin) + m_rtf.SetDraw(false); + + //set the insertion point at the bottom + sel.cpMin = sel.cpMax = m_rtf.GetRichTextLength(); + m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel); + + // fix for the indent... must be a M$ bug + if (sel.cpMax == 0) + bRedraw = TRUE; + + // should the event(s) be appended to the current log + WPARAM wp = bRedraw ? SF_RTF : SFF_SELECTION | SF_RTF; + + //get the number of pixels per logical inch + if (bRedraw) { + HDC hdc = GetDC(nullptr); + g_chatApi.logPixelSY = GetDeviceCaps(hdc, LOGPIXELSY); + g_chatApi.logPixelSX = GetDeviceCaps(hdc, LOGPIXELSX); + ReleaseDC(nullptr, hdc); + m_rtf.SetDraw(false); + bFlag = true; + } + + // stream in the event(s) + streamData.lin = lin; + streamData.bRedraw = bRedraw; + m_rtf.SendMsg(EM_STREAMIN, wp, (LPARAM)&stream); + + // do smileys + if (g_plugin.bSmileyInstalled && (bRedraw || (lin->ptszText && lin->iType != GC_EVENT_JOIN && lin->iType != GC_EVENT_NICK && lin->iType != GC_EVENT_ADDSTATUS && lin->iType != GC_EVENT_REMOVESTATUS))) { + CHARRANGE newsel; + newsel.cpMax = -1; + newsel.cpMin = sel.cpMin; + if (newsel.cpMin < 0) + newsel.cpMin = 0; + + SMADD_RICHEDIT3 sm = {}; + sm.cbSize = sizeof(sm); + sm.hwndRichEditControl = m_rtf.GetHwnd(); + sm.Protocolname = si->pszModule; + sm.rangeToReplace = bRedraw ? nullptr : &newsel; + sm.disableRedraw = TRUE; + sm.hContact = si->hContact; + CallService(MS_SMILEYADD_REPLACESMILEYS, 0, (LPARAM)&sm); + } + + // scroll log to bottom if the log was previously scrolled to bottom, else restore old position + if (bRedraw || (UINT)scroll.nPos >= (UINT)scroll.nMax - scroll.nPage - 5 || scroll.nMax - scroll.nMin - scroll.nPage < 50) + ScrollToBottom(); + else + m_rtf.SendMsg(EM_SETSCROLLPOS, 0, (LPARAM)&point); + + // do we need to restore the selection + if (oldsel.cpMax != oldsel.cpMin) { + m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&oldsel); + m_rtf.SetDraw(true); + InvalidateRect(m_rtf.GetHwnd(), nullptr, TRUE); + } + + // need to invalidate the window + if (bFlag) { + sel.cpMin = sel.cpMax = m_rtf.GetRichTextLength(); + m_rtf.SendMsg(EM_EXSETSEL, 0, (LPARAM)&sel); + m_rtf.SetDraw(true); + InvalidateRect(m_rtf.GetHwnd(), nullptr, TRUE); + } +} + +///////////////////////////////////////////////////////////////////////////////////////// + +INT_PTR CALLBACK CMsgDialog::FilterWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + static CMsgDialog *pDlg = nullptr; + switch (uMsg) { + case WM_INITDIALOG: + pDlg = (CMsgDialog*)lParam; + CheckDlgButton(hwndDlg, IDC_1, pDlg->m_iLogFilterFlags & GC_EVENT_ACTION ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_2, pDlg->m_iLogFilterFlags & GC_EVENT_MESSAGE ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_3, pDlg->m_iLogFilterFlags & GC_EVENT_NICK ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_4, pDlg->m_iLogFilterFlags & GC_EVENT_JOIN ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_5, pDlg->m_iLogFilterFlags & GC_EVENT_PART ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_6, pDlg->m_iLogFilterFlags & GC_EVENT_TOPIC ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_7, pDlg->m_iLogFilterFlags & GC_EVENT_ADDSTATUS ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_8, pDlg->m_iLogFilterFlags & GC_EVENT_INFORMATION ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_9, pDlg->m_iLogFilterFlags & GC_EVENT_QUIT ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_10, pDlg->m_iLogFilterFlags & GC_EVENT_KICK ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_11, pDlg->m_iLogFilterFlags & GC_EVENT_NOTICE ? BST_CHECKED : BST_UNCHECKED); + break; + + case WM_CTLCOLOREDIT: + case WM_CTLCOLORSTATIC: + SetTextColor((HDC)wParam, RGB(60, 60, 150)); + SetBkColor((HDC)wParam, GetSysColor(COLOR_WINDOW)); + return (INT_PTR)GetSysColorBrush(COLOR_WINDOW); + + case WM_ACTIVATE: + if (LOWORD(wParam) == WA_INACTIVE) { + int iFlags = 0; + + if (IsDlgButtonChecked(hwndDlg, IDC_1) == BST_CHECKED) + iFlags |= GC_EVENT_ACTION; + if (IsDlgButtonChecked(hwndDlg, IDC_2) == BST_CHECKED) + iFlags |= GC_EVENT_MESSAGE; + if (IsDlgButtonChecked(hwndDlg, IDC_3) == BST_CHECKED) + iFlags |= GC_EVENT_NICK; + if (IsDlgButtonChecked(hwndDlg, IDC_4) == BST_CHECKED) + iFlags |= GC_EVENT_JOIN; + if (IsDlgButtonChecked(hwndDlg, IDC_5) == BST_CHECKED) + iFlags |= GC_EVENT_PART; + if (IsDlgButtonChecked(hwndDlg, IDC_6) == BST_CHECKED) + iFlags |= GC_EVENT_TOPIC; + if (IsDlgButtonChecked(hwndDlg, IDC_7) == BST_CHECKED) + iFlags |= GC_EVENT_ADDSTATUS; + if (IsDlgButtonChecked(hwndDlg, IDC_8) == BST_CHECKED) + iFlags |= GC_EVENT_INFORMATION; + if (IsDlgButtonChecked(hwndDlg, IDC_9) == BST_CHECKED) + iFlags |= GC_EVENT_QUIT; + if (IsDlgButtonChecked(hwndDlg, IDC_10) == BST_CHECKED) + iFlags |= GC_EVENT_KICK; + if (IsDlgButtonChecked(hwndDlg, IDC_11) == BST_CHECKED) + iFlags |= GC_EVENT_NOTICE; + + if (iFlags & GC_EVENT_ADDSTATUS) + iFlags |= GC_EVENT_REMOVESTATUS; + + pDlg->m_iLogFilterFlags = iFlags; + if (pDlg->m_bFilterEnabled) + pDlg->RedrawLog(); + PostMessage(hwndDlg, WM_CLOSE, 0, 0); + } + break; + + case WM_CLOSE: + DestroyWindow(hwndDlg); + break; + } + + return FALSE; +} diff --git a/src/core/stdmsg/src/cmdlist.cpp b/src/core/stdmsg/src/cmdlist.cpp index beb669dcf5..1ace5b0545 100644 --- a/src/core/stdmsg/src/cmdlist.cpp +++ b/src/core/stdmsg/src/cmdlist.cpp @@ -1,6 +1,6 @@ /* -Copyright 2000-12 Miranda IM, 2012-22 Miranda NG team, +Copyright 2000-12 Miranda IM, 2012-23 Miranda NG team, all portions of this codebase are copyrighted to the people listed in contributors.txt. diff --git a/src/core/stdmsg/src/cmdlist.h b/src/core/stdmsg/src/cmdlist.h index bbe8c9b11b..fda5562689 100644 --- a/src/core/stdmsg/src/cmdlist.h +++ b/src/core/stdmsg/src/cmdlist.h @@ -1,6 +1,6 @@ /* -Copyright 2000-12 Miranda IM, 2012-22 Miranda NG team, +Copyright 2000-12 Miranda IM, 2012-23 Miranda NG team, all portions of this codebase are copyrighted to the people listed in contributors.txt. diff --git a/src/core/stdmsg/src/globals.cpp b/src/core/stdmsg/src/globals.cpp index de2ca11c6d..5d2b95cc46 100644 --- a/src/core/stdmsg/src/globals.cpp +++ b/src/core/stdmsg/src/globals.cpp @@ -1,6 +1,6 @@ /* -Copyright 2000-12 Miranda IM, 2012-22 Miranda NG team, +Copyright 2000-12 Miranda IM, 2012-23 Miranda NG team, all portions of this codebase are copyrighted to the people listed in contributors.txt. diff --git a/src/core/stdmsg/src/msgdialog.cpp b/src/core/stdmsg/src/msgdialog.cpp index 8e0c4ff3ed..359b308022 100644 --- a/src/core/stdmsg/src/msgdialog.cpp +++ b/src/core/stdmsg/src/msgdialog.cpp @@ -1,6 +1,6 @@ /* -Copyright 2000-12 Miranda IM, 2012-22 Miranda NG team, +Copyright 2000-12 Miranda IM, 2012-23 Miranda NG team, all portions of this codebase are copyrighted to the people listed in contributors.txt. diff --git a/src/core/stdmsg/src/msglog.cpp b/src/core/stdmsg/src/msglog.cpp index 8fb1f5edbd..791cd1b71e 100644 --- a/src/core/stdmsg/src/msglog.cpp +++ b/src/core/stdmsg/src/msglog.cpp @@ -1,6 +1,6 @@ /* -Copyright 2000-12 Miranda IM, 2012-22 Miranda NG team, +Copyright 2000-12 Miranda IM, 2012-23 Miranda NG team, all portions of this codebase are copyrighted to the people listed in contributors.txt. diff --git a/src/core/stdmsg/src/msgoptions.cpp b/src/core/stdmsg/src/msgoptions.cpp index 590afa2478..34dc8e044f 100644 --- a/src/core/stdmsg/src/msgoptions.cpp +++ b/src/core/stdmsg/src/msgoptions.cpp @@ -1,6 +1,6 @@ /* -Copyright 2000-12 Miranda IM, 2012-22 Miranda NG team, +Copyright 2000-12 Miranda IM, 2012-23 Miranda NG team, all portions of this codebase are copyrighted to the people listed in contributors.txt. diff --git a/src/core/stdmsg/src/msgs.cpp b/src/core/stdmsg/src/msgs.cpp index 95b209fd02..9f5be7be28 100644 --- a/src/core/stdmsg/src/msgs.cpp +++ b/src/core/stdmsg/src/msgs.cpp @@ -1,6 +1,6 @@ /* -Copyright 2000-12 Miranda IM, 2012-22 Miranda NG team, +Copyright 2000-12 Miranda IM, 2012-23 Miranda NG team, all portions of this codebase are copyrighted to the people listed in contributors.txt. diff --git a/src/core/stdmsg/src/msgs.h b/src/core/stdmsg/src/msgs.h index f21110e641..0e9f38dead 100644 --- a/src/core/stdmsg/src/msgs.h +++ b/src/core/stdmsg/src/msgs.h @@ -1,6 +1,6 @@ /* -Copyright 2000-12 Miranda IM, 2012-22 Miranda NG team, +Copyright 2000-12 Miranda IM, 2012-23 Miranda NG team, all portions of this codebase are copyrighted to the people listed in contributors.txt. diff --git a/src/core/stdmsg/src/msgtimedout.cpp b/src/core/stdmsg/src/msgtimedout.cpp index 19744fe695..828924580e 100644 --- a/src/core/stdmsg/src/msgtimedout.cpp +++ b/src/core/stdmsg/src/msgtimedout.cpp @@ -1,6 +1,6 @@ /* -Copyright 2000-12 Miranda IM, 2012-22 Miranda NG team, +Copyright 2000-12 Miranda IM, 2012-23 Miranda NG team, all portions of this codebase are copyrighted to the people listed in contributors.txt. diff --git a/src/core/stdmsg/src/srmm.cpp b/src/core/stdmsg/src/srmm.cpp index 69c350aad7..4485d40bb3 100644 --- a/src/core/stdmsg/src/srmm.cpp +++ b/src/core/stdmsg/src/srmm.cpp @@ -1,6 +1,6 @@ /* -Copyright 2000-12 Miranda IM, 2012-22 Miranda NG team, +Copyright 2000-12 Miranda IM, 2012-23 Miranda NG team, all portions of this codebase are copyrighted to the people listed in contributors.txt. diff --git a/src/core/stdmsg/src/statusicon.cpp b/src/core/stdmsg/src/statusicon.cpp index 4244f9037c..6255dc3e1e 100644 --- a/src/core/stdmsg/src/statusicon.cpp +++ b/src/core/stdmsg/src/statusicon.cpp @@ -1,6 +1,6 @@ /* -Copyright 2000-12 Miranda IM, 2012-22 Miranda NG team, +Copyright 2000-12 Miranda IM, 2012-23 Miranda NG team, all portions of this codebase are copyrighted to the people listed in contributors.txt. diff --git a/src/core/stdmsg/src/stdafx.cxx b/src/core/stdmsg/src/stdafx.cxx index 52ec2d6817..e23069a5b8 100644 --- a/src/core/stdmsg/src/stdafx.cxx +++ b/src/core/stdmsg/src/stdafx.cxx @@ -1,6 +1,6 @@ /* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org) +Copyright (C) 2012-23 Miranda NG team (https://miranda-ng.org) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/src/core/stdmsg/src/stdafx.h b/src/core/stdmsg/src/stdafx.h index a42feafac9..33d557a6a9 100644 --- a/src/core/stdmsg/src/stdafx.h +++ b/src/core/stdmsg/src/stdafx.h @@ -1,6 +1,6 @@ /* -Copyright 2000-12 Miranda IM, 2012-22 Miranda NG team, +Copyright 2000-12 Miranda IM, 2012-23 Miranda NG team, all portions of this codebase are copyrighted to the people listed in contributors.txt. diff --git a/src/core/stdmsg/src/tabs.cpp b/src/core/stdmsg/src/tabs.cpp index d60bec7634..402d1f2f0f 100644 --- a/src/core/stdmsg/src/tabs.cpp +++ b/src/core/stdmsg/src/tabs.cpp @@ -1,668 +1,668 @@ -/* - -Copyright 2000-12 Miranda IM, 2012-22 Miranda NG team, -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" -#include "statusicon.h" - -CTabbedWindow *g_pTabDialog = nullptr; - -///////////////////////////////////////////////////////////////////////////////////////// - -CTabbedWindow* GetContainer() -{ - if (g_Settings.bTabsEnable) { - if (g_pTabDialog == nullptr) { - g_pTabDialog = new CTabbedWindow(); - g_pTabDialog->Show(); - } - return g_pTabDialog; - } - - return new CTabbedWindow(); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static LRESULT CALLBACK TabSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - CTabbedWindow *pOwner = (CTabbedWindow*)GetWindowLongPtr(hwnd, GWLP_USERDATA); - TCHITTESTINFO tci = {}; - - static bool bDragging = false; - static int iBeginIndex = 0; - switch (msg) { - case WM_LBUTTONDOWN: - tci.pt.x = (short)LOWORD(GetMessagePos()); - tci.pt.y = (short)HIWORD(GetMessagePos()); - if (DragDetect(hwnd, tci.pt) && TabCtrl_GetItemCount(hwnd) > 1) { - tci.flags = TCHT_ONITEM; - ScreenToClient(hwnd, &tci.pt); - int idx = TabCtrl_HitTest(hwnd, &tci); - if (idx != -1) { - CMsgDialog *pDlg = (CMsgDialog*)pOwner->m_tab.GetNthPage(idx); - if (pDlg) { - bDragging = true; - iBeginIndex = idx; - ImageList_BeginDrag(Clist_GetImageList(), pDlg->GetImageId(), 8, 8); - ImageList_DragEnter(hwnd, tci.pt.x, tci.pt.y); - SetCapture(hwnd); - } - return TRUE; - } - } - else pOwner->TabClicked(); - break; - - case WM_CAPTURECHANGED: - bDragging = false; - ImageList_DragLeave(hwnd); - ImageList_EndDrag(); - break; - - case WM_MOUSEMOVE: - if (bDragging) { - tci.pt.x = (short)LOWORD(GetMessagePos()); - tci.pt.y = (short)HIWORD(GetMessagePos()); - ScreenToClient(hwnd, &tci.pt); - ImageList_DragMove(tci.pt.x, tci.pt.y); - } - break; - - case WM_LBUTTONUP: - if (bDragging && ReleaseCapture()) { - tci.pt.x = (short)LOWORD(GetMessagePos()); - tci.pt.y = (short)HIWORD(GetMessagePos()); - tci.flags = TCHT_ONITEM; - bDragging = false; - ImageList_DragLeave(hwnd); - ImageList_EndDrag(); - - ScreenToClient(hwnd, &tci.pt); - int idx = TabCtrl_HitTest(hwnd, &tci); - if (idx != -1 && idx != iBeginIndex) - pOwner->DropTab(idx, iBeginIndex); - } - break; - - case WM_LBUTTONDBLCLK: - if (g_Settings.bTabCloseOnDblClick) { - tci.pt.x = (short)LOWORD(GetMessagePos()); - tci.pt.y = (short)HIWORD(GetMessagePos()); - ScreenToClient(hwnd, &tci.pt); - - tci.flags = TCHT_ONITEM; - int idx = TabCtrl_HitTest(hwnd, &tci); - if (idx != -1) { - CMsgDialog *pDlg = (CMsgDialog*)pOwner->m_tab.GetNthPage(idx); - if (pDlg) - pDlg->CloseTab(); - } - } - break; - - case WM_MBUTTONUP: - tci.pt.x = (short)LOWORD(GetMessagePos()); - tci.pt.y = (short)HIWORD(GetMessagePos()); - tci.flags = TCHT_ONITEM; - - ScreenToClient(hwnd, &tci.pt); - int idx = TabCtrl_HitTest(hwnd, &tci); - if (idx != -1) { - CMsgDialog *pDlg = (CMsgDialog*)pOwner->m_tab.GetNthPage(idx); - if (pDlg) - pDlg->CloseTab(); - } - break; - } - - return mir_callNextSubclass(hwnd, TabSubclassProc, msg, wParam, lParam); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -CTabbedWindow::CTabbedWindow() : - CDlgBase(g_plugin, IDD_CONTAINER), - m_tab(this, IDC_TAB) -{ - SetMinSize(450, 350); -} - -bool CTabbedWindow::OnInitDialog() -{ - SetWindowLongPtr(m_tab.GetHwnd(), GWLP_USERDATA, LPARAM(this)); - mir_subclassWindow(m_tab.GetHwnd(), ::TabSubclassProc); - - m_hwndStatus = CreateWindowEx(0, STATUSCLASSNAME, nullptr, WS_CHILD | WS_VISIBLE | SBT_TOOLTIPS | SBARS_SIZEGRIP, 0, 0, 0, 0, m_hwnd, nullptr, g_plugin.getInst(), nullptr); - SendMessage(m_hwndStatus, SB_SETMINHEIGHT, GetSystemMetrics(SM_CYSMICON), 0); - - RECT rc; - GetWindowRect(m_hwndStatus, &rc); - m_statusHeight = rc.bottom - rc.top; - - SetWindowPosition(); - - if (!g_Settings.bTabsEnable) { - m_tab.Hide(); - return false; - } - - LONG_PTR mask = GetWindowLongPtr(m_tab.GetHwnd(), GWL_STYLE); - if (g_Settings.bTabsAtBottom) - mask |= TCS_BOTTOM; - else - mask &= ~TCS_BOTTOM; - SetWindowLongPtr(m_tab.GetHwnd(), GWL_STYLE, mask); - - TabCtrl_SetMinTabWidth(m_tab.GetHwnd(), 80); - TabCtrl_SetImageList(m_tab.GetHwnd(), Clist_GetImageList()); - return true; -} - -void CTabbedWindow::OnDestroy() -{ - DestroyWindow(m_hwndStatus); m_hwndStatus = nullptr; - - SaveWindowPosition(true); - - Utils_SaveWindowPosition(m_hwnd, g_plugin.bSavePerContact ? ((m_pEmbed == nullptr) ? 0 : m_pEmbed->m_hContact) : 0, CHAT_MODULE, "room"); - - if (m_pEmbed == nullptr) - g_pTabDialog = nullptr; -} - -void CTabbedWindow::OnResize() -{ - CDlgBase::OnResize(); - - SendMessage(m_hwndStatus, WM_SIZE, 0, 0); - - if (m_pEmbed) { - RECT rc; - GetClientRect(m_tab.GetHwnd(), &rc); - MoveWindow(m_pEmbed->GetHwnd(), 0, 0, rc.right - rc.left, rc.bottom - rc.top, FALSE); - } - - SaveWindowPosition(false); -} - -int CTabbedWindow::Resizer(UTILRESIZECONTROL *urc) -{ - if (urc->wId == IDC_TAB) { - urc->rcItem.top = 1; - urc->rcItem.bottom = urc->dlgNewSize.cy - m_statusHeight - 1; - return RD_ANCHORX_WIDTH | RD_ANCHORY_CUSTOM; - } - - return RD_ANCHORX_WIDTH | RD_ANCHORY_BOTTOM; // status bar -} - -///////////////////////////////////////////////////////////////////////////////////////// - -CTabbedWindow* CTabbedWindow::AddPage(MCONTACT hContact, wchar_t *pwszText, int iNoActivate) -{ - CMsgDialog *pDlg = new CMsgDialog(this, hContact); - pDlg->m_wszInitialText = pwszText; - if (iNoActivate != -1) - pDlg->m_bNoActivate = iNoActivate != 0; - - if (g_Settings.bTabsEnable) { - m_tab.AddPage(Clist_GetContactDisplayName(hContact), nullptr, pDlg); - FixTabIcons(pDlg); - - m_tab.ActivatePage(m_tab.GetCount() - 1); - } - else { - m_pEmbed = pDlg; - Create(); - pDlg->SetParent(m_hwnd); - pDlg->Create(); - Show(); - } - - PostMessage(m_hwnd, WM_SIZE, 0, 0); - return this; -} - -void CTabbedWindow::AddPage(SESSION_INFO *si, int insertAt) -{ - // does the tab already exist? - int indexfound = (si->pDlg) ? m_tab.GetDlgIndex(si->pDlg) : -1; - if (indexfound == -1) { // create a new tab - wchar_t szTemp[30]; - mir_wstrncpy(szTemp, si->ptszName, 21); - if (mir_wstrlen(si->ptszName) > 20) - mir_wstrncpy(szTemp + 20, L"...", 4); - - if (!IsWindowVisible(m_hwnd)) - Show(SW_SHOW); - - CMsgDialog *pDlg = new CMsgDialog(this, si); - pDlg->SetParent(m_hwnd); - m_tab.AddPage(szTemp, nullptr, pDlg); - m_tab.ActivatePage(m_tab.GetCount() - 1); - FixTabIcons(pDlg); - } - else if (insertAt == -1) - m_tab.ActivatePage(indexfound); -} - -CMsgDialog* CTabbedWindow::CurrPage() const -{ - return (m_pEmbed != nullptr) ? m_pEmbed : (CMsgDialog*)m_tab.GetActivePage(); -} - -void CTabbedWindow::DropTab(int begin, int end) -{ - if (begin == end) - return; - - m_tab.SwapPages(begin, end); - - CMsgDialog *pDlg = (CMsgDialog *)m_tab.GetNthPage(end); - if (pDlg) { - FixTabIcons(pDlg); - m_tab.ActivatePage(end); - } - - // fix the "fixed" positions - int tabCount = m_tab.GetCount(); - for (int i = 0; i < tabCount; i++) { - pDlg = (CMsgDialog *)m_tab.GetNthPage(i); - if (pDlg == nullptr) - continue; - - SESSION_INFO *si = pDlg->m_si; - if (si && si->hContact && db_get_w(si->hContact, si->pszModule, "TabPosition", 0) != 0) - db_set_w(si->hContact, si->pszModule, "TabPosition", i + 1); - } -} - -void CTabbedWindow::FixTabIcons(CMsgDialog *pDlg) -{ - if (pDlg == nullptr) - return; - - int image = pDlg->GetImageId(); - - // if tabs are turned off, simply change the window's icon, otherwise set the tab's icon first - if (m_pEmbed == nullptr) { - int idx = m_tab.GetDlgIndex(pDlg); - if (idx == -1) - return; - - TCITEM tci = {}; - tci.mask = TCIF_IMAGE; - TabCtrl_GetItem(m_tab.GetHwnd(), idx, &tci); - if (tci.iImage != image) { - tci.iImage = image; - TabCtrl_SetItem(m_tab.GetHwnd(), idx, &tci); - } - } - - // set the container's icon only if we're processing the current page - if (pDlg == CurrPage()) { - Window_FreeIcon_IcoLib(m_hwnd); - if (g_plugin.bUseStatusWinIcon) - Window_SetProtoIcon_IcoLib(m_hwnd, pDlg->m_szProto, pDlg->m_wStatus); - else if (pDlg->isChat()) - Window_SetIcon_IcoLib(m_hwnd, g_plugin.getIconHandle(IDI_CHANMGR)); - else - Window_SetSkinIcon_IcoLib(m_hwnd, SKINICON_EVENT_MESSAGE); - } -} - -void CTabbedWindow::RemoveTab(CMsgDialog *pDlg) -{ - int idx = m_tab.GetDlgIndex(pDlg); - if (idx == -1) - return; - - m_tab.RemovePage(idx); - if (m_tab.GetCount() == 0) - PostMessage(m_hwnd, WM_CLOSE, 0, 0); - else { - if (m_tab.GetNthPage(idx) == nullptr) - idx--; - m_tab.ActivatePage(idx); - } -} - -void CTabbedWindow::SaveWindowPosition(bool bUpdateSession) -{ - WINDOWPLACEMENT wp = {}; - wp.length = sizeof(wp); - GetWindowPlacement(m_hwnd, &wp); - - g_Settings.iX = wp.rcNormalPosition.left; - g_Settings.iY = wp.rcNormalPosition.top; - g_Settings.iWidth = wp.rcNormalPosition.right - wp.rcNormalPosition.left; - g_Settings.iHeight = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top; - - if (bUpdateSession) { - iX = g_Settings.iX; - iY = g_Settings.iY; - iWidth = g_Settings.iWidth; - iHeight = g_Settings.iHeight; - } -} - -void CTabbedWindow::SetMessageHighlight(CMsgDialog *pDlg) -{ - if (m_tab.GetDlgIndex(pDlg) == -1) - return; - - pDlg->m_si->wState |= GC_EVENT_HIGHLIGHT; - FixTabIcons(pDlg); - if (Chat::bFlashWindowHighlight && pDlg != m_tab.GetActivePage()) - pDlg->StartFlash(); -} - -void CTabbedWindow::SetTabHighlight(CMsgDialog *pDlg) -{ - if (m_tab.GetDlgIndex(pDlg) == -1) - return; - - FixTabIcons(pDlg); - if (Chat::bFlashWindow && pDlg != m_tab.GetActivePage()) - pDlg->StartFlash(); -} - -void CTabbedWindow::SetWindowPosition() -{ - if (m_pEmbed == nullptr) { - Utils_RestoreWindowPosition(m_hwnd, 0, CHAT_MODULE, "room"); - return; - } - - if (iX) { - WINDOWPLACEMENT wp; - wp.length = sizeof(wp); - GetWindowPlacement(m_hwnd, &wp); - - wp.rcNormalPosition.left = iX; - wp.rcNormalPosition.top = iY; - wp.rcNormalPosition.right = wp.rcNormalPosition.left + iWidth; - wp.rcNormalPosition.bottom = wp.rcNormalPosition.top + iHeight; - wp.showCmd = SW_HIDE; - SetWindowPlacement(m_hwnd, &wp); - return; - } - - int flag = m_pEmbed->m_bNoActivate ? RWPF_HIDDEN : 0; - if (Utils_RestoreWindowPosition(m_hwnd, g_plugin.bSavePerContact ? m_pEmbed->m_hContact : 0, CHAT_MODULE, "room", flag)) { - if (g_plugin.bSavePerContact) { - if (Utils_RestoreWindowPosition(m_hwnd, 0, CHAT_MODULE, "room", flag | RWPF_NOMOVE)) - SetWindowPos(m_hwnd, nullptr, 0, 0, 550, 400, SWP_NOZORDER | SWP_NOMOVE | SWP_SHOWWINDOW); - } - else SetWindowPos(m_hwnd, nullptr, 0, 0, 550, 400, SWP_NOZORDER | SWP_NOMOVE | SWP_SHOWWINDOW); - } - - if (!g_plugin.bSavePerContact && g_plugin.bCascade) { - RECT rc, rcMax = {}; - CTabbedWindow *pMaxTab = nullptr; - - for (auto &it : g_arDialogs) { - auto *pTab = it->m_pOwner; - if (pTab == this) - continue; - - GetWindowRect(pTab->GetHwnd(), &rc); - if (rc.left > rcMax.left && rc.top > rcMax.top) { - pMaxTab = pTab; - rcMax = rc; - } - } - - if (pMaxTab) { - m_windowWasCascaded = 1; - int offset = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYFRAME); - SetWindowPos(m_hwnd, nullptr, rcMax.left + offset, rcMax.top + offset, 0, 0, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE); - } - } -} - -void CTabbedWindow::SwitchNextTab() -{ - int total = m_tab.GetCount(); - int i = TabCtrl_GetCurSel(m_tab.GetHwnd()); - if (i != -1 && total > 1) { - if (i < total - 1) - i++; - else - i = 0; - m_tab.ActivatePage(i); - TabClicked(); - } -} - -void CTabbedWindow::SwitchPrevTab() -{ - int total = m_tab.GetCount(); - int i = TabCtrl_GetCurSel(m_tab.GetHwnd()); - if (i != -1 && total >= 1) { - if (i > 0) - i--; - else - i = total - 1; - m_tab.ActivatePage(i); - TabClicked(); - } -} - -void CTabbedWindow::SwitchTab(int iNewTab) -{ - int total = m_tab.GetCount(); - int i = TabCtrl_GetCurSel(m_tab.GetHwnd()); - if (i != -1 && total != -1 && total != 1 && i != iNewTab && total > iNewTab) { - m_tab.ActivatePage(iNewTab); - TabClicked(); - } -} - -void CTabbedWindow::TabClicked() -{ - CMsgDialog *pDlg = (CMsgDialog*)m_tab.GetActivePage(); - if (pDlg == nullptr) - return; - - SetFocus(pDlg->m_message.GetHwnd()); - - SESSION_INFO *si = pDlg->m_si; - if (si) { - if (si->wState & STATE_TALK) { - si->wState &= ~STATE_TALK; - db_set_w(si->hContact, si->pszModule, "ApparentMode", 0); - } - - if (si->wState & GC_EVENT_HIGHLIGHT) { - si->wState &= ~GC_EVENT_HIGHLIGHT; - - if (g_clistApi.pfnGetEvent(si->hContact, 0)) - g_clistApi.pfnRemoveEvent(si->hContact, GC_FAKE_EVENT); - } - - if (!si->pDlg) { - g_chatApi.ShowRoom(si); - SendMessage(m_hwnd, WM_MOUSEACTIVATE, 0, 0); - } - } - - FixTabIcons(pDlg); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -INT_PTR CTabbedWindow::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) -{ - RECT rc; - int idx; - - switch (msg) { - case WM_MOVE: - SaveWindowPosition(false); - break; - - case WM_ENTERSIZEMOVE: - GetClientRect(m_hwnd, &rc); - oldSizeX = rc.right - rc.left; - oldSizeY = rc.bottom - rc.top; - break; - - case WM_EXITSIZEMOVE: - GetClientRect(m_hwnd, &rc); - if (!((rc.right - rc.left) == oldSizeX && (rc.bottom - rc.top) == oldSizeY)) { - CMsgDialog *pDlg = (g_Settings.bTabsEnable) ? (CMsgDialog*)m_tab.GetActivePage() : m_pEmbed; - if (pDlg != nullptr) { - pDlg->m_pLog->ScrollToBottom(); - pDlg->Resize(); - } - } - break; - - case WM_DRAWITEM: - { - LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT)lParam; - if (dis->hwndItem == m_hwndStatus) { - CMsgDialog *pDlg = (g_Settings.bTabsEnable) ? (CMsgDialog*)m_tab.GetActivePage() : m_pEmbed; - if (pDlg != nullptr) - DrawStatusIcons(pDlg->m_hContact, dis->hDC, dis->rcItem, 2); - return TRUE; - } - } - break; - - case WM_COMMAND: - if (LOWORD(wParam) == IDOK) { - CMsgDialog *pDlg = (g_Settings.bTabsEnable) ? (CMsgDialog*)m_tab.GetActivePage() : m_pEmbed; - if (pDlg != nullptr) { - pDlg->m_btnOk.Click(); - return TRUE; - } - } - break; - - case WM_ACTIVATE: - if (LOWORD(wParam) == WA_INACTIVE) - break; - - if (!m_pEmbed) { - idx = TabCtrl_GetCurSel(m_tab.GetHwnd()); - if (idx != -1) - m_tab.ActivatePage(idx); - } - else m_pEmbed->OnActivate(); - break; - - case WM_NOTIFY: - if (((LPNMHDR)lParam)->hwndFrom == m_hwndStatus) { - if (((LPNMHDR)lParam)->code == NM_CLICK || ((LPNMHDR)lParam)->code == NM_RCLICK) { - NMMOUSE *nm = (NMMOUSE *)lParam; - SendMessage(m_hwndStatus, SB_GETRECT, SendMessage(m_hwndStatus, SB_GETPARTS, 0, 0) - 1, (LPARAM)&rc); - if (nm->pt.x >= rc.left) { - CMsgDialog *pDlg = (g_Settings.bTabsEnable) ? (CMsgDialog*)m_tab.GetActivePage() : m_pEmbed; - if (pDlg != nullptr) - CheckStatusIconClick(pDlg->m_hContact, m_hwndStatus, nm->pt, rc, 2, ((LPNMHDR)lParam)->code == NM_RCLICK ? MBCF_RIGHTBUTTON : 0); - } - return TRUE; - } - } - - if (((LPNMHDR)lParam)->idFrom == IDC_TAB) { - switch (((LPNMHDR)lParam)->code) { - case TCN_SELCHANGE: - m_tab.ActivatePage(TabCtrl_GetCurSel(m_tab.GetHwnd())); - break; - - case NM_RCLICK: - int i = TabCtrl_GetCurSel(((LPNMHDR)lParam)->hwndFrom); - if (i == -1) - break; - - TCHITTESTINFO tci = {}; - tci.pt.x = (short)LOWORD(GetMessagePos()); - tci.pt.y = (short)HIWORD(GetMessagePos()); - tci.flags = TCHT_ONITEM; - ScreenToClient(GetDlgItem(m_hwnd, IDC_TAB), &tci.pt); - if ((i = TabCtrl_HitTest(((LPNMHDR)lParam)->hwndFrom, &tci)) == -1) - break; - - CMsgDialog *pDlg = (CMsgDialog*)m_tab.GetNthPage(i); - SESSION_INFO *si = pDlg->m_si; - - ClientToScreen(GetDlgItem(m_hwnd, IDC_TAB), &tci.pt); - HMENU hSubMenu = GetSubMenu(g_hMenu, 1); - TranslateMenu(hSubMenu); - - if (si != nullptr) { - uint16_t w = db_get_w(si->hContact, si->pszModule, "TabPosition", 0); - if (w == 0) - CheckMenuItem(hSubMenu, ID_LOCKPOSITION, MF_BYCOMMAND | MF_UNCHECKED); - else - CheckMenuItem(hSubMenu, ID_LOCKPOSITION, MF_BYCOMMAND | MF_CHECKED); - } - else CheckMenuItem(hSubMenu, ID_LOCKPOSITION, MF_BYCOMMAND | MF_UNCHECKED); - - switch (TrackPopupMenu(hSubMenu, TPM_RETURNCMD, tci.pt.x, tci.pt.y, 0, m_hwnd, nullptr)) { - case ID_CLOSE: - pDlg->CloseTab(); - break; - - case ID_LOCKPOSITION: - if (si != nullptr) { - if (!(GetMenuState(hSubMenu, ID_LOCKPOSITION, MF_BYCOMMAND)&MF_CHECKED)) { - if (si->hContact) - db_set_w(si->hContact, si->pszModule, "TabPosition", (uint16_t)(i + 1)); - } - else db_unset(si->hContact, si->pszModule, "TabPosition"); - } - break; - - case ID_CLOSEOTHER: - int tabCount = m_tab.GetCount(); - if (tabCount > 1) { - while (tabCount--) { - if (tabCount == i) - continue; - - if (pDlg = (CMsgDialog*)m_tab.GetNthPage(tabCount)) - pDlg->CloseTab(); - } - m_tab.ActivatePage(0); - } - break; - } - } - } - break; - } - - return CDlgBase::DlgProc(msg, wParam, lParam); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void UninitTabs() -{ - if (g_pTabDialog != nullptr) { - g_pTabDialog->Close(); - g_pTabDialog = nullptr; - } -} +/* + +Copyright 2000-12 Miranda IM, 2012-23 Miranda NG team, +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" +#include "statusicon.h" + +CTabbedWindow *g_pTabDialog = nullptr; + +///////////////////////////////////////////////////////////////////////////////////////// + +CTabbedWindow* GetContainer() +{ + if (g_Settings.bTabsEnable) { + if (g_pTabDialog == nullptr) { + g_pTabDialog = new CTabbedWindow(); + g_pTabDialog->Show(); + } + return g_pTabDialog; + } + + return new CTabbedWindow(); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static LRESULT CALLBACK TabSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + CTabbedWindow *pOwner = (CTabbedWindow*)GetWindowLongPtr(hwnd, GWLP_USERDATA); + TCHITTESTINFO tci = {}; + + static bool bDragging = false; + static int iBeginIndex = 0; + switch (msg) { + case WM_LBUTTONDOWN: + tci.pt.x = (short)LOWORD(GetMessagePos()); + tci.pt.y = (short)HIWORD(GetMessagePos()); + if (DragDetect(hwnd, tci.pt) && TabCtrl_GetItemCount(hwnd) > 1) { + tci.flags = TCHT_ONITEM; + ScreenToClient(hwnd, &tci.pt); + int idx = TabCtrl_HitTest(hwnd, &tci); + if (idx != -1) { + CMsgDialog *pDlg = (CMsgDialog*)pOwner->m_tab.GetNthPage(idx); + if (pDlg) { + bDragging = true; + iBeginIndex = idx; + ImageList_BeginDrag(Clist_GetImageList(), pDlg->GetImageId(), 8, 8); + ImageList_DragEnter(hwnd, tci.pt.x, tci.pt.y); + SetCapture(hwnd); + } + return TRUE; + } + } + else pOwner->TabClicked(); + break; + + case WM_CAPTURECHANGED: + bDragging = false; + ImageList_DragLeave(hwnd); + ImageList_EndDrag(); + break; + + case WM_MOUSEMOVE: + if (bDragging) { + tci.pt.x = (short)LOWORD(GetMessagePos()); + tci.pt.y = (short)HIWORD(GetMessagePos()); + ScreenToClient(hwnd, &tci.pt); + ImageList_DragMove(tci.pt.x, tci.pt.y); + } + break; + + case WM_LBUTTONUP: + if (bDragging && ReleaseCapture()) { + tci.pt.x = (short)LOWORD(GetMessagePos()); + tci.pt.y = (short)HIWORD(GetMessagePos()); + tci.flags = TCHT_ONITEM; + bDragging = false; + ImageList_DragLeave(hwnd); + ImageList_EndDrag(); + + ScreenToClient(hwnd, &tci.pt); + int idx = TabCtrl_HitTest(hwnd, &tci); + if (idx != -1 && idx != iBeginIndex) + pOwner->DropTab(idx, iBeginIndex); + } + break; + + case WM_LBUTTONDBLCLK: + if (g_Settings.bTabCloseOnDblClick) { + tci.pt.x = (short)LOWORD(GetMessagePos()); + tci.pt.y = (short)HIWORD(GetMessagePos()); + ScreenToClient(hwnd, &tci.pt); + + tci.flags = TCHT_ONITEM; + int idx = TabCtrl_HitTest(hwnd, &tci); + if (idx != -1) { + CMsgDialog *pDlg = (CMsgDialog*)pOwner->m_tab.GetNthPage(idx); + if (pDlg) + pDlg->CloseTab(); + } + } + break; + + case WM_MBUTTONUP: + tci.pt.x = (short)LOWORD(GetMessagePos()); + tci.pt.y = (short)HIWORD(GetMessagePos()); + tci.flags = TCHT_ONITEM; + + ScreenToClient(hwnd, &tci.pt); + int idx = TabCtrl_HitTest(hwnd, &tci); + if (idx != -1) { + CMsgDialog *pDlg = (CMsgDialog*)pOwner->m_tab.GetNthPage(idx); + if (pDlg) + pDlg->CloseTab(); + } + break; + } + + return mir_callNextSubclass(hwnd, TabSubclassProc, msg, wParam, lParam); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +CTabbedWindow::CTabbedWindow() : + CDlgBase(g_plugin, IDD_CONTAINER), + m_tab(this, IDC_TAB) +{ + SetMinSize(450, 350); +} + +bool CTabbedWindow::OnInitDialog() +{ + SetWindowLongPtr(m_tab.GetHwnd(), GWLP_USERDATA, LPARAM(this)); + mir_subclassWindow(m_tab.GetHwnd(), ::TabSubclassProc); + + m_hwndStatus = CreateWindowEx(0, STATUSCLASSNAME, nullptr, WS_CHILD | WS_VISIBLE | SBT_TOOLTIPS | SBARS_SIZEGRIP, 0, 0, 0, 0, m_hwnd, nullptr, g_plugin.getInst(), nullptr); + SendMessage(m_hwndStatus, SB_SETMINHEIGHT, GetSystemMetrics(SM_CYSMICON), 0); + + RECT rc; + GetWindowRect(m_hwndStatus, &rc); + m_statusHeight = rc.bottom - rc.top; + + SetWindowPosition(); + + if (!g_Settings.bTabsEnable) { + m_tab.Hide(); + return false; + } + + LONG_PTR mask = GetWindowLongPtr(m_tab.GetHwnd(), GWL_STYLE); + if (g_Settings.bTabsAtBottom) + mask |= TCS_BOTTOM; + else + mask &= ~TCS_BOTTOM; + SetWindowLongPtr(m_tab.GetHwnd(), GWL_STYLE, mask); + + TabCtrl_SetMinTabWidth(m_tab.GetHwnd(), 80); + TabCtrl_SetImageList(m_tab.GetHwnd(), Clist_GetImageList()); + return true; +} + +void CTabbedWindow::OnDestroy() +{ + DestroyWindow(m_hwndStatus); m_hwndStatus = nullptr; + + SaveWindowPosition(true); + + Utils_SaveWindowPosition(m_hwnd, g_plugin.bSavePerContact ? ((m_pEmbed == nullptr) ? 0 : m_pEmbed->m_hContact) : 0, CHAT_MODULE, "room"); + + if (m_pEmbed == nullptr) + g_pTabDialog = nullptr; +} + +void CTabbedWindow::OnResize() +{ + CDlgBase::OnResize(); + + SendMessage(m_hwndStatus, WM_SIZE, 0, 0); + + if (m_pEmbed) { + RECT rc; + GetClientRect(m_tab.GetHwnd(), &rc); + MoveWindow(m_pEmbed->GetHwnd(), 0, 0, rc.right - rc.left, rc.bottom - rc.top, FALSE); + } + + SaveWindowPosition(false); +} + +int CTabbedWindow::Resizer(UTILRESIZECONTROL *urc) +{ + if (urc->wId == IDC_TAB) { + urc->rcItem.top = 1; + urc->rcItem.bottom = urc->dlgNewSize.cy - m_statusHeight - 1; + return RD_ANCHORX_WIDTH | RD_ANCHORY_CUSTOM; + } + + return RD_ANCHORX_WIDTH | RD_ANCHORY_BOTTOM; // status bar +} + +///////////////////////////////////////////////////////////////////////////////////////// + +CTabbedWindow* CTabbedWindow::AddPage(MCONTACT hContact, wchar_t *pwszText, int iNoActivate) +{ + CMsgDialog *pDlg = new CMsgDialog(this, hContact); + pDlg->m_wszInitialText = pwszText; + if (iNoActivate != -1) + pDlg->m_bNoActivate = iNoActivate != 0; + + if (g_Settings.bTabsEnable) { + m_tab.AddPage(Clist_GetContactDisplayName(hContact), nullptr, pDlg); + FixTabIcons(pDlg); + + m_tab.ActivatePage(m_tab.GetCount() - 1); + } + else { + m_pEmbed = pDlg; + Create(); + pDlg->SetParent(m_hwnd); + pDlg->Create(); + Show(); + } + + PostMessage(m_hwnd, WM_SIZE, 0, 0); + return this; +} + +void CTabbedWindow::AddPage(SESSION_INFO *si, int insertAt) +{ + // does the tab already exist? + int indexfound = (si->pDlg) ? m_tab.GetDlgIndex(si->pDlg) : -1; + if (indexfound == -1) { // create a new tab + wchar_t szTemp[30]; + mir_wstrncpy(szTemp, si->ptszName, 21); + if (mir_wstrlen(si->ptszName) > 20) + mir_wstrncpy(szTemp + 20, L"...", 4); + + if (!IsWindowVisible(m_hwnd)) + Show(SW_SHOW); + + CMsgDialog *pDlg = new CMsgDialog(this, si); + pDlg->SetParent(m_hwnd); + m_tab.AddPage(szTemp, nullptr, pDlg); + m_tab.ActivatePage(m_tab.GetCount() - 1); + FixTabIcons(pDlg); + } + else if (insertAt == -1) + m_tab.ActivatePage(indexfound); +} + +CMsgDialog* CTabbedWindow::CurrPage() const +{ + return (m_pEmbed != nullptr) ? m_pEmbed : (CMsgDialog*)m_tab.GetActivePage(); +} + +void CTabbedWindow::DropTab(int begin, int end) +{ + if (begin == end) + return; + + m_tab.SwapPages(begin, end); + + CMsgDialog *pDlg = (CMsgDialog *)m_tab.GetNthPage(end); + if (pDlg) { + FixTabIcons(pDlg); + m_tab.ActivatePage(end); + } + + // fix the "fixed" positions + int tabCount = m_tab.GetCount(); + for (int i = 0; i < tabCount; i++) { + pDlg = (CMsgDialog *)m_tab.GetNthPage(i); + if (pDlg == nullptr) + continue; + + SESSION_INFO *si = pDlg->m_si; + if (si && si->hContact && db_get_w(si->hContact, si->pszModule, "TabPosition", 0) != 0) + db_set_w(si->hContact, si->pszModule, "TabPosition", i + 1); + } +} + +void CTabbedWindow::FixTabIcons(CMsgDialog *pDlg) +{ + if (pDlg == nullptr) + return; + + int image = pDlg->GetImageId(); + + // if tabs are turned off, simply change the window's icon, otherwise set the tab's icon first + if (m_pEmbed == nullptr) { + int idx = m_tab.GetDlgIndex(pDlg); + if (idx == -1) + return; + + TCITEM tci = {}; + tci.mask = TCIF_IMAGE; + TabCtrl_GetItem(m_tab.GetHwnd(), idx, &tci); + if (tci.iImage != image) { + tci.iImage = image; + TabCtrl_SetItem(m_tab.GetHwnd(), idx, &tci); + } + } + + // set the container's icon only if we're processing the current page + if (pDlg == CurrPage()) { + Window_FreeIcon_IcoLib(m_hwnd); + if (g_plugin.bUseStatusWinIcon) + Window_SetProtoIcon_IcoLib(m_hwnd, pDlg->m_szProto, pDlg->m_wStatus); + else if (pDlg->isChat()) + Window_SetIcon_IcoLib(m_hwnd, g_plugin.getIconHandle(IDI_CHANMGR)); + else + Window_SetSkinIcon_IcoLib(m_hwnd, SKINICON_EVENT_MESSAGE); + } +} + +void CTabbedWindow::RemoveTab(CMsgDialog *pDlg) +{ + int idx = m_tab.GetDlgIndex(pDlg); + if (idx == -1) + return; + + m_tab.RemovePage(idx); + if (m_tab.GetCount() == 0) + PostMessage(m_hwnd, WM_CLOSE, 0, 0); + else { + if (m_tab.GetNthPage(idx) == nullptr) + idx--; + m_tab.ActivatePage(idx); + } +} + +void CTabbedWindow::SaveWindowPosition(bool bUpdateSession) +{ + WINDOWPLACEMENT wp = {}; + wp.length = sizeof(wp); + GetWindowPlacement(m_hwnd, &wp); + + g_Settings.iX = wp.rcNormalPosition.left; + g_Settings.iY = wp.rcNormalPosition.top; + g_Settings.iWidth = wp.rcNormalPosition.right - wp.rcNormalPosition.left; + g_Settings.iHeight = wp.rcNormalPosition.bottom - wp.rcNormalPosition.top; + + if (bUpdateSession) { + iX = g_Settings.iX; + iY = g_Settings.iY; + iWidth = g_Settings.iWidth; + iHeight = g_Settings.iHeight; + } +} + +void CTabbedWindow::SetMessageHighlight(CMsgDialog *pDlg) +{ + if (m_tab.GetDlgIndex(pDlg) == -1) + return; + + pDlg->m_si->wState |= GC_EVENT_HIGHLIGHT; + FixTabIcons(pDlg); + if (Chat::bFlashWindowHighlight && pDlg != m_tab.GetActivePage()) + pDlg->StartFlash(); +} + +void CTabbedWindow::SetTabHighlight(CMsgDialog *pDlg) +{ + if (m_tab.GetDlgIndex(pDlg) == -1) + return; + + FixTabIcons(pDlg); + if (Chat::bFlashWindow && pDlg != m_tab.GetActivePage()) + pDlg->StartFlash(); +} + +void CTabbedWindow::SetWindowPosition() +{ + if (m_pEmbed == nullptr) { + Utils_RestoreWindowPosition(m_hwnd, 0, CHAT_MODULE, "room"); + return; + } + + if (iX) { + WINDOWPLACEMENT wp; + wp.length = sizeof(wp); + GetWindowPlacement(m_hwnd, &wp); + + wp.rcNormalPosition.left = iX; + wp.rcNormalPosition.top = iY; + wp.rcNormalPosition.right = wp.rcNormalPosition.left + iWidth; + wp.rcNormalPosition.bottom = wp.rcNormalPosition.top + iHeight; + wp.showCmd = SW_HIDE; + SetWindowPlacement(m_hwnd, &wp); + return; + } + + int flag = m_pEmbed->m_bNoActivate ? RWPF_HIDDEN : 0; + if (Utils_RestoreWindowPosition(m_hwnd, g_plugin.bSavePerContact ? m_pEmbed->m_hContact : 0, CHAT_MODULE, "room", flag)) { + if (g_plugin.bSavePerContact) { + if (Utils_RestoreWindowPosition(m_hwnd, 0, CHAT_MODULE, "room", flag | RWPF_NOMOVE)) + SetWindowPos(m_hwnd, nullptr, 0, 0, 550, 400, SWP_NOZORDER | SWP_NOMOVE | SWP_SHOWWINDOW); + } + else SetWindowPos(m_hwnd, nullptr, 0, 0, 550, 400, SWP_NOZORDER | SWP_NOMOVE | SWP_SHOWWINDOW); + } + + if (!g_plugin.bSavePerContact && g_plugin.bCascade) { + RECT rc, rcMax = {}; + CTabbedWindow *pMaxTab = nullptr; + + for (auto &it : g_arDialogs) { + auto *pTab = it->m_pOwner; + if (pTab == this) + continue; + + GetWindowRect(pTab->GetHwnd(), &rc); + if (rc.left > rcMax.left && rc.top > rcMax.top) { + pMaxTab = pTab; + rcMax = rc; + } + } + + if (pMaxTab) { + m_windowWasCascaded = 1; + int offset = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYFRAME); + SetWindowPos(m_hwnd, nullptr, rcMax.left + offset, rcMax.top + offset, 0, 0, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSIZE); + } + } +} + +void CTabbedWindow::SwitchNextTab() +{ + int total = m_tab.GetCount(); + int i = TabCtrl_GetCurSel(m_tab.GetHwnd()); + if (i != -1 && total > 1) { + if (i < total - 1) + i++; + else + i = 0; + m_tab.ActivatePage(i); + TabClicked(); + } +} + +void CTabbedWindow::SwitchPrevTab() +{ + int total = m_tab.GetCount(); + int i = TabCtrl_GetCurSel(m_tab.GetHwnd()); + if (i != -1 && total >= 1) { + if (i > 0) + i--; + else + i = total - 1; + m_tab.ActivatePage(i); + TabClicked(); + } +} + +void CTabbedWindow::SwitchTab(int iNewTab) +{ + int total = m_tab.GetCount(); + int i = TabCtrl_GetCurSel(m_tab.GetHwnd()); + if (i != -1 && total != -1 && total != 1 && i != iNewTab && total > iNewTab) { + m_tab.ActivatePage(iNewTab); + TabClicked(); + } +} + +void CTabbedWindow::TabClicked() +{ + CMsgDialog *pDlg = (CMsgDialog*)m_tab.GetActivePage(); + if (pDlg == nullptr) + return; + + SetFocus(pDlg->m_message.GetHwnd()); + + SESSION_INFO *si = pDlg->m_si; + if (si) { + if (si->wState & STATE_TALK) { + si->wState &= ~STATE_TALK; + db_set_w(si->hContact, si->pszModule, "ApparentMode", 0); + } + + if (si->wState & GC_EVENT_HIGHLIGHT) { + si->wState &= ~GC_EVENT_HIGHLIGHT; + + if (g_clistApi.pfnGetEvent(si->hContact, 0)) + g_clistApi.pfnRemoveEvent(si->hContact, GC_FAKE_EVENT); + } + + if (!si->pDlg) { + g_chatApi.ShowRoom(si); + SendMessage(m_hwnd, WM_MOUSEACTIVATE, 0, 0); + } + } + + FixTabIcons(pDlg); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +INT_PTR CTabbedWindow::DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) +{ + RECT rc; + int idx; + + switch (msg) { + case WM_MOVE: + SaveWindowPosition(false); + break; + + case WM_ENTERSIZEMOVE: + GetClientRect(m_hwnd, &rc); + oldSizeX = rc.right - rc.left; + oldSizeY = rc.bottom - rc.top; + break; + + case WM_EXITSIZEMOVE: + GetClientRect(m_hwnd, &rc); + if (!((rc.right - rc.left) == oldSizeX && (rc.bottom - rc.top) == oldSizeY)) { + CMsgDialog *pDlg = (g_Settings.bTabsEnable) ? (CMsgDialog*)m_tab.GetActivePage() : m_pEmbed; + if (pDlg != nullptr) { + pDlg->m_pLog->ScrollToBottom(); + pDlg->Resize(); + } + } + break; + + case WM_DRAWITEM: + { + LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT)lParam; + if (dis->hwndItem == m_hwndStatus) { + CMsgDialog *pDlg = (g_Settings.bTabsEnable) ? (CMsgDialog*)m_tab.GetActivePage() : m_pEmbed; + if (pDlg != nullptr) + DrawStatusIcons(pDlg->m_hContact, dis->hDC, dis->rcItem, 2); + return TRUE; + } + } + break; + + case WM_COMMAND: + if (LOWORD(wParam) == IDOK) { + CMsgDialog *pDlg = (g_Settings.bTabsEnable) ? (CMsgDialog*)m_tab.GetActivePage() : m_pEmbed; + if (pDlg != nullptr) { + pDlg->m_btnOk.Click(); + return TRUE; + } + } + break; + + case WM_ACTIVATE: + if (LOWORD(wParam) == WA_INACTIVE) + break; + + if (!m_pEmbed) { + idx = TabCtrl_GetCurSel(m_tab.GetHwnd()); + if (idx != -1) + m_tab.ActivatePage(idx); + } + else m_pEmbed->OnActivate(); + break; + + case WM_NOTIFY: + if (((LPNMHDR)lParam)->hwndFrom == m_hwndStatus) { + if (((LPNMHDR)lParam)->code == NM_CLICK || ((LPNMHDR)lParam)->code == NM_RCLICK) { + NMMOUSE *nm = (NMMOUSE *)lParam; + SendMessage(m_hwndStatus, SB_GETRECT, SendMessage(m_hwndStatus, SB_GETPARTS, 0, 0) - 1, (LPARAM)&rc); + if (nm->pt.x >= rc.left) { + CMsgDialog *pDlg = (g_Settings.bTabsEnable) ? (CMsgDialog*)m_tab.GetActivePage() : m_pEmbed; + if (pDlg != nullptr) + CheckStatusIconClick(pDlg->m_hContact, m_hwndStatus, nm->pt, rc, 2, ((LPNMHDR)lParam)->code == NM_RCLICK ? MBCF_RIGHTBUTTON : 0); + } + return TRUE; + } + } + + if (((LPNMHDR)lParam)->idFrom == IDC_TAB) { + switch (((LPNMHDR)lParam)->code) { + case TCN_SELCHANGE: + m_tab.ActivatePage(TabCtrl_GetCurSel(m_tab.GetHwnd())); + break; + + case NM_RCLICK: + int i = TabCtrl_GetCurSel(((LPNMHDR)lParam)->hwndFrom); + if (i == -1) + break; + + TCHITTESTINFO tci = {}; + tci.pt.x = (short)LOWORD(GetMessagePos()); + tci.pt.y = (short)HIWORD(GetMessagePos()); + tci.flags = TCHT_ONITEM; + ScreenToClient(GetDlgItem(m_hwnd, IDC_TAB), &tci.pt); + if ((i = TabCtrl_HitTest(((LPNMHDR)lParam)->hwndFrom, &tci)) == -1) + break; + + CMsgDialog *pDlg = (CMsgDialog*)m_tab.GetNthPage(i); + SESSION_INFO *si = pDlg->m_si; + + ClientToScreen(GetDlgItem(m_hwnd, IDC_TAB), &tci.pt); + HMENU hSubMenu = GetSubMenu(g_hMenu, 1); + TranslateMenu(hSubMenu); + + if (si != nullptr) { + uint16_t w = db_get_w(si->hContact, si->pszModule, "TabPosition", 0); + if (w == 0) + CheckMenuItem(hSubMenu, ID_LOCKPOSITION, MF_BYCOMMAND | MF_UNCHECKED); + else + CheckMenuItem(hSubMenu, ID_LOCKPOSITION, MF_BYCOMMAND | MF_CHECKED); + } + else CheckMenuItem(hSubMenu, ID_LOCKPOSITION, MF_BYCOMMAND | MF_UNCHECKED); + + switch (TrackPopupMenu(hSubMenu, TPM_RETURNCMD, tci.pt.x, tci.pt.y, 0, m_hwnd, nullptr)) { + case ID_CLOSE: + pDlg->CloseTab(); + break; + + case ID_LOCKPOSITION: + if (si != nullptr) { + if (!(GetMenuState(hSubMenu, ID_LOCKPOSITION, MF_BYCOMMAND)&MF_CHECKED)) { + if (si->hContact) + db_set_w(si->hContact, si->pszModule, "TabPosition", (uint16_t)(i + 1)); + } + else db_unset(si->hContact, si->pszModule, "TabPosition"); + } + break; + + case ID_CLOSEOTHER: + int tabCount = m_tab.GetCount(); + if (tabCount > 1) { + while (tabCount--) { + if (tabCount == i) + continue; + + if (pDlg = (CMsgDialog*)m_tab.GetNthPage(tabCount)) + pDlg->CloseTab(); + } + m_tab.ActivatePage(0); + } + break; + } + } + } + break; + } + + return CDlgBase::DlgProc(msg, wParam, lParam); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void UninitTabs() +{ + if (g_pTabDialog != nullptr) { + g_pTabDialog->Close(); + g_pTabDialog = nullptr; + } +} diff --git a/src/core/stdmsg/src/version.h b/src/core/stdmsg/src/version.h index 80b240e521..c2573ed98b 100644 --- a/src/core/stdmsg/src/version.h +++ b/src/core/stdmsg/src/version.h @@ -9,4 +9,4 @@ #define __DESCRIPTION "Core module for send/receive instant messages." #define __AUTHOR "Miranda NG team" #define __AUTHORWEB "https://miranda-ng.org/p/StdMsg" -#define __COPYRIGHT "© 2012-22 Miranda NG team" +#define __COPYRIGHT "© 2012-23 Miranda NG team" diff --git a/src/core/stdpopup/src/stdafx.cxx b/src/core/stdpopup/src/stdafx.cxx index 1ab0efee94..ebbde0ade1 100644 --- a/src/core/stdpopup/src/stdafx.cxx +++ b/src/core/stdpopup/src/stdafx.cxx @@ -1,18 +1,18 @@ -/* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org) - -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 version 2 -of the License. - -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, see . -*/ - +/* +Copyright (C) 2012-23 Miranda NG team (https://miranda-ng.org) + +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 version 2 +of the License. + +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, see . +*/ + #include "stdafx.h" \ No newline at end of file diff --git a/src/core/stdpopup/src/version.h b/src/core/stdpopup/src/version.h index 2ffc660f71..16d5b005cd 100644 --- a/src/core/stdpopup/src/version.h +++ b/src/core/stdpopup/src/version.h @@ -8,4 +8,4 @@ #define __DESCRIPTION "Core module for popups." #define __AUTHOR "Scott Ellis, Miranda NG team" #define __AUTHORWEB "https://miranda-ng.org/p/StdPopup" -#define __COPYRIGHT "© 2012-22 Miranda NG team" +#define __COPYRIGHT "© 2012-23 Miranda NG team" diff --git a/src/core/stduihist/src/history.cpp b/src/core/stduihist/src/history.cpp index 56c3aba8a5..ae92875fab 100644 --- a/src/core/stduihist/src/history.cpp +++ b/src/core/stduihist/src/history.cpp @@ -2,7 +2,7 @@ Miranda NG: the free IM client for Microsoft* Windows* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org), +Copyright (C) 2012-23 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. diff --git a/src/core/stduihist/src/main.cpp b/src/core/stduihist/src/main.cpp index 1911bd9792..1be11d7ac3 100644 --- a/src/core/stduihist/src/main.cpp +++ b/src/core/stduihist/src/main.cpp @@ -2,7 +2,7 @@ Standard ugly history viewer for Miranda NG -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org) +Copyright (C) 2012-23 Miranda NG team (https://miranda-ng.org) 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 diff --git a/src/core/stduihist/src/stdafx.h b/src/core/stduihist/src/stdafx.h index 9817742ad3..aae29d451d 100644 --- a/src/core/stduihist/src/stdafx.h +++ b/src/core/stduihist/src/stdafx.h @@ -2,7 +2,7 @@ Miranda NG: the free IM client for Microsoft* Windows* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org), +Copyright (C) 2012-23 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. diff --git a/src/core/stduihist/src/version.h b/src/core/stduihist/src/version.h index 62eda51681..ee7cceff2a 100644 --- a/src/core/stduihist/src/version.h +++ b/src/core/stduihist/src/version.h @@ -8,4 +8,4 @@ #define __DESCRIPTION "Core module for built-in history viewer." #define __AUTHOR "Miranda NG team" #define __AUTHORWEB "https://miranda-ng.org/p/StdUIHist" -#define __COPYRIGHT "© 2012-22 Miranda NG team" +#define __COPYRIGHT "© 2012-23 Miranda NG team" diff --git a/src/core/stduserinfo/src/contactinfo.cpp b/src/core/stduserinfo/src/contactinfo.cpp index a19783e4df..7adec4c09b 100644 --- a/src/core/stduserinfo/src/contactinfo.cpp +++ b/src/core/stduserinfo/src/contactinfo.cpp @@ -2,7 +2,7 @@ Miranda NG: the free IM client for Microsoft* Windows* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org), +Copyright (C) 2012-23 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. diff --git a/src/core/stduserinfo/src/main.cpp b/src/core/stduserinfo/src/main.cpp index 5334c9727f..9bd9b6f7be 100644 --- a/src/core/stduserinfo/src/main.cpp +++ b/src/core/stduserinfo/src/main.cpp @@ -2,7 +2,7 @@ Standard User Info plugin for Miranda NG -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org) +Copyright (C) 2012-23 Miranda NG team (https://miranda-ng.org) 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 diff --git a/src/core/stduserinfo/src/stdafx.h b/src/core/stduserinfo/src/stdafx.h index 76b456e716..ca5412f200 100644 --- a/src/core/stduserinfo/src/stdafx.h +++ b/src/core/stduserinfo/src/stdafx.h @@ -2,7 +2,7 @@ Miranda NG: the free IM client for Microsoft* Windows* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org), +Copyright (C) 2012-23 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. diff --git a/src/core/stduserinfo/src/stdinfo.cpp b/src/core/stduserinfo/src/stdinfo.cpp index 5acec2d245..ca3b2edd20 100644 --- a/src/core/stduserinfo/src/stdinfo.cpp +++ b/src/core/stduserinfo/src/stdinfo.cpp @@ -2,7 +2,7 @@ Miranda NG: the free IM client for Microsoft* Windows* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org), +Copyright (C) 2012-23 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. diff --git a/src/core/stduserinfo/src/userinfo.cpp b/src/core/stduserinfo/src/userinfo.cpp index 9448d5c96f..30792d9244 100644 --- a/src/core/stduserinfo/src/userinfo.cpp +++ b/src/core/stduserinfo/src/userinfo.cpp @@ -2,7 +2,7 @@ Miranda NG: the free IM client for Microsoft* Windows* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org), +Copyright (C) 2012-23 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. diff --git a/src/core/stduserinfo/src/utils.h b/src/core/stduserinfo/src/utils.h index cb766c47ae..9ceb33b61d 100644 --- a/src/core/stduserinfo/src/utils.h +++ b/src/core/stduserinfo/src/utils.h @@ -1,214 +1,214 @@ -/* - -Standard User Info plugin for Miranda NG - -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org) - -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. -*/ - -#define SVS_NORMAL 0 -#define SVS_GENDER 1 -#define SVS_ZEROISUNSPEC 2 -#define SVS_IP 3 -#define SVS_COUNTRY 4 -#define SVS_MONTH 5 -#define SVS_SIGNED 6 -#define SVS_TIMEZONE 7 -#define SVS_MARITAL 8 - -///////////////////////////////////////////////////////////////////////////////////////// - -struct DataItem -{ - const char *szSetting; - int idCtrl, special; -}; - -template -bool IsEmptyValue(MCONTACT hContact, DataItem(&buffer)[_Size], const char *szModule = nullptr) -{ - if (szModule == nullptr) - szModule = Proto_GetBaseAccountName(hContact); - - DBVARIANT dbv; - for (auto &it : buffer) { - if (db_get_s(hContact, szModule, it.szSetting, &dbv, 0) != 0) - continue; - - db_free(&dbv); - return false; - } - - return true; -} - -template -void SetValue(HWND hwndDlg, MCONTACT hContact, DataItem(&buffer)[_Size], const char *szModule = nullptr) -{ - if (szModule == nullptr) - szModule = Proto_GetBaseAccountName(hContact); - - for (auto &it : buffer) { - char *pstr = nullptr; - wchar_t *pwstr = nullptr, wstr[80]; - - DBVARIANT dbv = { DBVT_DELETED }; - - bool unspecified; - if (szModule == nullptr) - unspecified = true; - else - unspecified = db_get_s(hContact, szModule, it.szSetting, &dbv, 0) != 0; - - if (!unspecified) { - switch (dbv.type) { - case DBVT_BYTE: - if (it.special == SVS_GENDER) { - if (dbv.cVal == 'M') pwstr = TranslateT("Male"); - else if (dbv.cVal == 'F') pwstr = TranslateT("Female"); - else unspecified = 1; - } - else if (it.special == SVS_MONTH) { - if (dbv.bVal > 0 && dbv.bVal <= 12) { - pwstr = wstr; - GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SABBREVMONTHNAME1 - 1 + dbv.bVal, wstr, _countof(wstr)); - } - else unspecified = 1; - } - else if (it.special == SVS_TIMEZONE) { - if (dbv.cVal == -100) unspecified = 1; - else { - pwstr = wstr; - mir_snwprintf(wstr, dbv.cVal ? L"UTC%+d:%02d" : L"UTC", -dbv.cVal / 2, (dbv.cVal & 1) * 30); - } - } - else if (it.special == SVS_MARITAL) { - switch (dbv.cVal) { - case 0: - pwstr = TranslateT(""); - break; - case 10: - pwstr = TranslateT("Single"); - break; - case 11: - pwstr = TranslateT("Close relationships"); - break; - case 12: - pwstr = TranslateT("Engaged"); - break; - case 20: - pwstr = TranslateT("Married"); - break; - case 30: - pwstr = TranslateT("Divorced"); - break; - case 31: - pwstr = TranslateT("Separated"); - break; - case 40: - pwstr = TranslateT("Widowed"); - break; - case 50: - pwstr = TranslateT("Actively searching"); - break; - case 60: - pwstr = TranslateT("In love"); - break; - case 70: - pwstr = TranslateT("It's complicated"); - break; - case 80: - pwstr = TranslateT("In a civil union"); - break; - default: - unspecified = 1; - } - } - else { - unspecified = (it.special == SVS_ZEROISUNSPEC && dbv.bVal == 0); - pwstr = _itow(it.special == SVS_SIGNED ? dbv.cVal : dbv.bVal, wstr, 10); - } - break; - - case DBVT_WORD: - if (it.special == SVS_COUNTRY) { - uint16_t wSave = dbv.wVal; - if (wSave == (uint16_t)-1) { - char szSettingName[100]; - mir_snprintf(szSettingName, "%sName", it.szSetting); - if (!db_get_ws(hContact, szModule, szSettingName, &dbv)) { - pwstr = dbv.pwszVal; - unspecified = false; - break; - } - } - - pwstr = TranslateW(_A2T((char *)CallService(MS_UTILS_GETCOUNTRYBYNUMBER, wSave, 0))); - unspecified = pwstr == nullptr; - } - else { - unspecified = (it.special == SVS_ZEROISUNSPEC && dbv.wVal == 0); - pwstr = _itow(it.special == SVS_SIGNED ? dbv.sVal : dbv.wVal, wstr, 10); - } - break; - - case DBVT_DWORD: - unspecified = (it.special == SVS_ZEROISUNSPEC && dbv.dVal == 0); - if (it.special == SVS_IP) { - struct in_addr ia; - ia.S_un.S_addr = htonl(dbv.dVal); - mir_wstrncpy(wstr, _A2T(inet_ntoa(ia)), _countof(wstr)); - pwstr = wstr; - if (dbv.dVal == 0) - unspecified = 1; - } - else pwstr = _itow(it.special == SVS_SIGNED ? dbv.lVal : dbv.dVal, wstr, 10); - break; - - case DBVT_ASCIIZ: - unspecified = (it.special == SVS_ZEROISUNSPEC && dbv.pszVal[0] == '\0'); - pstr = dbv.pszVal; - break; - - case DBVT_UTF8: - unspecified = (it.special == SVS_ZEROISUNSPEC && dbv.pszVal[0] == '\0'); - if (!unspecified) { - SetDlgItemTextW(hwndDlg, it.idCtrl, TranslateW(ptrW(mir_utf8decodeW(dbv.pszVal)))); - goto LBL_Exit; - } - - mir_utf8decode(dbv.pszVal, &pwstr); - break; - - default: - pwstr = wstr; - mir_wstrcpy(wstr, L"???"); - break; - } - } - - if (unspecified) - SetDlgItemText(hwndDlg, it.idCtrl, TranslateT("")); - else if (pwstr != nullptr) - SetDlgItemText(hwndDlg, it.idCtrl, pwstr); - else - SetDlgItemTextA(hwndDlg, it.idCtrl, pstr); - -LBL_Exit: - EnableWindow(GetDlgItem(hwndDlg, it.idCtrl), !unspecified); - db_free(&dbv); - } -} +/* + +Standard User Info plugin for Miranda NG + +Copyright (C) 2012-23 Miranda NG team (https://miranda-ng.org) + +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. +*/ + +#define SVS_NORMAL 0 +#define SVS_GENDER 1 +#define SVS_ZEROISUNSPEC 2 +#define SVS_IP 3 +#define SVS_COUNTRY 4 +#define SVS_MONTH 5 +#define SVS_SIGNED 6 +#define SVS_TIMEZONE 7 +#define SVS_MARITAL 8 + +///////////////////////////////////////////////////////////////////////////////////////// + +struct DataItem +{ + const char *szSetting; + int idCtrl, special; +}; + +template +bool IsEmptyValue(MCONTACT hContact, DataItem(&buffer)[_Size], const char *szModule = nullptr) +{ + if (szModule == nullptr) + szModule = Proto_GetBaseAccountName(hContact); + + DBVARIANT dbv; + for (auto &it : buffer) { + if (db_get_s(hContact, szModule, it.szSetting, &dbv, 0) != 0) + continue; + + db_free(&dbv); + return false; + } + + return true; +} + +template +void SetValue(HWND hwndDlg, MCONTACT hContact, DataItem(&buffer)[_Size], const char *szModule = nullptr) +{ + if (szModule == nullptr) + szModule = Proto_GetBaseAccountName(hContact); + + for (auto &it : buffer) { + char *pstr = nullptr; + wchar_t *pwstr = nullptr, wstr[80]; + + DBVARIANT dbv = { DBVT_DELETED }; + + bool unspecified; + if (szModule == nullptr) + unspecified = true; + else + unspecified = db_get_s(hContact, szModule, it.szSetting, &dbv, 0) != 0; + + if (!unspecified) { + switch (dbv.type) { + case DBVT_BYTE: + if (it.special == SVS_GENDER) { + if (dbv.cVal == 'M') pwstr = TranslateT("Male"); + else if (dbv.cVal == 'F') pwstr = TranslateT("Female"); + else unspecified = 1; + } + else if (it.special == SVS_MONTH) { + if (dbv.bVal > 0 && dbv.bVal <= 12) { + pwstr = wstr; + GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SABBREVMONTHNAME1 - 1 + dbv.bVal, wstr, _countof(wstr)); + } + else unspecified = 1; + } + else if (it.special == SVS_TIMEZONE) { + if (dbv.cVal == -100) unspecified = 1; + else { + pwstr = wstr; + mir_snwprintf(wstr, dbv.cVal ? L"UTC%+d:%02d" : L"UTC", -dbv.cVal / 2, (dbv.cVal & 1) * 30); + } + } + else if (it.special == SVS_MARITAL) { + switch (dbv.cVal) { + case 0: + pwstr = TranslateT(""); + break; + case 10: + pwstr = TranslateT("Single"); + break; + case 11: + pwstr = TranslateT("Close relationships"); + break; + case 12: + pwstr = TranslateT("Engaged"); + break; + case 20: + pwstr = TranslateT("Married"); + break; + case 30: + pwstr = TranslateT("Divorced"); + break; + case 31: + pwstr = TranslateT("Separated"); + break; + case 40: + pwstr = TranslateT("Widowed"); + break; + case 50: + pwstr = TranslateT("Actively searching"); + break; + case 60: + pwstr = TranslateT("In love"); + break; + case 70: + pwstr = TranslateT("It's complicated"); + break; + case 80: + pwstr = TranslateT("In a civil union"); + break; + default: + unspecified = 1; + } + } + else { + unspecified = (it.special == SVS_ZEROISUNSPEC && dbv.bVal == 0); + pwstr = _itow(it.special == SVS_SIGNED ? dbv.cVal : dbv.bVal, wstr, 10); + } + break; + + case DBVT_WORD: + if (it.special == SVS_COUNTRY) { + uint16_t wSave = dbv.wVal; + if (wSave == (uint16_t)-1) { + char szSettingName[100]; + mir_snprintf(szSettingName, "%sName", it.szSetting); + if (!db_get_ws(hContact, szModule, szSettingName, &dbv)) { + pwstr = dbv.pwszVal; + unspecified = false; + break; + } + } + + pwstr = TranslateW(_A2T((char *)CallService(MS_UTILS_GETCOUNTRYBYNUMBER, wSave, 0))); + unspecified = pwstr == nullptr; + } + else { + unspecified = (it.special == SVS_ZEROISUNSPEC && dbv.wVal == 0); + pwstr = _itow(it.special == SVS_SIGNED ? dbv.sVal : dbv.wVal, wstr, 10); + } + break; + + case DBVT_DWORD: + unspecified = (it.special == SVS_ZEROISUNSPEC && dbv.dVal == 0); + if (it.special == SVS_IP) { + struct in_addr ia; + ia.S_un.S_addr = htonl(dbv.dVal); + mir_wstrncpy(wstr, _A2T(inet_ntoa(ia)), _countof(wstr)); + pwstr = wstr; + if (dbv.dVal == 0) + unspecified = 1; + } + else pwstr = _itow(it.special == SVS_SIGNED ? dbv.lVal : dbv.dVal, wstr, 10); + break; + + case DBVT_ASCIIZ: + unspecified = (it.special == SVS_ZEROISUNSPEC && dbv.pszVal[0] == '\0'); + pstr = dbv.pszVal; + break; + + case DBVT_UTF8: + unspecified = (it.special == SVS_ZEROISUNSPEC && dbv.pszVal[0] == '\0'); + if (!unspecified) { + SetDlgItemTextW(hwndDlg, it.idCtrl, TranslateW(ptrW(mir_utf8decodeW(dbv.pszVal)))); + goto LBL_Exit; + } + + mir_utf8decode(dbv.pszVal, &pwstr); + break; + + default: + pwstr = wstr; + mir_wstrcpy(wstr, L"???"); + break; + } + } + + if (unspecified) + SetDlgItemText(hwndDlg, it.idCtrl, TranslateT("")); + else if (pwstr != nullptr) + SetDlgItemText(hwndDlg, it.idCtrl, pwstr); + else + SetDlgItemTextA(hwndDlg, it.idCtrl, pstr); + +LBL_Exit: + EnableWindow(GetDlgItem(hwndDlg, it.idCtrl), !unspecified); + db_free(&dbv); + } +} diff --git a/src/core/stduserinfo/src/version.h b/src/core/stduserinfo/src/version.h index 1a68b614db..441fd0cdef 100644 --- a/src/core/stduserinfo/src/version.h +++ b/src/core/stduserinfo/src/version.h @@ -8,4 +8,4 @@ #define __DESCRIPTION "Core module for providing user information." #define __AUTHOR "Miranda NG team" #define __AUTHORWEB "https://miranda-ng.org/p/StdUserInfo" -#define __COPYRIGHT "© 2012-22 Miranda NG team" +#define __COPYRIGHT "© 2012-23 Miranda NG team" diff --git a/src/core/stduseronline/src/main.cpp b/src/core/stduseronline/src/main.cpp index 255a954e35..da3e0c5cd8 100644 --- a/src/core/stduseronline/src/main.cpp +++ b/src/core/stduseronline/src/main.cpp @@ -2,7 +2,7 @@ Standard user online monitor for Miranda NG -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org) +Copyright (C) 2012-23 Miranda NG team (https://miranda-ng.org) 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 diff --git a/src/core/stduseronline/src/stdafx.h b/src/core/stduseronline/src/stdafx.h index a34a26fd31..1f069e243c 100644 --- a/src/core/stduseronline/src/stdafx.h +++ b/src/core/stduseronline/src/stdafx.h @@ -2,7 +2,7 @@ Miranda NG: the free IM client for Microsoft* Windows* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org), +Copyright (C) 2012-23 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. diff --git a/src/core/stduseronline/src/useronline.cpp b/src/core/stduseronline/src/useronline.cpp index 3b1520a0a6..be50bf3165 100644 --- a/src/core/stduseronline/src/useronline.cpp +++ b/src/core/stduseronline/src/useronline.cpp @@ -2,7 +2,7 @@ Miranda NG: the free IM client for Microsoft* Windows* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org), +Copyright (C) 2012-23 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. diff --git a/src/core/stduseronline/src/version.h b/src/core/stduseronline/src/version.h index 3edec197fb..ec2b47a6f8 100644 --- a/src/core/stduseronline/src/version.h +++ b/src/core/stduseronline/src/version.h @@ -8,4 +8,4 @@ #define __DESCRIPTION "Core module for user-is-online event processing." #define __AUTHOR "Miranda NG team" #define __AUTHORWEB "https://miranda-ng.org/p/StdUserOnline" -#define __COPYRIGHT "© 2012-22 Miranda NG team" +#define __COPYRIGHT "© 2012-23 Miranda NG team" -- cgit v1.2.3